{ "title": "Code Walk-through", "steps": [ { "title": "Introduction", "description": "This web part was designed to demonstrate how to use a new custom Adaptive Card host component, along with a few concepts:\r\n* Loading property pane resources only when the property pane is displayed\r\n* Supporting themes and section background colors\r\n\r\nYou can use the `AdaptiveCard` component in your own web part, our web part isn't intended to be used in production.", "file": "README.md", "line": 1 }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 29, "description": "Adding these imports are crucial for adding theme and section background support." }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 96, "description": "The `_themeProvider` and `_themeVariant` will be used at render time to pass theme information to our components.", "selection": { "start": { "line": 96, "character": 3 }, "end": { "line": 97, "character": 53 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 113, "description": "This is how we let the web part know that we want to be notified when there are theme changes.", "selection": { "start": { "line": 107, "character": 5 }, "end": { "line": 113, "character": 84 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 364, "description": "This event handler will get called when the theme changes. It stores the `_themeVariant` and calls `render` to update the web part body.", "selection": { "start": { "line": 364, "character": 1 }, "end": { "line": 367, "character": 4 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 137, "description": "We pass the theme variant to the component that will render the web part body so that it can query the theme colors at render time.", "selection": { "start": { "line": 137, "character": 9 }, "end": { "line": 137, "character": 42 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 162, "description": "`loadPropertyPaneResources` is a standard web part event that gets called before the property pane is rendered.\\\r\n\r\nYou can use this to load resource-intensive components that only need to be shown in the property pane. That way, when the web part is showing in \"view\" mode (for most users), we don't need to load the extra resources. When the web part is in \"edit\" mode, and when we load the property pane, we load all the heavy stuff.", "selection": { "start": { "line": 162, "character": 19 }, "end": { "line": 162, "character": 44 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 169, "description": "For example, this `_templatePropertyPaneHelper` defines a @pnp code editor control. That way, we don't need to load all the code editing and syntax highlighting resources unless we're actually editing the web part properties.", "selection": { "start": { "line": 169, "character": 5 }, "end": { "line": 169, "character": 37 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 193, "description": "Because we pre-defined property pane controls in the `loadPropertyPaneResources` event handler, we can use the controls in this method..." }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 238, "description": "...when it is time to render the property pane, we simply use the pre-created `_templatePropertyPaneHelper`.", "selection": { "start": { "line": 238, "character": 17 }, "end": { "line": 238, "character": 72 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 117, "description": "We also set up the pnpjs `spfxContent` with the web part's context so that we can make it easy to get the data later.", "selection": { "start": { "line": 117, "character": 5 }, "end": { "line": 120, "character": 1 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 372, "description": "If we need to, we load the data from a SharePoint list so that we can pass the data to the `AdaptiveCard` component.", "selection": { "start": { "line": 372, "character": 17 }, "end": { "line": 372, "character": 34 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 386, "description": "We load the view that was selected so we can get the schema and the query.", "selection": { "start": { "line": 383, "character": 5 }, "end": { "line": 386, "character": 6 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 391, "description": "Calling `renderListDataAsStream` returns not only the data, but everything we need to render the complete data -- including looking field views, user info, etc.\r\n\r\nThis is similar to how SharePoint renders lists out-of-the-box. (Don't believe me? Use the network tab in your browser's Developer Tools on a SharePoint page that shows a list. You'll find calls to `renderListDataAsStream`)", "selection": { "start": { "line": 389, "character": 4 }, "end": { "line": 391, "character": 8 } } }, { "file": "src/webparts/adaptiveCardHost/AdaptiveCardHostWebPart.ts", "line": 140, "description": "When it is time to render the web part's body, our `AdaptiveCard` component only needs the template JSON, the data (if used), and a flag to tell us whether we're using Adaptive Card Templating or not.", "selection": { "start": { "line": 138, "character": 9 }, "end": { "line": 140, "character": 63 } } }, { "file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx", "line": 17, "description": "This renders the web part's body", "selection": { "start": { "line": 17, "character": 22 }, "end": { "line": 17, "character": 38 } } }, { "file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx", "line": 37, "description": "We detect if the web part is configured by looking at the `template` prop, the `data` prop, and whether the template contains the string `$data` -- which is an indicator that the template uses Adaptive Card templating.", "selection": { "start": { "line": 30, "character": 5 }, "end": { "line": 38, "character": 1 } } }, { "file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx", "line": 47, "description": "If we need a template, we show a placeholder", "selection": { "start": { "line": 40, "character": 5 }, "end": { "line": 47, "character": 9 } } }, { "file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx", "line": 56, "description": "If we need data, we show another friendly placeholder.", "selection": { "start": { "line": 48, "character": 7 }, "end": { "line": 56, "character": 9 } } }, { "file": "src/webparts/adaptiveCardHost/components/AdaptiveCardHost.tsx", "line": 70, "description": "If we detect that the template uses Adaptive Card templating, we display a friendly message.", "selection": { "start": { "line": 73, "character": 11 }, "end": { "line": 80, "character": 13 } } }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 29, "description": "This is where all the Adaptive Card processing gets done. You can use this component in your own web parts -- just pass the props you need.", "selection": { "start": { "line": 29, "character": 14 }, "end": { "line": 29, "character": 26 } } }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 61, "description": "This `div` will contain the rendered HTML.", "selection": { "start": { "line": 61, "character": 6 }, "end": { "line": 61, "character": 95 } } }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 59, "description": "I don't really like showing the errors in the `AdaptiveCard` component itself (I would have preferred to let the web part handle it), but that's all I could get working for now.", "selection": { "start": { "line": 54, "character": 9 }, "end": { "line": 59, "character": 22 } } }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 49, "description": "Once the component is mounted and/or when the properties change, we render the Adaptive Card.", "selection": { "start": { "line": 40, "character": 2 }, "end": { "line": 49, "character": 4 } } }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 4, "description": "We use the Adaptive Card team's npm package to render the cards." }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 5, "description": "We use the npm package to support Adaptive Card templating." }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 6, "description": "And we use this npm package to make the Adaptive Cards look like they belong to SharePoint by giving them a Office Fabric look." }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 14, "description": "We also use `markdown-it` to parse the Markdown from the rendered HTML so that we fully support the Adaptive Card schema." }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 132, "description": "This is how we render the specify to use Office Fabric, adjust the theme colors, and handle Markdown before rendering the card.", "selection": { "start": { "line": 123, "character": 4 }, "end": { "line": 133, "character": 1 } } }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 136, "description": "This is a generic handler to raise Adaptive Card actions back to the component's parent." }, { "file": "src/controls/AdaptiveCard/AdaptiveCard.tsx", "line": 197, "description": "This is pretty much a brute force method where we change the Adaptive Card's host configuration with the theme's colors. \r\n\r\nWe used trial and error to find what theme slots match which host configuration styles. \r\n\r\nWould love to get your feedback!" } ] }