Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document @wordpress/components structure #33111

Open
1 of 3 tasks
Tracked by #34304
sarayourfriend opened this issue Jun 30, 2021 · 15 comments
Open
1 of 3 tasks
Tracked by #34304

Document @wordpress/components structure #33111

sarayourfriend opened this issue Jun 30, 2021 · 15 comments
Assignees
Labels
[Feature] Component System WordPress component system [Status] In Progress Tracking issues with work in progress [Type] Developer Documentation Documentation for developers [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues.

Comments

@sarayourfriend
Copy link
Contributor

sarayourfriend commented Jun 30, 2021

What problem does this address?

@wordpress/components is a package with roughly two (maybe even three, but I'm not sure) "levels" of components:

  1. First, we have the "UI primitives" like Tooltip, Button, Text, and Popover/Flyout, etc. These are the primitives that we build the second type out of
  2. Second, we have "UI blocks" (please help me think of a better name that isn't confusing in a Gutenberg context) like ColorPicker, AnglePickerControl, AlignmentMatrixControl, etc.

Currently there is zero delineation between these two types of components. For block developers and other consumers of @wordpress/components this means there's no clear guidance as far as which components to use and when. Furthermore, there's no guidance around where and when to use things like the i18n library for default values.

On a very basic level, UI primitives are usually more complicated to use/have many more props, whereas UI blocks usually have very few props (probably an onChange, value, and some other minor configuration props). UI blocks also often times contain translated text, whereas UI primitives most often do not (instead opting for labels and other text to be passed in as props).

Documenting the difference between these two styles of components and classifying each of the components in @wordpress/components under one or the other could help future developers understand expectations as far as what technologies to use in each instance (particularly around i18n). It could also help consumers of @wordpress/components understand how to best utilize the library. If they just want to build an app with all new UI that looks and feels like WordPress but isn't powered by other WordPress technologies like @wordpress/i18n, then they can stick to the primitives alone and not worry about also having to adopt a whole new i18n solution. If they're working inside a WordPress environment already, then they can use the blocks as well to achieve seamless integration with Gutenberg.

What is your proposed solution?

Document the above differences:

  • First classify each existing component in a table in this issue
  • Next update the READMEs for each component to reflect this, picking a standardized callout similar to the experimental callout explaining whether the component is a UI primitive or UI block.
  • Finally decide on rules for each type of component (like whether we can/should use i18n) and then update this issue to track the progress
@sarayourfriend sarayourfriend added [Status] In Progress Tracking issues with work in progress [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues. [Feature] Component System WordPress component system labels Jun 30, 2021
@sarayourfriend
Copy link
Contributor Author

sarayourfriend commented Jun 30, 2021

Component name Type (UI primitive/UI block)
AlignmentMatrixControl UI Block
AnglePickerControl UI Block
Animate utils
Autocomplete UI primitive
BaseControl UI primitive
BaseField UI primitive
BoxControl UI block
Button UI primitive
ButtonGroup UI primitive
Card UI primitive
CheckboxControl UI primitive
ColorEdit UI block
ColorIndicator UI primitive
ColorListPicker UI primitive
ColorPalette UI block
ColorPicker UI block
ComboboxControl UI block
ControlGroup UI primitive
ControlLabel UI primitive
CustomGradientPicker UI block
CustomSelectControl UI primitive
DashIcon UI primitive
DateTime UI block
DimensionControl UI block
Disabled utils
Divider UI primitive
Draggable utils
DropZone UI block
Dropdown UI primitive
DropdownMenu UI primitive
DuotonePicker UI block
Elevation UI primitive
ExternalLink UI block
Flex UI primitive
Flyout UI primitive
FocalPointPicker UI block
FocusableIframe UI primitive
FontSizePicker UI block
FormGroup UI primitive
FormFileUpload UI primitive
FormToggle UI primitive
FormTokenField UI block
GradientPicker UI block
Grid UI primitive
Guide UI block
HStack UI primitive
Heading UI primitive
Icon UI primitive
InputControl UI primitive
IsolatedEventContainer UI block
ItemGroup UI primitive
KeyboardShortcuts UI primitive
MenuGroup UI primitive
MenuItem UI primitive
MenuItemsChoice UI primitive
Modal UI primitive
NavigableContainer UI primitive
Navigation UI primitive
Notice UI primitive
NumberControl UI primitive
Panel UI primitive
Placeholder UI block
Popover UI primitive
QueryControls UI block
Radio UI primitive
RadioControl UI primitive
RadioGroup UI primitive
RangeControl UI primitive
ResizableBox UI primitive
ResponsiveWrapper UI primitive
Sandbox UI primitive
ScrollLock UI primitive
Scrollable UI primitive
SelectControl UI primitive
Shortcut UI primitive
SlotFill UI primitive
Snackbar UI block
Spacer UI primitive
Spinner UI primitive
StyleProvider utils
Surface UI primitive
Swatch UI block
TabPanel UI block
Text UI primitive
TextControl UI primitive
TextHighlight UI primitive
TextareaControl UI primitive
Tip UI block
ToggleControl UI primitive
Toolbar UI block
Tooltip UI primitive
TreeGrid UI block
TreeSelect UI block
Truncate UI primitive
UnitControl UI primitive
VStack UI primitive
View UI primitive
VisuallyHidden UI primitive
ZStack UI primitive

@sarayourfriend
Copy link
Contributor Author

@ciampo When you have time to review my indications, please do! Thanks!

@ciampo
Copy link
Contributor

ciampo commented Jul 7, 2021

Hey @sarayourfriend, I agree with your proposal of splitting the components into "low-level" UI primitives and "high-level" UI blocks, but I'm finding it hard to draw a line between the 2 groups.

I also compared the list from your comment above against the contents of packages/components/ and against the docs manifest (docs/manifest.json).

A few components seem to be missing:

  • DashIcon (found in packages/components/src/dashicon), although it doesn't have any JSDoc / README
  • Icon (found in packages/components/src/icon)

Finally, while reviewing your work I took some notes and prepared the following questions:

  • Should we aim at documenting web and native, or just web (e.g components, like ColorControl, FooterMessageControl, and the whole packages/components/src/mobile folder)?
  • Should we document HoCs from the footer-message-control folder?
  • Should we mention non-UI components that are still exported (like StyleProvider, RadioContext, ToolbarContext)?
  • Should we document re-exports from Reakit? (like the contents of packages/components/src/composite/ and packages/components/src/disclosure/ )
  • Should we document sub-components too? (e.g Card, Flex, Toolbar, Navigation, ...)
  • Should we document experimental components?
  • The list you wrote current features some "unpromoted" components (i.e. in the ui/ folder, like ControlGroup ControlLabel FormGroup ItemGroup) — should they be listed?
  • Should we refactor the folder structure for Toolbar and its subcomponents, so that its subcomponent are all within the same parent directory? (lie we did for flex, card...)
  • Some of the components listed in this PR don't have a README file, which would make it quite hard for a user of this library to use them appropriately: CircularOptionPicker, ColorEdit, ColorListPicker, ControlGroup, ControlLabel, CustomGradientPicker, FormGroup, GradientPicker, ItemGroup, Radio, Shortcut, Swatch, Tip, and View
  • Should we list internal components, i.e. components that are not exported (e.g. CustomGradientBar, ResizeTooltip, CircularOptionPicker)?
  • Should we list deprecated components?

@sarayourfriend
Copy link
Contributor Author

Should we aim at documenting web and native, or just web (e.g components, like ColorControl, FooterMessageControl, and the whole packages/components/src/mobile folder)?

I think we should focus on web first, just to keep it with what we're already familiar with at least. Native can follow the lead once we've hammered out the details for the web components, which is already a big task.

Should we document HoCs from the footer-message-control folder?

I don't think so, they're just HoCs.

Should we mention non-UI components that are still exported (like StyleProvider, RadioContext, ToolbarContext)?

StyleProvider should be mentioned as a primitive or maybe one of the "in between/utility" ones (I think there's a few of these, maybe Draggable and Disabled count as these as well)

Should we document re-exports from Reakit? (like the contents of packages/components/src/composite/ and packages/components/src/disclosure/ )

I don't think we should document anything we don't have control over.

Should we document sub-components too? (e.g Card, Flex, Toolbar, Navigation, ...)

I don't think we'll find that the sub-components are different than the parents. They work together. If Card is a UI Primitive, all of its related components are primitives as well.

Should we document experimental components?

I believe that we are 🙂

The list you wrote current features some "unpromoted" components (i.e. in the ui/ folder, like ControlGroup ControlLabel FormGroup ItemGroup) — should they be listed?

They'll eventually be moved out of that folder so I believe yes they should be.

Should we refactor the folder structure for Toolbar and its subcomponents, so that its subcomponent are all within the same parent directory? (lie we did for flex, card...)

We don't refactor just to refactor, I think we should leave it alone.

Some of the components listed in this PR don't have a README file, which would make it quite hard for a user of this library to use them appropriately: CircularOptionPicker, ColorEdit, ColorListPicker, ControlGroup, ControlLabel, CustomGradientPicker, FormGroup, GradientPicker, ItemGroup, Radio, Shortcut, Swatch, Tip, and View

We can open a separate task for those.

View however is internal and should not have a README.

Should we list internal components, i.e. components that are not exported (e.g. CustomGradientBar, ResizeTooltip, CircularOptionPicker)?

No. This is meant to document the external structure of the package to make it easier for block developers to know what to use.

Should we list deprecated components?

Probably we shouldn't spend time on deprecated components.

@ciampo
Copy link
Contributor

ciampo commented Jul 7, 2021

Thank you for clarifying! I went ahead and added Icon and DashIcon to your WIP list in the comment above

I don't think so, they're just HoCs.

Makes sense. The same should apply for the contents of packages/components/src/higher-order/

StyleProvider should be mentioned as a primitive or maybe one of the "in between/utility" ones (I think there's a few of these, maybe Draggable and Disabled count as these as well)

Yes, we should probably create a third category for "non-UI" utils.

I don't think we'll find that the sub-components are different than the parents. They work together. If Card is a UI Primitive, all of its related components are primitives as well.

I agree with that, I was just wondering if, when listing a component (e.g. Card), we should also mention the subcomponents (e.g. CardHeader, CardBody, ...), maybe within the same line / table cell

We can open a separate task for those.

I went ahead and created #33263 to track this task

No. This is meant to document the external structure of the package to make it easier for block developers to know what to use.

Makes sense — I believe that CircularOptionPicker should be removed from your WIP list above.

Probably we shouldn't spend time on deprecated components.

If we are not listing deprecated components, I believe we should also remove ClipboardButton from your WIP list above

@sarayourfriend
Copy link
Contributor Author

Great! I update the list to call out some things I think are utils. Do you mind having another review of it?

@ciampo
Copy link
Contributor

ciampo commented Jul 8, 2021

The list looks good! I'm just still having a hard time finding a clear way to define UI primitives vs UI blocks

@ryanwelcher
Copy link
Contributor

@sarayourfriend is there work to be done for this issue?

Related: #48998

@sarayourfriend
Copy link
Contributor Author

I'm not sure, I haven't been involved in Gutenberg or wp/components development for some time now. @mirka or @ciampo would know better what work is necessary for this issue.

@ciampo
Copy link
Contributor

ciampo commented Apr 11, 2023

Hey @ryanwelcher , this is still something that we'd like to explore at some point.

Perhaps, as we look into rewriting some of our components using headless component libraries, we could tidy the package up a bit — which would also include documenting its structure after the tidy up.

@chad1008
Copy link
Contributor

👋 I'm planning on picking up some of this work to move the project forward, and wanted to share some initial thoughts (mostly so Future Me has somewhere to find them 😆 ). Thank you for laying such a solid foundation @sarahmonster, that list you made is a huge head start.

Second, we have "UI blocks" (please help me think of a better name that isn't confusing in a Gutenberg context)

Two potential alternatives:

  • UI Elements
  • UI Modules

Knowing the list on this issue is already a couple of years old, I've gone through to check for any new or moved components that need to be added. I didn't find a ton, but here they are, with how I'd classify them. If that makes sense (cc @ciampo), I can add them to the official list above.

Component name Type (UI primitive/UI block)
BorderBoxControl UI Primitive
BorderControl UI Primitive
ConfirmDialog UI Block
Navigator UI Block
PaletteEdit UI Block
Theme utils
ToggleGroupControl UI Primitive
ToolsPanel UI Block

My logic/reasoning on which of those belongs in which category may not be rock solid, and it's likely something that will shift as this work continues and we formalize the differences and definitions, but if anyone has strong opinions before I add them to the main list above, please let me know!

Items I'm planning to remove from the list:

@mirka
Copy link
Member

mirka commented May 12, 2023

Adding my thoughts before we continue 🙂

Groupings

Assuming that the point of these groupings is to help a developer find what they need, I don't think that a low-level/high-level classification is necessarily the best way. It can be difficult to predict whether a thing you're looking for is primitive or composed if you have no idea how they're implemented.

One iterative approach I might suggest is to not try and classify everything all at once, but to identify a group of commonly used components and start with that. For example, make a group for the "Controls" (aka "Inputs" or "Forms"). We can take inspiration from Chakra or MUI for more common groupings.

Just having this one grouping will already make life easier for the vast majority because most devs are looking for form components.

How the groupings are manifested

I suggest we start by expressing these groupings only in the Storybook, not in actual codebase folder structure or readme files. This will help us stay agile with our groupings, since we will likely find better ways of classification as things change. Our efforts here should be as low-stakes as possible, rather than high-stakes commitment to a classification system set in stone.

Experimental components

As we start doing functional groupings in the Storybook, I think we should remove the "Experimental" grouping and instead suffix the experimental components with a 🧪 emoji.

@chad1008
Copy link
Contributor

That sounds logical to me, but I'll hold off on actually grouping things until we've had a chance to discuss further. I do really like the idea of moving experimental components into the groupings they'd naturally exist in and just highlighting/labelling them individually as experiments. That will make them much easier to identify and locate!

One question that I know was raised in the individual issue was guidance on how to use or interact with a given component, specifically in terms of i18n. If we find that the recommendations for this aren't something we can apply at a categoric level, it might be worth considering a callout in the README files of specific components that highlights how translations are or should be handled.

@ciampo
Copy link
Contributor

ciampo commented May 18, 2023

For the short term, I agree with @mirka 's suggestion to work iteratively and:

  • start identifying some groups (ie. controls)
  • group them only in storybook (ie. not through folders)
  • remove the "experimental" storybook group and replace it with a 🧪 icon

We can discuss those new groupings directly in this issue.

In the long term, I'd like to find a better way to showcase the offering of components to consumers of the package. There are many ways to achieve this, and low-level primitives vs high-level block is just one of them.

In the future, I'd also like to investigate further how we document our components. One idea that I have in mind is to use Storybook as our canonical way to publish documentation, and then find a way to mirror the same information in READMEs (maybe by statically exporting the Storybook docs pages?).

One question that I know was raised in the individual issue was guidance on how to use or interact with a given component, specifically in terms of i18n

We could start by adding a section in the package's README about it?

At a high level, it sounds like the topics to cover would be:

  • Most components expect text to be passed from their consumers as React props. In order to ensure proper translation of those pieces of text, developers should tag them for translation. In the context of Gutenberg, they could use the @wordpress/i18n package, or otherwise use a different i18n solution.
  • Explain that some components include hardcoded translated text, which is internally wrapped in calls to utilities from the @wordpress/i18n package. This also means that, if consumers of this library are not using WordPress technology such as the @wordpress/i18n package, such components won't show the translated text correctly.

(Although this would definitely need to get fact-checked)

@mirka
Copy link
Member

mirka commented Jan 26, 2024

remove the "experimental" storybook group and replace it with a 🧪 icon

Here are some ideas to maintain existing permalinks when moving everything out of the "experimental" grouping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Component System WordPress component system [Status] In Progress Tracking issues with work in progress [Type] Developer Documentation Documentation for developers [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues.
Projects
None yet
Development

No branches or pull requests

6 participants