@weasel-js/theme 1.9.4 → 1.10.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 +44 -4
- package/dist/{chunk-7LCRXZDY.js → chunk-2PY2YTDY.js} +5 -54
- package/dist/chunk-2PY2YTDY.js.map +1 -0
- package/dist/chunk-3NIEJ77B.js +245 -0
- package/dist/chunk-3NIEJ77B.js.map +1 -0
- package/dist/{chunk-EFGZ56CE.js → chunk-JX2OC444.js} +169 -159
- package/dist/chunk-JX2OC444.js.map +1 -0
- package/dist/chunk-P5F3GZV6.js +54 -0
- package/dist/chunk-P5F3GZV6.js.map +1 -0
- package/dist/{definition-GS7_Kz9D.d.ts → definition-CSeERbSL.d.ts} +79 -21
- package/dist/engine.d.ts +11 -15
- package/dist/engine.js +153 -2
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +38 -3
- package/dist/index.js +46 -25
- package/dist/index.js.map +1 -1
- package/dist/react.d.ts +15 -4
- package/dist/react.js +16 -7
- package/dist/react.js.map +1 -1
- package/dist/themes/platinum.d.ts +22 -0
- package/dist/themes/platinum.js +802 -0
- package/dist/themes/platinum.js.map +1 -0
- package/dist/themes/win9x.d.ts +16 -0
- package/dist/themes/win9x.js +788 -0
- package/dist/themes/win9x.js.map +1 -0
- package/dist/tokens.css +24 -1
- package/package.json +11 -3
- package/dist/chunk-7LCRXZDY.js.map +0 -1
- package/dist/chunk-EFGZ56CE.js.map +0 -1
package/dist/react.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { isColorModePreference,
|
|
2
|
-
export { isColorModePreference } from './chunk-
|
|
3
|
-
import { themeAxes,
|
|
1
|
+
import { isColorModePreference, themeTones, applyTheme, colorSourceCss } from './chunk-3NIEJ77B.js';
|
|
2
|
+
export { isColorModePreference } from './chunk-3NIEJ77B.js';
|
|
3
|
+
import { themeAxes, resolveTheme } from './chunk-2PY2YTDY.js';
|
|
4
|
+
import { weaselTheme } from './chunk-JX2OC444.js';
|
|
5
|
+
import { fullSelection, selectionKey } from './chunk-P5F3GZV6.js';
|
|
4
6
|
import { createContext, useState, useEffect, useCallback, useRef, useMemo, useLayoutEffect, useContext } from 'react';
|
|
5
7
|
import { jsx } from 'react/jsx-runtime';
|
|
6
8
|
|
|
@@ -54,10 +56,12 @@ function useColorModePreference(options = {}) {
|
|
|
54
56
|
return { preference, setPreference, mode: useResolvedColorMode(preference) };
|
|
55
57
|
}
|
|
56
58
|
var ThemeContext = createContext(null);
|
|
59
|
+
var NO_PALETTE = { entries: [] };
|
|
57
60
|
function ThemeProvider({
|
|
58
61
|
theme = weaselTheme,
|
|
59
62
|
selection,
|
|
60
63
|
tones,
|
|
64
|
+
palette = NO_PALETTE,
|
|
61
65
|
className,
|
|
62
66
|
style,
|
|
63
67
|
children
|
|
@@ -67,9 +71,9 @@ function ThemeProvider({
|
|
|
67
71
|
const full = fullSelection(axes, selection);
|
|
68
72
|
const key = selectionKey(axes, full);
|
|
69
73
|
const value = useMemo(
|
|
70
|
-
() => ({ theme, selection: full, resolved: resolveTheme(theme, full), tones: tones ?? themeTones(theme) }),
|
|
74
|
+
() => ({ theme, selection: full, resolved: resolveTheme(theme, full), tones: tones ?? themeTones(theme), palette }),
|
|
71
75
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
-
[theme, key, tones]
|
|
76
|
+
[theme, key, tones, palette]
|
|
73
77
|
);
|
|
74
78
|
const release = useRef(null);
|
|
75
79
|
useLayoutEffect(() => {
|
|
@@ -95,10 +99,15 @@ function useTones() {
|
|
|
95
99
|
theme: weaselTheme,
|
|
96
100
|
selection: fullSelection(themeAxes(weaselTheme)),
|
|
97
101
|
resolved: resolveTheme(weaselTheme),
|
|
98
|
-
tones: themeTones(weaselTheme)
|
|
102
|
+
tones: themeTones(weaselTheme),
|
|
103
|
+
palette: NO_PALETTE
|
|
99
104
|
};
|
|
100
105
|
}
|
|
106
|
+
function useColorCss() {
|
|
107
|
+
const ctx = useTones();
|
|
108
|
+
return useCallback((source) => source == null ? void 0 : colorSourceCss(source, ctx) ?? void 0, [ctx]);
|
|
109
|
+
}
|
|
101
110
|
|
|
102
|
-
export { ThemeContext, ThemeProvider, useColorModePreference, useResolvedColorMode, useTheme, useThemeOptional, useTones };
|
|
111
|
+
export { ThemeContext, ThemeProvider, useColorCss, useColorModePreference, useResolvedColorMode, useTheme, useThemeOptional, useTones };
|
|
103
112
|
//# sourceMappingURL=react.js.map
|
|
104
113
|
//# sourceMappingURL=react.js.map
|
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 // 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/useColorMode.ts","../src/react.tsx"],"names":["useCallback"],"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 type { ColorSource, Palette } from '@weasel-js/paint';\nimport React, { createContext, useCallback, useContext, useMemo, useRef, useLayoutEffect } from 'react';\nimport { applyTheme } from './applyTheme';\nimport { themeTones, type ColorList } from './colorList';\nimport { colorSourceCss } from './colorSource';\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 and palette in force. */\nexport interface ThemeContextValue {\n readonly theme: Theme;\n readonly selection: Selection;\n readonly resolved: ResolvedTheme;\n readonly tones: ColorList;\n readonly palette: Palette;\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\nconst NO_PALETTE: Palette = { entries: [] };\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 /** Colors a `ColorRef` names in this subtree, answered before the theme's own names. Absent: none. */\n readonly palette?: Palette;\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 palette = NO_PALETTE,\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), palette }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [theme, key, tones, palette],\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 palette: NO_PALETTE,\n });\n}\n\n/**\n * Turns a `ColorSource` into a CSS color under the theme, tones, and palette in\n * force: `colorSourceCss` against `useTones()`. Every component that takes a\n * color writes it through this. `undefined` for no source, and for one nothing\n * answers.\n */\nexport function useColorCss(): (source: ColorSource | null | undefined) => string | undefined {\n const ctx = useTones();\n return useCallback((source) => (source == null ? undefined : (colorSourceCss(source, ctx) ?? undefined)), [ctx]);\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { a as Theme } from '../definition-CSeERbSL.js';
|
|
2
|
+
import '@weasel-js/paint';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What every classic Mac OS look shares, whatever its era: the system faces
|
|
6
|
+
* and their sizes, square windows and fields, centered window titles, and flat
|
|
7
|
+
* control faces. It names no color, so on its own it draws in the built-in
|
|
8
|
+
* theme's; an era's theme extends it with colors and edges.
|
|
9
|
+
*/
|
|
10
|
+
declare const classicMacTheme: Theme;
|
|
11
|
+
/**
|
|
12
|
+
* Mac OS 8 and 9's Platinum appearance: light gray faces with a black outline
|
|
13
|
+
* and a soft two-tone edge, white fields, and pinstriped window titles. The
|
|
14
|
+
* faces themselves are not bundled, so the stack falls through to what the
|
|
15
|
+
* machine has. Opens in light mode; the dark one is this theme's own invention.
|
|
16
|
+
*
|
|
17
|
+
* Pair it with `<DefaultMotif motif={motifs.titlebar()}>` from `@weasel-js/ui`
|
|
18
|
+
* to title every group as a window.
|
|
19
|
+
*/
|
|
20
|
+
declare const platinumTheme: Theme;
|
|
21
|
+
|
|
22
|
+
export { classicMacTheme, platinumTheme };
|