@tappify/extension-sdk 2.1.0-beta.2 → 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.
Files changed (137) hide show
  1. package/README.md +18 -54
  2. package/dist/{chunk-6HETNZJY.cjs → chunk-2DBSVKAU.cjs} +1 -1
  3. package/dist/{chunk-6HETNZJY.cjs.map → chunk-2DBSVKAU.cjs.map} +1 -1
  4. package/dist/{chunk-O357OJXL.cjs → chunk-3YWVYA42.cjs} +18 -14
  5. package/dist/chunk-3YWVYA42.cjs.map +1 -0
  6. package/dist/{chunk-GAUZYBXE.cjs → chunk-5AAPD5WV.cjs} +11 -11
  7. package/dist/chunk-5AAPD5WV.cjs.map +1 -0
  8. package/dist/{chunk-SGEYDV3K.mjs → chunk-BDCX6LRQ.mjs} +3 -3
  9. package/dist/chunk-BDCX6LRQ.mjs.map +1 -0
  10. package/dist/{chunk-KZ5NGFUP.mjs → chunk-C3YNVHBP.mjs} +7 -20
  11. package/dist/chunk-C3YNVHBP.mjs.map +1 -0
  12. package/dist/{chunk-QXD7WVKK.mjs → chunk-CSTYBKZC.mjs} +1 -1
  13. package/dist/chunk-CSTYBKZC.mjs.map +1 -0
  14. package/dist/{chunk-SWG7CNTZ.mjs → chunk-CTSZ5D7S.mjs} +5 -9
  15. package/dist/chunk-CTSZ5D7S.mjs.map +1 -0
  16. package/dist/chunk-EW54H7CR.cjs +722 -0
  17. package/dist/chunk-EW54H7CR.cjs.map +1 -0
  18. package/dist/chunk-EX3NFXDK.mjs +722 -0
  19. package/dist/chunk-EX3NFXDK.mjs.map +1 -0
  20. package/dist/{chunk-A74HCO6T.cjs → chunk-G7XZSN2Q.cjs} +18 -31
  21. package/dist/chunk-G7XZSN2Q.cjs.map +1 -0
  22. package/dist/{chunk-RBIQT75L.mjs → chunk-GG3IX52W.mjs} +2 -2
  23. package/dist/{chunk-SLGOHIBL.mjs → chunk-IGK2AP6J.mjs} +17 -13
  24. package/dist/chunk-IGK2AP6J.mjs.map +1 -0
  25. package/dist/{chunk-VV7ELNRW.cjs → chunk-JMUK3K47.cjs} +3 -3
  26. package/dist/{chunk-VV7ELNRW.cjs.map → chunk-JMUK3K47.cjs.map} +1 -1
  27. package/dist/{chunk-SGCYEEXD.mjs → chunk-MNDVYPEP.mjs} +2 -9
  28. package/dist/chunk-MNDVYPEP.mjs.map +1 -0
  29. package/dist/{chunk-BPCGXXMD.cjs → chunk-NFUPPCX4.cjs} +18 -22
  30. package/dist/chunk-NFUPPCX4.cjs.map +1 -0
  31. package/dist/{chunk-PRCZMOLD.cjs → chunk-OPPYEA7F.cjs} +3 -3
  32. package/dist/{chunk-PRCZMOLD.cjs.map → chunk-OPPYEA7F.cjs.map} +1 -1
  33. package/dist/{chunk-7YKH4LZN.cjs → chunk-PYJMJF44.cjs} +2 -9
  34. package/dist/chunk-PYJMJF44.cjs.map +1 -0
  35. package/dist/{chunk-QA5AL3VZ.mjs → chunk-QHM7XNRK.mjs} +2 -2
  36. package/dist/{chunk-QA5AL3VZ.mjs.map → chunk-QHM7XNRK.mjs.map} +1 -1
  37. package/dist/codegen.cjs.map +1 -1
  38. package/dist/codegen.d.cts +7 -43
  39. package/dist/codegen.d.ts +7 -43
  40. package/dist/codegen.mjs.map +1 -1
  41. package/dist/{constants-Bh759FUI.d.cts → constants-DJ_KgZpN.d.cts} +8 -44
  42. package/dist/{constants-Bh759FUI.d.ts → constants-DJ_KgZpN.d.ts} +8 -44
  43. package/dist/{context-mr8R5CNt.d.ts → context-Dt6xh_5t.d.cts} +4 -5
  44. package/dist/{context-DI0EJCRD.d.cts → context-Ml7k_V14.d.ts} +4 -5
  45. package/dist/{errors-Cqh0wrqt.d.ts → errors-COsBh7kd.d.cts} +2 -3
  46. package/dist/{errors-Cqh0wrqt.d.cts → errors-COsBh7kd.d.ts} +2 -3
  47. package/dist/handler-CZIlZ5vu.d.ts +227 -0
  48. package/dist/handler-kU9Jf36K.d.cts +227 -0
  49. package/dist/host.cjs +4 -4
  50. package/dist/host.d.cts +4 -4
  51. package/dist/host.d.ts +4 -4
  52. package/dist/host.mjs +3 -3
  53. package/dist/index.cjs +34 -5
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.d.cts +627 -69
  56. package/dist/index.d.ts +627 -69
  57. package/dist/index.mjs +33 -4
  58. package/dist/manifest.cjs +24 -136
  59. package/dist/manifest.cjs.map +1 -1
  60. package/dist/manifest.d.cts +12 -97
  61. package/dist/manifest.d.ts +12 -97
  62. package/dist/manifest.mjs +10 -122
  63. package/dist/manifest.mjs.map +1 -1
  64. package/dist/server.cjs +66 -14
  65. package/dist/server.cjs.map +1 -1
  66. package/dist/server.d.cts +6 -6
  67. package/dist/server.d.ts +6 -6
  68. package/dist/server.mjs +61 -9
  69. package/dist/server.mjs.map +1 -1
  70. package/dist/styles.css +367 -0
  71. package/dist/testing/index.cjs +13 -72
  72. package/dist/testing/index.cjs.map +1 -1
  73. package/dist/testing/index.d.cts +10 -29
  74. package/dist/testing/index.d.ts +10 -29
  75. package/dist/testing/index.mjs +13 -72
  76. package/dist/testing/index.mjs.map +1 -1
  77. package/dist/testing/jest.cjs +5 -5
  78. package/dist/testing/jest.mjs +2 -2
  79. package/dist/testing/vitest.cjs +5 -5
  80. package/dist/testing/vitest.cjs.map +1 -1
  81. package/dist/testing/vitest.d.cts +0 -10
  82. package/dist/testing/vitest.d.ts +0 -10
  83. package/dist/testing/vitest.mjs +2 -2
  84. package/dist/testing/vitest.mjs.map +1 -1
  85. package/dist/{types-uGHrRaOj.d.ts → types-DDAGLpov.d.ts} +3 -4
  86. package/dist/{types-BdDaLnqs.d.cts → types-DrpQSv_2.d.cts} +3 -4
  87. package/dist/vite-preview.cjs +125 -294
  88. package/dist/vite-preview.cjs.map +1 -1
  89. package/dist/vite-preview.d.cts +24 -6
  90. package/dist/vite-preview.d.ts +24 -6
  91. package/dist/vite-preview.mjs +118 -287
  92. package/dist/vite-preview.mjs.map +1 -1
  93. package/dist/vite.cjs +24 -137
  94. package/dist/vite.cjs.map +1 -1
  95. package/dist/vite.d.cts +7 -43
  96. package/dist/vite.d.ts +7 -43
  97. package/dist/vite.mjs +18 -131
  98. package/dist/vite.mjs.map +1 -1
  99. package/package.json +2 -12
  100. package/schema/extension-v2.json +121 -440
  101. package/dist/chunk-2CY5HVY7.mjs +0 -59
  102. package/dist/chunk-2CY5HVY7.mjs.map +0 -1
  103. package/dist/chunk-7YKH4LZN.cjs.map +0 -1
  104. package/dist/chunk-A74HCO6T.cjs.map +0 -1
  105. package/dist/chunk-BPCGXXMD.cjs.map +0 -1
  106. package/dist/chunk-EB5XWQAU.cjs +0 -132
  107. package/dist/chunk-EB5XWQAU.cjs.map +0 -1
  108. package/dist/chunk-GAUZYBXE.cjs.map +0 -1
  109. package/dist/chunk-KZ5NGFUP.mjs.map +0 -1
  110. package/dist/chunk-O357OJXL.cjs.map +0 -1
  111. package/dist/chunk-ONJMPO3P.cjs +0 -59
  112. package/dist/chunk-ONJMPO3P.cjs.map +0 -1
  113. package/dist/chunk-QJMZRV7A.mjs +0 -132
  114. package/dist/chunk-QJMZRV7A.mjs.map +0 -1
  115. package/dist/chunk-QXD7WVKK.mjs.map +0 -1
  116. package/dist/chunk-SGCYEEXD.mjs.map +0 -1
  117. package/dist/chunk-SGEYDV3K.mjs.map +0 -1
  118. package/dist/chunk-SLGOHIBL.mjs.map +0 -1
  119. package/dist/chunk-SWG7CNTZ.mjs.map +0 -1
  120. package/dist/client-BO3kavn0.d.ts +0 -25
  121. package/dist/client-DE-vMgdO.d.cts +0 -25
  122. package/dist/ui/styles.css +0 -740
  123. package/dist/ui.cjs +0 -1018
  124. package/dist/ui.cjs.map +0 -1
  125. package/dist/ui.d.cts +0 -231
  126. package/dist/ui.d.ts +0 -231
  127. package/dist/ui.mjs +0 -1018
  128. package/dist/ui.mjs.map +0 -1
  129. package/dist/vite-preview-bootstrap.cjs +0 -66
  130. package/dist/vite-preview-bootstrap.cjs.map +0 -1
  131. package/dist/vite-preview-bootstrap.d.cts +0 -15
  132. package/dist/vite-preview-bootstrap.d.ts +0 -15
  133. package/dist/vite-preview-bootstrap.mjs +0 -66
  134. package/dist/vite-preview-bootstrap.mjs.map +0 -1
  135. package/dist/work-events-BlOVpK0k.d.ts +0 -547
  136. package/dist/work-events-D97EoqvS.d.cts +0 -547
  137. /package/dist/{chunk-RBIQT75L.mjs.map → chunk-GG3IX52W.mjs.map} +0 -0
package/dist/ui.mjs DELETED
@@ -1,1018 +0,0 @@
1
- import {
2
- useTap
3
- } from "./chunk-QA5AL3VZ.mjs";
4
- import {
5
- TapError
6
- } from "./chunk-QXD7WVKK.mjs";
7
- import "./chunk-J5LGTIGS.mjs";
8
-
9
- // src/client/ui/cn.ts
10
- import clsx from "clsx";
11
- function cn(...values) {
12
- return clsx(values);
13
- }
14
-
15
- // src/client/ui/button.tsx
16
- import { jsx, jsxs } from "react/jsx-runtime";
17
- function Button({
18
- "aria-busy": ariaBusy,
19
- "data-slot": slot = "button",
20
- children,
21
- className,
22
- disabled,
23
- loading = false,
24
- size = "default",
25
- type = "button",
26
- variant = "primary",
27
- ...props
28
- }) {
29
- return /* @__PURE__ */ jsxs(
30
- "button",
31
- {
32
- ...props,
33
- "aria-busy": ariaBusy ?? (loading || void 0),
34
- className: cn("tap-button", className),
35
- "data-loading": loading || void 0,
36
- "data-size": size,
37
- "data-slot": slot,
38
- "data-variant": variant,
39
- disabled: loading ? true : disabled,
40
- type,
41
- children: [
42
- loading ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "tap-button__spinner" }) : null,
43
- children
44
- ]
45
- }
46
- );
47
- }
48
-
49
- // src/client/ui/card.tsx
50
- import { jsx as jsx2 } from "react/jsx-runtime";
51
- function Card({ className, size = "default", ...props }) {
52
- return /* @__PURE__ */ jsx2(
53
- "div",
54
- {
55
- ...props,
56
- className: cn("tap-ui-card", className),
57
- "data-size": size,
58
- "data-slot": "card"
59
- }
60
- );
61
- }
62
- function CardHeader({
63
- className,
64
- ...props
65
- }) {
66
- return /* @__PURE__ */ jsx2(
67
- "div",
68
- {
69
- ...props,
70
- className: cn("tap-card__header", className),
71
- "data-slot": "card-header"
72
- }
73
- );
74
- }
75
- function CardTitle({
76
- className,
77
- ...props
78
- }) {
79
- return /* @__PURE__ */ jsx2(
80
- "div",
81
- {
82
- ...props,
83
- className: cn("tap-card__title", className),
84
- "data-slot": "card-title"
85
- }
86
- );
87
- }
88
- function CardDescription({
89
- className,
90
- ...props
91
- }) {
92
- return /* @__PURE__ */ jsx2(
93
- "div",
94
- {
95
- ...props,
96
- className: cn("tap-card__description", className),
97
- "data-slot": "card-description"
98
- }
99
- );
100
- }
101
- function CardAction({
102
- className,
103
- ...props
104
- }) {
105
- return /* @__PURE__ */ jsx2(
106
- "div",
107
- {
108
- ...props,
109
- className: cn("tap-card__action", className),
110
- "data-slot": "card-action"
111
- }
112
- );
113
- }
114
- function CardContent({
115
- className,
116
- ...props
117
- }) {
118
- return /* @__PURE__ */ jsx2(
119
- "div",
120
- {
121
- ...props,
122
- className: cn("tap-card__content", className),
123
- "data-slot": "card-content"
124
- }
125
- );
126
- }
127
- function CardFooter({
128
- className,
129
- ...props
130
- }) {
131
- return /* @__PURE__ */ jsx2(
132
- "div",
133
- {
134
- ...props,
135
- className: cn("tap-card__footer", className),
136
- "data-slot": "card-footer"
137
- }
138
- );
139
- }
140
-
141
- // src/client/ui/dialog.tsx
142
- import {
143
- createContext,
144
- useCallback,
145
- useContext,
146
- useEffect,
147
- useId,
148
- useRef
149
- } from "react";
150
- import { createPortal } from "react-dom";
151
- import { jsx as jsx3 } from "react/jsx-runtime";
152
- var FOCUSABLE = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
153
- function activeElementNear(node) {
154
- const root = node?.getRootNode();
155
- return root instanceof ShadowRoot ? root.activeElement : document.activeElement;
156
- }
157
- var DialogContext = createContext(null);
158
- function useDialogPart() {
159
- const value = useContext(DialogContext);
160
- if (!value)
161
- throw new Error("Dialog compound parts must be rendered inside Dialog.");
162
- return value;
163
- }
164
- function Dialog({
165
- children,
166
- onOpenChange,
167
- open
168
- }) {
169
- const tap = useTap();
170
- const contentRef = useRef(null);
171
- const titleId = useId();
172
- const descriptionId = useId();
173
- const close = useCallback(() => onOpenChange(false), [onOpenChange]);
174
- const focusables = useCallback(
175
- () => Array.from(
176
- contentRef.current?.querySelectorAll(FOCUSABLE) ?? []
177
- ),
178
- []
179
- );
180
- useEffect(() => {
181
- if (!open) return;
182
- const previous = activeElementNear(contentRef.current);
183
- focusables()[0]?.focus();
184
- return () => {
185
- if (previous instanceof HTMLElement) previous.focus();
186
- };
187
- }, [focusables, open]);
188
- useEffect(() => {
189
- if (!open || !tap.__portal) return;
190
- tap.__portal.addEventListener("tap:dialog-close", close);
191
- return () => tap.__portal?.removeEventListener("tap:dialog-close", close);
192
- }, [close, open, tap]);
193
- if (!open) return null;
194
- if (!tap.__portal) {
195
- throw new TapError(
196
- "TAP_NO_PORTAL",
197
- "Dialog needs the host portal node inside the extension shadow root."
198
- );
199
- }
200
- const onKeyDown = (event) => {
201
- if (event.key === "Escape") {
202
- event.preventDefault();
203
- event.stopPropagation();
204
- close();
205
- return;
206
- }
207
- if (event.key !== "Tab") return;
208
- const items = focusables();
209
- if (items.length === 0) return;
210
- const first = items[0];
211
- const last = items.at(-1);
212
- const active = activeElementNear(contentRef.current);
213
- if (event.shiftKey && active === first) {
214
- event.preventDefault();
215
- last.focus();
216
- } else if (!event.shiftKey && active === last) {
217
- event.preventDefault();
218
- first.focus();
219
- }
220
- };
221
- return createPortal(
222
- /* @__PURE__ */ jsx3(
223
- DialogContext.Provider,
224
- {
225
- value: { close, contentRef, descriptionId, titleId },
226
- children: /* @__PURE__ */ jsx3(
227
- "div",
228
- {
229
- className: "tap-root tap-ui-dialog-overlay",
230
- "data-slot": "dialog-overlay",
231
- onKeyDown,
232
- onMouseDown: (event) => {
233
- if (event.target === event.currentTarget) close();
234
- },
235
- children
236
- }
237
- )
238
- }
239
- ),
240
- tap.__portal
241
- );
242
- }
243
- function DialogContent({
244
- className,
245
- size = "default",
246
- surface = "paper",
247
- ...props
248
- }) {
249
- const dialog = useDialogPart();
250
- return /* @__PURE__ */ jsx3(
251
- "div",
252
- {
253
- ...props,
254
- "aria-describedby": props["aria-describedby"] ?? dialog.descriptionId,
255
- "aria-labelledby": props["aria-labelledby"] ?? dialog.titleId,
256
- "aria-modal": "true",
257
- className: cn("tap-ui-dialog", className),
258
- "data-size": size,
259
- "data-slot": "dialog-content",
260
- "data-surface": surface,
261
- ref: dialog.contentRef,
262
- role: "dialog"
263
- }
264
- );
265
- }
266
- function DialogHeader({
267
- className,
268
- ...props
269
- }) {
270
- return /* @__PURE__ */ jsx3(
271
- "header",
272
- {
273
- ...props,
274
- className: cn("tap-dialog__header", className),
275
- "data-slot": "dialog-header"
276
- }
277
- );
278
- }
279
- function DialogTitle({
280
- className,
281
- ...props
282
- }) {
283
- const dialog = useDialogPart();
284
- return /* @__PURE__ */ jsx3(
285
- "h2",
286
- {
287
- ...props,
288
- className: cn("tap-dialog__title", className),
289
- "data-slot": "dialog-title",
290
- id: props.id ?? dialog.titleId
291
- }
292
- );
293
- }
294
- function DialogDescription({
295
- className,
296
- ...props
297
- }) {
298
- const dialog = useDialogPart();
299
- return /* @__PURE__ */ jsx3(
300
- "div",
301
- {
302
- ...props,
303
- className: cn("tap-dialog__description", className),
304
- "data-slot": "dialog-description",
305
- id: props.id ?? dialog.descriptionId
306
- }
307
- );
308
- }
309
- function DialogBody({
310
- className,
311
- ...props
312
- }) {
313
- return /* @__PURE__ */ jsx3(
314
- "div",
315
- {
316
- ...props,
317
- className: cn("tap-dialog__body", className),
318
- "data-slot": "dialog-body"
319
- }
320
- );
321
- }
322
- function DialogFooter({
323
- className,
324
- ...props
325
- }) {
326
- return /* @__PURE__ */ jsx3(
327
- "footer",
328
- {
329
- ...props,
330
- className: cn("tap-dialog__footer", className),
331
- "data-slot": "dialog-footer"
332
- }
333
- );
334
- }
335
- function DialogClose({
336
- children = "\xD7",
337
- ...props
338
- }) {
339
- const dialog = useDialogPart();
340
- return /* @__PURE__ */ jsx3(
341
- Button,
342
- {
343
- ...props,
344
- "aria-label": props["aria-label"] ?? "Close dialog",
345
- "data-slot": "dialog-close",
346
- onClick: (event) => {
347
- props.onClick?.(event);
348
- if (!event.defaultPrevented) dialog.close();
349
- },
350
- size: "icon-sm",
351
- variant: "tertiary",
352
- children
353
- }
354
- );
355
- }
356
-
357
- // src/client/ui/layout.tsx
358
- import { jsx as jsx4 } from "react/jsx-runtime";
359
- function Stack({
360
- gap = 16,
361
- className,
362
- "data-slot": slot = "stack",
363
- ...props
364
- }) {
365
- return /* @__PURE__ */ jsx4(
366
- "div",
367
- {
368
- ...props,
369
- className: cn("tap-stack", className),
370
- "data-gap": gap,
371
- "data-slot": slot
372
- }
373
- );
374
- }
375
- function Inline({
376
- align = "center",
377
- gap = 8,
378
- justify = "start",
379
- className,
380
- "data-slot": slot = "inline",
381
- ...props
382
- }) {
383
- return /* @__PURE__ */ jsx4(
384
- "div",
385
- {
386
- ...props,
387
- className: cn("tap-inline", className),
388
- "data-align": align,
389
- "data-gap": gap,
390
- "data-justify": justify,
391
- "data-slot": slot
392
- }
393
- );
394
- }
395
-
396
- // src/client/ui/feedback.tsx
397
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
398
- function Metric({ delta, description, label, value }) {
399
- const percent = delta === void 0 ? void 0 : Math.round(delta * 100);
400
- const direction = percent === void 0 || percent === 0 ? "flat" : percent > 0 ? "up" : "down";
401
- return /* @__PURE__ */ jsxs2("div", { className: "tap-metric", "data-slot": "metric", children: [
402
- /* @__PURE__ */ jsx5("div", { className: "tap-metric__label", "data-slot": "metric-label", children: label }),
403
- /* @__PURE__ */ jsx5("div", { className: "tap-metric__value", "data-slot": "metric-value", children: value }),
404
- percent !== void 0 ? /* @__PURE__ */ jsxs2(
405
- "div",
406
- {
407
- className: "tap-metric__delta",
408
- "data-direction": direction,
409
- "data-slot": "metric-delta",
410
- children: [
411
- percent > 0 ? "+" : "",
412
- percent,
413
- "%"
414
- ]
415
- }
416
- ) : null,
417
- description ? /* @__PURE__ */ jsx5("div", { className: "tap-metric__description", "data-slot": "metric-description", children: description }) : null
418
- ] });
419
- }
420
- function Skeleton({ className, lines = 1, width }) {
421
- return /* @__PURE__ */ jsx5("div", { className: cn("tap-ui-skeleton", className), "data-slot": "skeleton", children: Array.from({ length: Math.max(0, lines) }, (_, index) => /* @__PURE__ */ jsx5(
422
- "span",
423
- {
424
- className: "tap-skeleton__line",
425
- "data-slot": "skeleton-line",
426
- style: { width }
427
- },
428
- index
429
- )) });
430
- }
431
- function EmptyState({ action, description, title }) {
432
- return /* @__PURE__ */ jsxs2(Stack, { className: "tap-ui-state", "data-slot": "empty-state", gap: 12, children: [
433
- /* @__PURE__ */ jsx5("div", { className: "tap-state__title", children: title }),
434
- description ? /* @__PURE__ */ jsx5("div", { className: "tap-state__description", children: description }) : null,
435
- action ? /* @__PURE__ */ jsx5("div", { className: "tap-state__action", children: action }) : null
436
- ] });
437
- }
438
- function ErrorState({
439
- code,
440
- description,
441
- onRetry,
442
- title
443
- }) {
444
- return /* @__PURE__ */ jsxs2(
445
- Stack,
446
- {
447
- className: "tap-ui-state tap-ui-state--error",
448
- "data-slot": "error-state",
449
- gap: 12,
450
- role: "alert",
451
- children: [
452
- /* @__PURE__ */ jsx5("div", { className: "tap-state__title", children: title }),
453
- description ? /* @__PURE__ */ jsx5("div", { className: "tap-state__description", children: description }) : null,
454
- code ? /* @__PURE__ */ jsx5("code", { className: "tap-state__code", children: code }) : null,
455
- onRetry ? /* @__PURE__ */ jsx5("div", { className: "tap-state__action", children: /* @__PURE__ */ jsx5(Button, { variant: "secondary", onClick: onRetry, children: "Try again" }) }) : null
456
- ]
457
- }
458
- );
459
- }
460
-
461
- // src/client/ui/field.tsx
462
- import {
463
- Children,
464
- createContext as createContext2,
465
- forwardRef,
466
- isValidElement,
467
- useContext as useContext2,
468
- useEffect as useEffect2,
469
- useId as useId2,
470
- useRef as useRef2
471
- } from "react";
472
- import { jsx as jsx6 } from "react/jsx-runtime";
473
- var FieldContext = createContext2(null);
474
- function Field({
475
- children,
476
- className,
477
- ...props
478
- }) {
479
- const generatedId = useId2();
480
- const items = Children.toArray(children);
481
- const control = items.find(
482
- (child) => isValidElement(child) && (child.type === Input || child.type === Textarea || child.type === Checkbox || child.type === Select)
483
- );
484
- const customId = isValidElement(control) && typeof control.props.id === "string" ? control.props.id : void 0;
485
- const hasDescription = items.some(
486
- (child) => isValidElement(child) && child.type === FieldDescription
487
- );
488
- const hasError = items.some(
489
- (child) => isValidElement(child) && child.type === FieldError
490
- );
491
- const baseId = `tap-ui-field-${generatedId.replace(/:/g, "")}`;
492
- const value = {
493
- controlId: customId ?? `${baseId}-control`,
494
- descriptionId: hasDescription ? `${baseId}-description` : void 0,
495
- errorId: hasError ? `${baseId}-error` : void 0
496
- };
497
- return /* @__PURE__ */ jsx6(FieldContext.Provider, { value, children: /* @__PURE__ */ jsx6(
498
- "div",
499
- {
500
- ...props,
501
- className: cn("tap-ui-field", className),
502
- "data-invalid": hasError || void 0,
503
- "data-slot": "field",
504
- children
505
- }
506
- ) });
507
- }
508
- function FieldLabel({
509
- className,
510
- ...props
511
- }) {
512
- const field = useContext2(FieldContext);
513
- return /* @__PURE__ */ jsx6(
514
- "label",
515
- {
516
- ...props,
517
- className: cn("tap-field__label", className),
518
- "data-slot": "field-label",
519
- htmlFor: props.htmlFor ?? field?.controlId
520
- }
521
- );
522
- }
523
- function FieldDescription({
524
- className,
525
- ...props
526
- }) {
527
- const field = useContext2(FieldContext);
528
- return /* @__PURE__ */ jsx6(
529
- "div",
530
- {
531
- ...props,
532
- className: cn("tap-field__description", className),
533
- "data-slot": "field-description",
534
- id: props.id ?? field?.descriptionId
535
- }
536
- );
537
- }
538
- function FieldError({
539
- className,
540
- ...props
541
- }) {
542
- const field = useContext2(FieldContext);
543
- return /* @__PURE__ */ jsx6(
544
- "div",
545
- {
546
- ...props,
547
- className: cn("tap-field__error", className),
548
- "data-slot": "field-error",
549
- id: props.id ?? field?.errorId,
550
- role: props.role ?? "alert"
551
- }
552
- );
553
- }
554
- function joinIds(...ids) {
555
- const unique = [
556
- ...new Set(ids.flatMap((id) => id?.split(/\s+/) ?? []).filter(Boolean))
557
- ];
558
- return unique.length > 0 ? unique.join(" ") : void 0;
559
- }
560
- function fieldControlProps(field, id, describedBy, invalid) {
561
- return {
562
- "aria-describedby": joinIds(
563
- describedBy,
564
- field?.descriptionId,
565
- field?.errorId
566
- ),
567
- "aria-invalid": field?.errorId ? true : invalid,
568
- id: id ?? field?.controlId
569
- };
570
- }
571
- var Input = forwardRef(function Input2({
572
- className,
573
- id,
574
- "aria-describedby": describedBy,
575
- "aria-invalid": invalid,
576
- ...props
577
- }, ref) {
578
- const field = useContext2(FieldContext);
579
- return /* @__PURE__ */ jsx6(
580
- "input",
581
- {
582
- ...props,
583
- ...fieldControlProps(field, id, describedBy, invalid),
584
- className: cn("tap-ui-control tap-input", className),
585
- "data-slot": "input",
586
- ref
587
- }
588
- );
589
- });
590
- var Textarea = forwardRef(function Textarea2({
591
- className,
592
- id,
593
- "aria-describedby": describedBy,
594
- "aria-invalid": invalid,
595
- ...props
596
- }, ref) {
597
- const field = useContext2(FieldContext);
598
- return /* @__PURE__ */ jsx6(
599
- "textarea",
600
- {
601
- ...props,
602
- ...fieldControlProps(field, id, describedBy, invalid),
603
- className: cn("tap-ui-control tap-textarea", className),
604
- "data-slot": "textarea",
605
- ref
606
- }
607
- );
608
- });
609
- var Select = forwardRef(function Select2({
610
- className,
611
- id,
612
- "aria-describedby": describedBy,
613
- "aria-invalid": invalid,
614
- ...props
615
- }, ref) {
616
- const field = useContext2(FieldContext);
617
- return /* @__PURE__ */ jsx6(
618
- "select",
619
- {
620
- ...props,
621
- ...fieldControlProps(field, id, describedBy, invalid),
622
- className: cn("tap-ui-control tap-select", className),
623
- "data-slot": "select",
624
- ref
625
- }
626
- );
627
- });
628
- var Checkbox = forwardRef(
629
- function Checkbox2({
630
- checked,
631
- className,
632
- id,
633
- indeterminate = false,
634
- "aria-describedby": describedBy,
635
- "aria-invalid": invalid,
636
- ...props
637
- }, forwardedRef) {
638
- const field = useContext2(FieldContext);
639
- const innerRef = useRef2(null);
640
- useEffect2(() => {
641
- if (innerRef.current) innerRef.current.indeterminate = indeterminate;
642
- }, [indeterminate]);
643
- const setRef = (element) => {
644
- innerRef.current = element;
645
- if (typeof forwardedRef === "function") forwardedRef(element);
646
- else if (forwardedRef) forwardedRef.current = element;
647
- };
648
- return /* @__PURE__ */ jsx6(
649
- "input",
650
- {
651
- ...props,
652
- ...fieldControlProps(field, id, describedBy, invalid),
653
- checked,
654
- className: cn("tap-checkbox", className),
655
- "data-slot": "checkbox",
656
- "data-state": indeterminate ? "indeterminate" : checked ? "checked" : "unchecked",
657
- ref: setRef,
658
- type: "checkbox"
659
- }
660
- );
661
- }
662
- );
663
-
664
- // src/client/ui/page-header.tsx
665
- import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
666
- function PageHeader({
667
- actions,
668
- className,
669
- description,
670
- title,
671
- ...props
672
- }) {
673
- return /* @__PURE__ */ jsxs3(
674
- "header",
675
- {
676
- ...props,
677
- className: cn("tap-ui-page-header", className),
678
- "data-slot": "page-header",
679
- children: [
680
- /* @__PURE__ */ jsxs3("div", { className: "tap-page-header__copy", "data-slot": "page-header-copy", children: [
681
- /* @__PURE__ */ jsx7("h2", { className: "tap-page-header__title", "data-slot": "page-header-title", children: title }),
682
- description ? /* @__PURE__ */ jsx7(
683
- "div",
684
- {
685
- className: "tap-page-header__description",
686
- "data-slot": "page-header-description",
687
- children: description
688
- }
689
- ) : null
690
- ] }),
691
- actions ? /* @__PURE__ */ jsx7(
692
- "div",
693
- {
694
- className: "tap-page-header__actions",
695
- "data-slot": "page-header-actions",
696
- children: actions
697
- }
698
- ) : null
699
- ]
700
- }
701
- );
702
- }
703
-
704
- // src/client/ui/schema-form.tsx
705
- import {
706
- useMemo,
707
- useState
708
- } from "react";
709
- import { z } from "zod";
710
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
711
- function text(source, key) {
712
- return typeof source[key] === "string" ? source[key] : void 0;
713
- }
714
- function humanize(name) {
715
- const spaced = name.replace(/[_-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim();
716
- return spaced.charAt(0).toUpperCase() + spaced.slice(1);
717
- }
718
- function fieldKind(property) {
719
- if (Array.isArray(property.enum)) return "enum";
720
- if (property.type === "boolean") return "boolean";
721
- if (property.type === "number" || property.type === "integer")
722
- return "number";
723
- if (property.format === "textarea") return "textarea";
724
- if (property.format === "date") return "date";
725
- return "text";
726
- }
727
- function schemaFields(schema) {
728
- if (typeof schema.properties !== "object" || schema.properties === null)
729
- return [];
730
- const required = new Set(
731
- Array.isArray(schema.required) ? schema.required.filter(
732
- (name) => typeof name === "string"
733
- ) : []
734
- );
735
- return Object.entries(schema.properties).flatMap(([name, raw]) => {
736
- if (typeof raw !== "object" || raw === null) return [];
737
- const property = { ...raw };
738
- const kind = fieldKind(property);
739
- const field = {
740
- name,
741
- label: text(property, "title") ?? humanize(name),
742
- kind,
743
- required: required.has(name)
744
- };
745
- const description = text(property, "description");
746
- if (description) field.description = description;
747
- if (kind === "enum" && Array.isArray(property.enum)) {
748
- field.options = property.enum.filter((option) => typeof option === "string").map((option) => ({ value: option, label: option }));
749
- }
750
- return [field];
751
- });
752
- }
753
- function compile(schema) {
754
- try {
755
- return z.fromJSONSchema(schema);
756
- } catch {
757
- return null;
758
- }
759
- }
760
- function clean(fields, values) {
761
- return Object.fromEntries(
762
- fields.flatMap((field) => {
763
- const value = values[field.name];
764
- return value === void 0 || value === "" ? [] : [[field.name, value]];
765
- })
766
- );
767
- }
768
- function validate(fields, compiled, values) {
769
- const errors = {};
770
- for (const field of fields) {
771
- if (field.required && (values[field.name] === void 0 || values[field.name] === "")) {
772
- errors[field.name] = `${field.label} is required.`;
773
- }
774
- }
775
- if (!compiled) return errors;
776
- const result = compiled.safeParse(values);
777
- if (result.success) return errors;
778
- for (const issue of result.error.issues) {
779
- const key = issue.path[0];
780
- if (typeof key === "string" && errors[key] === void 0)
781
- errors[key] = issue.message;
782
- }
783
- return errors;
784
- }
785
- function SchemaForm({
786
- schema,
787
- value,
788
- submitLabel = "Submit",
789
- cancelLabel = "Cancel",
790
- busy = false,
791
- onSubmit,
792
- onCancel
793
- }) {
794
- const fields = useMemo(() => schemaFields(schema), [schema]);
795
- const compiled = useMemo(() => compile(schema), [schema]);
796
- const [values, setValues] = useState(() => ({ ...value }));
797
- const [errors, setErrors] = useState({});
798
- const set = (name, next) => {
799
- setValues((current) => ({ ...current, [name]: next }));
800
- setErrors((current) => {
801
- if (current[name] === void 0) return current;
802
- const { [name]: _removed, ...rest } = current;
803
- return rest;
804
- });
805
- };
806
- const submit = (event) => {
807
- event.preventDefault();
808
- const candidate = clean(fields, values);
809
- const found = validate(fields, compiled, candidate);
810
- setErrors(found);
811
- if (Object.keys(found).length === 0) void onSubmit(candidate);
812
- };
813
- return /* @__PURE__ */ jsxs4(
814
- "form",
815
- {
816
- className: "tap-schema-form",
817
- "data-slot": "schema-form",
818
- noValidate: true,
819
- onSubmit: submit,
820
- children: [
821
- fields.map((field) => {
822
- const raw = values[field.name];
823
- const description = field.description ? /* @__PURE__ */ jsx8(FieldDescription, { children: field.description }) : null;
824
- const error = errors[field.name] ? /* @__PURE__ */ jsx8(FieldError, { children: errors[field.name] }) : null;
825
- if (field.kind === "boolean") {
826
- return /* @__PURE__ */ jsxs4(Field, { className: "tap-ui-field--checkbox", children: [
827
- /* @__PURE__ */ jsxs4(FieldLabel, { className: "tap-checkbox-row", children: [
828
- /* @__PURE__ */ jsx8(
829
- Checkbox,
830
- {
831
- checked: raw === true,
832
- onChange: (event) => set(field.name, event.target.checked)
833
- }
834
- ),
835
- /* @__PURE__ */ jsx8("span", { children: field.label })
836
- ] }),
837
- description,
838
- error
839
- ] }, field.name);
840
- }
841
- return /* @__PURE__ */ jsxs4(Field, { children: [
842
- /* @__PURE__ */ jsx8(FieldLabel, { children: field.label }),
843
- field.kind === "enum" ? /* @__PURE__ */ jsxs4(
844
- Select,
845
- {
846
- required: field.required,
847
- value: typeof raw === "string" ? raw : "",
848
- onChange: (event) => set(field.name, event.target.value),
849
- children: [
850
- /* @__PURE__ */ jsx8("option", { value: "", children: "Choose one" }),
851
- field.options?.map((option) => /* @__PURE__ */ jsx8("option", { value: option.value, children: option.label }, option.value))
852
- ]
853
- }
854
- ) : field.kind === "textarea" ? /* @__PURE__ */ jsx8(
855
- Textarea,
856
- {
857
- required: field.required,
858
- value: typeof raw === "string" ? raw : "",
859
- onChange: (event) => set(field.name, event.target.value)
860
- }
861
- ) : /* @__PURE__ */ jsx8(
862
- Input,
863
- {
864
- required: field.required,
865
- type: field.kind === "number" ? "number" : field.kind === "date" ? "date" : "text",
866
- value: typeof raw === "string" || typeof raw === "number" ? String(raw) : "",
867
- onChange: (event) => set(
868
- field.name,
869
- field.kind === "number" ? event.target.value === "" ? "" : Number(event.target.value) : event.target.value
870
- )
871
- }
872
- ),
873
- description,
874
- error
875
- ] }, field.name);
876
- }),
877
- /* @__PURE__ */ jsxs4(
878
- Inline,
879
- {
880
- className: "tap-schema-form__actions",
881
- "data-slot": "form-actions",
882
- justify: "end",
883
- children: [
884
- onCancel ? /* @__PURE__ */ jsx8(Button, { variant: "secondary", onClick: onCancel, children: cancelLabel }) : null,
885
- /* @__PURE__ */ jsx8(Button, { loading: busy, type: "submit", children: submitLabel })
886
- ]
887
- }
888
- )
889
- ]
890
- }
891
- );
892
- }
893
-
894
- // src/client/ui/table.tsx
895
- import { jsx as jsx9 } from "react/jsx-runtime";
896
- function Table({
897
- className,
898
- ...props
899
- }) {
900
- return /* @__PURE__ */ jsx9("div", { className: "tap-ui-table-container", "data-slot": "table-container", children: /* @__PURE__ */ jsx9(
901
- "table",
902
- {
903
- ...props,
904
- className: cn("tap-ui-table", className),
905
- "data-slot": "table"
906
- }
907
- ) });
908
- }
909
- function TableHeader({
910
- className,
911
- ...props
912
- }) {
913
- return /* @__PURE__ */ jsx9(
914
- "thead",
915
- {
916
- ...props,
917
- className: cn("tap-table__header", className),
918
- "data-slot": "table-header"
919
- }
920
- );
921
- }
922
- function TableBody({
923
- className,
924
- ...props
925
- }) {
926
- return /* @__PURE__ */ jsx9(
927
- "tbody",
928
- {
929
- ...props,
930
- className: cn("tap-table__body", className),
931
- "data-slot": "table-body"
932
- }
933
- );
934
- }
935
- function TableRow({
936
- className,
937
- variant = "body",
938
- ...props
939
- }) {
940
- return /* @__PURE__ */ jsx9(
941
- "tr",
942
- {
943
- ...props,
944
- className: cn("tap-table__row", className),
945
- "data-slot": "table-row",
946
- "data-variant": variant
947
- }
948
- );
949
- }
950
- function TableHead({
951
- className,
952
- ...props
953
- }) {
954
- return /* @__PURE__ */ jsx9(
955
- "th",
956
- {
957
- ...props,
958
- className: cn("tap-table__head", className),
959
- "data-slot": "table-head"
960
- }
961
- );
962
- }
963
- function TableCell({
964
- className,
965
- ...props
966
- }) {
967
- return /* @__PURE__ */ jsx9(
968
- "td",
969
- {
970
- ...props,
971
- className: cn("tap-table__cell", className),
972
- "data-slot": "table-cell"
973
- }
974
- );
975
- }
976
- export {
977
- Button,
978
- Card,
979
- CardAction,
980
- CardContent,
981
- CardDescription,
982
- CardFooter,
983
- CardHeader,
984
- CardTitle,
985
- Checkbox,
986
- Dialog,
987
- DialogBody,
988
- DialogClose,
989
- DialogContent,
990
- DialogDescription,
991
- DialogFooter,
992
- DialogHeader,
993
- DialogTitle,
994
- EmptyState,
995
- ErrorState,
996
- Field,
997
- FieldDescription,
998
- FieldError,
999
- FieldLabel,
1000
- Inline,
1001
- Input,
1002
- Metric,
1003
- PageHeader,
1004
- SchemaForm,
1005
- Select,
1006
- Skeleton,
1007
- Stack,
1008
- Table,
1009
- TableBody,
1010
- TableCell,
1011
- TableHead,
1012
- TableHeader,
1013
- TableRow,
1014
- Textarea,
1015
- cn,
1016
- schemaFields
1017
- };
1018
- //# sourceMappingURL=ui.mjs.map