@pyreon/ui-core 0.13.1 → 0.14.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 +5 -1
- package/lib/index.d.ts +8 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +9 -2
- package/lib/index.js.map +1 -1
- package/package.json +7 -6
- package/src/__tests__/manifest-snapshot.test.ts +27 -0
- package/src/manifest.ts +104 -0
- package/src/utils.ts +10 -3
package/README.md
CHANGED
|
@@ -80,13 +80,17 @@ isEmpty({ a: 1 }) // => false
|
|
|
80
80
|
|
|
81
81
|
#### omit / pick
|
|
82
82
|
|
|
83
|
-
Create objects without or with only specified keys. Accept nullable inputs.
|
|
83
|
+
Create objects without or with only specified keys. Accept nullable inputs. `omit()` also accepts a pre-built `Set<string>` for hot paths where the same key list is reused across many calls (avoids per-call Set allocation).
|
|
84
84
|
|
|
85
85
|
```ts
|
|
86
86
|
import { omit, pick } from '@pyreon/ui-core'
|
|
87
87
|
|
|
88
88
|
omit({ a: 1, b: 2, c: 3 }, ['b']) // => { a: 1, c: 3 }
|
|
89
89
|
pick({ a: 1, b: 2, c: 3 }, ['a', 'b']) // => { a: 1, b: 2 }
|
|
90
|
+
|
|
91
|
+
// Hot-path usage with pre-built Set (used by rocketstyle):
|
|
92
|
+
const omitSet = new Set(['b', 'c'])
|
|
93
|
+
omit({ a: 1, b: 2, c: 3 }, omitSet) // => { a: 1 }
|
|
90
94
|
```
|
|
91
95
|
|
|
92
96
|
#### set / get
|
package/lib/index.d.ts
CHANGED
|
@@ -295,7 +295,14 @@ declare const render: Render;
|
|
|
295
295
|
declare const useStableValue: <T>(value: T) => T;
|
|
296
296
|
//#endregion
|
|
297
297
|
//#region src/utils.d.ts
|
|
298
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Returns a copy of `obj` without the specified keys.
|
|
300
|
+
*
|
|
301
|
+
* Accepts either an array of keys (builds a Set internally) or a
|
|
302
|
+
* pre-built `Set<string>` for hot paths where the same key list is
|
|
303
|
+
* reused across many calls (avoids per-call Set allocation).
|
|
304
|
+
*/
|
|
305
|
+
declare const omit: <T extends Record<string, any>>(obj: T | null | undefined, keys?: readonly (string | keyof T)[] | Set<string>) => Partial<T>;
|
|
299
306
|
declare const pick: <T extends Record<string, any>>(obj: T | null | undefined, keys?: readonly (string | keyof T)[]) => Partial<T>;
|
|
300
307
|
declare const get: (obj: any, path: string | string[], defaultValue?: any) => any;
|
|
301
308
|
declare const set: (obj: Record<string, any>, path: string | string[], value: any) => Record<string, any>;
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/compose.ts","../../src/html/htmlElementAttrs.ts","../../src/html/htmlTags.ts","../../src/html/index.ts","../../src/config.ts","../../src/types.ts","../../src/context.tsx","../../src/hoistNonReactStatics.ts","../../src/isEmpty.ts","../../src/isEqual.ts","../../src/PyreonUI.tsx","../../src/render.tsx","../../src/useStableValue.ts","../../src/utils.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/compose.ts","../../src/html/htmlElementAttrs.ts","../../src/html/htmlTags.ts","../../src/html/index.ts","../../src/config.ts","../../src/types.ts","../../src/context.tsx","../../src/hoistNonReactStatics.ts","../../src/isEmpty.ts","../../src/isEqual.ts","../../src/PyreonUI.tsx","../../src/render.tsx","../../src/useStableValue.ts","../../src/utils.ts"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -405,11 +405,18 @@ const useStableValue = (value) => {
|
|
|
405
405
|
|
|
406
406
|
//#endregion
|
|
407
407
|
//#region src/utils.ts
|
|
408
|
+
/**
|
|
409
|
+
* Returns a copy of `obj` without the specified keys.
|
|
410
|
+
*
|
|
411
|
+
* Accepts either an array of keys (builds a Set internally) or a
|
|
412
|
+
* pre-built `Set<string>` for hot paths where the same key list is
|
|
413
|
+
* reused across many calls (avoids per-call Set allocation).
|
|
414
|
+
*/
|
|
408
415
|
const omit = (obj, keys) => {
|
|
409
416
|
if (obj == null) return {};
|
|
410
|
-
if (!keys || keys.length === 0) return { ...obj };
|
|
417
|
+
if (!keys || (keys instanceof Set ? keys.size === 0 : keys.length === 0)) return { ...obj };
|
|
418
|
+
const keysSet = keys instanceof Set ? keys : new Set(keys);
|
|
411
419
|
const result = {};
|
|
412
|
-
const keysSet = new Set(keys);
|
|
413
420
|
for (const key in obj) if (Object.hasOwn(obj, key) && !keysSet.has(key)) result[key] = obj[key];
|
|
414
421
|
return result;
|
|
415
422
|
};
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["coreContext"],"sources":["../src/compose.ts","../src/config.ts","../src/isEmpty.ts","../src/context.tsx","../src/hoistNonReactStatics.ts","../src/html/htmlTags.ts","../src/isEqual.ts","../src/PyreonUI.tsx","../src/render.tsx","../src/useStableValue.ts","../src/utils.ts"],"sourcesContent":["type ArityOneFn = (arg: any) => any\ntype PickLastInTuple<T extends any[]> = T extends [...rest: infer _U, argn: infer L] ? L : any\ntype FirstFnParameterType<T extends any[]> = Parameters<PickLastInTuple<T>>[any]\ntype LastFnReturnType<T extends any[]> = ReturnType<T[0]>\n\nconst compose =\n <T extends ArityOneFn[]>(...fns: T) =>\n (p: FirstFnParameterType<T>): LastFnReturnType<T> =>\n fns.reduceRight((acc: any, cur: any) => cur(acc), p)\n\nexport default compose\n","import type { StyledFunction } from '@pyreon/styler'\nimport { css, keyframes, styled } from '@pyreon/styler'\nimport type { HTMLTags } from './html'\n\n/**\n * Describes the shape of the CSS-in-JS engine.\n * Pyreon uses @pyreon/styler directly — no connector abstraction needed.\n * This type is kept for API compatibility with downstream packages.\n */\nexport interface CSSEngineConnector {\n css: typeof css\n styled: typeof styled\n keyframes: typeof keyframes\n}\n\ninterface PlatformConfig {\n component: string | HTMLTags\n textComponent: string | HTMLTags\n createMediaQueries?: (props: {\n breakpoints: Record<string, number>\n rootSize: number\n css: CSSEngineConnector['css']\n }) => Record<string, (...args: any[]) => any>\n}\n\ntype InitConfig = Partial<CSSEngineConnector & PlatformConfig>\n\n/**\n * Configuration singleton that bridges the UI system with the CSS engine.\n * All packages reference config.css, config.styled, etc.\n *\n * In Pyreon, the engine is @pyreon/styler and is available immediately —\n * no lazy initialization or connector pattern needed.\n */\nclass Configuration {\n css = css\n styled: StyledFunction = styled\n keyframes = keyframes\n component: string | HTMLTags = 'div'\n textComponent: string | HTMLTags = 'span'\n createMediaQueries: PlatformConfig['createMediaQueries'] = undefined\n\n init = (props: InitConfig) => {\n if (props.css) this.css = props.css\n if (props.styled) this.styled = props.styled\n if (props.keyframes) this.keyframes = props.keyframes\n if (props.component) this.component = props.component\n if (props.textComponent) this.textComponent = props.textComponent\n if (props.createMediaQueries) this.createMediaQueries = props.createMediaQueries\n }\n}\n\nconst config = new Configuration()\nconst { init } = config\n\nexport default config\nexport { init }\n","export type IsEmpty = <T extends Record<number | string, any> | any[] | null | undefined>(\n param: T,\n) => T extends null | undefined\n ? true\n : keyof T extends never\n ? true\n : T extends T[]\n ? T[number] extends never\n ? true\n : false\n : false\n\nconst isEmpty = (<T extends Record<number | string, any> | any[] | null | undefined>(param: T) => {\n if (!param) return true\n if (typeof param !== 'object') return true\n if (Array.isArray(param)) return param.length === 0\n return Object.keys(param).length === 0\n}) as IsEmpty\n\nexport default isEmpty\n","import type { VNodeChild } from '@pyreon/core'\nimport { createReactiveContext, provide } from '@pyreon/core'\nimport isEmpty from './isEmpty'\nimport type { Breakpoints } from './types'\n\n/**\n * Core context value shared across all @pyreon UI packages.\n */\nexport interface CoreContextValue {\n theme: Record<string, unknown>\n mode: 'light' | 'dark'\n isDark: boolean\n isLight: boolean\n}\n\n/**\n * Internal reactive context shared across all @pyreon packages.\n * Carries the theme object, mode, and derived dark/light flags.\n *\n * ReactiveContext means useContext() returns `() => CoreContextValue`.\n */\nconst context = createReactiveContext<CoreContextValue>({\n theme: {},\n mode: 'light',\n isDark: false,\n isLight: true,\n})\n\ntype Theme = Partial<\n {\n rootSize: number\n breakpoints: Breakpoints\n } & Record<string, any>\n>\n\ntype ProviderType = Partial<\n {\n theme: Theme\n children: VNodeChild\n } & Record<string, any>\n>\n\n/**\n * @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.\n *\n * Provider that feeds the internal Pyreon context with the theme.\n * When no theme is supplied, renders children directly.\n *\n * @deprecated Prefer `<PyreonUI theme={theme}>` which handles all context layers.\n */\nconst __DEV__ = typeof process !== 'undefined' && process?.env?.NODE_ENV !== 'production'\n\nfunction Provider({ theme, children, ...props }: ProviderType): VNodeChild {\n if (__DEV__) {\n // oxlint-disable-next-line no-console\n console.warn(\n '[Pyreon] CoreProvider is internal. Use <PyreonUI theme={theme}> instead — it handles all context layers (styler, core, mode) in one component.',\n )\n }\n if (isEmpty(theme) || !theme) return children ?? null\n\n provide(context, () => ({\n theme: theme as Record<string, unknown>,\n mode: (props.mode as 'light' | 'dark') ?? 'light',\n isDark: props.isDark as boolean ?? false,\n isLight: props.isLight as boolean ?? true,\n ...props,\n }))\n\n return children ?? null\n}\n\nexport { context }\n\nexport default Provider\n","const KNOWN_STATICS: Record<string, true> = {\n name: true,\n length: true,\n prototype: true,\n caller: true,\n callee: true,\n arguments: true,\n arity: true,\n}\n\nconst COMPONENT_STATICS: Record<string, true> = {\n displayName: true,\n defaultProps: true,\n}\n\n/**\n * Copies non-framework static properties from a source component to a target.\n *\n * Pyreon equivalent of hoistNonReactStatics — simplified since Pyreon\n * components are plain functions without React-specific statics like\n * contextType, propTypes, getDerivedStateFromProps, etc.\n */\nconst hoistNonReactStatics = <T, S>(\n target: T,\n source: S,\n excludeList?: Record<string, true>,\n): T => {\n if (typeof source === 'string') return target\n\n const proto = Object.getPrototypeOf(source)\n if (proto && proto !== Object.prototype) {\n hoistNonReactStatics(target, proto, excludeList)\n }\n\n const keys: (string | symbol)[] = [\n ...Object.getOwnPropertyNames(source),\n ...Object.getOwnPropertySymbols(source),\n ]\n\n for (const key of keys) {\n const k = key as string\n if (KNOWN_STATICS[k] || excludeList?.[k] || COMPONENT_STATICS[k]) {\n continue\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(source, key)\n if (descriptor) {\n try {\n Object.defineProperty(target, key, descriptor)\n } catch {\n // Silently skip non-configurable properties\n }\n }\n }\n\n return target\n}\n\nexport default hoistNonReactStatics\n","const HTML_TAGS = [\n 'a',\n 'abbr',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'data',\n 'datalist',\n 'dd',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'embed',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'html',\n 'i',\n 'iframe',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'meter',\n 'nav',\n 'object',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'small',\n 'source',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'svg',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n] as const\n\nconst HTML_TEXT_TAGS = [\n 'abbr',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blockquote',\n 'cite',\n 'code',\n 'del',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'i',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'p',\n 'pre',\n 'q',\n 'rp',\n 'rt',\n 's',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'time',\n 'u',\n] as const\n\nexport type HTMLTags = (typeof HTML_TAGS)[number]\nexport type HTMLTextTags = (typeof HTML_TEXT_TAGS)[number]\nexport { HTML_TAGS, HTML_TEXT_TAGS }\n","const isArrayEqual = (a: unknown[], b: unknown[]): boolean => {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!isEqual(a[i], b[i])) return false\n }\n return true\n}\n\nconst isObjectEqual = (a: Record<string, unknown>, b: Record<string, unknown>): boolean => {\n const aKeys = Object.keys(a)\n if (aKeys.length !== Object.keys(b).length) return false\n for (const key of aKeys) {\n if (!Object.hasOwn(b, key)) return false\n if (!isEqual(a[key], b[key])) return false\n }\n return true\n}\n\nconst isEqual = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true\n if (typeof a !== typeof b || a == null || b == null || typeof a !== 'object') return false\n if (Array.isArray(a)) return Array.isArray(b) && isArrayEqual(a, b)\n if (Array.isArray(b)) return false\n return isObjectEqual(a as Record<string, unknown>, b as Record<string, unknown>)\n}\n\nexport default isEqual\n","import type { VNodeChild } from '@pyreon/core'\nimport { createReactiveContext, provide, useContext } from '@pyreon/core'\nimport { computed, signal } from '@pyreon/reactivity'\nimport { ThemeContext } from '@pyreon/styler'\nimport type { PyreonTheme } from '@pyreon/unistyle'\nimport { enrichTheme } from '@pyreon/unistyle'\nimport { context as coreContext } from './context'\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport type ThemeMode = 'light' | 'dark'\nexport type ThemeModeInput = ThemeMode | 'system'\n\nexport interface PyreonUIProps {\n /** Theme object with breakpoints, rootSize, and custom keys. */\n theme: PyreonTheme\n /**\n * Color mode: \"light\", \"dark\", or \"system\" (follows OS preference).\n * Can be a signal or getter for reactive mode switching.\n * @default \"light\"\n */\n mode?: ThemeModeInput | (() => ThemeModeInput) | undefined\n /** Flip mode for a nested section (e.g. dark sidebar in light app). */\n inversed?: boolean | undefined\n children?: VNodeChild\n}\n\n// ─── System mode detection ──────────────────────────────────────────────────\n\nconst _isBrowser = typeof window !== 'undefined' && typeof matchMedia === 'function'\n\n/** Reactive signal tracking the OS dark mode preference. Lazy-initialized on first use. */\nlet _systemMode: ReturnType<typeof signal<ThemeMode>> | undefined\n\nfunction getSystemMode(): ReturnType<typeof signal<ThemeMode>> {\n if (_systemMode) return _systemMode\n\n const prefersDark = _isBrowser && matchMedia('(prefers-color-scheme: dark)').matches\n _systemMode = signal<ThemeMode>(prefersDark ? 'dark' : 'light')\n\n if (_isBrowser) {\n matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\n _systemMode?.set(e.matches ? 'dark' : 'light')\n })\n }\n\n return _systemMode\n}\n\n// ─── Mode context ───────────────────────────────────────────────────────────\n\n/** Reactive context — useContext(ModeContext) returns () => ThemeMode. */\nconst ModeContext = createReactiveContext<ThemeMode>('light')\n\nconst INVERSED: Record<ThemeMode, ThemeMode> = { light: 'dark', dark: 'light' }\n\n/**\n * Read the resolved color mode (\"light\" | \"dark\") from the nearest PyreonUI.\n * Reactive — updates when the mode prop changes or when OS preference changes\n * (if mode=\"system\").\n *\n * @example\n * const mode = useMode() // \"light\" | \"dark\"\n */\nexport function useMode(): ThemeMode {\n return useContext(ModeContext)()\n}\n\n// ─── Auto-init ──────────────────────────────────────────────────────────────\n\nlet _autoInitDone = false\n\nfunction autoInit(): void {\n if (_autoInitDone) return\n _autoInitDone = true\n}\n\n// ─── PyreonUI ───────────────────────────────────────────────────────────────\n\n/**\n * Unified provider for the Pyreon UI system.\n *\n * Replaces the need for separate UnistyleProvider, RocketstyleProvider,\n * and ThemeProvider — one component, zero init.\n *\n * Mode can be a static string OR a signal/getter for reactive switching:\n * ```tsx\n * // Static\n * <PyreonUI theme={theme} mode=\"dark\">\n *\n * // Reactive signal\n * const mode = signal<ThemeModeInput>(\"light\")\n * <PyreonUI theme={theme} mode={mode}>\n *\n * // System (follows OS preference)\n * <PyreonUI theme={theme} mode=\"system\">\n * ```\n */\nexport function PyreonUI(props: PyreonUIProps): VNodeChild {\n autoInit()\n\n // IMPORTANT: do NOT destructure props. Components run once in Pyreon, and\n // destructuring captures values at setup time — losing reactivity. Reading\n // `props.mode` / `props.inversed` lazily inside `resolveMode()` lets the\n // computed re-evaluate when the underlying reactive props change (parent\n // re-renders with a different value, or signal-driven mode toggling).\n //\n // Previously this destructured `{ theme, mode = 'light', inversed, children }`\n // which made `inversed` permanently static — toggling inversed in a parent\n // had no effect because the local boolean was captured once. See\n // `.claude/rules/anti-patterns.md` \"Destructuring props\" entry.\n\n // Create a reactive mode getter that resolves \"system\" and applies inversion.\n // This getter is provided via context — consumers read it lazily in their\n // own reactive scopes, so mode changes propagate automatically.\n //\n // When `inversed` is set without an explicit `mode`, inherit the parent's\n // mode and flip it. This makes nested `<PyreonUI inversed>` work reactively:\n // outer light → inner dark, outer dark → inner light.\n //\n // useContext(ModeContext) returns the reactive accessor from the nearest\n // parent PyreonUI. At root level (no parent), the ReactiveContext default\n // returns 'light'. This read is TRACKED inside the computed below, so when\n // the parent's mode changes, this child's computed re-evaluates.\n const parentModeAccessor = useContext(ModeContext)\n const resolveMode = (): ThemeMode => {\n const mode = props.mode\n let resolved: ThemeMode\n if (mode === undefined || mode === null) {\n // No explicit mode — inherit from parent context\n resolved = parentModeAccessor()\n } else {\n const raw = typeof mode === 'function' ? mode() : mode\n resolved = raw === 'system' ? getSystemMode()() : raw\n }\n return props.inversed ? INVERSED[resolved] : resolved\n }\n\n // Wrap in computed for memoization\n const modeComputed = computed(resolveMode)\n\n // Enrich theme — wrapped in computed so user-preference theme swaps\n // propagate. The enrichment itself is cheap (builds a __PYREON__ block).\n const enrichedTheme = computed(() => enrichTheme(props.theme))\n\n // Provide to all three context layers:\n\n // 1. Styler ThemeContext — reactive accessor. DynamicStyled reads this\n // inside its computed() to re-resolve CSS on theme swap.\n provide(ThemeContext, () => enrichedTheme())\n\n // 2. Core context — provide a reactive getter function.\n // coreContext is a ReactiveContext, so provide(() => value).\n // Rocketstyle reads mode/isDark/isLight by calling the getter.\n provide(coreContext, () => ({\n theme: enrichedTheme(),\n mode: modeComputed(),\n isDark: modeComputed() === 'dark',\n isLight: modeComputed() === 'light',\n }))\n\n // 3. Mode context — getter function for useMode()\n provide(ModeContext, () => modeComputed())\n\n return props.children ?? null\n}\n","import type { ComponentFn, Props, VNodeChild } from '@pyreon/core'\nimport { h } from '@pyreon/core'\n\ntype RenderProps<T extends Record<string, unknown> | undefined> = (props: Partial<T>) => VNodeChild\n\n/**\n * Flexible element renderer that handles multiple content types:\n * - Primitives (string, number) — returned as-is\n * - Arrays — returned as-is\n * - Component functions — created via h()\n * - VNode objects — returned as-is (with props merged if provided)\n * - Render props (functions) — called with attachProps\n * - Falsy values — return null\n */\nexport type Render = <T extends Record<string, any> | undefined>(\n content?: ComponentFn | string | VNodeChild | VNodeChild[] | RenderProps<T>,\n attachProps?: T,\n) => VNodeChild\n\nconst render: Render = (content, attachProps) => {\n if (!content) return null\n\n const t = typeof content\n if (t === 'string' || t === 'number' || t === 'boolean' || t === 'bigint') {\n return content as VNodeChild\n }\n\n if (Array.isArray(content)) {\n return content as VNodeChild\n }\n\n if (typeof content === 'function') {\n // Extract key from props — it's a VNode concept, not a component prop.\n // Passing key inside props causes JSX runtime warnings.\n if (attachProps && 'key' in attachProps) {\n const { key, ...rest } = attachProps\n return h(content as string | ComponentFn, rest as Props)\n }\n return h(content as string | ComponentFn, (attachProps ?? {}) as Props)\n }\n\n // VNode object — return directly\n if (typeof content === 'object') {\n return content as VNodeChild\n }\n\n return content as VNodeChild\n}\n\nexport default render\n","import { signal } from '@pyreon/reactivity'\nimport isEqual from './isEqual'\n\n/**\n * Returns a referentially stable version of `value`. The returned reference\n * only changes when the value is no longer deeply equal to the previous one.\n *\n * Pyreon equivalent of the React useStableValue hook — uses a signal\n * internally to hold the stable reference.\n */\nconst useStableValue = <T>(value: T): T => {\n const ref = signal(value)\n\n if (!isEqual(ref.peek(), value)) {\n ref.set(value)\n }\n\n return ref.peek()\n}\n\nexport default useStableValue\n","export const omit = <T extends Record<string, any>>(\n obj: T | null | undefined,\n keys?: readonly (string | keyof T)[],\n): Partial<T> => {\n if (obj == null) return {} as Partial<T>\n if (!keys || keys.length === 0) return { ...obj }\n const result: Record<string, any> = {}\n const keysSet = new Set(keys as readonly string[])\n for (const key in obj) {\n if (Object.hasOwn(obj, key) && !keysSet.has(key)) {\n result[key] = obj[key]\n }\n }\n return result as Partial<T>\n}\n\nexport const pick = <T extends Record<string, any>>(\n obj: T | null | undefined,\n keys?: readonly (string | keyof T)[],\n): Partial<T> => {\n if (obj == null) return {} as Partial<T>\n if (!keys || keys.length === 0) return { ...obj }\n const result: Record<string, any> = {}\n for (const key of keys) {\n const k = key as string\n if (Object.hasOwn(obj, k)) {\n result[k] = obj[k]\n }\n }\n return result as Partial<T>\n}\n\nconst PATH_RE = /[^.[\\]]+/g\n\nconst parsePath = (path: string | string[]): string[] => {\n if (Array.isArray(path)) return path\n const parts = path.match(PATH_RE)\n return parts ?? []\n}\n\nconst isUnsafeKey = (key: string): boolean =>\n key === '__proto__' || key === 'prototype' || key === 'constructor'\n\nexport const get = (obj: any, path: string | string[], defaultValue?: any): any => {\n const keys = parsePath(path)\n let result = obj\n for (const key of keys) {\n if (result == null || isUnsafeKey(key)) return defaultValue\n result = result[key]\n }\n return result === undefined ? defaultValue : result\n}\n\nexport const set = (\n obj: Record<string, any>,\n path: string | string[],\n value: any,\n): Record<string, any> => {\n const keys = parsePath(path)\n let current = obj\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i] as string\n if (isUnsafeKey(key)) return obj\n const nextKey = keys[i + 1] as string\n if (isUnsafeKey(nextKey)) return obj\n if (current[key] == null) {\n current[key] = /^\\d+$/.test(nextKey) ? [] : {}\n }\n current = current[key]\n }\n const lastKey = keys[keys.length - 1]\n if (lastKey != null && !isUnsafeKey(lastKey)) {\n current[lastKey] = value\n }\n return obj\n}\n\nexport const throttle = <T extends (...args: any[]) => any>(\n fn: T,\n wait: number = 0,\n options?: { leading?: boolean; trailing?: boolean },\n): T & { cancel: () => void } => {\n const leading = options?.leading !== false\n const trailing = options?.trailing !== false\n let lastCallTime: number | undefined\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n let lastArgs: any[] | undefined\n\n const invoke = (args: any[]) => {\n lastCallTime = Date.now()\n fn(...args)\n }\n\n const startTrailingTimer = (args: any[], delay: number) => {\n lastArgs = args\n if (timeoutId !== undefined) return\n timeoutId = setTimeout(() => {\n timeoutId = undefined\n if (lastArgs) {\n invoke(lastArgs)\n lastArgs = undefined\n }\n }, delay)\n }\n\n const throttled = (...args: any[]) => {\n const now = Date.now()\n const elapsed = lastCallTime === undefined ? wait : now - lastCallTime\n if (elapsed >= wait) {\n if (leading) {\n invoke(args)\n } else {\n lastCallTime = now\n if (trailing) startTrailingTimer(args, wait)\n }\n } else if (trailing) {\n startTrailingTimer(args, wait - elapsed)\n }\n }\n\n throttled.cancel = () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId)\n timeoutId = undefined\n }\n lastArgs = undefined\n lastCallTime = undefined\n }\n\n return throttled as T & { cancel: () => void }\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, any> =>\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) === Object.prototype\n\nexport const merge = <T extends Record<string, any>>(\n target: T,\n ...sources: Record<string, any>[]\n): T => {\n for (const source of sources) {\n if (source == null) continue\n for (const key of Object.keys(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue\n const targetVal = (target as Record<string, unknown>)[key]\n const sourceVal = source[key]\n if (isPlainObject(targetVal) && isPlainObject(sourceVal)) {\n ;(target as Record<string, unknown>)[key] = merge({ ...targetVal }, sourceVal)\n } else {\n ;(target as Record<string, unknown>)[key] = sourceVal\n }\n }\n }\n return target\n}\n"],"mappings":";;;;;;AAKA,MAAM,WACqB,GAAG,SAC3B,MACC,IAAI,aAAa,KAAU,QAAa,IAAI,IAAI,EAAE,EAAE;;;;;;;;;;;AC0BxD,IAAM,gBAAN,MAAoB;CAClB,MAAM;CACN,SAAyB;CACzB,YAAY;CACZ,YAA+B;CAC/B,gBAAmC;CACnC,qBAA2D;CAE3D,QAAQ,UAAsB;AAC5B,MAAI,MAAM,IAAK,MAAK,MAAM,MAAM;AAChC,MAAI,MAAM,OAAQ,MAAK,SAAS,MAAM;AACtC,MAAI,MAAM,UAAW,MAAK,YAAY,MAAM;AAC5C,MAAI,MAAM,UAAW,MAAK,YAAY,MAAM;AAC5C,MAAI,MAAM,cAAe,MAAK,gBAAgB,MAAM;AACpD,MAAI,MAAM,mBAAoB,MAAK,qBAAqB,MAAM;;;AAIlE,MAAM,SAAS,IAAI,eAAe;AAClC,MAAM,EAAE,SAAS;;;;ACzCjB,MAAM,YAA+E,UAAa;AAChG,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,WAAW;AAClD,QAAO,OAAO,KAAK,MAAM,CAAC,WAAW;;;;;;;;;;;ACKvC,MAAM,UAAU,sBAAwC;CACtD,OAAO,EAAE;CACT,MAAM;CACN,QAAQ;CACR,SAAS;CACV,CAAC;;;;;;;;;AAwBF,MAAM,UAAU,OAAO,YAAY,eAAe,SAAS,KAAK,aAAa;AAE7E,SAAS,SAAS,EAAE,OAAO,UAAU,GAAG,SAAmC;AACzE,KAAI,QAEF,SAAQ,KACN,iJACD;AAEH,KAAI,QAAQ,MAAM,IAAI,CAAC,MAAO,QAAO,YAAY;AAEjD,SAAQ,gBAAgB;EACf;EACP,MAAO,MAAM,QAA6B;EAC1C,QAAQ,MAAM,UAAqB;EACnC,SAAS,MAAM,WAAsB;EACrC,GAAG;EACJ,EAAE;AAEH,QAAO,YAAY;;;;;ACrErB,MAAM,gBAAsC;CAC1C,MAAM;CACN,QAAQ;CACR,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,OAAO;CACR;AAED,MAAM,oBAA0C;CAC9C,aAAa;CACb,cAAc;CACf;;;;;;;;AASD,MAAM,wBACJ,QACA,QACA,gBACM;AACN,KAAI,OAAO,WAAW,SAAU,QAAO;CAEvC,MAAM,QAAQ,OAAO,eAAe,OAAO;AAC3C,KAAI,SAAS,UAAU,OAAO,UAC5B,sBAAqB,QAAQ,OAAO,YAAY;CAGlD,MAAM,OAA4B,CAChC,GAAG,OAAO,oBAAoB,OAAO,EACrC,GAAG,OAAO,sBAAsB,OAAO,CACxC;AAED,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,IAAI;AACV,MAAI,cAAc,MAAM,cAAc,MAAM,kBAAkB,GAC5D;EAGF,MAAM,aAAa,OAAO,yBAAyB,QAAQ,IAAI;AAC/D,MAAI,WACF,KAAI;AACF,UAAO,eAAe,QAAQ,KAAK,WAAW;UACxC;;AAMZ,QAAO;;;;;ACvDT,MAAM,YAAY;CAChB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;AClJD,MAAM,gBAAgB,GAAc,MAA0B;AAC5D,KAAI,EAAE,WAAW,EAA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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["coreContext"],"sources":["../src/compose.ts","../src/config.ts","../src/isEmpty.ts","../src/context.tsx","../src/hoistNonReactStatics.ts","../src/html/htmlTags.ts","../src/isEqual.ts","../src/PyreonUI.tsx","../src/render.tsx","../src/useStableValue.ts","../src/utils.ts"],"sourcesContent":["type ArityOneFn = (arg: any) => any\ntype PickLastInTuple<T extends any[]> = T extends [...rest: infer _U, argn: infer L] ? L : any\ntype FirstFnParameterType<T extends any[]> = Parameters<PickLastInTuple<T>>[any]\ntype LastFnReturnType<T extends any[]> = ReturnType<T[0]>\n\nconst compose =\n <T extends ArityOneFn[]>(...fns: T) =>\n (p: FirstFnParameterType<T>): LastFnReturnType<T> =>\n fns.reduceRight((acc: any, cur: any) => cur(acc), p)\n\nexport default compose\n","import type { StyledFunction } from '@pyreon/styler'\nimport { css, keyframes, styled } from '@pyreon/styler'\nimport type { HTMLTags } from './html'\n\n/**\n * Describes the shape of the CSS-in-JS engine.\n * Pyreon uses @pyreon/styler directly — no connector abstraction needed.\n * This type is kept for API compatibility with downstream packages.\n */\nexport interface CSSEngineConnector {\n css: typeof css\n styled: typeof styled\n keyframes: typeof keyframes\n}\n\ninterface PlatformConfig {\n component: string | HTMLTags\n textComponent: string | HTMLTags\n createMediaQueries?: (props: {\n breakpoints: Record<string, number>\n rootSize: number\n css: CSSEngineConnector['css']\n }) => Record<string, (...args: any[]) => any>\n}\n\ntype InitConfig = Partial<CSSEngineConnector & PlatformConfig>\n\n/**\n * Configuration singleton that bridges the UI system with the CSS engine.\n * All packages reference config.css, config.styled, etc.\n *\n * In Pyreon, the engine is @pyreon/styler and is available immediately —\n * no lazy initialization or connector pattern needed.\n */\nclass Configuration {\n css = css\n styled: StyledFunction = styled\n keyframes = keyframes\n component: string | HTMLTags = 'div'\n textComponent: string | HTMLTags = 'span'\n createMediaQueries: PlatformConfig['createMediaQueries'] = undefined\n\n init = (props: InitConfig) => {\n if (props.css) this.css = props.css\n if (props.styled) this.styled = props.styled\n if (props.keyframes) this.keyframes = props.keyframes\n if (props.component) this.component = props.component\n if (props.textComponent) this.textComponent = props.textComponent\n if (props.createMediaQueries) this.createMediaQueries = props.createMediaQueries\n }\n}\n\nconst config = new Configuration()\nconst { init } = config\n\nexport default config\nexport { init }\n","export type IsEmpty = <T extends Record<number | string, any> | any[] | null | undefined>(\n param: T,\n) => T extends null | undefined\n ? true\n : keyof T extends never\n ? true\n : T extends T[]\n ? T[number] extends never\n ? true\n : false\n : false\n\nconst isEmpty = (<T extends Record<number | string, any> | any[] | null | undefined>(param: T) => {\n if (!param) return true\n if (typeof param !== 'object') return true\n if (Array.isArray(param)) return param.length === 0\n return Object.keys(param).length === 0\n}) as IsEmpty\n\nexport default isEmpty\n","import type { VNodeChild } from '@pyreon/core'\nimport { createReactiveContext, provide } from '@pyreon/core'\nimport isEmpty from './isEmpty'\nimport type { Breakpoints } from './types'\n\n/**\n * Core context value shared across all @pyreon UI packages.\n */\nexport interface CoreContextValue {\n theme: Record<string, unknown>\n mode: 'light' | 'dark'\n isDark: boolean\n isLight: boolean\n}\n\n/**\n * Internal reactive context shared across all @pyreon packages.\n * Carries the theme object, mode, and derived dark/light flags.\n *\n * ReactiveContext means useContext() returns `() => CoreContextValue`.\n */\nconst context = createReactiveContext<CoreContextValue>({\n theme: {},\n mode: 'light',\n isDark: false,\n isLight: true,\n})\n\ntype Theme = Partial<\n {\n rootSize: number\n breakpoints: Breakpoints\n } & Record<string, any>\n>\n\ntype ProviderType = Partial<\n {\n theme: Theme\n children: VNodeChild\n } & Record<string, any>\n>\n\n/**\n * @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.\n *\n * Provider that feeds the internal Pyreon context with the theme.\n * When no theme is supplied, renders children directly.\n *\n * @deprecated Prefer `<PyreonUI theme={theme}>` which handles all context layers.\n */\nconst __DEV__ = typeof process !== 'undefined' && process?.env?.NODE_ENV !== 'production'\n\nfunction Provider({ theme, children, ...props }: ProviderType): VNodeChild {\n if (__DEV__) {\n // oxlint-disable-next-line no-console\n console.warn(\n '[Pyreon] CoreProvider is internal. Use <PyreonUI theme={theme}> instead — it handles all context layers (styler, core, mode) in one component.',\n )\n }\n if (isEmpty(theme) || !theme) return children ?? null\n\n provide(context, () => ({\n theme: theme as Record<string, unknown>,\n mode: (props.mode as 'light' | 'dark') ?? 'light',\n isDark: props.isDark as boolean ?? false,\n isLight: props.isLight as boolean ?? true,\n ...props,\n }))\n\n return children ?? null\n}\n\nexport { context }\n\nexport default Provider\n","const KNOWN_STATICS: Record<string, true> = {\n name: true,\n length: true,\n prototype: true,\n caller: true,\n callee: true,\n arguments: true,\n arity: true,\n}\n\nconst COMPONENT_STATICS: Record<string, true> = {\n displayName: true,\n defaultProps: true,\n}\n\n/**\n * Copies non-framework static properties from a source component to a target.\n *\n * Pyreon equivalent of hoistNonReactStatics — simplified since Pyreon\n * components are plain functions without React-specific statics like\n * contextType, propTypes, getDerivedStateFromProps, etc.\n */\nconst hoistNonReactStatics = <T, S>(\n target: T,\n source: S,\n excludeList?: Record<string, true>,\n): T => {\n if (typeof source === 'string') return target\n\n const proto = Object.getPrototypeOf(source)\n if (proto && proto !== Object.prototype) {\n hoistNonReactStatics(target, proto, excludeList)\n }\n\n const keys: (string | symbol)[] = [\n ...Object.getOwnPropertyNames(source),\n ...Object.getOwnPropertySymbols(source),\n ]\n\n for (const key of keys) {\n const k = key as string\n if (KNOWN_STATICS[k] || excludeList?.[k] || COMPONENT_STATICS[k]) {\n continue\n }\n\n const descriptor = Object.getOwnPropertyDescriptor(source, key)\n if (descriptor) {\n try {\n Object.defineProperty(target, key, descriptor)\n } catch {\n // Silently skip non-configurable properties\n }\n }\n }\n\n return target\n}\n\nexport default hoistNonReactStatics\n","const HTML_TAGS = [\n 'a',\n 'abbr',\n 'address',\n 'area',\n 'article',\n 'aside',\n 'audio',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blockquote',\n 'body',\n 'br',\n 'button',\n 'canvas',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'data',\n 'datalist',\n 'dd',\n 'del',\n 'details',\n 'dfn',\n 'dialog',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'embed',\n 'fieldset',\n 'figcaption',\n 'figure',\n 'footer',\n 'form',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'header',\n 'hr',\n 'html',\n 'i',\n 'iframe',\n 'img',\n 'input',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'main',\n 'map',\n 'mark',\n 'meter',\n 'nav',\n 'object',\n 'ol',\n 'optgroup',\n 'option',\n 'output',\n 'p',\n 'picture',\n 'pre',\n 'progress',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'section',\n 'select',\n 'small',\n 'source',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'svg',\n 'table',\n 'tbody',\n 'td',\n 'template',\n 'textarea',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'track',\n 'u',\n 'ul',\n 'var',\n 'video',\n 'wbr',\n] as const\n\nconst HTML_TEXT_TAGS = [\n 'abbr',\n 'b',\n 'bdi',\n 'bdo',\n 'big',\n 'blockquote',\n 'cite',\n 'code',\n 'del',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'i',\n 'ins',\n 'kbd',\n 'label',\n 'legend',\n 'li',\n 'p',\n 'pre',\n 'q',\n 'rp',\n 'rt',\n 's',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'time',\n 'u',\n] as const\n\nexport type HTMLTags = (typeof HTML_TAGS)[number]\nexport type HTMLTextTags = (typeof HTML_TEXT_TAGS)[number]\nexport { HTML_TAGS, HTML_TEXT_TAGS }\n","const isArrayEqual = (a: unknown[], b: unknown[]): boolean => {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i++) {\n if (!isEqual(a[i], b[i])) return false\n }\n return true\n}\n\nconst isObjectEqual = (a: Record<string, unknown>, b: Record<string, unknown>): boolean => {\n const aKeys = Object.keys(a)\n if (aKeys.length !== Object.keys(b).length) return false\n for (const key of aKeys) {\n if (!Object.hasOwn(b, key)) return false\n if (!isEqual(a[key], b[key])) return false\n }\n return true\n}\n\nconst isEqual = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true\n if (typeof a !== typeof b || a == null || b == null || typeof a !== 'object') return false\n if (Array.isArray(a)) return Array.isArray(b) && isArrayEqual(a, b)\n if (Array.isArray(b)) return false\n return isObjectEqual(a as Record<string, unknown>, b as Record<string, unknown>)\n}\n\nexport default isEqual\n","import type { VNodeChild } from '@pyreon/core'\nimport { createReactiveContext, provide, useContext } from '@pyreon/core'\nimport { computed, signal } from '@pyreon/reactivity'\nimport { ThemeContext } from '@pyreon/styler'\nimport type { PyreonTheme } from '@pyreon/unistyle'\nimport { enrichTheme } from '@pyreon/unistyle'\nimport { context as coreContext } from './context'\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport type ThemeMode = 'light' | 'dark'\nexport type ThemeModeInput = ThemeMode | 'system'\n\nexport interface PyreonUIProps {\n /** Theme object with breakpoints, rootSize, and custom keys. */\n theme: PyreonTheme\n /**\n * Color mode: \"light\", \"dark\", or \"system\" (follows OS preference).\n * Can be a signal or getter for reactive mode switching.\n * @default \"light\"\n */\n mode?: ThemeModeInput | (() => ThemeModeInput) | undefined\n /** Flip mode for a nested section (e.g. dark sidebar in light app). */\n inversed?: boolean | undefined\n children?: VNodeChild\n}\n\n// ─── System mode detection ──────────────────────────────────────────────────\n\nconst _isBrowser = typeof window !== 'undefined' && typeof matchMedia === 'function'\n\n/** Reactive signal tracking the OS dark mode preference. Lazy-initialized on first use. */\nlet _systemMode: ReturnType<typeof signal<ThemeMode>> | undefined\n\nfunction getSystemMode(): ReturnType<typeof signal<ThemeMode>> {\n if (_systemMode) return _systemMode\n\n const prefersDark = _isBrowser && matchMedia('(prefers-color-scheme: dark)').matches\n _systemMode = signal<ThemeMode>(prefersDark ? 'dark' : 'light')\n\n if (_isBrowser) {\n matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {\n _systemMode?.set(e.matches ? 'dark' : 'light')\n })\n }\n\n return _systemMode\n}\n\n// ─── Mode context ───────────────────────────────────────────────────────────\n\n/** Reactive context — useContext(ModeContext) returns () => ThemeMode. */\nconst ModeContext = createReactiveContext<ThemeMode>('light')\n\nconst INVERSED: Record<ThemeMode, ThemeMode> = { light: 'dark', dark: 'light' }\n\n/**\n * Read the resolved color mode (\"light\" | \"dark\") from the nearest PyreonUI.\n * Reactive — updates when the mode prop changes or when OS preference changes\n * (if mode=\"system\").\n *\n * @example\n * const mode = useMode() // \"light\" | \"dark\"\n */\nexport function useMode(): ThemeMode {\n return useContext(ModeContext)()\n}\n\n// ─── Auto-init ──────────────────────────────────────────────────────────────\n\nlet _autoInitDone = false\n\nfunction autoInit(): void {\n if (_autoInitDone) return\n _autoInitDone = true\n}\n\n// ─── PyreonUI ───────────────────────────────────────────────────────────────\n\n/**\n * Unified provider for the Pyreon UI system.\n *\n * Replaces the need for separate UnistyleProvider, RocketstyleProvider,\n * and ThemeProvider — one component, zero init.\n *\n * Mode can be a static string OR a signal/getter for reactive switching:\n * ```tsx\n * // Static\n * <PyreonUI theme={theme} mode=\"dark\">\n *\n * // Reactive signal\n * const mode = signal<ThemeModeInput>(\"light\")\n * <PyreonUI theme={theme} mode={mode}>\n *\n * // System (follows OS preference)\n * <PyreonUI theme={theme} mode=\"system\">\n * ```\n */\nexport function PyreonUI(props: PyreonUIProps): VNodeChild {\n autoInit()\n\n // IMPORTANT: do NOT destructure props. Components run once in Pyreon, and\n // destructuring captures values at setup time — losing reactivity. Reading\n // `props.mode` / `props.inversed` lazily inside `resolveMode()` lets the\n // computed re-evaluate when the underlying reactive props change (parent\n // re-renders with a different value, or signal-driven mode toggling).\n //\n // Previously this destructured `{ theme, mode = 'light', inversed, children }`\n // which made `inversed` permanently static — toggling inversed in a parent\n // had no effect because the local boolean was captured once. See\n // `.claude/rules/anti-patterns.md` \"Destructuring props\" entry.\n\n // Create a reactive mode getter that resolves \"system\" and applies inversion.\n // This getter is provided via context — consumers read it lazily in their\n // own reactive scopes, so mode changes propagate automatically.\n //\n // When `inversed` is set without an explicit `mode`, inherit the parent's\n // mode and flip it. This makes nested `<PyreonUI inversed>` work reactively:\n // outer light → inner dark, outer dark → inner light.\n //\n // useContext(ModeContext) returns the reactive accessor from the nearest\n // parent PyreonUI. At root level (no parent), the ReactiveContext default\n // returns 'light'. This read is TRACKED inside the computed below, so when\n // the parent's mode changes, this child's computed re-evaluates.\n const parentModeAccessor = useContext(ModeContext)\n const resolveMode = (): ThemeMode => {\n const mode = props.mode\n let resolved: ThemeMode\n if (mode === undefined || mode === null) {\n // No explicit mode — inherit from parent context\n resolved = parentModeAccessor()\n } else {\n const raw = typeof mode === 'function' ? mode() : mode\n resolved = raw === 'system' ? getSystemMode()() : raw\n }\n return props.inversed ? INVERSED[resolved] : resolved\n }\n\n // Wrap in computed for memoization\n const modeComputed = computed(resolveMode)\n\n // Enrich theme — wrapped in computed so user-preference theme swaps\n // propagate. The enrichment itself is cheap (builds a __PYREON__ block).\n const enrichedTheme = computed(() => enrichTheme(props.theme))\n\n // Provide to all three context layers:\n\n // 1. Styler ThemeContext — reactive accessor. DynamicStyled reads this\n // inside its computed() to re-resolve CSS on theme swap.\n provide(ThemeContext, () => enrichedTheme())\n\n // 2. Core context — provide a reactive getter function.\n // coreContext is a ReactiveContext, so provide(() => value).\n // Rocketstyle reads mode/isDark/isLight by calling the getter.\n provide(coreContext, () => ({\n theme: enrichedTheme(),\n mode: modeComputed(),\n isDark: modeComputed() === 'dark',\n isLight: modeComputed() === 'light',\n }))\n\n // 3. Mode context — getter function for useMode()\n provide(ModeContext, () => modeComputed())\n\n return props.children ?? null\n}\n","import type { ComponentFn, Props, VNodeChild } from '@pyreon/core'\nimport { h } from '@pyreon/core'\n\ntype RenderProps<T extends Record<string, unknown> | undefined> = (props: Partial<T>) => VNodeChild\n\n/**\n * Flexible element renderer that handles multiple content types:\n * - Primitives (string, number) — returned as-is\n * - Arrays — returned as-is\n * - Component functions — created via h()\n * - VNode objects — returned as-is (with props merged if provided)\n * - Render props (functions) — called with attachProps\n * - Falsy values — return null\n */\nexport type Render = <T extends Record<string, any> | undefined>(\n content?: ComponentFn | string | VNodeChild | VNodeChild[] | RenderProps<T>,\n attachProps?: T,\n) => VNodeChild\n\nconst render: Render = (content, attachProps) => {\n if (!content) return null\n\n const t = typeof content\n if (t === 'string' || t === 'number' || t === 'boolean' || t === 'bigint') {\n return content as VNodeChild\n }\n\n if (Array.isArray(content)) {\n return content as VNodeChild\n }\n\n if (typeof content === 'function') {\n // Extract key from props — it's a VNode concept, not a component prop.\n // Passing key inside props causes JSX runtime warnings.\n if (attachProps && 'key' in attachProps) {\n const { key, ...rest } = attachProps\n return h(content as string | ComponentFn, rest as Props)\n }\n return h(content as string | ComponentFn, (attachProps ?? {}) as Props)\n }\n\n // VNode object — return directly\n if (typeof content === 'object') {\n return content as VNodeChild\n }\n\n return content as VNodeChild\n}\n\nexport default render\n","import { signal } from '@pyreon/reactivity'\nimport isEqual from './isEqual'\n\n/**\n * Returns a referentially stable version of `value`. The returned reference\n * only changes when the value is no longer deeply equal to the previous one.\n *\n * Pyreon equivalent of the React useStableValue hook — uses a signal\n * internally to hold the stable reference.\n */\nconst useStableValue = <T>(value: T): T => {\n const ref = signal(value)\n\n if (!isEqual(ref.peek(), value)) {\n ref.set(value)\n }\n\n return ref.peek()\n}\n\nexport default useStableValue\n","/**\n * Returns a copy of `obj` without the specified keys.\n *\n * Accepts either an array of keys (builds a Set internally) or a\n * pre-built `Set<string>` for hot paths where the same key list is\n * reused across many calls (avoids per-call Set allocation).\n */\nexport const omit = <T extends Record<string, any>>(\n obj: T | null | undefined,\n keys?: readonly (string | keyof T)[] | Set<string>,\n): Partial<T> => {\n if (obj == null) return {} as Partial<T>\n if (!keys || (keys instanceof Set ? keys.size === 0 : keys.length === 0)) return { ...obj }\n const keysSet = keys instanceof Set ? keys : new Set(keys as readonly string[])\n const result: Record<string, any> = {}\n for (const key in obj) {\n if (Object.hasOwn(obj, key) && !keysSet.has(key)) {\n result[key] = obj[key]\n }\n }\n return result as Partial<T>\n}\n\nexport const pick = <T extends Record<string, any>>(\n obj: T | null | undefined,\n keys?: readonly (string | keyof T)[],\n): Partial<T> => {\n if (obj == null) return {} as Partial<T>\n if (!keys || keys.length === 0) return { ...obj }\n const result: Record<string, any> = {}\n for (const key of keys) {\n const k = key as string\n if (Object.hasOwn(obj, k)) {\n result[k] = obj[k]\n }\n }\n return result as Partial<T>\n}\n\nconst PATH_RE = /[^.[\\]]+/g\n\nconst parsePath = (path: string | string[]): string[] => {\n if (Array.isArray(path)) return path\n const parts = path.match(PATH_RE)\n return parts ?? []\n}\n\nconst isUnsafeKey = (key: string): boolean =>\n key === '__proto__' || key === 'prototype' || key === 'constructor'\n\nexport const get = (obj: any, path: string | string[], defaultValue?: any): any => {\n const keys = parsePath(path)\n let result = obj\n for (const key of keys) {\n if (result == null || isUnsafeKey(key)) return defaultValue\n result = result[key]\n }\n return result === undefined ? defaultValue : result\n}\n\nexport const set = (\n obj: Record<string, any>,\n path: string | string[],\n value: any,\n): Record<string, any> => {\n const keys = parsePath(path)\n let current = obj\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i] as string\n if (isUnsafeKey(key)) return obj\n const nextKey = keys[i + 1] as string\n if (isUnsafeKey(nextKey)) return obj\n if (current[key] == null) {\n current[key] = /^\\d+$/.test(nextKey) ? [] : {}\n }\n current = current[key]\n }\n const lastKey = keys[keys.length - 1]\n if (lastKey != null && !isUnsafeKey(lastKey)) {\n current[lastKey] = value\n }\n return obj\n}\n\nexport const throttle = <T extends (...args: any[]) => any>(\n fn: T,\n wait: number = 0,\n options?: { leading?: boolean; trailing?: boolean },\n): T & { cancel: () => void } => {\n const leading = options?.leading !== false\n const trailing = options?.trailing !== false\n let lastCallTime: number | undefined\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n let lastArgs: any[] | undefined\n\n const invoke = (args: any[]) => {\n lastCallTime = Date.now()\n fn(...args)\n }\n\n const startTrailingTimer = (args: any[], delay: number) => {\n lastArgs = args\n if (timeoutId !== undefined) return\n timeoutId = setTimeout(() => {\n timeoutId = undefined\n if (lastArgs) {\n invoke(lastArgs)\n lastArgs = undefined\n }\n }, delay)\n }\n\n const throttled = (...args: any[]) => {\n const now = Date.now()\n const elapsed = lastCallTime === undefined ? wait : now - lastCallTime\n if (elapsed >= wait) {\n if (leading) {\n invoke(args)\n } else {\n lastCallTime = now\n if (trailing) startTrailingTimer(args, wait)\n }\n } else if (trailing) {\n startTrailingTimer(args, wait - elapsed)\n }\n }\n\n throttled.cancel = () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId)\n timeoutId = undefined\n }\n lastArgs = undefined\n lastCallTime = undefined\n }\n\n return throttled as T & { cancel: () => void }\n}\n\nconst isPlainObject = (value: unknown): value is Record<string, any> =>\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) === Object.prototype\n\nexport const merge = <T extends Record<string, any>>(\n target: T,\n ...sources: Record<string, any>[]\n): T => {\n for (const source of sources) {\n if (source == null) continue\n for (const key of Object.keys(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue\n const targetVal = (target as Record<string, unknown>)[key]\n const sourceVal = source[key]\n if (isPlainObject(targetVal) && isPlainObject(sourceVal)) {\n ;(target as Record<string, unknown>)[key] = merge({ ...targetVal }, sourceVal)\n } else {\n ;(target as Record<string, unknown>)[key] = sourceVal\n }\n }\n }\n return target\n}\n"],"mappings":";;;;;;AAKA,MAAM,WACqB,GAAG,SAC3B,MACC,IAAI,aAAa,KAAU,QAAa,IAAI,IAAI,EAAE,EAAE;;;;;;;;;;;AC0BxD,IAAM,gBAAN,MAAoB;CAClB,MAAM;CACN,SAAyB;CACzB,YAAY;CACZ,YAA+B;CAC/B,gBAAmC;CACnC,qBAA2D;CAE3D,QAAQ,UAAsB;AAC5B,MAAI,MAAM,IAAK,MAAK,MAAM,MAAM;AAChC,MAAI,MAAM,OAAQ,MAAK,SAAS,MAAM;AACtC,MAAI,MAAM,UAAW,MAAK,YAAY,MAAM;AAC5C,MAAI,MAAM,UAAW,MAAK,YAAY,MAAM;AAC5C,MAAI,MAAM,cAAe,MAAK,gBAAgB,MAAM;AACpD,MAAI,MAAM,mBAAoB,MAAK,qBAAqB,MAAM;;;AAIlE,MAAM,SAAS,IAAI,eAAe;AAClC,MAAM,EAAE,SAAS;;;;ACzCjB,MAAM,YAA+E,UAAa;AAChG,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,WAAW;AAClD,QAAO,OAAO,KAAK,MAAM,CAAC,WAAW;;;;;;;;;;;ACKvC,MAAM,UAAU,sBAAwC;CACtD,OAAO,EAAE;CACT,MAAM;CACN,QAAQ;CACR,SAAS;CACV,CAAC;;;;;;;;;AAwBF,MAAM,UAAU,OAAO,YAAY,eAAe,SAAS,KAAK,aAAa;AAE7E,SAAS,SAAS,EAAE,OAAO,UAAU,GAAG,SAAmC;AACzE,KAAI,QAEF,SAAQ,KACN,iJACD;AAEH,KAAI,QAAQ,MAAM,IAAI,CAAC,MAAO,QAAO,YAAY;AAEjD,SAAQ,gBAAgB;EACf;EACP,MAAO,MAAM,QAA6B;EAC1C,QAAQ,MAAM,UAAqB;EACnC,SAAS,MAAM,WAAsB;EACrC,GAAG;EACJ,EAAE;AAEH,QAAO,YAAY;;;;;ACrErB,MAAM,gBAAsC;CAC1C,MAAM;CACN,QAAQ;CACR,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,OAAO;CACR;AAED,MAAM,oBAA0C;CAC9C,aAAa;CACb,cAAc;CACf;;;;;;;;AASD,MAAM,wBACJ,QACA,QACA,gBACM;AACN,KAAI,OAAO,WAAW,SAAU,QAAO;CAEvC,MAAM,QAAQ,OAAO,eAAe,OAAO;AAC3C,KAAI,SAAS,UAAU,OAAO,UAC5B,sBAAqB,QAAQ,OAAO,YAAY;CAGlD,MAAM,OAA4B,CAChC,GAAG,OAAO,oBAAoB,OAAO,EACrC,GAAG,OAAO,sBAAsB,OAAO,CACxC;AAED,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,IAAI;AACV,MAAI,cAAc,MAAM,cAAc,MAAM,kBAAkB,GAC5D;EAGF,MAAM,aAAa,OAAO,yBAAyB,QAAQ,IAAI;AAC/D,MAAI,WACF,KAAI;AACF,UAAO,eAAe,QAAQ,KAAK,WAAW;UACxC;;AAMZ,QAAO;;;;;ACvDT,MAAM,YAAY;CAChB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;AClJD,MAAM,gBAAgB,GAAc,MAA0B;AAC5D,KAAI,EAAE,WAAW,EAA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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/ui-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Core utilities, config, and context for Pyreon UI System",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,14 +36,15 @@
|
|
|
36
36
|
"typecheck": "tsc --noEmit"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@pyreon/
|
|
39
|
+
"@pyreon/manifest": "0.13.1",
|
|
40
|
+
"@pyreon/typescript": "^0.14.0",
|
|
40
41
|
"@vitus-labs/tools-rolldown": "^1.15.3"
|
|
41
42
|
},
|
|
42
43
|
"peerDependencies": {
|
|
43
|
-
"@pyreon/core": "^0.
|
|
44
|
-
"@pyreon/reactivity": "^0.
|
|
45
|
-
"@pyreon/styler": "^0.
|
|
46
|
-
"@pyreon/unistyle": "^0.
|
|
44
|
+
"@pyreon/core": "^0.14.0",
|
|
45
|
+
"@pyreon/reactivity": "^0.14.0",
|
|
46
|
+
"@pyreon/styler": "^0.14.0",
|
|
47
|
+
"@pyreon/unistyle": "^0.14.0"
|
|
47
48
|
},
|
|
48
49
|
"engines": {
|
|
49
50
|
"node": ">= 22"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderApiReferenceEntries,
|
|
3
|
+
renderLlmsFullSection,
|
|
4
|
+
renderLlmsTxtLine,
|
|
5
|
+
} from '@pyreon/manifest'
|
|
6
|
+
import manifest from '../manifest'
|
|
7
|
+
|
|
8
|
+
describe('gen-docs — ui-core snapshot', () => {
|
|
9
|
+
it('renders a llms.txt bullet starting with the package prefix', () => {
|
|
10
|
+
const line = renderLlmsTxtLine(manifest)
|
|
11
|
+
expect(line.startsWith('- @pyreon/ui-core —')).toBe(true)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('renders a llms-full.txt section with the right header', () => {
|
|
15
|
+
const section = renderLlmsFullSection(manifest)
|
|
16
|
+
expect(section.startsWith('## @pyreon/ui-core —')).toBe(true)
|
|
17
|
+
expect(section).toContain('```typescript')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('renders MCP api-reference entries for every api[] item', () => {
|
|
21
|
+
const record = renderApiReferenceEntries(manifest)
|
|
22
|
+
expect(Object.keys(record).sort()).toEqual([
|
|
23
|
+
'ui-core/PyreonUI',
|
|
24
|
+
'ui-core/useMode',
|
|
25
|
+
])
|
|
26
|
+
})
|
|
27
|
+
})
|
package/src/manifest.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { defineManifest } from '@pyreon/manifest'
|
|
2
|
+
|
|
3
|
+
export default defineManifest({
|
|
4
|
+
name: '@pyreon/ui-core',
|
|
5
|
+
title: 'UI Provider + Config',
|
|
6
|
+
tagline:
|
|
7
|
+
'Unified `PyreonUI` provider (theme + mode + config), `useMode()` hook, init() escape hatch',
|
|
8
|
+
description:
|
|
9
|
+
'Foundation layer for the Pyreon UI system. `PyreonUI` is the single provider replacing the previous theme / mode / config split — it accepts a theme, a `mode` of `"light" | "dark" | "system"`, and an optional `inversed` flip, then auto-detects OS preference via `prefers-color-scheme` when `mode="system"`. `useMode()` returns the resolved mode as a reactive signal. The package also exposes the `init()` escape hatch (called internally by `PyreonUI` but available for SSR / test setups), the static `HTML_TAGS` / `HTML_TEXT_TAGS` lists used by the bases, and zero-dep utilities (`get`, `set`, `merge`, `pick`, `omit`, `throttle`, `isEmpty`, `isEqual`).',
|
|
10
|
+
category: 'browser',
|
|
11
|
+
features: [
|
|
12
|
+
'PyreonUI({ theme, mode, inversed }) — single provider replaces 3 separate providers',
|
|
13
|
+
'mode="system" auto-detects OS preference via matchMedia and updates reactively',
|
|
14
|
+
'useMode() returns Signal<"light" | "dark"> resolved against system preference + inversed',
|
|
15
|
+
'init() callable directly for custom environments (tests, SSR without PyreonUI)',
|
|
16
|
+
'enrichTheme() (re-exported from @pyreon/unistyle) merges user theme with defaults',
|
|
17
|
+
'Zero-dep utilities: get, set, merge, pick, omit, throttle, isEmpty, isEqual',
|
|
18
|
+
'HTML_TAGS / HTML_TEXT_TAGS constants drive Element / Text base tag dispatching',
|
|
19
|
+
],
|
|
20
|
+
longExample: `import { PyreonUI, useMode } from '@pyreon/ui-core'
|
|
21
|
+
import { enrichTheme } from '@pyreon/unistyle'
|
|
22
|
+
|
|
23
|
+
// Single provider — wraps theme, mode, and config in one tree
|
|
24
|
+
const theme = enrichTheme({
|
|
25
|
+
colors: { primary: '#3b82f6', secondary: '#6366f1' },
|
|
26
|
+
fonts: { body: 'Inter, sans-serif' },
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const App = () => (
|
|
30
|
+
<PyreonUI theme={theme} mode="system">
|
|
31
|
+
<MyApp />
|
|
32
|
+
</PyreonUI>
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
// useMode() reads the resolved mode reactively
|
|
36
|
+
function ThemeBadge() {
|
|
37
|
+
const mode = useMode()
|
|
38
|
+
return <div class={mode() === 'dark' ? 'badge-dark' : 'badge-light'}>{mode()}</div>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// inversed flips the resolved mode (light → dark and vice versa)
|
|
42
|
+
const InvertedSection = () => (
|
|
43
|
+
<PyreonUI inversed>
|
|
44
|
+
<Sidebar />
|
|
45
|
+
</PyreonUI>
|
|
46
|
+
)`,
|
|
47
|
+
api: [
|
|
48
|
+
{
|
|
49
|
+
name: 'PyreonUI',
|
|
50
|
+
kind: 'component',
|
|
51
|
+
signature:
|
|
52
|
+
"(props: { theme?: Theme; mode?: 'light' | 'dark' | 'system'; inversed?: boolean; children: VNodeChild }) => VNodeChild",
|
|
53
|
+
summary:
|
|
54
|
+
"Unified provider replacing the previous theme / mode / config split (3 nested providers became 1). Accepts an enriched `theme` object (merge with defaults via `enrichTheme()`), a `mode` of `'light' | 'dark' | 'system'`, and an optional `inversed` flip. When `mode='system'`, the provider subscribes to `matchMedia('(prefers-color-scheme: dark)')` and re-resolves the mode reactively. Calls `init()` internally so consumers don\\\'t need to wire it up themselves. Whole-theme swaps (user-preference themes) propagate through the styler resolver and re-resolve CSS without remounting the VNode.",
|
|
55
|
+
example: `import { PyreonUI } from "@pyreon/ui-core"
|
|
56
|
+
import { enrichTheme } from "@pyreon/unistyle"
|
|
57
|
+
|
|
58
|
+
const theme = enrichTheme({ colors: { primary: "#3b82f6" } })
|
|
59
|
+
|
|
60
|
+
<PyreonUI theme={theme} mode="system">
|
|
61
|
+
<App />
|
|
62
|
+
</PyreonUI>
|
|
63
|
+
|
|
64
|
+
// mode="system" auto-detects OS dark mode via prefers-color-scheme
|
|
65
|
+
// inversed flips the resolved mode (light↔dark)`,
|
|
66
|
+
mistakes: [
|
|
67
|
+
'Using `ThemeProvider` + `ModeProvider` + `ConfigProvider` separately — `PyreonUI` is the single replacement covering all three',
|
|
68
|
+
'Forgetting `enrichTheme()` — raw theme objects miss default breakpoints / spacing / unit utilities',
|
|
69
|
+
'Destructuring `props` inside the provider — components run once; destructuring captures values at setup. Read `props.mode` lazily inside reactive scopes',
|
|
70
|
+
'Re-augmenting the `ThemeDefault` / `StylesDefault` interfaces in your app — `@pyreon/ui-theme` already augments them; double-augmentation throws TS2320',
|
|
71
|
+
],
|
|
72
|
+
seeAlso: ['useMode', 'enrichTheme', 'init'],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'useMode',
|
|
76
|
+
kind: 'hook',
|
|
77
|
+
signature: "useMode(): Signal<'light' | 'dark'>",
|
|
78
|
+
summary:
|
|
79
|
+
"Returns the currently resolved mode as a reactive signal — `'light'` or `'dark'`. When the nearest `PyreonUI` ancestor uses `mode='system'`, the signal reflects the OS preference and updates when the user changes their system setting. When `inversed` is true on any ancestor, the mode is flipped before resolution. Component-scoped subscription — readers re-run only when the resolved mode actually changes.",
|
|
80
|
+
example: `import { useMode } from "@pyreon/ui-core"
|
|
81
|
+
|
|
82
|
+
const mode = useMode()
|
|
83
|
+
// mode() returns "light" or "dark" (resolved, reactive)
|
|
84
|
+
// Reflects OS preference when PyreonUI mode="system"`,
|
|
85
|
+
mistakes: [
|
|
86
|
+
'Reading `useMode()` without calling it — the value is a `Signal`; use `mode()` to read',
|
|
87
|
+
'Using `useMode()` outside any `PyreonUI` ancestor — falls back to a default but loses the reactive system / inversed handling',
|
|
88
|
+
],
|
|
89
|
+
seeAlso: ['PyreonUI'],
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
gotchas: [
|
|
93
|
+
{
|
|
94
|
+
label: 'Provider replacement',
|
|
95
|
+
note:
|
|
96
|
+
'The legacy split (separate theme / mode / config providers) is removed. `PyreonUI` is the only correct mount; calling `init()` directly is the escape hatch for SSR or test environments where the provider tree is unavailable.',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
label: 'System-mode subscription',
|
|
100
|
+
note:
|
|
101
|
+
'`mode="system"` lazily creates a `matchMedia(\'(prefers-color-scheme: dark)\')` subscription on first read; the listener stays alive for the document lifetime, so a single subscription handles every `useMode()` consumer.',
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
})
|
package/src/utils.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a copy of `obj` without the specified keys.
|
|
3
|
+
*
|
|
4
|
+
* Accepts either an array of keys (builds a Set internally) or a
|
|
5
|
+
* pre-built `Set<string>` for hot paths where the same key list is
|
|
6
|
+
* reused across many calls (avoids per-call Set allocation).
|
|
7
|
+
*/
|
|
1
8
|
export const omit = <T extends Record<string, any>>(
|
|
2
9
|
obj: T | null | undefined,
|
|
3
|
-
keys?: readonly (string | keyof T)[]
|
|
10
|
+
keys?: readonly (string | keyof T)[] | Set<string>,
|
|
4
11
|
): Partial<T> => {
|
|
5
12
|
if (obj == null) return {} as Partial<T>
|
|
6
|
-
if (!keys || keys.length === 0) return { ...obj }
|
|
13
|
+
if (!keys || (keys instanceof Set ? keys.size === 0 : keys.length === 0)) return { ...obj }
|
|
14
|
+
const keysSet = keys instanceof Set ? keys : new Set(keys as readonly string[])
|
|
7
15
|
const result: Record<string, any> = {}
|
|
8
|
-
const keysSet = new Set(keys as readonly string[])
|
|
9
16
|
for (const key in obj) {
|
|
10
17
|
if (Object.hasOwn(obj, key) && !keysSet.has(key)) {
|
|
11
18
|
result[key] = obj[key]
|