jsswift 2.0.1 → 2.1.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/AI.md +5 -0
- package/README.md +2 -0
- package/dist/build/build-configured-runtime.d.mts +29 -0
- package/dist/build/build-configured-runtime.mjs +92 -0
- package/dist/build/runtime-layout.mjs +13 -0
- package/dist/build/select-ui.mjs +167 -0
- package/dist/build/vite-jss.d.mts +2 -0
- package/dist/build/vite-jss.mjs +73 -0
- package/dist/cms.js +3522 -0
- package/dist/documentions/AI.md +5 -0
- package/dist/documentions/README.md +1 -0
- package/dist/documentions/configured-runtime.md +82 -0
- package/dist/documentions/knowledge-map.json +20 -1
- package/dist/ui-src/00-bootstrap.js +330 -0
- package/dist/ui-src/01-foundation-helpers.js +809 -0
- package/dist/ui-src/10-primitives-layout.js +5091 -0
- package/dist/ui-src/20-display-content.js +780 -0
- package/dist/ui-src/21-list-content.js +246 -0
- package/dist/ui-src/22-banner-content.js +376 -0
- package/dist/ui-src/23-tooltip.js +276 -0
- package/dist/ui-src/31-form-advanced.js +2784 -0
- package/dist/ui-src/40-navigation.js +1262 -0
- package/dist/ui-src/41-tab-panel.js +896 -0
- package/dist/ui-src/50-feedback.js +999 -0
- package/dist/ui-src/51-feedback-service.js +166 -0
- package/dist/ui-src/60-shell-app.js +1223 -0
- package/dist/ui-src/61-form-service.js +368 -0
- package/dist/ui-src/70-dialog.js +333 -0
- package/dist/ui-src/71-menu-overlays.js +1217 -0
- package/dist/ui-src/80-data.js +437 -0
- package/dist/ui-src/modules.json +212 -0
- package/dist/ui.js +12565 -0
- package/package.json +26 -2
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
const UI_SHADOW_TOKENS = new Set(["none", "sm", "md", "lg"]);
|
|
2
|
+
const sizeMap = {
|
|
3
|
+
xxs: { font: "9px", pad: "2px 5px" },
|
|
4
|
+
xs: { font: "10px", pad: "2px 6px" },
|
|
5
|
+
sm: { font: "11px", pad: "2px 7px" },
|
|
6
|
+
md: { font: "12px", pad: "2px 8px" },
|
|
7
|
+
lg: { font: "13px", pad: "3px 10px" },
|
|
8
|
+
xl: { font: "14px", pad: "4px 12px" },
|
|
9
|
+
xxl: { font: "15px", pad: "5px 14px" },
|
|
10
|
+
xxxl: { font: "16px", pad: "6px 16px" }
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// normalize color is RGB | RGBA | HEX | color name
|
|
14
|
+
const isTokenCSS = (value) => {
|
|
15
|
+
// se la parola contiene un trattino - è un token
|
|
16
|
+
if (value.indexOf("-") > -1) return true;
|
|
17
|
+
}
|
|
18
|
+
const normalizeState = (value) => {
|
|
19
|
+
if (!value) return "";
|
|
20
|
+
const key = String(value).toLowerCase();
|
|
21
|
+
return UI_STATE_ALIASES[key] || "";
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const normalizeRadius = (value) => {
|
|
25
|
+
if (value == null) return null;
|
|
26
|
+
const key = String(value).toLowerCase();
|
|
27
|
+
if (key === "full") return "xxxl";
|
|
28
|
+
if (UI_RADIUS_TOKENS.has(key)) return key;
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const normalizeShadow = (value) => {
|
|
33
|
+
if (value === true) return "sm";
|
|
34
|
+
if (value == null || value === false) return null;
|
|
35
|
+
const key = String(value).toLowerCase();
|
|
36
|
+
if (UI_SHADOW_TOKENS.has(key)) return key;
|
|
37
|
+
return null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const isUIPlainObject = (value) => value && typeof value === "object" && !value.nodeType && !Array.isArray(value) && !(value instanceof Function);
|
|
41
|
+
const isListItemNode = (value) => value && value.nodeType === 1 && String(value.tagName || "").toLowerCase() === "li";
|
|
42
|
+
const asNodeArray = (value) => {
|
|
43
|
+
if (value == null || value === false || value === "") return [];
|
|
44
|
+
return Array.isArray(value) ? value : [value];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
JSswift.isUIPlainObject = isUIPlainObject;
|
|
48
|
+
JSswift.isListItemNode = isListItemNode;
|
|
49
|
+
JSswift.asNodeArray = asNodeArray;
|
|
50
|
+
|
|
51
|
+
const UI_RESPONSIVE_DEVICES = [
|
|
52
|
+
{ key: "mobile", aliases: ["mobile", "mobil"], prefix: "jss-" },
|
|
53
|
+
{ key: "tablet", aliases: ["tablet"], prefix: "jss-tablet-" },
|
|
54
|
+
{ key: "pc", aliases: ["pc", "desktop"], prefix: "jss-pc-" }
|
|
55
|
+
];
|
|
56
|
+
const UI_RESPONSIVE_PROP_KEYS = UI_RESPONSIVE_DEVICES.flatMap((device) => device.aliases);
|
|
57
|
+
const uiResponsiveHasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj || {}, key);
|
|
58
|
+
const uiResponsivePropsFor = (props = {}, device) => {
|
|
59
|
+
if (!device) return null;
|
|
60
|
+
for (const alias of device.aliases) {
|
|
61
|
+
if (!uiResponsiveHasOwn(props, alias)) continue;
|
|
62
|
+
const value = uiUnwrap(props[alias]);
|
|
63
|
+
if (isUIPlainObject(value)) return value;
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
};
|
|
67
|
+
const uiResponsiveHasProp = (props = {}, names) => {
|
|
68
|
+
const list = Array.isArray(names) ? names : [names];
|
|
69
|
+
return UI_RESPONSIVE_DEVICES.some((device) => {
|
|
70
|
+
const deviceProps = uiResponsivePropsFor(props, device);
|
|
71
|
+
return !!deviceProps && list.some((name) => uiResponsiveHasOwn(deviceProps, name));
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
const uiResponsiveNormalizeToken = (value) => String(value).trim().toLowerCase().replace(/\s+/g, "-");
|
|
75
|
+
const uiResponsiveClassList = (props = {}, rules = []) => {
|
|
76
|
+
const tokens = [];
|
|
77
|
+
for (const device of UI_RESPONSIVE_DEVICES) {
|
|
78
|
+
const deviceProps = uiResponsivePropsFor(props, device);
|
|
79
|
+
if (!deviceProps) continue;
|
|
80
|
+
for (const rule of rules) {
|
|
81
|
+
const propNames = Array.isArray(rule.prop) ? rule.prop : [rule.prop];
|
|
82
|
+
let hasValue = false;
|
|
83
|
+
let value;
|
|
84
|
+
let propName = "";
|
|
85
|
+
for (const name of propNames) {
|
|
86
|
+
if (!uiResponsiveHasOwn(deviceProps, name)) continue;
|
|
87
|
+
value = uiUnwrap(deviceProps[name]);
|
|
88
|
+
propName = name;
|
|
89
|
+
hasValue = true;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
if (!hasValue || value == null || value === "" || (value === false && !rule.allowFalse)) continue;
|
|
93
|
+
const resolved = typeof rule.map === "function"
|
|
94
|
+
? rule.map(value, { propName, props: deviceProps, device, rule })
|
|
95
|
+
: `${rule.class}-${uiResponsiveNormalizeToken(value)}`;
|
|
96
|
+
const list = Array.isArray(resolved) ? resolved : [resolved];
|
|
97
|
+
for (const suffix of list) {
|
|
98
|
+
if (!suffix) continue;
|
|
99
|
+
tokens.push(String(suffix).startsWith("jss-") ? suffix : `${device.prefix}${suffix}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return tokens;
|
|
104
|
+
};
|
|
105
|
+
const uiResponsiveHasConfig = (props = {}) => {
|
|
106
|
+
return UI_RESPONSIVE_DEVICES.some((device) => !!uiResponsivePropsFor(props, device));
|
|
107
|
+
};
|
|
108
|
+
const uiResponsiveFirstValue = (props = {}, propNames = []) => {
|
|
109
|
+
for (const propName of propNames) {
|
|
110
|
+
if (!uiResponsiveHasOwn(props, propName)) continue;
|
|
111
|
+
const value = uiUnwrap(props[propName]);
|
|
112
|
+
if (value == null || value === "") continue;
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
return undefined;
|
|
116
|
+
};
|
|
117
|
+
const uiResponsiveDefaultValue = (value, rule = {}) => {
|
|
118
|
+
if (value == null || value === "" || (value === false && !rule.allowFalse)) return "";
|
|
119
|
+
if (typeof rule.mapValue === "function") return rule.mapValue(value, rule);
|
|
120
|
+
if (typeof value === "number") return rule.number === "raw" ? String(value) : `${value}px`;
|
|
121
|
+
if (rule.token && typeof value === "string" && JSswift.uiSizes?.includes(value)) {
|
|
122
|
+
return `var(--jss-${rule.token}-${value})`;
|
|
123
|
+
}
|
|
124
|
+
return String(value);
|
|
125
|
+
};
|
|
126
|
+
const uiResponsiveSetStyle = (style, name, value) => {
|
|
127
|
+
if (!style || value == null || value === "") return;
|
|
128
|
+
if (typeof style.setProperty === "function") style.setProperty(name, value);
|
|
129
|
+
else style[name] = value;
|
|
130
|
+
};
|
|
131
|
+
const uiResponsiveVarClass = (deviceKey, varName) => {
|
|
132
|
+
return deviceKey === "mobile" ? `jss-rsp-${varName}` : `jss-rsp-${deviceKey}-${varName}`;
|
|
133
|
+
};
|
|
134
|
+
const uiResponsiveAddClass = (target, className) => {
|
|
135
|
+
if (!target || !className) return;
|
|
136
|
+
if (target.classList?.add) {
|
|
137
|
+
target.classList.add(className);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
target.class = uiClass([target.class, className]);
|
|
141
|
+
};
|
|
142
|
+
const uiApplyResponsiveProps = (target, props = {}, rules = []) => {
|
|
143
|
+
if (!target || !props) return target;
|
|
144
|
+
const configurations = [];
|
|
145
|
+
for (const device of UI_RESPONSIVE_DEVICES) {
|
|
146
|
+
const deviceProps = uiResponsivePropsFor(props, device);
|
|
147
|
+
if (deviceProps) configurations.push([device.key, deviceProps]);
|
|
148
|
+
}
|
|
149
|
+
if (!configurations.length) return target;
|
|
150
|
+
const style = target.style || {};
|
|
151
|
+
let hasResponsiveVars = false;
|
|
152
|
+
|
|
153
|
+
for (const rule of rules) {
|
|
154
|
+
const propNames = Array.isArray(rule.prop) ? rule.prop : [rule.prop];
|
|
155
|
+
const setVar = (deviceKey, sourceProps) => {
|
|
156
|
+
const rawValue = uiResponsiveFirstValue(sourceProps, propNames);
|
|
157
|
+
const value = uiResponsiveDefaultValue(rawValue, rule);
|
|
158
|
+
if (!value) return;
|
|
159
|
+
const varName = rule.var || rule.css;
|
|
160
|
+
const prefix = deviceKey === "mobile" ? "--jss-rsp-" : `--jss-rsp-${deviceKey}-`;
|
|
161
|
+
uiResponsiveSetStyle(style, `${prefix}${varName}`, value);
|
|
162
|
+
uiResponsiveAddClass(target, uiResponsiveVarClass(deviceKey, varName));
|
|
163
|
+
hasResponsiveVars = true;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
setVar("mobile", props);
|
|
167
|
+
for (const [deviceKey, deviceProps] of configurations) setVar(deviceKey, deviceProps);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (hasResponsiveVars) {
|
|
171
|
+
if (!target.nodeType) target.style = style;
|
|
172
|
+
uiResponsiveAddClass(target, "jss-rsp");
|
|
173
|
+
}
|
|
174
|
+
return target;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
JSswift.uiResponsiveDevices = UI_RESPONSIVE_DEVICES;
|
|
178
|
+
JSswift.uiResponsiveOmitProps = UI_RESPONSIVE_PROP_KEYS;
|
|
179
|
+
JSswift.uiResponsivePropsFor = uiResponsivePropsFor;
|
|
180
|
+
JSswift.uiResponsiveHasConfig = uiResponsiveHasConfig;
|
|
181
|
+
JSswift.uiResponsiveHasProp = uiResponsiveHasProp;
|
|
182
|
+
JSswift.uiResponsiveClasses = uiResponsiveClassList;
|
|
183
|
+
JSswift.uiApplyResponsiveProps = uiApplyResponsiveProps;
|
|
184
|
+
|
|
185
|
+
const uiOmitBase = JSswift.omit;
|
|
186
|
+
JSswift.omit = (obj, keys = []) => {
|
|
187
|
+
const allKeys = Array.isArray(keys)
|
|
188
|
+
? keys.concat(UI_RESPONSIVE_PROP_KEYS)
|
|
189
|
+
: UI_RESPONSIVE_PROP_KEYS;
|
|
190
|
+
return uiOmitBase(obj, allKeys);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const applyCommonProps = (props = {}) => {
|
|
194
|
+
const classTokens = [];
|
|
195
|
+
const style = {};
|
|
196
|
+
|
|
197
|
+
classTokens.push(
|
|
198
|
+
uiWhen(props.clickable, "jss-clickable"),
|
|
199
|
+
uiWhen(props.dense, "jss-dense"),
|
|
200
|
+
uiWhen(props.flat, "jss-flat"),
|
|
201
|
+
uiWhen(props.border, "jss-border"),
|
|
202
|
+
uiWhen(props.glossy, "jss-glossy"),
|
|
203
|
+
uiWhen(props.glow, "jss-glow"),
|
|
204
|
+
uiWhen(props.glass, "jss-glass"),
|
|
205
|
+
uiWhen(props.shadow, "jss-shadow"),
|
|
206
|
+
uiWhen(props.outline, "jss-outline"),
|
|
207
|
+
uiWhen(props.rounded, "jss-rounded"),
|
|
208
|
+
uiWhen(props.gradient, "jss-gradient"),
|
|
209
|
+
uiWhen(props.textGradient, "jss-text-gradient"),
|
|
210
|
+
uiWhen(props.lightShadow, "jss-light-shadow")
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (uiIsReactive(props.color)) {
|
|
214
|
+
classTokens.push(() => {
|
|
215
|
+
const v = uiUnwrap(props.color);
|
|
216
|
+
const state = normalizeState(v);
|
|
217
|
+
return state ? `jss-state-${state}` : "";
|
|
218
|
+
});
|
|
219
|
+
style.backgroundColor = () => {
|
|
220
|
+
const v = uiUnwrap(props.color);
|
|
221
|
+
const state = normalizeState(v);
|
|
222
|
+
if (state) return "";
|
|
223
|
+
if (v && isTokenCSS(String(v))) return `var(--jss-${v})`;
|
|
224
|
+
return v || "";
|
|
225
|
+
};
|
|
226
|
+
} else {
|
|
227
|
+
const state = normalizeState(props.color);
|
|
228
|
+
if (state) {
|
|
229
|
+
classTokens.push(`jss-state-${state}`);
|
|
230
|
+
} else if (props.color && isTokenCSS(props.color)) {
|
|
231
|
+
style.backgroundColor = `var(--jss-${props.color})`;
|
|
232
|
+
} else if (props.color) {
|
|
233
|
+
style.backgroundColor = props.color;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// facciamo text color per i token
|
|
238
|
+
if (uiIsReactive(props.textColor)) {
|
|
239
|
+
style.color = () => {
|
|
240
|
+
const v = uiUnwrap(props.textColor);
|
|
241
|
+
if (v && isTokenCSS(String(v))) return `var(--jss-${v})`;
|
|
242
|
+
return v || "";
|
|
243
|
+
};
|
|
244
|
+
} else if (props.textColor && isTokenCSS(props.textColor)) {
|
|
245
|
+
style.color = `var(--jss-${props.textColor})`;
|
|
246
|
+
} else if (props.textColor) {
|
|
247
|
+
style.color = props.textColor;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (uiIsReactive(props.size)) {
|
|
251
|
+
classTokens.push(() => {
|
|
252
|
+
const v = uiUnwrap(props.size);
|
|
253
|
+
if (typeof v === "string" && JSswift.uiSizes?.includes(v)) return `jss-size-${v}`;
|
|
254
|
+
return "";
|
|
255
|
+
});
|
|
256
|
+
} else {
|
|
257
|
+
const size = props.size;
|
|
258
|
+
if (typeof size === "string" && JSswift.uiSizes?.includes(size)) {
|
|
259
|
+
classTokens.push(`jss-size-${size}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (uiIsReactive(props.shadow)) {
|
|
264
|
+
classTokens.push(() => {
|
|
265
|
+
const v = uiUnwrap(props.shadow);
|
|
266
|
+
const shadow = normalizeShadow(v);
|
|
267
|
+
return shadow ? `jss-shadow-${shadow}` : "";
|
|
268
|
+
});
|
|
269
|
+
style.boxShadow = () => {
|
|
270
|
+
const v = uiUnwrap(props.shadow);
|
|
271
|
+
const shadow = normalizeShadow(v);
|
|
272
|
+
if (shadow || v == null || v === false) return "";
|
|
273
|
+
return typeof v === "string" ? v : "";
|
|
274
|
+
};
|
|
275
|
+
} else {
|
|
276
|
+
const shadow = normalizeShadow(props.shadow);
|
|
277
|
+
if (shadow) classTokens.push(`jss-shadow-${shadow}`);
|
|
278
|
+
else if (props.shadow && typeof props.shadow === "string") {
|
|
279
|
+
style.boxShadow = props.shadow;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (classTokens.length) {
|
|
284
|
+
props.class = uiClass([props.class, ...classTokens]);
|
|
285
|
+
}
|
|
286
|
+
if (Object.keys(style).length) {
|
|
287
|
+
props.style = { ...style, ...(props.style || {}) };
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const normalizeArgsBase = JSswift.uiNormalizeArgs;
|
|
292
|
+
JSswift.uiNormalizeArgs = function (args) {
|
|
293
|
+
const out = normalizeArgsBase(args);
|
|
294
|
+
const props = out.props || {};
|
|
295
|
+
if (props && Object.prototype.hasOwnProperty.call(props, "children")) {
|
|
296
|
+
const propChildren = props.children;
|
|
297
|
+
if (!out.children || out.children.length === 0) {
|
|
298
|
+
out.children = Array.isArray(propChildren) ? propChildren : [propChildren];
|
|
299
|
+
}
|
|
300
|
+
delete props.children;
|
|
301
|
+
}
|
|
302
|
+
applyCommonProps(props);
|
|
303
|
+
return out;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// --------------------------------
|
|
307
|
+
// 2) UI PRIMITIVES (layout + atoms)
|
|
308
|
+
// --------------------------------
|
|
309
|
+
const UI = window._;
|
|
310
|
+
|
|
311
|
+
/*
|
|
312
|
+
UI.Row
|
|
313
|
+
UI.Col
|
|
314
|
+
UI.Spacer
|
|
315
|
+
UI.Container
|
|
316
|
+
UI.Card
|
|
317
|
+
UI.Btn
|
|
318
|
+
UI.Input
|
|
319
|
+
UI.Select
|
|
320
|
+
UI.Layout
|
|
321
|
+
UI.Footer
|
|
322
|
+
UI.Toolbar
|
|
323
|
+
UI.Grid
|
|
324
|
+
UI.GridCol
|
|
325
|
+
UI.Icon
|
|
326
|
+
UI.Badge
|
|
327
|
+
UI.Avatar
|
|
328
|
+
UI.Chip
|
|
329
|
+
UI.Tooltip
|
|
330
|
+
UI.List
|
|
331
|
+
UI.Item
|
|
332
|
+
UI.Separator
|
|
333
|
+
UI.Checkbox
|
|
334
|
+
UI.Radio
|
|
335
|
+
UI.Toggle
|
|
336
|
+
UI.Slider
|
|
337
|
+
UI.Rating
|
|
338
|
+
UI.Datepicker
|
|
339
|
+
UI.Calendar
|
|
340
|
+
UI.Date
|
|
341
|
+
UI.Time
|
|
342
|
+
UI.Tabs
|
|
343
|
+
UI.RouteTab
|
|
344
|
+
UI.Breadcrumbs
|
|
345
|
+
UI.Pagination
|
|
346
|
+
UI.Spinner
|
|
347
|
+
UI.Progress
|
|
348
|
+
UI.LoadingBar
|
|
349
|
+
UI.Banner
|
|
350
|
+
UI.Header
|
|
351
|
+
UI.Drawer
|
|
352
|
+
UI.Page
|
|
353
|
+
UI.AppShell
|
|
354
|
+
UI.Parallax
|
|
355
|
+
*/
|
|
356
|
+
|
|
357
|
+
function flattenSlotValue(value) {
|
|
358
|
+
if (!value) return null;
|
|
359
|
+
if (!Array.isArray(value)) return value;
|
|
360
|
+
const out = [];
|
|
361
|
+
const stack = value.slice();
|
|
362
|
+
while (stack.length) {
|
|
363
|
+
const item = stack.shift();
|
|
364
|
+
if (!item) continue;
|
|
365
|
+
if (Array.isArray(item)) stack.unshift(...item);
|
|
366
|
+
else out.push(item);
|
|
367
|
+
}
|
|
368
|
+
return out.length ? out : null;
|
|
369
|
+
}
|
|
370
|
+
const STYLE_PROP_TOKEN_MAP = {
|
|
371
|
+
padding: "p",
|
|
372
|
+
paddingTop: "p",
|
|
373
|
+
paddingRight: "p",
|
|
374
|
+
paddingBottom: "p",
|
|
375
|
+
paddingLeft: "p",
|
|
376
|
+
paddingInline: "p",
|
|
377
|
+
paddingInlineStart: "p",
|
|
378
|
+
paddingInlineEnd: "p",
|
|
379
|
+
paddingBlock: "p",
|
|
380
|
+
paddingBlockStart: "p",
|
|
381
|
+
paddingBlockEnd: "p",
|
|
382
|
+
margin: "m",
|
|
383
|
+
marginTop: "m",
|
|
384
|
+
marginRight: "m",
|
|
385
|
+
marginBottom: "m",
|
|
386
|
+
marginLeft: "m",
|
|
387
|
+
marginInline: "m",
|
|
388
|
+
marginInlineStart: "m",
|
|
389
|
+
marginInlineEnd: "m",
|
|
390
|
+
marginBlock: "m",
|
|
391
|
+
marginBlockStart: "m",
|
|
392
|
+
marginBlockEnd: "m",
|
|
393
|
+
width: "w",
|
|
394
|
+
minWidth: "w",
|
|
395
|
+
maxWidth: "w",
|
|
396
|
+
height: "h",
|
|
397
|
+
minHeight: "h",
|
|
398
|
+
maxHeight: "h"
|
|
399
|
+
};
|
|
400
|
+
const uiResponsiveWrapValue = (value) => {
|
|
401
|
+
if (value === true) return "wrap";
|
|
402
|
+
if (value === false) return "nowrap";
|
|
403
|
+
return String(value);
|
|
404
|
+
};
|
|
405
|
+
const uiResponsiveGridColsValue = (value) => {
|
|
406
|
+
if (typeof value === "number") return `repeat(${Math.max(1, Math.round(value))}, minmax(0, 1fr))`;
|
|
407
|
+
return String(value);
|
|
408
|
+
};
|
|
409
|
+
const uiResponsiveGridFlowValue = (value) => {
|
|
410
|
+
const flow = String(value).trim().toLowerCase().replace("-", " ");
|
|
411
|
+
return flow;
|
|
412
|
+
};
|
|
413
|
+
const UI_RESPONSIVE_STYLE_RULES = [
|
|
414
|
+
{ prop: "display", css: "display", var: "display" },
|
|
415
|
+
{ prop: "direction", css: "flex-direction", var: "flex-direction" },
|
|
416
|
+
{ prop: "wrap", css: "flex-wrap", var: "flex-wrap", allowFalse: true, mapValue: uiResponsiveWrapValue },
|
|
417
|
+
{ prop: "align", css: "align-items", var: "align-items" },
|
|
418
|
+
{ prop: "justify", css: "justify-content", var: "justify-content" },
|
|
419
|
+
{ prop: "self", css: "align-self", var: "align-self" },
|
|
420
|
+
{ prop: "justifySelf", css: "justify-self", var: "justify-self" },
|
|
421
|
+
{ prop: "place", css: "place-items", var: "place-items" },
|
|
422
|
+
{ prop: "placeSelf", css: "place-self", var: "place-self" },
|
|
423
|
+
{ prop: ["cols", "columns"], css: "grid-template-columns", var: "grid-template-columns", mapValue: uiResponsiveGridColsValue },
|
|
424
|
+
{ prop: "rows", css: "grid-template-rows", var: "grid-template-rows", mapValue: uiResponsiveGridColsValue },
|
|
425
|
+
{ prop: "flow", css: "grid-auto-flow", var: "grid-auto-flow", mapValue: uiResponsiveGridFlowValue },
|
|
426
|
+
{ prop: "autoRows", css: "grid-auto-rows", var: "grid-auto-rows" },
|
|
427
|
+
{ prop: ["span", "gridColumn"], css: "grid-column", var: "grid-column", number: "raw" },
|
|
428
|
+
{ prop: ["row", "rowSpan"], css: "grid-row", var: "grid-row", number: "raw" },
|
|
429
|
+
{ prop: "area", css: "grid-area", var: "grid-area" },
|
|
430
|
+
{ prop: "gap", css: "gap", var: "gap", token: "gap" },
|
|
431
|
+
{ prop: "rowGap", css: "row-gap", var: "row-gap", token: "gap" },
|
|
432
|
+
{ prop: ["columnGap", "colGap"], css: "column-gap", var: "column-gap", token: "gap" },
|
|
433
|
+
{ prop: "width", css: "width", var: "width", token: "w" },
|
|
434
|
+
{ prop: "minWidth", css: "min-width", var: "min-width", token: "min-w" },
|
|
435
|
+
{ prop: "maxWidth", css: "max-width", var: "max-width", token: "max-w" },
|
|
436
|
+
{ prop: "height", css: "height", var: "height", token: "h" },
|
|
437
|
+
{ prop: "minHeight", css: "min-height", var: "min-height", token: "min-h" },
|
|
438
|
+
{ prop: "maxHeight", css: "max-height", var: "max-height", token: "max-h" },
|
|
439
|
+
{ prop: "padding", css: "padding", var: "padding", token: "p" },
|
|
440
|
+
{ prop: "paddingLeft", css: "padding-left", var: "padding-left", token: "p" },
|
|
441
|
+
{ prop: "paddingRight", css: "padding-right", var: "padding-right", token: "p" },
|
|
442
|
+
{ prop: "paddingTop", css: "padding-top", var: "padding-top", token: "p" },
|
|
443
|
+
{ prop: "paddingBottom", css: "padding-bottom", var: "padding-bottom", token: "p" },
|
|
444
|
+
{ prop: "margin", css: "margin", var: "margin", token: "m" },
|
|
445
|
+
{ prop: "marginLeft", css: "margin-left", var: "margin-left", token: "m" },
|
|
446
|
+
{ prop: "marginRight", css: "margin-right", var: "margin-right", token: "m" },
|
|
447
|
+
{ prop: "marginTop", css: "margin-top", var: "margin-top", token: "m" },
|
|
448
|
+
{ prop: "marginBottom", css: "margin-bottom", var: "margin-bottom", token: "m" },
|
|
449
|
+
{ prop: "fontSize", css: "font-size", var: "font-size", token: "f" },
|
|
450
|
+
{ prop: "fontWeight", css: "font-weight", var: "font-weight", token: "fw", number: "raw" },
|
|
451
|
+
{ prop: "lineHeight", css: "line-height", var: "line-height", token: "lh", number: "raw" },
|
|
452
|
+
{ prop: "letterSpacing", css: "letter-spacing", var: "letter-spacing", token: "ls" },
|
|
453
|
+
{ prop: ["borderRadius", "radius"], css: "border-radius", var: "border-radius", token: "r" },
|
|
454
|
+
{ prop: "overflow", css: "overflow", var: "overflow" },
|
|
455
|
+
{ prop: "order", css: "order", var: "order", number: "raw" },
|
|
456
|
+
];
|
|
457
|
+
const UI_RESPONSIVE_COMMON_STYLE_RULES = UI_RESPONSIVE_STYLE_RULES.filter((rule) => {
|
|
458
|
+
const props = Array.isArray(rule.prop) ? rule.prop : [rule.prop];
|
|
459
|
+
return props.some((prop) => Object.prototype.hasOwnProperty.call(STYLE_PROP_TOKEN_MAP, prop))
|
|
460
|
+
|| props.includes("fontSize")
|
|
461
|
+
|| props.includes("fontWeight")
|
|
462
|
+
|| props.includes("lineHeight")
|
|
463
|
+
|| props.includes("letterSpacing")
|
|
464
|
+
|| props.includes("borderRadius")
|
|
465
|
+
|| props.includes("radius");
|
|
466
|
+
});
|
|
467
|
+
JSswift.uiResponsiveStyleRules = UI_RESPONSIVE_STYLE_RULES;
|
|
468
|
+
JSswift.uiResponsiveCommonStyleRules = UI_RESPONSIVE_COMMON_STYLE_RULES;
|
|
469
|
+
const camelToCssProperty = (name) => name.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
470
|
+
const applyStyleProp = (obj, value, name, tokenName) => {
|
|
471
|
+
if (value == null || value === false || value === "") return;
|
|
472
|
+
obj.style.setProperty(camelToCssProperty(name), unitCover(value, tokenName));
|
|
473
|
+
};
|
|
474
|
+
function setPropertyProps(obj, props) {
|
|
475
|
+
if (props.size) {
|
|
476
|
+
if (typeof props.size === "number") {
|
|
477
|
+
obj.style.setProperty("--jss-font-size", `${props.size}px`);
|
|
478
|
+
} else if (JSswift.uiSizes.includes(props.size)) {
|
|
479
|
+
obj.style.setProperty("--jss-font-size", `var(--jss-font-size-${props.size})`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
Object.entries(STYLE_PROP_TOKEN_MAP).forEach(([name, tokenName]) => {
|
|
484
|
+
if (uiResponsiveHasProp(props, name)) return;
|
|
485
|
+
applyStyleProp(obj, props[name], name, tokenName);
|
|
486
|
+
});
|
|
487
|
+
uiApplyResponsiveProps(obj, props, UI_RESPONSIVE_COMMON_STYLE_RULES);
|
|
488
|
+
|
|
489
|
+
// gradient
|
|
490
|
+
if (props.gradient) {
|
|
491
|
+
if (typeof props.gradient == "number") {
|
|
492
|
+
obj.style.setProperty("--set-gradient-deg", `${props.gradient}deg`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
// radius
|
|
496
|
+
if (props.radius) {
|
|
497
|
+
if (typeof props.radius == "number") {
|
|
498
|
+
obj.style.setProperty("--set-border-radius", `${props.radius}px`);
|
|
499
|
+
} else if (JSswift.uiSizes.includes(props.radius)) {
|
|
500
|
+
obj.style.setProperty("--set-border-radius", `var(--jss-r-${props.radius})`);
|
|
501
|
+
} else {
|
|
502
|
+
obj.style.setProperty("--set-border-radius", `${props.radius}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function uiOptionNode(props = {}, ...children) {
|
|
509
|
+
const el = document.createElement("option");
|
|
510
|
+
if (props && typeof props === "object") {
|
|
511
|
+
if (props.value != null) el.value = String(props.value);
|
|
512
|
+
if (props.label != null) el.label = String(props.label);
|
|
513
|
+
if (props.disabled != null) el.disabled = !!props.disabled;
|
|
514
|
+
if (props.selected != null) el.selected = !!props.selected;
|
|
515
|
+
if (props.class != null) el.className = String(props.class);
|
|
516
|
+
}
|
|
517
|
+
const content = children.flat ? children.flat(Infinity) : children;
|
|
518
|
+
if (content.length) {
|
|
519
|
+
content.forEach((child) => {
|
|
520
|
+
if (child == null || child === false) return;
|
|
521
|
+
if (child instanceof Node) el.appendChild(child);
|
|
522
|
+
else el.appendChild(document.createTextNode(String(child)));
|
|
523
|
+
});
|
|
524
|
+
} else if (props && props.text != null) {
|
|
525
|
+
el.textContent = String(props.text);
|
|
526
|
+
}
|
|
527
|
+
return el;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
JSswift.ui.getSlot = (slots, name) => {
|
|
531
|
+
if (!slots) return null;
|
|
532
|
+
return Object.prototype.hasOwnProperty.call(slots, name) ? slots[name] : null;
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
JSswift.ui.renderSlot = (slots, name, ctx, fallback) => {
|
|
536
|
+
const slot = JSswift.ui.getSlot(slots, name);
|
|
537
|
+
const hasSlot = slot !== null && slot !== undefined;
|
|
538
|
+
const raw = hasSlot ? (typeof slot === "function" ? slot(ctx || {}) : slot) : fallback;
|
|
539
|
+
if (raw == null) return null;
|
|
540
|
+
return flattenSlotValue(JSswift.ui.slot(raw));
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
const renderSlotToArray = (slots, name, ctx, fallback) => {
|
|
544
|
+
const v = JSswift.ui.renderSlot(slots, name, ctx, fallback);
|
|
545
|
+
if (!v) return [];
|
|
546
|
+
return Array.isArray(v) ? v : [v];
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
const UI_SHORTCODE_REGISTRY = new Set();
|
|
550
|
+
let uiShortcodeListenerAttached = false;
|
|
551
|
+
const UI_SHORTCODE_MODIFIERS = new Set(["ctrl", "alt", "shift", "meta"]);
|
|
552
|
+
const UI_SHORTCODE_ALIASES = {
|
|
553
|
+
control: "ctrl",
|
|
554
|
+
ctl: "ctrl",
|
|
555
|
+
option: "alt",
|
|
556
|
+
opt: "alt",
|
|
557
|
+
command: "meta",
|
|
558
|
+
cmd: "meta",
|
|
559
|
+
"⌘": "meta",
|
|
560
|
+
"⌃": "ctrl",
|
|
561
|
+
"⌥": "alt",
|
|
562
|
+
"⇧": "shift",
|
|
563
|
+
esc: "escape",
|
|
564
|
+
return: "enter",
|
|
565
|
+
plus: "+",
|
|
566
|
+
spacebar: "space",
|
|
567
|
+
up: "arrowup",
|
|
568
|
+
down: "arrowdown",
|
|
569
|
+
left: "arrowleft",
|
|
570
|
+
right: "arrowright",
|
|
571
|
+
del: "delete"
|
|
572
|
+
};
|
|
573
|
+
const UI_SHORTCODE_DISPLAY = {
|
|
574
|
+
ctrl: "Ctrl",
|
|
575
|
+
alt: "Alt",
|
|
576
|
+
shift: "Shift",
|
|
577
|
+
meta: "Meta",
|
|
578
|
+
escape: "Esc",
|
|
579
|
+
enter: "Enter",
|
|
580
|
+
tab: "Tab",
|
|
581
|
+
space: "Space",
|
|
582
|
+
backspace: "Backspace",
|
|
583
|
+
delete: "Del",
|
|
584
|
+
arrowup: "Up",
|
|
585
|
+
arrowdown: "Down",
|
|
586
|
+
arrowleft: "Left",
|
|
587
|
+
arrowright: "Right",
|
|
588
|
+
pageup: "PgUp",
|
|
589
|
+
pagedown: "PgDn"
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
const uiIsApplePlatform = () => {
|
|
593
|
+
if (typeof navigator === "undefined") return false;
|
|
594
|
+
const platform = String(navigator.platform || navigator.userAgent || "");
|
|
595
|
+
return /(mac|iphone|ipad|ipod)/i.test(platform);
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
const uiNormalizeShortcodeToken = (token) => {
|
|
599
|
+
if (token == null) return "";
|
|
600
|
+
const raw = String(token).trim().toLowerCase();
|
|
601
|
+
if (!raw) return "";
|
|
602
|
+
return UI_SHORTCODE_ALIASES[raw] || raw;
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
const uiParseShortcode = (rawValue) => {
|
|
606
|
+
if (rawValue == null || rawValue === false) return null;
|
|
607
|
+
const source = String(rawValue).trim();
|
|
608
|
+
if (!source) return null;
|
|
609
|
+
|
|
610
|
+
const parts = source
|
|
611
|
+
.split("+")
|
|
612
|
+
.map(uiNormalizeShortcodeToken)
|
|
613
|
+
.filter(Boolean);
|
|
614
|
+
|
|
615
|
+
if (!parts.length) return null;
|
|
616
|
+
|
|
617
|
+
const spec = {
|
|
618
|
+
raw: source,
|
|
619
|
+
key: "",
|
|
620
|
+
ctrl: false,
|
|
621
|
+
alt: false,
|
|
622
|
+
shift: false,
|
|
623
|
+
meta: false
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
parts.forEach((part) => {
|
|
627
|
+
if (part === "mod") {
|
|
628
|
+
if (uiIsApplePlatform()) spec.meta = true;
|
|
629
|
+
else spec.ctrl = true;
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (UI_SHORTCODE_MODIFIERS.has(part)) {
|
|
633
|
+
spec[part] = true;
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
spec.key = part;
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
if (!spec.key) return null;
|
|
640
|
+
return spec;
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
const uiNormalizeShortcodeList = (rawValue) => {
|
|
644
|
+
if (rawValue == null || rawValue === false) return [];
|
|
645
|
+
const list = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
646
|
+
return list.map((item) => {
|
|
647
|
+
if (item == null || item === false) return null;
|
|
648
|
+
if (typeof item === "object" && !Array.isArray(item)) {
|
|
649
|
+
const parsed = uiParseShortcode(item.shortcode ?? item.shortcut ?? item.keys ?? item.key);
|
|
650
|
+
return parsed ? { ...item, ...parsed } : null;
|
|
651
|
+
}
|
|
652
|
+
const parsed = uiParseShortcode(item);
|
|
653
|
+
return parsed ? { ...parsed } : null;
|
|
654
|
+
}).filter(Boolean);
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
const uiResolveShortcodeList = (props = {}) =>
|
|
658
|
+
uiNormalizeShortcodeList(props.shortcode ?? props.shortcut ?? props.hotkey ?? props.keys);
|
|
659
|
+
|
|
660
|
+
const uiIsShortcodeVisible = (props = {}) =>
|
|
661
|
+
props.showShortcode === true || props.showShortcut === true;
|
|
662
|
+
|
|
663
|
+
const uiFormatShortcodeKey = (key) => {
|
|
664
|
+
const normalized = uiNormalizeShortcodeToken(key);
|
|
665
|
+
if (!normalized) return "";
|
|
666
|
+
const display = { ...UI_SHORTCODE_DISPLAY };
|
|
667
|
+
if (uiIsApplePlatform()) {
|
|
668
|
+
display.alt = "Option";
|
|
669
|
+
display.meta = "Cmd";
|
|
670
|
+
}
|
|
671
|
+
if (display[normalized]) return display[normalized];
|
|
672
|
+
if (normalized.length === 1) return normalized.toUpperCase();
|
|
673
|
+
return normalized.replace(/(^|[-_ ])(\w)/g, (_, prefix, char) => `${prefix}${char.toUpperCase()}`);
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
const uiFormatShortcode = (spec) => {
|
|
677
|
+
if (!spec) return "";
|
|
678
|
+
const parts = [];
|
|
679
|
+
if (spec.ctrl) parts.push(uiFormatShortcodeKey("ctrl"));
|
|
680
|
+
if (spec.alt) parts.push(uiFormatShortcodeKey("alt"));
|
|
681
|
+
if (spec.shift) parts.push(uiFormatShortcodeKey("shift"));
|
|
682
|
+
if (spec.meta) parts.push(uiFormatShortcodeKey("meta"));
|
|
683
|
+
parts.push(uiFormatShortcodeKey(spec.key));
|
|
684
|
+
return parts.filter(Boolean).join("+");
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
const uiFormatShortcodeList = (specs) =>
|
|
688
|
+
(Array.isArray(specs) ? specs : []).map(uiFormatShortcode).filter(Boolean).join(" / ");
|
|
689
|
+
|
|
690
|
+
const uiCreateShortcodeHint = (props = {}, options = {}) => {
|
|
691
|
+
const specs = uiResolveShortcodeList(props);
|
|
692
|
+
if (!uiIsShortcodeVisible(props) || !specs.length || typeof document === "undefined") return null;
|
|
693
|
+
const node = document.createElement("span");
|
|
694
|
+
node.className = options.className || "jss-shortcode";
|
|
695
|
+
node.setAttribute("aria-hidden", "true");
|
|
696
|
+
node.textContent = uiFormatShortcodeList(specs);
|
|
697
|
+
return node;
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
const uiIsEditableEventTarget = (target) => {
|
|
701
|
+
const el = target?.nodeType === 1 ? target : target?.parentElement;
|
|
702
|
+
if (!el || typeof el.closest !== "function") return false;
|
|
703
|
+
if (el.isContentEditable) return true;
|
|
704
|
+
const editable = el.closest("input, textarea, select, [contenteditable], [contenteditable='true'], [contenteditable='plaintext-only']");
|
|
705
|
+
if (!editable) return false;
|
|
706
|
+
if ("disabled" in editable && editable.disabled) return false;
|
|
707
|
+
return true;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
const uiEventMatchesShortcode = (event, spec) => {
|
|
711
|
+
if (!event || !spec) return false;
|
|
712
|
+
if (!!event.ctrlKey !== !!spec.ctrl) return false;
|
|
713
|
+
if (!!event.altKey !== !!spec.alt) return false;
|
|
714
|
+
if (!!event.shiftKey !== !!spec.shift) return false;
|
|
715
|
+
if (!!event.metaKey !== !!spec.meta) return false;
|
|
716
|
+
return uiNormalizeShortcodeToken(event.key) === spec.key;
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
const uiDetachShortcodeListenerIfEmpty = () => {
|
|
720
|
+
if (UI_SHORTCODE_REGISTRY.size || !uiShortcodeListenerAttached || typeof document === "undefined") return;
|
|
721
|
+
document.removeEventListener("keydown", uiHandleShortcodeKeydown, true);
|
|
722
|
+
uiShortcodeListenerAttached = false;
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
function uiHandleShortcodeKeydown(event) {
|
|
726
|
+
if (!UI_SHORTCODE_REGISTRY.size || !event || event.defaultPrevented || event.isComposing) return;
|
|
727
|
+
|
|
728
|
+
const isEditable = uiIsEditableEventTarget(event.target);
|
|
729
|
+
const bindings = Array.from(UI_SHORTCODE_REGISTRY);
|
|
730
|
+
|
|
731
|
+
for (let index = bindings.length - 1; index >= 0; index -= 1) {
|
|
732
|
+
const binding = bindings[index];
|
|
733
|
+
const anchor = binding?.anchor;
|
|
734
|
+
if (!anchor || !anchor.isConnected) {
|
|
735
|
+
UI_SHORTCODE_REGISTRY.delete(binding);
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
if (binding.isEnabled?.() === false) continue;
|
|
739
|
+
|
|
740
|
+
const matched = binding.specs.find((spec) => {
|
|
741
|
+
const allowInEditable = spec.allowInEditable ?? binding.allowInEditable ?? false;
|
|
742
|
+
if (isEditable && !allowInEditable) return false;
|
|
743
|
+
return uiEventMatchesShortcode(event, spec);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
if (!matched) continue;
|
|
747
|
+
|
|
748
|
+
const shouldPreventDefault = matched.preventDefault ?? binding.preventDefault ?? true;
|
|
749
|
+
const shouldStopPropagation = matched.stopPropagation ?? binding.stopPropagation ?? true;
|
|
750
|
+
if (shouldPreventDefault) event.preventDefault();
|
|
751
|
+
if (shouldStopPropagation) event.stopPropagation();
|
|
752
|
+
|
|
753
|
+
const result = binding.action?.(event, matched, anchor);
|
|
754
|
+
if (result !== false) break;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
uiDetachShortcodeListenerIfEmpty();
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const uiRegisterShortcode = (anchor, props = {}, options = {}) => {
|
|
761
|
+
const specs = uiResolveShortcodeList(props);
|
|
762
|
+
if (!anchor || !specs.length || typeof document === "undefined") return null;
|
|
763
|
+
|
|
764
|
+
const binding = {
|
|
765
|
+
anchor,
|
|
766
|
+
specs,
|
|
767
|
+
action: typeof options.action === "function" ? options.action : () => anchor.click?.(),
|
|
768
|
+
isEnabled: typeof options.isEnabled === "function" ? options.isEnabled : null,
|
|
769
|
+
allowInEditable: !!options.allowInEditable,
|
|
770
|
+
preventDefault: options.preventDefault ?? true,
|
|
771
|
+
stopPropagation: options.stopPropagation ?? true
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
UI_SHORTCODE_REGISTRY.add(binding);
|
|
775
|
+
|
|
776
|
+
if (!uiShortcodeListenerAttached) {
|
|
777
|
+
document.addEventListener("keydown", uiHandleShortcodeKeydown, true);
|
|
778
|
+
uiShortcodeListenerAttached = true;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const dispose = () => {
|
|
782
|
+
UI_SHORTCODE_REGISTRY.delete(binding);
|
|
783
|
+
uiDetachShortcodeListenerIfEmpty();
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
JSswift._registerCleanup(anchor, dispose);
|
|
787
|
+
return dispose;
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
const uiFocusShortcutTarget = (target, options = {}) => {
|
|
791
|
+
if (!target || typeof target.focus !== "function") return false;
|
|
792
|
+
try {
|
|
793
|
+
target.focus({ preventScroll: options.preventScroll ?? true });
|
|
794
|
+
} catch {
|
|
795
|
+
target.focus();
|
|
796
|
+
}
|
|
797
|
+
if (options.selectText && typeof target.select === "function") {
|
|
798
|
+
try { target.select(); } catch { }
|
|
799
|
+
}
|
|
800
|
+
return true;
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
const unitCover = (v, name = 'size') => {
|
|
804
|
+
if (typeof v === "number") return v + "px";
|
|
805
|
+
if (JSswift.uiSizes.includes(v)) return `var(--jss-${name}-${v})`;
|
|
806
|
+
if (typeof v === "string") return v;
|
|
807
|
+
return v;
|
|
808
|
+
};
|
|
809
|
+
|