@floegence/floe-webapp-core 0.79.1 → 0.80.1

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/dist/chat.css CHANGED
@@ -1847,6 +1847,13 @@ pre.chat-md-code-block *::selection,
1847
1847
  @layer components {
1848
1848
  .chat-media { position: relative; display: flex; flex-direction: column; width: fit-content; max-width: min(100%, 42rem); min-width: 0; margin: .8rem 0 1rem; color: var(--foreground); text-align: left; }
1849
1849
  .chat-media[data-media-kind="html"] { width: 100%; }
1850
+ .chat-media[data-media-kind="image"] { width: min(100%, 36rem); }
1851
+ .chat-media-viewport { display: block; width: 100%; min-width: 0; overflow: hidden; }
1852
+ .chat-media[data-media-kind="image"] .chat-media-viewport,
1853
+ .chat-media[data-media-kind="video"] .chat-media-viewport { aspect-ratio: 16 / 9; }
1854
+ .chat-media[data-media-kind="audio"] .chat-media-viewport { height: 54px; }
1855
+ .chat-media[data-media-kind="html"] .chat-media-viewport { height: 22rem; }
1856
+ .chat-media-expanded[data-media-kind="html"] .chat-media-viewport { height: min(70vh, 48rem); }
1850
1857
  .chat-media[data-media-kind="video"] { width: min(100%, 36rem); }
1851
1858
  .chat-media[data-media-kind="audio"] { width: min(100%, 28rem); }
1852
1859
  .chat-media-header { display: flex; align-items: center; min-width: 0; padding: .4rem .15rem 0; }
@@ -1861,12 +1868,12 @@ pre.chat-md-code-block *::selection,
1861
1868
  .chat-media-action svg, .chat-media-retry svg { width: .95rem; height: .95rem; }
1862
1869
  .chat-media-action:focus-visible { outline: 2px solid white; outline-offset: -2px; }
1863
1870
  .chat-media-image-button:focus-visible, .chat-media-retry:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
1864
- .chat-media-placeholder { display: flex; align-items: center; justify-content: center; gap: .75rem; width: min(22rem, 100%); min-height: 7rem; padding: 1rem; border-radius: .75rem; background: var(--muted); font-size: .75rem; color: var(--muted-foreground); }
1871
+ .chat-media-placeholder { display: flex; align-items: center; justify-content: center; gap: .75rem; width: 100%; height: 100%; overflow: auto; padding: .5rem; border-radius: .75rem; background: var(--muted); font-size: .75rem; color: var(--muted-foreground); }
1865
1872
  .chat-media-retry { display: inline-flex; align-items: center; gap: .4rem; padding: .4rem .65rem; border-radius: .4rem; cursor: pointer; color: var(--foreground); }
1866
1873
  .chat-media-retry:hover { background: var(--background); }
1867
- .chat-media-image-button { display: block; max-width: 100%; padding: 0; border: 0; border-radius: .75rem; overflow: hidden; cursor: zoom-in; background: transparent; }
1868
- .chat-media-image { display: block; width: auto; height: auto; max-width: 100%; max-height: 28rem; object-fit: contain; margin: 0; border: 0; border-radius: .75rem; }
1869
- .chat-media-video { display: block; width: 100%; max-width: 100%; max-height: 28rem; border: 0; border-radius: .75rem; background: #111; }
1874
+ .chat-media-image-button { display: block; width: 100%; height: 100%; padding: 0; border: 0; border-radius: .75rem; overflow: hidden; cursor: zoom-in; background: transparent; }
1875
+ .chat-media-image { display: block; width: 100%; height: 100%; object-fit: contain; margin: 0; border: 0; border-radius: .75rem; }
1876
+ .chat-media-video { display: block; width: 100%; height: 100%; object-fit: contain; border: 0; border-radius: .75rem; background: #111; }
1870
1877
  .chat-media-audio { display: block; width: min(28rem, 100%); }
1871
1878
  .chat-media-html { display: block; width: 100%; height: 22rem; border: 0; border-radius: .75rem; background: white; color-scheme: light; }
1872
1879
  .chat-media-expanded { max-width: 100%; }
@@ -1875,5 +1882,5 @@ pre.chat-md-code-block *::selection,
1875
1882
  .chat-media-full-image { display: block; width: 100%; height: 100%; min-height: 0; object-fit: contain; }
1876
1883
  @media (hover: none) { .chat-media-actions { opacity: 1; transform: none; } }
1877
1884
  @media (prefers-reduced-motion: reduce) { .chat-media-actions { transition: none; } }
1878
- @media (max-width: 480px) { .chat-media-html { height: 18rem; } }
1885
+ @media (max-width: 480px) { .chat-media[data-media-kind="html"] .chat-media-viewport, .chat-media-html { height: 18rem; } .chat-media-expanded[data-media-kind="html"] .chat-media-viewport { height: min(70vh, 48rem); } }
1879
1886
  }
@@ -1,22 +1,22 @@
1
- import { use as A, insert as s, createComponent as o, effect as u, setAttribute as n, memo as _, className as J, template as v, delegateEvents as K } from "solid-js/web";
2
- import { createSignal as x, onMount as P, onCleanup as F, createMemo as Q, createEffect as X, Switch as B, Match as w, Show as E } from "solid-js";
3
- import { FloatingWindow as Y } from "../../ui/FloatingWindow.js";
4
- import { Refresh as Z, FolderOpen as p, Eye as ee, Maximize as re, ExternalLink as te } from "../../icons/index.js";
5
- import { cn as ae } from "../../../utils/cn.js";
6
- import { sandboxedMarkdownHtml as D, safeMarkdownMediaURL as le } from "../markdown/media.js";
7
- var ne = /* @__PURE__ */ v("<span class=chat-media-placeholder role=status>"), ie = /* @__PURE__ */ v("<span class=chat-media-placeholder role=status><span></span><button type=button class=chat-media-retry>"), oe = /* @__PURE__ */ v("<button type=button class=chat-media-image-button><img class=chat-media-image loading=lazy decoding=async referrerpolicy=no-referrer>", !0, !1, !1), se = /* @__PURE__ */ v("<video class=chat-media-video controls playsinline preload=metadata>"), ce = /* @__PURE__ */ v("<audio class=chat-media-audio controls preload=metadata>"), de = /* @__PURE__ */ v("<iframe class=chat-media-html sandbox=allow-scripts referrerpolicy=no-referrer>"), H = /* @__PURE__ */ v("<button type=button class=chat-media-action>"), ue = /* @__PURE__ */ v("<div class=chat-media-preview-content><img referrerpolicy=no-referrer class=chat-media-full-image>"), ve = /* @__PURE__ */ v("<span><span class=chat-media-header><span class=chat-media-heading><span class=chat-media-kind></span><span class=chat-media-title></span></span><span class=chat-media-actions>"), he = /* @__PURE__ */ v('<a class=chat-media-action target=_blank rel="noopener noreferrer">');
8
- async function me(a) {
9
- const f = le(a.src ?? "");
1
+ import { use as F, insert as s, createComponent as o, effect as u, setAttribute as n, memo as _, className as K, template as v, delegateEvents as P } from "solid-js/web";
2
+ import { createSignal as x, onMount as Q, onCleanup as B, createMemo as X, createEffect as Y, Switch as D, Match as w, Show as S } from "solid-js";
3
+ import { FloatingWindow as Z } from "../../ui/FloatingWindow.js";
4
+ import { Refresh as p, FolderOpen as ee, Eye as re, Maximize as te, ExternalLink as ae } from "../../icons/index.js";
5
+ import { cn as le } from "../../../utils/cn.js";
6
+ import { sandboxedMarkdownHtml as N, safeMarkdownMediaURL as ne } from "../markdown/media.js";
7
+ var ie = /* @__PURE__ */ v("<span class=chat-media-placeholder role=status>"), oe = /* @__PURE__ */ v("<span class=chat-media-placeholder role=status><span></span><button type=button class=chat-media-retry>"), se = /* @__PURE__ */ v("<button type=button class=chat-media-image-button><img class=chat-media-image loading=lazy decoding=async referrerpolicy=no-referrer>", !0, !1, !1), ce = /* @__PURE__ */ v("<video class=chat-media-video controls playsinline preload=metadata>"), de = /* @__PURE__ */ v("<audio class=chat-media-audio controls preload=metadata>"), ue = /* @__PURE__ */ v("<iframe class=chat-media-html sandbox=allow-scripts referrerpolicy=no-referrer>"), H = /* @__PURE__ */ v("<button type=button class=chat-media-action>"), ve = /* @__PURE__ */ v("<div class=chat-media-preview-content><img referrerpolicy=no-referrer class=chat-media-full-image>"), he = /* @__PURE__ */ v("<span><span class=chat-media-viewport></span><span class=chat-media-header><span class=chat-media-heading><span class=chat-media-kind></span><span class=chat-media-title></span></span><span class=chat-media-actions>"), me = /* @__PURE__ */ v('<a class=chat-media-action target=_blank rel="noopener noreferrer">');
8
+ async function ge(a) {
9
+ const f = ne(a.src ?? "");
10
10
  if (!f || a.kind === "html") throw new Error("A host resolver is required");
11
11
  return {
12
12
  src: f,
13
13
  openURL: f
14
14
  };
15
15
  }
16
- const $e = (a) => {
16
+ const xe = (a) => {
17
17
  let f, q;
18
- const [N, z] = x(!1);
19
- P(() => {
18
+ const [V, z] = x(!1);
19
+ Q(() => {
20
20
  if (typeof IntersectionObserver > "u") {
21
21
  z(!0);
22
22
  return;
@@ -26,22 +26,22 @@ const $e = (a) => {
26
26
  }, {
27
27
  rootMargin: "400px"
28
28
  });
29
- i.observe(f), F(() => i.disconnect());
29
+ i.observe(f), B(() => i.disconnect());
30
30
  });
31
- const [h, I] = x(), [V, R] = x(), [k, y] = x("loading"), [W, j] = x(0), [$, S] = x(!1), m = () => a.source.title || a.labels[a.source.kind], G = Q(() => a.source), T = () => h()?.preview?.label || a.labels.previewImage || a.labels.expand, O = (i) => {
31
+ const [h, I] = x(), [W, R] = x(), [k, y] = x("loading"), [j, G] = x(0), [$, E] = x(!1), m = () => a.source.title || a.labels[a.source.kind], J = X(() => a.source), T = () => h()?.preview?.label || a.labels.previewImage || a.labels.expand, O = (i) => {
32
32
  q = i.currentTarget;
33
33
  const g = h()?.preview;
34
- g ? g.onSelect() : S(!0);
34
+ g ? g.onSelect() : E(!0);
35
35
  };
36
- return X(() => {
37
- if (!N()) return;
38
- const i = G(), g = a.resolve ?? me;
39
- W();
36
+ return Y(() => {
37
+ if (!V()) return;
38
+ const i = J(), g = a.resolve ?? ge;
39
+ j();
40
40
  const d = new AbortController();
41
- F(() => d.abort()), I(void 0), R(void 0), y("loading"), S(!1), (async () => {
41
+ B(() => d.abort()), I(void 0), R(void 0), y("loading"), E(!1), (async () => {
42
42
  if (i.kind === "html" && i.html !== void 0) {
43
43
  if (i.html.length > 1e6) throw new Error("HTML preview is too large");
44
- d.signal.aborted || R(D(i.html));
44
+ d.signal.aborted || R(N(i.html));
45
45
  } else {
46
46
  const b = await g(i, d.signal);
47
47
  if (d.signal.aborted) return;
@@ -50,7 +50,7 @@ const $e = (a) => {
50
50
  const M = await b.loadHTML(d.signal);
51
51
  if (d.signal.aborted) return;
52
52
  if (M.length > 1e6) throw new Error("HTML preview is too large");
53
- R(D(M));
53
+ R(N(M));
54
54
  } else if (!b.src) throw new Error("Media URL is required");
55
55
  I(b);
56
56
  }
@@ -59,15 +59,15 @@ const $e = (a) => {
59
59
  d.signal.aborted || y("error");
60
60
  });
61
61
  }), (() => {
62
- var i = ve(), g = i.firstChild, d = g.firstChild, b = d.firstChild, M = b.nextSibling, C = d.nextSibling, U = f;
63
- return typeof U == "function" ? A(U, i) : f = i, s(i, o(B, {
62
+ var i = he(), g = i.firstChild, d = g.nextSibling, b = d.firstChild, M = b.firstChild, U = M.nextSibling, C = b.nextSibling, A = f;
63
+ return typeof A == "function" ? F(A, i) : f = i, s(g, o(D, {
64
64
  get children() {
65
65
  return [o(w, {
66
66
  get when() {
67
67
  return k() === "loading";
68
68
  },
69
69
  get children() {
70
- var e = ne();
70
+ var e = ie();
71
71
  return s(e, () => a.labels.loading), e;
72
72
  }
73
73
  }), o(w, {
@@ -75,22 +75,22 @@ const $e = (a) => {
75
75
  return k() === "error";
76
76
  },
77
77
  get children() {
78
- var e = ie(), r = e.firstChild, t = r.nextSibling;
79
- return s(r, () => a.labels.unavailable), t.$$click = () => j((l) => l + 1), s(t, o(Z, {}), null), s(t, () => a.labels.retry, null), e;
78
+ var e = oe(), r = e.firstChild, t = r.nextSibling;
79
+ return s(r, () => a.labels.unavailable), t.$$click = () => G((l) => l + 1), s(t, o(p, {}), null), s(t, () => a.labels.retry, null), e;
80
80
  }
81
81
  }), o(w, {
82
82
  get when() {
83
83
  return k() === "ready";
84
84
  },
85
85
  get children() {
86
- return o(B, {
86
+ return o(D, {
87
87
  get children() {
88
88
  return [o(w, {
89
89
  get when() {
90
90
  return a.source.kind === "image";
91
91
  },
92
92
  get children() {
93
- var e = oe(), r = e.firstChild;
93
+ var e = se(), r = e.firstChild;
94
94
  return e.$$click = O, r.addEventListener("error", () => y("error")), u((t) => {
95
95
  var l = `${T()}: ${m()}`, c = h()?.src, L = m();
96
96
  return l !== t.e && n(e, "aria-label", t.e = l), c !== t.t && n(r, "src", t.t = c), L !== t.a && n(r, "alt", t.a = L), t;
@@ -105,7 +105,7 @@ const $e = (a) => {
105
105
  return a.source.kind === "video";
106
106
  },
107
107
  get children() {
108
- var e = se();
108
+ var e = ce();
109
109
  return e.addEventListener("error", () => y("error")), u((r) => {
110
110
  var t = h()?.src, l = m();
111
111
  return t !== r.e && n(e, "src", r.e = t), l !== r.t && n(e, "aria-label", r.t = l), r;
@@ -119,7 +119,7 @@ const $e = (a) => {
119
119
  return a.source.kind === "audio";
120
120
  },
121
121
  get children() {
122
- var e = ce();
122
+ var e = de();
123
123
  return e.addEventListener("error", () => y("error")), u((r) => {
124
124
  var t = h()?.src, l = m();
125
125
  return t !== r.e && n(e, "src", r.e = t), l !== r.t && n(e, "aria-label", r.t = l), r;
@@ -133,9 +133,9 @@ const $e = (a) => {
133
133
  return a.source.kind === "html";
134
134
  },
135
135
  get children() {
136
- var e = de();
136
+ var e = ue();
137
137
  return u((r) => {
138
- var t = m(), l = V();
138
+ var t = m(), l = W();
139
139
  return t !== r.e && n(e, "title", r.e = t), l !== r.t && n(e, "srcdoc", r.t = l), r;
140
140
  }, {
141
141
  e: void 0,
@@ -148,13 +148,13 @@ const $e = (a) => {
148
148
  }
149
149
  })];
150
150
  }
151
- }), g), s(b, () => a.labels[a.source.kind]), s(M, m), s(C, o(E, {
151
+ })), s(M, () => a.labels[a.source.kind]), s(U, m), s(C, o(S, {
152
152
  get when() {
153
153
  return _(() => k() === "ready")() && h()?.reveal;
154
154
  },
155
155
  children: (e) => (() => {
156
156
  var r = H();
157
- return r.$$click = () => e().onSelect(), s(r, o(p, {})), u((t) => {
157
+ return r.$$click = () => e().onSelect(), s(r, o(ee, {})), u((t) => {
158
158
  var l = e().label, c = e().label;
159
159
  return l !== t.e && n(r, "aria-label", t.e = l), c !== t.t && n(r, "title", t.t = c), t;
160
160
  }, {
@@ -162,13 +162,13 @@ const $e = (a) => {
162
162
  t: void 0
163
163
  }), r;
164
164
  })()
165
- }), null), s(C, o(E, {
165
+ }), null), s(C, o(S, {
166
166
  get when() {
167
167
  return _(() => k() === "ready")() && a.source.kind === "image";
168
168
  },
169
169
  get children() {
170
170
  var e = H();
171
- return e.$$click = O, s(e, o(ee, {})), u((r) => {
171
+ return e.$$click = O, s(e, o(re, {})), u((r) => {
172
172
  var t = T(), l = T();
173
173
  return t !== r.e && n(e, "aria-label", r.e = t), l !== r.t && n(e, "title", r.t = l), r;
174
174
  }, {
@@ -176,13 +176,13 @@ const $e = (a) => {
176
176
  t: void 0
177
177
  }), e;
178
178
  }
179
- }), null), s(C, o(E, {
179
+ }), null), s(C, o(S, {
180
180
  get when() {
181
181
  return _(() => k() === "ready")() && a.source.kind === "html";
182
182
  },
183
183
  get children() {
184
184
  var e = H();
185
- return e.$$click = () => S(!$()), s(e, o(re, {})), u((r) => {
185
+ return e.$$click = () => E(!$()), s(e, o(te, {})), u((r) => {
186
186
  var t = $() ? a.labels.collapse : a.labels.expand, l = $() ? a.labels.collapse : a.labels.expand, c = $();
187
187
  return t !== r.e && n(e, "aria-label", r.e = t), l !== r.t && n(e, "title", r.t = l), c !== r.a && n(e, "aria-expanded", r.a = c), r;
188
188
  }, {
@@ -191,13 +191,13 @@ const $e = (a) => {
191
191
  a: void 0
192
192
  }), e;
193
193
  }
194
- }), null), s(C, o(E, {
194
+ }), null), s(C, o(S, {
195
195
  get when() {
196
196
  return _(() => a.source.kind !== "image" && !h()?.reveal)() && h()?.openURL;
197
197
  },
198
198
  children: (e) => (() => {
199
- var r = he();
200
- return s(r, o(te, {})), u((t) => {
199
+ var r = me();
200
+ return s(r, o(ae, {})), u((t) => {
201
201
  var l = e(), c = a.labels.open, L = a.labels.open;
202
202
  return l !== t.e && n(r, "href", t.e = l), c !== t.t && n(r, "aria-label", t.t = c), L !== t.a && n(r, "title", t.a = L), t;
203
203
  }, {
@@ -206,17 +206,17 @@ const $e = (a) => {
206
206
  a: void 0
207
207
  }), r;
208
208
  })()
209
- }), null), s(i, o(E, {
209
+ }), null), s(i, o(S, {
210
210
  get when() {
211
211
  return a.source.kind === "image";
212
212
  },
213
213
  get children() {
214
- return o(Y, {
214
+ return o(Z, {
215
215
  get open() {
216
216
  return $();
217
217
  },
218
218
  onOpenChange: (e) => {
219
- S(e), e || q?.focus({
219
+ E(e), e || q?.focus({
220
220
  preventScroll: !0
221
221
  });
222
222
  },
@@ -241,8 +241,8 @@ const $e = (a) => {
241
241
  compactBelow: 640,
242
242
  class: "chat-media-preview-window",
243
243
  get children() {
244
- var e = ue(), r = e.firstChild;
245
- return A((t) => queueMicrotask(() => t.closest('[role="dialog"]')?.focus({
244
+ var e = ve(), r = e.firstChild;
245
+ return F((t) => queueMicrotask(() => t.closest('[role="dialog"]')?.focus({
246
246
  preventScroll: !0
247
247
  })), e), u((t) => {
248
248
  var l = h()?.src, c = m();
@@ -255,8 +255,8 @@ const $e = (a) => {
255
255
  });
256
256
  }
257
257
  }), null), u((e) => {
258
- var r = ae("chat-media", $() && a.source.kind === "html" && "chat-media-expanded", a.class), t = a.source.kind, l = m();
259
- return r !== e.e && J(i, e.e = r), t !== e.t && n(i, "data-media-kind", e.t = t), l !== e.a && n(M, "title", e.a = l), e;
258
+ var r = le("chat-media", $() && a.source.kind === "html" && "chat-media-expanded", a.class), t = a.source.kind, l = m();
259
+ return r !== e.e && K(i, e.e = r), t !== e.t && n(i, "data-media-kind", e.t = t), l !== e.a && n(U, "title", e.a = l), e;
260
260
  }, {
261
261
  e: void 0,
262
262
  t: void 0,
@@ -264,7 +264,7 @@ const $e = (a) => {
264
264
  }), i;
265
265
  })();
266
266
  };
267
- K(["click"]);
267
+ P(["click"]);
268
268
  export {
269
- $e as MarkdownMedia
269
+ xe as MarkdownMedia
270
270
  };
@@ -1,9 +1,9 @@
1
- import { spread as d, mergeProps as c, insert as n, createComponent as t, memo as g, Dynamic as l, template as u } from "solid-js/web";
2
- import { splitProps as m, Show as b } from "solid-js";
3
- import { cn as a } from "../../utils/cn.js";
4
- import { Loader2 as p } from "../icons/index.js";
5
- var h = /* @__PURE__ */ u("<button type=button data-floe-control=button data-floe-surface-part=action>");
6
- const v = {
1
+ import { spread as u, mergeProps as g, insert as n, createComponent as t, memo as m, Dynamic as b, effect as h, className as f, template as d } from "solid-js/web";
2
+ import { splitProps as p, Show as i } from "solid-js";
3
+ import { cn as s } from "../../utils/cn.js";
4
+ import { Loader2 as v } from "../icons/index.js";
5
+ var x = /* @__PURE__ */ d("<span aria-hidden=true>"), y = /* @__PURE__ */ d("<button type=button data-floe-control=button data-floe-surface-part=action>");
6
+ const w = {
7
7
  default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 active:bg-primary/80",
8
8
  primary: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 active:bg-primary/80",
9
9
  secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80 active:bg-secondary/70",
@@ -11,57 +11,64 @@ const v = {
11
11
  ghost: "hover:bg-accent hover:text-accent-foreground active:bg-accent/80",
12
12
  "ghost-destructive": "bg-transparent text-muted-foreground hover:bg-error hover:text-error-foreground active:bg-error/80",
13
13
  destructive: "bg-error text-error-foreground shadow-sm hover:bg-error/90 active:bg-error/80"
14
- }, f = {
14
+ }, z = {
15
15
  xs: "h-6 px-2 text-[11px] rounded",
16
16
  sm: "h-7 px-2.5 text-xs rounded",
17
17
  md: "h-8 px-3 text-xs rounded-md",
18
18
  lg: "h-9 px-4 text-sm rounded-md",
19
19
  icon: "h-8 w-8 rounded-md"
20
- }, x = {
20
+ }, S = {
21
21
  xs: "w-3 h-3",
22
22
  sm: "w-3.5 h-3.5",
23
23
  md: "w-3.5 h-3.5",
24
24
  lg: "w-4 h-4",
25
25
  icon: "w-4 h-4"
26
26
  };
27
- function k(i) {
28
- const [r, s] = m(i, ["variant", "size", "loading", "icon", "class", "children", "disabled"]), o = () => x[r.size ?? "md"];
27
+ function P(a) {
28
+ const [e, c] = p(a, ["variant", "size", "loading", "icon", "class", "children", "disabled"]), l = () => S[e.size ?? "md"];
29
29
  return (() => {
30
- var e = h();
31
- return d(e, c({
30
+ var r = y();
31
+ return u(r, g({
32
32
  get "data-floe-surface"() {
33
- return r.variant === "ghost" || r.variant === "ghost-destructive" ? void 0 : "raised";
33
+ return e.variant === "ghost" || e.variant === "ghost-destructive" ? void 0 : "raised";
34
34
  },
35
35
  get class() {
36
- return a("inline-flex items-center justify-center gap-1.5 font-medium cursor-pointer", "transition-[color,background-color,border-color] duration-120", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed", v[r.variant ?? "default"], f[r.size ?? "md"], r.class);
36
+ return s("inline-flex items-center justify-center gap-1.5 font-medium cursor-pointer", "transition-[color,background-color,border-color] duration-120", "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2", "disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed", w[e.variant ?? "default"], z[e.size ?? "md"], e.class);
37
37
  },
38
38
  get disabled() {
39
- return r.disabled || r.loading;
39
+ return e.disabled || e.loading;
40
+ },
41
+ get "aria-busy"() {
42
+ return e.loading || void 0;
40
43
  }
41
- }, s), !1, !0), n(e, t(b, {
44
+ }, c), !1, !0), n(r, t(i, {
42
45
  get when() {
43
- return r.loading;
44
- },
45
- get fallback() {
46
- return g(() => !!r.icon)() && t(l, {
47
- get component() {
48
- return r.icon;
49
- },
50
- get class() {
51
- return o();
52
- }
53
- });
46
+ return e.icon || "loading" in a;
54
47
  },
55
48
  get children() {
56
- return t(p, {
57
- get class() {
58
- return a(o(), "animate-spin");
49
+ var o = x();
50
+ return n(o, t(i, {
51
+ get when() {
52
+ return e.loading;
53
+ },
54
+ get fallback() {
55
+ return m(() => !!e.icon)() && t(b, {
56
+ get component() {
57
+ return e.icon;
58
+ },
59
+ class: "h-full w-full"
60
+ });
61
+ },
62
+ get children() {
63
+ return t(v, {
64
+ class: "h-full w-full animate-spin"
65
+ });
59
66
  }
60
- });
67
+ })), h(() => f(o, s("inline-flex shrink-0 items-center justify-center", l()))), o;
61
68
  }
62
- }), null), n(e, () => r.children, null), e;
69
+ }), null), n(r, () => e.children, null), r;
63
70
  })();
64
71
  }
65
72
  export {
66
- k as Button
73
+ P as Button
67
74
  };
@@ -0,0 +1,9 @@
1
+ import { type JSX } from 'solid-js';
2
+ export interface StableTextProps {
3
+ children: string;
4
+ /** All transient labels, in the current locale. Only the current label is exposed to assistive technology. */
5
+ reserve: readonly string[];
6
+ class?: string;
7
+ }
8
+ /** Intrinsic sizing includes every state before the first interaction, including wrapped labels. */
9
+ export declare function StableText(props: StableTextProps): JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { insert as a, createComponent as m, effect as o, style as d, className as v, template as c } from "solid-js/web";
2
+ import { For as h } from "solid-js";
3
+ var u = /* @__PURE__ */ c("<span style=display:inline-grid;min-width:0;vertical-align:bottom;align-items:center><span>"), f = /* @__PURE__ */ c("<span aria-hidden=true style=visibility:hidden;pointer-events:none;user-select:none>");
4
+ function p(i) {
5
+ const s = {
6
+ "grid-area": "1 / 1",
7
+ "min-width": "0"
8
+ };
9
+ return (() => {
10
+ var r = u(), n = r.firstChild;
11
+ return a(r, m(h, {
12
+ get each() {
13
+ return i.reserve;
14
+ },
15
+ children: (e) => (() => {
16
+ var t = f();
17
+ return a(t, e), o((l) => d(t, {
18
+ ...s
19
+ }, l)), t;
20
+ })()
21
+ }), n), a(n, () => i.children), o((e) => {
22
+ var t = i.class, l = s;
23
+ return t !== e.e && v(r, e.e = t), e.t = d(n, l, e.t), e;
24
+ }, {
25
+ e: void 0,
26
+ t: void 0
27
+ }), r;
28
+ })();
29
+ }
30
+ export {
31
+ p as StableText
32
+ };
@@ -0,0 +1,8 @@
1
+ import { type JSX } from 'solid-js';
2
+ export interface StatusRegionProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, 'style'> {
3
+ /** Reserve a bounded number of text lines through idle, pending, success, and failure. */
4
+ lines?: number;
5
+ style?: JSX.CSSProperties;
6
+ }
7
+ /** A persistent, scrollable feedback slot. Long errors remain available without resizing adjacent content. */
8
+ export declare function StatusRegion(props: StatusRegionProps): JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { spread as o, mergeProps as i, insert as s, template as n } from "solid-js/web";
2
+ import { splitProps as a } from "solid-js";
3
+ var p = /* @__PURE__ */ n("<div role=status aria-live=polite>");
4
+ function f(t) {
5
+ const [e, l] = a(t, ["lines", "style", "children"]);
6
+ return (() => {
7
+ var r = p();
8
+ return o(r, i(l, {
9
+ get style() {
10
+ return {
11
+ "block-size": `${e.lines ?? 2}lh`,
12
+ "flex-shrink": "0",
13
+ "min-width": "0",
14
+ overflow: "auto",
15
+ "overflow-wrap": "anywhere",
16
+ ...e.style
17
+ };
18
+ }
19
+ }), !1, !0), s(r, () => e.children), r;
20
+ })();
21
+ }
22
+ export {
23
+ f as StatusRegion
24
+ };
@@ -1,4 +1,6 @@
1
1
  export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from './Button';
2
+ export { StableText, type StableTextProps } from './StableText';
3
+ export { StatusRegion, type StatusRegionProps } from './StatusRegion';
2
4
  export { intersectSurfaceRects, type SurfaceFloatingBoundary } from './surfaceFloatingBoundary';
3
5
  export { Tag, type TagProps, type TagVariant, type TagSize } from './Tag';
4
6
  export { Input, Textarea, NumberInput, AffixInput, type InputProps, type InputSize, type TextareaProps, type NumberInputProps, type AffixInputProps, type AffixOption, } from './Input';