@weasel-js/theme 1.9.2 → 1.9.4
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 +7 -0
- package/dist/{chunk-NUILKH2Z.js → chunk-7LCRXZDY.js} +43 -20
- package/dist/chunk-7LCRXZDY.js.map +1 -0
- package/dist/{chunk-CAMHNPQN.js → chunk-EFGZ56CE.js} +311 -51
- package/dist/chunk-EFGZ56CE.js.map +1 -0
- package/dist/{definition-DLgEuUUG.d.ts → definition-GS7_Kz9D.d.ts} +45 -8
- package/dist/engine.d.ts +4 -4
- package/dist/engine.js +76 -36
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +19 -9
- package/dist/index.js +21 -7
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +6 -4
- package/dist/react.js.map +1 -1
- package/dist/tokens.css +32 -4
- package/package.json +3 -2
- package/dist/chunk-CAMHNPQN.js.map +0 -1
- package/dist/chunk-NUILKH2Z.js.map +0 -1
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { a as Theme, S as Selection, o as ResolvedTheme, v as ColorList } from './definition-
|
|
2
|
+
import { a as Theme, S as Selection, o as ResolvedTheme, v as ColorList } from './definition-GS7_Kz9D.js';
|
|
3
3
|
import { a as ColorModePreference, C as ColorMode } from './colorMode-CoklZomJ.js';
|
|
4
4
|
export { i as isColorModePreference } from './colorMode-CoklZomJ.js';
|
|
5
5
|
|
package/dist/react.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isColorModePreference, weaselTheme, themeTones, applyTheme } from './chunk-
|
|
2
|
-
export { isColorModePreference } from './chunk-
|
|
3
|
-
import { themeAxes, fullSelection, selectionKey, resolveTheme } from './chunk-
|
|
1
|
+
import { isColorModePreference, weaselTheme, themeTones, applyTheme } from './chunk-EFGZ56CE.js';
|
|
2
|
+
export { isColorModePreference } from './chunk-EFGZ56CE.js';
|
|
3
|
+
import { themeAxes, fullSelection, selectionKey, resolveTheme } from './chunk-7LCRXZDY.js';
|
|
4
4
|
import { createContext, useState, useEffect, useCallback, useRef, useMemo, useLayoutEffect, useContext } from 'react';
|
|
5
5
|
import { jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
@@ -71,9 +71,11 @@ function ThemeProvider({
|
|
|
71
71
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
72
|
[theme, key, tones]
|
|
73
73
|
);
|
|
74
|
+
const release = useRef(null);
|
|
74
75
|
useLayoutEffect(() => {
|
|
75
|
-
if (ref.current) applyTheme(ref.current, theme, value.selection);
|
|
76
|
+
if (ref.current) release.current = applyTheme(ref.current, theme, value.selection);
|
|
76
77
|
}, [theme, value]);
|
|
78
|
+
useLayoutEffect(() => () => release.current?.(), []);
|
|
77
79
|
const attrs = Object.fromEntries(Object.keys(axes).map((a) => [`data-wzl-${a}`, full[a]]));
|
|
78
80
|
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { ref, className, style, "data-wzl-theme": theme.name, ...attrs, children }) });
|
|
79
81
|
}
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useColorMode.ts","../src/react.tsx"],"names":[],"mappings":"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","file":"react.js","sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { isColorModePreference, type ColorMode, type ColorModePreference } from './colorMode';\n\nfunction systemQuery(): MediaQueryList | null {\n if (typeof globalThis.matchMedia !== 'function') return null;\n return globalThis.matchMedia('(prefers-color-scheme: light)');\n}\n\nconst systemMode = (): ColorMode => (systemQuery()?.matches ? 'light' : 'dark');\n\n/**\n * Resolves a preference to the mode a `ThemeProvider` selection takes.\n * `'auto'` subscribes to the OS setting and follows it live; an explicit\n * choice opts out of the subscription entirely.\n */\nexport function useResolvedColorMode(preference: ColorModePreference): ColorMode {\n const [system, setSystem] = useState<ColorMode>(systemMode);\n\n useEffect(() => {\n if (preference !== 'auto') return;\n const mq = systemQuery();\n if (!mq) return;\n // eslint-disable-next-line react-hooks/set-state-in-effect -- syncs to the OS color-scheme query\n setSystem(mq.matches ? 'light' : 'dark');\n const onChange = (e: { matches: boolean }) => setSystem(e.matches ? 'light' : 'dark');\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [preference]);\n\n return preference === 'auto' ? system : preference;\n}\n\n/** The part of `Storage` {@link useColorModePreference} reads and writes. */\nexport type ColorModeStorage = Pick<Storage, 'getItem' | 'setItem'>;\n\n/** Options for {@link useColorModePreference}. */\nexport interface ColorModePreferenceOptions {\n /** Where the choice is remembered. Unset, it lasts as long as the component. */\n readonly storageKey?: string;\n /** The store `storageKey` names a slot in. Defaults to `localStorage`. */\n readonly storage?: ColorModeStorage;\n /** The preference before the user has chosen one. Defaults to `'auto'`. */\n readonly defaultPreference?: ColorModePreference;\n}\n\n/** What {@link useColorModePreference} returns. */\nexport interface ColorModePreferenceState {\n readonly preference: ColorModePreference;\n readonly setPreference: (next: ColorModePreference) => void;\n /** `preference` resolved against the OS — what to put in the theme's `mode` axis. */\n readonly mode: ColorMode;\n}\n\nfunction defaultStorage(): ColorModeStorage | undefined {\n try {\n return globalThis.localStorage ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * A user's color-mode choice, optionally remembered across loads, and the mode\n * it resolves to. Storage that is missing or throws (a private window, blocked\n * site data) degrades to an unremembered choice rather than an error.\n */\nexport function useColorModePreference(\n options: ColorModePreferenceOptions = {},\n): ColorModePreferenceState {\n const { storageKey, storage, defaultPreference = 'auto' } = options;\n\n const [preference, setState] = useState<ColorModePreference>(() => {\n if (storageKey === undefined) return defaultPreference;\n try {\n const stored = (storage ?? defaultStorage())?.getItem(storageKey);\n return isColorModePreference(stored) ? stored : defaultPreference;\n } catch {\n return defaultPreference;\n }\n });\n\n const setPreference = useCallback(\n (next: ColorModePreference) => {\n setState(next);\n if (storageKey === undefined) return;\n try {\n (storage ?? defaultStorage())?.setItem(storageKey, next);\n } catch {\n // Unremembered, but still applied.\n }\n },\n [storageKey, storage],\n );\n\n return { preference, setPreference, mode: useResolvedColorMode(preference) };\n}\n","import React, { createContext, useContext, useMemo, useRef, useLayoutEffect } from 'react';\nimport { applyTheme } from './applyTheme';\nimport { themeTones, type ColorList } from './colorList';\nimport { fullSelection, selectionKey, type Selection } from './axes';\nimport { resolveTheme, themeAxes, type ResolvedTheme } from './resolveTheme';\nimport { weaselTheme, type Theme } from './theme';\n\nexport {\n useColorModePreference,\n useResolvedColorMode,\n type ColorModePreferenceOptions,\n type ColorModePreferenceState,\n type ColorModeStorage,\n} from './useColorMode';\nexport { isColorModePreference, type ColorMode, type ColorModePreference } from './colorMode';\n\n/** What `<ThemeProvider>` publishes: the theme, the full selection in force, the\n * fully resolved token record for that pair, and the tone list in force. */\nexport interface ThemeContextValue {\n readonly theme: Theme;\n readonly selection: Selection;\n readonly resolved: ResolvedTheme;\n readonly tones: ColorList;\n}\n\n/** What `<ThemeProvider>` publishes. Provide `null` to hide an outer theme from a subtree, as a\n * boundary that renders its children the way a page with no provider would. */\nexport const ThemeContext = createContext<ThemeContextValue | null>(null);\n\n/** Props for `<ThemeProvider>`. */\nexport interface ThemeProviderProps {\n readonly theme?: Theme;\n /** Axis values, e.g. `{ mode: 'light' }`. A missing axis takes its default. */\n readonly selection?: Selection;\n /** The colors a `tone` index picks from in this subtree. Absent: the theme's own. */\n readonly tones?: ColorList;\n /** Applied to the wrapper element, so it can be the layout element too. */\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly children: React.ReactNode;\n}\n\n/**\n * Applies a theme to a wrapper element and publishes the resolved record.\n *\n * Consumers that draw outside the DOM (the WebGL HUD) read `resolved` and\n * never touch `getComputedStyle`.\n *\n * The wrapper is a real element in the layout. Pass `className` rather than\n * nesting your own div inside — an anonymous div between a flex parent and\n * its child breaks percentage heights.\n */\nexport function ThemeProvider({\n theme = weaselTheme,\n selection,\n tones,\n className,\n style,\n children,\n}: ThemeProviderProps): React.ReactElement {\n const ref = useRef<HTMLDivElement>(null);\n const axes = themeAxes(theme);\n const full = fullSelection(axes, selection);\n // Keyed on the selection's content: callers pass a fresh object every render.\n const key = selectionKey(axes, full);\n\n const value = useMemo<ThemeContextValue>(\n () => ({ theme, selection: full, resolved: resolveTheme(theme, full), tones: tones ?? themeTones(theme) }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [theme, key, tones],\n );\n\n useLayoutEffect(() => {\n if (ref.current) applyTheme(ref.current, theme, value.selection);\n }, [theme, value]);\n\n const attrs = Object.fromEntries(Object.keys(axes).map((a) => [`data-wzl-${a}`, full[a]]));\n return (\n <ThemeContext.Provider value={value}>\n <div ref={ref} className={className} style={style} data-wzl-theme={theme.name} {...attrs}>\n {children}\n </div>\n </ThemeContext.Provider>\n );\n}\n\n/** The theme in force. Throws outside a `<ThemeProvider>`; use\n * `useThemeOptional` where the provider is not guaranteed. */\nexport function useTheme(): ThemeContextValue {\n const ctx = useContext(ThemeContext);\n if (!ctx) throw new Error('useTheme must be used inside a <ThemeProvider>');\n return ctx;\n}\n\n/**\n * The theme if one is provided, `null` otherwise.\n *\n * For kit internals that should follow a theme when the app supplies one but\n * must still work in an app that never mounted a provider — `useHud` is the\n * motivating case.\n */\nexport function useThemeOptional(): ThemeContextValue | null {\n return useContext(ThemeContext);\n}\n\nlet defaultTones: ThemeContextValue | undefined;\n\n/**\n * The tone list in force and what it resolves against — the nearest\n * `<ThemeProvider>`'s, else the built-in theme's at its defaults. Pass the\n * result as `colorAt`'s context.\n */\nexport function useTones(): ThemeContextValue {\n const ctx = useContext(ThemeContext);\n if (ctx) return ctx;\n return (defaultTones ??= {\n theme: weaselTheme,\n selection: fullSelection(themeAxes(weaselTheme)),\n resolved: resolveTheme(weaselTheme),\n tones: themeTones(weaselTheme),\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useColorMode.ts","../src/react.tsx"],"names":[],"mappings":";;;;;;AAGA,SAAS,WAAA,GAAqC;AAC5C,EAAA,IAAI,OAAO,UAAA,CAAW,UAAA,KAAe,UAAA,EAAY,OAAO,IAAA;AACxD,EAAA,OAAO,UAAA,CAAW,WAAW,+BAA+B,CAAA;AAC9D;AAEA,IAAM,UAAA,GAAa,MAAkB,WAAA,EAAY,EAAG,UAAU,OAAA,GAAU,MAAA;AAOjE,SAAS,qBAAqB,UAAA,EAA4C;AAC/E,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAoB,UAAU,CAAA;AAE1D,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,eAAe,MAAA,EAAQ;AAC3B,IAAA,MAAM,KAAK,WAAA,EAAY;AACvB,IAAA,IAAI,CAAC,EAAA,EAAI;AAET,IAAA,SAAA,CAAU,EAAA,CAAG,OAAA,GAAU,OAAA,GAAU,MAAM,CAAA;AACvC,IAAA,MAAM,WAAW,CAAC,CAAA,KAA4B,UAAU,CAAA,CAAE,OAAA,GAAU,UAAU,MAAM,CAAA;AACpF,IAAA,EAAA,CAAG,gBAAA,CAAiB,UAAU,QAAQ,CAAA;AACtC,IAAA,OAAO,MAAM,EAAA,CAAG,mBAAA,CAAoB,QAAA,EAAU,QAAQ,CAAA;AAAA,EACxD,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAA,OAAO,UAAA,KAAe,SAAS,MAAA,GAAS,UAAA;AAC1C;AAuBA,SAAS,cAAA,GAA+C;AACtD,EAAA,IAAI;AACF,IAAA,OAAO,WAAW,YAAA,IAAgB,KAAA,CAAA;AAAA,EACpC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAOO,SAAS,sBAAA,CACd,OAAA,GAAsC,EAAC,EACb;AAC1B,EAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,iBAAA,GAAoB,QAAO,GAAI,OAAA;AAE5D,EAAA,MAAM,CAAC,UAAA,EAAY,QAAQ,CAAA,GAAI,SAA8B,MAAM;AACjE,IAAA,IAAI,UAAA,KAAe,QAAW,OAAO,iBAAA;AACrC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAA,CAAU,OAAA,IAAW,cAAA,EAAe,GAAI,QAAQ,UAAU,CAAA;AAChE,MAAA,OAAO,qBAAA,CAAsB,MAAM,CAAA,GAAI,MAAA,GAAS,iBAAA;AAAA,IAClD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,iBAAA;AAAA,IACT;AAAA,EACF,CAAC,CAAA;AAED,EAAA,MAAM,aAAA,GAAgB,WAAA;AAAA,IACpB,CAAC,IAAA,KAA8B;AAC7B,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,IAAI,eAAe,MAAA,EAAW;AAC9B,MAAA,IAAI;AACF,QAAA,CAAC,OAAA,IAAW,cAAA,EAAe,GAAI,OAAA,CAAQ,YAAY,IAAI,CAAA;AAAA,MACzD,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA;AAAA,IACA,CAAC,YAAY,OAAO;AAAA,GACtB;AAEA,EAAA,OAAO,EAAE,UAAA,EAAY,aAAA,EAAe,IAAA,EAAM,oBAAA,CAAqB,UAAU,CAAA,EAAE;AAC7E;ACpEO,IAAM,YAAA,GAAe,cAAwC,IAAI;AAyBjE,SAAS,aAAA,CAAc;AAAA,EAC5B,KAAA,GAAQ,WAAA;AAAA,EACR,SAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAA2C;AACzC,EAAA,MAAM,GAAA,GAAM,OAAuB,IAAI,CAAA;AACvC,EAAA,MAAM,IAAA,GAAO,UAAU,KAAK,CAAA;AAC5B,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,IAAA,EAAM,SAAS,CAAA;AAE1C,EAAA,MAAM,GAAA,GAAM,YAAA,CAAa,IAAA,EAAM,IAAI,CAAA;AAEnC,EAAA,MAAM,KAAA,GAAQ,OAAA;AAAA,IACZ,OAAO,EAAE,KAAA,EAAO,SAAA,EAAW,MAAM,QAAA,EAAU,YAAA,CAAa,KAAA,EAAO,IAAI,CAAA,EAAG,KAAA,EAAO,KAAA,IAAS,UAAA,CAAW,KAAK,CAAA,EAAE,CAAA;AAAA;AAAA,IAExG,CAAC,KAAA,EAAO,GAAA,EAAK,KAAK;AAAA,GACpB;AAGA,EAAA,MAAM,OAAA,GAAU,OAA4B,IAAI,CAAA;AAChD,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,IAAI,GAAA,CAAI,SAAS,OAAA,CAAQ,OAAA,GAAU,WAAW,GAAA,CAAI,OAAA,EAAS,KAAA,EAAO,KAAA,CAAM,SAAS,CAAA;AAAA,EACnF,CAAA,EAAG,CAAC,KAAA,EAAO,KAAK,CAAC,CAAA;AACjB,EAAA,eAAA,CAAgB,MAAM,MAAM,OAAA,CAAQ,OAAA,IAAU,EAAG,EAAE,CAAA;AAEnD,EAAA,MAAM,QAAQ,MAAA,CAAO,WAAA,CAAY,OAAO,IAAA,CAAK,IAAI,EAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,YAAY,CAAC,CAAA,CAAA,EAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AACzF,EAAA,2BACG,YAAA,CAAa,QAAA,EAAb,EAAsB,KAAA,EACrB,8BAAC,KAAA,EAAA,EAAI,GAAA,EAAU,SAAA,EAAsB,KAAA,EAAc,kBAAgB,KAAA,CAAM,IAAA,EAAO,GAAG,KAAA,EAChF,UACH,CAAA,EACF,CAAA;AAEJ;AAIO,SAAS,QAAA,GAA8B;AAC5C,EAAA,MAAM,GAAA,GAAM,WAAW,YAAY,CAAA;AACnC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,MAAM,gDAAgD,CAAA;AAC1E,EAAA,OAAO,GAAA;AACT;AASO,SAAS,gBAAA,GAA6C;AAC3D,EAAA,OAAO,WAAW,YAAY,CAAA;AAChC;AAEA,IAAI,YAAA;AAOG,SAAS,QAAA,GAA8B;AAC5C,EAAA,MAAM,GAAA,GAAM,WAAW,YAAY,CAAA;AACnC,EAAA,IAAI,KAAK,OAAO,GAAA;AAChB,EAAA,OAAQ,YAAA,KAAiB;AAAA,IACvB,KAAA,EAAO,WAAA;AAAA,IACP,SAAA,EAAW,aAAA,CAAc,SAAA,CAAU,WAAW,CAAC,CAAA;AAAA,IAC/C,QAAA,EAAU,aAAa,WAAW,CAAA;AAAA,IAClC,KAAA,EAAO,WAAW,WAAW;AAAA,GAC/B;AACF","file":"react.js","sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { isColorModePreference, type ColorMode, type ColorModePreference } from './colorMode';\n\nfunction systemQuery(): MediaQueryList | null {\n if (typeof globalThis.matchMedia !== 'function') return null;\n return globalThis.matchMedia('(prefers-color-scheme: light)');\n}\n\nconst systemMode = (): ColorMode => (systemQuery()?.matches ? 'light' : 'dark');\n\n/**\n * Resolves a preference to the mode a `ThemeProvider` selection takes.\n * `'auto'` subscribes to the OS setting and follows it live; an explicit\n * choice opts out of the subscription entirely.\n */\nexport function useResolvedColorMode(preference: ColorModePreference): ColorMode {\n const [system, setSystem] = useState<ColorMode>(systemMode);\n\n useEffect(() => {\n if (preference !== 'auto') return;\n const mq = systemQuery();\n if (!mq) return;\n // eslint-disable-next-line react-hooks/set-state-in-effect -- syncs to the OS color-scheme query\n setSystem(mq.matches ? 'light' : 'dark');\n const onChange = (e: { matches: boolean }) => setSystem(e.matches ? 'light' : 'dark');\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [preference]);\n\n return preference === 'auto' ? system : preference;\n}\n\n/** The part of `Storage` {@link useColorModePreference} reads and writes. */\nexport type ColorModeStorage = Pick<Storage, 'getItem' | 'setItem'>;\n\n/** Options for {@link useColorModePreference}. */\nexport interface ColorModePreferenceOptions {\n /** Where the choice is remembered. Unset, it lasts as long as the component. */\n readonly storageKey?: string;\n /** The store `storageKey` names a slot in. Defaults to `localStorage`. */\n readonly storage?: ColorModeStorage;\n /** The preference before the user has chosen one. Defaults to `'auto'`. */\n readonly defaultPreference?: ColorModePreference;\n}\n\n/** What {@link useColorModePreference} returns. */\nexport interface ColorModePreferenceState {\n readonly preference: ColorModePreference;\n readonly setPreference: (next: ColorModePreference) => void;\n /** `preference` resolved against the OS — what to put in the theme's `mode` axis. */\n readonly mode: ColorMode;\n}\n\nfunction defaultStorage(): ColorModeStorage | undefined {\n try {\n return globalThis.localStorage ?? undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * A user's color-mode choice, optionally remembered across loads, and the mode\n * it resolves to. Storage that is missing or throws (a private window, blocked\n * site data) degrades to an unremembered choice rather than an error.\n */\nexport function useColorModePreference(\n options: ColorModePreferenceOptions = {},\n): ColorModePreferenceState {\n const { storageKey, storage, defaultPreference = 'auto' } = options;\n\n const [preference, setState] = useState<ColorModePreference>(() => {\n if (storageKey === undefined) return defaultPreference;\n try {\n const stored = (storage ?? defaultStorage())?.getItem(storageKey);\n return isColorModePreference(stored) ? stored : defaultPreference;\n } catch {\n return defaultPreference;\n }\n });\n\n const setPreference = useCallback(\n (next: ColorModePreference) => {\n setState(next);\n if (storageKey === undefined) return;\n try {\n (storage ?? defaultStorage())?.setItem(storageKey, next);\n } catch {\n // Unremembered, but still applied.\n }\n },\n [storageKey, storage],\n );\n\n return { preference, setPreference, mode: useResolvedColorMode(preference) };\n}\n","import React, { createContext, useContext, useMemo, useRef, useLayoutEffect } from 'react';\nimport { applyTheme } from './applyTheme';\nimport { themeTones, type ColorList } from './colorList';\nimport { fullSelection, selectionKey, type Selection } from './axes';\nimport { resolveTheme, themeAxes, type ResolvedTheme } from './resolveTheme';\nimport { weaselTheme, type Theme } from './theme';\n\nexport {\n useColorModePreference,\n useResolvedColorMode,\n type ColorModePreferenceOptions,\n type ColorModePreferenceState,\n type ColorModeStorage,\n} from './useColorMode';\nexport { isColorModePreference, type ColorMode, type ColorModePreference } from './colorMode';\n\n/** What `<ThemeProvider>` publishes: the theme, the full selection in force, the\n * fully resolved token record for that pair, and the tone list in force. */\nexport interface ThemeContextValue {\n readonly theme: Theme;\n readonly selection: Selection;\n readonly resolved: ResolvedTheme;\n readonly tones: ColorList;\n}\n\n/** What `<ThemeProvider>` publishes. Provide `null` to hide an outer theme from a subtree, as a\n * boundary that renders its children the way a page with no provider would. */\nexport const ThemeContext = createContext<ThemeContextValue | null>(null);\n\n/** Props for `<ThemeProvider>`. */\nexport interface ThemeProviderProps {\n readonly theme?: Theme;\n /** Axis values, e.g. `{ mode: 'light' }`. A missing axis takes its default. */\n readonly selection?: Selection;\n /** The colors a `tone` index picks from in this subtree. Absent: the theme's own. */\n readonly tones?: ColorList;\n /** Applied to the wrapper element, so it can be the layout element too. */\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly children: React.ReactNode;\n}\n\n/**\n * Applies a theme to a wrapper element and publishes the resolved record.\n *\n * Consumers that draw outside the DOM (the WebGL HUD) read `resolved` and\n * never touch `getComputedStyle`.\n *\n * The wrapper is a real element in the layout. Pass `className` rather than\n * nesting your own div inside — an anonymous div between a flex parent and\n * its child breaks percentage heights.\n */\nexport function ThemeProvider({\n theme = weaselTheme,\n selection,\n tones,\n className,\n style,\n children,\n}: ThemeProviderProps): React.ReactElement {\n const ref = useRef<HTMLDivElement>(null);\n const axes = themeAxes(theme);\n const full = fullSelection(axes, selection);\n // Keyed on the selection's content: callers pass a fresh object every render.\n const key = selectionKey(axes, full);\n\n const value = useMemo<ThemeContextValue>(\n () => ({ theme, selection: full, resolved: resolveTheme(theme, full), tones: tones ?? themeTones(theme) }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [theme, key, tones],\n );\n\n // Applying again replaces what the element held, so only the unmount releases.\n const release = useRef<(() => void) | null>(null);\n useLayoutEffect(() => {\n if (ref.current) release.current = applyTheme(ref.current, theme, value.selection);\n }, [theme, value]);\n useLayoutEffect(() => () => release.current?.(), []);\n\n const attrs = Object.fromEntries(Object.keys(axes).map((a) => [`data-wzl-${a}`, full[a]]));\n return (\n <ThemeContext.Provider value={value}>\n <div ref={ref} className={className} style={style} data-wzl-theme={theme.name} {...attrs}>\n {children}\n </div>\n </ThemeContext.Provider>\n );\n}\n\n/** The theme in force. Throws outside a `<ThemeProvider>`; use\n * `useThemeOptional` where the provider is not guaranteed. */\nexport function useTheme(): ThemeContextValue {\n const ctx = useContext(ThemeContext);\n if (!ctx) throw new Error('useTheme must be used inside a <ThemeProvider>');\n return ctx;\n}\n\n/**\n * The theme if one is provided, `null` otherwise.\n *\n * For kit internals that should follow a theme when the app supplies one but\n * must still work in an app that never mounted a provider — `useHud` is the\n * motivating case.\n */\nexport function useThemeOptional(): ThemeContextValue | null {\n return useContext(ThemeContext);\n}\n\nlet defaultTones: ThemeContextValue | undefined;\n\n/**\n * The tone list in force and what it resolves against — the nearest\n * `<ThemeProvider>`'s, else the built-in theme's at its defaults. Pass the\n * result as `colorAt`'s context.\n */\nexport function useTones(): ThemeContextValue {\n const ctx = useContext(ThemeContext);\n if (ctx) return ctx;\n return (defaultTones ??= {\n theme: weaselTheme,\n selection: fullSelection(themeAxes(weaselTheme)),\n resolved: resolveTheme(weaselTheme),\n tones: themeTones(weaselTheme),\n });\n}\n"]}
|
package/dist/tokens.css
CHANGED
|
@@ -77,6 +77,18 @@
|
|
|
77
77
|
--wzl-fg-inverse: var(--wzl-gray-900);
|
|
78
78
|
/* Elevation. Always darker than any surface — never derived from fg, which is near-white on dark. */
|
|
79
79
|
--wzl-shadow: rgba(0, 0, 0, 0.6);
|
|
80
|
+
/* Keywords in highlighted code. */
|
|
81
|
+
--wzl-code-keyword: var(--wzl-swatch-violet);
|
|
82
|
+
/* String literals in highlighted code. */
|
|
83
|
+
--wzl-code-string: var(--wzl-swatch-green);
|
|
84
|
+
/* Numbers in highlighted code. */
|
|
85
|
+
--wzl-code-number: var(--wzl-swatch-amber);
|
|
86
|
+
/* true, false, null and undefined in highlighted code. */
|
|
87
|
+
--wzl-code-constant: var(--wzl-swatch-teal);
|
|
88
|
+
/* Property keys and attribute names in highlighted code. */
|
|
89
|
+
--wzl-code-property: var(--wzl-swatch-sky);
|
|
90
|
+
/* Functions, classes and other names in highlighted code. */
|
|
91
|
+
--wzl-code-name: var(--wzl-swatch-rose);
|
|
80
92
|
/* Fill of a PropertyPanel. */
|
|
81
93
|
--wzl-panel-surface: var(--wzl-surface-raised);
|
|
82
94
|
--wzl-panel-border-color: var(--wzl-border);
|
|
@@ -174,10 +186,10 @@
|
|
|
174
186
|
--wzl-slider-track-slop: 6px;
|
|
175
187
|
/* How far past a range thumb's edge a press still grabs the thumb rather than landing on the track. Sits over the track's own slop. */
|
|
176
188
|
--wzl-slider-thumb-slop: 6px;
|
|
177
|
-
/*
|
|
178
|
-
--wzl-slider-track-mix:
|
|
179
|
-
/*
|
|
180
|
-
--wzl-slider-thumb-mix:
|
|
189
|
+
/* Proportion of accent-fg in a range track, as a color-mix percentage — not a color. Mixed into a real property, never into another custom property. Higher in dark mode, where a light tint of the accent sinks into the surface. */
|
|
190
|
+
--wzl-slider-track-mix: 40%;
|
|
191
|
+
/* Proportion of accent-fg in a range thumb, as a color-mix percentage — not a color. Solid in dark mode. */
|
|
192
|
+
--wzl-slider-thumb-mix: 100%;
|
|
181
193
|
/* Edge of a draggable handle on a plot or timeline — a keyframe diamond, a timeline key, an event mark. The default rank; -sm and -lg are the two deliberate departures from it. */
|
|
182
194
|
--wzl-handle-size: 9px;
|
|
183
195
|
/* A handle that is drawn but not draggable — a locked or pinned point. Smaller so it reads as inert next to a live one. */
|
|
@@ -268,6 +280,14 @@
|
|
|
268
280
|
--wzl-accent-fg: var(--wzl-accent-strong);
|
|
269
281
|
--wzl-fg-inverse: var(--wzl-gray-900);
|
|
270
282
|
--wzl-shadow: rgba(0, 0, 0, 0.6);
|
|
283
|
+
--wzl-code-keyword: var(--wzl-swatch-violet);
|
|
284
|
+
--wzl-code-string: var(--wzl-swatch-green);
|
|
285
|
+
--wzl-code-number: var(--wzl-swatch-amber);
|
|
286
|
+
--wzl-code-constant: var(--wzl-swatch-teal);
|
|
287
|
+
--wzl-code-property: var(--wzl-swatch-sky);
|
|
288
|
+
--wzl-code-name: var(--wzl-swatch-rose);
|
|
289
|
+
--wzl-slider-track-mix: 40%;
|
|
290
|
+
--wzl-slider-thumb-mix: 100%;
|
|
271
291
|
--wzl-secondary-fg: var(--wzl-secondary-base);
|
|
272
292
|
--wzl-panel-surface: var(--wzl-surface-raised);
|
|
273
293
|
--wzl-panel-border-color: var(--wzl-border);
|
|
@@ -319,6 +339,14 @@
|
|
|
319
339
|
--wzl-accent-fg: var(--wzl-accent-base);
|
|
320
340
|
--wzl-fg-inverse: var(--wzl-gray-50);
|
|
321
341
|
--wzl-shadow: rgba(0, 0, 0, 0.18);
|
|
342
|
+
--wzl-code-keyword: #6d28d9;
|
|
343
|
+
--wzl-code-string: #15803d;
|
|
344
|
+
--wzl-code-number: #b45309;
|
|
345
|
+
--wzl-code-constant: #0f766e;
|
|
346
|
+
--wzl-code-property: #0369a1;
|
|
347
|
+
--wzl-code-name: #be123c;
|
|
348
|
+
--wzl-slider-track-mix: 18%;
|
|
349
|
+
--wzl-slider-thumb-mix: 70%;
|
|
322
350
|
--wzl-secondary-fg: var(--wzl-secondary-soft);
|
|
323
351
|
--wzl-panel-surface: var(--wzl-surface-raised);
|
|
324
352
|
--wzl-panel-border-color: var(--wzl-border);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weasel-js/theme",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "Design tokens shared by weasel-ui and weasel-hud — CSS variables + a parallel TS export.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"./package.json": "./package.json"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@weasel-js/paint": "1.9.
|
|
34
|
+
"@weasel-js/paint": "1.9.4",
|
|
35
|
+
"@weasel-js/registry": "1.9.4"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"react": ">=18"
|