braid-design-system 31.0.0 → 31.2.2

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 (106) hide show
  1. package/.nvmrc +1 -1
  2. package/CHANGELOG.md +58 -0
  3. package/color-mode/index.ts +9 -0
  4. package/css/atoms.docs.tsx +26 -20
  5. package/css/colorModeStyle.docs.tsx +81 -0
  6. package/css/index.ts +5 -1
  7. package/lib/components/Alert/Alert.css.ts +19 -0
  8. package/lib/components/Alert/Alert.docs.tsx +17 -5
  9. package/lib/components/Alert/Alert.tsx +61 -30
  10. package/lib/components/Badge/Badge.tsx +11 -31
  11. package/lib/components/Box/BackgroundContext.tsx +34 -17
  12. package/lib/components/Box/Box.docs.tsx +34 -14
  13. package/lib/components/Box/Box.playroom.tsx +37 -0
  14. package/lib/components/Box/Box.tsx +38 -7
  15. package/lib/components/Box/BoxRenderer.tsx +28 -9
  16. package/lib/components/Box/ColoredBox.tsx +168 -13
  17. package/lib/components/BraidPortal/BraidPortal.tsx +4 -1
  18. package/lib/components/BraidProvider/BraidProvider.tsx +11 -3
  19. package/lib/components/BraidProvider/VanillaThemeContainer.tsx +24 -0
  20. package/lib/components/Button/Button.css.ts +38 -5
  21. package/lib/components/Button/Button.screenshots.tsx +4 -1
  22. package/lib/components/Button/Button.tsx +102 -70
  23. package/lib/components/Card/Card.tsx +2 -13
  24. package/lib/components/Checkbox/Checkbox.screenshots.tsx +17 -8
  25. package/lib/components/Divider/Divider.css.ts +45 -4
  26. package/lib/components/Divider/Divider.tsx +20 -14
  27. package/lib/components/Dropdown/Dropdown.docs.tsx +0 -1
  28. package/lib/components/FieldLabel/FieldLabel.docs.tsx +1 -1
  29. package/lib/components/FieldMessage/FieldMessage.screenshots.tsx +6 -0
  30. package/lib/components/Heading/Heading.docs.tsx +6 -4
  31. package/lib/components/Heading/Heading.screenshots.tsx +4 -1
  32. package/lib/components/Loader/Loader.css.ts +3 -4
  33. package/lib/components/Loader/Loader.screenshots.tsx +4 -1
  34. package/lib/components/Loader/Loader.tsx +27 -30
  35. package/lib/components/MenuItem/MenuItemLink.tsx +9 -2
  36. package/lib/components/MenuItem/useMenuItem.tsx +4 -4
  37. package/lib/components/MenuItemCheckbox/MenuItemCheckbox.tsx +3 -1
  38. package/lib/components/MenuRenderer/testHelper.tsx +5 -2
  39. package/lib/components/Pagination/Pagination.css.ts +17 -3
  40. package/lib/components/Pagination/Pagination.tsx +6 -5
  41. package/lib/components/Rating/Rating.css.ts +16 -3
  42. package/lib/components/Rating/Rating.screenshots.tsx +4 -1
  43. package/lib/components/Rating/Rating.tsx +6 -1
  44. package/lib/components/Tabs/Tab.tsx +6 -2
  45. package/lib/components/Tabs/Tabs.css.ts +9 -1
  46. package/lib/components/Tabs/Tabs.tsx +4 -1
  47. package/lib/components/Text/Text.docs.tsx +4 -0
  48. package/lib/components/Text/Text.screenshots.tsx +8 -1
  49. package/lib/components/TextField/TextField.docs.tsx +0 -1
  50. package/lib/components/TextLink/TextLink.css.ts +139 -0
  51. package/lib/components/TextLink/TextLink.docs.tsx +1 -1
  52. package/lib/components/TextLink/TextLink.screenshots.tsx +3 -1
  53. package/lib/components/TextLink/TextLink.tsx +45 -37
  54. package/lib/components/Textarea/Highlight/Highlight.tsx +1 -1
  55. package/lib/components/Textarea/Textarea.docs.tsx +0 -1
  56. package/lib/components/Toggle/Toggle.css.ts +34 -7
  57. package/lib/components/Toggle/Toggle.tsx +8 -3
  58. package/lib/components/iconButtons/IconButton.css.ts +0 -32
  59. package/lib/components/iconButtons/IconButton.tsx +26 -48
  60. package/lib/components/icons/IconTip/IconTip.docs.tsx +20 -0
  61. package/lib/components/icons/IconTip/IconTip.tsx +12 -0
  62. package/lib/components/icons/IconTip/IconTipSvg.tsx +21 -0
  63. package/lib/components/icons/IconZoomIn/IconZoomIn.docs.tsx +20 -0
  64. package/lib/components/icons/IconZoomIn/IconZoomIn.tsx +12 -0
  65. package/lib/components/icons/IconZoomIn/IconZoomInSvg.tsx +20 -0
  66. package/lib/components/icons/IconZoomOut/IconZoomOut.docs.tsx +20 -0
  67. package/lib/components/icons/IconZoomOut/IconZoomOut.tsx +12 -0
  68. package/lib/components/icons/IconZoomOut/IconZoomOutSvg.tsx +20 -0
  69. package/lib/components/icons/Icons.screenshots.tsx +2 -2
  70. package/lib/components/icons/index.ts +3 -0
  71. package/lib/components/index.ts +3 -1
  72. package/lib/components/private/Field/Field.css.ts +2 -1
  73. package/lib/components/private/Field/Field.tsx +4 -6
  74. package/lib/components/private/InlineField/InlineField.css.ts +6 -6
  75. package/lib/components/private/InlineField/StyledInput.tsx +14 -9
  76. package/lib/components/private/Keyline/Keyline.css.ts +70 -0
  77. package/lib/components/private/Keyline/Keyline.tsx +38 -0
  78. package/lib/components/private/Placeholder/Placeholder.css.ts +44 -12
  79. package/lib/components/private/Placeholder/Placeholder.tsx +7 -3
  80. package/lib/components/private/touchable/debugTouchable.ts +7 -7
  81. package/lib/components/private/touchable/virtualTouchable.css.ts +12 -12
  82. package/lib/components/useToast/Toast.tsx +2 -8
  83. package/lib/css/atoms/atomicProperties.ts +7 -2
  84. package/lib/css/atoms/sprinkles.css.ts +24 -0
  85. package/lib/css/colorModeStyle.ts +33 -0
  86. package/lib/css/reset/reset.css.ts +12 -8
  87. package/lib/hooks/typography/index.ts +8 -61
  88. package/lib/hooks/typography/typography.css.ts +95 -93
  89. package/lib/hooks/useIcon/index.ts +4 -2
  90. package/lib/playroom/FrameComponent.tsx +50 -17
  91. package/lib/playroom/components.ts +1 -0
  92. package/lib/playroom/useScope.ts +44 -1
  93. package/lib/stories/all.stories.tsx +61 -30
  94. package/lib/themes/baseTokens/apac.ts +8 -0
  95. package/lib/themes/catho/tokens.ts +23 -6
  96. package/lib/themes/docs/tokens.ts +8 -0
  97. package/lib/themes/makeBraidTheme.ts +4 -1
  98. package/lib/themes/occ/tokens.ts +25 -5
  99. package/lib/themes/seekAnz/tokens.ts +25 -5
  100. package/lib/themes/tokenType.ts +8 -0
  101. package/lib/themes/wireframe/tokens.ts +22 -5
  102. package/package.json +2 -2
  103. package/sku.config.js +1 -0
  104. package/sku.routes.js +2 -0
  105. package/tsconfig.json +1 -0
  106. package/lib/components/Card/Card.css.ts +0 -6
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ComponentDocs } from '../../../site/src/types';
3
3
  import {
4
- Box,
5
4
  Text,
6
5
  TextLink,
7
6
  Stack,
@@ -12,6 +11,10 @@ import {
12
11
  Strong,
13
12
  Alert,
14
13
  } from '../';
14
+ // TODO: COLORMODE RELEASE
15
+ // Use public import
16
+ import { Box } from './Box';
17
+ import type { SimpleBackground } from './Box';
15
18
  import source from '../../utils/source.macro';
16
19
  import Code from '../../../site/src/App/Code/Code';
17
20
  import {
@@ -23,15 +26,12 @@ import {
23
26
  PseudoProperties,
24
27
  BoxShadow,
25
28
  } from '../../css/atoms/atomicProperties';
26
- import { vars } from '../../themes/vars.css';
27
29
  import { ThemedExample } from '../../../site/src/App/ThemeSetting';
28
30
 
29
- type BackgroundDocs = Required<
30
- Record<keyof typeof vars.backgroundColor, string>
31
- >;
31
+ type BackgroundDocs = Required<Record<SimpleBackground, string>>;
32
32
  const validateBackgrounds = (backgrounds: BackgroundDocs) => backgrounds;
33
33
 
34
- type BoxShadowDocs = Required<Record<Exclude<BoxShadow, 'none'>, string>>;
34
+ type BoxShadowDocs = Required<Record<BoxShadow, string>>;
35
35
  const validateBoxShadows = (boxShadows: BoxShadowDocs) => boxShadows;
36
36
 
37
37
  interface AtomicPropertyProps {
@@ -466,6 +466,9 @@ const docs: ComponentDocs = {
466
466
  {Object.entries(
467
467
  validateBackgrounds({
468
468
  body: 'Used for elements that need to match the body background.',
469
+ // TODO: COLORMODE RELEASE
470
+ // bodyDark:
471
+ // 'Used for elements that need to match the body background in dark context.',
469
472
  brand: 'Used for branding larger areas of the screen.',
470
473
  brandAccent: 'Used for hero elements on the screen.',
471
474
  brandAccentHover: 'Hover colour for “brandAccent” elements.',
@@ -508,6 +511,9 @@ const docs: ComponentDocs = {
508
511
  neutralSoftActive: 'Active colour for "neutralSoft" elements',
509
512
  neutralSoftHover: 'Hover colour for "neutralSoft" elements',
510
513
  surface: 'Used for surfaces that sit on top of body elements',
514
+ // TODO: COLORMODE RELEASE
515
+ // surfaceDark:
516
+ // 'Used for surfaces that sit on top of body elements in a dark context',
511
517
  }),
512
518
  ).map(([background, description]) => (
513
519
  <Columns key={background} space="medium" alignY="center">
@@ -518,11 +524,17 @@ const docs: ComponentDocs = {
518
524
  padding="gutter"
519
525
  >
520
526
  <Box
521
- background={background as keyof BackgroundDocs}
527
+ background={{
528
+ lightMode: background as keyof BackgroundDocs,
529
+ darkMode: background as keyof BackgroundDocs,
530
+ }}
522
531
  boxShadow={
523
- background === 'surface'
524
- ? 'borderNeutralLight'
525
- : undefined
532
+ (
533
+ {
534
+ surface: { lightMode: 'borderNeutralLight' },
535
+ surfaceDark: { darkMode: 'borderNeutral' },
536
+ } as const
537
+ )[background]
526
538
  }
527
539
  borderRadius="large"
528
540
  padding="gutter"
@@ -632,14 +644,22 @@ const docs: ComponentDocs = {
632
644
  <Columns key={boxShadow} space="medium" alignY="center">
633
645
  <Column width="content">
634
646
  <Box
635
- background={
636
- boxShadow.includes('Inverted') ? 'brand' : 'surface'
637
- }
647
+ background={{
648
+ lightMode: boxShadow.includes('Inverted')
649
+ ? 'neutral'
650
+ : 'surface',
651
+ darkMode: /^border|outline/.test(boxShadow)
652
+ ? 'surfaceDark'
653
+ : 'surface',
654
+ }}
638
655
  borderRadius="large"
639
656
  padding="gutter"
640
657
  >
641
658
  <Box
642
- boxShadow={boxShadow as keyof BoxShadowDocs}
659
+ boxShadow={{
660
+ lightMode: boxShadow as keyof BoxShadowDocs,
661
+ darkMode: boxShadow as keyof BoxShadowDocs,
662
+ }}
643
663
  borderRadius="large"
644
664
  padding="gutter"
645
665
  />
@@ -0,0 +1,37 @@
1
+ import React, { forwardRef } from 'react';
2
+ import { atoms, Atoms } from '../../css/atoms/atoms';
3
+ import { sprinkles } from '../../css/atoms/sprinkles.css';
4
+ import { Box as BraidBox, BoxProps } from './Box';
5
+
6
+ export const Box = forwardRef<HTMLElement, BoxProps>((props, ref) => {
7
+ const sprinklesProps: Record<string, unknown> = {};
8
+ const otherProps: Record<string, unknown> = {};
9
+
10
+ for (const key in props) {
11
+ if (sprinkles.properties.has(key as keyof Omit<Atoms, 'reset'>)) {
12
+ const value = props[key as keyof typeof props];
13
+ try {
14
+ // Try passing to atoms, if sprinkle property but value is not
15
+ // valid, property will be left out until value is valid.
16
+ atoms({ [key]: value });
17
+ sprinklesProps[key] = value;
18
+ } catch (e) {
19
+ if (key === 'background') {
20
+ if (
21
+ (typeof value === 'string' &&
22
+ /^customDark|customLight$/.test(value)) ||
23
+ (typeof value === 'object' && (value.darkMode || value.lightMode))
24
+ ) {
25
+ sprinklesProps[key] = value;
26
+ }
27
+ }
28
+ }
29
+ } else {
30
+ otherProps[key] = props[key as keyof typeof props];
31
+ }
32
+ }
33
+
34
+ return <BraidBox ref={ref} {...sprinklesProps} {...otherProps} />;
35
+ });
36
+
37
+ Box.displayName = 'Box';
@@ -9,15 +9,15 @@ import React, {
9
9
  import dedent from 'dedent';
10
10
  import { base as baseReset } from '../../css/reset/reset.css';
11
11
  import { atoms, Atoms } from '../../css/atoms/atoms';
12
- import { sprinkles } from '../../css/atoms/sprinkles.css';
12
+ import { sprinkles, ColorModeValue } from '../../css/atoms/sprinkles.css';
13
13
  import { ColoredBox } from './ColoredBox';
14
- import { Background } from '../../css/atoms/atomicProperties';
14
+ import { Background, BoxShadow } from '../../css/atoms/atomicProperties';
15
15
 
16
16
  export type BoxBackgroundVariant = Background | 'customDark' | 'customLight';
17
17
 
18
18
  export interface BoxBaseProps extends Omit<Atoms, 'reset' | 'background'> {
19
19
  className?: ClassValue;
20
- background?: BoxBackgroundVariant;
20
+ background?: ColorModeValue<BoxBackgroundVariant>;
21
21
  }
22
22
 
23
23
  export interface BoxProps
@@ -27,7 +27,7 @@ export interface BoxProps
27
27
  }
28
28
 
29
29
  export const Box = forwardRef<HTMLElement, BoxProps>(
30
- ({ component = 'div', className, ...props }, ref) => {
30
+ ({ component = 'div', className, background, boxShadow, ...props }, ref) => {
31
31
  const atomProps: Record<string, unknown> = {};
32
32
  const nativeProps: Record<string, unknown> = {};
33
33
 
@@ -61,17 +61,17 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
61
61
  const atomicClasses = atoms({
62
62
  reset: typeof component === 'string' ? component : 'div',
63
63
  ...atomProps,
64
- background: undefined,
65
64
  });
66
65
 
67
66
  const combinedClasses = `${atomicClasses}${
68
67
  userClasses ? ` ${userClasses}` : ''
69
68
  }`;
70
69
 
71
- return props.background ? (
70
+ return background || boxShadow ? (
72
71
  <ColoredBox
73
72
  component={component}
74
- background={props.background}
73
+ background={background}
74
+ boxShadow={boxShadow}
75
75
  className={combinedClasses}
76
76
  ref={ref}
77
77
  {...nativeProps}
@@ -87,3 +87,34 @@ export const Box = forwardRef<HTMLElement, BoxProps>(
87
87
  );
88
88
 
89
89
  Box.displayName = 'Box';
90
+
91
+ // TODO: COLORMODE RELEASE
92
+ // Remove PublicBox
93
+ export type SimpleBackground = Exclude<Background, 'bodyDark' | 'surfaceDark'>;
94
+ export interface PublicBoxProps extends BoxProps {
95
+ background?: SimpleBackground | 'customDark' | 'customLight';
96
+ boxShadow?: BoxShadow;
97
+ }
98
+
99
+ export const PublicBox = forwardRef<HTMLElement, PublicBoxProps>(
100
+ (props, ref) => {
101
+ if (process.env.NODE_ENV !== 'production') {
102
+ if (
103
+ typeof props.background !== 'undefined' &&
104
+ typeof props.background !== 'string'
105
+ ) {
106
+ throw new Error('Conditional backgrounds are not suppported');
107
+ }
108
+
109
+ if (
110
+ typeof props.boxShadow !== 'undefined' &&
111
+ typeof props.boxShadow !== 'string'
112
+ ) {
113
+ throw new Error('Conditional boxShadows are not suppported');
114
+ }
115
+ }
116
+ return <Box {...props} ref={ref} />;
117
+ },
118
+ );
119
+
120
+ PublicBox.displayName = 'Box';
@@ -1,28 +1,42 @@
1
1
  import React, { ReactElement } from 'react';
2
2
  import clsx from 'clsx';
3
- import { renderBackgroundProvider } from './BackgroundContext';
3
+ import { BackgroundProvider } from './BackgroundContext';
4
4
  import { atoms, Atoms } from '../../css/atoms/atoms';
5
- import { BoxBaseProps } from './Box';
6
- import { resolveBackgroundAtom } from './ColoredBox';
5
+ import { BoxBaseProps, SimpleBackground } from './Box';
6
+ import { useColoredBoxClasses } from './ColoredBox';
7
+ import { BoxShadow } from '../../css/atoms/atomicProperties';
7
8
 
8
9
  export interface BoxRendererProps extends BoxBaseProps {
9
10
  component?: Atoms['reset'];
11
+ // TODO: COLORMODE RELEASE
12
+ // Remove overrides
13
+ background?: SimpleBackground | 'customDark' | 'customLight';
14
+ boxShadow?: BoxShadow;
10
15
  children: (className: string) => ReactElement | null;
11
16
  }
12
17
 
13
18
  const ColoredBoxRenderer = ({
14
19
  background,
20
+ boxShadow,
15
21
  children,
16
22
  className,
17
23
  }: {
18
- background: NonNullable<BoxRendererProps['background']>;
24
+ background: BoxRendererProps['background'];
25
+ boxShadow: BoxRendererProps['boxShadow'];
19
26
  children: BoxRendererProps['children'];
20
27
  className: string;
21
28
  }) => {
22
- const colorClasses = resolveBackgroundAtom(background);
23
- const element = children(clsx(className, colorClasses));
29
+ const { backgroundContext, classList } = useColoredBoxClasses({
30
+ background,
31
+ boxShadow,
32
+ });
33
+ const element = children(clsx(className, classList));
24
34
 
25
- return renderBackgroundProvider(background, element);
35
+ return backgroundContext ? (
36
+ <BackgroundProvider value={backgroundContext}>{element}</BackgroundProvider>
37
+ ) : (
38
+ element
39
+ );
26
40
  };
27
41
 
28
42
  export const BoxRenderer = ({
@@ -30,12 +44,17 @@ export const BoxRenderer = ({
30
44
  component = 'div',
31
45
  className,
32
46
  background,
47
+ boxShadow,
33
48
  ...props
34
49
  }: BoxRendererProps) => {
35
50
  const classes = clsx(className, atoms({ reset: component, ...props }));
36
51
 
37
- return background ? (
38
- <ColoredBoxRenderer background={background} className={classes}>
52
+ return background || boxShadow ? (
53
+ <ColoredBoxRenderer
54
+ background={background}
55
+ boxShadow={boxShadow}
56
+ className={classes}
57
+ >
39
58
  {children}
40
59
  </ColoredBoxRenderer>
41
60
  ) : (
@@ -1,23 +1,172 @@
1
- import { createElement, forwardRef } from 'react';
1
+ import React, { createElement, forwardRef } from 'react';
2
2
  import { atoms } from '../../css/atoms/atoms';
3
- import { renderBackgroundProvider } from './BackgroundContext';
4
- import { BoxProps } from './Box';
3
+ import { useBraidTheme } from '../BraidProvider/BraidThemeContext';
4
+ import {
5
+ BackgroundProvider,
6
+ useBackground,
7
+ useBackgroundLightness,
8
+ } from './BackgroundContext';
9
+ import { BoxBackgroundVariant, BoxProps } from './Box';
10
+ import { Background, BoxShadow } from '../../css/atoms/atomicProperties';
11
+ import * as typographyStyles from '../../hooks/typography/typography.css';
5
12
 
6
13
  export interface ColoredBoxProps extends BoxProps {
7
14
  component: NonNullable<BoxProps['component']>;
8
- background: NonNullable<BoxProps['background']>;
9
15
  }
10
16
 
11
- export const resolveBackgroundAtom = (
12
- background: ColoredBoxProps['background'],
13
- ) =>
14
- background === 'customDark' || background === 'customLight'
15
- ? undefined
16
- : atoms({ background });
17
+ const adaptiveBackgrounds: Partial<Record<BoxBackgroundVariant, Background>> = {
18
+ body: 'bodyDark',
19
+ surface: 'surfaceDark',
20
+ brand: 'neutral',
21
+ promoteLight: 'neutral',
22
+ infoLight: 'neutral',
23
+ positiveLight: 'neutral',
24
+ cautionLight: 'neutral',
25
+ criticalLight: 'neutral',
26
+ neutralLight: 'neutral',
27
+ formAccentSoft: 'neutral',
28
+ formAccentSoftActive: 'neutralActive',
29
+ formAccentSoftHover: 'neutralHover',
30
+ };
31
+
32
+ const adaptiveBoxShadow: Partial<Record<BoxShadow, BoxShadow>> = {
33
+ borderBrandAccentLarge: 'borderBrandAccentLightLarge',
34
+ borderCaution: 'borderCautionLight',
35
+ borderCritical: 'borderCriticalLight',
36
+ borderCriticalLarge: 'borderCriticalLightLarge',
37
+ borderFormAccent: 'borderFormAccentLight',
38
+ borderFormAccentLarge: 'borderFormAccentLightLarge',
39
+ borderInfo: 'borderInfoLight',
40
+ borderNeutral: 'borderNeutralInverted',
41
+ borderNeutralLarge: 'borderNeutralInvertedLarge',
42
+ borderNeutralLight: 'borderNeutral',
43
+ borderPositive: 'borderPositiveLight',
44
+ borderPromote: 'borderPromoteLight',
45
+ };
46
+
47
+ const normaliseBackground = (background: ColoredBoxProps['background']) => ({
48
+ lightMode: typeof background === 'object' ? background.lightMode : background,
49
+ darkMode:
50
+ typeof background === 'object'
51
+ ? background.darkMode
52
+ : adaptiveBackgrounds[background!] || background,
53
+ });
54
+
55
+ const normalisedBoxShadow = (boxShadow: ColoredBoxProps['boxShadow']) => ({
56
+ lightMode: typeof boxShadow === 'object' ? boxShadow.lightMode : boxShadow,
57
+ darkMode: typeof boxShadow === 'object' ? boxShadow.darkMode : boxShadow,
58
+ });
59
+
60
+ export const useColoredBoxClasses = ({
61
+ background,
62
+ boxShadow,
63
+ }: {
64
+ background?: ColoredBoxProps['background'];
65
+ boxShadow?: ColoredBoxProps['boxShadow'];
66
+ }) => {
67
+ const parentLightness = useBackgroundLightness();
68
+ const currentBackgroundContext = useBackground();
69
+ const { backgroundLightness } = useBraidTheme();
70
+ const lightnessMap = {
71
+ ...backgroundLightness,
72
+ customDark: 'dark',
73
+ customLight: 'light',
74
+ } as const;
75
+
76
+ const classList: Array<string> = [];
77
+
78
+ if (boxShadow) {
79
+ const normalisedBoxShadows = normalisedBoxShadow(boxShadow);
80
+ const isSemantic = typeof boxShadow === 'string';
81
+
82
+ classList.push(
83
+ atoms({
84
+ boxShadow: {
85
+ lightMode:
86
+ isSemantic && parentLightness.lightMode === 'dark'
87
+ ? adaptiveBoxShadow[normalisedBoxShadows.lightMode!] ||
88
+ normalisedBoxShadows.lightMode
89
+ : normalisedBoxShadows.lightMode,
90
+ darkMode:
91
+ isSemantic && parentLightness.darkMode === 'dark'
92
+ ? adaptiveBoxShadow[normalisedBoxShadows.darkMode!] ||
93
+ normalisedBoxShadows.darkMode
94
+ : normalisedBoxShadows.darkMode,
95
+ },
96
+ }),
97
+ );
98
+ }
99
+
100
+ if (background) {
101
+ // ---------------------------------------------------------------------------
102
+ // Normalise simple background to populated conditional value
103
+ const { lightMode, darkMode } = normaliseBackground(background);
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Assign text tone vars based on the lightness context
107
+ classList.push(typographyStyles.lightModeTone[lightnessMap[lightMode!]]);
108
+ classList.push(typographyStyles.darkModeTone[lightnessMap[darkMode!]]);
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // Override `neutral` text tone based on the lightness context
112
+
113
+ // 1. If `neutral` background, check background tone in opposite color mode
114
+ const lightModeTone = lightMode === 'neutral' ? darkMode : lightMode;
115
+ const darkModeTone = darkMode === 'neutral' ? lightMode : darkMode;
116
+
117
+ // 2. If neutral text override exists for background, apply it
118
+ if (
119
+ lightModeTone &&
120
+ typographyStyles.lightModeNeutralOverride[lightModeTone]
121
+ ) {
122
+ classList.push(typographyStyles.lightModeNeutralOverride[lightModeTone]);
123
+ }
124
+
125
+ if (
126
+ darkModeTone &&
127
+ typographyStyles.darkModeNeutralOverride[darkModeTone]
128
+ ) {
129
+ classList.push(typographyStyles.darkModeNeutralOverride[darkModeTone]);
130
+ }
131
+
132
+ // ---------------------------------------------------------------------------
133
+ // Set background atoms classes
134
+ classList.push(
135
+ atoms({
136
+ background: {
137
+ lightMode:
138
+ lightMode === 'customDark' || lightMode === 'customLight'
139
+ ? undefined
140
+ : lightMode,
141
+ darkMode:
142
+ darkMode === 'customDark' || darkMode === 'customLight'
143
+ ? undefined
144
+ : darkMode,
145
+ },
146
+ }),
147
+ );
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Return updated background context and class list
151
+ return {
152
+ backgroundContext: {
153
+ lightMode: lightMode || currentBackgroundContext.lightMode,
154
+ darkMode: darkMode || currentBackgroundContext.darkMode,
155
+ },
156
+ classList: classList.join(' '),
157
+ };
158
+ }
159
+
160
+ return {
161
+ classList: classList.join(' '),
162
+ };
163
+ };
17
164
 
18
165
  export const ColoredBox = forwardRef<HTMLElement, ColoredBoxProps>(
19
- ({ component, background, className, ...props }, ref) => {
20
- const colorClasses = resolveBackgroundAtom(background);
166
+ ({ component, background, boxShadow, className, ...props }, ref) => {
167
+ const { backgroundContext, classList: colorClasses } = useColoredBoxClasses(
168
+ { background, boxShadow },
169
+ );
21
170
 
22
171
  const element = createElement(component, {
23
172
  className: `${className}${colorClasses ? ` ${colorClasses}` : ''}`,
@@ -25,7 +174,13 @@ export const ColoredBox = forwardRef<HTMLElement, ColoredBoxProps>(
25
174
  ref,
26
175
  });
27
176
 
28
- return renderBackgroundProvider(background, element);
177
+ return backgroundContext ? (
178
+ <BackgroundProvider value={backgroundContext}>
179
+ {element}
180
+ </BackgroundProvider>
181
+ ) : (
182
+ element
183
+ );
29
184
  },
30
185
  );
31
186
 
@@ -2,6 +2,7 @@ import React, { ReactNode } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import { TextContext } from '../Text/TextContext';
4
4
  import { useBraidTheme } from '../BraidProvider/BraidThemeContext';
5
+ import { VanillaThemeContainer } from '../BraidProvider/VanillaThemeContainer';
5
6
 
6
7
  export interface BraidPortalProps {
7
8
  children: ReactNode;
@@ -13,7 +14,9 @@ export const BraidPortal = ({ children, container }: BraidPortalProps) => {
13
14
 
14
15
  return createPortal(
15
16
  <TextContext.Provider value={false}>
16
- <div className={vanillaTheme}>{children}</div>
17
+ <VanillaThemeContainer theme={vanillaTheme} setDefaultTextTones>
18
+ {children}
19
+ </VanillaThemeContainer>
17
20
  </TextContext.Provider>,
18
21
  container ?? document.body,
19
22
  );
@@ -17,6 +17,8 @@ import { BraidTestProviderContext } from '../BraidTestProvider/BraidTestProvider
17
17
  import { BreakpointProvider } from './BreakpointContext';
18
18
  import { BraidThemeContext } from './BraidThemeContext';
19
19
  import { BraidTheme } from '../../themes/BraidTheme';
20
+ import { darkMode } from '../../css/atoms/sprinkles.css';
21
+ import { VanillaThemeContainer } from './VanillaThemeContainer';
20
22
 
21
23
  if (process.env.NODE_ENV === 'development') {
22
24
  ensureResetImported();
@@ -92,9 +94,15 @@ export const BraidProvider = ({
92
94
  <BraidThemeContext.Provider value={theme}>
93
95
  <TreatProvider theme={theme.treatTheme}>
94
96
  {styleBody ? (
95
- <style type="text/css">{`body{margin:0;padding:0;background:${theme.background}}`}</style>
97
+ <style type="text/css">{`
98
+ html,body{margin:0;padding:0;background:${theme.background.lightMode}}
99
+ html.${darkMode},html.${darkMode} body{color-scheme:dark;background:${theme.background.darkMode}}
100
+ `}</style>
96
101
  ) : null}
97
- <div className={theme.vanillaTheme}>
102
+ <VanillaThemeContainer
103
+ theme={theme.vanillaTheme}
104
+ setDefaultTextTones={!alreadyInBraidProvider}
105
+ >
98
106
  <LinkComponentContext.Provider
99
107
  value={linkComponent || linkComponentFromContext}
100
108
  >
@@ -104,7 +112,7 @@ export const BraidProvider = ({
104
112
  <BreakpointProvider>{children}</BreakpointProvider>
105
113
  )}
106
114
  </LinkComponentContext.Provider>
107
- </div>
115
+ </VanillaThemeContainer>
108
116
  </TreatProvider>
109
117
  </BraidThemeContext.Provider>
110
118
  );
@@ -0,0 +1,24 @@
1
+ import React, { ReactNode } from 'react';
2
+
3
+ import * as typographyStyles from '../../hooks/typography/typography.css';
4
+
5
+ interface Props {
6
+ children: ReactNode;
7
+ theme: string;
8
+ setDefaultTextTones: boolean;
9
+ }
10
+
11
+ const textTones = [
12
+ typographyStyles.lightModeTone.light,
13
+ typographyStyles.darkModeTone.dark,
14
+ ].join(' ');
15
+
16
+ export const VanillaThemeContainer = ({
17
+ children,
18
+ theme,
19
+ setDefaultTextTones,
20
+ }: Props) => (
21
+ <div className={`${theme}${setDefaultTextTones ? ` ${textTones}` : ''}`}>
22
+ {children}
23
+ </div>
24
+ );
@@ -1,6 +1,7 @@
1
1
  import { keyframes, style, styleVariants } from '@vanilla-extract/css';
2
2
  import { calc } from '@vanilla-extract/css-utils';
3
3
  import { rgba } from 'polished';
4
+ import { colorModeStyle } from '../../css/colorModeStyle';
4
5
  import { responsiveStyle } from '../../css/responsiveStyle';
5
6
  import { vars } from '../../themes/vars.css';
6
7
 
@@ -12,9 +13,11 @@ export const root = style({
12
13
  textDecoration: 'none',
13
14
  });
14
15
 
16
+ export const forceActive = style({});
17
+
15
18
  export const activeOverlay = style({
16
19
  selectors: {
17
- [`${root}:active &`]: {
20
+ [`${root}:active &, ${forceActive}&`]: {
18
21
  opacity: 1,
19
22
  },
20
23
  },
@@ -121,8 +124,38 @@ export const loadingDot = style({
121
124
  },
122
125
  });
123
126
 
124
- export const invertedBackgrounds = styleVariants({
125
- soft: { background: rgba('#fff', 0.075) },
126
- hover: { background: rgba('#fff', 0.15) },
127
- active: { background: rgba('#000', 0.05) },
127
+ export const invertedBackgroundsLightMode = styleVariants({
128
+ soft: colorModeStyle({
129
+ lightMode: {
130
+ background: rgba('#fff', 0.1),
131
+ },
132
+ }),
133
+ hover: colorModeStyle({
134
+ lightMode: {
135
+ background: rgba('#fff', 0.15),
136
+ },
137
+ }),
138
+ active: colorModeStyle({
139
+ lightMode: {
140
+ background: rgba('#fff', 0.15),
141
+ },
142
+ }),
143
+ });
144
+
145
+ export const invertedBackgroundsDarkMode = styleVariants({
146
+ soft: colorModeStyle({
147
+ darkMode: {
148
+ background: rgba('#fff', 0.1),
149
+ },
150
+ }),
151
+ hover: colorModeStyle({
152
+ darkMode: {
153
+ background: rgba('#fff', 0.15),
154
+ },
155
+ }),
156
+ active: colorModeStyle({
157
+ darkMode: {
158
+ background: rgba('#fff', 0.15),
159
+ },
160
+ }),
128
161
  });
@@ -1,6 +1,9 @@
1
1
  import React, { Fragment } from 'react';
2
2
  import { ComponentScreenshot } from '../../../site/src/types';
3
- import { Box, Button } from '../';
3
+ import { Button } from '../';
4
+ // TODO: COLORMODE RELEASE
5
+ // Use public import
6
+ import { Box } from '../Box/Box';
4
7
  import { Inline } from '../Inline/Inline';
5
8
  import { Heading } from '../Heading/Heading';
6
9
  import { backgrounds } from '../../utils/docsHelpers';