@octane-xplat/ui 0.2.1 → 0.4.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.
Files changed (126) hide show
  1. package/README.md +46 -0
  2. package/dist/native/octane-client-build.json +1 -1
  3. package/dist/native/ui.js +52 -19
  4. package/dist/native/ui10.js +25 -45
  5. package/dist/native/ui11.js +52 -57
  6. package/dist/native/ui12.js +47 -16
  7. package/dist/native/ui13.js +24 -18
  8. package/dist/native/ui14.js +117 -12
  9. package/dist/native/ui15.js +78 -17
  10. package/dist/native/ui16.js +88 -115
  11. package/dist/native/ui17.js +29 -19
  12. package/dist/native/ui18.js +34 -12
  13. package/dist/native/ui19.js +244 -8
  14. package/dist/native/ui2.js +10 -48
  15. package/dist/native/ui20.js +28 -0
  16. package/dist/native/ui21.js +383 -0
  17. package/dist/native/ui22.js +36 -0
  18. package/dist/native/ui23.js +55 -0
  19. package/dist/native/ui24.js +83 -0
  20. package/dist/native/ui25.js +141 -0
  21. package/dist/native/ui26.js +12 -0
  22. package/dist/native/ui27.js +61 -0
  23. package/dist/native/ui28.js +40 -0
  24. package/dist/native/ui29.js +108 -0
  25. package/dist/native/ui3.js +17 -20
  26. package/dist/native/ui30.js +18 -0
  27. package/dist/native/ui31.js +58 -0
  28. package/dist/native/ui32.js +58 -0
  29. package/dist/native/ui33.js +38 -0
  30. package/dist/native/ui34.js +53 -0
  31. package/dist/native/ui35.js +105 -0
  32. package/dist/native/ui36.js +10 -0
  33. package/dist/native/ui37.js +44 -0
  34. package/dist/native/ui38.js +197 -0
  35. package/dist/native/ui39.js +105 -0
  36. package/dist/native/ui4.js +23 -48
  37. package/dist/native/ui40.js +58 -0
  38. package/dist/native/ui41.js +19 -0
  39. package/dist/native/ui42.js +8 -0
  40. package/dist/native/ui43.js +38 -0
  41. package/dist/native/ui44.js +267 -0
  42. package/dist/native/ui45.js +28 -0
  43. package/dist/native/ui46.js +35 -0
  44. package/dist/native/ui47.js +41 -0
  45. package/dist/native/ui48.js +72 -0
  46. package/dist/native/ui49.js +66 -0
  47. package/dist/native/ui5.js +37 -34
  48. package/dist/native/ui50.js +27 -0
  49. package/dist/native/ui51.js +13 -0
  50. package/dist/native/ui52.js +92 -0
  51. package/dist/native/ui53.js +34 -0
  52. package/dist/native/ui54.js +17 -0
  53. package/dist/native/ui55.js +156 -0
  54. package/dist/native/ui56.js +33 -0
  55. package/dist/native/ui57.js +14 -0
  56. package/dist/native/ui58.js +22 -0
  57. package/dist/native/ui59.js +8 -0
  58. package/dist/native/ui6.js +79 -20
  59. package/dist/native/ui60.js +108 -0
  60. package/dist/native/ui61.js +76 -0
  61. package/dist/native/ui7.js +44 -65
  62. package/dist/native/ui8.js +25 -17
  63. package/dist/native/ui9.js +24 -12
  64. package/dist/web/octane-client-build.json +1 -1
  65. package/dist/web/ui.js +51 -19
  66. package/dist/web/ui10.js +33 -30
  67. package/dist/web/ui11.js +40 -55
  68. package/dist/web/ui12.js +36 -15
  69. package/dist/web/ui13.js +212 -20
  70. package/dist/web/ui14.js +84 -14
  71. package/dist/web/ui15.js +425 -46
  72. package/dist/web/ui16.js +12 -93
  73. package/dist/web/ui17.js +246 -28
  74. package/dist/web/ui18.js +238 -15
  75. package/dist/web/ui19.js +36 -8
  76. package/dist/web/ui2.js +15 -103
  77. package/dist/web/ui20.js +85 -0
  78. package/dist/web/ui21.js +111 -0
  79. package/dist/web/ui22.js +108 -0
  80. package/dist/web/ui23.js +96 -0
  81. package/dist/web/ui24.js +32 -0
  82. package/dist/web/ui25.js +108 -0
  83. package/dist/web/ui26.js +45 -0
  84. package/dist/web/ui27.js +16 -0
  85. package/dist/web/ui28.js +11 -0
  86. package/dist/web/ui29.js +58 -0
  87. package/dist/web/ui3.js +30 -27
  88. package/dist/web/ui30.js +34 -0
  89. package/dist/web/ui31.js +123 -0
  90. package/dist/web/ui32.js +44 -0
  91. package/dist/web/ui33.js +159 -0
  92. package/dist/web/ui34.js +70 -0
  93. package/dist/web/ui35.js +57 -0
  94. package/dist/web/ui36.js +22 -0
  95. package/dist/web/ui37.js +7 -0
  96. package/dist/web/ui38.js +38 -0
  97. package/dist/web/ui39.js +154 -0
  98. package/dist/web/ui4.js +46 -24
  99. package/dist/web/ui40.js +43 -0
  100. package/dist/web/ui41.js +42 -0
  101. package/dist/web/ui42.js +76 -0
  102. package/dist/web/ui43.js +42 -0
  103. package/dist/web/ui44.js +62 -0
  104. package/dist/web/ui45.js +9 -0
  105. package/dist/web/ui46.js +45 -0
  106. package/dist/web/ui47.js +13 -0
  107. package/dist/web/ui48.js +63 -0
  108. package/dist/web/ui49.js +47 -0
  109. package/dist/web/ui5.js +158 -52
  110. package/dist/web/ui50.js +17 -0
  111. package/dist/web/ui51.js +149 -0
  112. package/dist/web/ui52.js +42 -0
  113. package/dist/web/ui53.js +17 -0
  114. package/dist/web/ui54.js +9 -0
  115. package/dist/web/ui55.js +22 -0
  116. package/dist/web/ui56.js +8 -0
  117. package/dist/web/ui57.js +44 -0
  118. package/dist/web/ui58.js +46 -0
  119. package/dist/web/ui6.js +85 -22
  120. package/dist/web/ui7.js +46 -41
  121. package/dist/web/ui8.js +28 -11
  122. package/dist/web/ui9.js +32 -13
  123. package/package.json +18 -6
  124. package/src/theme/tokens.css +444 -47
  125. package/types/index.d.ts +180 -29
  126. package/types/props.d.ts +553 -8
@@ -0,0 +1,45 @@
1
+ import { __s, bag5, clone, createElement, delegateEvents, hookSlots, queueRefAttach, queueRefDetach, setEventHandler, template, useEffect, useMemo, useRef } from "octane";
2
+ import { bindSignalChild, enableSignalBindings, replaceRef, setClassNameIfChanged } from "octane/internal/client";
3
+ //#region src/Modal.web.tsrx
4
+ enableSignalBindings(1, true);
5
+ delegateEvents(["close"]);
6
+ var _t$0 = /* @__PURE__ */ template("<dialog></dialog>");
7
+ var _hs$ = /* @__PURE__ */ hookSlots(3);
8
+ var _rm$1 = [
9
+ "r",
10
+ "b",
11
+ "a"
12
+ ];
13
+ var Modal = /* @__PURE__ */ __s(function Modal(props, __s, __extra) {
14
+ const el = useRef(null, _hs$ + 0);
15
+ const content = useMemo(() => props.component ? createElement(props.component, props.params ?? {}) : props.children, [props], _hs$ + 1);
16
+ const presentation = props.presentation;
17
+ const className = presentation === "sheet" ? "vx-modal vx-modal--sheet" : presentation === "dialog" ? "vx-modal vx-modal--dialog" : presentation === "fullscreen" || !presentation && props.fullscreen ? "vx-modal vx-modal--fullscreen" : "vx-modal";
18
+ useEffect(() => {
19
+ const d = el.current;
20
+ if (!d) return;
21
+ if (props.open && !d.open) d.showModal();
22
+ else if (!props.open && d.open) d.close();
23
+ }, [props.open], _hs$ + 2);
24
+ if (__s.block.pending && !__s.block.crossRenderUpdate) return;
25
+ let _b = __s.slots[0];
26
+ if (_b === void 0) {
27
+ let _m0, _m1;
28
+ const _root = clone(_t$0);
29
+ queueRefAttach(__s, _m1 = el, _m0 = _root);
30
+ (__s.cleanups ??= []).push(() => _b && queueRefDetach(_b.b, _b.a));
31
+ setEventHandler(_root, "$$close", () => props.onClose?.());
32
+ _b = bag5(__s, _root, _m0, _m1, void 0, null, void 0);
33
+ __s.refFields = _rm$1;
34
+ } else {
35
+ {
36
+ const _r = el;
37
+ if (_r !== _b.b) _b.b = replaceRef(__s, _b.b, _r, _b.a);
38
+ }
39
+ setEventHandler(_b.a, "$$close", () => props.onClose?.());
40
+ }
41
+ _b.c = setClassNameIfChanged(className, _b.c, _b.a);
42
+ _b.f = bindSignalChild(__s, _b.f, 1, _b.a, content, "b:44cec141", null, void 0, void 0, void 0, true);
43
+ });
44
+ //#endregion
45
+ export { Modal };
@@ -0,0 +1,16 @@
1
+ import { hookSlots, useSyncExternalStore } from "octane";
2
+ //#region src/theme/colorScheme.web.ts
3
+ function getColorScheme() {
4
+ return typeof matchMedia === "function" && matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
5
+ }
6
+ function subscribeSystemScheme(cb) {
7
+ const mq = matchMedia("(prefers-color-scheme: dark)");
8
+ mq.addEventListener("change", cb);
9
+ return () => mq.removeEventListener("change", cb);
10
+ }
11
+ function useColorScheme() {
12
+ return useSyncExternalStore(subscribeSystemScheme, getColorScheme, _h$0);
13
+ }
14
+ var _h$0 = /* @__PURE__ */ Symbol(/* @__PURE__ */ hookSlots(1));
15
+ //#endregion
16
+ export { getColorScheme, subscribeSystemScheme, useColorScheme };
@@ -0,0 +1,11 @@
1
+ //#region src/cx.ts
2
+ /** NS `className` splits on ' ' only, and the universal driver applies the
3
+ * prop via `String(value)` — an array would arrive comma-joined and match
4
+ * no class at all. Native leaves normalize through cx() before handing
5
+ * className to an intrinsic. (The DOM renderer already flattens arrays,
6
+ * so web leaves don't need this.) */
7
+ function cx(...parts) {
8
+ return parts.flat(Infinity).filter(Boolean).join(" ");
9
+ }
10
+ //#endregion
11
+ export { cx };
@@ -0,0 +1,58 @@
1
+ import { getColorScheme, subscribeSystemScheme } from "./ui27.js";
2
+ import { cx } from "./ui28.js";
3
+ import { hookSlots, useSyncExternalStore } from "octane";
4
+ //#region src/theme/theme-scheme.ts
5
+ var preference = "system";
6
+ var listeners = /* @__PURE__ */ new Set();
7
+ var emit = () => listeners.forEach((l) => l());
8
+ /** App-level theme override. 'system' clears the override and follows the OS. */
9
+ function setThemePreference(p) {
10
+ if (p !== preference) {
11
+ preference = p;
12
+ emit();
13
+ }
14
+ }
15
+ function getThemePreference() {
16
+ return preference;
17
+ }
18
+ /** The effective scheme: explicit override if set, else system appearance. */
19
+ function getThemeScheme() {
20
+ return preference === "system" ? getColorScheme() : preference;
21
+ }
22
+ function subscribe(cb) {
23
+ listeners.add(cb);
24
+ const offSystem = subscribeSystemScheme(cb);
25
+ return () => {
26
+ listeners.delete(cb);
27
+ offSystem();
28
+ };
29
+ }
30
+ /** Reactive effective scheme — re-renders on override or OS change. */
31
+ function useThemeScheme() {
32
+ return useSyncExternalStore(subscribe, getThemeScheme, _h$0);
33
+ }
34
+ /** Class string to stamp on independently-mounted roots (portal hosts,
35
+ * overlay/sheet/modal/toast containers): 'ns-dark dark' when effective
36
+ * dark, '' otherwise. Both names because tokens.css publishes both
37
+ * selectors and hosts may render either vocabulary. */
38
+ function themeSchemeClasses() {
39
+ return getThemeScheme() === "dark" ? "ns-dark dark" : "";
40
+ }
41
+ /** Subscribe imperative hosts to effective-scheme changes; returns an
42
+ * unsubscribe. Use for hosts that live outside any render cycle. */
43
+ function onThemeSchemeChange(cb) {
44
+ return subscribe(cb);
45
+ }
46
+ /** Stamp `base + themeSchemeClasses()` onto an imperative host (NS view or
47
+ * DOM element) and keep it live — returns an unsubscribe to call when the
48
+ * host closes. Works on both leaves since both honor `.className`. */
49
+ function applyThemeClasses(view, base) {
50
+ const apply = () => {
51
+ view.className = cx(base, themeSchemeClasses());
52
+ };
53
+ apply();
54
+ return onThemeSchemeChange(apply);
55
+ }
56
+ var _h$0 = /* @__PURE__ */ Symbol(/* @__PURE__ */ hookSlots(1));
57
+ //#endregion
58
+ export { applyThemeClasses, getThemePreference, getThemeScheme, onThemeSchemeChange, setThemePreference, themeSchemeClasses, useThemeScheme };
package/dist/web/ui3.js CHANGED
@@ -1,28 +1,31 @@
1
- import { __s, bag5, clone, setStyle, template } from "octane";
2
- import { childTextHoleUpdate, updateFreshClassName } from "octane/internal/client";
3
- //#region src/Row.web.tsrx
4
- var _t$0 = /* @__PURE__ */ template("<div></div>");
5
- var Row = /* @__PURE__ */ __s(function Row(props, __s, __extra) {
6
- let _b = __s.slots[0];
7
- if (_b === void 0) {
8
- let _m1;
9
- const _root = clone(_t$0);
10
- _m1 = _root;
11
- _b = bag5(__s, _root, void 0, _m1, void 0, null, void 0);
12
- }
13
- _b.a = updateFreshClassName(["vx-row", props.className], _b.a, _b.b);
14
- {
15
- const _v = props.style;
16
- if (_b.c !== _v) {
17
- setStyle(_b.b, _v, _b.c);
18
- _b.c = _v;
19
- }
20
- }
21
- {
22
- const _v = props.children;
23
- _b.d = childTextHoleUpdate(__s, 1, _b.b, _v, _b.d, _b.e);
24
- _b.e = _v;
25
- }
26
- });
1
+ //#region src/glass.ts
2
+ /** Normalize the `glass` surface prop into the config object handed to
3
+ * `iosGlassEffect` on native. Always returns an object — the upstream
4
+ * string shorthand silently drops `interactive` on the layout's update
5
+ * path, and an empty config defaults the variant to 'regular' here rather
6
+ * than upstream's own fallback. `false`/'none'/'identity' → no glass. */
7
+ function glassConfigOf(glass) {
8
+ if (!glass || glass === "none" || glass === "identity") return;
9
+ const c = typeof glass === "string" ? { variant: glass } : glass === true ? {} : glass;
10
+ if (c.variant === "none" || c.variant === "identity") return;
11
+ return {
12
+ variant: "regular",
13
+ ...c
14
+ };
15
+ }
16
+ /** `vx-glass` classes shared by web (real styling) and native (hook for
17
+ * app-supplied fallback CSS on non-glass OSes). */
18
+ function glassClassOf(glass) {
19
+ const c = glassConfigOf(glass);
20
+ if (!c) return;
21
+ return c.variant === "clear" ? "vx-glass vx-glass--clear" : "vx-glass";
22
+ }
23
+ /** Style merge for the web approximation — `tint` becomes the surface
24
+ * color (the class's translucent fallback is a weaker claim than an
25
+ * explicit inline value). Caller spreads result into its style object. */
26
+ function glassStyleOf(glass) {
27
+ const c = glassConfigOf(glass);
28
+ return c?.tint ? { backgroundColor: c.tint } : {};
29
+ }
27
30
  //#endregion
28
- export { Row };
31
+ export { glassClassOf, glassConfigOf, glassStyleOf };
@@ -0,0 +1,34 @@
1
+ import { applyThemeClasses } from "./ui29.js";
2
+ import { createRoot } from "octane";
3
+ //#region src/modal-service.web.ts
4
+ /** Open a component in a document-level dialog and resolve with close(value). */
5
+ var openModal = (Component, params, options = {}) => new Promise((resolve) => {
6
+ const dialog = document.createElement("dialog");
7
+ dialog.className = options.presentation === "sheet" ? "vx-modal vx-modal--sheet" : options.presentation === "dialog" ? "vx-modal vx-modal--dialog" : options.presentation === "fullscreen" || !options.presentation && options.fullscreen ? "vx-modal vx-modal--fullscreen" : "vx-modal";
8
+ const unbindTheme = applyThemeClasses(dialog, dialog.className);
9
+ document.body.appendChild(dialog);
10
+ const root = createRoot(dialog);
11
+ let finished = false;
12
+ const finish = (result) => {
13
+ if (finished) return;
14
+ finished = true;
15
+ unbindTheme();
16
+ root.unmount();
17
+ dialog.remove();
18
+ resolve(result);
19
+ };
20
+ const close = (result) => {
21
+ if (finished) return;
22
+ if (dialog.open) dialog.close();
23
+ finish(result);
24
+ };
25
+ dialog.addEventListener("close", () => finish());
26
+ dialog.addEventListener("cancel", () => finish());
27
+ root.render(Component, {
28
+ params,
29
+ close
30
+ });
31
+ dialog.showModal();
32
+ });
33
+ //#endregion
34
+ export { openModal };
@@ -0,0 +1,123 @@
1
+ import { cx } from "./ui28.js";
2
+ import { useThemeScheme } from "./ui29.js";
3
+ import { bag1, bag2, bag9, child, clone, delegateEvents, drainFrag, hookSlots, ifBlock, markDangerouslySetInnerHTMLChildren, portal, setEventHandler, sibling, snapshotSpread, template, withSlot } from "octane";
4
+ import { bindSignalChild, bindSignalHostPropSources, enableSignalBindings } from "octane/internal/client";
5
+ //#region src/Overlay.web.tsrx
6
+ enableSignalBindings(1, true);
7
+ delegateEvents(["click"]);
8
+ var _t$0 = /* @__PURE__ */ template("<div class=\"vx-overlay-shade\"></div>");
9
+ var _t$1 = /* @__PURE__ */ template("<div><!><div class=\"vx-overlay-content\"></div></div>");
10
+ var _t$2 = /* @__PURE__ */ template("<!>", 0, 1);
11
+ var _h$0 = /* @__PURE__ */ Symbol(/* @__PURE__ */ hookSlots(4));
12
+ function __then$2(__props, __s, __extra) {
13
+ const props = __extra[0];
14
+ let _b = __s.slots[0];
15
+ if (_b === void 0) {
16
+ let _m0;
17
+ const _root = clone(_t$0);
18
+ _m0 = _root;
19
+ setEventHandler(_root, "$$click", props.onDismiss);
20
+ _b = bag1(__s, _root, _m0);
21
+ } else setEventHandler(_b.a, "$$click", props.onDismiss);
22
+ }
23
+ var _rm$5 = [
24
+ "s",
25
+ "e",
26
+ "d"
27
+ ];
28
+ function __portal$1(__props, __s, __extra) {
29
+ const dark = __extra[0];
30
+ const props = __extra[1];
31
+ let _b = __s.slots[0];
32
+ if (_b === void 0) {
33
+ let _m0, _m1, _m2, _m3, _m4, _m5, _m6;
34
+ const _root = clone(_t$1);
35
+ _m0 = cx("vx-overlay", dark && "dark", props.className);
36
+ _m1 = {
37
+ ...props.style,
38
+ position: "fixed",
39
+ inset: 0
40
+ };
41
+ _m2 = snapshotSpread(props.web);
42
+ _m3 = _root;
43
+ _m4 = bindSignalHostPropSources(__s, void 0, _root, [
44
+ [
45
+ false,
46
+ "className",
47
+ _m0
48
+ ],
49
+ [
50
+ false,
51
+ "style",
52
+ _m1
53
+ ],
54
+ [true, _m2]
55
+ ], "b:843a5624", true);
56
+ const _el0 = sibling(child(_root), 1);
57
+ _m5 = _el0;
58
+ setEventHandler(_el0, "$$click", (event) => event.stopPropagation());
59
+ markDangerouslySetInnerHTMLChildren(_root);
60
+ _m6 = child(_root);
61
+ _b = bag9(__s, _root, _m0, _m1, _m2, _m3, _m4, _m5, _m6, null, void 0);
62
+ __s.refFields = _rm$5;
63
+ } else {
64
+ {
65
+ const _v = cx("vx-overlay", dark && "dark", props.className);
66
+ if (_b.a !== _v) _b.a = _v;
67
+ }
68
+ {
69
+ const _v = {
70
+ ...props.style,
71
+ position: "fixed",
72
+ inset: 0
73
+ };
74
+ if (_b.b !== _v) _b.b = _v;
75
+ }
76
+ _b.c = snapshotSpread(props.web);
77
+ _b.e = bindSignalHostPropSources(__s, _b.e, _b.d, [
78
+ [
79
+ false,
80
+ "className",
81
+ _b.a
82
+ ],
83
+ [
84
+ false,
85
+ "style",
86
+ _b.b
87
+ ],
88
+ [true, _b.c]
89
+ ], "b:843a5624", true);
90
+ setEventHandler(_b.f, "$$click", (event) => event.stopPropagation());
91
+ }
92
+ {
93
+ const __ifCondition = props.shadeCover;
94
+ ifBlock(__s, 1, _b.d, __ifCondition, __then$2, null, _b.g, __ifCondition ? [props] : void 0);
95
+ }
96
+ _b.j = bindSignalChild(__s, _b.j, 2, _b.f, props.children, "b:f597242e", null, void 0, void 0, void 0, true);
97
+ }
98
+ function __then$0(__props, __s, __extra) {
99
+ const __block = __s.block;
100
+ const dark = __extra[0];
101
+ const props = __extra[1];
102
+ let _b = __s.slots[0];
103
+ if (_b === void 0) {
104
+ let _m0, _m1;
105
+ const _root = clone(_t$2);
106
+ _m0 = __block.parentNode;
107
+ _m1 = child(_root);
108
+ drainFrag(_root, __block.parentNode, __block.endMarker);
109
+ _b = bag2(__s, null, _m0, _m1);
110
+ }
111
+ portal(__s, 1, document.body, __portal$1, void 0, _b.a, [dark, props], void 0, _b.b);
112
+ }
113
+ var Overlay = function Overlay(props, __s, __extra) {
114
+ const __block = __s.block;
115
+ const dark = withSlot(_h$0, useThemeScheme) === "dark";
116
+ if (__s.block.pending && !__s.block.crossRenderUpdate) return;
117
+ {
118
+ const __ifCondition$ = props.open;
119
+ ifBlock(__s, 0, __block.parentNode, __ifCondition$, __then$0, null, __block.endMarker, __ifCondition$ ? [dark, props] : void 0);
120
+ }
121
+ };
122
+ //#endregion
123
+ export { Overlay };
@@ -0,0 +1,44 @@
1
+ //#region src/popover-position.ts
2
+ var opposite = {
3
+ top: "bottom",
4
+ bottom: "top",
5
+ left: "right",
6
+ right: "left"
7
+ };
8
+ /** Place beside the anchor, flip once when the requested side overflows, then clamp. */
9
+ function positionPopover(anchor, panel, viewport, requested = "bottom", gap = 8) {
10
+ const at = (placement) => {
11
+ switch (placement) {
12
+ case "top": return {
13
+ left: anchor.left,
14
+ top: anchor.top - panel.height - gap
15
+ };
16
+ case "bottom": return {
17
+ left: anchor.left,
18
+ top: anchor.top + anchor.height + gap
19
+ };
20
+ case "left": return {
21
+ left: anchor.left - panel.width - gap,
22
+ top: anchor.top
23
+ };
24
+ case "right": return {
25
+ left: anchor.left + anchor.width + gap,
26
+ top: anchor.top
27
+ };
28
+ }
29
+ throw new Error(`Unknown popover placement: ${placement}`);
30
+ };
31
+ const fits = (position) => position.left >= viewport.left && position.top >= viewport.top && position.left + panel.width <= viewport.left + viewport.width && position.top + panel.height <= viewport.top + viewport.height;
32
+ const preferred = at(requested);
33
+ const placement = fits(preferred) ? requested : opposite[requested];
34
+ const raw = placement === requested ? preferred : at(placement);
35
+ const maxLeft = Math.max(viewport.left, viewport.left + viewport.width - panel.width);
36
+ const maxTop = Math.max(viewport.top, viewport.top + viewport.height - panel.height);
37
+ return {
38
+ left: Math.min(maxLeft, Math.max(viewport.left, raw.left)),
39
+ top: Math.min(maxTop, Math.max(viewport.top, raw.top)),
40
+ placement
41
+ };
42
+ }
43
+ //#endregion
44
+ export { positionPopover };
@@ -0,0 +1,159 @@
1
+ import { cx } from "./ui28.js";
2
+ import { useThemeScheme } from "./ui29.js";
3
+ import { positionPopover } from "./ui32.js";
4
+ import { bag4, child, clone, componentSlotVoid, createElement, createPortal, createScopedElement, createScopedValue, drainFrag, hookSlots, ifBlock, positionalChildren, template, useEffect, useRef, useState, withSlot } from "octane";
5
+ import { compilerMemoRegion, hookMemoCreate, hookMemoPublishInvariant, textHoleUpdate } from "octane/internal/client";
6
+ //#region src/Popover.web.tsrx
7
+ var _t$0 = /* @__PURE__ */ template("<!>", 0, 1);
8
+ var _hs$ = /* @__PURE__ */ hookSlots(6);
9
+ var _h$0 = /* @__PURE__ */ Symbol(_hs$);
10
+ function __then$0(__props, __s, __extra) {
11
+ const __block = __s.block;
12
+ const dark = __extra[0];
13
+ const dismiss = __extra[1];
14
+ const panelRef = __extra[2];
15
+ const position = __extra[3];
16
+ const props = __extra[4];
17
+ const stopPointer = __extra[5];
18
+ let _b = __s.slots[0];
19
+ if (_b === void 0) {
20
+ let _m0, _m1;
21
+ const _root = clone(_t$0);
22
+ _m0 = __block.parentNode;
23
+ _m1 = child(_root);
24
+ drainFrag(_root, __block.parentNode, __block.endMarker);
25
+ _b = bag4(__s, null, _m0, _m1, null, void 0);
26
+ }
27
+ {
28
+ const _v = /* @__PURE__ */ createPortal(createScopedValue(() => createScopedElement("div", {
29
+ className: cx("vx-popover-layer", dark && "dark"),
30
+ style: {
31
+ position: "fixed",
32
+ inset: 0,
33
+ zIndex: 1e3,
34
+ pointerEvents: "none"
35
+ }
36
+ }, () => positionalChildren([(props.dismissOnOutsideTap ?? true) && createScopedValue(() => createElement("div", {
37
+ className: "vx-popover-backdrop",
38
+ style: {
39
+ position: "fixed",
40
+ inset: 0,
41
+ zIndex: 0,
42
+ pointerEvents: "auto"
43
+ },
44
+ onPointerDown: stopPointer,
45
+ onClick: dismiss
46
+ })), createScopedValue(() => createScopedElement("div", {
47
+ ref: panelRef,
48
+ className: cx("vx-popover", props.className),
49
+ style: {
50
+ ...props.style,
51
+ position: "fixed",
52
+ top: position.top,
53
+ left: position.left,
54
+ zIndex: 1,
55
+ pointerEvents: "auto"
56
+ },
57
+ ...props.web
58
+ }, () => props.children))]))), document.body);
59
+ _b.c = textHoleUpdate(__s, 1, _b.a, _v, _b.c, _b.d, _b.b, true, true);
60
+ _b.d = _v;
61
+ }
62
+ }
63
+ function __then$3(__props, __s, __extra) {
64
+ const __block = __s.block;
65
+ const anchorElement = __extra[0];
66
+ const props = __extra[1];
67
+ componentSlotVoid(__s, 0, __block.parentNode, PopoverLayer, {
68
+ ...props,
69
+ "anchorElement": anchorElement
70
+ }, __block.endMarker, void 0, void 0, void 0, void 0, "c:541a23d1");
71
+ }
72
+ var PopoverLayer = function PopoverLayer(props, __s, __extra) {
73
+ const __block = __s.block;
74
+ const __memoRegion = compilerMemoRegion(__s, _hs$ + 0);
75
+ let __hk = __memoRegion.hooks;
76
+ if (__hk === void 0) __memoRegion.hooks = __hk = hookMemoCreate(1);
77
+ const dark = withSlot(_h$0, useThemeScheme) === "dark";
78
+ const panelRef = useRef(null, _hs$ + 1);
79
+ const [position, setPosition] = useState(null, _hs$ + 2);
80
+ const update = () => {
81
+ const anchor = props.anchorElement;
82
+ if (!anchor?.getBoundingClientRect) return;
83
+ const anchorRect = anchor.getBoundingClientRect();
84
+ const panelRect = panelRef.current?.getBoundingClientRect?.();
85
+ const placed = positionPopover({
86
+ left: anchorRect.left,
87
+ top: anchorRect.top,
88
+ width: anchorRect.width,
89
+ height: anchorRect.height
90
+ }, {
91
+ width: panelRect?.width ?? 0,
92
+ height: panelRect?.height ?? 0
93
+ }, {
94
+ left: 0,
95
+ top: 0,
96
+ width: window.innerWidth,
97
+ height: window.innerHeight
98
+ }, props.placement ?? "bottom");
99
+ setPosition((current) => current?.left === placed.left && current?.top === placed.top ? current : placed);
100
+ };
101
+ useEffect(() => {
102
+ if (!props.open || !props.anchorElement?.getBoundingClientRect) {
103
+ setPosition(null);
104
+ return;
105
+ }
106
+ update();
107
+ window.addEventListener("resize", update);
108
+ window.addEventListener("scroll", update, true);
109
+ const observer = typeof ResizeObserver === "undefined" || !panelRef.current ? null : new ResizeObserver(update);
110
+ if (observer && panelRef.current) observer.observe(panelRef.current);
111
+ return () => {
112
+ window.removeEventListener("resize", update);
113
+ window.removeEventListener("scroll", update, true);
114
+ observer?.disconnect();
115
+ };
116
+ }, [
117
+ props.open,
118
+ props.anchorElement,
119
+ props.placement,
120
+ props.children,
121
+ position === null
122
+ ], _hs$ + 3);
123
+ const stopPointer = __hk[0] ?? hookMemoPublishInvariant(__hk, 0, (event) => event.stopPropagation());
124
+ const dismiss = (event) => {
125
+ event.preventDefault();
126
+ event.stopPropagation();
127
+ props.onDismiss?.();
128
+ };
129
+ if (__s.block.pending && !__s.block.crossRenderUpdate) return;
130
+ {
131
+ const __ifCondition = props.open && position;
132
+ ifBlock(__s, 0, __block.parentNode, __ifCondition, __then$0, null, __block.endMarker, __ifCondition ? [
133
+ dark,
134
+ dismiss,
135
+ panelRef,
136
+ position,
137
+ props,
138
+ stopPointer
139
+ ] : void 0);
140
+ }
141
+ };
142
+ var Popover = function Popover(props, __s, __extra) {
143
+ const __block = __s.block;
144
+ const [anchorElement, setAnchorElement] = useState(null, _hs$ + 4);
145
+ useEffect(() => {
146
+ const next = props.anchor?.current ?? null;
147
+ if (next !== anchorElement) setAnchorElement(next);
148
+ }, [
149
+ props.anchor,
150
+ props.open,
151
+ anchorElement
152
+ ], _hs$ + 5);
153
+ {
154
+ const __ifCondition$ = props.open && anchorElement;
155
+ ifBlock(__s, 0, __block.parentNode, __ifCondition$, __then$3, null, __block.endMarker, __ifCondition$ ? [anchorElement, props] : void 0);
156
+ }
157
+ };
158
+ //#endregion
159
+ export { Popover };
@@ -0,0 +1,70 @@
1
+ import { cx } from "./ui28.js";
2
+ import { applyThemeClasses } from "./ui29.js";
3
+ import { __s, bag1, bag3, clone, componentSlot, createRoot, ifBlock, template } from "octane";
4
+ import { childTextHoleUpdate } from "octane/internal/client";
5
+ //#region src/toast.web.tsrx
6
+ var _t$0 = /* @__PURE__ */ template("<div class=\"vx-toast\"></div>");
7
+ function __then$0(__props, __s, __extra) {
8
+ const props = __extra[0];
9
+ let _b = __s.slots[0];
10
+ if (_b === void 0) {
11
+ let _m0;
12
+ const _root = clone(_t$0);
13
+ _m0 = _root;
14
+ _b = bag3(__s, _root, _m0, null, void 0);
15
+ }
16
+ {
17
+ const _v = props.content;
18
+ _b.b = childTextHoleUpdate(__s, 1, _b.a, _v, _b.b, _b.c);
19
+ _b.c = _v;
20
+ }
21
+ }
22
+ function __else$2(__props, __s, __extra) {
23
+ const Component = __extra[0].content;
24
+ let _b = __s.slots[0];
25
+ if (_b === void 0) {
26
+ let _m0;
27
+ const _root = clone(_t$0);
28
+ _m0 = _root;
29
+ _b = bag1(__s, _root, _m0);
30
+ }
31
+ componentSlot(__s, 1, _b.a, Component, {}, void 0, void 0, void 0, void 0, void 0, "c:1641d101");
32
+ }
33
+ var queue = [];
34
+ var active = false;
35
+ var ToastBody = /* @__PURE__ */ __s(function ToastBody(props, __s, __extra) {
36
+ const __block = __s.block;
37
+ ifBlock(__s, 0, __block.parentNode, typeof props.content === "string", __then$0, __else$2, __block.endMarker, [props]);
38
+ });
39
+ function applyWebProps(host, props) {
40
+ if (!props) return;
41
+ for (const [key, value] of Object.entries(props)) if (key.includes("-")) host.setAttribute(key, String(value));
42
+ else host[key] = value;
43
+ }
44
+ function showNext() {
45
+ if (active || queue.length === 0) return;
46
+ active = true;
47
+ const entry = queue.shift();
48
+ const host = document.createElement("div");
49
+ const unbindTheme = applyThemeClasses(host, cx("vx-toast-host", entry.options.position === "top" ? "vx-toast-top" : "vx-toast-bottom"));
50
+ applyWebProps(host, entry.options.web);
51
+ document.body.appendChild(host);
52
+ const root = createRoot(host);
53
+ root.render(ToastBody, { content: entry.content });
54
+ setTimeout(() => {
55
+ unbindTheme();
56
+ root.unmount();
57
+ host.remove();
58
+ active = false;
59
+ showNext();
60
+ }, Math.max(0, entry.options.duration ?? 3e3));
61
+ }
62
+ function showToast(content, options = {}) {
63
+ queue.push({
64
+ content,
65
+ options
66
+ });
67
+ showNext();
68
+ }
69
+ //#endregion
70
+ export { showToast };
@@ -0,0 +1,57 @@
1
+ import { hookSlots, useRef } from "octane";
2
+ //#region src/anim.web.tsrx
3
+ var _h$0 = /* @__PURE__ */ Symbol(/* @__PURE__ */ hookSlots(1));
4
+ function createAnimated(initial, prop) {
5
+ let el = null;
6
+ let current = initial;
7
+ let raf = 0;
8
+ const apply = (v) => {
9
+ current = v;
10
+ if (el) el.style.transform = `translateX(${v}px)`;
11
+ };
12
+ const run = (step) => {
13
+ cancelAnimationFrame(raf);
14
+ const start = Date.now();
15
+ const tick = () => {
16
+ const v = step(Date.now() - start);
17
+ if (v === null) return;
18
+ apply(v);
19
+ raf = requestAnimationFrame(tick);
20
+ };
21
+ raf = requestAnimationFrame(tick);
22
+ };
23
+ return {
24
+ get value() {
25
+ return current;
26
+ },
27
+ bind(e) {
28
+ el = e;
29
+ if (el) el.style.transform = `translateX(${current}px)`;
30
+ },
31
+ to(target, opts) {
32
+ const dur = opts?.duration ?? 300;
33
+ const from = current;
34
+ run((t) => t >= dur ? (apply(target), null) : from + (target - from) * (t / dur));
35
+ },
36
+ spring(target, opts) {
37
+ const damping = opts?.damping ?? 14, stiffness = opts?.stiffness ?? 120;
38
+ let v = 0, x = current;
39
+ run(() => {
40
+ const dt = 1 / 60;
41
+ v += (-stiffness * (x - target) - damping * v) * dt;
42
+ x += v * dt;
43
+ return Math.abs(v) < .5 && Math.abs(x - target) < .5 ? (apply(target), null) : x;
44
+ });
45
+ },
46
+ stop() {
47
+ cancelAnimationFrame(raf);
48
+ }
49
+ };
50
+ }
51
+ function useAnimation(initial = 0, prop = "translateX") {
52
+ const c = useRef(null, _h$0);
53
+ if (!c.current) c.current = createAnimated(initial, prop);
54
+ return c.current;
55
+ }
56
+ //#endregion
57
+ export { useAnimation };