@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.
Files changed (50) hide show
  1. package/README.md +4 -4
  2. package/distr/component/button-group/css/button-group.min.css +1 -1
  3. package/distr/core/contracts/public-variables.v1.json +88 -0
  4. package/distr/core/contracts/third-party-notices.v1.json +1 -1
  5. package/distr/core/css/core.css +3 -2
  6. package/distr/core/js/composition/overlay.mjs +472 -24
  7. package/distr/core/js/composition/sortable-inserter.mjs +534 -0
  8. package/distr/core/js/core-loader.js +1 -1
  9. package/distr/core/js/core-loader.min.js +1 -1
  10. package/distr/core/js/core-rules.js +242 -185
  11. package/distr/core/js/core-rules.min.js +1 -1
  12. package/distr/core/js/open-surface-mark.js +88 -0
  13. package/distr/core/js/template-utilities.generated.json +3 -0
  14. package/distr/rule/js/rule.min.js +1 -1
  15. package/distr/rule/rule.json +47 -1
  16. package/distr/smart/color/css/color.min.css +1 -0
  17. package/distr/smart/color/js/color.min.js +36 -17
  18. package/distr/smart/color/smart.manifest.json +45 -4
  19. package/distr/smart/color/template/default.js +13 -2
  20. package/distr/smart/composition-overlay/css/composition-overlay.min.css +1 -1
  21. package/distr/smart/composition-overlay/js/composition-overlay.min.js +1 -1
  22. package/distr/smart/composition-overlay/smart.manifest.json +178 -11
  23. package/distr/smart/dropdown/css/dropdown.min.css +1 -0
  24. package/distr/smart/dropdown/js/dropdown.min.js +41 -21
  25. package/distr/smart/dropdown/smart.manifest.json +62 -3
  26. package/distr/smart/dropdown/template/default.js +5 -1
  27. package/distr/smart/field-renderers/js/field-renderers.min.js +54 -42
  28. package/distr/smart/image-field/css/image-field.min.css +1 -0
  29. package/distr/smart/image-field/js/image-field.min.js +62 -0
  30. package/distr/smart/image-field/smart.manifest.json +519 -0
  31. package/distr/smart/image-field/studio.fixture.json +15 -0
  32. package/distr/smart/image-field/studio.scenario.json +22 -0
  33. package/distr/smart/image-field/template/default.js +125 -0
  34. package/distr/smart/inputs/css/inputs.min.css +1 -0
  35. package/distr/smart/inputs/js/inputs.min.js +93 -75
  36. package/distr/smart/inputs/smart.manifest.json +62 -3
  37. package/distr/smart/inputs/template/default.js +8 -2
  38. package/distr/smart/sortable/css/sortable.min.css +1 -1
  39. package/distr/smart/sortable/js/sortable.min.js +1 -1
  40. package/distr/smart/sortable/smart.manifest.json +101 -14
  41. package/distr/smart/switch/css/switch.min.css +1 -0
  42. package/distr/smart/switch/js/switch.min.js +31 -13
  43. package/distr/smart/switch/smart.manifest.json +62 -3
  44. package/distr/smart/switch/template/default.js +2 -0
  45. package/distr/smart/textarea/css/textarea.min.css +1 -0
  46. package/distr/smart/textarea/js/textarea.min.js +51 -32
  47. package/distr/smart/textarea/smart.manifest.json +62 -3
  48. package/distr/smart/textarea/template/default.js +8 -1
  49. package/package-manifest.json +50 -39
  50. 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;
@@ -201,6 +201,9 @@
201
201
  "font-weight/default",
202
202
  "position/default"
203
203
  ],
204
+ "cl-image-field": [
205
+ "position/default"
206
+ ],
204
207
  "cl-inputs": [
205
208
  "align-items/default",
206
209
  "display/default",