docs(widgets) Custom Widget Developer Guide#9304
docs(widgets) Custom Widget Developer Guide#9304chrisgervang wants to merge 24 commits intomasterfrom
Conversation
| {layers.filter(layer => ( | ||
| this.deck?.props.layerFilter({layer, viewport}) | ||
| )).map((layer) => { | ||
| <li key={layer.id}>{layer.id}</li> |
There was a problem hiding this comment.
Would it be much more code to show how control the layers in some way? For example, have a checkbox next to each layer to toggle visibility in that view?
There was a problem hiding this comment.
I can try it.. but controlling anything the user sets starts to get into a territory where user state and internal state can get out of sync. At least, there's nothing preventing user-space from just overriding any changes a widget makes to a layer. And there's some risk of introducing a race condition.
I think what this would look like with our current API is something like:
this.deck?.setProps({ layers: layers.map(layer => layer.clone({ visible: isVisible }) })
This could cause events to fire in the app that in-turn call setProps. Is there a way to draw the layers without alerting the user? Perhaps:
this.deck?._drawLayers('layer-list-widget', { layers: ... })
ibgreen
left a comment
There was a problem hiding this comment.
This is awesome work.
FWIW - One thing that I suspect will make widgets critical for me over the next year is the ability to use them in Python/pydeck. It could be a next step, making these available in python.
| /** | ||
| * Widget positioning within the view. Default: 'top-left'. | ||
| */ | ||
| placement?: WidgetPlacement; |
There was a problem hiding this comment.
consider exporting a set of base WidgetProps so that widget writers don't need to retype all of that?
| placement?: WidgetPlacement; | |
| export type WidgetProps = { | |
| id?: string; | |
| placement?: WidgetPlacement; | |
| viewId?: string | null; | |
| }; | |
| ... | |
| export type AwesomeWidgetProps = WidgetProps & { | |
| customText: string; | |
| } |
There was a problem hiding this comment.
I like the idea to encourage consistency, though it's still 100% up to the widget authors to decide how they implement this since we're only defining an interface.
| } | ||
| ``` | ||
|
|
||
| ## Best Practices |
There was a problem hiding this comment.
This section looks a little "lost" here at the very end of the page. Maybe lead with something like this before all the examples?. Or maybe the section will grow and it will look more natural.
|
|
||
| ## Handling View Interaction Events | ||
|
|
||
| A widget can update in response to a user interacting with the deck.gl view the widget is attached to. |
There was a problem hiding this comment.
This is easily the most important section and needs its own page IMHO. (I do understand that we have work to do here.)
There was a problem hiding this comment.
Say more? What kind of example would you like to see?
There was a problem hiding this comment.
I've been struggling to port the graph layers controller React component to a widget, I was looking for docs on how to implement zooms and pans
|
|
||
| Below is a comprehensive example demonstrating a layer list widget implemented using Preact for dynamic UI rendering: | ||
|
|
||
| ```tsx |
There was a problem hiding this comment.
We should really use MDX capabilities and make these widgets live on the pages...
There was a problem hiding this comment.
@Pessimistress suggested I can embed CodePen (e.g. LightingEffect) and found a react template too https://codepen.io/AdventureBear/pen/LYqwbwx
Co-authored-by: Ib Green <7025232+ibgreen@users.noreply.github.com>
Co-authored-by: Ib Green <7025232+ibgreen@users.noreply.github.com>
Co-authored-by: felixpalmer <felixpalmer@gmail.com>
| } | ||
| ``` | ||
|
|
||
| ##### Applying the deck.gl widget design system |
There was a problem hiding this comment.
Should applying the design system be it's own page?
There was a problem hiding this comment.
+1, the styling system is an important (top-level) part of your design!
Mutating the dom via ref is a react anti-pattern
ibgreen
left a comment
There was a problem hiding this comment.
This is getting quite good.
I believe that a couple of iterative passes to make this even more logical and incremental to readers and would improve it further.
I added some suggestions to show what I mean.
| Define a prop for adding a CSS class | ||
|
|
||
| ```ts | ||
| interface AwesomeWidgetProps { |
There was a problem hiding this comment.
Total nit: Maybe tone it down somewhat and call it CustomWidget? "Awesome" seems a bit out of style with rest of the docs.
| @@ -0,0 +1,77 @@ | |||
| # Writing Your Own Widget | |||
|
|
|||
| ## Preparations | |||
There was a problem hiding this comment.
| ## Preparations | |
| ## Preliminaries |
|
|
||
| * **[Implement a universal widget](./universal-widgets.md)** - A "universal widget" is a widget compatible with any deck.gl application and is UI framework agnostic. This is the best option for developing widgets intended to work across the deck.gl ecosystem. | ||
| * **[Use Preact in a universal widget](./preact-widgets.md)** - Preact is a lightweight virtual DOM library commonly used to implement dynamic widget UI. It enables you to create highly interactive widgets without tightly coupling their internals to an application’s UI framework. | ||
| * **[Wrap widgets in a React component](./react-widgets.md)** - If you are developing a custom Widget for a React application, you can use React to build the UI. This approach allows you to use React components and can coexist alongside other widgets. |
There was a problem hiding this comment.
These bullets do not fully explain the situation the way I see it.
It seems to me that there are two types of widgets - "universal" and "react".
| * **[Wrap widgets in a React component](./react-widgets.md)** - If you are developing a custom Widget for a React application, you can use React to build the UI. This approach allows you to use React components and can coexist alongside other widgets. | |
| - universal widgets can be 1) used in React apps 2) wrapped into React widgets, but the reverse is not true. | |
| For React specifically, you have several options: | |
| - You can use the universal widgets by supplying them to the `<DeckGL widgets={[new Widget()]} />` prop. | |
| - You can wrap universal components into React components using the `useWidget()` hook. This way you can specify your components using JSX syntax.. | |
| - If you are creating new components, can also create your own React components that implement the DeckGL widget interface. The advantage is that you write your code in the same style as the rest of your React application, however, these components would not be reusable in non-React applications.``` |
There was a problem hiding this comment.
Good point. Even calling it "react" doesn't really say what this is.. it's fine, but people could use other frameworks, in theory.
Really, they're making the choice between implementing UI within the widget class, or outside of it.
Do any of these terms pair better? "universal", "internal", or "portable" for UI within the widget.
"react", "external", or "BYOF" (bring your own framework) for UI injected into the widget class.
| @@ -0,0 +1,215 @@ | |||
| # Wrapping Widgets with React Components | |||
There was a problem hiding this comment.
| # Wrapping Widgets with React Components | |
| # React Widgets | |
| ## Wrapping Widgets with React Components |
| } | ||
| ``` | ||
|
|
||
| ##### Applying the deck.gl widget design system |
There was a problem hiding this comment.
+1, the styling system is an important (top-level) part of your design!
|
|
||
| Widgets in deck.gl allow developers to create custom UI elements that are deeply integrated into the deck.gl rendering system. This guide covers the steps to implement widgets that are framework-agnostic, ensuring compatibility across various applications. | ||
|
|
||
| ## Implementing the Widget Lifecycle Functions |
There was a problem hiding this comment.
It could be worth having a separate first page describing the widget lifecycle and interface before listing all the sundry ways of implementing this lifecycle/interface.
| @@ -0,0 +1,374 @@ | |||
| # Universal Widgets | |||
|
|
|||
| Widgets in deck.gl allow developers to create custom UI elements that are deeply integrated into the deck.gl rendering system. This guide covers the steps to implement widgets that are framework-agnostic, ensuring compatibility across various applications. | |||
There was a problem hiding this comment.
I would move the first sentence into an introductory page (about-widgets.md).
| Widgets in deck.gl allow developers to create custom UI elements that are deeply integrated into the deck.gl rendering system. This guide covers the steps to implement widgets that are framework-agnostic, ensuring compatibility across various applications. | |
| This guide covers the steps to implement widgets that are "universal" or framework-agnostic, ensuring compatibility across various applications. | |
| (Widgets in deck.gl allow developers to create custom UI elements that are deeply integrated into the deck.gl rendering system. ) |
|
|
||
| ### Adding a Widget | ||
|
|
||
| [`onAdd({deck, viewId}): HTMLElement?`](../../api-reference/core/widget.md#onadd) - This method provides deck.gl with the root DOM element of your widget. This element is positioned based on `placement` and `viewId` members. |
There was a problem hiding this comment.
This is a lifecycle method, Deck.gl calls this method at some point?
There was a problem hiding this comment.
Yes, it's called when the widget is first added.
Co-authored-by: Ib Green <7025232+ibgreen@users.noreply.github.com>
Co-authored-by: Ib Green <7025232+ibgreen@users.noreply.github.com>
| onRedraw({layers}: {layers: Layer[]}) { | ||
| this.layers = layers; | ||
| this.update(); | ||
| } |
There was a problem hiding this comment.
@Pessimistress one thing I noticed is this layers arg includes all sub-layers in a flattened list. While that could be useful sometime, I imagine most widgets would want to display state from the top-level layers. Is there a way to access this aside from deck.props.layers?
For #7946
Background
Adding developer guide to include more advanced examples about how to write both react and non-react widgets. This way our getting-started examples can be very simple, and we can have something to point more advanced users to when they're writing their own widgets.
Change List