@pyreon/ui-core 0.11.5 → 0.11.7

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 CHANGED
@@ -25,7 +25,9 @@ import { Provider } from '@pyreon/ui-core'
25
25
 
26
26
  Provider({
27
27
  theme: { rootSize: 16, breakpoints: { xs: 0, md: 768 } },
28
- children: [/* your app */],
28
+ children: [
29
+ /* your app */
30
+ ],
29
31
  })
30
32
  ```
31
33
 
@@ -58,9 +60,9 @@ Flexible element renderer. Handles components, elements, primitives, and arrays.
58
60
  ```ts
59
61
  import { render } from '@pyreon/ui-core'
60
62
 
61
- render('hello') // => 'hello'
62
- render(MyComponent) // => MyComponent({})
63
- render(null) // => null
63
+ render('hello') // => 'hello'
64
+ render(MyComponent) // => MyComponent({})
65
+ render(null) // => null
64
66
  ```
65
67
 
66
68
  #### isEmpty
@@ -70,9 +72,9 @@ Type-safe emptiness check. Returns `true` for `null`, `undefined`, `{}`, `[]`, a
70
72
  ```ts
71
73
  import { isEmpty } from '@pyreon/ui-core'
72
74
 
73
- isEmpty({}) // => true
74
- isEmpty([]) // => true
75
- isEmpty(null) // => true
75
+ isEmpty({}) // => true
76
+ isEmpty([]) // => true
77
+ isEmpty(null) // => true
76
78
  isEmpty({ a: 1 }) // => false
77
79
  ```
78
80
 
@@ -83,7 +85,7 @@ Create objects without or with only specified keys. Accept nullable inputs.
83
85
  ```ts
84
86
  import { omit, pick } from '@pyreon/ui-core'
85
87
 
86
- omit({ a: 1, b: 2, c: 3 }, ['b']) // => { a: 1, c: 3 }
88
+ omit({ a: 1, b: 2, c: 3 }, ['b']) // => { a: 1, c: 3 }
87
89
  pick({ a: 1, b: 2, c: 3 }, ['a', 'b']) // => { a: 1, b: 2 }
88
90
  ```
89
91
 
@@ -95,8 +97,8 @@ Nested property access and mutation by dot/bracket path. `set` has built-in prot
95
97
  import { set, get } from '@pyreon/ui-core'
96
98
 
97
99
  const obj = {}
98
- set(obj, 'a.b.c', 42) // => { a: { b: { c: 42 } } }
99
- get(obj, 'a.b.c') // => 42
100
+ set(obj, 'a.b.c', 42) // => { a: { b: { c: 42 } } }
101
+ get(obj, 'a.b.c') // => 42
100
102
  get(obj, 'a.x', 'default') // => 'default'
101
103
  ```
102
104
 
@@ -135,9 +137,9 @@ Both have corresponding TypeScript union types: `HTMLTags` and `HTMLTextTags`.
135
137
 
136
138
  ## Peer Dependencies
137
139
 
138
- | Package | Version |
139
- | ------- | ------- |
140
- | @pyreon/core | >= 0.0.1 |
140
+ | Package | Version |
141
+ | -------------- | -------- |
142
+ | @pyreon/core | >= 0.0.1 |
141
143
  | @pyreon/styler | >= 0.0.1 |
142
144
 
143
145
  ## License
package/lib/index.d.ts CHANGED
@@ -144,7 +144,7 @@ interface PlatformConfig {
144
144
  createMediaQueries?: (props: {
145
145
  breakpoints: Record<string, number>;
146
146
  rootSize: number;
147
- css: CSSEngineConnector["css"];
147
+ css: CSSEngineConnector['css'];
148
148
  }) => Record<string, (...args: any[]) => any>;
149
149
  }
150
150
  type InitConfig = Partial<CSSEngineConnector & PlatformConfig>;
@@ -164,7 +164,7 @@ declare class Configuration {
164
164
  };
165
165
  component: string | HTMLTags;
166
166
  textComponent: string | HTMLTags;
167
- createMediaQueries: PlatformConfig["createMediaQueries"];
167
+ createMediaQueries: PlatformConfig['createMediaQueries'];
168
168
  init: (props: InitConfig) => void;
169
169
  }
170
170
  declare const config: Configuration;
@@ -178,10 +178,21 @@ type BreakpointKeys = keyof Breakpoints;
178
178
  //#endregion
179
179
  //#region src/context.d.ts
180
180
  /**
181
- * Internal context shared across all @pyreon packages.
182
- * Carries the theme object plus any extra provider props.
181
+ * Core context value shared across all @pyreon UI packages.
183
182
  */
184
- declare const context: _pyreon_core0.Context<any>;
183
+ interface CoreContextValue {
184
+ theme: Record<string, unknown>;
185
+ mode: 'light' | 'dark';
186
+ isDark: boolean;
187
+ isLight: boolean;
188
+ }
189
+ /**
190
+ * Internal reactive context shared across all @pyreon packages.
191
+ * Carries the theme object, mode, and derived dark/light flags.
192
+ *
193
+ * ReactiveContext means useContext() returns `() => CoreContextValue`.
194
+ */
195
+ declare const context: _pyreon_core0.ReactiveContext<CoreContextValue>;
185
196
  type Theme = Partial<{
186
197
  rootSize: number;
187
198
  breakpoints: Breakpoints;
@@ -190,10 +201,6 @@ type ProviderType = Partial<{
190
201
  theme: Theme;
191
202
  children: VNodeChild;
192
203
  } & Record<string, any>>;
193
- /**
194
- * Provider that feeds the internal Pyreon context with the theme.
195
- * When no theme is supplied, renders children directly.
196
- */
197
204
  declare function Provider({
198
205
  theme,
199
206
  children,
@@ -218,8 +225,8 @@ declare const isEmpty: IsEmpty;
218
225
  declare const isEqual: (a: unknown, b: unknown) => boolean;
219
226
  //#endregion
220
227
  //#region src/PyreonUI.d.ts
221
- type ThemeMode = "light" | "dark";
222
- type ThemeModeInput = ThemeMode | "system";
228
+ type ThemeMode = 'light' | 'dark';
229
+ type ThemeModeInput = ThemeMode | 'system';
223
230
  interface PyreonUIProps {
224
231
  /** Theme object with breakpoints, rootSize, and custom keys. */
225
232
  theme: PyreonTheme;
@@ -305,5 +312,5 @@ declare const throttle: <T extends (...args: any[]) => any>(fn: T, wait?: number
305
312
  };
306
313
  declare const merge: <T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]) => T;
307
314
  //#endregion
308
- export { type BreakpointKeys, type Breakpoints, type CSSEngineConnector, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, PyreonUI, type PyreonUIProps, type Render, type ThemeMode, type ThemeModeInput, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useMode, useStableValue };
315
+ export { type BreakpointKeys, type Breakpoints, type CSSEngineConnector, type CoreContextValue, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, PyreonUI, type PyreonUIProps, type Render, type ThemeMode, type ThemeModeInput, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useMode, useStableValue };
309
316
  //# sourceMappingURL=index2.d.ts.map
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ThemeContext, css, keyframes, styled } from "@pyreon/styler";
2
- import { createContext, h, provide, useContext } from "@pyreon/core";
2
+ import { createReactiveContext, h, provide, useContext } from "@pyreon/core";
3
3
  import { computed, signal } from "@pyreon/reactivity";
4
4
  import { enrichTheme } from "@pyreon/unistyle";
5
5
 
@@ -46,20 +46,36 @@ const isEmpty = ((param) => {
46
46
  //#endregion
47
47
  //#region src/context.tsx
48
48
  /**
49
- * Internal context shared across all @pyreon packages.
50
- * Carries the theme object plus any extra provider props.
49
+ * Internal reactive context shared across all @pyreon packages.
50
+ * Carries the theme object, mode, and derived dark/light flags.
51
+ *
52
+ * ReactiveContext means useContext() returns `() => CoreContextValue`.
51
53
  */
52
- const context = createContext({});
54
+ const context = createReactiveContext({
55
+ theme: {},
56
+ mode: "light",
57
+ isDark: false,
58
+ isLight: true
59
+ });
53
60
  /**
61
+ * @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.
62
+ *
54
63
  * Provider that feeds the internal Pyreon context with the theme.
55
64
  * When no theme is supplied, renders children directly.
65
+ *
66
+ * @deprecated Prefer `<PyreonUI theme={theme}>` which handles all context layers.
56
67
  */
68
+ const __DEV__ = typeof process !== "undefined" && process?.env?.NODE_ENV !== "production";
57
69
  function Provider({ theme, children, ...props }) {
70
+ if (__DEV__) console.warn("[Pyreon] CoreProvider is internal. Use <PyreonUI theme={theme}> instead — it handles all context layers (styler, core, mode) in one component.");
58
71
  if (isEmpty(theme) || !theme) return children ?? null;
59
- provide(context, {
72
+ provide(context, () => ({
60
73
  theme,
74
+ mode: props.mode ?? "light",
75
+ isDark: props.isDark ?? false,
76
+ isLight: props.isLight ?? true,
61
77
  ...props
62
- });
78
+ }));
63
79
  return children ?? null;
64
80
  }
65
81
 
@@ -287,8 +303,8 @@ function getSystemMode() {
287
303
  });
288
304
  return _systemMode;
289
305
  }
290
- /** Context value is a getter consumers call it to read the current mode reactively. */
291
- const ModeContext = createContext(() => "light");
306
+ /** Reactive contextuseContext(ModeContext) returns () => ThemeMode. */
307
+ const ModeContext = createReactiveContext("light");
292
308
  const INVERSED = {
293
309
  light: "dark",
294
310
  dark: "light"
@@ -338,18 +354,12 @@ function PyreonUI({ theme, mode = "light", inversed, children }) {
338
354
  const modeComputed = computed(resolveMode);
339
355
  const enrichedTheme = enrichTheme(theme);
340
356
  provide(ThemeContext, enrichedTheme);
341
- provide(context, {
357
+ provide(context, () => ({
342
358
  theme: enrichedTheme,
343
- get mode() {
344
- return modeComputed();
345
- },
346
- get isDark() {
347
- return modeComputed() === "dark";
348
- },
349
- get isLight() {
350
- return modeComputed() === "light";
351
- }
352
- });
359
+ mode: modeComputed(),
360
+ isDark: modeComputed() === "dark",
361
+ isLight: modeComputed() === "light"
362
+ }));
353
363
  provide(ModeContext, () => modeComputed());
354
364
  return children ?? null;
355
365
  }
package/package.json CHANGED
@@ -1,24 +1,13 @@
1
1
  {
2
2
  "name": "@pyreon/ui-core",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
+ "description": "Core utilities, config, and context for Pyreon UI System",
5
+ "license": "MIT",
4
6
  "repository": {
5
7
  "type": "git",
6
8
  "url": "https://github.com/pyreon/pyreon",
7
9
  "directory": "packages/ui-system/ui-core"
8
10
  },
9
- "description": "Core utilities, config, and context for Pyreon UI System",
10
- "license": "MIT",
11
- "type": "module",
12
- "sideEffects": false,
13
- "exports": {
14
- ".": {
15
- "bun": "./src/index.ts",
16
- "import": "./lib/index.js",
17
- "types": "./lib/index.d.ts"
18
- }
19
- },
20
- "types": "./lib/index.d.ts",
21
- "main": "./lib/index.js",
22
11
  "files": [
23
12
  "lib",
24
13
  "!lib/**/*.map",
@@ -27,26 +16,37 @@
27
16
  "LICENSE",
28
17
  "src"
29
18
  ],
30
- "engines": {
31
- "node": ">= 22"
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "main": "./lib/index.js",
22
+ "types": "./lib/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "bun": "./src/index.ts",
26
+ "import": "./lib/index.js",
27
+ "types": "./lib/index.d.ts"
28
+ }
32
29
  },
33
30
  "publishConfig": {
34
31
  "access": "public"
35
32
  },
36
33
  "scripts": {
37
34
  "build": "bun run vl_rolldown_build",
38
- "lint": "biome check src/",
35
+ "lint": "oxlint .",
39
36
  "test": "vitest run",
40
37
  "typecheck": "tsc --noEmit"
41
38
  },
39
+ "devDependencies": {
40
+ "@pyreon/typescript": "^0.11.7",
41
+ "@vitus-labs/tools-rolldown": "^1.15.3"
42
+ },
42
43
  "peerDependencies": {
43
- "@pyreon/core": "^0.11.5",
44
- "@pyreon/styler": "^0.11.5",
45
- "@pyreon/reactivity": "^0.11.5",
46
- "@pyreon/unistyle": "^0.11.5"
44
+ "@pyreon/core": "^0.11.7",
45
+ "@pyreon/reactivity": "^0.11.7",
46
+ "@pyreon/styler": "^0.11.7",
47
+ "@pyreon/unistyle": "^0.11.7"
47
48
  },
48
- "devDependencies": {
49
- "@vitus-labs/tools-rolldown": "^1.15.3",
50
- "@pyreon/typescript": "^0.11.5"
49
+ "engines": {
50
+ "node": ">= 22"
51
51
  }
52
52
  }
package/src/PyreonUI.tsx CHANGED
@@ -1,15 +1,15 @@
1
- import type { VNodeChild } from "@pyreon/core"
2
- import { createContext, provide, useContext } from "@pyreon/core"
3
- import { computed, signal } from "@pyreon/reactivity"
4
- import { ThemeContext } from "@pyreon/styler"
5
- import type { PyreonTheme } from "@pyreon/unistyle"
6
- import { enrichTheme } from "@pyreon/unistyle"
7
- import { context as coreContext } from "./context"
1
+ import type { VNodeChild } from '@pyreon/core'
2
+ import { createReactiveContext, provide, useContext } from '@pyreon/core'
3
+ import { computed, signal } from '@pyreon/reactivity'
4
+ import { ThemeContext } from '@pyreon/styler'
5
+ import type { PyreonTheme } from '@pyreon/unistyle'
6
+ import { enrichTheme } from '@pyreon/unistyle'
7
+ import { context as coreContext } from './context'
8
8
 
9
9
  // ─── Types ──────────────────────────────────────────────────────────────────
10
10
 
11
- export type ThemeMode = "light" | "dark"
12
- export type ThemeModeInput = ThemeMode | "system"
11
+ export type ThemeMode = 'light' | 'dark'
12
+ export type ThemeModeInput = ThemeMode | 'system'
13
13
 
14
14
  export interface PyreonUIProps {
15
15
  /** Theme object with breakpoints, rootSize, and custom keys. */
@@ -27,7 +27,7 @@ export interface PyreonUIProps {
27
27
 
28
28
  // ─── System mode detection ──────────────────────────────────────────────────
29
29
 
30
- const _isBrowser = typeof window !== "undefined" && typeof matchMedia === "function"
30
+ const _isBrowser = typeof window !== 'undefined' && typeof matchMedia === 'function'
31
31
 
32
32
  /** Reactive signal tracking the OS dark mode preference. Lazy-initialized on first use. */
33
33
  let _systemMode: ReturnType<typeof signal<ThemeMode>> | undefined
@@ -35,12 +35,12 @@ let _systemMode: ReturnType<typeof signal<ThemeMode>> | undefined
35
35
  function getSystemMode(): ReturnType<typeof signal<ThemeMode>> {
36
36
  if (_systemMode) return _systemMode
37
37
 
38
- const prefersDark = _isBrowser && matchMedia("(prefers-color-scheme: dark)").matches
39
- _systemMode = signal<ThemeMode>(prefersDark ? "dark" : "light")
38
+ const prefersDark = _isBrowser && matchMedia('(prefers-color-scheme: dark)').matches
39
+ _systemMode = signal<ThemeMode>(prefersDark ? 'dark' : 'light')
40
40
 
41
41
  if (_isBrowser) {
42
- matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
43
- _systemMode?.set(e.matches ? "dark" : "light")
42
+ matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
43
+ _systemMode?.set(e.matches ? 'dark' : 'light')
44
44
  })
45
45
  }
46
46
 
@@ -49,10 +49,10 @@ function getSystemMode(): ReturnType<typeof signal<ThemeMode>> {
49
49
 
50
50
  // ─── Mode context ───────────────────────────────────────────────────────────
51
51
 
52
- /** Context value is a getter consumers call it to read the current mode reactively. */
53
- const ModeContext = createContext<() => ThemeMode>(() => "light")
52
+ /** Reactive contextuseContext(ModeContext) returns () => ThemeMode. */
53
+ const ModeContext = createReactiveContext<ThemeMode>('light')
54
54
 
55
- const INVERSED: Record<ThemeMode, ThemeMode> = { light: "dark", dark: "light" }
55
+ const INVERSED: Record<ThemeMode, ThemeMode> = { light: 'dark', dark: 'light' }
56
56
 
57
57
  /**
58
58
  * Read the resolved color mode ("light" | "dark") from the nearest PyreonUI.
@@ -96,15 +96,15 @@ function autoInit(): void {
96
96
  * <PyreonUI theme={theme} mode="system">
97
97
  * ```
98
98
  */
99
- export function PyreonUI({ theme, mode = "light", inversed, children }: PyreonUIProps): VNodeChild {
99
+ export function PyreonUI({ theme, mode = 'light', inversed, children }: PyreonUIProps): VNodeChild {
100
100
  autoInit()
101
101
 
102
102
  // Create a reactive mode getter that resolves "system" and applies inversion.
103
103
  // This getter is provided via context — consumers read it lazily in their
104
104
  // own reactive scopes, so mode changes propagate automatically.
105
105
  const resolveMode = (): ThemeMode => {
106
- const raw = typeof mode === "function" ? mode() : mode
107
- const resolved = raw === "system" ? getSystemMode()() : raw
106
+ const raw = typeof mode === 'function' ? mode() : mode
107
+ const resolved = raw === 'system' ? getSystemMode()() : raw
108
108
  return inversed ? INVERSED[resolved] : resolved
109
109
  }
110
110
 
@@ -119,21 +119,15 @@ export function PyreonUI({ theme, mode = "light", inversed, children }: PyreonUI
119
119
  // 1. Styler ThemeContext — for styled() components and useTheme()
120
120
  provide(ThemeContext, enrichedTheme)
121
121
 
122
- // 2. Core context — provide a reactive object with getters.
123
- // Rocketstyle reads mode/isDark/isLight from this context.
124
- // By providing getters, the values update when modeComputed changes.
125
- provide(coreContext, {
122
+ // 2. Core context — provide a reactive getter function.
123
+ // coreContext is a ReactiveContext, so provide(() => value).
124
+ // Rocketstyle reads mode/isDark/isLight by calling the getter.
125
+ provide(coreContext, () => ({
126
126
  theme: enrichedTheme,
127
- get mode() {
128
- return modeComputed()
129
- },
130
- get isDark() {
131
- return modeComputed() === "dark"
132
- },
133
- get isLight() {
134
- return modeComputed() === "light"
135
- },
136
- })
127
+ mode: modeComputed(),
128
+ isDark: modeComputed() === 'dark',
129
+ isLight: modeComputed() === 'light',
130
+ }))
137
131
 
138
132
  // 3. Mode context — getter function for useMode()
139
133
  provide(ModeContext, () => modeComputed())
@@ -1,97 +1,100 @@
1
- import { h } from "@pyreon/core"
2
- import { describe, expect, it, vi } from "vitest"
3
- import { PyreonUI } from "../PyreonUI"
1
+ import { h } from '@pyreon/core'
2
+ import { describe, expect, it, vi } from 'vitest'
3
+ import { PyreonUI } from '../PyreonUI'
4
4
 
5
5
  // Spy on provide to verify context provision
6
- const provideSpy = vi.spyOn(await import("@pyreon/core"), "provide")
6
+ const provideSpy = vi.spyOn(await import('@pyreon/core'), 'provide')
7
7
 
8
8
  /** Get the value argument (2nd arg) from a provide() call by index. */
9
9
  const getProvideValue = (callIndex: number): any => provideSpy.mock.calls[callIndex]![1]
10
10
 
11
- describe("PyreonUI", () => {
11
+ describe('PyreonUI', () => {
12
12
  const theme = {
13
13
  rootSize: 16,
14
14
  breakpoints: { xs: 0, sm: 576, md: 768 },
15
- colors: { primary: "#228be6" },
15
+ colors: { primary: '#228be6' },
16
16
  }
17
17
 
18
18
  beforeEach(() => {
19
19
  provideSpy.mockClear()
20
20
  })
21
21
 
22
- it("renders children", () => {
23
- const child = h("div", null, "hello")
22
+ it('renders children', () => {
23
+ const child = h('div', null, 'hello')
24
24
  const result = PyreonUI({ theme, children: child })
25
25
  expect(result).toBe(child)
26
26
  })
27
27
 
28
- it("returns null when no children", () => {
28
+ it('returns null when no children', () => {
29
29
  const result = PyreonUI({ theme })
30
30
  expect(result).toBeNull()
31
31
  })
32
32
 
33
- it("calls provide three times (ThemeContext, core context, mode context)", () => {
33
+ it('calls provide three times (ThemeContext, core context, mode context)', () => {
34
34
  PyreonUI({ theme, children: null })
35
35
  expect(provideSpy).toHaveBeenCalledTimes(3)
36
36
  })
37
37
 
38
- it("defaults mode to light", () => {
38
+ it('defaults mode to light', () => {
39
39
  PyreonUI({ theme, children: null })
40
40
 
41
- // Core context (2nd call) — has getter properties for reactive mode
42
- const coreCtx = getProvideValue(1)
43
- expect(coreCtx.mode).toBe("light")
41
+ // Core context (2nd call) — ReactiveContext getter function
42
+ const coreCtxGetter = getProvideValue(1)
43
+ expect(typeof coreCtxGetter).toBe('function')
44
+ const coreCtx = coreCtxGetter()
45
+ expect(coreCtx.mode).toBe('light')
44
46
  expect(coreCtx.isLight).toBe(true)
45
47
  expect(coreCtx.isDark).toBe(false)
46
48
 
47
49
  // Mode context (3rd call) — getter function
48
50
  const modeGetter = getProvideValue(2)
49
- expect(typeof modeGetter).toBe("function")
50
- expect(modeGetter()).toBe("light")
51
+ expect(typeof modeGetter).toBe('function')
52
+ expect(modeGetter()).toBe('light')
51
53
  })
52
54
 
53
- it("provides dark mode", () => {
54
- PyreonUI({ theme, mode: "dark", children: null })
55
+ it('provides dark mode', () => {
56
+ PyreonUI({ theme, mode: 'dark', children: null })
55
57
 
56
- const coreCtx = getProvideValue(1)
57
- expect(coreCtx.mode).toBe("dark")
58
+ const coreCtxGetter = getProvideValue(1)
59
+ const coreCtx = coreCtxGetter()
60
+ expect(coreCtx.mode).toBe('dark')
58
61
  expect(coreCtx.isDark).toBe(true)
59
62
  expect(coreCtx.isLight).toBe(false)
60
63
 
61
64
  const modeGetter = getProvideValue(2)
62
- expect(modeGetter()).toBe("dark")
65
+ expect(modeGetter()).toBe('dark')
63
66
  })
64
67
 
65
- it("inverts mode when inversed=true", () => {
66
- PyreonUI({ theme, mode: "light", inversed: true, children: null })
67
- expect(getProvideValue(2)()).toBe("dark")
68
+ it('inverts mode when inversed=true', () => {
69
+ PyreonUI({ theme, mode: 'light', inversed: true, children: null })
70
+ expect(getProvideValue(2)()).toBe('dark')
68
71
  })
69
72
 
70
- it("inverts dark to light", () => {
71
- PyreonUI({ theme, mode: "dark", inversed: true, children: null })
72
- expect(getProvideValue(2)()).toBe("light")
73
+ it('inverts dark to light', () => {
74
+ PyreonUI({ theme, mode: 'dark', inversed: true, children: null })
75
+ expect(getProvideValue(2)()).toBe('light')
73
76
  })
74
77
 
75
- it("enriches theme with __PYREON__ before providing", () => {
78
+ it('enriches theme with __PYREON__ before providing', () => {
76
79
  PyreonUI({ theme, children: null })
77
80
 
78
81
  const providedTheme = getProvideValue(0)
79
82
  expect(providedTheme.__PYREON__).toBeDefined()
80
- expect(providedTheme.__PYREON__.sortedBreakpoints).toEqual(["xs", "sm", "md"])
81
- expect(providedTheme.colors).toEqual({ primary: "#228be6" })
83
+ expect(providedTheme.__PYREON__.sortedBreakpoints).toEqual(['xs', 'sm', 'md'])
84
+ expect(providedTheme.colors).toEqual({ primary: '#228be6' })
82
85
  })
83
86
 
84
- it("works with system mode (resolves to light in happy-dom)", () => {
85
- PyreonUI({ theme, mode: "system", children: null })
86
- expect(getProvideValue(2)()).toBe("light")
87
+ it('works with system mode (resolves to light in happy-dom)', () => {
88
+ PyreonUI({ theme, mode: 'system', children: null })
89
+ expect(getProvideValue(2)()).toBe('light')
87
90
  })
88
91
 
89
- it("mode context is a getter function (reactive-ready)", () => {
90
- PyreonUI({ theme, mode: "dark", children: null })
92
+ it('mode context is a getter function (reactive-ready)', () => {
93
+ PyreonUI({ theme, mode: 'dark', children: null })
91
94
  const modeGetter = getProvideValue(2)
92
95
  // Mode context is a function, not a static value — consumers call it
93
96
  // inside their own reactive scopes for reactive mode switching.
94
- expect(typeof modeGetter).toBe("function")
95
- expect(modeGetter()).toBe("dark")
97
+ expect(typeof modeGetter).toBe('function')
98
+ expect(modeGetter()).toBe('dark')
96
99
  })
97
100
  })
@@ -1,8 +1,8 @@
1
- import { describe, expect, it } from "vitest"
2
- import compose from "../compose"
1
+ import { describe, expect, it } from 'vitest'
2
+ import compose from '../compose'
3
3
 
4
- describe("compose", () => {
5
- it("should compose two functions right-to-left", () => {
4
+ describe('compose', () => {
5
+ it('should compose two functions right-to-left', () => {
6
6
  const double = (x: number) => x * 2
7
7
  const addOne = (x: number) => x + 1
8
8
  const composed = compose(addOne, double)
@@ -10,7 +10,7 @@ describe("compose", () => {
10
10
  expect(composed(3)).toBe(7)
11
11
  })
12
12
 
13
- it("should compose three functions right-to-left", () => {
13
+ it('should compose three functions right-to-left', () => {
14
14
  const add = (x: number) => x + 1
15
15
  const mul = (x: number) => x * 3
16
16
  const sub = (x: number) => x - 2
@@ -18,15 +18,15 @@ describe("compose", () => {
18
18
  expect(compose(add, mul, sub)(5)).toBe(10)
19
19
  })
20
20
 
21
- it("should work with a single function", () => {
21
+ it('should work with a single function', () => {
22
22
  const identity = (x: number) => x
23
23
  expect(compose(identity)(42)).toBe(42)
24
24
  })
25
25
 
26
- it("should pass value through string transforms", () => {
26
+ it('should pass value through string transforms', () => {
27
27
  const upper = (s: string) => s.toUpperCase()
28
28
  const exclaim = (s: string) => `${s}!`
29
29
  // exclaim('hello') = 'hello!', upper('hello!') = 'HELLO!'
30
- expect(compose(upper, exclaim)("hello")).toBe("HELLO!")
30
+ expect(compose(upper, exclaim)('hello')).toBe('HELLO!')
31
31
  })
32
32
  })