[RFC] Utility/Patterns Components Proposal
See original GitHub issueHi all! 👋 With some of the updates coming into React, like Suspense, I thought it might be interesting to think about how we could start exposing some utility/pattern components for things like fallbacks, external links, and more. I wanted to take a moment to document what kind of components we could start introducing, why they could be useful, and their high-level API design. Can’t wait to hear your thoughts!
<RootFallback>
When developing applications using suspense, the pattern should be to add loaders from the highest level to the lowest level. This is intended to make sure that loaders are provided for all cases, and then progressive loaders are added in to improve the user experience. It would be cool if we could provide that <RootFallback>
that handles capturing suspense at the top-level of an app. The implementation could just be our <Loading>
component, which is to say:
function App() {
return (
<RootFallback>
{/* write your application code */}
</RootFallback>
);
}
// RootFallback.js
function RootFallback({ children, ...rest }) {
return (
<Suspense {...rest} fallback={<Loading />}>
{children}
</Suspense>
)
}
This strategy would go well in accompanying our skeletons for progressively enhancing the loading stages of applications built using Carbon.
<ExternalLink>
Would be a generic wrapper for <a rel="noopener noreferrer">
, could wrap our <Link>
internally.
<AssistiveText>
Would be a generic wrapper for the <span class="bx--assistive-text"></span>
pattern to allow folks to more easily add content for screenreaders in parts of their application without exposing the underlying implementation detail (e.g. the class).
<Menu>
, <MenuBar />
Would be awesome if we could provide generic wrappers for Menu’s and Menubar’s that support proper focus management and keyboard patterns.
<I18nProvider>
As we make a push for first-class globalization, we should see if we could create Context providers for messages to make it easier to globalize an application at the top-level instead of passing in messages per-component. However, we could still use this provider to customize messages per-components, if needed.
Hooks
With the introduction of hooks, it’d be interesting if we could expose common stateful patterns, or at the very least incorporate them so that individuals could receive updates. This would be most helpful for things like <DataTable>
where we could change our signature to be:
function Example() {
const [updater /* reducer? */, onStateChange, stateTypes] = useDataTable(initialState);
const [myState, mySetState] = useState();
onStateChange(state => {
// Use `mySetState` in some way
// `state` may have fields like `type` to use switch on
switch (state.type) {
case stateTypes.sort:
// ...
default:
}
});
return (
<DataTable updater={updater}>
{/* ... */}
</DataTable>
);
}
react-cache
For some of our data-intensive applications, it would interesting if we could have them require a resource
from the react-cache
project instead of passing in items directly. This way we could more easily interop with things like <Suspense>
for data that needs to be fetched in things like <DataTable>
. Essentially, exposing this pattern could allow us to create async versions of a lot of our components, provided we provide the appropriate fallbacks using <Suspense>
.
Inside of each component, we would just call resource.read()
with the index, or potentially a custom prop function for getting the ID from an index. This allows us to write code synchronously that could refer to an in-memory access, or network request, and provide a fallback for network requests using <Suspense>
.
For <DataTable>
, this could look like:
const RowItemResource = createResource(index => {
// Given an index, can correspond to cursors or offsets for REST or GraphQL endpoints
});
function MyApp() {
// Top-level suspense, but could provide row or page-level suspense, as well
return (
<Suspense fallback={<DataTableSkeleton />}>
<DataTable resource={RowItemResource}>
{/* ... */}
</DataTable>
</Suspense>
);
}
<Grid>
Provides <Grid>
, <Row>
, and <Column>
helpers to use alongside the elements grid.
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
I think part of this is asking ourselves if we want them together, or not. Definitely understand wanting a
carbon-addons-product
-type thing with product helpers 👍Thanks @joshblack for bringing up many interesting proposals! In the list of your proposed components/notions I can see two groups in them:
<AssistiveText>
and<Grid>
)Great to maintain the latter in a separate library, as it would be a pattern using React in general, instead of just
carbon-components-react
. Thanks!