ranui 0.2.0-alpha.6 → 0.2.1-alpha.1
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 +38 -3
- package/README.zh-CN.md +40 -10
- package/dist/arrow-down-Bi5kqUrX.js +12 -0
- package/dist/builder.d.ts +2 -2
- package/dist/builder.js +32 -28
- package/dist/builtin-D9djWkCE.js +409 -0
- package/dist/{button-Be_uHDZG.js → button-BfYw0fes.js} +1 -1
- package/dist/button.js +1 -1
- package/dist/{card-BVvXX6KM.js → card-CqJa4Q_v.js} +1 -1
- package/dist/card.js +1 -1
- package/dist/{checkbox-BtoX9X2Z.js → checkbox-CThC9-vy.js} +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/{colorpicker-Dukms7ET.js → colorpicker-XNxDRcQ-.js} +5 -6
- package/dist/colorpicker.js +1 -1
- package/dist/components/colorpicker/index.d.ts +3 -3
- package/dist/components/icon/builtin.d.ts +9 -0
- package/dist/components/icon/index.d.ts +8 -0
- package/dist/components/route/index.d.ts +10 -4
- package/dist/components/router/index.d.ts +3 -0
- package/dist/{dropdown-BYS1Trdu.js → dropdown-CCvsambb.js} +1 -1
- package/dist/dropdown.js +1 -1
- package/dist/factory-DCrO37si.js +334 -0
- package/dist/{form-BsB5JhS4.js → form-Ceq3uJzz.js} +1 -1
- package/dist/form.js +1 -1
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +6 -0
- package/dist/{icon-pfolda2m.js → icon-C_ENrJ3F.js} +50 -13
- package/dist/icon.js +4 -3
- package/dist/icons.js +5 -0
- package/dist/iife/button.iife.js +1 -1
- package/dist/iife/card.iife.js +1 -1
- package/dist/iife/checkbox.iife.js +1 -1
- package/dist/iife/colorpicker.iife.js +2 -2
- package/dist/iife/dropdown.iife.js +1 -1
- package/dist/iife/form.iife.js +1 -1
- package/dist/iife/icon.iife.js +1 -1
- package/dist/iife/image.iife.js +1 -1
- package/dist/iife/input.iife.js +1 -1
- package/dist/iife/loading.iife.js +1 -1
- package/dist/iife/math.iife.js +14 -14
- package/dist/iife/message.iife.js +1 -1
- package/dist/iife/modal.iife.js +1 -1
- package/dist/iife/player.iife.js +8 -8
- package/dist/iife/popover.iife.js +1 -1
- package/dist/iife/progress.iife.js +1 -1
- package/dist/iife/radar.iife.js +1 -1
- package/dist/iife/route.iife.js +1 -1
- package/dist/iife/router.iife.js +1 -1
- package/dist/iife/scratch.iife.js +1 -1
- package/dist/iife/section.iife.js +1 -1
- package/dist/iife/select.iife.js +2 -2
- package/dist/iife/skeleton.iife.js +1 -1
- package/dist/iife/tab.iife.js +1 -1
- package/dist/iife/tabpane.iife.js +1 -1
- package/dist/{image-BXpKQ9sU.js → image-B7MBI5n_.js} +1 -1
- package/dist/image.js +1 -1
- package/dist/index.cjs +256 -23
- package/dist/index.d.ts +3 -1
- package/dist/index.iife.js +266 -33
- package/dist/index.js +79 -74
- package/dist/{input-BMMM60e6.js → input-RNqdEHPf.js} +2 -2
- package/dist/input.js +1 -1
- package/dist/{loading-BScjyeVm.js → loading-B9MFI03l.js} +1 -1
- package/dist/loading.js +1 -1
- package/dist/{math-IjzOAwnA.js → math-CudIwEXZ.js} +1 -1
- package/dist/math.js +1 -1
- package/dist/{message-CLpuP8HY.js → message-DW7qWpEm.js} +34 -49
- package/dist/message.js +1 -1
- package/dist/{modal-DOTpABRe.js → modal-CrvGKL2B.js} +1 -1
- package/dist/modal.js +1 -1
- package/dist/{player-5olrw-qB.js → player-BKQaaT7o.js} +2 -2
- package/dist/player.js +1 -1
- package/dist/{popover-DRUQjdPs.js → popover-CvYIVgUS.js} +2 -2
- package/dist/popover.js +1 -1
- package/dist/{progress-BIEXYYd2.js → progress-C6jctsFH.js} +1 -1
- package/dist/progress.js +1 -1
- package/dist/{radar-DAF95_Mj.js → radar-BUb4EzmG.js} +1 -1
- package/dist/radar.js +1 -1
- package/dist/route-Djrf9UR_.js +116 -0
- package/dist/route.js +1 -1
- package/dist/{router-B9rCrWXm.js → router-BU2KhtxV.js} +22 -17
- package/dist/router.js +1 -1
- package/dist/{scratch-QlPyy1f4.js → scratch-CO4I2dIa.js} +1 -1
- package/dist/scratch.js +1 -1
- package/dist/{section-D0qMm9KM.js → section-CsUkp8bv.js} +1 -1
- package/dist/section.js +1 -1
- package/dist/{select-aAaWoveE.js → select-Dn26ajJZ.js} +8 -15
- package/dist/select.js +1 -1
- package/dist/{skeleton-CFqQmKyt.js → skeleton-BuMLhvzQ.js} +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/{tab-CiF2YPck.js → tab-40fDkuox.js} +1 -1
- package/dist/tab.js +1 -1
- package/dist/{tabpane-B-m3xwqu.js → tabpane-F4Pd7JtC.js} +1 -1
- package/dist/tabpane.js +1 -1
- package/dist/test/unit/icon.builtin.test.d.ts +1 -0
- package/dist/test/unit/utils.colorpicker.reconnect.test.d.ts +1 -0
- package/dist/test/unit/utils.route.lazy.test.d.ts +1 -0
- package/dist/test/unit/utils.router.match.test.d.ts +1 -0
- package/dist/test/unit/utils.signal.owner.test.d.ts +1 -0
- package/dist/theme-kOWZbKCq.js +70 -0
- package/dist/theme-switch-B09egc6h.js +104 -0
- package/dist/theme-switch.js +1 -1
- package/dist/theme.d.ts +2 -0
- package/dist/theme.js +9 -0
- package/dist/utils/builder/core.d.ts +20 -13
- package/dist/utils/builder/factory.d.ts +1 -1
- package/dist/utils/builder/index.d.ts +2 -2
- package/dist/utils/builder/signal.d.ts +93 -64
- package/dist/utils/i18n/index.d.ts +17 -1
- package/dist/utils/i18n.js +16 -15
- package/dist/utils/router/index.d.ts +13 -3
- package/dist/utils/router.js +95 -54
- package/dist/utils/theme.d.ts +1 -1
- package/dist/warning-circle-fill-Cz0qu7AH.js +23 -0
- package/docs/BUILDER.md +230 -0
- package/docs/COMPONENTS.md +21 -3
- package/package.json +41 -3
- package/dist/factory-BdsO0dEW.js +0 -165
- package/dist/route-MQZpn2BP.js +0 -88
- package/dist/signal-CSSZxlK5.js +0 -57
- package/dist/theme-switch-B_FZvqBN.js +0 -170
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { a as i, i as o, n as h, r as c, t as l } from "./utils-DBfrRFoE.js";
|
|
2
|
+
import { t as d } from "./events-C59wGdni.js";
|
|
3
|
+
import { a as u, n as m } from "./ssr-DSGwPtEd.js";
|
|
4
|
+
import { i as b, n as v } from "./theme-kOWZbKCq.js";
|
|
5
|
+
var g = ".remove-wap-active-focus{outline:0;-webkit-tap-highlight-color:transparent}.remove-wap-active-focus:active,.remove-wap-active-focus:focus{outline:0;-webkit-tap-highlight-color:transparent}:host{display:var(--ran-theme-switch-display, inline-flex);box-sizing:border-box}.ran-theme-switch{display:inline-flex;align-items:center;gap:var(--ran-theme-switch-gap, 2px);padding:var(--ran-theme-switch-padding, 2px);border-width:var(--ran-skin-border-width, 1px);border-style:var(--ran-skin-border-style, solid);border-color:var(--ran-theme-switch-border-color, var(--ran-color-border, #eaeaea));border-radius:var(--ran-theme-switch-radius, var(--ran-radius-full, 9999px));background:var(--ran-theme-switch-background, transparent);box-sizing:border-box}.ran-theme-switch button{width:var(--ran-theme-switch-button-size, 28px);height:var(--ran-theme-switch-button-size, 28px);display:grid;place-items:center;border:none;border-radius:var(--ran-theme-switch-radius, var(--ran-radius-full, 9999px));background:transparent;color:var(--ran-theme-switch-color, var(--ran-color-text-secondary, #4d4d4d));cursor:pointer;padding:0}.ran-theme-switch button:hover{color:var(--ran-theme-switch-hover-color, var(--ran-color-text, #171717))}.ran-theme-switch button[aria-pressed=true]{background:var(--ran-theme-switch-active-background, var(--ran-color-bg-hover, #ebebeb));color:var(--ran-theme-switch-active-color, var(--ran-color-text, #171717))}.ran-theme-switch button:focus-visible{outline:var(--ran-theme-switch-focus-outline, 2px solid var(--ran-color-primary, #006bff));outline-offset:2px}.ran-theme-switch svg{width:var(--ran-theme-switch-icon-size, 16px);height:var(--ran-theme-switch-icon-size, 16px)}", a = [
|
|
6
|
+
"system",
|
|
7
|
+
"light",
|
|
8
|
+
"dark"
|
|
9
|
+
], p = {
|
|
10
|
+
system: '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.5" y="2.5" width="13" height="9" rx="1.5" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M5.5 14h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
11
|
+
light: '<svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="3" fill="none" stroke="currentColor" stroke-width="1.5"/><path d="M8 1v1.8M8 13.2V15M15 8h-1.8M2.8 8H1m11.4-4.4-1.3 1.3M4.9 11.1l-1.3 1.3m9.8 0-1.3-1.3M4.9 4.9 3.6 3.6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>',
|
|
12
|
+
dark: '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M13.5 9.5A6 6 0 0 1 6.5 2.5a6 6 0 1 0 7 7z" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/></svg>'
|
|
13
|
+
}, s = "ran-theme-switch-sync", w = class extends m {
|
|
14
|
+
static get observedAttributes() {
|
|
15
|
+
return [
|
|
16
|
+
"label-system",
|
|
17
|
+
"label-light",
|
|
18
|
+
"label-dark",
|
|
19
|
+
"sheet"
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
_events = new d();
|
|
23
|
+
_shadowDom;
|
|
24
|
+
_group;
|
|
25
|
+
constructor() {
|
|
26
|
+
super(), this._shadowDom = h(this, g), this._group = l(this._shadowDom, ".ran-theme-switch", () => {
|
|
27
|
+
const e = document.createElement("div");
|
|
28
|
+
e.className = "ran-theme-switch", e.setAttribute("part", "switch"), e.setAttribute("role", "group");
|
|
29
|
+
for (const t of a) {
|
|
30
|
+
const r = document.createElement("button");
|
|
31
|
+
r.type = "button", r.dataset.choice = t, r.setAttribute("part", `button ${t}`), r.setAttribute("aria-pressed", "false"), r.innerHTML = p[t], e.appendChild(r);
|
|
32
|
+
}
|
|
33
|
+
return e;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
get sheet() {
|
|
37
|
+
return c(this, "sheet");
|
|
38
|
+
}
|
|
39
|
+
set sheet(e) {
|
|
40
|
+
o(this, "sheet", e);
|
|
41
|
+
}
|
|
42
|
+
get value() {
|
|
43
|
+
return v() || "system";
|
|
44
|
+
}
|
|
45
|
+
set value(e) {
|
|
46
|
+
a.includes(e) && this._select(e);
|
|
47
|
+
}
|
|
48
|
+
_label(e) {
|
|
49
|
+
const t = {
|
|
50
|
+
system: "System theme",
|
|
51
|
+
light: "Light theme",
|
|
52
|
+
dark: "Dark theme"
|
|
53
|
+
}[e];
|
|
54
|
+
return this.getAttribute(`label-${e}`) || t;
|
|
55
|
+
}
|
|
56
|
+
_syncLabels() {
|
|
57
|
+
this._group.setAttribute("aria-label", this.getAttribute("label") || "Theme");
|
|
58
|
+
for (const e of this._group.querySelectorAll("button")) e.setAttribute("aria-label", this._label(e.dataset.choice));
|
|
59
|
+
}
|
|
60
|
+
_reflect() {
|
|
61
|
+
const e = this.value;
|
|
62
|
+
for (const t of this._group.querySelectorAll("button")) t.setAttribute("aria-pressed", t.dataset.choice === e ? "true" : "false");
|
|
63
|
+
}
|
|
64
|
+
_select(e) {
|
|
65
|
+
b(e), this._reflect(), this._syncMeta(e), document.dispatchEvent(new CustomEvent(s)), this.dispatchEvent(new CustomEvent("change", {
|
|
66
|
+
detail: { theme: e },
|
|
67
|
+
bubbles: !0,
|
|
68
|
+
composed: !0
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
_syncMeta(e) {
|
|
72
|
+
if (typeof requestAnimationFrame > "u") return;
|
|
73
|
+
const t = document.querySelectorAll('meta[name="theme-color"]');
|
|
74
|
+
t.length && requestAnimationFrame(() => {
|
|
75
|
+
for (const r of t)
|
|
76
|
+
if (r.dataset.ranOriginalContent === void 0 && (r.dataset.ranOriginalContent = r.getAttribute("content") || ""), e === "system") r.setAttribute("content", r.dataset.ranOriginalContent);
|
|
77
|
+
else {
|
|
78
|
+
const n = getComputedStyle(document.documentElement).getPropertyValue("--ran-color-bg").trim() || getComputedStyle(document.body).backgroundColor;
|
|
79
|
+
r.setAttribute("content", n);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
_handleClick = (e) => {
|
|
84
|
+
const t = e.target.closest?.("button")?.dataset.choice;
|
|
85
|
+
t && a.includes(t) && this._select(t);
|
|
86
|
+
};
|
|
87
|
+
_handleSync = () => this._reflect();
|
|
88
|
+
handlerExternalCss = () => {
|
|
89
|
+
i(this, this._shadowDom, "sheet", null, this.sheet);
|
|
90
|
+
};
|
|
91
|
+
connectedCallback() {
|
|
92
|
+
this.handlerExternalCss(), this._syncLabels(), this._reflect(), this._events.on(this._group, "click", this._handleClick), document.addEventListener(s, this._handleSync), typeof window < "u" && window.addEventListener("storage", this._handleSync);
|
|
93
|
+
}
|
|
94
|
+
disconnectedCallback() {
|
|
95
|
+
this._events.abort(), document.removeEventListener(s, this._handleSync), typeof window < "u" && window.removeEventListener("storage", this._handleSync);
|
|
96
|
+
}
|
|
97
|
+
attributeChangedCallback(e, t, r) {
|
|
98
|
+
t !== r && (e === "sheet" && this.handlerExternalCss(), e.startsWith("label") && this._syncLabels());
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
u("r-theme-switch", w);
|
|
102
|
+
export {
|
|
103
|
+
w as t
|
|
104
|
+
};
|
package/dist/theme-switch.js
CHANGED
package/dist/theme.d.ts
ADDED
package/dist/theme.js
ADDED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EventManager } from './events';
|
|
2
|
+
import { type Getter } from './signal';
|
|
2
3
|
export interface Ref<T extends HTMLElement = HTMLElement> {
|
|
3
4
|
current: T | null;
|
|
4
5
|
}
|
|
@@ -7,22 +8,28 @@ export declare class ElementBuilder<T extends HTMLElement = HTMLElement> {
|
|
|
7
8
|
private el;
|
|
8
9
|
constructor(tag: string);
|
|
9
10
|
id(value: string): this;
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Apply a value now, or bind it reactively when a getter is passed.
|
|
13
|
+
* A getter creates an effect owned by the current reactive scope (createRoot),
|
|
14
|
+
* so the binding is disposed automatically when that scope is torn down.
|
|
15
|
+
*/
|
|
16
|
+
private bind;
|
|
17
|
+
class(name: string | Getter<string>): this;
|
|
11
18
|
addClass(...names: string[]): this;
|
|
12
19
|
removeClass(...names: string[]): this;
|
|
13
|
-
attr(name: string, value: string): this;
|
|
20
|
+
attr(name: string, value: string | Getter<string>): this;
|
|
14
21
|
attrs(values: Record<string, string | number | boolean | null | undefined>): this;
|
|
15
|
-
boolAttr(name: string, value: boolean
|
|
16
|
-
part(value: string): this;
|
|
17
|
-
data(key: string, value: string): this;
|
|
18
|
-
style(keyOrMap: string | Record<string, string>, value?: string): this;
|
|
19
|
-
cssVar(name: string, value: string): this;
|
|
20
|
-
aria(key: string, value: string): this;
|
|
21
|
-
role(value: string): this;
|
|
22
|
+
boolAttr(name: string, value: boolean | Getter<boolean>, enabledValue?: string): this;
|
|
23
|
+
part(value: string | Getter<string>): this;
|
|
24
|
+
data(key: string, value: string | Getter<string>): this;
|
|
25
|
+
style(keyOrMap: string | Record<string, string>, value?: string | Getter<string>): this;
|
|
26
|
+
cssVar(name: string, value: string | Getter<string>): this;
|
|
27
|
+
aria(key: string, value: string | Getter<string>): this;
|
|
28
|
+
role(value: string | Getter<string>): this;
|
|
22
29
|
tabIndex(value: number): this;
|
|
23
|
-
label(value: string): this;
|
|
24
|
-
labelledBy(id: string): this;
|
|
25
|
-
describedBy(id: string): this;
|
|
30
|
+
label(value: string | Getter<string>): this;
|
|
31
|
+
labelledBy(id: string | Getter<string>): this;
|
|
32
|
+
describedBy(id: string | Getter<string>): this;
|
|
26
33
|
ariaHidden(hidden?: boolean): this;
|
|
27
34
|
/**
|
|
28
35
|
* Permanent build-time listener — tied to the element's lifetime.
|
|
@@ -48,7 +55,7 @@ export declare class ElementBuilder<T extends HTMLElement = HTMLElement> {
|
|
|
48
55
|
delegate<K extends keyof HTMLElementEventMap>(manager: EventManager, selector: string, type: K, handler: (ev: HTMLElementEventMap[K], target: Element) => void, options?: Omit<AddEventListenerOptions, 'signal'>): this;
|
|
49
56
|
children(...items: (HTMLElement | string | ElementBuilder<any> | undefined | null | (HTMLElement | string | ElementBuilder<any> | undefined | null)[])[]): this;
|
|
50
57
|
replaceChildren(...items: (HTMLElement | string | ElementBuilder<any> | undefined | null | (HTMLElement | string | ElementBuilder<any> | undefined | null)[])[]): this;
|
|
51
|
-
text(value: string): this;
|
|
58
|
+
text(value: string | Getter<string>): this;
|
|
52
59
|
ref(holder: Ref<T>): this;
|
|
53
60
|
shadow(options?: ShadowRootInit): ShadowBuilder<T>;
|
|
54
61
|
build(): T;
|
|
@@ -15,4 +15,4 @@ export declare const Nav: () => ElementBuilder<HTMLElement>;
|
|
|
15
15
|
export declare const Header: () => ElementBuilder<HTMLElement>;
|
|
16
16
|
export declare const Footer: () => ElementBuilder<HTMLElement>;
|
|
17
17
|
export declare const Main: () => ElementBuilder<HTMLElement>;
|
|
18
|
-
export declare const DeclarativeShadow: (mode?:
|
|
18
|
+
export declare const DeclarativeShadow: (mode?: 'open' | 'closed', delegatesFocus?: boolean) => ElementBuilder<HTMLTemplateElement>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { isSSR } from './env';
|
|
2
2
|
export { EventManager } from './events';
|
|
3
|
-
export { signal, createEffect, computed, batch } from './signal';
|
|
4
|
-
export type { Getter, Setter, SignalOptions } from './signal';
|
|
3
|
+
export { signal, createEffect, computed, batch, untrack, createRoot, onCleanup, getOwner, runWithOwner, } from './signal';
|
|
4
|
+
export type { Getter, Setter, SignalOptions, Owner } from './signal';
|
|
5
5
|
export { escapeHtml, escapeHtmlAttribute } from './escape';
|
|
6
6
|
export { type MockNode, matchSelector, collectMatches } from './selectors';
|
|
7
7
|
export { DocumentFragmentMock, HTMLElementMock, ShadowRootMock } from './mocks';
|
|
@@ -1,87 +1,116 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reactive primitives — signal /
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* computed
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
2
|
+
* Reactive primitives — signal / computed / createEffect / batch, plus an
|
|
3
|
+
* ownership layer (createRoot / onCleanup / getOwner / runWithOwner) and untrack.
|
|
4
|
+
*
|
|
5
|
+
* Design reference: SwiftUI @Observable + Solid.js fine-grained reactivity.
|
|
6
|
+
*
|
|
7
|
+
* View = f(State)
|
|
8
|
+
* signal — reactive source (@State)
|
|
9
|
+
* computed — derived, LAZY + memoized (SwiftUI computed property / Solid memo)
|
|
10
|
+
* createEffect— side effect that re-runs when its reads change (≈ body)
|
|
11
|
+
* ownership — effects/memos form an owner tree; disposing a scope disposes
|
|
12
|
+
* everything created under it (critical for MPA: tear down a page
|
|
13
|
+
* and every effect it spawned is cleaned up in one call).
|
|
14
|
+
*
|
|
15
|
+
* Model (push-pull scheduling + lazy memos):
|
|
16
|
+
* - Reading a source inside a computation links them both ways.
|
|
17
|
+
* - Writing a signal marks direct observers DIRTY and their transitive memo
|
|
18
|
+
* observers CHECK ("maybe dirty"), scheduling any dependent effects. Effects
|
|
19
|
+
* flush once (deduped — diamond dependencies run an effect a single time).
|
|
20
|
+
* - Memos recompute lazily on read, and only re-notify their observers when
|
|
21
|
+
* their derived value actually changes (via `equals`). A CHECK computation
|
|
22
|
+
* first pulls its sources up to date; if none changed value, it is skipped —
|
|
23
|
+
* so a memo whose output is stable never wakes the effects behind it.
|
|
24
|
+
* - Every computation is owned; re-running or disposing it first disposes its
|
|
25
|
+
* owned children and runs its cleanups (no leaked nested effects).
|
|
23
26
|
*/
|
|
24
27
|
export type Getter<T> = () => T;
|
|
25
28
|
export type Setter<T> = (value: T | ((prev: T) => T)) => void;
|
|
26
29
|
export interface SignalOptions<T> {
|
|
27
|
-
/** Custom equality
|
|
30
|
+
/** Custom equality. Defaults to Object.is. Return true to skip the update. */
|
|
28
31
|
equals?: (prev: T, next: T) => boolean;
|
|
29
32
|
}
|
|
33
|
+
/** Anything a computation can subscribe to (a signal, or a memo). */
|
|
34
|
+
interface SourceLike {
|
|
35
|
+
observers: Set<Computation>;
|
|
36
|
+
}
|
|
37
|
+
/** Staleness of a computation. CLEAN → up to date; CHECK → a memo source may
|
|
38
|
+
* have changed (verify before recomputing); DIRTY → definitely recompute. */
|
|
39
|
+
declare const CLEAN = 0;
|
|
40
|
+
declare const CHECK = 1;
|
|
41
|
+
declare const DIRTY = 2;
|
|
42
|
+
type State = typeof CLEAN | typeof CHECK | typeof DIRTY;
|
|
43
|
+
/** An effect or a memo — a node that runs a function and tracks its reads. */
|
|
44
|
+
interface Computation extends Owner {
|
|
45
|
+
fn: () => unknown;
|
|
46
|
+
/** Sources (signals / memos) read during the last run. */
|
|
47
|
+
sources: Set<SourceLike>;
|
|
48
|
+
isEffect: boolean;
|
|
49
|
+
running: boolean;
|
|
50
|
+
disposed: boolean;
|
|
51
|
+
state: State;
|
|
52
|
+
observers: Set<Computation>;
|
|
53
|
+
value: unknown;
|
|
54
|
+
equals: (a: unknown, b: unknown) => boolean;
|
|
55
|
+
}
|
|
56
|
+
/** A node that can own child computations + cleanups (effect, memo, or root). */
|
|
57
|
+
export interface Owner {
|
|
58
|
+
owned: Computation[];
|
|
59
|
+
cleanups: Array<() => void>;
|
|
60
|
+
owner: Owner | null;
|
|
61
|
+
}
|
|
30
62
|
/**
|
|
31
|
-
* Create a reactive value. Returns a [getter, setter] tuple.
|
|
63
|
+
* Create a reactive value. Returns a `[getter, setter]` tuple.
|
|
32
64
|
*
|
|
33
65
|
* const [count, setCount] = signal(0);
|
|
34
|
-
* count()
|
|
35
|
-
* setCount(1)
|
|
36
|
-
* setCount(n => n + 1) // updater
|
|
66
|
+
* count(); // read — auto-tracked inside computed / createEffect
|
|
67
|
+
* setCount(1); // write — notifies dependents; skipped if unchanged
|
|
68
|
+
* setCount((n) => n + 1) // updater form
|
|
37
69
|
*/
|
|
38
70
|
export declare function signal<T>(initial: T, options?: SignalOptions<T>): [Getter<T>, Setter<T>];
|
|
39
71
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
72
|
+
* Derived, read-only, LAZY + memoized value. Recomputes only when read after a
|
|
73
|
+
* dependency changed; unread memos never recompute. When a recompute produces an
|
|
74
|
+
* equal value (default `Object.is`, override via `options.equals`) the memo does
|
|
75
|
+
* NOT notify its observers — so effects behind a value-stable memo stay asleep.
|
|
76
|
+
* Owned by the current scope, so it is disposed when that scope is.
|
|
77
|
+
*
|
|
78
|
+
* const fullName = computed(() => `${first()} ${last()}`);
|
|
79
|
+
* fullName(); // computes on first read, caches until a dep's value changes
|
|
80
|
+
*/
|
|
81
|
+
export declare function computed<T>(fn: () => T, options?: SignalOptions<T>): Getter<T>;
|
|
82
|
+
/**
|
|
83
|
+
* Run `fn` immediately, then re-run it whenever a signal/memo it read changes.
|
|
84
|
+
* Owned by the current scope. `fn` may return a cleanup, called before each
|
|
85
|
+
* re-run and on dispose. Returns a dispose function.
|
|
48
86
|
*
|
|
49
87
|
* const dispose = createEffect(() => {
|
|
50
|
-
*
|
|
51
|
-
* return () => {
|
|
88
|
+
* el.textContent = `Count: ${count()}`;
|
|
89
|
+
* return () => {}; // optional cleanup
|
|
52
90
|
* });
|
|
53
|
-
*
|
|
54
|
-
* dispose(); // stop tracking, remove from all signals
|
|
55
91
|
*/
|
|
56
92
|
export declare function createEffect(fn: () => void | (() => void)): () => void;
|
|
57
93
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* const [firstName, setFirstName] = signal('Jane');
|
|
61
|
-
* const [lastName, setLastName] = signal('Doe');
|
|
62
|
-
* const fullName = computed(() => `${firstName()} ${lastName()}`);
|
|
63
|
-
*
|
|
64
|
-
* fullName() // 'Jane Doe'
|
|
65
|
-
* setFirstName('John');
|
|
66
|
-
* fullName() // 'John Doe'
|
|
94
|
+
* Coalesce multiple writes into one flush. Effects run once after `fn` returns,
|
|
95
|
+
* deduplicated. Nested batches are absorbed by the outermost one.
|
|
67
96
|
*/
|
|
68
|
-
export declare function
|
|
97
|
+
export declare function batch(fn: () => void): void;
|
|
98
|
+
/** Read signals without subscribing the current computation to them. */
|
|
99
|
+
export declare function untrack<T>(fn: () => T): T;
|
|
69
100
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
101
|
+
* Create a disposable reactive scope. Effects/memos created inside are owned by
|
|
102
|
+
* it; calling the passed `dispose` tears them all down. Use one per page/route
|
|
103
|
+
* in an MPA/SPA so navigating away cleans up every effect that page spawned.
|
|
72
104
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* setFirstName('John');
|
|
77
|
-
* setLastName('Smith');
|
|
78
|
-
*
|
|
79
|
-
* // With batch: one flush after both writes (1 run)
|
|
80
|
-
* batch(() => {
|
|
81
|
-
* setFirstName('John');
|
|
82
|
-
* setLastName('Smith');
|
|
83
|
-
* });
|
|
84
|
-
*
|
|
85
|
-
* Nested batch() calls are safe — inner calls are absorbed by the outer batch.
|
|
105
|
+
* const dispose = createRoot((dispose) => { renderPage(); return dispose; });
|
|
106
|
+
* // ...later, on navigation:
|
|
107
|
+
* dispose();
|
|
86
108
|
*/
|
|
87
|
-
export declare function
|
|
109
|
+
export declare function createRoot<T>(fn: (dispose: () => void) => T): T;
|
|
110
|
+
/** Register a cleanup on the current scope, run when it re-runs or is disposed. */
|
|
111
|
+
export declare function onCleanup(fn: () => void): void;
|
|
112
|
+
/** The current owner scope (for advanced integrations, e.g. a router). */
|
|
113
|
+
export declare function getOwner(): Owner | null;
|
|
114
|
+
/** Run `fn` under a specific owner scope (pairs with getOwner). */
|
|
115
|
+
export declare function runWithOwner<T>(owner: Owner | null, fn: () => T): T;
|
|
116
|
+
export {};
|
|
@@ -37,9 +37,25 @@ export declare class I18nCore {
|
|
|
37
37
|
get availableLocales(): string[];
|
|
38
38
|
/**
|
|
39
39
|
* Translate a key against the active locale, falling back to the fallback
|
|
40
|
-
* locale and finally the key itself. `{param}` placeholders are interpolated
|
|
40
|
+
* locale and finally the key itself. `{param}` placeholders are interpolated;
|
|
41
|
+
* `{{` / `}}` are escapes for literal `{` / `}` (see {@link I18nCore._interpolate}).
|
|
41
42
|
*/
|
|
42
43
|
t(key: string, params?: TranslateParams): string;
|
|
44
|
+
/**
|
|
45
|
+
* Substitute `{param}` placeholders and unescape literal braces.
|
|
46
|
+
*
|
|
47
|
+
* Grammar (a single left-to-right pass, so escapes and placeholders never
|
|
48
|
+
* fight each other), matching the format-string convention used by Rust
|
|
49
|
+
* `format!`, Python `str.format`, and .NET `String.Format`:
|
|
50
|
+
* - `{{` → literal `{`
|
|
51
|
+
* - `}}` → literal `}`
|
|
52
|
+
* - `{name}` → `params.name` (stringified), or left untouched when the param
|
|
53
|
+
* is absent, so a stray placeholder is visible rather than silently blank.
|
|
54
|
+
*
|
|
55
|
+
* A lone `{`/`}` or a `{ spaced }` group is not a placeholder and is emitted
|
|
56
|
+
* verbatim, so CSS/JSON/code fragments in a message pass through unharmed.
|
|
57
|
+
* To wrap a value in literal braces, double the outer pair: `{{{name}}}`.
|
|
58
|
+
*/
|
|
43
59
|
private _interpolate;
|
|
44
60
|
/** Subscribe to locale changes. Returns an unsubscribe function. */
|
|
45
61
|
onChange(handler: LocaleChangeHandler): () => void;
|
package/dist/utils/i18n.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
var
|
|
1
|
+
var n = "ran-locale", i = Object.freeze({}), o = (e) => {
|
|
2
2
|
if (typeof localStorage > "u") return null;
|
|
3
3
|
try {
|
|
4
4
|
return localStorage.getItem(e);
|
|
5
5
|
} catch {
|
|
6
6
|
return null;
|
|
7
7
|
}
|
|
8
|
-
},
|
|
8
|
+
}, _ = (e, t) => {
|
|
9
9
|
if (!(typeof localStorage > "u"))
|
|
10
10
|
try {
|
|
11
11
|
localStorage.setItem(e, t);
|
|
12
12
|
} catch {
|
|
13
13
|
}
|
|
14
|
-
},
|
|
14
|
+
}, c = (e) => {
|
|
15
15
|
if (typeof navigator > "u" || !navigator.language) return null;
|
|
16
16
|
const t = navigator.language.toLowerCase();
|
|
17
17
|
return e.find((s) => s.toLowerCase() === t) ?? e.find((s) => t.startsWith(s.toLowerCase())) ?? e.find((s) => t.startsWith(`${s.toLowerCase()}-`)) ?? null;
|
|
18
|
-
},
|
|
18
|
+
}, h = class {
|
|
19
19
|
_locale;
|
|
20
20
|
_fallback;
|
|
21
21
|
_messages;
|
|
@@ -23,14 +23,14 @@ var l = "ran-locale", n = (e) => {
|
|
|
23
23
|
_storageKey;
|
|
24
24
|
_handlers = /* @__PURE__ */ new Set();
|
|
25
25
|
constructor(e = {}) {
|
|
26
|
-
this._messages = { ...e.messages }, this._fallback = e.fallbackLocale ?? "en", this._persist = e.persist ?? !1, this._storageKey = e.storageKey ??
|
|
26
|
+
this._messages = { ...e.messages }, this._fallback = e.fallbackLocale ?? "en", this._persist = e.persist ?? !1, this._storageKey = e.storageKey ?? n, this._locale = this._resolveInitialLocale(e);
|
|
27
27
|
}
|
|
28
28
|
_resolveInitialLocale(e) {
|
|
29
|
-
const t = Object.keys(this._messages), s = this._persist ?
|
|
29
|
+
const t = Object.keys(this._messages), s = this._persist ? o(this._storageKey) : null;
|
|
30
30
|
if (s && (this._messages[s] || t.length === 0)) return s;
|
|
31
31
|
if (e.locale) return e.locale;
|
|
32
32
|
if (e.detectNavigator) {
|
|
33
|
-
const r =
|
|
33
|
+
const r = c(t);
|
|
34
34
|
if (r) return r;
|
|
35
35
|
}
|
|
36
36
|
return this._fallback;
|
|
@@ -42,7 +42,7 @@ var l = "ran-locale", n = (e) => {
|
|
|
42
42
|
return this._locale;
|
|
43
43
|
}
|
|
44
44
|
setLocale(e) {
|
|
45
|
-
e !== this._locale && (this._locale = e, this._persist &&
|
|
45
|
+
e !== this._locale && (this._locale = e, this._persist && _(this._storageKey, e), this._notify());
|
|
46
46
|
}
|
|
47
47
|
addMessages(e, t) {
|
|
48
48
|
this._messages[e] = {
|
|
@@ -61,7 +61,8 @@ var l = "ran-locale", n = (e) => {
|
|
|
61
61
|
return this._interpolate(s, t);
|
|
62
62
|
}
|
|
63
63
|
_interpolate(e, t) {
|
|
64
|
-
|
|
64
|
+
const s = t ?? i;
|
|
65
|
+
return e.replace(/\{\{|\}\}|\{(\w+)\}/g, (r, l) => r === "{{" ? "{" : r === "}}" ? "}" : s[l] != null ? String(s[l]) : r);
|
|
65
66
|
}
|
|
66
67
|
onChange(e) {
|
|
67
68
|
return this._handlers.add(e), () => {
|
|
@@ -75,14 +76,14 @@ var l = "ran-locale", n = (e) => {
|
|
|
75
76
|
this._handlers.clear();
|
|
76
77
|
}
|
|
77
78
|
}, a = null;
|
|
78
|
-
function
|
|
79
|
-
return a = new
|
|
79
|
+
function u(e = {}) {
|
|
80
|
+
return a = new h(e), a;
|
|
80
81
|
}
|
|
81
|
-
function
|
|
82
|
+
function g() {
|
|
82
83
|
return a;
|
|
83
84
|
}
|
|
84
85
|
export {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
h as I18nCore,
|
|
87
|
+
u as createI18n,
|
|
88
|
+
g as useI18n
|
|
88
89
|
};
|
|
@@ -55,10 +55,19 @@ export interface RouterComponentElement extends HTMLElement {
|
|
|
55
55
|
export declare function getSSGPath(): string | null;
|
|
56
56
|
export declare function setSSGPath(path: string): void;
|
|
57
57
|
export declare function clearSSGPath(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Match a route pattern (with `:param` and `*` segments) against a path.
|
|
60
|
+
* Single source of truth shared by RouterCore and the `<r-route>` element.
|
|
61
|
+
*/
|
|
62
|
+
export declare function matchPath(routePath: string, exact: boolean, path: string): {
|
|
63
|
+
matched: boolean;
|
|
64
|
+
params: Record<string, string>;
|
|
65
|
+
};
|
|
58
66
|
export declare class RouterCore {
|
|
59
67
|
private readonly _mode;
|
|
60
68
|
private readonly _base;
|
|
61
69
|
private readonly _routes;
|
|
70
|
+
private readonly _flatRoutes;
|
|
62
71
|
private readonly _vtMode;
|
|
63
72
|
private readonly _beforeGuards;
|
|
64
73
|
private readonly _afterGuards;
|
|
@@ -73,10 +82,11 @@ export declare class RouterCore {
|
|
|
73
82
|
get base(): string;
|
|
74
83
|
get routes(): RouteConfig[];
|
|
75
84
|
get currentRoute(): RouteLocation | null;
|
|
76
|
-
|
|
77
|
-
/** Return the first RouteConfig whose path matches the given URL path, or null. */
|
|
85
|
+
/** Return the first matching route (absolute path, nested-aware), or null. */
|
|
78
86
|
matchRoute(path: string): RouteConfig | null;
|
|
79
|
-
/**
|
|
87
|
+
/** Extract `:param` values for the first matching route ({} if none). */
|
|
88
|
+
matchParams(path: string): Record<string, string>;
|
|
89
|
+
/** All declared route paths (nested flattened) — used to enumerate SSG pages. */
|
|
80
90
|
getStaticPaths(): string[];
|
|
81
91
|
private _enableMpa;
|
|
82
92
|
private _disableMpa;
|