slexkit 0.3.0 → 0.3.2
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/CHANGELOG.md +30 -0
- package/README.md +4 -3
- package/README.zh-CN.md +4 -3
- package/dist/ai/llms-components.txt +2 -1
- package/dist/ai/llms-full.txt +85 -42
- package/dist/ai/llms-runtime.txt +11 -12
- package/dist/ai/llms.txt +1 -1
- package/dist/ai/slexkit-ai-manifest.json +77 -73
- package/dist/base.css +0 -46
- package/dist/components/checkbox.js +1 -0
- package/dist/components/choice.css +2 -2
- package/dist/components/display.css +1 -1
- package/dist/components/index.js +56 -153
- package/dist/components/input.css +53 -119
- package/dist/components/input.js +33 -143
- package/dist/components/radio-group.js +1 -0
- package/dist/components/select.css +0 -6
- package/dist/components/slider.css +27 -18
- package/dist/components/specs.js +2 -1
- package/dist/components/switch.css +3 -3
- package/dist/components/switch.js +1 -0
- package/dist/components/text-input.css +21 -90
- package/dist/components/text.js +12 -0
- package/dist/components/tooling.css +0 -1
- package/dist/runtime.cjs +67 -28
- package/dist/runtime.js +67 -28
- package/dist/slexkit.cjs +123 -181
- package/dist/slexkit.css +54 -167
- package/dist/slexkit.js +123 -181
- package/dist/types/engine/types.d.ts +1 -1
- package/dist/types/version.d.ts +2 -2
- package/dist/umd/slexkit.tooling.umd.js +122 -181
- package/dist/umd/slexkit.umd.js +123 -181
- package/package.json +3 -2
- package/skills/slexkit-host-integration/SKILL.md +1 -1
- package/src/components/svelte/display/Text.svelte +14 -1
- package/src/components/svelte/input/Checkbox.svelte +1 -1
- package/src/components/svelte/input/Input.svelte +0 -110
- package/src/components/svelte/input/RadioGroup.svelte +1 -1
- package/src/components/svelte/input/Switch.svelte +1 -1
- package/src/styles/components/choice.css +2 -2
- package/src/styles/components/select.css +0 -6
- package/src/styles/components/slider.css +27 -18
- package/src/styles/components/switch.css +3 -3
- package/src/styles/components/text-input.css +21 -90
- package/src/styles/display.css +1 -1
- package/src/styles/layout.css +0 -46
- package/src/styles/tooling.css +0 -1
|
@@ -104,11 +104,11 @@
|
|
|
104
104
|
opacity: 0.55;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
.slex-switch
|
|
107
|
+
.slex-switch[data-disabled="true"] {
|
|
108
108
|
cursor: not-allowed;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
.slex-switch
|
|
112
|
-
.slex-switch
|
|
111
|
+
.slex-switch[data-disabled="true"]:hover .slex-switch-control,
|
|
112
|
+
.slex-switch[data-disabled="true"]:hover .slex-switch-control::after {
|
|
113
113
|
box-shadow: none;
|
|
114
114
|
}
|
|
@@ -89,6 +89,7 @@ function Switch($$anchor, $$props) {
|
|
|
89
89
|
reset(span);
|
|
90
90
|
template_effect(($0, $1) => {
|
|
91
91
|
set_attribute(label, "data-state", get(enabled) ? "on" : "off");
|
|
92
|
+
set_attribute(label, "data-disabled", get(p).disabled ? "true" : undefined);
|
|
92
93
|
input.disabled = !!get(p).disabled;
|
|
93
94
|
set_attribute(input, "aria-label", $0);
|
|
94
95
|
set_text(text_1, $1);
|
|
@@ -45,16 +45,18 @@
|
|
|
45
45
|
border: 1px solid var(--input);
|
|
46
46
|
border-radius: var(--radius);
|
|
47
47
|
background: var(--background);
|
|
48
|
+
background-clip: padding-box;
|
|
48
49
|
color: var(--foreground);
|
|
49
50
|
font-family: inherit;
|
|
50
51
|
font-size: 0.875rem;
|
|
51
52
|
line-height: 1.5;
|
|
52
53
|
outline: none;
|
|
54
|
+
-webkit-appearance: none;
|
|
55
|
+
appearance: none;
|
|
53
56
|
transition: border-color 150ms ease, box-shadow 150ms ease;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
.slex-input-control[data-has-unit="true"] .slex-input
|
|
57
|
-
.slex-input-control[data-has-controls="true"] .slex-input {
|
|
59
|
+
.slex-input-control[data-has-unit="true"] .slex-input {
|
|
58
60
|
border-top-right-radius: 0;
|
|
59
61
|
border-bottom-right-radius: 0;
|
|
60
62
|
}
|
|
@@ -78,79 +80,16 @@
|
|
|
78
80
|
transition: border-color 150ms ease, box-shadow 150ms ease;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
.slex-input-control[data-has-controls="true"] .slex-input-unit {
|
|
82
|
-
border-radius: 0;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.slex-input-controls {
|
|
86
|
-
box-sizing: border-box;
|
|
87
|
-
display: inline-grid;
|
|
88
|
-
grid-template-rows: repeat(2, minmax(0, 1fr));
|
|
89
|
-
align-items: stretch;
|
|
90
|
-
flex: 0 0 auto;
|
|
91
|
-
width: 1.875rem;
|
|
92
|
-
min-width: 1.875rem;
|
|
93
|
-
min-height: 2.5625rem;
|
|
94
|
-
overflow: hidden;
|
|
95
|
-
border: 1px solid var(--input);
|
|
96
|
-
border-left: 0;
|
|
97
|
-
border-radius: 0 var(--radius) var(--radius) 0;
|
|
98
|
-
background: var(--background);
|
|
99
|
-
transition: border-color 150ms ease, box-shadow 150ms ease;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.slex-input-step {
|
|
103
|
-
box-sizing: border-box;
|
|
104
|
-
display: inline-flex;
|
|
105
|
-
align-items: center;
|
|
106
|
-
justify-content: center;
|
|
107
|
-
width: 100%;
|
|
108
|
-
min-width: 0;
|
|
109
|
-
min-height: 0;
|
|
110
|
-
padding: 0;
|
|
111
|
-
border: 0;
|
|
112
|
-
border-top: 1px solid var(--input);
|
|
113
|
-
border-radius: 0;
|
|
114
|
-
background: transparent;
|
|
115
|
-
color: var(--foreground);
|
|
116
|
-
font: inherit;
|
|
117
|
-
font-size: 0.75rem;
|
|
118
|
-
font-weight: 600;
|
|
119
|
-
line-height: 1;
|
|
120
|
-
cursor: pointer;
|
|
121
|
-
transition: border-color 150ms ease, background 150ms ease, box-shadow 150ms ease;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.slex-input-step:first-child {
|
|
125
|
-
border-top: 0;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.slex-input-step:last-child {
|
|
129
|
-
border-radius: 0;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.slex-input-step:hover:not(:disabled) {
|
|
133
|
-
background: color-mix(in oklab, var(--muted) 52%, var(--background));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.slex-input-step:focus-visible {
|
|
137
|
-
z-index: 1;
|
|
138
|
-
outline: none;
|
|
139
|
-
background: color-mix(in oklab, var(--muted) 58%, var(--background));
|
|
140
|
-
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--ring) 34%, transparent);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.slex-input-step:disabled {
|
|
144
|
-
opacity: 0.45;
|
|
145
|
-
cursor: not-allowed;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
83
|
.slex-input::placeholder {
|
|
149
84
|
color: var(--muted-foreground);
|
|
150
85
|
}
|
|
151
86
|
|
|
152
87
|
.slex-input:focus {
|
|
153
88
|
border-color: var(--ring);
|
|
89
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--ring) 18%, transparent);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.slex-input-control[data-has-unit="true"] .slex-input:focus {
|
|
154
93
|
box-shadow: none;
|
|
155
94
|
}
|
|
156
95
|
|
|
@@ -175,6 +114,10 @@
|
|
|
175
114
|
|
|
176
115
|
.slex-input-field[data-invalid="true"] .slex-input:focus {
|
|
177
116
|
border-color: var(--destructive);
|
|
117
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--destructive) 18%, transparent);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.slex-input-field[data-invalid="true"] .slex-input-control[data-has-unit="true"] .slex-input:focus {
|
|
178
121
|
box-shadow: none;
|
|
179
122
|
}
|
|
180
123
|
|
|
@@ -182,13 +125,12 @@
|
|
|
182
125
|
box-shadow: 0 0 0 2px color-mix(in oklab, var(--ring) 16%, transparent);
|
|
183
126
|
}
|
|
184
127
|
|
|
185
|
-
.slex-input-control:focus-within
|
|
186
|
-
|
|
187
|
-
.slex-input-control:focus-within .slex-input-controls {
|
|
188
|
-
border-color: var(--ring);
|
|
128
|
+
.slex-input-control:not([data-has-unit]):focus-within {
|
|
129
|
+
box-shadow: none;
|
|
189
130
|
}
|
|
190
131
|
|
|
191
|
-
.slex-input-control:focus-within .slex-input
|
|
132
|
+
.slex-input-control:focus-within .slex-input,
|
|
133
|
+
.slex-input-control:focus-within .slex-input-unit {
|
|
192
134
|
border-color: var(--ring);
|
|
193
135
|
}
|
|
194
136
|
|
|
@@ -197,22 +139,16 @@
|
|
|
197
139
|
color: color-mix(in oklab, var(--destructive) 84%, var(--muted-foreground));
|
|
198
140
|
}
|
|
199
141
|
|
|
200
|
-
.slex-input-field[data-invalid="true"] .slex-input-step {
|
|
201
|
-
border-color: color-mix(in oklab, var(--destructive) 72%, var(--input));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.slex-input-field[data-invalid="true"] .slex-input-controls {
|
|
205
|
-
border-color: color-mix(in oklab, var(--destructive) 72%, var(--input));
|
|
206
|
-
}
|
|
207
|
-
|
|
208
142
|
.slex-input-field[data-invalid="true"] .slex-input-control:focus-within {
|
|
209
143
|
box-shadow: 0 0 0 2px color-mix(in oklab, var(--destructive) 18%, transparent);
|
|
210
144
|
}
|
|
211
145
|
|
|
146
|
+
.slex-input-field[data-invalid="true"] .slex-input-control:not([data-has-unit]):focus-within {
|
|
147
|
+
box-shadow: none;
|
|
148
|
+
}
|
|
149
|
+
|
|
212
150
|
.slex-input-field[data-invalid="true"] .slex-input-control:focus-within .slex-input,
|
|
213
|
-
.slex-input-field[data-invalid="true"] .slex-input-control:focus-within .slex-input-unit
|
|
214
|
-
.slex-input-field[data-invalid="true"] .slex-input-control:focus-within .slex-input-controls,
|
|
215
|
-
.slex-input-field[data-invalid="true"] .slex-input-control:focus-within .slex-input-step {
|
|
151
|
+
.slex-input-field[data-invalid="true"] .slex-input-control:focus-within .slex-input-unit {
|
|
216
152
|
border-color: var(--destructive);
|
|
217
153
|
}
|
|
218
154
|
|
|
@@ -226,11 +162,6 @@
|
|
|
226
162
|
cursor: not-allowed;
|
|
227
163
|
}
|
|
228
164
|
|
|
229
|
-
.slex-input[disabled] ~ .slex-input-controls,
|
|
230
|
-
.slex-input[readonly] ~ .slex-input-controls {
|
|
231
|
-
opacity: 0.6;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
165
|
.slex-input-description {
|
|
235
166
|
color: var(--muted-foreground);
|
|
236
167
|
font-size: 0.75rem;
|
package/dist/components/text.js
CHANGED
|
@@ -11,10 +11,12 @@ import {
|
|
|
11
11
|
reset,
|
|
12
12
|
set,
|
|
13
13
|
set_class,
|
|
14
|
+
set_style,
|
|
14
15
|
set_text,
|
|
15
16
|
state,
|
|
16
17
|
template_effect,
|
|
17
18
|
text1 as text,
|
|
19
|
+
user_derived,
|
|
18
20
|
user_effect
|
|
19
21
|
} from "../chunks/button-cr1fhsa7.js";
|
|
20
22
|
|
|
@@ -27,11 +29,21 @@ function Text($$anchor, $$props) {
|
|
|
27
29
|
push($$props, true);
|
|
28
30
|
let p = state(proxy({}));
|
|
29
31
|
user_effect(() => bindPropStore($$props.props, (next) => set(p, next, true)));
|
|
32
|
+
const color = user_derived(() => get(p).color == null || get(p).color === "" ? undefined : text(get(p).color));
|
|
33
|
+
const size = user_derived(() => cssLength(get(p).size));
|
|
34
|
+
function cssLength(value) {
|
|
35
|
+
if (value == null || value === "")
|
|
36
|
+
return;
|
|
37
|
+
const rendered = text(value);
|
|
38
|
+
return /^-?\d+(\.\d+)?$/.test(rendered) ? `${rendered}px` : rendered;
|
|
39
|
+
}
|
|
30
40
|
var div = root();
|
|
41
|
+
let styles;
|
|
31
42
|
var text_1 = child(div, true);
|
|
32
43
|
reset(div);
|
|
33
44
|
template_effect(($0, $1) => {
|
|
34
45
|
set_class(div, 1, $0);
|
|
46
|
+
styles = set_style(div, "", styles, { color: get(color), "font-size": get(size) });
|
|
35
47
|
set_text(text_1, $1);
|
|
36
48
|
}, [
|
|
37
49
|
() => `slex-text${get(p).variant ? ` slex-text--${text(get(p).variant)}` : ""}${get(p).class ? ` ${text(get(p).class)}` : ""}`,
|
package/dist/runtime.cjs
CHANGED
|
@@ -468,19 +468,31 @@ function configureComponentScope(options) {
|
|
|
468
468
|
function createComponentAccessor(read) {
|
|
469
469
|
const subscribers = new Set;
|
|
470
470
|
let current = read();
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
471
|
+
let stopEffect;
|
|
472
|
+
const start = () => {
|
|
473
|
+
if (stopEffect)
|
|
474
|
+
return;
|
|
475
|
+
stopEffect = createEffect(() => {
|
|
476
476
|
current = read();
|
|
477
|
-
for (const subscriber of subscribers)
|
|
477
|
+
for (const subscriber of Array.from(subscribers))
|
|
478
478
|
subscriber(current);
|
|
479
479
|
flushDom?.();
|
|
480
480
|
});
|
|
481
|
+
};
|
|
482
|
+
const accessor = () => current;
|
|
483
|
+
accessor.subscribe = (run) => {
|
|
484
|
+
const wasIdle = subscribers.size === 0;
|
|
485
|
+
subscribers.add(run);
|
|
486
|
+
if (wasIdle)
|
|
487
|
+
start();
|
|
488
|
+
else
|
|
489
|
+
run(current);
|
|
481
490
|
return () => {
|
|
482
491
|
subscribers.delete(run);
|
|
483
|
-
|
|
492
|
+
if (subscribers.size === 0) {
|
|
493
|
+
stopEffect?.();
|
|
494
|
+
stopEffect = undefined;
|
|
495
|
+
}
|
|
484
496
|
};
|
|
485
497
|
};
|
|
486
498
|
return accessor;
|
|
@@ -761,6 +773,9 @@ function isWritableComponent(type) {
|
|
|
761
773
|
const mode = getComponentStateMode(type);
|
|
762
774
|
return mode === "value" || mode === "checked" || mode === "enabled";
|
|
763
775
|
}
|
|
776
|
+
function isReadableComponent(type) {
|
|
777
|
+
return getComponentStateMode(type) === "readable";
|
|
778
|
+
}
|
|
764
779
|
function isStatefulComponent(type) {
|
|
765
780
|
return getComponentStateMode(type) !== "none";
|
|
766
781
|
}
|
|
@@ -877,7 +892,10 @@ function createGProxy(g, components, componentTypes) {
|
|
|
877
892
|
function ensureComponentState(name, type, components, componentTypes) {
|
|
878
893
|
if (!components[name])
|
|
879
894
|
components[name] = {};
|
|
880
|
-
componentTypes[name]
|
|
895
|
+
const previousType = componentTypes[name] ?? "";
|
|
896
|
+
if (!(isWritableComponent(previousType) && isReadableComponent(type))) {
|
|
897
|
+
componentTypes[name] = type;
|
|
898
|
+
}
|
|
881
899
|
return components[name];
|
|
882
900
|
}
|
|
883
901
|
function syncReadableComponentProp(type, state, propName, value) {
|
|
@@ -905,6 +923,9 @@ function syncReadableComponentProp(type, state, propName, value) {
|
|
|
905
923
|
function syncComponentProps(type, name, props, components, componentTypes) {
|
|
906
924
|
if (!name || !isStatefulComponent(type))
|
|
907
925
|
return;
|
|
926
|
+
const previousType = componentTypes[name] ?? "";
|
|
927
|
+
if (isWritableComponent(previousType) && isReadableComponent(type))
|
|
928
|
+
return;
|
|
908
929
|
const state = ensureComponentState(name, type, components, componentTypes);
|
|
909
930
|
if (type === "input" && typeof props.type === "string") {
|
|
910
931
|
assignInputType(state, props.type);
|
|
@@ -969,7 +990,7 @@ function seedStaticComponentState(type, state, props) {
|
|
|
969
990
|
function warnDuplicateState(ns, name, currentType, currentPath, previous) {
|
|
970
991
|
console.warn(`[SlexKit][${ns}] Component state '${name}' is declared more than once at ${previous.path} and ${currentPath}; state is shared by namespace and component name.`);
|
|
971
992
|
if (previous.type !== currentType) {
|
|
972
|
-
console.warn(`[SlexKit][${ns}] Component state '${name}' is used by multiple component types (${previous.type}, ${currentType});
|
|
993
|
+
console.warn(`[SlexKit][${ns}] Component state '${name}' is used by multiple component types (${previous.type}, ${currentType}); use distinct names when components should not share state.`);
|
|
973
994
|
}
|
|
974
995
|
}
|
|
975
996
|
function dynamicStateBinding(type, props) {
|
|
@@ -981,6 +1002,9 @@ function isMirroredValueControlPair(previousType, currentType) {
|
|
|
981
1002
|
return previousType === "input" && currentType === "slider" || previousType === "slider" && currentType === "input";
|
|
982
1003
|
}
|
|
983
1004
|
function shouldWarnDuplicateState(currentType, currentBinding, previous) {
|
|
1005
|
+
if (isReadableComponent(previous.type) && isReadableComponent(currentType)) {
|
|
1006
|
+
return false;
|
|
1007
|
+
}
|
|
984
1008
|
if (currentBinding && previous.stateBinding === currentBinding && isMirroredValueControlPair(previous.type, currentType)) {
|
|
985
1009
|
return false;
|
|
986
1010
|
}
|
|
@@ -1319,9 +1343,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1319
1343
|
const renderer = getRenderer(type);
|
|
1320
1344
|
if (!renderer)
|
|
1321
1345
|
return;
|
|
1322
|
-
const
|
|
1323
|
-
|
|
1324
|
-
|
|
1346
|
+
const doc = container.ownerDocument || document;
|
|
1347
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1348
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1349
|
+
container.append(startAnchor, endAnchor);
|
|
1325
1350
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1326
1351
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1327
1352
|
const $keyProp = props.$key;
|
|
@@ -1334,8 +1359,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1334
1359
|
disposedSlots.add(slot);
|
|
1335
1360
|
leavingSlots.delete(slot);
|
|
1336
1361
|
callHook(g, name, "onUnmount");
|
|
1337
|
-
|
|
1338
|
-
|
|
1362
|
+
if (slot.el) {
|
|
1363
|
+
disposeComponent(slot.el);
|
|
1364
|
+
slot.el.remove();
|
|
1365
|
+
}
|
|
1339
1366
|
if (slot.dispose)
|
|
1340
1367
|
slot.dispose();
|
|
1341
1368
|
};
|
|
@@ -1360,12 +1387,16 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1360
1387
|
}
|
|
1361
1388
|
}
|
|
1362
1389
|
for (const slot of deletedSlots) {
|
|
1363
|
-
container.appendChild(slot.el);
|
|
1364
1390
|
leavingSlots.add(slot);
|
|
1391
|
+
if (!slot.el) {
|
|
1392
|
+
disposeSlot(slot);
|
|
1393
|
+
continue;
|
|
1394
|
+
}
|
|
1365
1395
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1366
1396
|
disposeSlot(slot);
|
|
1367
1397
|
});
|
|
1368
1398
|
}
|
|
1399
|
+
let cursor = startAnchor;
|
|
1369
1400
|
arr.forEach((item, index) => {
|
|
1370
1401
|
item = asReactiveValue(item, g);
|
|
1371
1402
|
const keyVal = newKeys[index];
|
|
@@ -1393,20 +1424,22 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1393
1424
|
const indexSignal = createSignal(index);
|
|
1394
1425
|
const revisionSignal = createSignal(0);
|
|
1395
1426
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1396
|
-
if (slot.el) {
|
|
1397
|
-
|
|
1398
|
-
|
|
1427
|
+
if (!slot.el) {
|
|
1428
|
+
disposeSlot(slot);
|
|
1429
|
+
return;
|
|
1399
1430
|
}
|
|
1431
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1432
|
+
callHook(g, name, "onMount");
|
|
1400
1433
|
slotMap.set(keyVal, slot);
|
|
1401
1434
|
}
|
|
1402
|
-
const
|
|
1403
|
-
if (slot.el &&
|
|
1404
|
-
|
|
1435
|
+
const nextChild = cursor.nextSibling;
|
|
1436
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1437
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1438
|
+
}
|
|
1439
|
+
if (slot.el) {
|
|
1440
|
+
cursor = slot.el;
|
|
1405
1441
|
}
|
|
1406
1442
|
});
|
|
1407
|
-
while (forWrapper.children.length > arr.length) {
|
|
1408
|
-
forWrapper.lastChild.remove();
|
|
1409
|
-
}
|
|
1410
1443
|
});
|
|
1411
1444
|
onCleanup(() => {
|
|
1412
1445
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1414,7 +1447,8 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1414
1447
|
slotMap.clear();
|
|
1415
1448
|
for (const slot of Array.from(leavingSlots))
|
|
1416
1449
|
disposeSlot(slot);
|
|
1417
|
-
|
|
1450
|
+
startAnchor.remove();
|
|
1451
|
+
endAnchor.remove();
|
|
1418
1452
|
});
|
|
1419
1453
|
}
|
|
1420
1454
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1791,7 +1825,7 @@ ${parseSource}
|
|
|
1791
1825
|
var parseSlexKitDsl = parseSlexSource;
|
|
1792
1826
|
|
|
1793
1827
|
// src/version.ts
|
|
1794
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1828
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1795
1829
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1796
1830
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1797
1831
|
function getSlexKitInfo() {
|
|
@@ -2919,7 +2953,6 @@ var inputSpec = component({
|
|
|
2919
2953
|
min: { type: "string | number", dynamic: true, description: "Minimum value used by numeric input controls." },
|
|
2920
2954
|
max: { type: "string | number", dynamic: true, description: "Maximum value used by numeric input controls." },
|
|
2921
2955
|
step: { type: "string | number", dynamic: true, description: "Step size used by numeric input controls." },
|
|
2922
|
-
controls: { type: "boolean", default: true, dynamic: true, description: "Show decrement and increment buttons for numeric inputs." },
|
|
2923
2956
|
onchange: { type: "write-expression", description: "Write expression invoked when the value changes." }
|
|
2924
2957
|
},
|
|
2925
2958
|
children: noChildren,
|
|
@@ -3427,6 +3460,8 @@ var textSpec = component({
|
|
|
3427
3460
|
content: { type: "string", dynamic: true, description: "Alias for text." },
|
|
3428
3461
|
label: { type: "string", dynamic: true, description: "Alias for text." },
|
|
3429
3462
|
variant: { type: "string", values: ["default", "muted"], default: "default", description: "Text visual variant." },
|
|
3463
|
+
color: { type: "string", dynamic: true, description: "Optional CSS color for controlled previews." },
|
|
3464
|
+
size: { type: "string | number", dynamic: true, description: "Optional font size. Numbers are treated as px." },
|
|
3430
3465
|
class: { type: "string", description: "Additional host-controlled CSS class." }
|
|
3431
3466
|
},
|
|
3432
3467
|
children: noChildren,
|
|
@@ -3727,7 +3762,11 @@ function isRenderableSource(value) {
|
|
|
3727
3762
|
return Object.keys(value).some((key) => key.includes(":"));
|
|
3728
3763
|
}
|
|
3729
3764
|
function bareLayoutFromSource(value) {
|
|
3730
|
-
const
|
|
3765
|
+
const layout = { ...value };
|
|
3766
|
+
delete layout.slex;
|
|
3767
|
+
delete layout.namespace;
|
|
3768
|
+
delete layout.g;
|
|
3769
|
+
delete layout.layout;
|
|
3731
3770
|
return layout;
|
|
3732
3771
|
}
|
|
3733
3772
|
function isStateOnlySource(value) {
|
package/dist/runtime.js
CHANGED
|
@@ -396,19 +396,31 @@ function configureComponentScope(options) {
|
|
|
396
396
|
function createComponentAccessor(read) {
|
|
397
397
|
const subscribers = new Set;
|
|
398
398
|
let current = read();
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
399
|
+
let stopEffect;
|
|
400
|
+
const start = () => {
|
|
401
|
+
if (stopEffect)
|
|
402
|
+
return;
|
|
403
|
+
stopEffect = createEffect(() => {
|
|
404
404
|
current = read();
|
|
405
|
-
for (const subscriber of subscribers)
|
|
405
|
+
for (const subscriber of Array.from(subscribers))
|
|
406
406
|
subscriber(current);
|
|
407
407
|
flushDom?.();
|
|
408
408
|
});
|
|
409
|
+
};
|
|
410
|
+
const accessor = () => current;
|
|
411
|
+
accessor.subscribe = (run) => {
|
|
412
|
+
const wasIdle = subscribers.size === 0;
|
|
413
|
+
subscribers.add(run);
|
|
414
|
+
if (wasIdle)
|
|
415
|
+
start();
|
|
416
|
+
else
|
|
417
|
+
run(current);
|
|
409
418
|
return () => {
|
|
410
419
|
subscribers.delete(run);
|
|
411
|
-
|
|
420
|
+
if (subscribers.size === 0) {
|
|
421
|
+
stopEffect?.();
|
|
422
|
+
stopEffect = undefined;
|
|
423
|
+
}
|
|
412
424
|
};
|
|
413
425
|
};
|
|
414
426
|
return accessor;
|
|
@@ -689,6 +701,9 @@ function isWritableComponent(type) {
|
|
|
689
701
|
const mode = getComponentStateMode(type);
|
|
690
702
|
return mode === "value" || mode === "checked" || mode === "enabled";
|
|
691
703
|
}
|
|
704
|
+
function isReadableComponent(type) {
|
|
705
|
+
return getComponentStateMode(type) === "readable";
|
|
706
|
+
}
|
|
692
707
|
function isStatefulComponent(type) {
|
|
693
708
|
return getComponentStateMode(type) !== "none";
|
|
694
709
|
}
|
|
@@ -805,7 +820,10 @@ function createGProxy(g, components, componentTypes) {
|
|
|
805
820
|
function ensureComponentState(name, type, components, componentTypes) {
|
|
806
821
|
if (!components[name])
|
|
807
822
|
components[name] = {};
|
|
808
|
-
componentTypes[name]
|
|
823
|
+
const previousType = componentTypes[name] ?? "";
|
|
824
|
+
if (!(isWritableComponent(previousType) && isReadableComponent(type))) {
|
|
825
|
+
componentTypes[name] = type;
|
|
826
|
+
}
|
|
809
827
|
return components[name];
|
|
810
828
|
}
|
|
811
829
|
function syncReadableComponentProp(type, state, propName, value) {
|
|
@@ -833,6 +851,9 @@ function syncReadableComponentProp(type, state, propName, value) {
|
|
|
833
851
|
function syncComponentProps(type, name, props, components, componentTypes) {
|
|
834
852
|
if (!name || !isStatefulComponent(type))
|
|
835
853
|
return;
|
|
854
|
+
const previousType = componentTypes[name] ?? "";
|
|
855
|
+
if (isWritableComponent(previousType) && isReadableComponent(type))
|
|
856
|
+
return;
|
|
836
857
|
const state = ensureComponentState(name, type, components, componentTypes);
|
|
837
858
|
if (type === "input" && typeof props.type === "string") {
|
|
838
859
|
assignInputType(state, props.type);
|
|
@@ -897,7 +918,7 @@ function seedStaticComponentState(type, state, props) {
|
|
|
897
918
|
function warnDuplicateState(ns, name, currentType, currentPath, previous) {
|
|
898
919
|
console.warn(`[SlexKit][${ns}] Component state '${name}' is declared more than once at ${previous.path} and ${currentPath}; state is shared by namespace and component name.`);
|
|
899
920
|
if (previous.type !== currentType) {
|
|
900
|
-
console.warn(`[SlexKit][${ns}] Component state '${name}' is used by multiple component types (${previous.type}, ${currentType});
|
|
921
|
+
console.warn(`[SlexKit][${ns}] Component state '${name}' is used by multiple component types (${previous.type}, ${currentType}); use distinct names when components should not share state.`);
|
|
901
922
|
}
|
|
902
923
|
}
|
|
903
924
|
function dynamicStateBinding(type, props) {
|
|
@@ -909,6 +930,9 @@ function isMirroredValueControlPair(previousType, currentType) {
|
|
|
909
930
|
return previousType === "input" && currentType === "slider" || previousType === "slider" && currentType === "input";
|
|
910
931
|
}
|
|
911
932
|
function shouldWarnDuplicateState(currentType, currentBinding, previous) {
|
|
933
|
+
if (isReadableComponent(previous.type) && isReadableComponent(currentType)) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
912
936
|
if (currentBinding && previous.stateBinding === currentBinding && isMirroredValueControlPair(previous.type, currentType)) {
|
|
913
937
|
return false;
|
|
914
938
|
}
|
|
@@ -1247,9 +1271,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1247
1271
|
const renderer = getRenderer(type);
|
|
1248
1272
|
if (!renderer)
|
|
1249
1273
|
return;
|
|
1250
|
-
const
|
|
1251
|
-
|
|
1252
|
-
|
|
1274
|
+
const doc = container.ownerDocument || document;
|
|
1275
|
+
const startAnchor = doc.createComment(`slexkit-for:${fullKey}:start`);
|
|
1276
|
+
const endAnchor = doc.createComment(`slexkit-for:${fullKey}:end`);
|
|
1277
|
+
container.append(startAnchor, endAnchor);
|
|
1253
1278
|
const evalCtx = buildComponentEvalContext(g, components, componentTypes, api, forCtx);
|
|
1254
1279
|
const items = createMemo(() => trackForCollection(evalRead(props.$for, evalCtx, ns, `${fullKey}:$for`)));
|
|
1255
1280
|
const $keyProp = props.$key;
|
|
@@ -1262,8 +1287,10 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1262
1287
|
disposedSlots.add(slot);
|
|
1263
1288
|
leavingSlots.delete(slot);
|
|
1264
1289
|
callHook(g, name, "onUnmount");
|
|
1265
|
-
|
|
1266
|
-
|
|
1290
|
+
if (slot.el) {
|
|
1291
|
+
disposeComponent(slot.el);
|
|
1292
|
+
slot.el.remove();
|
|
1293
|
+
}
|
|
1267
1294
|
if (slot.dispose)
|
|
1268
1295
|
slot.dispose();
|
|
1269
1296
|
};
|
|
@@ -1288,12 +1315,16 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1288
1315
|
}
|
|
1289
1316
|
}
|
|
1290
1317
|
for (const slot of deletedSlots) {
|
|
1291
|
-
container.appendChild(slot.el);
|
|
1292
1318
|
leavingSlots.add(slot);
|
|
1319
|
+
if (!slot.el) {
|
|
1320
|
+
disposeSlot(slot);
|
|
1321
|
+
continue;
|
|
1322
|
+
}
|
|
1293
1323
|
applyLeaveAnimation(slot.el, slot.props, () => {
|
|
1294
1324
|
disposeSlot(slot);
|
|
1295
1325
|
});
|
|
1296
1326
|
}
|
|
1327
|
+
let cursor = startAnchor;
|
|
1297
1328
|
arr.forEach((item, index) => {
|
|
1298
1329
|
item = asReactiveValue(item, g);
|
|
1299
1330
|
const keyVal = newKeys[index];
|
|
@@ -1321,20 +1352,22 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1321
1352
|
const indexSignal = createSignal(index);
|
|
1322
1353
|
const revisionSignal = createSignal(0);
|
|
1323
1354
|
slot = renderAndMountSlot(item, index, keyVal, indexSignal, revisionSignal, renderer, type, name, props, container, g, components, componentTypes, api, forCtx, ns, fullKey, options);
|
|
1324
|
-
if (slot.el) {
|
|
1325
|
-
|
|
1326
|
-
|
|
1355
|
+
if (!slot.el) {
|
|
1356
|
+
disposeSlot(slot);
|
|
1357
|
+
return;
|
|
1327
1358
|
}
|
|
1359
|
+
applyEnterAnimation(slot.el, slot.props);
|
|
1360
|
+
callHook(g, name, "onMount");
|
|
1328
1361
|
slotMap.set(keyVal, slot);
|
|
1329
1362
|
}
|
|
1330
|
-
const
|
|
1331
|
-
if (slot.el &&
|
|
1332
|
-
|
|
1363
|
+
const nextChild = cursor.nextSibling;
|
|
1364
|
+
if (slot.el && nextChild !== slot.el) {
|
|
1365
|
+
container.insertBefore(slot.el, nextChild ?? endAnchor);
|
|
1366
|
+
}
|
|
1367
|
+
if (slot.el) {
|
|
1368
|
+
cursor = slot.el;
|
|
1333
1369
|
}
|
|
1334
1370
|
});
|
|
1335
|
-
while (forWrapper.children.length > arr.length) {
|
|
1336
|
-
forWrapper.lastChild.remove();
|
|
1337
|
-
}
|
|
1338
1371
|
});
|
|
1339
1372
|
onCleanup(() => {
|
|
1340
1373
|
for (const slot of Array.from(slotMap.values()))
|
|
@@ -1342,7 +1375,8 @@ function renderForNode(fullKey, props, container, g, components, componentTypes,
|
|
|
1342
1375
|
slotMap.clear();
|
|
1343
1376
|
for (const slot of Array.from(leavingSlots))
|
|
1344
1377
|
disposeSlot(slot);
|
|
1345
|
-
|
|
1378
|
+
startAnchor.remove();
|
|
1379
|
+
endAnchor.remove();
|
|
1346
1380
|
});
|
|
1347
1381
|
}
|
|
1348
1382
|
function renderNormalNode(fullKey, props, container, g, components, componentTypes, api, forCtx, ns, options) {
|
|
@@ -1719,7 +1753,7 @@ ${parseSource}
|
|
|
1719
1753
|
var parseSlexKitDsl = parseSlexSource;
|
|
1720
1754
|
|
|
1721
1755
|
// src/version.ts
|
|
1722
|
-
var SLEXKIT_VERSION = "0.3.
|
|
1756
|
+
var SLEXKIT_VERSION = "0.3.2";
|
|
1723
1757
|
var SLEX_PROTOCOL_VERSION = "0.1";
|
|
1724
1758
|
var SLEXKIT_COMPONENTS_VERSION = SLEXKIT_VERSION;
|
|
1725
1759
|
function getSlexKitInfo() {
|
|
@@ -2847,7 +2881,6 @@ var inputSpec = component({
|
|
|
2847
2881
|
min: { type: "string | number", dynamic: true, description: "Minimum value used by numeric input controls." },
|
|
2848
2882
|
max: { type: "string | number", dynamic: true, description: "Maximum value used by numeric input controls." },
|
|
2849
2883
|
step: { type: "string | number", dynamic: true, description: "Step size used by numeric input controls." },
|
|
2850
|
-
controls: { type: "boolean", default: true, dynamic: true, description: "Show decrement and increment buttons for numeric inputs." },
|
|
2851
2884
|
onchange: { type: "write-expression", description: "Write expression invoked when the value changes." }
|
|
2852
2885
|
},
|
|
2853
2886
|
children: noChildren,
|
|
@@ -3355,6 +3388,8 @@ var textSpec = component({
|
|
|
3355
3388
|
content: { type: "string", dynamic: true, description: "Alias for text." },
|
|
3356
3389
|
label: { type: "string", dynamic: true, description: "Alias for text." },
|
|
3357
3390
|
variant: { type: "string", values: ["default", "muted"], default: "default", description: "Text visual variant." },
|
|
3391
|
+
color: { type: "string", dynamic: true, description: "Optional CSS color for controlled previews." },
|
|
3392
|
+
size: { type: "string | number", dynamic: true, description: "Optional font size. Numbers are treated as px." },
|
|
3358
3393
|
class: { type: "string", description: "Additional host-controlled CSS class." }
|
|
3359
3394
|
},
|
|
3360
3395
|
children: noChildren,
|
|
@@ -3655,7 +3690,11 @@ function isRenderableSource(value) {
|
|
|
3655
3690
|
return Object.keys(value).some((key) => key.includes(":"));
|
|
3656
3691
|
}
|
|
3657
3692
|
function bareLayoutFromSource(value) {
|
|
3658
|
-
const
|
|
3693
|
+
const layout = { ...value };
|
|
3694
|
+
delete layout.slex;
|
|
3695
|
+
delete layout.namespace;
|
|
3696
|
+
delete layout.g;
|
|
3697
|
+
delete layout.layout;
|
|
3659
3698
|
return layout;
|
|
3660
3699
|
}
|
|
3661
3700
|
function isStateOnlySource(value) {
|