@guardian/stand 0.0.5 → 0.0.7

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.
Files changed (83) hide show
  1. package/README.md +445 -7
  2. package/dist/{byline → components/byline}/Byline.cjs +5 -5
  3. package/dist/{byline → components/byline}/Byline.js +5 -5
  4. package/dist/components/byline/styles.cjs +266 -0
  5. package/dist/components/byline/styles.js +256 -0
  6. package/dist/components/tag-picker/TagAutocomplete.cjs +107 -0
  7. package/dist/components/tag-picker/TagAutocomplete.js +26 -0
  8. package/dist/components/tag-picker/TagTable.cjs +203 -0
  9. package/dist/components/tag-picker/TagTable.js +91 -0
  10. package/dist/components/tag-picker/styles.cjs +198 -0
  11. package/dist/components/tag-picker/styles.js +185 -0
  12. package/dist/components/util.cjs +19 -0
  13. package/dist/components/util.js +17 -0
  14. package/dist/index.cjs +16 -1
  15. package/dist/index.js +8 -1
  16. package/dist/styleD/build/css/css/base/colors.css +122 -0
  17. package/dist/styleD/build/css/css/base/typography.css +43 -0
  18. package/dist/styleD/build/css/css/component/byline.css +36 -0
  19. package/dist/styleD/build/css/css/component/tagAutocomplete.css +23 -0
  20. package/dist/styleD/build/css/css/component/tagTable.css +39 -0
  21. package/dist/styleD/build/css/css/semantic/colors.css +27 -0
  22. package/dist/styleD/build/css/css/semantic/typography.css +138 -0
  23. package/dist/styleD/build/typescript/base/colors.cjs +144 -0
  24. package/dist/styleD/build/typescript/base/colors.js +142 -0
  25. package/dist/styleD/build/typescript/base/typography.cjs +65 -0
  26. package/dist/styleD/build/typescript/base/typography.js +63 -0
  27. package/dist/styleD/build/typescript/component/byline.cjs +42 -0
  28. package/dist/styleD/build/typescript/component/byline.js +40 -0
  29. package/dist/styleD/build/typescript/component/tagAutocomplete.cjs +29 -0
  30. package/dist/styleD/build/typescript/component/tagAutocomplete.js +27 -0
  31. package/dist/styleD/build/typescript/component/tagTable.cjs +53 -0
  32. package/dist/styleD/build/typescript/component/tagTable.js +51 -0
  33. package/dist/styleD/build/typescript/semantic/colors.cjs +37 -0
  34. package/dist/styleD/build/typescript/semantic/colors.js +35 -0
  35. package/dist/styleD/build/typescript/semantic/typography.cjs +462 -0
  36. package/dist/styleD/build/typescript/semantic/typography.js +460 -0
  37. package/dist/styleD/utils/semantic/typography.cjs +29 -0
  38. package/dist/styleD/utils/semantic/typography.js +26 -0
  39. package/dist/types/components/byline/Byline.d.ts +83 -0
  40. package/dist/types/components/byline/styles.d.ts +13 -0
  41. package/dist/types/components/byline/theme.d.ts +3 -0
  42. package/dist/types/components/tag-picker/TagAutocomplete.d.ts +117 -0
  43. package/dist/types/components/tag-picker/TagTable.d.ts +126 -0
  44. package/dist/types/components/tag-picker/example-tags.d.ts +2 -0
  45. package/dist/types/components/tag-picker/styles.d.ts +16 -0
  46. package/dist/types/components/tag-picker/types.d.ts +65 -0
  47. package/dist/types/{byline → components}/util.d.ts +1 -0
  48. package/dist/types/index.d.ts +26 -2
  49. package/dist/types/styleD/build/typescript/base/colors.d.ts +144 -0
  50. package/dist/types/styleD/build/typescript/base/typography.d.ts +65 -0
  51. package/dist/types/styleD/build/typescript/component/byline.d.ts +42 -0
  52. package/dist/types/styleD/build/typescript/component/tagAutocomplete.d.ts +29 -0
  53. package/dist/types/styleD/build/typescript/component/tagTable.d.ts +53 -0
  54. package/dist/types/styleD/build/typescript/semantic/colors.d.ts +37 -0
  55. package/dist/types/styleD/build/typescript/semantic/typography.d.ts +462 -0
  56. package/dist/types/styleD/stories/base/Typography.d.ts +1 -0
  57. package/dist/types/styleD/stories/base/storybookColorPalette.d.ts +19 -0
  58. package/dist/types/styleD/stories/semantic/TypographyPresets.d.ts +1 -0
  59. package/dist/types/styleD/utils/semantic/typography.d.ts +16 -0
  60. package/dist/types/styleD/utils/semantic/typography.test.d.ts +1 -0
  61. package/package.json +68 -22
  62. package/dist/byline/styles.cjs +0 -244
  63. package/dist/byline/styles.js +0 -234
  64. package/dist/types/byline/Byline.d.ts +0 -17
  65. package/dist/types/byline/styles.d.ts +0 -11
  66. package/dist/types/byline/theme.d.ts +0 -44
  67. /package/dist/{byline → components/byline}/Preview.cjs +0 -0
  68. /package/dist/{byline → components/byline}/Preview.js +0 -0
  69. /package/dist/{byline → components/byline}/lib.cjs +0 -0
  70. /package/dist/{byline → components/byline}/lib.js +0 -0
  71. /package/dist/{byline → components/byline}/placeholder.cjs +0 -0
  72. /package/dist/{byline → components/byline}/placeholder.js +0 -0
  73. /package/dist/{byline → components/byline}/plugins.cjs +0 -0
  74. /package/dist/{byline → components/byline}/plugins.js +0 -0
  75. /package/dist/{byline → components/byline}/schema.cjs +0 -0
  76. /package/dist/{byline → components/byline}/schema.js +0 -0
  77. /package/dist/types/{byline → components/byline}/Preview.d.ts +0 -0
  78. /package/dist/types/{byline → components/byline}/contributors-fixture.d.ts +0 -0
  79. /package/dist/types/{byline → components/byline}/lib.d.ts +0 -0
  80. /package/dist/types/{byline → components/byline}/lib.test.d.ts +0 -0
  81. /package/dist/types/{byline → components/byline}/placeholder.d.ts +0 -0
  82. /package/dist/types/{byline → components/byline}/plugins.d.ts +0 -0
  83. /package/dist/types/{byline → components/byline}/schema.d.ts +0 -0
package/README.md CHANGED
@@ -4,21 +4,459 @@ _Find what you need on the (news)stand!_
4
4
 
5
5
  Stand is component library for Guardian editorial tools. It is co-located within flexible-content as Composer is expected to be the main consumer of the UI components within Stand. But any editorial tool should be able to make use of the components as an npm package - `@guardian/stand` - and developers should feel comfortable contributing.
6
6
 
7
- ## Setup
7
+ ## Installation
8
+
9
+ ```bash
10
+ $ pnpm add @guardian/stand # or yarn or npm
11
+ ```
12
+
13
+ You'll also need to have TypeScript, React, and Emotion installed in your project.
14
+
15
+ The compatible versions are listed in the `peerDependencies` section of `package.json`.
16
+
17
+ Some components have additional dependencies that you will need to install too. See the [Components](#components) section for more details for which components have which peer dependencies.
18
+
19
+ ## Foundations
20
+
21
+ The Editorial Design System foundations are available via Stand. These are split into two categories: Semantic and Base / Primitives.
22
+
23
+ In most cases consumers should use the Semantic tokens, which are more meaningful abstractions of the Base / Primitives tokens, i.e applied to specific use cases.
24
+
25
+ The base / primitives tokens are available for low-level use cases, or very specific cases, but these should be avoided where possible in favour of the semantic tokens.
26
+
27
+ Stand provides the foundations via CSS variables, as well as JS/TS exports for use in code, which could also be used in CSS-in-JS solutions.
28
+
29
+ Base / Primitive tokens should not be overridden if they are used directly, as this could have unintended consequences. Instead override the Semantic tokens which are designed to be overridden.
30
+
31
+ ### Fonts
32
+
33
+ Most applications should only need to load the `Open Sans` and `Guardian Headline` fonts, as these are the primary fonts used across the Guardian's Editorial Tool design system.
34
+
35
+ You only need to load Guardian Text Egyptian if you're planning to use it in your project, in most cases you only need this when working on Guardian editorial content on an editorial tool, i.e. when using `article-body-*` semantic tokens.
36
+
37
+ #### Open Sans
38
+
39
+ We're currently looking at how to best self host this font under a Guardian specific domain, before we release `@guardian/stand` design system for wider usage.
40
+
41
+ For now, the Open Sans variable font can be loaded via Google Fonts:
42
+
43
+ 1. Visit [Google Fonts - Open Sans](https://fonts.google.com/specimen/Open+Sans)
44
+ 2. Click "Get Font" -> "Get embed code"
45
+ 3. Click "Change styles" dropdown
46
+ 4. Use "Full axis" for all options (Italic, Weight, Width)
47
+ 5. Copy the relevant `<link>` tag or `@import` code snippet into your project
48
+ - You don't need to include the CSS class, as the design system will handle applying the correct font-family via CSS variables or JS/TS tokens.
49
+
50
+ ### Guardian Fonts
51
+
52
+ Make sure to visit [guardian/fonts](https://github.com/guardian/fonts) repo for the latest information on how to self-host these fonts.
53
+
54
+ In general, we always want to use the `full-not-hinted` versions of the fonts where possible.
55
+
56
+ #### Guardian Headline
57
+
58
+ We only use the bold weight (700) of Guardian Headline in the design system.
59
+
60
+ ```css
61
+ @font-face {
62
+ font-family: 'GH Guardian Headline';
63
+ src: url('https://assets.guim.co.uk/static/frontend/fonts/guardian-headline/full-not-hinted/GHGuardianHeadline-Bold.woff2')
64
+ format('woff2');
65
+ font-weight: 700;
66
+ font-style: normal;
67
+ font-display: swap;
68
+ }
69
+ ```
70
+
71
+ #### Guardian Text Egyptian
72
+
73
+ We want the regular/normal weight (400), the bold weight (700), and the italic version of each weight for Guardian Text Egyptian in the design system.
74
+
75
+ ```css
76
+ @font-face {
77
+ font-family: 'GuardianTextEgyptian';
78
+ src: url('https://assets.guim.co.uk/static/frontend/fonts/guardian-textegyptian/full-not-hinted/GuardianTextEgyptian-Regular.woff2')
79
+ format('woff2');
80
+ font-weight: 400;
81
+ font-style: normal;
82
+ font-display: swap;
83
+ }
84
+ @font-face {
85
+ font-family: 'GuardianTextEgyptian';
86
+ src: url('https://assets.guim.co.uk/static/frontend/fonts/guardian-textegyptian/full-not-hinted/GuardianTextEgyptian-RegularItalic.woff2')
87
+ format('woff2');
88
+ font-weight: 400;
89
+ font-style: italic;
90
+ font-display: swap;
91
+ }
92
+ @font-face {
93
+ font-family: 'GuardianTextEgyptian';
94
+ src: url('https://assets.guim.co.uk/static/frontend/fonts/guardian-textegyptian/full-not-hinted/GuardianTextEgyptian-Bold.woff2')
95
+ format('woff2');
96
+ font-weight: 700;
97
+ font-style: normal;
98
+ font-display: swap;
99
+ }
100
+ @font-face {
101
+ font-family: 'GuardianTextEgyptian';
102
+ src: url('https://assets.guim.co.uk/static/frontend/fonts/guardian-textegyptian/full-not-hinted/GuardianTextEgyptian-BoldItalic.woff2')
103
+ format('woff2');
104
+ font-weight: 700;
105
+ font-style: italic;
106
+ font-display: swap;
107
+ }
108
+ ```
109
+
110
+ ### Semantic
111
+
112
+ #### Colors
113
+
114
+ ```ts
115
+ import { css } from '@emotion/react';
116
+ import { semanticColors } from '@guardian/stand'; // JS/TS usage
117
+ import '@guardian/stand/semantic/colors.css'; // CSS usage
118
+
119
+ const stringStyle = css`
120
+ color: ${semanticColors.text.primary}; /* JS/TS usage */
121
+ background-color: var(
122
+ --semantic-colors-bg-default-on-light
123
+ ); /* CSS usage */
124
+ `;
125
+
126
+ const objectStyle = {
127
+ color: semanticColors.text.primary /* JS/TS usage */,
128
+ backgroundColor:
129
+ 'var(--semantic-colors-bg-default-on-light)' /* CSS usage */,
130
+ };
131
+ ```
132
+
133
+ For a list of available semantic color styles see the [Storybook Semantic Colors](https://68c12e3ed577cb56abfd31bf-kggeezequd.chromatic.com/?path=/docs/stand-editorial-design-system-semantic-color-palette--docs) section.
134
+
135
+ For a full list of CSS Semantic Color tokens see [`semantic/colors.css`](./src/styleD/build/css/semantic/colors.css).
136
+
137
+ #### Typography
138
+
139
+ ```ts
140
+ import { css } from '@emotion/react';
141
+ import {
142
+ semanticColors,
143
+ semanticTypography,
144
+ convertTypographyToEmotionObjectStyle, // helper function to convert from typography token object to emotion CSS object style
145
+ convertTypographyToEmotionStringStyle, // helper function to convert from typography token object to emotion CSS string style
146
+ } from '@guardian/stand'; // JS/TS usage
147
+ import '@guardian/stand/semantic/typography.css'; // CSS usage
148
+
149
+ /* JS/TS usage */
150
+ const stringStyleJS = css`
151
+ ${convertTypographyToEmotionStringStyle(
152
+ semanticTypography['body-compact-md'],
153
+ )}
154
+ `;
155
+ const objectStyleJS = {
156
+ // other styles e.g.
157
+ color: semanticColors.text.primary,
158
+
159
+ // typography styles
160
+ ...convertTypographyToEmotionObjectStyle(
161
+ semanticTypography['body-compact-sm'],
162
+ ),
163
+ };
164
+
165
+ /* CSS usage */
166
+ const stringStyleCSS = css`
167
+ /* CSS usage */
168
+ font: var(--semantic-typography-body-compact-sm-font);
169
+ letter-spacing: var(--semantic-typography-body-compact-sm-letter-spacing);
170
+ font-variation-settings: 'wdth'
171
+ var(--semantic-typography-body-compact-sm-font-width);
172
+ `;
173
+ const objectStyleCSS = {
174
+ fontFamily: 'var(--semantic-typography-body-compact-sm-font-family)',
175
+ fontWeight: 'var(--semantic-typography-body-compact-sm-font-weight)',
176
+ fontSize: 'var(--semantic-typography-body-compact-sm-font-size)',
177
+ lineHeight: 'var(--semantic-typography-body-compact-sm-line-height)',
178
+ letterSpacing: 'var(--semantic-typography-body-compact-sm-letter-spacing)',
179
+ fontVariationSettings: `'wdth' var(--semantic-typography-body-compact-sm-font-variation-settings)`,
180
+ };
181
+ ```
182
+
183
+ For a list of available typography styles see the [Storybook Semantic Typography](https://68c12e3ed577cb56abfd31bf-kggeezequd.chromatic.com/?path=/docs/stand-editorial-design-system-semantic-typography--docs) section.
184
+
185
+ For a full list of CSS Semantic Typography tokens see [`semantic/typography.css`](./src/styleD/build/css/semantic/typography.css).
186
+
187
+ ### Base / Primitives
188
+
189
+ #### Colors
190
+
191
+ ```ts
192
+ import { css } from '@emotion/react';
193
+ import { baseColors } from '@guardian/stand'; // JS/TS usage
194
+ import '@guardian/stand/base/colors.css'; // CSS usage
195
+
196
+ const stringStyle = css`
197
+ color: ${baseColors.neutral['900']}; /* JS/TS usage */
198
+ background-color: var(--base-colors-blue-500); /* CSS usage */
199
+ `;
200
+
201
+ const objectStyle = {
202
+ color: baseColors.neutral['900'] /* JS/TS usage */,
203
+ backgroundColor: 'var(--base-colors-blue-500)' /* CSS usage */,
204
+ };
205
+ ```
206
+
207
+ For a list of the available base/primitives color styles see the [Storybook Base Colors](https://68c12e3ed577cb56abfd31bf-kggeezequd.chromatic.com/?path=/docs/stand-editorial-design-system-base-color-palette--docs) section.
208
+
209
+ For a full list of CSS Base/Primitives Color tokens see [`base/colors.css`](./src/styleD/build/css/base/colors.css).
210
+
211
+ #### Typography
212
+
213
+ ```ts
214
+ import { css } from '@emotion/react';
215
+ import { baseTypography } from '@guardian/stand'; // JS/TS usage
216
+ import '@guardian/stand/base/typography.css'; // CSS usage
217
+
218
+ /* JS/TS usage */
219
+ const stringStyleJS = css`
220
+ font-family: ${baseTypography.family['Open Sans']};
221
+ font-size: ${baseTypography.size['14-px']};
222
+ font-weight: ${baseTypography.weight['Open Sans'].normal};
223
+ font-variation-settings: 'wdth' ${baseTypography.width['Open Sans']};
224
+ style: ${baseTypography.style.normal};
225
+ line-height: ${baseTypography.lineHeight.normal};
226
+ letter-spacing: ${baseTypography.letterSpacing['default-px']};
227
+ `;
228
+ const objectStyleJS = {
229
+ fontFamily: baseTypography.family['Open Sans'],
230
+ fontSize: baseTypography.size['14-px'],
231
+ fontWeight: baseTypography.weight['Open Sans'].normal,
232
+ fontVariationSettings: `'wdth' ${baseTypography.width['Open Sans']}`,
233
+ fontStyle: baseTypography.style.normal,
234
+ lineHeight: baseTypography.lineHeight.normal,
235
+ letterSpacing: baseTypography.letterSpacing['default-px'],
236
+ };
237
+
238
+ /* CSS usage */
239
+ const stringStyleCSS = css`
240
+ font-family: var(--base-typography-family-open-sans);
241
+ font-size: var(--base-typography-size-14-px);
242
+ font-weight: var(--base-typography-weight-open-sans-normal);
243
+ font-variation-settings: 'wdth' var(--base-typography-width-open-sans);
244
+ font-style: var(--base-typography-style-normal);
245
+ line-height: var(--base-typography-line-height-normal);
246
+ letter-spacing: var(--base-typography-letter-spacing-default-px);
247
+ `;
248
+ const objectStyleCSS = {
249
+ fontFamily: 'var(--base-typography-family-open-sans)',
250
+ fontSize: 'var(--base-typography-size-14-px)',
251
+ fontWeight: 'var(--base-typography-weight-open-sans-normal)',
252
+ fontVariationSettings: `'wdth' var(--base-typography-width-open-sans)`,
253
+ fontStyle: 'var(--base-typography-style-normal)',
254
+ lineHeight: 'var(--base-typography-line-height-normal)',
255
+ letterSpacing: 'var(--base-typography-letter-spacing-default-px)',
256
+ };
257
+ ```
258
+
259
+ For a list of the available base/primitives typography tokens see the [Storybook Base Typography](https://68c12e3ed577cb56abfd31bf-kggeezequd.chromatic.com/?path=/docs/stand-editorial-design-system-base-typography--docs) section.
260
+
261
+ For a full list of CSS Base/Primitives Typography tokens see [`base/typography.css`](./src/styleD/build/css/base/typography.css).
262
+
263
+ ## Components
264
+
265
+ ### `Byline`
266
+
267
+ A flexible byline editor component built in ProseMirror and React with usability and accessibility in mind.
268
+
269
+ **Peer dependencies:**
270
+
271
+ You'll need to install the following peer dependencies in your project to use the `Byline` component:
272
+
273
+ - `@guardian/prosemirror-invisibles`
274
+ - `prosemirror-dropcursor`
275
+ - `prosemirror-history`
276
+ - `prosemirror-keymap`
277
+ - `prosemirror-model`
278
+ - `prosemirror-state`
279
+ - `prosemirror-view`
280
+
281
+ See the `peerDependencies` section of `package.json` for compatible versions to install.
282
+
283
+ #### Usage
284
+
285
+ ```tsx
286
+ import type { BylineModel } from '@guardian/stand';
287
+ import { Byline } from '@guardian/stand';
288
+
289
+ const Component = () => {
290
+ const bylineModel: BylineModel = {
291
+ // ...set up your byline model here
292
+ };
293
+ ...
294
+ return (
295
+ <>
296
+ ...
297
+ <Byline initialValue={bylineModel} />
298
+ ...
299
+ </>
300
+ );
301
+ };
302
+ ```
303
+
304
+ By itself the `Byline` component is just the editor UI. You will need to set up the ProseMirror editor state, schema, and plugins to get a fully functioning byline editor. See the props and example below for a more complete implementation.
305
+
306
+ The `BylineModel` type defines the structure of the byline data which is agnostic from any other data structure. You must convert to/from this model when integrating with your application's data structures.
307
+
308
+ #### Props
309
+
310
+ See [`BylineProps`](src/byline/Byline.tsx#L41) for the full list of props, usage example can be seen in Storybook.
311
+
312
+ #### Example
313
+
314
+ The `ContentByline` component in `flexible-frontend` has a detailed example of how to use the `Byline` component from Stand. See [ContentByline.tsx](https://github.com/guardian/flexible-content/blob/1d537615a18ae24a4a5410a3f945b2b9db1dbb47/flexible-frontend/src/app/components/furniture/content-byline/ContentByline.tsx#L72-L205).
315
+
316
+ ### TagPicker
317
+
318
+ #### TagAutocomplete
319
+
320
+ _Status: Testing_
321
+
322
+ Part of the overall TagPicker component, the TagAutocomplete provides an accessible
323
+ autocomplete input for selecting tags from a list of options, based on the [React Aria ComboBox](https://react-spectrum.adobe.com/react-aria/ComboBox) component.
324
+
325
+ **Peer dependencies:**
326
+
327
+ - `react-aria-components`
328
+
329
+ See the `peerDependencies` section of the `package.json` for compatible versions to install.
330
+
331
+ ##### Props
332
+
333
+ See [`TagAutocompleteProps`](src/components/tag-picker/TagAutocomplete.tsx#L23) for the full list of props, usage example can be seen in Storybook.
334
+
335
+ #### TagTable
336
+
337
+ _Status: Testing_
338
+
339
+ Part of the overall TagPicker component, the TagTable provides an accessible
340
+ table for displaying tags, with options to add, remove, and reorder tags via drag and drop,
341
+ based on the [React Aria Table](https://react-spectrum.adobe.com/react-aria/Table) component.
342
+
343
+ **Peer dependencies:**
344
+
345
+ - `react-aria-components`
346
+
347
+ See the `peerDependencies` section of the `package.json` for compatible versions to install.
348
+
349
+ ##### Props
350
+
351
+ See [`TagTableProps`](src/components/tag-picker/TagTable.tsx#L31) for the full list of props, usage example can be seen in Storybook.
352
+
353
+ #### Usage
354
+
355
+ _Example with TagAutocomplete and TagTable combined:_
356
+
357
+ ```tsx
358
+ import { TagAutocomplete, TagTable } from '@guardian/stand';
359
+
360
+ const Component = () => {
361
+ const [selectedTags, setSelectedTags] = useState<
362
+ TagManagerObjectData[] // TagManagerObjectData is an internal type representing a Tag
363
+ >([]);
364
+ const [options, setOptions] = useState<TagManagerObjectData[]>([]);
365
+ const [value, setValue] = useState('');
366
+ const onChange = (inputText: string) => {
367
+ setValue(inputText);
368
+ if (inputText === '') {
369
+ setOptions([]);
370
+ return;
371
+ }
372
+
373
+ if (inputText === '*') {
374
+ setOptions(exampleTags); // exampleTags is an array of Tags
375
+ return;
376
+ }
377
+
378
+ // Simple filtering against exampleTags
379
+ const filteredItems = exampleTags.filter((t) =>
380
+ t.internalName.toLowerCase().includes(inputText.toLowerCase()),
381
+ );
382
+ return setOptions(filteredItems);
383
+ };
384
+ return (
385
+ <>
386
+ <div
387
+ css={css`
388
+ display: flex;
389
+ `}
390
+ >
391
+ <TagAutocomplete
392
+ onChange={onChange}
393
+ options={options}
394
+ label="Tags"
395
+ addTag={(tag) =>
396
+ setSelectedTags((tags) => {
397
+ return [...tags, tag];
398
+ })
399
+ }
400
+ loading={false}
401
+ placeholder={''}
402
+ disabled={false}
403
+ value={value}
404
+ />
405
+ <select>
406
+ option>All tags</option>
407
+ </select>
408
+ </div>
409
+ <TagTable rows={selectedTags} filterRows={() => true} />
410
+ </>
411
+ );
412
+ };
413
+ ```
414
+
415
+ #### Example
416
+
417
+ This is currently still in testing phase, so a production implementation is not yet available.
418
+
419
+ ### Contributing
420
+
421
+ See the [Contributing to Stand](./CONTRIBUTING.md) documentation for guidelines on contributing to this project. Project setup and common tasks are listed below.
422
+
423
+ ### Setup
8
424
 
9
425
  - Run `./setup.sh` in the project root (flexible-content) directory to set up pnpm, install dependencies, and build the project.
10
426
 
11
- ## Tasks
427
+ ### Tasks
12
428
 
13
429
  - Run `pnpm install` to install dependencies.
14
430
  - Run `pnpm build` to build, this makes any changes available to flexible-frontend
15
431
  - Run `pnpm storybook` to run Storybook
432
+ - Run `pnpm build:storybook` to build the Storybook static site
433
+ - Run `pnpm build-styled` to build the Style Dictionary styles
434
+ - Run `pnpm test` to run tests
435
+ - Run `pnpm test:e2e` to run end-to-end tests using Playwright
436
+ - Run `pnpm test:react-matrix` to run matrix tests (see Compatibility section below)
437
+ - Run `pnpm tsc` to run check TypeScript types
438
+ - Run `pnpm lint` to run the linter
439
+ - Run `pnpm lint:fix` to fix any auto-fixable issues
440
+ - Run `pnpm format:check` to check code formatting
441
+ - Run `pnpm format:fix` to fix code formatting issues
442
+
443
+ ### Style Dictionary
444
+
445
+ The project uses [Style Dictionary](https://styledictionary.com/) to manage design tokens.
446
+
447
+ Tokens are defined in the `src/styleD/tokens` folder.
448
+
449
+ The output styles are generated into the `src/styleD/build` folder.
450
+
451
+ We use rollup to copy the built styles into the `dist/styleD/build` folder during the build process, and these are published with the package.
452
+
453
+ Most tokens are generated from Figma variables using a script to make these available in the `src/styleD/tokens` folder. See the [Generate Design Tokens from Figma Variables](./scripts/figma/README.md) documentation for more details.
16
454
 
17
- ## Contributing
455
+ Use `pnpm build-styled` to generate the styles after making changes to the tokens and make sure to test and commit the changes to the built styles.
18
456
 
19
- See the [Contributing to Stand](./CONTRIBUTING.md) documentation
457
+ See the [Style Dictionary documentation](./docs/style-dictionary.md) for more details on how we structure and generate the styles.
20
458
 
21
- ## Compatibility
459
+ ### Compatibility
22
460
 
23
461
  See the package.json `peerDependencies` section for compatible versions of React and other dependencies that Stand works with.
24
462
 
@@ -33,7 +471,7 @@ All three variables (`REACT_VERSIONS`, `EMOTION_VERSIONS`, `TS_VERSIONS`) must b
33
471
 
34
472
  Matrix generation in CI uses the same JSON file in the workflow: `../.github/workflows/stand-component-library-deps-matrix.yml` to ensure consistency.
35
473
 
36
- ### Updating Supported Versions
474
+ #### Updating Supported Versions
37
475
 
38
476
  1. Edit `./scripts/deps-matrix-versions.json` with new versions
39
477
  2. Run the matrix test locally:
@@ -48,7 +486,7 @@ Matrix generation in CI uses the same JSON file in the workflow: `../.github/wor
48
486
  5. Update `peerDependencies` in `package.json` to reflect the new minimum / tested range
49
487
  6. Open a PR, the CI pipeline will comment with the compatibility matrix
50
488
 
51
- ### Tips
489
+ #### Tips
52
490
 
53
491
  - Keep versions in ascending order for readability
54
492
  - Remove deprecated versions only after confirming no downstream tool depends on them
@@ -294,7 +294,7 @@ const Byline = ({
294
294
  /* @__PURE__ */ jsxRuntime.jsx(
295
295
  "div",
296
296
  {
297
- css: styles.bylineEditorStyles(theme?.editor),
297
+ css: styles.bylineEditorStyles(theme),
298
298
  ref: editorRef,
299
299
  onBlur
300
300
  }
@@ -317,8 +317,8 @@ const Byline = ({
317
317
  role: "option",
318
318
  "aria-selected": i === currentOptionIndex,
319
319
  css: [
320
- styles.dropdownLiStyles(theme),
321
- i === currentOptionIndex && styles.selectedDropdownLiStyles(theme)
320
+ styles.dropdownLiStyles(theme?.dropdown),
321
+ i === currentOptionIndex && styles.selectedDropdownLiStyles(theme?.dropdown)
322
322
  ],
323
323
  onMouseMove: () => {
324
324
  if (currentOptionIndex !== i) {
@@ -346,8 +346,8 @@ const Byline = ({
346
346
  id: `contributor-option-${taggedContributors.length}`,
347
347
  "aria-selected": currentOptionIndex === taggedContributors.length,
348
348
  css: [
349
- styles.dropdownLiStyles(theme),
350
- currentOptionIndex === taggedContributors.length && styles.selectedDropdownLiStyles(theme)
349
+ styles.dropdownLiStyles(theme?.dropdown),
350
+ currentOptionIndex === taggedContributors.length && styles.selectedDropdownLiStyles(theme?.dropdown)
351
351
  ],
352
352
  onMouseMove: () => {
353
353
  if (currentOptionIndex !== taggedContributors.length) {
@@ -246,10 +246,10 @@ const Byline = ({ theme, allowUntaggedContributors, contributorLimit, enablePrev
246
246
  contributorLimit,
247
247
  allowUntaggedContributors
248
248
  ]);
249
- return jsxs("div", { css: bylineContainerStyles, children: [jsx("div", { css: bylineEditorStyles(theme?.editor), ref: editorRef, onBlur }), jsx("div", { ref: dropdownRef, tabIndex: 0, css: dropdownContainerStyles(showDropdown && // show the dropdown if there are tagged contributors to select or untagged contributors are allowed
249
+ return jsxs("div", { css: bylineContainerStyles, children: [jsx("div", { css: bylineEditorStyles(theme), ref: editorRef, onBlur }), jsx("div", { ref: dropdownRef, tabIndex: 0, css: dropdownContainerStyles(showDropdown && // show the dropdown if there are tagged contributors to select or untagged contributors are allowed
250
250
  (taggedContributors.length > 0 || !!allowUntaggedContributors), theme?.dropdown), children: jsxs("ul", { id: "byline-dropdown", role: "listbox", css: dropdownUlStyles, children: [taggedContributors.map((contributor, i) => jsx("li", { id: `contributor-option-${i}`, role: "option", "aria-selected": i === currentOptionIndex, css: [
251
- dropdownLiStyles(theme),
252
- i === currentOptionIndex && selectedDropdownLiStyles(theme)
251
+ dropdownLiStyles(theme?.dropdown),
252
+ i === currentOptionIndex && selectedDropdownLiStyles(theme?.dropdown)
253
253
  ], onMouseMove: () => {
254
254
  if (currentOptionIndex !== i) {
255
255
  setCurrentOptionIndex(i);
@@ -258,8 +258,8 @@ const Byline = ({ theme, allowUntaggedContributors, contributorLimit, enablePrev
258
258
  e.preventDefault();
259
259
  addTaggedContributor(contributor, viewRef, setShowDropdown, contributorLimit, isTypingFromStartRange.current);
260
260
  }, children: contributor.internalLabel ?? contributor.label }, contributor.tagId)), allowUntaggedContributors && jsxs("li", { role: "option", id: `contributor-option-${taggedContributors.length}`, "aria-selected": currentOptionIndex === taggedContributors.length, css: [
261
- dropdownLiStyles(theme),
262
- currentOptionIndex === taggedContributors.length && selectedDropdownLiStyles(theme)
261
+ dropdownLiStyles(theme?.dropdown),
262
+ currentOptionIndex === taggedContributors.length && selectedDropdownLiStyles(theme?.dropdown)
263
263
  ], onMouseMove: () => {
264
264
  if (currentOptionIndex !== taggedContributors.length) {
265
265
  setCurrentOptionIndex(taggedContributors.length);