@theroutingcompany/components 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # TRC TREX Component Library
2
2
 
3
+ View the [StoryBook](https://6392297e45ccab79e466ee19-iytnzjepcr.chromatic.com/).
4
+
3
5
  ## UI Libraries
4
6
 
5
7
  The component library is built on the following 'component primitives' UI libraries, low-level unstyled building blocks.
@@ -23,18 +25,255 @@ The approach is roughly:
23
25
  - All variant are placed in an object (a map but not a `Map()`)
24
26
  - The exported takes a `variant` prop and uses it to get the right styled component from the object map
25
27
 
28
+ ## Missing
29
+
30
+ This component library is very much a work in progress and has many gaps.
31
+
32
+ * A component that exposes the spacing design tokens in an easy-to-use, type-safe way. Usually this is called `Box`.
33
+ * Far from all components in the [Components Figma](https://www.figma.com/file/xfnqeuF8FgoqhJSUs5GTsK/PDS-Components-Desktop) have been implemented
34
+ * For existing component, we need more documentation. Often, design systems include a "Guidelines" or "When to Use" section" on the component doc page.
35
+ * Tests!
36
+
26
37
  ## Guiding Principles
27
38
 
28
- https://www.gabe.pizza/notes-on-component-libraries/
39
+ Partly inspired by these
29
40
 
30
- - For content, prefer composition over props
41
+ * [Notes on maintaining an internal React component library](https://www.gabe.pizza/notes-on-component-libraries/)
42
+ * [Component API Standards](https://jonambas.com/posts/component-api-standards)
43
+
44
+ ### For content, prefer composition over props
31
45
 
32
- - ✅ `<Text variant="body">Some text</Text>`
33
46
  - ❌ `<Text variant="body" text="Some text" />`
47
+ - ✅ `<Text variant="body">Some text</Text>`
48
+
49
+ ### Prefer `compound components` over one large component with many props
50
+
51
+ Similar to last point. Compound components scale better.
52
+
53
+
54
+ ```jsx
55
+ <AlertDialog
56
+ title="Header"
57
+ description="Optional description"
58
+ cancelButtonText="Close"
59
+ onCancel={() => {}}
60
+ confirmButtonText="Delete"
61
+ confirmButtonVariant="primary"
62
+ onDelete={() => {}}
63
+ // ... and so on
64
+ >
65
+ <Text type='body'>
66
+ Powering the next generation of transit We help build more sustainable
67
+ cities with convenient and reliable transit for all
68
+ </Text>
69
+ </AlertDialog>
70
+ ```
71
+
72
+
73
+ ```jsx
74
+ <AlertDialog>
75
+ <AlertDialogTrigger asChild>
76
+ <Button>Open dialog</Button>
77
+ </AlertDialogTrigger>
78
+ <AlertDialogContent size={size}>
79
+ <AlertDialogTitle>Header</AlertDialogTitle>
80
+ <AlertDialogDescription>Optional description</AlertDialogDescription>
81
+ <Text type='body'>
82
+ Powering the next generation of transit We help build more sustainable
83
+ cities with convenient and reliable transit for all
84
+ </Text>
85
+ <AlertDialogFooter>
86
+ <AlertDialogCancel asChild>
87
+ <Button size='large' variant='primary' emphasis='medium'>
88
+ Close
89
+ </Button>
90
+ </AlertDialogCancel>
91
+ <AlertDialogAction asChild>
92
+ <Button size='large' variant='danger'>
93
+ Delete
94
+ </Button>
95
+ </AlertDialogAction>
96
+ </AlertDialogFooter>
97
+ </AlertDialogContent>
98
+ </AlertDialog>
99
+ ```
100
+
101
+ ### Prefer React Context for components that depend on each other
102
+
103
+ See [Most of the time, it’s a good idea to use React context for components that depend on each other.](https://www.gabe.pizza/notes-on-component-libraries/#most-of-the-time-its-a-good-idea-to-use-react-context-for-components-that-depend-on-each-other) for an example. This is also how Radix does it.
104
+
105
+ <figure>
106
+ > [T]he context should be kept internal to the library. Allowing the naked context to be imported and handled by applications creates a brittle coupling that will easily break in future upgrades.
107
+ <figcaption>
108
+ <cite>
109
+ <a href="https://www.gabe.pizza/notes-on-component-libraries/#most-of-the-time-its-a-good-idea-to-use-react-context-for-components-that-depend-on-each-other">Notes on maintaining an internal React component library
110
+ — Most of the time, it’s a good idea to use React context for components that depend on each other.</a>
111
+ </cite>
112
+ </figcaption>
113
+ </figure>
114
+
115
+ ### Avoid the `React.Children` API and `React.cloneElement`, prefer React Context
116
+
117
+ Avoid the Children API and `cloneElement`.
118
+
119
+ The Children API is a <q>leaky abstraction</q> and in [maintenance mode](https://github.com/reactjs/rfcs/pull/61#issuecomment-431247764).
120
+ <small>At the moment it's only used in the breadcrumbs component.</small>
121
+
122
+ The [React docs](https://beta.reactjs.org/reference/react/cloneElement#cloneelement) discourages the use of `cloneElement` because <q cite="https://beta.reactjs.org/reference/react/cloneElement#cloneelement">Cloning children makes it hard to tell how the data flows through your app.</q> and <q cite="https://beta.reactjs.org/reference/react/cloneElement#cloneelement">Using cloneElement is uncommon and can lead to fragile code</q>..
123
+
124
+
125
+ ### Don't rename HTML attributes
126
+
127
+ <figure>
128
+ > Native attributes or common props, such as `className`, `id` or `onClick`, should not be renamed. Don't force your engineers to learn APIs they already know.
129
+ <figcaption>
130
+ <cite>
131
+ <a href="https://www.jonambas.com/posts/component-api-standards">React Component API Standards — Native Attributes</a>
132
+ </cite>
133
+ </figcaption>
134
+ </figure>
135
+
136
+ - ❌ `<TextInput isDisabled />`
137
+ - ✅ `<TextInput disabled />`
138
+
139
+ It is unfortunate that react-aria breaks with this principle. Therefore we have to rename boolean props before passing them to react-aria's hooks, usually prefix them with `is-`, and the reverse, remove the prefixes from the types.
140
+
141
+ ### Use design tokens where possible
142
+
143
+ Using design tokens consistently will make it easier to change values at scale in the future.
144
+
145
+ - ❌ `color: black;`
146
+ - ✅ `color: ${tokens.color_black};`
147
+
148
+ ## Prefer meaningful tokens
149
+
150
+ For example, if we ever decide to implement dark mode, meaningfully-named tokens will make this switch easier.
151
+
152
+ - ❌ `color: ${tokens.color_black};`
153
+ - ✅ `color: ${tokens.tokens.color_text_strong};`
154
+
155
+ ### Use HSL colors
156
+
157
+ [HSL notation](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl) is more readable and more intuitive. Prefer it over other color notations like hex codes or `rgb()`
158
+
159
+ - ❌ `color: #4287f5;`
160
+ - ❌ `color: rgb(66, 135, 245);`
161
+ - ✅ `color: hsl(217deg 90% 61%);`
162
+
163
+ Prefer modern [`hsl()`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl) over `hsla()`. `hsla` is legacy syntax. Add the alpha channel at the end after a `/`.
164
+
165
+ - ❌ `color: hsla(217deg, 90%, 61%, 0.8);`
166
+ - ✅ `color: hsl(217deg 90% 61% / 0.8);`
167
+
168
+ Some reading material on this:
34
169
 
35
- - Don't rename
170
+ * [Why you should use HSL over other colour formats in your CSS.](https://sujansundareswaran.com/blog/why-hsl-is-better-than-hex-and-rgb)
171
+ * [Using HSL Colors In CSS](https://www.smashingmagazine.com/2021/07/hsl-colors-css/)
36
172
 
37
- TODO Expand
173
+ ## Style variants
174
+
175
+ Style styled-components usingg CSS variables defined in the component.
176
+
177
+ > **Warning**
178
+ > This is not settled and this pattern is not followed consistently (yet?).
179
+
180
+ See [The styled-components Happy Path](https://www.joshwcomeau.com/css/styled-components/)
181
+
182
+ ### Forward refs
183
+
184
+ <figure>
185
+ > Refs should always be forwarded, either to the outermost DOM element, or to the most applicable element of the component. For example form components should forward refs to `<input/>`.
186
+ <figcaption>
187
+ <cite>
188
+ <a href="https://www.jonambas.com/posts/component-api-standards">React Component API Standards — Refs</a>
189
+ </cite>
190
+ </figcaption>
191
+ </figure>
192
+
193
+ This is very important for components based on RadixUI and react-aria to work correctly.
194
+
195
+ <figure>
196
+ > All component parts that render a DOM element have an `asChild` prop. This is useful when you want a part to attach its accessibility and functional requirements onto your own element instead.
197
+ <figcaption>
198
+ <cite>
199
+ <a href="https://www.radix-ui.com/docs/primitives/overview/styling#changing-the-rendered-element">React Component API Standards — Changing the rendered element</a>
200
+ </cite>
201
+ </figcaption>
202
+ </figure>
203
+
204
+ For components based on react-aria that require a DOM ref, use `useObjectRef` hook from `@react-aria/utils` with the forwarded ref. See PR [Add a useObjectRef util](https://github.com/adobe/react-spectrum/pull/2293)
205
+
206
+ ### Prefer attribute selectors to style component states
207
+
208
+ Don't add classNames to style a component in a certain state (eg invalid, selected, disabled), use attribute selectors instead. Use `aria-` or custom `data-` attributes to add styles for states.
209
+
210
+ Prefer `~=` over `=`. `~=` matches <q cite="https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors#syntax">whitespace-separated list of words, one of which is exactly value</q>, whereas `=` matches an <q>attr whose value is exactly value</q>.
211
+ For compound states, e.g `date-state='selected on'` the latter will not work.
212
+
213
+ (I like to think of it like `[...strings.split(" ")].includes(value)`. vs `strings === value`)
214
+
215
+ - ❌ `[data-state='selected']`.
216
+ - ✅ `[data-state~='selected']`
217
+
218
+ Radix adds a custom attribute with the state automatically. The attribute names and values are listed on each component's doc page ([example](https://www.radix-ui.com/docs/primitives/components/toggle#root)).
219
+ For component built on react-aria, we need to add `data-` attribute ourselves.
220
+
221
+ Recommended reads:
222
+
223
+ - [Building a Button Part 1: Press Events](https://react-spectrum.adobe.com/blog/building-a-button-part-1.html)
224
+ - [Building a Button Part 2: Hover Interactions](https://react-spectrum.adobe.com/blog/building-a-button-part-2.html)
225
+ - [Building a Button Part 3: Keyboard Focus Behavior](https://react-spectrum.adobe.com/blog/building-a-button-part-3.html)
226
+
227
+ ### Prefer `:focus-visible` over `:focus`
228
+
229
+ Focus state styles should only be shown on keyboard interactions. Basically [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) is a smarter pseudo-selector that only shows the focus states with (not totally sure about that).
230
+
231
+ There are also a few react-aria hooks to handle these interaction state ([useFocus](https://react-spectrum.adobe.com/react-aria/useFocus.html), [useHover](https://react-spectrum.adobe.com/react-aria/useHover.html)), it's not totally clear to me yet what the benefit of these hooks are over plain CSS pseudo-selectors.
232
+
233
+ ### TypeScript only
234
+
235
+ > **Warning**
236
+ > Unfinished
237
+
238
+
239
+ Only write TypeScript files.
240
+ The linting config is also quite strict with `@typescript-eslint`.
241
+
242
+ ### Types of component props should be strong
243
+
244
+ Correct component types make it easier to use components without having to look at the source or example.
245
+ Exact types for props (for editor autocomplete) is a necessity, not a nice-to-have. Be as detailed as possible.
246
+
247
+ <figure>
248
+ > Avoid “stringly typed” code. Prefer more appropriate types where not every string is a possibility.
249
+ > Prefer a union of string literal types to string if that more accurately describes the domain of a variable. You’ll get stricter type checking and improve the development experience.
250
+ <figcaption>
251
+ <cite>
252
+ <a href="https://www.oreilly.com/library/view/effective-typescript/9781492053736/ch04.html#avoid-strings">Effective TypeScript - Prefer More Precise Alternatives to String Types</a>
253
+ </cite>
254
+ </figcaption>
255
+ </figure>
256
+ </figure>
257
+
258
+
259
+ - ❌ `type Variant = string;`
260
+ - ✅ `type Variant = 'primary' | 'secondary' | 'danger' | 'inverse';`
261
+
262
+ ### Avoid spreads on native JSX elements
263
+
264
+ > **Warning**
265
+ > This is a principle we don't currently abide by but should!
266
+
267
+ See [Avoiding JSX spread on foreign data prevents weird bugs sometimes.](https://www.gabe.pizza/notes-on-component-libraries/#avoiding-jsx-spread-on-foreign-data-prevents-weird-bugs-sometimes).
268
+
269
+ Two ways we can solve this
270
+
271
+ 1. Filter spread props. Reject all non-DOM props using a utility. Note react-aria has a util names `filterDOMProps` despite its name it does not filter DOM props (I think it's a legacy util).
272
+ 2. Be more explicit. Write out all the props to forward and types explicitly.
273
+
274
+ > I recommend, whenever possible, to destructure the props object and forward keys as needed. Breaking the props down removes excessive keys, allows setting defaults, and makes grepping the code easier.
275
+
276
+ One downside I see the #2 is that
38
277
 
39
278
  ## Examples
40
279
 
@@ -60,8 +299,7 @@ TODO Expand
60
299
 
61
300
  - [Apple Developer: Layout - Foundations - Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/foundations/layout/)
62
301
 
63
- - https://jonambas.com/posts/lessons-learned
64
- - [https://jonambas.com/posts/component-api-standards](https://jonambas.com/posts/component-api-standards)
302
+
65
303
 
66
304
  #### TypeScript
67
305