@pyreon/ui-core 0.3.0 → 0.11.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/lib/index.d.ts +46 -1
- package/lib/index.js +73 -150
- package/package.json +9 -6
package/lib/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as _pyreon_styler0 from "@pyreon/styler";
|
|
|
2
2
|
import { StyledFunction, css, keyframes, styled } from "@pyreon/styler";
|
|
3
3
|
import * as _pyreon_core0 from "@pyreon/core";
|
|
4
4
|
import { ComponentFn, VNodeChild } from "@pyreon/core";
|
|
5
|
+
import { PyreonTheme } from "@pyreon/unistyle";
|
|
5
6
|
|
|
6
7
|
//#region src/compose.d.ts
|
|
7
8
|
type ArityOneFn = (arg: any) => any;
|
|
@@ -216,6 +217,50 @@ declare const isEmpty: IsEmpty;
|
|
|
216
217
|
//#region src/isEqual.d.ts
|
|
217
218
|
declare const isEqual: (a: unknown, b: unknown) => boolean;
|
|
218
219
|
//#endregion
|
|
220
|
+
//#region src/PyreonUI.d.ts
|
|
221
|
+
type ThemeMode = "light" | "dark";
|
|
222
|
+
type ThemeModeInput = ThemeMode | "system";
|
|
223
|
+
interface PyreonUIProps {
|
|
224
|
+
/** Theme object with breakpoints, rootSize, and custom keys. */
|
|
225
|
+
theme: PyreonTheme;
|
|
226
|
+
/**
|
|
227
|
+
* Color mode: "light", "dark", or "system" (follows OS preference).
|
|
228
|
+
* @default "light"
|
|
229
|
+
*/
|
|
230
|
+
mode?: ThemeModeInput | undefined;
|
|
231
|
+
/** Flip mode for a nested section (e.g. dark sidebar in light app). */
|
|
232
|
+
inversed?: boolean | undefined;
|
|
233
|
+
children?: VNodeChild;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Read the resolved color mode ("light" | "dark") from the nearest PyreonUI.
|
|
237
|
+
* Reactive — updates when the mode prop changes or when OS preference changes
|
|
238
|
+
* (if mode="system").
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* const mode = useMode() // "light" | "dark"
|
|
242
|
+
*/
|
|
243
|
+
declare function useMode(): ThemeMode;
|
|
244
|
+
/**
|
|
245
|
+
* Unified provider for the Pyreon UI system.
|
|
246
|
+
*
|
|
247
|
+
* Replaces the need for separate UnistyleProvider, RocketstyleProvider,
|
|
248
|
+
* and ThemeProvider — one component, zero init.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```tsx
|
|
252
|
+
* <PyreonUI theme={{ rootSize: 16, breakpoints: { xs: 0, sm: 576, md: 768 } }} mode="system">
|
|
253
|
+
* <App />
|
|
254
|
+
* </PyreonUI>
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
declare function PyreonUI({
|
|
258
|
+
theme,
|
|
259
|
+
mode,
|
|
260
|
+
inversed,
|
|
261
|
+
children
|
|
262
|
+
}: PyreonUIProps): VNodeChild;
|
|
263
|
+
//#endregion
|
|
219
264
|
//#region src/render.d.ts
|
|
220
265
|
type RenderProps<T extends Record<string, unknown> | undefined> = (props: Partial<T>) => VNodeChild;
|
|
221
266
|
/**
|
|
@@ -253,5 +298,5 @@ declare const throttle: <T extends (...args: any[]) => any>(fn: T, wait?: number
|
|
|
253
298
|
};
|
|
254
299
|
declare const merge: <T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]) => T;
|
|
255
300
|
//#endregion
|
|
256
|
-
export { type BreakpointKeys, type Breakpoints, type CSSEngineConnector, type HTMLElementAttrs, type HTMLTagAttrsByTag, type HTMLTags, type HTMLTextTags, HTML_TAGS, HTML_TEXT_TAGS, type IsEmpty, Provider, type Render, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue };
|
|
301
|
+
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 };
|
|
257
302
|
//# sourceMappingURL=index2.d.ts.map
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { css, keyframes, styled } from "@pyreon/styler";
|
|
2
|
-
import { createContext, h, provide } from "@pyreon/core";
|
|
1
|
+
import { ThemeContext, css, keyframes, styled } from "@pyreon/styler";
|
|
2
|
+
import { createContext, h, provide, useContext } from "@pyreon/core";
|
|
3
|
+
import { signal } from "@pyreon/reactivity";
|
|
4
|
+
import { enrichTheme } from "@pyreon/unistyle";
|
|
3
5
|
|
|
4
6
|
//#region src/compose.ts
|
|
5
7
|
const compose = (...fns) => (p) => fns.reduceRight((acc, cur) => cur(acc), p);
|
|
@@ -273,166 +275,87 @@ const isEqual = (a, b) => {
|
|
|
273
275
|
};
|
|
274
276
|
|
|
275
277
|
//#endregion
|
|
276
|
-
//#region src/
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
if (
|
|
284
|
-
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
//#endregion
|
|
288
|
-
//#region ../../node_modules/.bun/@pyreon+reactivity@0.7.12/node_modules/@pyreon/reactivity/lib/index.js
|
|
289
|
-
let batchDepth = 0;
|
|
290
|
-
const setA = /* @__PURE__ */ new Set();
|
|
291
|
-
let pendingNotifications = setA;
|
|
292
|
-
function isBatching() {
|
|
293
|
-
return batchDepth > 0;
|
|
294
|
-
}
|
|
295
|
-
function enqueuePendingNotification(notify) {
|
|
296
|
-
pendingNotifications.add(notify);
|
|
297
|
-
}
|
|
298
|
-
let activeEffect = null;
|
|
299
|
-
const effectDeps = /* @__PURE__ */ new WeakMap();
|
|
300
|
-
let _depsCollector = null;
|
|
301
|
-
let _skipDepsCollection = false;
|
|
302
|
-
/**
|
|
303
|
-
* Register the active effect as a subscriber of the given reactive source.
|
|
304
|
-
* The subscriber Set is created lazily on the host — sources read only outside
|
|
305
|
-
* effects never allocate a Set.
|
|
306
|
-
*/
|
|
307
|
-
function trackSubscriber(host) {
|
|
308
|
-
if (activeEffect) {
|
|
309
|
-
if (!host._s) host._s = /* @__PURE__ */ new Set();
|
|
310
|
-
host._s.add(activeEffect);
|
|
311
|
-
if (_skipDepsCollection) return;
|
|
312
|
-
if (_depsCollector) _depsCollector.push(host._s);
|
|
313
|
-
else {
|
|
314
|
-
let deps = effectDeps.get(activeEffect);
|
|
315
|
-
if (!deps) {
|
|
316
|
-
deps = /* @__PURE__ */ new Set();
|
|
317
|
-
effectDeps.set(activeEffect, deps);
|
|
318
|
-
}
|
|
319
|
-
deps.add(host._s);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
function notifySubscribers(subscribers) {
|
|
324
|
-
if (subscribers.size === 0) return;
|
|
325
|
-
if (subscribers.size === 1) {
|
|
326
|
-
const sub = subscribers.values().next().value;
|
|
327
|
-
if (isBatching()) enqueuePendingNotification(sub);
|
|
328
|
-
else sub();
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
if (isBatching()) for (const sub of subscribers) enqueuePendingNotification(sub);
|
|
332
|
-
else {
|
|
333
|
-
const originalSize = subscribers.size;
|
|
334
|
-
let i = 0;
|
|
335
|
-
for (const sub of subscribers) {
|
|
336
|
-
if (i >= originalSize) break;
|
|
337
|
-
sub();
|
|
338
|
-
i++;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
let _traceListeners = null;
|
|
343
|
-
/** @internal — called from signal.set() when tracing is active */
|
|
344
|
-
function _notifyTraceListeners(sig, prev, next) {
|
|
345
|
-
if (!_traceListeners) return;
|
|
346
|
-
const event = {
|
|
347
|
-
signal: sig,
|
|
348
|
-
name: sig.label,
|
|
349
|
-
prev,
|
|
350
|
-
next,
|
|
351
|
-
stack: (/* @__PURE__ */ new Error()).stack ?? "",
|
|
352
|
-
timestamp: performance.now()
|
|
353
|
-
};
|
|
354
|
-
for (const l of _traceListeners) l(event);
|
|
355
|
-
}
|
|
356
|
-
/** Check if any trace listeners are active (fast path for signal.set) */
|
|
357
|
-
function isTracing() {
|
|
358
|
-
return _traceListeners !== null;
|
|
359
|
-
}
|
|
360
|
-
function _peek() {
|
|
361
|
-
return this._v;
|
|
362
|
-
}
|
|
363
|
-
function _set(newValue) {
|
|
364
|
-
if (Object.is(this._v, newValue)) return;
|
|
365
|
-
const prev = this._v;
|
|
366
|
-
this._v = newValue;
|
|
367
|
-
if (isTracing()) _notifyTraceListeners(this, prev, newValue);
|
|
368
|
-
if (this._d) notifyDirect(this._d);
|
|
369
|
-
if (this._s) notifySubscribers(this._s);
|
|
370
|
-
}
|
|
371
|
-
function _update(fn) {
|
|
372
|
-
_set.call(this, fn(this._v));
|
|
373
|
-
}
|
|
374
|
-
function _subscribe(listener) {
|
|
375
|
-
if (!this._s) this._s = /* @__PURE__ */ new Set();
|
|
376
|
-
this._s.add(listener);
|
|
377
|
-
return () => this._s?.delete(listener);
|
|
278
|
+
//#region src/PyreonUI.tsx
|
|
279
|
+
const _isBrowser = typeof window !== "undefined" && typeof matchMedia === "function";
|
|
280
|
+
/** Reactive signal tracking the OS dark mode preference. Lazy-initialized on first use. */
|
|
281
|
+
let _systemMode;
|
|
282
|
+
function getSystemMode() {
|
|
283
|
+
if (_systemMode) return _systemMode;
|
|
284
|
+
_systemMode = signal(_isBrowser && matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
|
285
|
+
if (_isBrowser) matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
|
286
|
+
_systemMode.set(e.matches ? "dark" : "light");
|
|
287
|
+
});
|
|
288
|
+
return _systemMode;
|
|
378
289
|
}
|
|
290
|
+
const ModeContext = createContext("light");
|
|
291
|
+
const INVERSED = {
|
|
292
|
+
light: "dark",
|
|
293
|
+
dark: "light"
|
|
294
|
+
};
|
|
379
295
|
/**
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
296
|
+
* Read the resolved color mode ("light" | "dark") from the nearest PyreonUI.
|
|
297
|
+
* Reactive — updates when the mode prop changes or when OS preference changes
|
|
298
|
+
* (if mode="system").
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* const mode = useMode() // "light" | "dark"
|
|
383
302
|
*/
|
|
384
|
-
function
|
|
385
|
-
|
|
386
|
-
const arr = this._d;
|
|
387
|
-
const idx = arr.length;
|
|
388
|
-
arr.push(updater);
|
|
389
|
-
return () => {
|
|
390
|
-
arr[idx] = null;
|
|
391
|
-
};
|
|
303
|
+
function useMode() {
|
|
304
|
+
return useContext(ModeContext);
|
|
392
305
|
}
|
|
306
|
+
let _autoInitDone = false;
|
|
393
307
|
/**
|
|
394
|
-
*
|
|
395
|
-
*
|
|
308
|
+
* Ensure the CSS engine is initialized. If init() was called manually,
|
|
309
|
+
* this is a no-op. Otherwise, imports @pyreon/styler defaults.
|
|
310
|
+
* Called once on first PyreonUI mount.
|
|
396
311
|
*/
|
|
397
|
-
function
|
|
398
|
-
if (
|
|
399
|
-
|
|
400
|
-
if (fn) enqueuePendingNotification(fn);
|
|
401
|
-
}
|
|
402
|
-
else for (let i = 0; i < updaters.length; i++) updaters[i]?.();
|
|
403
|
-
}
|
|
404
|
-
function _debug() {
|
|
405
|
-
return {
|
|
406
|
-
name: this.label,
|
|
407
|
-
value: this._v,
|
|
408
|
-
subscriberCount: this._s?.size ?? 0
|
|
409
|
-
};
|
|
312
|
+
function autoInit() {
|
|
313
|
+
if (_autoInitDone) return;
|
|
314
|
+
_autoInitDone = true;
|
|
410
315
|
}
|
|
411
316
|
/**
|
|
412
|
-
*
|
|
317
|
+
* Unified provider for the Pyreon UI system.
|
|
318
|
+
*
|
|
319
|
+
* Replaces the need for separate UnistyleProvider, RocketstyleProvider,
|
|
320
|
+
* and ThemeProvider — one component, zero init.
|
|
413
321
|
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```tsx
|
|
324
|
+
* <PyreonUI theme={{ rootSize: 16, breakpoints: { xs: 0, sm: 576, md: 768 } }} mode="system">
|
|
325
|
+
* <App />
|
|
326
|
+
* </PyreonUI>
|
|
327
|
+
* ```
|
|
417
328
|
*/
|
|
418
|
-
function
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
329
|
+
function PyreonUI({ theme, mode = "light", inversed, children }) {
|
|
330
|
+
autoInit();
|
|
331
|
+
let resolvedMode;
|
|
332
|
+
if (mode === "system") resolvedMode = getSystemMode()();
|
|
333
|
+
else resolvedMode = mode;
|
|
334
|
+
if (inversed) resolvedMode = INVERSED[resolvedMode];
|
|
335
|
+
const enrichedTheme = enrichTheme(theme);
|
|
336
|
+
provide(ThemeContext, enrichedTheme);
|
|
337
|
+
provide(context, {
|
|
338
|
+
theme: enrichedTheme,
|
|
339
|
+
mode: resolvedMode,
|
|
340
|
+
isDark: resolvedMode === "dark",
|
|
341
|
+
isLight: resolvedMode === "light"
|
|
422
342
|
});
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
read._d = null;
|
|
426
|
-
read.peek = _peek;
|
|
427
|
-
read.set = _set;
|
|
428
|
-
read.update = _update;
|
|
429
|
-
read.subscribe = _subscribe;
|
|
430
|
-
read.direct = _directFn;
|
|
431
|
-
read.debug = _debug;
|
|
432
|
-
read.label = options?.name;
|
|
433
|
-
return read;
|
|
343
|
+
provide(ModeContext, resolvedMode);
|
|
344
|
+
return children ?? null;
|
|
434
345
|
}
|
|
435
346
|
|
|
347
|
+
//#endregion
|
|
348
|
+
//#region src/render.tsx
|
|
349
|
+
const render = (content, attachProps) => {
|
|
350
|
+
if (!content) return null;
|
|
351
|
+
const t = typeof content;
|
|
352
|
+
if (t === "string" || t === "number" || t === "boolean" || t === "bigint") return content;
|
|
353
|
+
if (Array.isArray(content)) return content;
|
|
354
|
+
if (typeof content === "function") return h(content, attachProps ?? {});
|
|
355
|
+
if (typeof content === "object") return content;
|
|
356
|
+
return content;
|
|
357
|
+
};
|
|
358
|
+
|
|
436
359
|
//#endregion
|
|
437
360
|
//#region src/useStableValue.ts
|
|
438
361
|
/**
|
|
@@ -555,5 +478,5 @@ const merge = (target, ...sources) => {
|
|
|
555
478
|
};
|
|
556
479
|
|
|
557
480
|
//#endregion
|
|
558
|
-
export { HTML_TAGS, HTML_TEXT_TAGS, Provider, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useStableValue };
|
|
481
|
+
export { HTML_TAGS, HTML_TEXT_TAGS, Provider, PyreonUI, compose, config, context, get, hoistNonReactStatics, init, isEmpty, isEqual, merge, omit, pick, render, set, throttle, useMode, useStableValue };
|
|
559
482
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/ui-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/pyreon/ui-system",
|
|
7
|
-
"directory": "packages/ui-core"
|
|
7
|
+
"directory": "packages/ui-system/ui-core"
|
|
8
8
|
},
|
|
9
9
|
"description": "Core utilities, config, and context for Pyreon UI System",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"sideEffects": false,
|
|
13
13
|
"exports": {
|
|
14
|
+
"bun": "./src/index.ts",
|
|
14
15
|
"source": "./src/index.ts",
|
|
15
16
|
"import": "./lib/index.js",
|
|
16
17
|
"types": "./lib/index.d.ts"
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
"LICENSE"
|
|
26
27
|
],
|
|
27
28
|
"engines": {
|
|
28
|
-
"node": ">=
|
|
29
|
+
"node": ">= 22"
|
|
29
30
|
},
|
|
30
31
|
"publishConfig": {
|
|
31
32
|
"access": "public"
|
|
@@ -37,11 +38,13 @@
|
|
|
37
38
|
"typecheck": "tsc --noEmit"
|
|
38
39
|
},
|
|
39
40
|
"peerDependencies": {
|
|
40
|
-
"@pyreon/core": "
|
|
41
|
-
"@pyreon/styler": "
|
|
41
|
+
"@pyreon/core": "^0.11.0",
|
|
42
|
+
"@pyreon/styler": "^0.11.0",
|
|
43
|
+
"@pyreon/reactivity": "^0.11.0",
|
|
44
|
+
"@pyreon/unistyle": "^0.11.0"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
44
47
|
"@vitus-labs/tools-rolldown": "^1.15.3",
|
|
45
|
-
"@pyreon/typescript": "^0.
|
|
48
|
+
"@pyreon/typescript": "^0.11.0"
|
|
46
49
|
}
|
|
47
50
|
}
|