@planningcenter/chat-react-native 1.6.2-rc.1 → 1.6.2-rc.3

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 (31) hide show
  1. package/build/components/display/badge.d.ts +58 -0
  2. package/build/components/display/badge.d.ts.map +1 -0
  3. package/build/components/display/badge.js +186 -0
  4. package/build/components/display/badge.js.map +1 -0
  5. package/build/components/display/button_color_utils.d.ts +1 -1
  6. package/build/components/display/index.d.ts +2 -0
  7. package/build/components/display/index.d.ts.map +1 -1
  8. package/build/components/display/index.js +2 -0
  9. package/build/components/display/index.js.map +1 -1
  10. package/build/components/display/switch.d.ts +4 -0
  11. package/build/components/display/switch.d.ts.map +1 -0
  12. package/build/components/display/switch.js +14 -0
  13. package/build/components/display/switch.js.map +1 -0
  14. package/build/screens/design_system_screen.d.ts.map +1 -1
  15. package/build/screens/design_system_screen.js +408 -332
  16. package/build/screens/design_system_screen.js.map +1 -1
  17. package/build/utils/theme.d.ts +19 -0
  18. package/build/utils/theme.d.ts.map +1 -1
  19. package/build/utils/theme.js +37 -0
  20. package/build/utils/theme.js.map +1 -1
  21. package/build/vendor/tapestry/tokens.d.ts +30 -0
  22. package/build/vendor/tapestry/tokens.d.ts.map +1 -1
  23. package/build/vendor/tapestry/tokens.js +30 -0
  24. package/build/vendor/tapestry/tokens.js.map +1 -1
  25. package/package.json +2 -2
  26. package/src/components/display/badge.tsx +323 -0
  27. package/src/components/display/index.ts +2 -0
  28. package/src/components/display/switch.tsx +23 -0
  29. package/src/screens/design_system_screen.tsx +714 -571
  30. package/src/utils/theme.ts +56 -0
  31. package/src/vendor/tapestry/tokens.ts +30 -0
@@ -5,12 +5,14 @@ import { useTheme } from '../hooks'
5
5
  import {
6
6
  Avatar,
7
7
  AvatarGroup,
8
+ Badge,
8
9
  Button,
9
10
  Heading,
10
11
  Icon,
11
12
  IconButton,
12
13
  Image,
13
14
  Spinner,
15
+ Switch,
14
16
  Text,
15
17
  TextButton,
16
18
  TextInlineButton,
@@ -22,6 +24,10 @@ import {
22
24
  platformFontWeightMedium,
23
25
  } from '../utils'
24
26
 
27
+ // =================================
28
+ // ====== Docs Utils ===============
29
+ // =================================
30
+
25
31
  const URL = {
26
32
  image: 'https://picsum.photos/seed/picsum/200',
27
33
  broken: 'https://broken.url',
@@ -43,587 +49,720 @@ const URL = {
43
49
 
44
50
  const buttonPress = () => Alert.alert('Button clicked')
45
51
 
52
+ // =================================
53
+ // ====== Component ================
54
+ // =================================
55
+
46
56
  export function DesignSystemScreen() {
47
57
  const styles = useStyles()
48
- const { colors } = useTheme()
49
58
 
50
59
  return (
51
60
  <ScrollView contentContainerStyle={styles.container} style={styles.scrollView}>
52
- <CollapsableSection title="Molecules">
53
- <Row>
54
- <Text>🚧 Coming soon! 🚧</Text>
55
- </Row>
56
- </CollapsableSection>
57
- <CollapsableSection title="Atoms">
58
- <Group
59
- title="Spinner"
60
- description="Loading indicators that can be used within or close to atomic components. Not intended for full-screen loading."
61
- >
62
- <Row style={styles.spinnerContainer}>
63
- <Spinner size={24} />
64
- </Row>
65
- </Group>
66
- <Group
67
- title="Image"
68
- description="Foundational way of displaying images. Loading or broken images will fallback to show a spinner. Hide decortive images from screen readers with `alt=''`."
69
- >
70
- <Row>
71
- <Image source={{ uri: URL.broken }} style={styles.image} alt="Mountain sunrise" />
72
- <Image source={{ uri: URL.image }} style={styles.image} alt="Mountain sunrise" />
73
- <Image source={{ uri: URL.image }} style={styles.image} alt="" />
74
- </Row>
75
- </Group>
76
- <Group
77
- title="Avatar"
78
- description='Displays the profile image for a user in different sizes and has a loading fallback. Can optionally show an online/offline "presence" indicator.'
79
- >
80
- <Row>
81
- <Avatar sourceUri={URL.broken} />
82
- <Avatar size="md" sourceUri={URL.avatar_fallback} />
83
- <Avatar sourceUri={URL.avatar} />
84
- </Row>
85
- <Row>
86
- <Avatar presence="offline" sourceUri={URL.broken} />
87
- <Avatar presence="online" size="md" sourceUri={URL.avatar_fallback} />
88
- <Avatar presence="offline" sourceUri={URL.avatar} />
89
- </Row>
90
- </Group>
91
- <Group
92
- title="AvatarGroup"
93
- description="Shows 1-4 images in a grid at different sizes. Loading fallback shows until all images successfully load."
94
- >
95
- <Row>
96
- <AvatarGroup sourceUris={[URL.broken]} />
97
- <AvatarGroup sourceUris={[URL.broken, URL.broken, ...URL.two_avatars]} />
98
- <AvatarGroup sourceUris={[URL.avatar]} />
99
- <AvatarGroup sourceUris={URL.two_avatars} />
100
- <AvatarGroup sourceUris={URL.three_avatars} />
101
- <AvatarGroup sourceUris={URL.four_avatars} />
102
- </Row>
103
- </Group>
104
- <Group
105
- title="Icon"
106
- description="Displays any icon from @planningcenter/icons. Missing icons will fallback to a grey circle. Styling with `fontSize` will allow it to scale with the device's text a11y size."
107
- >
108
- <Row>
109
- <Icon name="missingIcon" size={20} />
110
- <Icon name="general.textMessage" size={20} />
111
- <Icon name="general.bell" size={20} color={colors.needsDesignPass} />
112
- <Icon name="churchCenter.sort" style={styles.icon} />
113
- </Row>
114
- </Group>
115
- <Group
116
- title="Button"
117
- description="Feature fill and outline variants for primary and danger usecases, along with disabled & loading states. Optionally shows icons to the left and right of the text."
118
- >
119
- <Row>
120
- <Button onPress={buttonPress} title="Default" size="sm" />
121
- <Button onPress={buttonPress} title="Default" size="md" />
122
- <Button onPress={buttonPress} title="Danger" appearance="danger" size="lg" />
123
- </Row>
124
- <Row>
125
- <Button disabled onPress={buttonPress} title="Disabled" size="sm" />
126
- <Button disabled onPress={buttonPress} title="Disabled" size="md" />
127
- <Button disabled onPress={buttonPress} title="Disabled" appearance="danger" size="lg" />
128
- </Row>
129
- <Row>
130
- <Button
131
- onPress={buttonPress}
132
- title="Default"
133
- size="sm"
134
- iconNameLeft="general.plus"
135
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
136
- />
137
- <Button
138
- onPress={buttonPress}
139
- title="Default"
140
- size="md"
141
- iconNameRight="churchCenter.sort"
142
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
143
- />
144
- <Button
145
- onPress={buttonPress}
146
- title="Danger"
147
- appearance="danger"
148
- size="lg"
149
- iconNameLeft="groups.cards"
150
- iconNameRight="general.downChevron"
151
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
152
- />
153
- </Row>
154
- <Row>
155
- <Button loading onPress={buttonPress} title="Default" size="sm" />
156
- <Button loading onPress={buttonPress} title="Default" size="md" />
157
- <Button loading onPress={buttonPress} title="Danger" appearance="danger" size="lg" />
158
- </Row>
159
- <Row>
160
- <Button onPress={buttonPress} title="Default" size="sm" variant="outline" />
161
- <Button onPress={buttonPress} title="Default" size="md" variant="outline" />
162
- <Button
163
- onPress={buttonPress}
164
- title="Danger"
165
- appearance="danger"
166
- size="lg"
167
- variant="outline"
168
- />
169
- </Row>
170
- <Row>
171
- <Button
172
- onPress={buttonPress}
173
- title="Default"
174
- size="sm"
175
- variant="outline"
176
- iconNameLeft="general.plus"
177
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
178
- />
179
- <Button
180
- onPress={buttonPress}
181
- title="Default"
182
- size="md"
183
- variant="outline"
184
- iconNameRight="churchCenter.sort"
185
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
186
- />
187
- <Button
188
- onPress={buttonPress}
189
- title="Danger"
190
- appearance="danger"
191
- size="lg"
192
- variant="outline"
193
- iconNameLeft="groups.cards"
194
- iconNameRight="general.downChevron"
195
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
196
- />
197
- </Row>
198
- <Row>
199
- <Button
200
- disabled
201
- onPress={buttonPress}
202
- title="Disabled"
203
- size="sm"
204
- variant="outline"
205
- iconNameLeft="general.plus"
206
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
207
- />
208
- <Button
209
- disabled
210
- onPress={buttonPress}
211
- title="Disabled"
212
- size="md"
213
- variant="outline"
214
- iconNameRight="churchCenter.sort"
215
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
216
- />
217
- <Button
218
- disabled
219
- onPress={buttonPress}
220
- title="Disabled"
221
- appearance="danger"
222
- size="lg"
223
- variant="outline"
224
- iconNameLeft="groups.cards"
225
- iconNameRight="general.downChevron"
226
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
227
- />
228
- </Row>
229
- <Row>
230
- <Button
231
- loading
232
- onPress={buttonPress}
233
- title="Default"
234
- size="sm"
235
- variant="outline"
236
- iconNameLeft="general.plus"
237
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
238
- />
239
- <Button
240
- loading
241
- onPress={buttonPress}
242
- title="Default"
243
- size="md"
244
- variant="outline"
245
- iconNameRight="churchCenter.sort"
246
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
247
- />
248
- <Button
249
- loading
250
- onPress={buttonPress}
251
- title="Danger"
252
- appearance="danger"
253
- size="lg"
254
- variant="outline"
255
- iconNameLeft="groups.cards"
256
- iconNameRight="general.downChevron"
257
- maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
258
- />
259
- </Row>
260
- </Group>
261
- <Group
262
- title="IconButton"
263
- description="Supports different appearances, sizes, along with loading & disabled states. Use `iconStyle` for custom colors and font sizes. Requires `accessibilityLabel` as icon's don't provide context to screen readers."
264
- >
265
- <Row>
266
- <IconButton
267
- onPress={buttonPress}
268
- name="general.paperclip"
269
- accessibilityLabel="Add attachment"
270
- accessibilityHint="Opens your device's image gallary"
271
- size="md"
272
- />
273
- <IconButton
274
- onPress={buttonPress}
275
- name="general.paperclip"
276
- accessibilityLabel="Add attachment"
277
- accessibilityHint="Opens your device's image gallary"
278
- appearance="danger"
279
- size="lg"
280
- />
281
- <IconButton
282
- onPress={buttonPress}
283
- name="general.paperclip"
284
- accessibilityLabel="Add attachment"
285
- accessibilityHint="Opens your device's image gallary"
286
- appearance="interaction"
287
- size="xl"
288
- />
289
- <IconButton
290
- onPress={buttonPress}
291
- name="general.paperclip"
292
- accessibilityLabel="Add attachment"
293
- accessibilityHint="Opens your device's image gallary"
294
- iconStyle={styles.customIconButtonColor}
295
- size="xxl"
296
- />
297
- <IconButton
298
- onPress={buttonPress}
299
- name="general.paperclip"
300
- accessibilityLabel="Add attachment"
301
- accessibilityHint="Opens your device's image gallary"
302
- size="xxxl"
303
- />
304
- </Row>
305
- <Row>
306
- <IconButton
307
- onPress={buttonPress}
308
- name="general.paperclip"
309
- accessibilityLabel="Add attachment"
310
- accessibilityHint="Opens your device's image gallary"
311
- size="md"
312
- disabled
313
- />
314
- <IconButton
315
- onPress={buttonPress}
316
- name="general.paperclip"
317
- accessibilityLabel="Add attachment"
318
- accessibilityHint="Opens your device's image gallary"
319
- appearance="danger"
320
- size="lg"
321
- disabled
322
- />
323
- <IconButton
324
- onPress={buttonPress}
325
- name="general.paperclip"
326
- accessibilityLabel="Add attachment"
327
- accessibilityHint="Opens your device's image gallary"
328
- appearance="interaction"
329
- size="xl"
330
- disabled
331
- />
332
- <IconButton
333
- onPress={buttonPress}
334
- name="general.paperclip"
335
- accessibilityLabel="Add attachment"
336
- accessibilityHint="Opens your device's image gallary"
337
- iconStyle={styles.customIconButtonColor}
338
- size="xxl"
339
- disabled
340
- />
341
- <IconButton
342
- onPress={buttonPress}
343
- name="general.paperclip"
344
- accessibilityLabel="Add attachment"
345
- accessibilityHint="Opens your device's image gallary"
346
- size="xxxl"
347
- disabled
348
- />
349
- </Row>
350
- <Row>
351
- <IconButton
352
- onPress={buttonPress}
353
- name="general.paperclip"
354
- accessibilityLabel="Add attachment"
355
- accessibilityHint="Opens your device's image gallary"
356
- size="md"
357
- loading
358
- />
359
- <IconButton
360
- onPress={buttonPress}
361
- name="general.paperclip"
362
- accessibilityLabel="Add attachment"
363
- accessibilityHint="Opens your device's image gallary"
364
- appearance="danger"
365
- size="lg"
366
- loading
367
- />
368
- <IconButton
369
- onPress={buttonPress}
370
- name="general.paperclip"
371
- accessibilityLabel="Add attachment"
372
- accessibilityHint="Opens your device's image gallary"
373
- appearance="interaction"
374
- size="xl"
375
- loading
376
- />
377
- <IconButton
378
- onPress={buttonPress}
379
- name="general.paperclip"
380
- accessibilityLabel="Add attachment"
381
- accessibilityHint="Opens your device's image gallary"
382
- iconStyle={styles.customIconButtonColor}
383
- size="xxl"
384
- loading
385
- />
386
- <IconButton
387
- onPress={buttonPress}
388
- name="general.paperclip"
389
- accessibilityLabel="Add attachment"
390
- accessibilityHint="Opens your device's image gallary"
391
- size="xxxl"
392
- loading
393
- />
394
- </Row>
395
- </Group>
396
- <Group
397
- title="TextButton"
398
- description="Pressable text with default & danger appearance options. Can be disabled and accept `Text` variance props."
399
- >
400
- <Row>
401
- <TextButton onPress={buttonPress}>Default</TextButton>
402
- <TextButton onPress={buttonPress} variant="secondary">
403
- Default
404
- </TextButton>
405
- <TextButton onPress={buttonPress} variant="tertiary">
406
- Default
407
- </TextButton>
408
- <TextButton onPress={buttonPress} variant="footnote">
409
- Default
410
- </TextButton>
411
- </Row>
412
- <Row>
413
- <TextButton onPress={buttonPress} appearance="danger">
414
- Danger
415
- </TextButton>
416
- <TextButton onPress={buttonPress} variant="secondary" appearance="danger">
417
- Danger
418
- </TextButton>
419
- <TextButton onPress={buttonPress} variant="tertiary" appearance="danger">
420
- Danger
421
- </TextButton>
422
- <TextButton onPress={buttonPress} variant="footnote" appearance="danger">
423
- Danger
424
- </TextButton>
425
- </Row>
426
- <Row>
427
- <TextButton onPress={buttonPress} disabled>
428
- Disabled
429
- </TextButton>
430
- <TextButton onPress={buttonPress} variant="secondary" disabled>
431
- Disabled
432
- </TextButton>
433
- <TextButton onPress={buttonPress} variant="tertiary" disabled>
434
- Disabled
435
- </TextButton>
436
- <TextButton onPress={buttonPress} variant="footnote" disabled>
437
- Disabled
438
- </TextButton>
439
- </Row>
440
- </Group>
441
- <Group
442
- title="TextInlineButton"
443
- description="Supports nesting within `Text`. Temporary component until React Native fixes a layout bug in `Pressable` which used in `TextButton`."
444
- >
445
- <Row style={styles.alignRowLeft}>
446
- <Text>
447
- This text is next to{' '}
448
- <TextInlineButton onPress={buttonPress}>default button text</TextInlineButton> Lorem
449
- ipsum dolor{' '}
450
- <TextInlineButton onPress={buttonPress} appearance="danger">
451
- danger button text
452
- </TextInlineButton>{' '}
453
- consectetur{' '}
454
- <TextInlineButton onPress={buttonPress} disabled>
455
- disabled button text
456
- </TextInlineButton>{' '}
457
- elit.
458
- </Text>
459
- <Text variant="secondary">
460
- This text is next to{' '}
461
- <TextInlineButton variant="secondary" onPress={buttonPress}>
462
- default button text
463
- </TextInlineButton>{' '}
464
- Lorem ipsum dolor{' '}
465
- <TextInlineButton variant="secondary" onPress={buttonPress} appearance="danger">
466
- danger button text
467
- </TextInlineButton>{' '}
468
- consectetur{' '}
469
- <TextInlineButton variant="secondary" onPress={buttonPress} disabled>
470
- disabled button text
471
- </TextInlineButton>{' '}
472
- elit.
473
- </Text>
474
- <Text variant="tertiary">
475
- This text is next to{' '}
476
- <TextInlineButton variant="tertiary" onPress={buttonPress}>
477
- default button text
478
- </TextInlineButton>{' '}
479
- Lorem ipsum dolor{' '}
480
- <TextInlineButton variant="tertiary" onPress={buttonPress} appearance="danger">
481
- danger button text
482
- </TextInlineButton>{' '}
483
- consectetur{' '}
484
- <TextInlineButton variant="tertiary" onPress={buttonPress} disabled>
485
- disabled button text
486
- </TextInlineButton>{' '}
487
- elit.
488
- </Text>
489
- <Text variant="footnote">
490
- This text is next to{' '}
491
- <TextInlineButton variant="footnote" onPress={buttonPress}>
492
- default button text
493
- </TextInlineButton>{' '}
494
- Lorem ipsum dolor{' '}
495
- <TextInlineButton variant="footnote" onPress={buttonPress} appearance="danger">
496
- danger button text
497
- </TextInlineButton>{' '}
498
- consectetur{' '}
499
- <TextInlineButton variant="footnote" onPress={buttonPress} disabled>
500
- disabled button text
501
- </TextInlineButton>{' '}
502
- elit.
503
- </Text>
504
- </Row>
505
- </Group>
506
- <Group
507
- title="Heading"
508
- description="Use for headings & titles as it includes the a11y 'header' role. Change the size and style with the h1-h4 variants."
509
- >
510
- <Row>
511
- <Heading>Heading 1</Heading>
512
- <Heading variant="h2">Heading 2</Heading>
513
- <Heading variant="h3">Heading 3</Heading>
514
- <Heading variant="h4">Heading 4</Heading>
515
- </Row>
516
- </Group>
517
- <Group title="Text" description="Use for body copy and supporting text.">
518
- <Row>
519
- <Text>Plain text</Text>
520
- <Text variant="secondary">Secondary</Text>
521
- <Text variant="tertiary">Tertiary</Text>
522
- <Text variant="footnote">Footnote</Text>
523
- </Row>
524
- </Group>
525
- </CollapsableSection>
526
- <CollapsableSection title="Theme" isLast>
527
- <TextGroup>
528
- <Text>There are four main parts to our theming system…</Text>
529
- <TextRow>
530
- <Heading variant="h3">Default theme</Heading>
531
- <Text>
532
- Start at `src/utils/theme` when adding new theme values. The file has more
533
- instructions and examples.
534
- </Text>
535
- <Text>At a high level, it provides…</Text>
536
- <TextListItem label="1.">
537
- Access to consuming app targets of what theme values that they can be customized.
538
- </TextListItem>
539
- <TextListItem label="2.">
540
- Fallback values for our components to use if the values weren't overriden.
541
- </TextListItem>
542
- </TextRow>
543
- <TextRow>
544
- <Heading variant="h3">Customizing the theme</Heading>
545
- <Text>
546
- Apps can override any default theme value by passing a `theme` object to our
547
- `ChatProvider` that holds a `theme` and a `colorScheme`.
548
- </Text>
549
- <Text>
550
- Currently types can be enforced by setting the parent theme object to
551
- `CreateChatThemeProps`.
552
- </Text>
553
- <Text variant="footnote">
554
- Example setup: `apps/mobile/src/context/chat_context_provider.tsx`
555
- </Text>
556
- </TextRow>
557
- <TextRow>
558
- <Heading variant="h3">Merged theme</Heading>
559
- <Text>
560
- In `src/contexts/chat_context.tsx` we merge the default theme and any custom values
561
- coming from a product target with the `useCreateChatTheme` hook. It creates a single
562
- `ChatTheme` type.
563
- </Text>
564
- </TextRow>
565
- <TextRow>
566
- <Heading variant="h3">Using theme values</Heading>
567
- <Text>
568
- Inside of our own `chat-react-native` components we can access the merged `ChatTheme`
569
- object via our own `useTheme` hook.
570
- </Text>
571
- <Text variant="footnote">Example setup: `src/components/display/button.tsx`</Text>
572
- </TextRow>
573
- </TextGroup>
574
- </CollapsableSection>
61
+ <ThemeSection />
575
62
  {/* TODO: Enable & update when we install @planningcenter/tapestry */}
576
- {/* <CollapsableSection title="Tokens" isLast>
577
- <TextGroup>
578
- <TextRow>
579
- <Heading variant="h3">What are they?</Heading>
580
- <Text>
581
- Tokens are UX approved CSS values that we can use to style our UI in a consistent way.
582
- (e.g. colors, spacing amounts, and font weights.)
583
- </Text>
584
- </TextRow>
585
- <TextRow>
586
- <Heading variant="h3">Where do they come from?</Heading>
587
- <Text>
588
- Tokens primarily come from our internal `@planningcenter/tapestry` package. However,
589
- at this time the package only support light mode colors, so Chat uses a workaround.
590
- </Text>
591
- <Text>
592
- Color-based tokens are infused into our theming system with two local files…
593
- </Text>
594
- <TextListItem label="1. `src/vendor/tapestry/tokens`:">
595
- Primitive color values are stored* here. Primitives capture light or dark mode values,
596
- but don't take into account the devices's colors scheme.
597
- </TextListItem>
598
- <TextListItem label="2. `src/vendor/tapestry/alias_tokens_color_map`:">
599
- Alias tokens reference the primitive color values token file* in light and dark mode
600
- specfic objects. Our theming system then selects the right color to use based on the
601
- device's color scheme.
602
- </TextListItem>
603
- <Text variant="footnote">
604
- *If available, reference the color from the Tapestry package instead.
605
- </Text>
606
- </TextRow>
607
- <TextRow>
608
- <Heading variant="h3">How do we use them?</Heading>
609
- <Text>There are two places to reference tokens at this time…</Text>
610
- <TextListItem label="• Color tokens:">
611
- Reference them from our internal `useTheme` hook to ensure the correct light or dark
612
- mode color token is used.
613
- </TextListItem>
614
- <TextListItem label="• All other tokens:">
615
- Use the `computedToken` function from `@planningcenter/tapestry` by passing it a
616
- string with the token's name. This function provides Typescript support and maps to
617
- the token's raw CSS value. There is another function called `token`, but it maps to
618
- CSS custom properties which React Native doesn't support.
619
- </TextListItem>
620
- </TextRow>
621
- </TextGroup>
622
- </CollapsableSection> */}
63
+ {/* <TokensSection /> */}
64
+ <IndicatorsSection />
65
+ <HeadingTextSection />
66
+ <PressablesSection />
67
+ <ImageIconsSection />
68
+ <FormControlsSection />
69
+ <StatusComponentsSection isLast />
623
70
  </ScrollView>
624
71
  )
625
72
  }
626
73
 
74
+ // =================================
75
+ // ====== Sections =================
76
+ // =================================
77
+
78
+ interface SectionProps {
79
+ isLast?: boolean
80
+ }
81
+
82
+ function ThemeSection({ isLast }: SectionProps) {
83
+ return (
84
+ <CollapsableSection title="Theme" isLast={isLast}>
85
+ <TextGroup>
86
+ <Text>There are four main parts to our theming system…</Text>
87
+ <TextRow>
88
+ <Heading variant="h3">Default theme</Heading>
89
+ <Text>
90
+ Start at `src/utils/theme` when adding new theme values or checking what target apps
91
+ have access to. The file has more instructions and examples.
92
+ </Text>
93
+ <Text>At a high level, it provides…</Text>
94
+ <TextListItem label="1.">
95
+ Access to consuming app targets of what theme values that they can be customized.
96
+ </TextListItem>
97
+ <TextListItem label="2.">
98
+ Fallback values for our components to use if the values weren't overriden.
99
+ </TextListItem>
100
+ </TextRow>
101
+ <TextRow>
102
+ <Heading variant="h3">Customizing the theme</Heading>
103
+ <Text>
104
+ Apps can override any default theme value by passing a `theme` object to our
105
+ `ChatProvider` that holds a `theme` and a `colorScheme`.
106
+ </Text>
107
+ <Text>
108
+ Currently types can be enforced by setting the parent theme object to
109
+ `CreateChatThemeProps`.
110
+ </Text>
111
+ <Text variant="footnote">
112
+ Example setup: `apps/mobile/src/context/chat_context_provider.tsx`
113
+ </Text>
114
+ </TextRow>
115
+ <TextRow>
116
+ <Heading variant="h3">Merged theme</Heading>
117
+ <Text>
118
+ In `src/contexts/chat_context.tsx` we merge the default theme and any custom values
119
+ coming from a product target with the `useCreateChatTheme` hook. It creates a single
120
+ `ChatTheme` type.
121
+ </Text>
122
+ </TextRow>
123
+ <TextRow>
124
+ <Heading variant="h3">Using theme values</Heading>
125
+ <Text>
126
+ Inside of our own `chat-react-native` components we can access the merged `ChatTheme`
127
+ object via our own `useTheme` hook.
128
+ </Text>
129
+ <Text variant="footnote">Example setup: `src/components/display/button.tsx`</Text>
130
+ </TextRow>
131
+ </TextGroup>
132
+ </CollapsableSection>
133
+ )
134
+ }
135
+
136
+ // function TokensSection({ isLast }: SectionProps) {
137
+ // return (
138
+ // <CollapsableSection title="Tokens" isLast={isLast}>
139
+ // <TextGroup>
140
+ // <TextRow>
141
+ // <Heading variant="h3">What are they?</Heading>
142
+ // <Text>
143
+ // Tokens are UX approved CSS values that we can use to style our UI in a consistent way.
144
+ // (e.g. colors, spacing amounts, and font weights.)
145
+ // </Text>
146
+ // </TextRow>
147
+ // <TextRow>
148
+ // <Heading variant="h3">Where do they come from?</Heading>
149
+ // <Text>
150
+ // Tokens primarily come from our internal `@planningcenter/tapestry` package. However, at
151
+ // this time the package only support light mode colors, so Chat uses a workaround.
152
+ // </Text>
153
+ // <Text>Color-based tokens are infused into our theming system with two local files…</Text>
154
+ // <TextListItem label="1. `src/vendor/tapestry/tokens`:">
155
+ // Primitive color values are stored* here. Primitives capture light or dark mode values,
156
+ // but don't take into account the devices's colors scheme.
157
+ // </TextListItem>
158
+ // <TextListItem label="2. `src/vendor/tapestry/alias_tokens_color_map`:">
159
+ // Alias tokens reference the primitive color values token file* in light and dark mode
160
+ // specfic objects. Our theming system then selects the right color to use based on the
161
+ // device's color scheme.
162
+ // </TextListItem>
163
+ // <Text variant="footnote">
164
+ // *If available, reference the color from the Tapestry package instead.
165
+ // </Text>
166
+ // </TextRow>
167
+ // <TextRow>
168
+ // <Heading variant="h3">How do we use them?</Heading>
169
+ // <Text>There are two places to reference tokens at this time…</Text>
170
+ // <TextListItem label="• Color tokens:">
171
+ // Reference them from our internal `useTheme` hook to ensure the correct light or dark
172
+ // mode color token is used.
173
+ // </TextListItem>
174
+ // <TextListItem label="• All other tokens:">
175
+ // Use the `computedToken` function from `@planningcenter/tapestry` by passing it a string
176
+ // with the token's name. This function provides Typescript support and maps to the token's
177
+ // raw CSS value. There is another function called `token`, but it maps to CSS custom
178
+ // properties which React Native doesn't support.
179
+ // </TextListItem>
180
+ // </TextRow>
181
+ // </TextGroup>
182
+ // </CollapsableSection>
183
+ // )
184
+ // }
185
+
186
+ function IndicatorsSection({ isLast }: SectionProps) {
187
+ const styles = useStyles()
188
+
189
+ return (
190
+ <CollapsableSection title="Indicators" isLast={isLast}>
191
+ <Group
192
+ title="Spinner"
193
+ description="Loading indicators that can be used within or close to atomic components. Not intended for full-screen loading."
194
+ >
195
+ <Row style={styles.spinnerContainer}>
196
+ <Spinner size={24} />
197
+ </Row>
198
+ </Group>
199
+ </CollapsableSection>
200
+ )
201
+ }
202
+
203
+ function HeadingTextSection({ isLast }: SectionProps) {
204
+ return (
205
+ <CollapsableSection title="Heading & Text" isLast={isLast}>
206
+ <Group
207
+ title="Heading"
208
+ description="Use for headings & titles as it includes the a11y 'header' role. Change the size and style with the h1-h4 variants."
209
+ >
210
+ <Row>
211
+ <Heading>Heading 1</Heading>
212
+ <Heading variant="h2">Heading 2</Heading>
213
+ <Heading variant="h3">Heading 3</Heading>
214
+ <Heading variant="h4">Heading 4</Heading>
215
+ </Row>
216
+ </Group>
217
+ <Group title="Text" description="Use for body copy and supporting text.">
218
+ <Row>
219
+ <Text>Plain text</Text>
220
+ <Text variant="secondary">Secondary</Text>
221
+ <Text variant="tertiary">Tertiary</Text>
222
+ <Text variant="footnote">Footnote</Text>
223
+ </Row>
224
+ </Group>
225
+ </CollapsableSection>
226
+ )
227
+ }
228
+
229
+ function PressablesSection({ isLast }: SectionProps) {
230
+ const styles = useStyles()
231
+
232
+ return (
233
+ <CollapsableSection title="Pressables" isLast={isLast}>
234
+ <Group
235
+ title="Button"
236
+ description="Feature fill and outline variants for primary and danger usecases, along with disabled & loading states. Optionally shows icons to the left and right of the text."
237
+ >
238
+ <Row>
239
+ <Button onPress={buttonPress} title="Default" size="sm" />
240
+ <Button onPress={buttonPress} title="Default" size="md" />
241
+ <Button onPress={buttonPress} title="Danger" appearance="danger" size="lg" />
242
+ </Row>
243
+ <Row>
244
+ <Button disabled onPress={buttonPress} title="Disabled" size="sm" />
245
+ <Button disabled onPress={buttonPress} title="Disabled" size="md" />
246
+ <Button disabled onPress={buttonPress} title="Disabled" appearance="danger" size="lg" />
247
+ </Row>
248
+ <Row>
249
+ <Button
250
+ onPress={buttonPress}
251
+ title="Default"
252
+ size="sm"
253
+ iconNameLeft="general.plus"
254
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
255
+ />
256
+ <Button
257
+ onPress={buttonPress}
258
+ title="Default"
259
+ size="md"
260
+ iconNameRight="churchCenter.sort"
261
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
262
+ />
263
+ <Button
264
+ onPress={buttonPress}
265
+ title="Danger"
266
+ appearance="danger"
267
+ size="lg"
268
+ iconNameLeft="groups.cards"
269
+ iconNameRight="general.downChevron"
270
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
271
+ />
272
+ </Row>
273
+ <Row>
274
+ <Button loading onPress={buttonPress} title="Default" size="sm" />
275
+ <Button loading onPress={buttonPress} title="Default" size="md" />
276
+ <Button loading onPress={buttonPress} title="Danger" appearance="danger" size="lg" />
277
+ </Row>
278
+ <Row>
279
+ <Button onPress={buttonPress} title="Default" size="sm" variant="outline" />
280
+ <Button onPress={buttonPress} title="Default" size="md" variant="outline" />
281
+ <Button
282
+ onPress={buttonPress}
283
+ title="Danger"
284
+ appearance="danger"
285
+ size="lg"
286
+ variant="outline"
287
+ />
288
+ </Row>
289
+ <Row>
290
+ <Button
291
+ onPress={buttonPress}
292
+ title="Default"
293
+ size="sm"
294
+ variant="outline"
295
+ iconNameLeft="general.plus"
296
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
297
+ />
298
+ <Button
299
+ onPress={buttonPress}
300
+ title="Default"
301
+ size="md"
302
+ variant="outline"
303
+ iconNameRight="churchCenter.sort"
304
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
305
+ />
306
+ <Button
307
+ onPress={buttonPress}
308
+ title="Danger"
309
+ appearance="danger"
310
+ size="lg"
311
+ variant="outline"
312
+ iconNameLeft="groups.cards"
313
+ iconNameRight="general.downChevron"
314
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
315
+ />
316
+ </Row>
317
+ <Row>
318
+ <Button
319
+ disabled
320
+ onPress={buttonPress}
321
+ title="Disabled"
322
+ size="sm"
323
+ variant="outline"
324
+ iconNameLeft="general.plus"
325
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
326
+ />
327
+ <Button
328
+ disabled
329
+ onPress={buttonPress}
330
+ title="Disabled"
331
+ size="md"
332
+ variant="outline"
333
+ iconNameRight="churchCenter.sort"
334
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
335
+ />
336
+ <Button
337
+ disabled
338
+ onPress={buttonPress}
339
+ title="Disabled"
340
+ appearance="danger"
341
+ size="lg"
342
+ variant="outline"
343
+ iconNameLeft="groups.cards"
344
+ iconNameRight="general.downChevron"
345
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
346
+ />
347
+ </Row>
348
+ <Row>
349
+ <Button
350
+ loading
351
+ onPress={buttonPress}
352
+ title="Default"
353
+ size="sm"
354
+ variant="outline"
355
+ iconNameLeft="general.plus"
356
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
357
+ />
358
+ <Button
359
+ loading
360
+ onPress={buttonPress}
361
+ title="Default"
362
+ size="md"
363
+ variant="outline"
364
+ iconNameRight="churchCenter.sort"
365
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
366
+ />
367
+ <Button
368
+ loading
369
+ onPress={buttonPress}
370
+ title="Danger"
371
+ appearance="danger"
372
+ size="lg"
373
+ variant="outline"
374
+ iconNameLeft="groups.cards"
375
+ iconNameRight="general.downChevron"
376
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
377
+ />
378
+ </Row>
379
+ </Group>
380
+ <Group
381
+ title="IconButton"
382
+ description="Supports different appearances, sizes, along with loading & disabled states. Use `iconStyle` for custom colors and font sizes. Requires `accessibilityLabel` as icon's don't provide context to screen readers."
383
+ >
384
+ <Row>
385
+ <IconButton
386
+ onPress={buttonPress}
387
+ name="general.paperclip"
388
+ accessibilityLabel="Add attachment"
389
+ accessibilityHint="Opens your device's image gallary"
390
+ size="md"
391
+ />
392
+ <IconButton
393
+ onPress={buttonPress}
394
+ name="general.paperclip"
395
+ accessibilityLabel="Add attachment"
396
+ accessibilityHint="Opens your device's image gallary"
397
+ appearance="danger"
398
+ size="lg"
399
+ />
400
+ <IconButton
401
+ onPress={buttonPress}
402
+ name="general.paperclip"
403
+ accessibilityLabel="Add attachment"
404
+ accessibilityHint="Opens your device's image gallary"
405
+ appearance="interaction"
406
+ size="xl"
407
+ />
408
+ <IconButton
409
+ onPress={buttonPress}
410
+ name="general.paperclip"
411
+ accessibilityLabel="Add attachment"
412
+ accessibilityHint="Opens your device's image gallary"
413
+ iconStyle={styles.customIconButtonColor}
414
+ size="xxl"
415
+ />
416
+ <IconButton
417
+ onPress={buttonPress}
418
+ name="general.paperclip"
419
+ accessibilityLabel="Add attachment"
420
+ accessibilityHint="Opens your device's image gallary"
421
+ size="xxxl"
422
+ />
423
+ </Row>
424
+ <Row>
425
+ <IconButton
426
+ onPress={buttonPress}
427
+ name="general.paperclip"
428
+ accessibilityLabel="Add attachment"
429
+ accessibilityHint="Opens your device's image gallary"
430
+ size="md"
431
+ disabled
432
+ />
433
+ <IconButton
434
+ onPress={buttonPress}
435
+ name="general.paperclip"
436
+ accessibilityLabel="Add attachment"
437
+ accessibilityHint="Opens your device's image gallary"
438
+ appearance="danger"
439
+ size="lg"
440
+ disabled
441
+ />
442
+ <IconButton
443
+ onPress={buttonPress}
444
+ name="general.paperclip"
445
+ accessibilityLabel="Add attachment"
446
+ accessibilityHint="Opens your device's image gallary"
447
+ appearance="interaction"
448
+ size="xl"
449
+ disabled
450
+ />
451
+ <IconButton
452
+ onPress={buttonPress}
453
+ name="general.paperclip"
454
+ accessibilityLabel="Add attachment"
455
+ accessibilityHint="Opens your device's image gallary"
456
+ iconStyle={styles.customIconButtonColor}
457
+ size="xxl"
458
+ disabled
459
+ />
460
+ <IconButton
461
+ onPress={buttonPress}
462
+ name="general.paperclip"
463
+ accessibilityLabel="Add attachment"
464
+ accessibilityHint="Opens your device's image gallary"
465
+ size="xxxl"
466
+ disabled
467
+ />
468
+ </Row>
469
+ <Row>
470
+ <IconButton
471
+ onPress={buttonPress}
472
+ name="general.paperclip"
473
+ accessibilityLabel="Add attachment"
474
+ accessibilityHint="Opens your device's image gallary"
475
+ size="md"
476
+ loading
477
+ />
478
+ <IconButton
479
+ onPress={buttonPress}
480
+ name="general.paperclip"
481
+ accessibilityLabel="Add attachment"
482
+ accessibilityHint="Opens your device's image gallary"
483
+ appearance="danger"
484
+ size="lg"
485
+ loading
486
+ />
487
+ <IconButton
488
+ onPress={buttonPress}
489
+ name="general.paperclip"
490
+ accessibilityLabel="Add attachment"
491
+ accessibilityHint="Opens your device's image gallary"
492
+ appearance="interaction"
493
+ size="xl"
494
+ loading
495
+ />
496
+ <IconButton
497
+ onPress={buttonPress}
498
+ name="general.paperclip"
499
+ accessibilityLabel="Add attachment"
500
+ accessibilityHint="Opens your device's image gallary"
501
+ iconStyle={styles.customIconButtonColor}
502
+ size="xxl"
503
+ loading
504
+ />
505
+ <IconButton
506
+ onPress={buttonPress}
507
+ name="general.paperclip"
508
+ accessibilityLabel="Add attachment"
509
+ accessibilityHint="Opens your device's image gallary"
510
+ size="xxxl"
511
+ loading
512
+ />
513
+ </Row>
514
+ </Group>
515
+ <Group
516
+ title="TextButton"
517
+ description="Pressable text with default & danger appearance options. Can be disabled and accept `Text` variance props."
518
+ >
519
+ <Row>
520
+ <TextButton onPress={buttonPress}>Default</TextButton>
521
+ <TextButton onPress={buttonPress} variant="secondary">
522
+ Default
523
+ </TextButton>
524
+ <TextButton onPress={buttonPress} variant="tertiary">
525
+ Default
526
+ </TextButton>
527
+ <TextButton onPress={buttonPress} variant="footnote">
528
+ Default
529
+ </TextButton>
530
+ </Row>
531
+ <Row>
532
+ <TextButton onPress={buttonPress} appearance="danger">
533
+ Danger
534
+ </TextButton>
535
+ <TextButton onPress={buttonPress} variant="secondary" appearance="danger">
536
+ Danger
537
+ </TextButton>
538
+ <TextButton onPress={buttonPress} variant="tertiary" appearance="danger">
539
+ Danger
540
+ </TextButton>
541
+ <TextButton onPress={buttonPress} variant="footnote" appearance="danger">
542
+ Danger
543
+ </TextButton>
544
+ </Row>
545
+ <Row>
546
+ <TextButton onPress={buttonPress} disabled>
547
+ Disabled
548
+ </TextButton>
549
+ <TextButton onPress={buttonPress} variant="secondary" disabled>
550
+ Disabled
551
+ </TextButton>
552
+ <TextButton onPress={buttonPress} variant="tertiary" disabled>
553
+ Disabled
554
+ </TextButton>
555
+ <TextButton onPress={buttonPress} variant="footnote" disabled>
556
+ Disabled
557
+ </TextButton>
558
+ </Row>
559
+ </Group>
560
+ <Group
561
+ title="TextInlineButton"
562
+ description="Supports nesting within `Text`. Temporary component until React Native fixes a layout bug in `Pressable` which used in `TextButton`."
563
+ >
564
+ <Row style={styles.alignRowLeft}>
565
+ <Text>
566
+ This text is next to{' '}
567
+ <TextInlineButton onPress={buttonPress}>default button text</TextInlineButton> Lorem
568
+ ipsum dolor{' '}
569
+ <TextInlineButton onPress={buttonPress} appearance="danger">
570
+ danger button text
571
+ </TextInlineButton>{' '}
572
+ consectetur{' '}
573
+ <TextInlineButton onPress={buttonPress} disabled>
574
+ disabled button text
575
+ </TextInlineButton>{' '}
576
+ elit.
577
+ </Text>
578
+ <Text variant="secondary">
579
+ This text is next to{' '}
580
+ <TextInlineButton variant="secondary" onPress={buttonPress}>
581
+ default button text
582
+ </TextInlineButton>{' '}
583
+ Lorem ipsum dolor{' '}
584
+ <TextInlineButton variant="secondary" onPress={buttonPress} appearance="danger">
585
+ danger button text
586
+ </TextInlineButton>{' '}
587
+ consectetur{' '}
588
+ <TextInlineButton variant="secondary" onPress={buttonPress} disabled>
589
+ disabled button text
590
+ </TextInlineButton>{' '}
591
+ elit.
592
+ </Text>
593
+ <Text variant="tertiary">
594
+ This text is next to{' '}
595
+ <TextInlineButton variant="tertiary" onPress={buttonPress}>
596
+ default button text
597
+ </TextInlineButton>{' '}
598
+ Lorem ipsum dolor{' '}
599
+ <TextInlineButton variant="tertiary" onPress={buttonPress} appearance="danger">
600
+ danger button text
601
+ </TextInlineButton>{' '}
602
+ consectetur{' '}
603
+ <TextInlineButton variant="tertiary" onPress={buttonPress} disabled>
604
+ disabled button text
605
+ </TextInlineButton>{' '}
606
+ elit.
607
+ </Text>
608
+ <Text variant="footnote">
609
+ This text is next to{' '}
610
+ <TextInlineButton variant="footnote" onPress={buttonPress}>
611
+ default button text
612
+ </TextInlineButton>{' '}
613
+ Lorem ipsum dolor{' '}
614
+ <TextInlineButton variant="footnote" onPress={buttonPress} appearance="danger">
615
+ danger button text
616
+ </TextInlineButton>{' '}
617
+ consectetur{' '}
618
+ <TextInlineButton variant="footnote" onPress={buttonPress} disabled>
619
+ disabled button text
620
+ </TextInlineButton>{' '}
621
+ elit.
622
+ </Text>
623
+ </Row>
624
+ </Group>
625
+ </CollapsableSection>
626
+ )
627
+ }
628
+
629
+ function ImageIconsSection({ isLast }: SectionProps) {
630
+ const styles = useStyles()
631
+ const { colors } = useTheme()
632
+
633
+ return (
634
+ <CollapsableSection title="Images & Icons" isLast={isLast}>
635
+ <Group
636
+ title="Image"
637
+ description="Foundational way of displaying images. Loading or broken images will fallback to show a spinner. Hide decortive images from screen readers with `alt=''`."
638
+ >
639
+ <Row>
640
+ <Image source={{ uri: URL.broken }} style={styles.image} alt="Mountain sunrise" />
641
+ <Image source={{ uri: URL.image }} style={styles.image} alt="Mountain sunrise" />
642
+ <Image source={{ uri: URL.image }} style={styles.image} alt="" />
643
+ </Row>
644
+ </Group>
645
+ <Group
646
+ title="Avatar"
647
+ description='Displays the profile image for a user in different sizes and has a loading fallback. Can optionally show an online/offline "presence" indicator.'
648
+ >
649
+ <Row>
650
+ <Avatar sourceUri={URL.broken} />
651
+ <Avatar size="md" sourceUri={URL.avatar_fallback} />
652
+ <Avatar sourceUri={URL.avatar} />
653
+ </Row>
654
+ <Row>
655
+ <Avatar presence="offline" sourceUri={URL.broken} />
656
+ <Avatar presence="online" size="md" sourceUri={URL.avatar_fallback} />
657
+ <Avatar presence="offline" sourceUri={URL.avatar} />
658
+ </Row>
659
+ </Group>
660
+ <Group
661
+ title="AvatarGroup"
662
+ description="Shows 1-4 images in a grid at different sizes. Loading fallback shows until all images successfully load."
663
+ >
664
+ <Row>
665
+ <AvatarGroup sourceUris={[URL.broken]} />
666
+ <AvatarGroup sourceUris={[URL.broken, URL.broken, ...URL.two_avatars]} />
667
+ <AvatarGroup sourceUris={[URL.avatar]} />
668
+ <AvatarGroup sourceUris={URL.two_avatars} />
669
+ <AvatarGroup sourceUris={URL.three_avatars} />
670
+ <AvatarGroup sourceUris={URL.four_avatars} />
671
+ </Row>
672
+ </Group>
673
+ <Group
674
+ title="Icon"
675
+ description="Displays any icon from @planningcenter/icons. Missing icons will fallback to a grey circle. Styling with `fontSize` will allow it to scale with the device's text a11y size."
676
+ >
677
+ <Row>
678
+ <Icon name="missingIcon" size={20} />
679
+ <Icon name="general.textMessage" size={20} />
680
+ <Icon name="general.bell" size={20} color={colors.needsDesignPass} />
681
+ <Icon name="churchCenter.sort" style={styles.icon} />
682
+ </Row>
683
+ </Group>
684
+ </CollapsableSection>
685
+ )
686
+ }
687
+
688
+ function FormControlsSection({ isLast }: SectionProps) {
689
+ const [switchEnabled, setSwitchEnabled] = useState(false)
690
+ return (
691
+ <CollapsableSection title="Form Controls" isLast={isLast}>
692
+ <Group
693
+ title="Switch"
694
+ description="Use to toggle a boolean value for some sort of contained setting. (ie. Muting a conversation) This is a light wrapper that takes into account themed colors."
695
+ >
696
+ <Row>
697
+ <Switch value={switchEnabled} onValueChange={value => setSwitchEnabled(value)} />
698
+ <Switch disabled />
699
+ </Row>
700
+ </Group>
701
+ </CollapsableSection>
702
+ )
703
+ }
704
+
705
+ function StatusComponentsSection({ isLast }: SectionProps) {
706
+ return (
707
+ <CollapsableSection title="Status components" isLast={isLast}>
708
+ <Group
709
+ title="Badge"
710
+ description="Badge that can convey a status and show an icon. It also supports a meta label and product logo for the conversation list and conversation header. Target products can change colors and hide the logo via theming."
711
+ >
712
+ <Row>
713
+ <Badge label="Neutral" appearance="neutral" />
714
+ <Badge label="Error" appearance="error" />
715
+ <Badge label="Info" appearance="info" />
716
+ <Badge label="Success" appearance="success" />
717
+ <Badge label="Warning" appearance="warning" />
718
+ </Row>
719
+ <Row>
720
+ <Badge label="Neutral" appearance="neutral" iconName="general.star" />
721
+ <Badge label="Error" appearance="error" iconName="general.exclamationTriangle" />
722
+ <Badge label="Info" appearance="info" iconName="general.outlinedInfoCircle" />
723
+ <Badge label="Success" appearance="success" iconName="general.check" />
724
+ <Badge label="Warning" appearance="warning" iconName="general.shieldExclamation" />
725
+ </Row>
726
+ <Row>
727
+ <Badge
728
+ variant="meta"
729
+ productLogoName="groups"
730
+ label="Group"
731
+ metaLabel="Worlds longest group name that will probably overflow if it gets very much longer"
732
+ />
733
+ <Badge variant="meta" productLogoName="groups" label="Group" metaLabel="Young adults" />
734
+ <Badge variant="meta" productLogoName="services" label="Plan" metaLabel="June 19, 2025" />
735
+ <Badge variant="meta" productLogoName="services" label="Team" />
736
+ </Row>
737
+ <Row>
738
+ <Badge
739
+ variant="metaSubtle"
740
+ productLogoName="groups"
741
+ label="Group"
742
+ metaLabel="Worlds longest group name that will probably overflow if it gets very much longer"
743
+ />
744
+ <Badge
745
+ variant="metaSubtle"
746
+ productLogoName="groups"
747
+ label="Group"
748
+ metaLabel="Young adults"
749
+ />
750
+ <Badge
751
+ variant="metaSubtle"
752
+ productLogoName="services"
753
+ label="Plan"
754
+ metaLabel="June 19, 2025"
755
+ />
756
+ <Badge variant="metaSubtle" productLogoName="services" label="Team" />
757
+ </Row>
758
+ </Group>
759
+ </CollapsableSection>
760
+ )
761
+ }
762
+
763
+ // =================================
764
+ // ====== Docs UI ==================
765
+ // =================================
627
766
  interface CollapsableSectionProps {
628
767
  children: React.ReactNode
629
768
  title: string
@@ -711,6 +850,10 @@ function TextListItem({ label, children }: TextListItemProps) {
711
850
  )
712
851
  }
713
852
 
853
+ // =================================
854
+ // ====== Styles ===================
855
+ // =================================
856
+
714
857
  const useStyles = () => {
715
858
  const { colors } = useTheme()
716
859