@zendeskgarden/react-theming 9.3.0 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,7 +42,37 @@ complex, depending on your needs:
42
42
  behavior and RTL layout of Garden's tabs component with an alternate visual
43
43
  design (i.e. closer to the look of browser tabs).
44
44
 
45
- ### RTL
45
+ #### Color scheme
46
+
47
+ The `ColorSchemeProvider` and `useColorScheme` hook add the capability for a
48
+ user to persist a preferred system color scheme (`'light'`, `'dark'`, or
49
+ `'system'`). See
50
+ [Storybook](https://zendeskgarden.github.io/react-components/?path=/docs/packages-theming-colorschemeprovider--color-scheme-provider)
51
+ for more details.
52
+
53
+ ```jsx
54
+ import {
55
+ useColorScheme,
56
+ ColorSchemeProvider,
57
+ ThemeProvider,
58
+ DEFAULT_THEME
59
+ } from '@zendeskgarden/react-theming';
60
+
61
+ const ThemedApp = ({ children }) => {
62
+ const { colorScheme } = useColorScheme();
63
+ const theme = { ...DEFAULT_THEME, colors: { ...DEFAULT_THEME.colors, base: colorScheme } };
64
+
65
+ return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
66
+ };
67
+
68
+ const App = ({ children }) => (
69
+ <ColorSchemeProvider>
70
+ <ThemedApp>{children}</ThemedApp>
71
+ </ColorSchemeProvider>
72
+ );
73
+ ```
74
+
75
+ #### RTL
46
76
 
47
77
  ```jsx
48
78
  import { ThemeProvider, DEFAULT_THEME } from '@zendeskgarden/react-theming';
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ import React, { createContext, useMemo, useCallback, useState, useEffect } from 'react';
8
+
9
+ const useColorScheme = function (initialState) {
10
+ let colorSchemeKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'color-scheme';
11
+ const localStorage = typeof window === 'undefined' ? undefined : window.localStorage;
12
+ const mediaQuery = typeof window === 'undefined' ? undefined : window.matchMedia('(prefers-color-scheme: dark)');
13
+ const getState = useCallback(_state => {
14
+ const isSystem = _state === 'system' || _state === undefined || _state === null;
15
+ let colorScheme;
16
+ if (isSystem) {
17
+ colorScheme = mediaQuery?.matches ? 'dark' : 'light';
18
+ } else {
19
+ colorScheme = _state;
20
+ }
21
+ return {
22
+ isSystem,
23
+ colorScheme
24
+ };
25
+ }, [mediaQuery?.matches]);
26
+ const [state, setState] = useState(getState(localStorage?.getItem(colorSchemeKey) || initialState));
27
+ useEffect(() => {
28
+ const eventListener = () => {
29
+ setState(getState('system'));
30
+ };
31
+ if (state.isSystem) {
32
+ mediaQuery?.addEventListener('change', eventListener);
33
+ } else {
34
+ mediaQuery?.removeEventListener('change', eventListener);
35
+ }
36
+ return () => {
37
+ mediaQuery?.removeEventListener('change', eventListener);
38
+ };
39
+ }, [getState, state.isSystem, mediaQuery]);
40
+ return {
41
+ isSystem: state.isSystem,
42
+ colorScheme: state.colorScheme,
43
+ setColorScheme: colorScheme => {
44
+ setState(getState(colorScheme));
45
+ localStorage?.setItem(colorSchemeKey, colorScheme);
46
+ }
47
+ };
48
+ };
49
+ const ColorSchemeContext = createContext(undefined);
50
+ const ColorSchemeProvider = _ref => {
51
+ let {
52
+ children,
53
+ colorSchemeKey,
54
+ initialColorScheme
55
+ } = _ref;
56
+ const {
57
+ isSystem,
58
+ colorScheme,
59
+ setColorScheme
60
+ } = useColorScheme(initialColorScheme, colorSchemeKey);
61
+ const contextValue = useMemo(() => ({
62
+ colorScheme,
63
+ isSystem,
64
+ setColorScheme
65
+ }), [isSystem, colorScheme, setColorScheme]);
66
+ return React.createElement(ColorSchemeContext.Provider, {
67
+ value: contextValue
68
+ }, children);
69
+ };
70
+
71
+ export { ColorSchemeContext, ColorSchemeProvider };
package/dist/esm/index.js CHANGED
@@ -4,10 +4,12 @@
4
4
  * Use of this source code is governed under the Apache License, Version 2.0
5
5
  * found at http://www.apache.org/licenses/LICENSE-2.0.
6
6
  */
7
+ export { ColorSchemeProvider } from './elements/ColorSchemeProvider.js';
7
8
  export { ThemeProvider } from './elements/ThemeProvider.js';
8
9
  export { default as DEFAULT_THEME } from './elements/theme/index.js';
9
10
  export { default as PALETTE } from './elements/palette/index.js';
10
11
  export { default as retrieveComponentStyles } from './utils/retrieveComponentStyles.js';
12
+ export { componentStyles } from './utils/componentStyles.js';
11
13
  export { getArrowPosition } from './utils/getArrowPosition.js';
12
14
  export { getCheckeredBackground } from './utils/getCheckeredBackground.js';
13
15
  export { getColor } from './utils/getColor.js';
@@ -18,6 +20,7 @@ export { default as getLineHeight } from './utils/getLineHeight.js';
18
20
  export { getMenuPosition } from './utils/getMenuPosition.js';
19
21
  export { default as mediaQuery } from './utils/mediaQuery.js';
20
22
  export { default as arrowStyles } from './utils/arrowStyles.js';
23
+ export { useColorScheme } from './utils/useColorScheme.js';
21
24
  export { useDocument } from './utils/useDocument.js';
22
25
  export { useWindow } from './utils/useWindow.js';
23
26
  export { useText } from './utils/useText.js';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ const componentStyles = props => {
8
+ let retVal;
9
+ const components = props.theme.components;
10
+ const componentId = props.componentId || props['data-garden-id'];
11
+ if (components && componentId) {
12
+ retVal = components[componentId];
13
+ if (typeof retVal === 'function') {
14
+ const fn = retVal;
15
+ retVal = fn(props);
16
+ }
17
+ }
18
+ return retVal;
19
+ };
20
+
21
+ export { componentStyles };
@@ -5,7 +5,7 @@
5
5
  * found at http://www.apache.org/licenses/LICENSE-2.0.
6
6
  */
7
7
  function retrieveComponentStyles(componentId, props) {
8
- const components = props.theme && props.theme.components;
8
+ const components = props.theme?.components;
9
9
  if (!components) {
10
10
  return undefined;
11
11
  }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ import { useContext } from 'react';
8
+ import { ColorSchemeContext } from '../elements/ColorSchemeProvider.js';
9
+
10
+ const useColorScheme = () => {
11
+ const context = useContext(ColorSchemeContext);
12
+ if (!context) {
13
+ throw new Error('Error: this component must be rendered within a <ColorSchemeProvider>.');
14
+ }
15
+ return context;
16
+ };
17
+
18
+ export { useColorScheme };
package/dist/index.cjs.js CHANGED
@@ -20,6 +20,68 @@ var styled__default = /*#__PURE__*/_interopDefault(styled);
20
20
  var get__default = /*#__PURE__*/_interopDefault(get);
21
21
  var memoize__default = /*#__PURE__*/_interopDefault(memoize);
22
22
 
23
+ const useColorScheme$1 = function (initialState) {
24
+ let colorSchemeKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'color-scheme';
25
+ const localStorage = typeof window === 'undefined' ? undefined : window.localStorage;
26
+ const mediaQuery = typeof window === 'undefined' ? undefined : window.matchMedia('(prefers-color-scheme: dark)');
27
+ const getState = React.useCallback(_state => {
28
+ const isSystem = _state === 'system' || _state === undefined || _state === null;
29
+ let colorScheme;
30
+ if (isSystem) {
31
+ colorScheme = mediaQuery?.matches ? 'dark' : 'light';
32
+ } else {
33
+ colorScheme = _state;
34
+ }
35
+ return {
36
+ isSystem,
37
+ colorScheme
38
+ };
39
+ }, [mediaQuery?.matches]);
40
+ const [state, setState] = React.useState(getState(localStorage?.getItem(colorSchemeKey) || initialState));
41
+ React.useEffect(() => {
42
+ const eventListener = () => {
43
+ setState(getState('system'));
44
+ };
45
+ if (state.isSystem) {
46
+ mediaQuery?.addEventListener('change', eventListener);
47
+ } else {
48
+ mediaQuery?.removeEventListener('change', eventListener);
49
+ }
50
+ return () => {
51
+ mediaQuery?.removeEventListener('change', eventListener);
52
+ };
53
+ }, [getState, state.isSystem, mediaQuery]);
54
+ return {
55
+ isSystem: state.isSystem,
56
+ colorScheme: state.colorScheme,
57
+ setColorScheme: colorScheme => {
58
+ setState(getState(colorScheme));
59
+ localStorage?.setItem(colorSchemeKey, colorScheme);
60
+ }
61
+ };
62
+ };
63
+ const ColorSchemeContext = React.createContext(undefined);
64
+ const ColorSchemeProvider = _ref => {
65
+ let {
66
+ children,
67
+ colorSchemeKey,
68
+ initialColorScheme
69
+ } = _ref;
70
+ const {
71
+ isSystem,
72
+ colorScheme,
73
+ setColorScheme
74
+ } = useColorScheme$1(initialColorScheme, colorSchemeKey);
75
+ const contextValue = React.useMemo(() => ({
76
+ colorScheme,
77
+ isSystem,
78
+ setColorScheme
79
+ }), [isSystem, colorScheme, setColorScheme]);
80
+ return React__default.default.createElement(ColorSchemeContext.Provider, {
81
+ value: contextValue
82
+ }, children);
83
+ };
84
+
23
85
  const PALETTE = {
24
86
  black: '#000',
25
87
  white: '#fff',
@@ -512,7 +574,7 @@ const ThemeProvider = _ref => {
512
574
  };
513
575
 
514
576
  function retrieveComponentStyles(componentId, props) {
515
- const components = props.theme && props.theme.components;
577
+ const components = props.theme?.components;
516
578
  if (!components) {
517
579
  return undefined;
518
580
  }
@@ -523,6 +585,20 @@ function retrieveComponentStyles(componentId, props) {
523
585
  return componentStyles;
524
586
  }
525
587
 
588
+ const componentStyles = props => {
589
+ let retVal;
590
+ const components = props.theme.components;
591
+ const componentId = props.componentId || props['data-garden-id'];
592
+ if (components && componentId) {
593
+ retVal = components[componentId];
594
+ if (typeof retVal === 'function') {
595
+ const fn = retVal;
596
+ retVal = fn(props);
597
+ }
598
+ }
599
+ return retVal;
600
+ };
601
+
526
602
  const POSITION_MAP = {
527
603
  top: 'bottom',
528
604
  'top-start': 'bottom-left',
@@ -1319,6 +1395,14 @@ function arrowStyles(position) {
1319
1395
  return styled.css(["position:relative;&::before,&::after{position:absolute;border-width:inherit;border-style:inherit;background-color:inherit;width:", ";height:", ";content:'';box-sizing:inherit;}&::before{border-color:inherit;clip-path:polygon(100% ", "px,", "px 100%,100% 100%);}&::after{border-color:transparent;background-clip:content-box;clip-path:polygon(100% ", "px,", "px 100%,100% 100%);}", ";", ";"], squareSizePx, squareSizePx, beforeOffset, beforeOffset, afterOffset, afterOffset, positionStyles(position, squareSizeRounded, inset, shift), options.animationModifier && animationStyles$1(position, options.animationModifier));
1320
1396
  }
1321
1397
 
1398
+ const useColorScheme = () => {
1399
+ const context = React.useContext(ColorSchemeContext);
1400
+ if (!context) {
1401
+ throw new Error('Error: this component must be rendered within a <ColorSchemeProvider>.');
1402
+ }
1403
+ return context;
1404
+ };
1405
+
1322
1406
  const useDocument = theme => {
1323
1407
  const [controlledDocument, setControlledDocument] = React.useState();
1324
1408
  React.useEffect(() => {
@@ -1472,6 +1556,7 @@ const MENU_POSITION = ['top', 'right', 'bottom', 'left'];
1472
1556
  const PLACEMENT = ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'end', 'end-top', 'end-bottom', 'start', 'start-top', 'start-bottom'];
1473
1557
 
1474
1558
  exports.ARROW_POSITION = ARROW_POSITION;
1559
+ exports.ColorSchemeProvider = ColorSchemeProvider;
1475
1560
  exports.DEFAULT_THEME = DEFAULT_THEME;
1476
1561
  exports.MENU_POSITION = MENU_POSITION;
1477
1562
  exports.PALETTE = PALETTE;
@@ -1480,6 +1565,7 @@ exports.SELECTOR_FOCUS_VISIBLE = SELECTOR_FOCUS_VISIBLE;
1480
1565
  exports.StyledBaseIcon = StyledBaseIcon;
1481
1566
  exports.ThemeProvider = ThemeProvider;
1482
1567
  exports.arrowStyles = arrowStyles;
1568
+ exports.componentStyles = componentStyles;
1483
1569
  exports.focusStyles = focusStyles;
1484
1570
  exports.getArrowPosition = getArrowPosition;
1485
1571
  exports.getCheckeredBackground = getCheckeredBackground;
@@ -1492,6 +1578,7 @@ exports.getMenuPosition = getMenuPosition;
1492
1578
  exports.mediaQuery = mediaQuery;
1493
1579
  exports.menuStyles = menuStyles;
1494
1580
  exports.retrieveComponentStyles = retrieveComponentStyles;
1581
+ exports.useColorScheme = useColorScheme;
1495
1582
  exports.useDocument = useDocument;
1496
1583
  exports.useText = useText;
1497
1584
  exports.useWindow = useWindow;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ import React, { PropsWithChildren } from 'react';
8
+ import { IColorSchemeContext, IColorSchemeProviderProps } from '../types';
9
+ export declare const ColorSchemeContext: React.Context<IColorSchemeContext | undefined>;
10
+ export declare const ColorSchemeProvider: ({ children, colorSchemeKey, initialColorScheme }: PropsWithChildren<IColorSchemeProviderProps>) => React.JSX.Element;
@@ -4,10 +4,12 @@
4
4
  * Use of this source code is governed under the Apache License, Version 2.0
5
5
  * found at http://www.apache.org/licenses/LICENSE-2.0.
6
6
  */
7
+ export { ColorSchemeProvider } from './elements/ColorSchemeProvider';
7
8
  export { ThemeProvider } from './elements/ThemeProvider';
8
9
  export { default as DEFAULT_THEME } from './elements/theme';
9
10
  export { default as PALETTE } from './elements/palette';
10
11
  export { default as retrieveComponentStyles } from './utils/retrieveComponentStyles';
12
+ export { componentStyles } from './utils/componentStyles';
11
13
  export { getArrowPosition } from './utils/getArrowPosition';
12
14
  export { getCheckeredBackground } from './utils/getCheckeredBackground';
13
15
  export { getColor } from './utils/getColor';
@@ -18,10 +20,11 @@ export { default as getLineHeight } from './utils/getLineHeight';
18
20
  export { getMenuPosition } from './utils/getMenuPosition';
19
21
  export { default as mediaQuery } from './utils/mediaQuery';
20
22
  export { default as arrowStyles } from './utils/arrowStyles';
23
+ export { useColorScheme } from './utils/useColorScheme';
21
24
  export { useDocument } from './utils/useDocument';
22
25
  export { useWindow } from './utils/useWindow';
23
26
  export { useText } from './utils/useText';
24
27
  export { default as menuStyles } from './utils/menuStyles';
25
28
  export { focusStyles, SELECTOR_FOCUS_VISIBLE } from './utils/focusStyles';
26
29
  export { StyledBaseIcon } from './utils/StyledBaseIcon';
27
- export { ARROW_POSITION, MENU_POSITION, PLACEMENT, type IGardenTheme, type IStyledBaseIconProps, type IThemeProviderProps, type ArrowPosition, type CheckeredBackgroundParameters, type ColorParameters, type FocusBoxShadowParameters, type FocusStylesParameters, type MenuPosition, type Placement } from './types';
30
+ export { ARROW_POSITION, MENU_POSITION, PLACEMENT, type IColorSchemeContext, type IColorSchemeProviderProps, type IGardenTheme, type IStyledBaseIconProps, type IThemeProviderProps, type ArrowPosition, type CheckeredBackgroundParameters, type ColorParameters, type ColorScheme, type FocusBoxShadowParameters, type FocusStylesParameters, type MenuPosition, type Placement } from './types';
@@ -165,6 +165,28 @@ export interface IGardenTheme {
165
165
  xxl: string;
166
166
  };
167
167
  }
168
+ export type ColorScheme = IGardenTheme['colors']['base'] | 'system';
169
+ export interface IColorSchemeContext {
170
+ /** Returns the current color scheme */
171
+ colorScheme: IGardenTheme['colors']['base'];
172
+ /** Indicates whether the `colorScheme` is determined by the system */
173
+ isSystem: boolean;
174
+ /** Provides the mechanism for updating the current color scheme */
175
+ setColorScheme: (colorScheme: ColorScheme) => void;
176
+ }
177
+ export interface IColorSchemeProviderProps {
178
+ /**
179
+ * Sets the initial color scheme and provides `localStorage` persistence (see
180
+ * the `useColorScheme` hook). A user's stored preference overrides this
181
+ * value.
182
+ */
183
+ initialColorScheme?: ColorScheme;
184
+ /**
185
+ * Specifies the key used to store the user's preferred color scheme in
186
+ * `localStorage`
187
+ */
188
+ colorSchemeKey?: string;
189
+ }
168
190
  export interface IThemeProviderProps extends Partial<ThemeProviderProps<IGardenTheme>> {
169
191
  /**
170
192
  * Provides values for component styling. See styled-components
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ import { DefaultTheme } from 'styled-components';
8
+ /**
9
+ * CSS for component customizations based on `theme.components[componentId]`.
10
+ *
11
+ * @param {Object} props.theme Provides `components` object use to resolve the given component ID
12
+ * @param {String} [props.componentId] Specifies the lookup id for * `theme.components` styles.
13
+ * The ID will be inferred from the `'data-garden-id'` attribute if not provided.
14
+ *
15
+ * @returns component CSS styles
16
+ */
17
+ export declare const componentStyles: (props: {
18
+ theme: DefaultTheme;
19
+ componentId?: string;
20
+ }) => string | undefined;
@@ -4,6 +4,8 @@
4
4
  * Use of this source code is governed under the Apache License, Version 2.0
5
5
  * found at http://www.apache.org/licenses/LICENSE-2.0.
6
6
  */
7
- import { ThemeProps, DefaultTheme } from 'styled-components';
8
- /** @component */
9
- export default function retrieveComponentStyles(componentId: string, props: Partial<ThemeProps<Partial<DefaultTheme>>>): any;
7
+ import { DefaultTheme } from 'styled-components';
8
+ /** @deprecated Use `componentStyles` instead. */
9
+ export default function retrieveComponentStyles(componentId: string, props: {
10
+ theme?: Partial<DefaultTheme>;
11
+ }): any;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ /**
8
+ * Provides the current color scheme for the context `ThemeProvider`.
9
+ *
10
+ * @returns {object} Current color scheme accessor and mutator.
11
+ */
12
+ export declare const useColorScheme: () => import("..").IColorSchemeContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zendeskgarden/react-theming",
3
- "version": "9.3.0",
3
+ "version": "9.5.0",
4
4
  "description": "Theming utilities and components within the Garden Design System",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Zendesk Garden <garden@zendesk.com>",
@@ -47,5 +47,5 @@
47
47
  "access": "public"
48
48
  },
49
49
  "zendeskgarden:src": "src/index.ts",
50
- "gitHead": "fa6461e0d9fae27956980056006e8013daedc6b9"
50
+ "gitHead": "43546784a9aa985332ddcc6dd09209a11e2c03ff"
51
51
  }