@simai-studio/ui 5.20261023.214 → 5.20261025.207
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 +4 -4
- package/distr/component/button-group/css/button-group.min.css +1 -1
- package/distr/core/contracts/public-variables.v1.json +88 -0
- package/distr/core/contracts/third-party-notices.v1.json +1 -1
- package/distr/core/css/core.css +3 -2
- package/distr/core/js/composition/overlay.mjs +472 -24
- package/distr/core/js/composition/sortable-inserter.mjs +534 -0
- package/distr/core/js/core-loader.js +1 -1
- package/distr/core/js/core-loader.min.js +1 -1
- package/distr/core/js/core-rules.js +242 -185
- package/distr/core/js/core-rules.min.js +1 -1
- package/distr/core/js/open-surface-mark.js +88 -0
- package/distr/core/js/template-utilities.generated.json +3 -0
- package/distr/rule/js/rule.min.js +1 -1
- package/distr/rule/rule.json +47 -1
- package/distr/smart/color/css/color.min.css +1 -0
- package/distr/smart/color/js/color.min.js +36 -17
- package/distr/smart/color/smart.manifest.json +45 -4
- package/distr/smart/color/template/default.js +13 -2
- package/distr/smart/composition-overlay/css/composition-overlay.min.css +1 -1
- package/distr/smart/composition-overlay/js/composition-overlay.min.js +1 -1
- package/distr/smart/composition-overlay/smart.manifest.json +178 -11
- package/distr/smart/dropdown/css/dropdown.min.css +1 -0
- package/distr/smart/dropdown/js/dropdown.min.js +41 -21
- package/distr/smart/dropdown/smart.manifest.json +62 -3
- package/distr/smart/dropdown/template/default.js +5 -1
- package/distr/smart/field-renderers/js/field-renderers.min.js +54 -42
- package/distr/smart/image-field/css/image-field.min.css +1 -0
- package/distr/smart/image-field/js/image-field.min.js +62 -0
- package/distr/smart/image-field/smart.manifest.json +519 -0
- package/distr/smart/image-field/studio.fixture.json +15 -0
- package/distr/smart/image-field/studio.scenario.json +22 -0
- package/distr/smart/image-field/template/default.js +125 -0
- package/distr/smart/inputs/css/inputs.min.css +1 -0
- package/distr/smart/inputs/js/inputs.min.js +93 -75
- package/distr/smart/inputs/smart.manifest.json +62 -3
- package/distr/smart/inputs/template/default.js +8 -2
- package/distr/smart/sortable/css/sortable.min.css +1 -1
- package/distr/smart/sortable/js/sortable.min.js +1 -1
- package/distr/smart/sortable/smart.manifest.json +101 -14
- package/distr/smart/switch/css/switch.min.css +1 -0
- package/distr/smart/switch/js/switch.min.js +31 -13
- package/distr/smart/switch/smart.manifest.json +62 -3
- package/distr/smart/switch/template/default.js +2 -0
- package/distr/smart/textarea/css/textarea.min.css +1 -0
- package/distr/smart/textarea/js/textarea.min.js +51 -32
- package/distr/smart/textarea/smart.manifest.json +62 -3
- package/distr/smart/textarea/template/default.js +8 -1
- package/package-manifest.json +50 -39
- package/package.json +5 -4
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// While a transient surface is open the root says so, and a component whose own
|
|
2
|
+
// Escape closes something larger -- a drawer, a modal, a record panel -- stands
|
|
3
|
+
// back. They all listen on the document in capture, where stopPropagation
|
|
4
|
+
// cannot reach a listener on the same node and the one registered first wins
|
|
5
|
+
// whatever it is: without a shared mark, one press closed the surface and the
|
|
6
|
+
// window behind it together.
|
|
7
|
+
//
|
|
8
|
+
// The mark started inside sf-popover, which made it that component's state
|
|
9
|
+
// instead of the protocol it is: a dropdown list is the same kind of surface and
|
|
10
|
+
// raised nothing, so Escape over an open list closed the record panel behind it
|
|
11
|
+
// (Larena storage QA, 2026-10-22) -- and a drawer and a modal read the same mark,
|
|
12
|
+
// so the same press closed those too. It lives here now, raised by every surface
|
|
13
|
+
// that owns Escape while it is open and read by every component that owns Escape
|
|
14
|
+
// for something larger.
|
|
15
|
+
//
|
|
16
|
+
// The attribute name is unchanged, because it is already the published protocol:
|
|
17
|
+
// `document.documentElement.dataset.sfPopoverOpen`.
|
|
18
|
+
const OPEN_MARK = 'sfPopoverOpen';
|
|
19
|
+
|
|
20
|
+
// A count, not a flag: two surfaces can be open at once -- a dropdown inside a
|
|
21
|
+
// popover -- and the first to close must not clear the mark the second needs.
|
|
22
|
+
const held = new WeakSet();
|
|
23
|
+
|
|
24
|
+
// The same holders in the order they opened, so the one opened last -- the
|
|
25
|
+
// innermost layer -- is known. The mark answers "is anything open"; this answers
|
|
26
|
+
// "is it me". Two surfaces that both listen on the document in capture cannot
|
|
27
|
+
// settle it with stopPropagation, which does not reach a listener on the same
|
|
28
|
+
// node: a calendar opened inside a popover closed together with the popover, and
|
|
29
|
+
// a popover closed over a dropdown list it held and left the list open.
|
|
30
|
+
//
|
|
31
|
+
// Kept on a shared global, not in module scope: every Smart bundle carries its
|
|
32
|
+
// own copy of this module, so a module-scope list in the popover's bundle never
|
|
33
|
+
// saw the calendar the datepicker's bundle opened. The count lives on the root
|
|
34
|
+
// for the same reason.
|
|
35
|
+
const LAYERS_KEY = Symbol.for('sf.openSurfaceLayers');
|
|
36
|
+
function openLayers() {
|
|
37
|
+
const scope = globalThis;
|
|
38
|
+
if (!Array.isArray(scope[LAYERS_KEY])) scope[LAYERS_KEY] = [];
|
|
39
|
+
return scope[LAYERS_KEY];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function step(delta) {
|
|
43
|
+
const root = globalThis.document?.documentElement;
|
|
44
|
+
if (!root) return;
|
|
45
|
+
const next = Math.max(0, Number(root.dataset[OPEN_MARK] || 0) + delta);
|
|
46
|
+
if (next) root.dataset[OPEN_MARK] = String(next);
|
|
47
|
+
else delete root.dataset[OPEN_MARK];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Idempotent for one owner, so a component can call it from every update with
|
|
51
|
+
// its own open state and only a change moves the count. An owner that is removed
|
|
52
|
+
// while open releases it the same way, from wherever it tears down.
|
|
53
|
+
export function holdOpenSurfaceMark(owner, open) {
|
|
54
|
+
if (!owner) return;
|
|
55
|
+
const wanted = Boolean(open);
|
|
56
|
+
if (wanted === held.has(owner)) return;
|
|
57
|
+
const layers = openLayers();
|
|
58
|
+
if (wanted) {
|
|
59
|
+
held.add(owner);
|
|
60
|
+
layers.push(owner);
|
|
61
|
+
} else {
|
|
62
|
+
held.delete(owner);
|
|
63
|
+
const at = layers.lastIndexOf(owner);
|
|
64
|
+
if (at >= 0) layers.splice(at, 1);
|
|
65
|
+
}
|
|
66
|
+
step(wanted ? 1 : -1);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// What a surface asks before its own Escape closes it: whether it is the
|
|
70
|
+
// innermost open layer. A holder that left the document without releasing is
|
|
71
|
+
// passed over rather than allowed to hold every Escape on the page. An owner
|
|
72
|
+
// that holds nothing is the top only when nothing else is open.
|
|
73
|
+
export function isTopOpenSurface(owner) {
|
|
74
|
+
const layers = openLayers();
|
|
75
|
+
for (let at = layers.length - 1; at >= 0; at -= 1) {
|
|
76
|
+
const layer = layers[at];
|
|
77
|
+
if (layer?.isConnected === false) continue;
|
|
78
|
+
return layer === owner;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// What a component asks before its own Escape closes something larger.
|
|
84
|
+
export function isOpenSurfaceMarked() {
|
|
85
|
+
return Boolean(globalThis.document?.documentElement?.dataset?.[OPEN_MARK]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const OPEN_SURFACE_MARK = OPEN_MARK;
|