@datalayer/primer-addons 1.0.10 → 1.0.11
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/lib/story-helpers.d.ts +31 -0
- package/lib/story-helpers.js +105 -0
- package/lib/theme/DatalayerThemeProvider.js +83 -6
- package/lib/theme/ThemeSwitcher.d.ts +17 -0
- package/lib/theme/ThemeSwitcher.js +19 -0
- package/lib/theme/ThemedProvider.d.ts +25 -0
- package/lib/theme/ThemedProvider.js +14 -0
- package/lib/theme/colors/datalayerColors.d.ts +14 -0
- package/lib/theme/colors/datalayerColors.js +17 -0
- package/lib/theme/colors/lovelyColors.d.ts +14 -0
- package/lib/theme/colors/lovelyColors.js +17 -0
- package/lib/theme/colors/matrixColors.d.ts +14 -0
- package/lib/theme/colors/matrixColors.js +17 -0
- package/lib/theme/colors/spatialColors.d.ts +14 -0
- package/lib/theme/colors/spatialColors.js +17 -0
- package/lib/theme/index.d.ts +3 -0
- package/lib/theme/index.js +3 -0
- package/lib/theme/themeRegistry.d.ts +75 -0
- package/lib/theme/themeRegistry.js +235 -0
- package/lib/theme/themes/createThemeCSSVars.d.ts +14 -1
- package/lib/theme/themes/createThemeCSSVars.js +70 -9
- package/lib/theme/themes/matrixTheme.d.ts +1 -4
- package/lib/theme/themes/matrixTheme.js +3 -7
- package/lib/theme/useThemeStore.d.ts +50 -0
- package/lib/theme/useThemeStore.js +65 -0
- package/lib/utils/Portals.d.ts +15 -0
- package/lib/utils/Portals.js +50 -0
- package/package.json +3 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ArgTypes } from '@storybook/react';
|
|
3
|
+
import { Icon } from '@primer/octicons-react';
|
|
4
|
+
type StoryContext = Record<string, unknown> & {
|
|
5
|
+
globals: {
|
|
6
|
+
colorScheme: string;
|
|
7
|
+
};
|
|
8
|
+
parameters: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
export declare const colormodeFromScheme: (colorScheme: string) => "dark" | "light";
|
|
11
|
+
export declare const withThemeProvider: (Story: React.FC<React.PropsWithChildren<StoryContext>>, context: StoryContext) => string | number | boolean | Iterable<React.ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
12
|
+
export declare const toolbarTypes: {
|
|
13
|
+
colorScheme: {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
defaultValue: string;
|
|
17
|
+
toolbar: {
|
|
18
|
+
icon: string;
|
|
19
|
+
items: string[];
|
|
20
|
+
title: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export declare const inputWrapperArgTypes: ArgTypes;
|
|
25
|
+
export declare const getTextInputArgTypes: (category?: string) => Record<string, unknown>;
|
|
26
|
+
export declare const OcticonArgType: (iconList: Icon[]) => {
|
|
27
|
+
options: string[];
|
|
28
|
+
control: string;
|
|
29
|
+
mapping: Record<string, Icon>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createGlobalStyle } from 'styled-components';
|
|
3
|
+
import { ThemeProvider, themeGet, BaseStyles, theme } from '@primer/react';
|
|
4
|
+
// set global theme styles for each story
|
|
5
|
+
const GlobalStyle = createGlobalStyle `
|
|
6
|
+
body,
|
|
7
|
+
.docs-story {
|
|
8
|
+
background-color: ${themeGet('colors.canvas.default')};
|
|
9
|
+
color: ${themeGet('colors.fg.default')};
|
|
10
|
+
}
|
|
11
|
+
`;
|
|
12
|
+
export const colormodeFromScheme = (colorScheme) => {
|
|
13
|
+
return colorScheme.startsWith('light') ? 'light' : 'dark';
|
|
14
|
+
};
|
|
15
|
+
export const withThemeProvider = (Story, context) => {
|
|
16
|
+
// used for testing ThemeProvider.stories.tsx
|
|
17
|
+
if (context.parameters.disableThemeDecorator)
|
|
18
|
+
return Story(context);
|
|
19
|
+
const { colorScheme } = context.globals;
|
|
20
|
+
return (_jsxs(ThemeProvider, { theme: theme, colorMode: colormodeFromScheme(colorScheme), dayScheme: colorScheme, nightScheme: colorScheme, children: [colorScheme.startsWith('light') ? (_jsx(GlobalStyle, { "$lightTheme": true })) : (_jsx(GlobalStyle, {})), _jsx(BaseStyles, { children: _jsx("div", { id: "html-addon-root", children: Story(context) }) })] }));
|
|
21
|
+
};
|
|
22
|
+
export const toolbarTypes = {
|
|
23
|
+
colorScheme: {
|
|
24
|
+
name: 'Color Scheme',
|
|
25
|
+
description: 'Switch color scheme',
|
|
26
|
+
defaultValue: 'light',
|
|
27
|
+
toolbar: {
|
|
28
|
+
icon: 'photo',
|
|
29
|
+
items: [...Object.keys(theme.colorSchemes)],
|
|
30
|
+
title: 'Color Scheme',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
export const inputWrapperArgTypes = {
|
|
35
|
+
block: {
|
|
36
|
+
defaultValue: false,
|
|
37
|
+
control: 'boolean',
|
|
38
|
+
},
|
|
39
|
+
contrast: {
|
|
40
|
+
defaultValue: false,
|
|
41
|
+
control: 'boolean',
|
|
42
|
+
},
|
|
43
|
+
disabled: {
|
|
44
|
+
defaultValue: false,
|
|
45
|
+
control: 'boolean',
|
|
46
|
+
},
|
|
47
|
+
placeholder: {
|
|
48
|
+
defaultValue: '',
|
|
49
|
+
control: 'text',
|
|
50
|
+
},
|
|
51
|
+
size: {
|
|
52
|
+
name: 'size (input)', // TODO: remove '(input)'
|
|
53
|
+
defaultValue: 'medium',
|
|
54
|
+
options: ['small', 'medium', 'large'],
|
|
55
|
+
control: 'radio',
|
|
56
|
+
},
|
|
57
|
+
validationStatus: {
|
|
58
|
+
defaultValue: undefined,
|
|
59
|
+
options: ['error', 'success', undefined],
|
|
60
|
+
control: 'radio',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
const textInputArgTypesUnsorted = {
|
|
64
|
+
...inputWrapperArgTypes,
|
|
65
|
+
loading: {
|
|
66
|
+
defaultValue: false,
|
|
67
|
+
control: 'boolean',
|
|
68
|
+
},
|
|
69
|
+
loaderPosition: {
|
|
70
|
+
defaultValue: 'auto',
|
|
71
|
+
options: ['auto', 'leading', 'trailing'],
|
|
72
|
+
control: 'radio',
|
|
73
|
+
},
|
|
74
|
+
monospace: {
|
|
75
|
+
defaultValue: false,
|
|
76
|
+
control: 'boolean',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
// Alphabetize and optionally categorize the props
|
|
80
|
+
export const getTextInputArgTypes = (category) => Object.keys(textInputArgTypesUnsorted)
|
|
81
|
+
.sort()
|
|
82
|
+
.reduce((obj, key) => {
|
|
83
|
+
obj[key] = category
|
|
84
|
+
? {
|
|
85
|
+
// have to do weird type casting so we can spread the object
|
|
86
|
+
...textInputArgTypesUnsorted[key],
|
|
87
|
+
table: {
|
|
88
|
+
category,
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
: textInputArgTypesUnsorted[key];
|
|
92
|
+
return obj;
|
|
93
|
+
}, {});
|
|
94
|
+
// Use this function for icon options in the controls. Desired icons are passed in as an array of Octicons
|
|
95
|
+
export const OcticonArgType = (iconList) => {
|
|
96
|
+
const icons = iconList.reduce((obj, icon) => {
|
|
97
|
+
obj[icon.displayName || 'Icon'] = icon;
|
|
98
|
+
return obj;
|
|
99
|
+
}, {});
|
|
100
|
+
return {
|
|
101
|
+
options: Object.keys(icons),
|
|
102
|
+
control: 'select',
|
|
103
|
+
mapping: icons,
|
|
104
|
+
};
|
|
105
|
+
};
|
|
@@ -3,21 +3,88 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
|
-
import { useEffect } from 'react';
|
|
6
|
+
import { useEffect, useMemo } from 'react';
|
|
7
7
|
import { BaseStyles, ThemeProvider } from '@primer/react';
|
|
8
8
|
import { useSystemColorMode } from './useSystemColorMode';
|
|
9
9
|
import { datalayerTheme, datalayerThemeStyles } from './themes/datalayerTheme';
|
|
10
|
-
import { setupPrimerPortals } from '../utils/Portals';
|
|
10
|
+
import { setupPrimerPortals, syncPortalThemeStyles } from '../utils/Portals';
|
|
11
|
+
/**
|
|
12
|
+
* System sans-serif font stack — shared between `fontFamily` and
|
|
13
|
+
* the Primer `--fontStack-*` CSS custom properties so that
|
|
14
|
+
* components using the CSS `font` shorthand (e.g. `Blankslate`)
|
|
15
|
+
* also pick up the themed typeface.
|
|
16
|
+
*/
|
|
17
|
+
const SYSTEM_FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"';
|
|
11
18
|
/**
|
|
12
19
|
* Shared typographic rhythm — clean, spacious feel inspired by
|
|
13
20
|
* modern developer-blog aesthetics (generous line-height, open
|
|
14
21
|
* letter-spacing on headings, crisp body text).
|
|
22
|
+
*
|
|
23
|
+
* Primer components like `Blankslate` use the CSS `font` shorthand
|
|
24
|
+
* through `--text-title-shorthand-*` / `--text-body-shorthand-*`.
|
|
25
|
+
* Those shorthand variables reference `--fontStack-sansSerif` (and
|
|
26
|
+
* `--fontStack-sansSerifDisplay`). If the `@primer/primitives`
|
|
27
|
+
* typography CSS isn't loaded, the shorthand vars are undefined and
|
|
28
|
+
* components fall back to a hardcoded system font stack baked into
|
|
29
|
+
* their CSS. We define the full set here so **every** theme gets
|
|
30
|
+
* correct font inheritance — no primitives CSS import required.
|
|
15
31
|
*/
|
|
16
32
|
const typographyVars = {
|
|
33
|
+
/* ── Font stacks ───────────────────────────────────────────────── */
|
|
34
|
+
'--fontStack-monospace': 'ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace',
|
|
35
|
+
'--fontStack-sansSerif': SYSTEM_FONT,
|
|
36
|
+
'--fontStack-sansSerifDisplay': SYSTEM_FONT,
|
|
37
|
+
'--fontStack-system': SYSTEM_FONT,
|
|
38
|
+
/* ── Base text weights (from @primer/primitives) ───────────────── */
|
|
39
|
+
'--base-text-weight-light': '300',
|
|
40
|
+
'--base-text-weight-normal': '400',
|
|
41
|
+
'--base-text-weight-medium': '500',
|
|
42
|
+
'--base-text-weight-semibold': '600',
|
|
43
|
+
/* ── Body sizing ───────────────────────────────────────────────── */
|
|
44
|
+
'--text-body-size-large': '1rem',
|
|
45
|
+
'--text-body-size-medium': '0.875rem',
|
|
46
|
+
'--text-body-size-small': '0.75rem',
|
|
47
|
+
'--text-body-lineHeight-large': '1.5',
|
|
48
|
+
'--text-body-lineHeight-medium': '1.4285',
|
|
49
|
+
'--text-body-lineHeight-small': '1.6666',
|
|
50
|
+
/* ── Title sizing ──────────────────────────────────────────────── */
|
|
51
|
+
'--text-title-size-large': '2rem',
|
|
52
|
+
'--text-title-size-medium': '1.25rem',
|
|
53
|
+
'--text-title-size-small': '1rem',
|
|
54
|
+
'--text-title-lineHeight-large': '1.5',
|
|
55
|
+
'--text-title-lineHeight-medium': '1.6',
|
|
56
|
+
'--text-title-lineHeight-small': '1.5',
|
|
57
|
+
/* ── Caption / subtitle / display ──────────────────────────────── */
|
|
58
|
+
'--text-caption-size': '0.75rem',
|
|
59
|
+
'--text-caption-lineHeight': '1.3333',
|
|
60
|
+
'--text-subtitle-size': '1.25rem',
|
|
61
|
+
'--text-subtitle-lineHeight': '1.6',
|
|
62
|
+
'--text-display-size': '2.5rem',
|
|
63
|
+
'--text-display-lineHeight': '1.4',
|
|
64
|
+
/* ── Font shorthand tokens ─────────────────────────────────────── *
|
|
65
|
+
* These are the tokens consumed by Primer components (Blankslate,
|
|
66
|
+
* etc.) via `font: var(--text-title-shorthand-medium, <fallback>)`.
|
|
67
|
+
* Defining them here prevents the hard-coded fallback from firing.
|
|
68
|
+
* Each one references `var(--fontStack-sansSerif)` or
|
|
69
|
+
* `SYSTEM_FONT` directly (no nested `var()`) so that the CSS
|
|
70
|
+
* `font` shorthand parses reliably. Themes that override fonts
|
|
71
|
+
* (e.g. Matrix monospace) replace these shorthand tokens via
|
|
72
|
+
* `buildThemeStyles({ fontFamily })` in their `themeStyles`.
|
|
73
|
+
* ─────────────────────────────────────────────────────────────── */
|
|
74
|
+
'--text-body-shorthand-large': `400 1rem/1.5 ${SYSTEM_FONT}`,
|
|
75
|
+
'--text-body-shorthand-medium': `400 0.875rem/1.4285 ${SYSTEM_FONT}`,
|
|
76
|
+
'--text-body-shorthand-small': `400 0.75rem/1.6666 ${SYSTEM_FONT}`,
|
|
77
|
+
'--text-title-shorthand-large': `600 2rem/1.5 ${SYSTEM_FONT}`,
|
|
78
|
+
'--text-title-shorthand-medium': `600 1.25rem/1.6 ${SYSTEM_FONT}`,
|
|
79
|
+
'--text-title-shorthand-small': `600 1rem/1.5 ${SYSTEM_FONT}`,
|
|
80
|
+
'--text-caption-shorthand': `400 0.75rem/1.3333 ${SYSTEM_FONT}`,
|
|
81
|
+
'--text-subtitle-shorthand': `400 1.25rem/1.6 ${SYSTEM_FONT}`,
|
|
82
|
+
'--text-display-shorthand': `500 2.5rem/1.4 ${SYSTEM_FONT}`,
|
|
83
|
+
/* ── Custom overrides ──────────────────────────────────────────── */
|
|
17
84
|
'--text-body-lineHeight': '1.7',
|
|
18
85
|
'--text-title-lineHeight': '1.2',
|
|
19
86
|
'--text-title-letterSpacing': '-0.02em',
|
|
20
|
-
fontFamily:
|
|
87
|
+
fontFamily: SYSTEM_FONT,
|
|
21
88
|
WebkitFontSmoothing: 'antialiased',
|
|
22
89
|
MozOsxFontSmoothing: 'grayscale',
|
|
23
90
|
textRendering: 'optimizeLegibility',
|
|
@@ -31,11 +98,21 @@ export function DatalayerThemeProvider(props) {
|
|
|
31
98
|
const resolvedTheme = theme ?? datalayerTheme;
|
|
32
99
|
const styles = themeStyles ?? datalayerThemeStyles;
|
|
33
100
|
const resolvedStyles = isDark ? styles.dark : styles.light;
|
|
34
|
-
//
|
|
35
|
-
//
|
|
101
|
+
// The full set of styles that <BaseStyles> receives — we also push
|
|
102
|
+
// these to document.body so Primer portal content inherits theme
|
|
103
|
+
// tokens, fonts, and colors.
|
|
104
|
+
const portalStyles = useMemo(() => ({
|
|
105
|
+
...typographyVars,
|
|
106
|
+
...resolvedStyles,
|
|
107
|
+
...baseStyles,
|
|
108
|
+
}), [resolvedStyles, baseStyles]);
|
|
109
|
+
// Keep document.body portal-root attributes AND theme styles in sync
|
|
110
|
+
// so that Primer portals (modals, dialogs, overlays) inherit the
|
|
111
|
+
// correct color mode **and** theme tokens (fonts, colors, CSS vars).
|
|
36
112
|
useEffect(() => {
|
|
37
113
|
setupPrimerPortals(resolvedColorMode === 'night' ? 'dark' : resolvedColorMode === 'day' ? 'light' : resolvedColorMode);
|
|
38
|
-
|
|
114
|
+
syncPortalThemeStyles(portalStyles);
|
|
115
|
+
}, [resolvedColorMode, portalStyles]);
|
|
39
116
|
return (_jsx(ThemeProvider, { colorMode: resolvedColorMode, theme: resolvedTheme, ...rest, children: _jsx(BaseStyles, { style: {
|
|
40
117
|
lineHeight: '1.7',
|
|
41
118
|
transition: 'background-color 0.25s ease, color 0.25s ease',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThemeSwitcher – Themed colour circles + light/dark/auto segmented control.
|
|
3
|
+
*
|
|
4
|
+
* The component requires an external Zustand `ThemeState` store (created
|
|
5
|
+
* with `createThemeStore`). Consumers pass the `useStore` hook as a prop
|
|
6
|
+
* so the switcher is completely decoupled from any specific app's store.
|
|
7
|
+
*
|
|
8
|
+
* @module theme/ThemeSwitcher
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import type { ThemeState } from './useThemeStore';
|
|
12
|
+
import type { UseBoundStore, StoreApi } from 'zustand';
|
|
13
|
+
export interface ThemeSwitcherProps {
|
|
14
|
+
/** A Zustand store hook created via `createThemeStore()`. */
|
|
15
|
+
useStore: UseBoundStore<StoreApi<ThemeState>>;
|
|
16
|
+
}
|
|
17
|
+
export declare const ThemeSwitcher: React.FC<ThemeSwitcherProps>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, IconButton, SegmentedControl, Tooltip } from '@primer/react';
|
|
3
|
+
import { SunIcon, MoonIcon, DeviceDesktopIcon, CircleIcon, } from '@primer/octicons-react';
|
|
4
|
+
import { themeConfigs, themeVariants } from './themeRegistry';
|
|
5
|
+
export const ThemeSwitcher = ({ useStore }) => {
|
|
6
|
+
const { colorMode, theme: themeVariant } = useStore();
|
|
7
|
+
return (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 3 }, children: [_jsx(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: themeVariants.map(variant => {
|
|
8
|
+
const tcfg = themeConfigs[variant];
|
|
9
|
+
const isSelected = themeVariant === variant;
|
|
10
|
+
return (_jsx(Tooltip, { text: tcfg.label, direction: "s", children: _jsx(IconButton, { "aria-label": tcfg.label, "aria-pressed": isSelected, icon: () => _jsx(CircleIcon, { size: 16, fill: tcfg.brandColor }), size: "small", variant: isSelected ? 'default' : 'invisible', onClick: () => useStore.getState().setTheme(variant, false), sx: {
|
|
11
|
+
border: isSelected ? '2px solid' : '1px solid',
|
|
12
|
+
borderColor: isSelected ? 'accent.fg' : 'border.muted',
|
|
13
|
+
borderRadius: '50%',
|
|
14
|
+
} }) }, variant));
|
|
15
|
+
}) }), _jsxs(SegmentedControl, { "aria-label": "Color mode", size: "small", onChange: (index) => {
|
|
16
|
+
const modes = ['light', 'dark', 'auto'];
|
|
17
|
+
useStore.getState().setColorMode(modes[index]);
|
|
18
|
+
}, children: [_jsx(SegmentedControl.IconButton, { selected: colorMode === 'light', icon: SunIcon, "aria-label": "Light" }), _jsx(SegmentedControl.IconButton, { selected: colorMode === 'dark', icon: MoonIcon, "aria-label": "Dark" }), _jsx(SegmentedControl.IconButton, { selected: colorMode === 'auto', icon: DeviceDesktopIcon, "aria-label": "Auto" })] })] }));
|
|
19
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThemedProvider – Drop-in theme provider that reads theme / color-mode
|
|
3
|
+
* from a Zustand `ThemeState` store and forwards them to
|
|
4
|
+
* `DatalayerThemeProvider`.
|
|
5
|
+
*
|
|
6
|
+
* Consumers pass the `useStore` hook as a prop, so the provider is
|
|
7
|
+
* completely decoupled from any specific application's store instance.
|
|
8
|
+
*
|
|
9
|
+
* @module theme/ThemedProvider
|
|
10
|
+
*/
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import { type IDatalayerThemeProviderProps } from './DatalayerThemeProvider';
|
|
13
|
+
import type { ThemeState } from './useThemeStore';
|
|
14
|
+
import type { UseBoundStore, StoreApi } from 'zustand';
|
|
15
|
+
export interface ThemedProviderProps extends Omit<IDatalayerThemeProviderProps, 'ref'> {
|
|
16
|
+
/** A Zustand store hook created via `createThemeStore()`. */
|
|
17
|
+
useStore: UseBoundStore<StoreApi<ThemeState>>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Drop-in replacement for `<DatalayerThemeProvider>`.
|
|
21
|
+
* Reads theme / colorMode from the supplied store and forwards them to
|
|
22
|
+
* the real provider. Any explicit props (colorMode, theme, themeStyles)
|
|
23
|
+
* are still respected as overrides.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ThemedProvider: React.FC<React.PropsWithChildren<ThemedProviderProps>>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { DatalayerThemeProvider, } from './DatalayerThemeProvider';
|
|
3
|
+
import { themeConfigs } from './themeRegistry';
|
|
4
|
+
/**
|
|
5
|
+
* Drop-in replacement for `<DatalayerThemeProvider>`.
|
|
6
|
+
* Reads theme / colorMode from the supplied store and forwards them to
|
|
7
|
+
* the real provider. Any explicit props (colorMode, theme, themeStyles)
|
|
8
|
+
* are still respected as overrides.
|
|
9
|
+
*/
|
|
10
|
+
export const ThemedProvider = ({ children, useStore, ...rest }) => {
|
|
11
|
+
const { colorMode, theme: themeVariant } = useStore();
|
|
12
|
+
const cfg = themeConfigs[themeVariant];
|
|
13
|
+
return (_jsx(DatalayerThemeProvider, { colorMode: rest.colorMode ?? colorMode, theme: rest.theme ?? cfg.primerTheme, themeStyles: rest.themeStyles ?? cfg.themeStyles, ...rest, children: children }));
|
|
14
|
+
};
|
|
@@ -12,4 +12,18 @@ export declare const datalayerColors: {
|
|
|
12
12
|
greenTint: string;
|
|
13
13
|
greenBright: string;
|
|
14
14
|
greenHover: string;
|
|
15
|
+
brightGlow: string;
|
|
16
|
+
brightPop: string;
|
|
17
|
+
brightSpark: string;
|
|
18
|
+
brightBlaze: string;
|
|
19
|
+
brightSurge: string;
|
|
20
|
+
brightFlame: string;
|
|
21
|
+
brightGold: string;
|
|
22
|
+
brightLightGlow: string;
|
|
23
|
+
brightLightPop: string;
|
|
24
|
+
brightLightSpark: string;
|
|
25
|
+
brightLightBlaze: string;
|
|
26
|
+
brightLightSurge: string;
|
|
27
|
+
brightLightFlame: string;
|
|
28
|
+
brightLightGold: string;
|
|
15
29
|
};
|
|
@@ -18,4 +18,21 @@ export const datalayerColors = {
|
|
|
18
18
|
greenTint: '#E9F7F1', // Soft background for success / callouts
|
|
19
19
|
greenBright: '#2ECC71', // Highlights and glow on dark backgrounds
|
|
20
20
|
greenHover: '#0E6655', // Primary button hover
|
|
21
|
+
// Bright / vivid colours for SVG illustrations (OpenAI-blog style)
|
|
22
|
+
brightGlow: '#00D68F', // Ultra-vivid emerald — primary glow
|
|
23
|
+
brightPop: '#00E5FF', // Electric cyan — contrasting accent
|
|
24
|
+
brightSpark: '#76FF03', // Lime neon — sparkle / tertiary
|
|
25
|
+
brightBlaze: '#FF1744', // Vivid red — warm accent
|
|
26
|
+
brightSurge: '#2979FF', // Electric blue — cool accent
|
|
27
|
+
// Warm vivid colours — yellow & orange accents for SVG illustrations
|
|
28
|
+
brightFlame: '#FF6D00', // Vivid orange — warm energy accent
|
|
29
|
+
brightGold: '#FFD600', // Vivid yellow — golden highlight
|
|
30
|
+
// Vivid brights for light backgrounds — punchy, saturated, OpenAI-blog vibrancy
|
|
31
|
+
brightLightGlow: '#00BFA5', // Vivid aqua-green
|
|
32
|
+
brightLightPop: '#00B0FF', // Vivid sky blue
|
|
33
|
+
brightLightSpark: '#64DD17', // Vivid chartreuse
|
|
34
|
+
brightLightBlaze: '#FF1744', // Vivid red
|
|
35
|
+
brightLightSurge: '#2979FF', // Electric blue
|
|
36
|
+
brightLightFlame: '#FF6D00', // Vivid orange
|
|
37
|
+
brightLightGold: '#FFAB00', // Vivid amber
|
|
21
38
|
};
|
|
@@ -12,4 +12,18 @@ export declare const lovelyColors: {
|
|
|
12
12
|
roseTint: string;
|
|
13
13
|
roseBright: string;
|
|
14
14
|
roseHover: string;
|
|
15
|
+
brightGlow: string;
|
|
16
|
+
brightPop: string;
|
|
17
|
+
brightSpark: string;
|
|
18
|
+
brightBlaze: string;
|
|
19
|
+
brightSurge: string;
|
|
20
|
+
brightFlame: string;
|
|
21
|
+
brightGold: string;
|
|
22
|
+
brightLightGlow: string;
|
|
23
|
+
brightLightPop: string;
|
|
24
|
+
brightLightSpark: string;
|
|
25
|
+
brightLightBlaze: string;
|
|
26
|
+
brightLightSurge: string;
|
|
27
|
+
brightLightFlame: string;
|
|
28
|
+
brightLightGold: string;
|
|
15
29
|
};
|
|
@@ -18,4 +18,21 @@ export const lovelyColors = {
|
|
|
18
18
|
roseTint: '#FDF2F8', // Soft background for callouts
|
|
19
19
|
roseBright: '#F472B6', // Highlights & glow on dark
|
|
20
20
|
roseHover: '#831843', // Primary button hover
|
|
21
|
+
// Bright / vivid colours for SVG illustrations (OpenAI-blog style)
|
|
22
|
+
brightGlow: '#FF4081', // Hot pink — primary glow
|
|
23
|
+
brightPop: '#FF6E40', // Vivid coral — contrasting accent
|
|
24
|
+
brightSpark: '#EA80FC', // Electric fuchsia — sparkle / tertiary
|
|
25
|
+
brightBlaze: '#FF1744', // Vivid crimson — warm accent
|
|
26
|
+
brightSurge: '#536DFE', // Indigo blue — cool accent
|
|
27
|
+
// Warm vivid colours — yellow & orange accents for SVG illustrations
|
|
28
|
+
brightFlame: '#FF6E40', // Coral orange — warm blush accent
|
|
29
|
+
brightGold: '#FFD740', // Amber gold — golden warmth
|
|
30
|
+
// Vivid brights for light backgrounds — punchy, saturated, OpenAI-blog vibrancy
|
|
31
|
+
brightLightGlow: '#FF4081', // Hot pink
|
|
32
|
+
brightLightPop: '#FF6E40', // Vivid coral
|
|
33
|
+
brightLightSpark: '#EA80FC', // Electric fuchsia
|
|
34
|
+
brightLightBlaze: '#FF1744', // Vivid crimson
|
|
35
|
+
brightLightSurge: '#536DFE', // Vivid indigo
|
|
36
|
+
brightLightFlame: '#FF6E40', // Vivid coral orange
|
|
37
|
+
brightLightGold: '#FFD740', // Vivid amber gold
|
|
21
38
|
};
|
|
@@ -17,4 +17,18 @@ export declare const matrixColors: {
|
|
|
17
17
|
greenGlow: string;
|
|
18
18
|
greenHover: string;
|
|
19
19
|
greenTerminal: string;
|
|
20
|
+
brightGlow: string;
|
|
21
|
+
brightPop: string;
|
|
22
|
+
brightSpark: string;
|
|
23
|
+
brightBlaze: string;
|
|
24
|
+
brightSurge: string;
|
|
25
|
+
brightFlame: string;
|
|
26
|
+
brightGold: string;
|
|
27
|
+
brightLightGlow: string;
|
|
28
|
+
brightLightPop: string;
|
|
29
|
+
brightLightSpark: string;
|
|
30
|
+
brightLightBlaze: string;
|
|
31
|
+
brightLightSurge: string;
|
|
32
|
+
brightLightFlame: string;
|
|
33
|
+
brightLightGold: string;
|
|
20
34
|
};
|
|
@@ -23,4 +23,21 @@ export const matrixColors = {
|
|
|
23
23
|
greenGlow: '#39FF14', // Neon phosphor glow — brightest accent on dark
|
|
24
24
|
greenHover: '#0E6655', // Datalayer hover — primary button hover
|
|
25
25
|
greenTerminal: '#003B00', // Deep terminal — dark mode subtle/canvas
|
|
26
|
+
// Bright / vivid colours for SVG illustrations (OpenAI-blog style)
|
|
27
|
+
brightGlow: '#39FF14', // Neon green — primary glow (re-stated for palette API)
|
|
28
|
+
brightPop: '#00FF88', // Phosphor cyan — contrasting accent
|
|
29
|
+
brightSpark: '#CCFF00', // Acid lime — sparkle / tertiary
|
|
30
|
+
brightBlaze: '#FF0040', // Matrix red pill — warm accent
|
|
31
|
+
brightSurge: '#00E5FF', // Electric blue — cool accent
|
|
32
|
+
// Warm vivid colours — yellow & orange accents for SVG illustrations
|
|
33
|
+
brightFlame: '#FF6D00', // Electric orange — glitch warm accent
|
|
34
|
+
brightGold: '#FFEA00', // Glitch yellow — phosphor highlight
|
|
35
|
+
// Vivid brights for light backgrounds — punchy, saturated, OpenAI-blog vibrancy
|
|
36
|
+
brightLightGlow: '#00E676', // Vivid green
|
|
37
|
+
brightLightPop: '#1DE9B6', // Vivid teal-mint
|
|
38
|
+
brightLightSpark: '#AEEA00', // Vivid lime
|
|
39
|
+
brightLightBlaze: '#FF1744', // Vivid red
|
|
40
|
+
brightLightSurge: '#00B0FF', // Vivid sky blue
|
|
41
|
+
brightLightFlame: '#FF6D00', // Vivid orange
|
|
42
|
+
brightLightGold: '#FFAB00', // Vivid amber
|
|
26
43
|
};
|
|
@@ -12,4 +12,18 @@ export declare const spatialColors: {
|
|
|
12
12
|
indigoTint: string;
|
|
13
13
|
indigoBright: string;
|
|
14
14
|
indigoHover: string;
|
|
15
|
+
brightGlow: string;
|
|
16
|
+
brightPop: string;
|
|
17
|
+
brightSpark: string;
|
|
18
|
+
brightBlaze: string;
|
|
19
|
+
brightSurge: string;
|
|
20
|
+
brightFlame: string;
|
|
21
|
+
brightGold: string;
|
|
22
|
+
brightLightGlow: string;
|
|
23
|
+
brightLightPop: string;
|
|
24
|
+
brightLightSpark: string;
|
|
25
|
+
brightLightBlaze: string;
|
|
26
|
+
brightLightSurge: string;
|
|
27
|
+
brightLightFlame: string;
|
|
28
|
+
brightLightGold: string;
|
|
15
29
|
};
|
|
@@ -18,4 +18,21 @@ export const spatialColors = {
|
|
|
18
18
|
indigoTint: '#EEF2FF', // Soft background for callouts
|
|
19
19
|
indigoBright: '#818CF8', // Highlights & glow on dark
|
|
20
20
|
indigoHover: '#312E81', // Primary button hover
|
|
21
|
+
// Bright / vivid colours for SVG illustrations (OpenAI-blog style)
|
|
22
|
+
brightGlow: '#7C4DFF', // Electric violet — primary glow
|
|
23
|
+
brightPop: '#448AFF', // Neon blue — contrasting accent
|
|
24
|
+
brightSpark: '#E040FB', // Vivid magenta — sparkle / tertiary
|
|
25
|
+
brightBlaze: '#FF5252', // Neon red — warm accent
|
|
26
|
+
brightSurge: '#00B0FF', // Deep sky blue — cool accent
|
|
27
|
+
// Warm vivid colours — yellow & orange accents for SVG illustrations
|
|
28
|
+
brightFlame: '#FF9100', // Amber orange — warm cosmic accent
|
|
29
|
+
brightGold: '#FFEA00', // Electric yellow — star highlight
|
|
30
|
+
// Vivid brights for light backgrounds — punchy, saturated, OpenAI-blog vibrancy
|
|
31
|
+
brightLightGlow: '#7C4DFF', // Electric violet
|
|
32
|
+
brightLightPop: '#448AFF', // Neon blue
|
|
33
|
+
brightLightSpark: '#D500F9', // Vivid purple
|
|
34
|
+
brightLightBlaze: '#FF5252', // Neon red
|
|
35
|
+
brightLightSurge: '#00B0FF', // Vivid sky blue
|
|
36
|
+
brightLightFlame: '#FF9100', // Vivid amber orange
|
|
37
|
+
brightLightGold: '#FFC400', // Vivid gold
|
|
21
38
|
};
|
package/lib/theme/index.d.ts
CHANGED
package/lib/theme/index.js
CHANGED
|
@@ -2,6 +2,37 @@ import { type CSSProperties } from 'react';
|
|
|
2
2
|
import { type ColorMode } from './DatalayerBrandThemeProvider';
|
|
3
3
|
/** Available theme variants. */
|
|
4
4
|
export type ThemeVariant = 'datalayer' | 'spatial' | 'lovely' | 'matrix';
|
|
5
|
+
/** A pair of colours for a two-stop gradient. */
|
|
6
|
+
export interface GradientPair {
|
|
7
|
+
/** Start colour (brighter / brand). */
|
|
8
|
+
from: string;
|
|
9
|
+
/** End colour (deeper / hover). */
|
|
10
|
+
to: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Vivid colour triplet for SVG illustrations.
|
|
14
|
+
*
|
|
15
|
+
* Inspired by OpenAI's blog — ultra-saturated, luminous hues designed
|
|
16
|
+
* to glow and pop against both light and dark backgrounds.
|
|
17
|
+
*/
|
|
18
|
+
export interface BrightPalette {
|
|
19
|
+
/** Primary vivid accent — the "star" glow colour. */
|
|
20
|
+
glow: string;
|
|
21
|
+
/** Optimal text colour for content rendered on a `glow` background. */
|
|
22
|
+
onGlow: string;
|
|
23
|
+
/** Contrasting vivid colour — analogous/complement. */
|
|
24
|
+
pop: string;
|
|
25
|
+
/** Third vivid colour — sparkle / small highlights. */
|
|
26
|
+
spark: string;
|
|
27
|
+
/** Vivid red / warm accent — energy, urgency, warmth. */
|
|
28
|
+
blaze: string;
|
|
29
|
+
/** Vivid blue / cool accent — depth, trust, electricity. */
|
|
30
|
+
surge: string;
|
|
31
|
+
/** Vivid orange — warm energy, fire, dynamism. */
|
|
32
|
+
flame: string;
|
|
33
|
+
/** Vivid yellow / gold — highlights, attention, optimism. */
|
|
34
|
+
gold: string;
|
|
35
|
+
}
|
|
5
36
|
/**
|
|
6
37
|
* Complete configuration for a theme, including the Primer theme object,
|
|
7
38
|
* display metadata, and CSS custom property overrides per color mode.
|
|
@@ -22,9 +53,53 @@ export interface ThemeConfig {
|
|
|
22
53
|
light: CSSProperties;
|
|
23
54
|
dark: CSSProperties;
|
|
24
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* Per-mode gradient pair for card backgrounds, banners, and other
|
|
58
|
+
* decorative surfaces that need a themed two-colour gradient.
|
|
59
|
+
*/
|
|
60
|
+
cardGradient: {
|
|
61
|
+
light: GradientPair;
|
|
62
|
+
dark: GradientPair;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Vivid colour triplet for SVG illustrations — ultra-saturated,
|
|
66
|
+
* luminous hues that glow and pop on dark backgrounds (OpenAI-blog style).
|
|
67
|
+
*/
|
|
68
|
+
brightPalette: BrightPalette;
|
|
69
|
+
/**
|
|
70
|
+
* Deeper / richer bright palette for light backgrounds.
|
|
71
|
+
* Same hue families as `brightPalette` but with higher contrast on
|
|
72
|
+
* light surfaces so illustrations don't appear faded.
|
|
73
|
+
*/
|
|
74
|
+
brightPaletteLight: BrightPalette;
|
|
25
75
|
}
|
|
26
76
|
export declare const themeConfigs: Record<ThemeVariant, ThemeConfig>;
|
|
27
77
|
/** All available theme variants in display order. */
|
|
28
78
|
export declare const themeVariants: ThemeVariant[];
|
|
29
79
|
/** Look up a theme config by variant name. */
|
|
30
80
|
export declare function getThemeConfig(variant: ThemeVariant): ThemeConfig;
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the card gradient for a given theme variant and colour mode.
|
|
83
|
+
* Falls back to `datalayer` / `light` when values are missing.
|
|
84
|
+
*/
|
|
85
|
+
export declare function getCardGradient(variant?: ThemeVariant, colorMode?: 'light' | 'dark' | 'auto'): GradientPair;
|
|
86
|
+
/**
|
|
87
|
+
* Get the bright (vivid / OpenAI-blog-style) palette for a given theme variant.
|
|
88
|
+
*
|
|
89
|
+
* When `colorMode` is `'light'` the vivid / saturated light-background palette
|
|
90
|
+
* is returned — these are punchy, high-saturation colours designed to keep SVG
|
|
91
|
+
* illustrations vibrant and energetic on near-white surfaces.
|
|
92
|
+
* When `colorMode` is `'auto'`, the OS preference is queried via
|
|
93
|
+
* `prefers-color-scheme` so palettes always match the effective background.
|
|
94
|
+
* Defaults to the dark-optimised neon palette for backward compatibility.
|
|
95
|
+
*/
|
|
96
|
+
export declare function getBrightPalette(variant?: ThemeVariant, colorMode?: 'light' | 'dark' | 'auto'): BrightPalette;
|
|
97
|
+
/**
|
|
98
|
+
* Get a 5-colour avatar palette for the given theme variant and colour mode.
|
|
99
|
+
*
|
|
100
|
+
* Designed for use with the `boring-avatars` library's `colors` prop.
|
|
101
|
+
* When `colorMode` is `'auto'`, the OS preference is queried via
|
|
102
|
+
* `prefers-color-scheme` so avatars always match the effective background.
|
|
103
|
+
* Falls back to `datalayer` / `light` when values are missing.
|
|
104
|
+
*/
|
|
105
|
+
export declare function getAvatarColors(variant?: ThemeVariant, colorMode?: 'light' | 'dark' | 'auto'): string[];
|