@pantheon-systems/pds-toolkit-react 2.0.0-alpha.44 → 2.0.0-alpha.45

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.
@@ -120,6 +120,7 @@ export * from './libs/types/custom-types';
120
120
  export * from './libs/types/input-types';
121
121
  export * from './libs/types/layout-types';
122
122
  export * from './libs/types/navigation-types';
123
+ export * from './utilities/context-providers/ThemeContext/ThemeContext';
123
124
  export * from './utilities/grid/Grid';
124
125
  export * from './utilities/grid/GridItem';
125
126
  export * from './utilities/hooks/useBreakpoint/useBreakpoint';
@@ -129,8 +129,20 @@ export interface AppLayoutProps extends ComponentPropsWithoutRef<'div'> {
129
129
  * Additional props for the sidebar `<div>` element.
130
130
  */
131
131
  sidebarProps?: ComponentPropsWithoutRef<'div'>;
132
+ /**
133
+ * Distance from the top of the viewport to the top of the layout, used to
134
+ * size the layout height (`100dvh - topOffset`). Set this when you render
135
+ * chrome above the layout (e.g. a banner) whose height the layout must
136
+ * account for — pass the measured height reactively.
137
+ *
138
+ * A number is treated as pixels; a string is used as-is (e.g. '3rem').
139
+ * When provided, this value is used verbatim and the built-in auto-measure
140
+ * is disabled. When omitted, the layout measures its own offset from the
141
+ * document top and keeps it updated.
142
+ */
143
+ topOffset?: number | string;
132
144
  }
133
145
  /**
134
146
  * AppLayout UI component
135
147
  */
136
- export declare const AppLayout: ({ children, className, drawerContent, drawerProps, hasDrawerToggle, hasSidebarToggle, isDrawerOpen, isSidebarCollapsed, keyboardShortcuts, labels, mainBackground, mainContentElement, mainContentMaxWidth, mainContentProps, onDrawerToggle, onSidebarToggle, scrollableContent, sidebarBackground, sidebarCollapsedWidth, sidebarExpandedWidth, sidebarExpandedWidthMax, sidebarExpandedWidthMin, sidebarProps, ...props }: AppLayoutProps) => import("react/jsx-runtime").JSX.Element;
148
+ export declare const AppLayout: ({ children, className, drawerContent, drawerProps, hasDrawerToggle, hasSidebarToggle, isDrawerOpen, isSidebarCollapsed, keyboardShortcuts, labels, mainBackground, mainContentElement, mainContentMaxWidth, mainContentProps, onDrawerToggle, onSidebarToggle, scrollableContent, sidebarBackground, sidebarCollapsedWidth, sidebarExpandedWidth, sidebarExpandedWidthMax, sidebarExpandedWidthMin, sidebarProps, topOffset, ...props }: AppLayoutProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
+ import { ThemeContextProviderProps } from '../context-providers/ThemeContext/ThemeContext';
2
3
  /**
3
4
  * Prop types for GlobalWrapper
4
5
  */
@@ -7,15 +8,28 @@ interface GlobalWrapperProps {
7
8
  * Child components
8
9
  */
9
10
  children: ReactNode;
11
+ /**
12
+ * Opt in to color-mode theme switching. When `true`, children are wrapped in
13
+ * a `ThemeContextProvider` that owns the theme and drives the `data-theme`
14
+ * attribute on the document root. Defaults to `false` so apps that manage
15
+ * their own theme are unaffected. Configure via `themeProps`.
16
+ */
17
+ enableThemeSwitching?: boolean;
10
18
  /**
11
19
  * Maximum viewport width in pixels at which mobile nav mode is active.
12
20
  * Sets the `data-pds-mobile` attribute on `:root` for CSS to react to.
13
21
  * Defaults to 767 to align with `--pds-bp-s-only` (`max-width: 767px`).
14
22
  */
15
23
  mobileMaxWidth?: number;
24
+ /**
25
+ * Configuration forwarded to the `ThemeContextProvider` (for example,
26
+ * `defaultTheme`, `storageKey`, or controlled `theme`/`onThemeChange`).
27
+ * Only applied when `enableThemeSwitching` is `true`.
28
+ */
29
+ themeProps?: Omit<ThemeContextProviderProps, 'children'>;
16
30
  }
17
31
  /**
18
32
  * GlobalWrapper wrapper component.
19
33
  */
20
- export declare const GlobalWrapper: ({ children, mobileMaxWidth, }: GlobalWrapperProps) => import("react/jsx-runtime").JSX.Element;
34
+ export declare const GlobalWrapper: ({ children, enableThemeSwitching, mobileMaxWidth, themeProps, }: GlobalWrapperProps) => import("react/jsx-runtime").JSX.Element;
21
35
  export {};
@@ -0,0 +1,113 @@
1
+ import React, { ReactNode, RefObject } from 'react';
2
+ /**
3
+ * The user's color-mode choice. Matches the ThemeSwitcher component's options.
4
+ * `'system'` follows the OS via `prefers-color-scheme`.
5
+ */
6
+ export type Theme = 'light' | 'dark' | 'system';
7
+ /**
8
+ * The concrete theme applied to the `data-theme` attribute. `'system'` is
9
+ * resolved to one of these before being applied.
10
+ */
11
+ export type ResolvedTheme = 'light' | 'dark';
12
+ interface ThemeContextValue {
13
+ /** Resolved theme applied to `data-theme` (`'system'` → `'light' | 'dark'`). */
14
+ resolvedTheme: ResolvedTheme;
15
+ /** Update the theme. In controlled mode this only notifies `onThemeChange`. */
16
+ setTheme: (theme: Theme) => void;
17
+ /** The user's current choice (`'system'` preserved as-is). */
18
+ theme: Theme;
19
+ }
20
+ export declare const ThemeContext: React.Context<ThemeContextValue>;
21
+ /**
22
+ * Prop types for ThemeContextProvider
23
+ */
24
+ export interface ThemeContextProviderProps {
25
+ /**
26
+ * Child components.
27
+ */
28
+ children: ReactNode;
29
+ /**
30
+ * Fallback theme when nothing is stored (and in uncontrolled mode).
31
+ * Defaults to `'light'`.
32
+ */
33
+ defaultTheme?: Theme;
34
+ /**
35
+ * Opt out of the inline anti-flash script the provider renders before its
36
+ * children. That script sets `data-theme` from `localStorage` during SSR
37
+ * before first paint, preventing a flash of the wrong theme. It is only
38
+ * rendered for the uncontrolled, persisted, whole-page case (no `nodeRef`);
39
+ * set this to `true` to suppress it — for example, if you inject the script
40
+ * yourself via {@link getThemeInitScript}. Defaults to `false`.
41
+ */
42
+ disableInitScript?: boolean;
43
+ /**
44
+ * Element to receive the `data-theme` attribute. Defaults to
45
+ * `document.documentElement` (the whole page). Provide a ref to scope theming
46
+ * to a subtree — for example, an embedded preview or a themed region.
47
+ */
48
+ nodeRef?: RefObject<HTMLElement | null>;
49
+ /**
50
+ * Callback fired whenever the user changes the theme. This is the hook point
51
+ * for persisting to a server/preference service later. Fires in both
52
+ * controlled and uncontrolled modes.
53
+ */
54
+ onThemeChange?: (theme: Theme) => void;
55
+ /**
56
+ * Whether to persist the theme to `localStorage`. Ignored in controlled
57
+ * mode (when `theme` is provided). Defaults to `true`.
58
+ */
59
+ persist?: boolean;
60
+ /**
61
+ * `localStorage` key used to persist the theme. Defaults to `'pds-theme'`.
62
+ */
63
+ storageKey?: string;
64
+ /**
65
+ * Controlled theme value. When provided, the consuming app owns the value
66
+ * (for example, sourced from a preference service) and the provider stops
67
+ * writing to `localStorage` — it only resolves and applies the value. Pair
68
+ * with `onThemeChange` to receive user-initiated changes.
69
+ */
70
+ theme?: Theme;
71
+ }
72
+ /**
73
+ * Options for {@link getThemeInitScript}. Match these to the values passed to
74
+ * the `ThemeContextProvider` (or `GlobalWrapper`'s `themeProps`).
75
+ */
76
+ export interface ThemeInitScriptOptions {
77
+ /** Fallback theme when nothing is stored. Defaults to `'light'`. */
78
+ defaultTheme?: Theme;
79
+ /** `localStorage` key the provider persists to. Defaults to `'pds-theme'`. */
80
+ storageKey?: string;
81
+ }
82
+ /**
83
+ * Returns a tiny synchronous script (as a string) that sets the `data-theme`
84
+ * attribute on the document root from the persisted preference **before first
85
+ * paint** — preventing a flash of the wrong theme on server-rendered pages (a
86
+ * flash the provider alone cannot prevent, since it only applies the theme
87
+ * after hydration).
88
+ *
89
+ * The `ThemeContextProvider` renders this script automatically for the
90
+ * uncontrolled, persisted, whole-page case, so most apps never call this
91
+ * directly. It is exported for advanced setups that want to place the script
92
+ * themselves (for example, in the document `<head>`). Note: importing it drags
93
+ * in this client module, so it cannot be called from a React Server Component —
94
+ * let the provider inject it, or inline the string. Either way, add
95
+ * `suppressHydrationWarning` to the `<html>` element, since the script mutates
96
+ * it before React hydrates.
97
+ */
98
+ export declare const getThemeInitScript: ({ defaultTheme, storageKey, }?: ThemeInitScriptOptions) => string;
99
+ /**
100
+ * ThemeContextProvider — owns color-mode state and drives the `data-theme`
101
+ * attribute on the document root.
102
+ *
103
+ * Works standalone or via `GlobalWrapper`'s opt-in. Persists to `localStorage`
104
+ * by default, and exposes a controlled mode (`theme` + `onThemeChange`) so an
105
+ * application can take over persistence.
106
+ */
107
+ export declare const ThemeContextProvider: ({ children, defaultTheme, disableInitScript, nodeRef, onThemeChange, persist, storageKey, theme: controlledTheme, }: ThemeContextProviderProps) => import("react/jsx-runtime").JSX.Element;
108
+ /**
109
+ * Access the current theme, the resolved theme, and a setter. Returns a no-op
110
+ * default when no `ThemeContextProvider` is present.
111
+ */
112
+ export declare const useTheme: () => ThemeContextValue;
113
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pantheon-systems/pds-toolkit-react",
3
3
  "technology": "React",
4
- "version": "2.0.0-alpha.44",
4
+ "version": "2.0.0-alpha.45",
5
5
  "description": "PDS toolkit built using the React framework",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -56,7 +56,7 @@
56
56
  "build:css:packageExtraCss": "PDS_CSS_LAYER=pds-v2 node scripts/package-extra-css.js",
57
57
  "build:css:watch": "npm run build:css -- -w",
58
58
  "prestorybook": "node scripts/filter-exports-by-tags.js && npm run build:css && npm run build:css:components && npm run build:css:layouts && npm run generate:ux-writing-search-index && npm run generate:ux-writing-guide",
59
- "storybook": "storybook dev -p 6006",
59
+ "storybook": "PDS_CSS_LAYER=pds-v2 storybook dev -p 6006",
60
60
  "prebuild": "npm run build:css && npm run build:css:components && npm run build:css:layouts && npm run build:css:packageExtraCss && npm run generate:ux-writing-search-index && npm run generate:ux-writing-guide",
61
61
  "build": "NODE_OPTIONS=--max-old-space-size=4096 NODE_ENV=production storybook build",
62
62
  "build-storybook": "NODE_ENV=production storybook build",