@tappify/extension-sdk 2.0.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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-2DBSVKAU.cjs +65 -0
  3. package/dist/chunk-2DBSVKAU.cjs.map +1 -0
  4. package/dist/chunk-3YWVYA42.cjs +142 -0
  5. package/dist/chunk-3YWVYA42.cjs.map +1 -0
  6. package/dist/chunk-4C5Z3CIK.mjs +26 -0
  7. package/dist/chunk-4C5Z3CIK.mjs.map +1 -0
  8. package/dist/chunk-5AAPD5WV.cjs +250 -0
  9. package/dist/chunk-5AAPD5WV.cjs.map +1 -0
  10. package/dist/chunk-7KIKOH5H.cjs +26 -0
  11. package/dist/chunk-7KIKOH5H.cjs.map +1 -0
  12. package/dist/chunk-BDCX6LRQ.mjs +250 -0
  13. package/dist/chunk-BDCX6LRQ.mjs.map +1 -0
  14. package/dist/chunk-CSTYBKZC.mjs +65 -0
  15. package/dist/chunk-CSTYBKZC.mjs.map +1 -0
  16. package/dist/chunk-IGK2AP6J.mjs +142 -0
  17. package/dist/chunk-IGK2AP6J.mjs.map +1 -0
  18. package/dist/chunk-MNDVYPEP.mjs +302 -0
  19. package/dist/chunk-MNDVYPEP.mjs.map +1 -0
  20. package/dist/chunk-OPPYEA7F.cjs +33 -0
  21. package/dist/chunk-OPPYEA7F.cjs.map +1 -0
  22. package/dist/chunk-PYJMJF44.cjs +302 -0
  23. package/dist/chunk-PYJMJF44.cjs.map +1 -0
  24. package/dist/chunk-QHM7XNRK.mjs +33 -0
  25. package/dist/chunk-QHM7XNRK.mjs.map +1 -0
  26. package/dist/chunk-RMUWRESK.cjs +365 -0
  27. package/dist/chunk-RMUWRESK.cjs.map +1 -0
  28. package/dist/chunk-ZT35X7KL.mjs +365 -0
  29. package/dist/chunk-ZT35X7KL.mjs.map +1 -0
  30. package/dist/codegen.cjs +300 -0
  31. package/dist/codegen.cjs.map +1 -0
  32. package/dist/codegen.d.cts +432 -0
  33. package/dist/codegen.d.ts +432 -0
  34. package/dist/codegen.mjs +272 -0
  35. package/dist/codegen.mjs.map +1 -0
  36. package/dist/constants-DJ_KgZpN.d.cts +449 -0
  37. package/dist/constants-DJ_KgZpN.d.ts +449 -0
  38. package/dist/context-Dt6xh_5t.d.cts +30 -0
  39. package/dist/context-Ml7k_V14.d.ts +30 -0
  40. package/dist/errors-COsBh7kd.d.cts +88 -0
  41. package/dist/errors-COsBh7kd.d.ts +88 -0
  42. package/dist/handler-CZIlZ5vu.d.ts +227 -0
  43. package/dist/handler-kU9Jf36K.d.cts +227 -0
  44. package/dist/host.cjs +24 -0
  45. package/dist/host.cjs.map +1 -0
  46. package/dist/host.d.cts +24 -0
  47. package/dist/host.d.ts +24 -0
  48. package/dist/host.mjs +24 -0
  49. package/dist/host.mjs.map +1 -0
  50. package/dist/index.cjs +698 -0
  51. package/dist/index.cjs.map +1 -0
  52. package/dist/index.d.cts +1016 -0
  53. package/dist/index.d.ts +1016 -0
  54. package/dist/index.mjs +698 -0
  55. package/dist/index.mjs.map +1 -0
  56. package/dist/manifest.cjs +872 -0
  57. package/dist/manifest.cjs.map +1 -0
  58. package/dist/manifest.d.cts +432 -0
  59. package/dist/manifest.d.ts +432 -0
  60. package/dist/manifest.mjs +872 -0
  61. package/dist/manifest.mjs.map +1 -0
  62. package/dist/matchers-Cz93AK1n.d.cts +74 -0
  63. package/dist/matchers-Cz93AK1n.d.ts +74 -0
  64. package/dist/server.cjs +210 -0
  65. package/dist/server.cjs.map +1 -0
  66. package/dist/server.d.cts +243 -0
  67. package/dist/server.d.ts +243 -0
  68. package/dist/server.mjs +210 -0
  69. package/dist/server.mjs.map +1 -0
  70. package/dist/styles.css +367 -0
  71. package/dist/testing/index.cjs +887 -0
  72. package/dist/testing/index.cjs.map +1 -0
  73. package/dist/testing/index.d.cts +512 -0
  74. package/dist/testing/index.d.ts +512 -0
  75. package/dist/testing/index.mjs +887 -0
  76. package/dist/testing/index.mjs.map +1 -0
  77. package/dist/testing/jest.cjs +17 -0
  78. package/dist/testing/jest.cjs.map +1 -0
  79. package/dist/testing/jest.d.cts +12 -0
  80. package/dist/testing/jest.d.ts +12 -0
  81. package/dist/testing/jest.mjs +17 -0
  82. package/dist/testing/jest.mjs.map +1 -0
  83. package/dist/testing/vitest.cjs +15 -0
  84. package/dist/testing/vitest.cjs.map +1 -0
  85. package/dist/testing/vitest.d.cts +10 -0
  86. package/dist/testing/vitest.d.ts +10 -0
  87. package/dist/testing/vitest.mjs +15 -0
  88. package/dist/testing/vitest.mjs.map +1 -0
  89. package/dist/types-DDAGLpov.d.ts +715 -0
  90. package/dist/types-DrpQSv_2.d.cts +715 -0
  91. package/dist/vite.cjs +1344 -0
  92. package/dist/vite.cjs.map +1 -0
  93. package/dist/vite.d.cts +434 -0
  94. package/dist/vite.d.ts +434 -0
  95. package/dist/vite.mjs +1314 -0
  96. package/dist/vite.mjs.map +1 -0
  97. package/package.json +268 -0
  98. package/schema/extension-v2.json +1500 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,698 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ var _chunk5AAPD5WVcjs = require('./chunk-5AAPD5WV.cjs');
19
+
20
+
21
+ var _chunkOPPYEA7Fcjs = require('./chunk-OPPYEA7F.cjs');
22
+
23
+
24
+
25
+
26
+ var _chunk2DBSVKAUcjs = require('./chunk-2DBSVKAU.cjs');
27
+
28
+ // src/client/ui/cn.ts
29
+ var _clsx = require('clsx'); var _clsx2 = _interopRequireDefault(_clsx);
30
+ function cn(...values) {
31
+ return _clsx2.default.call(void 0, values);
32
+ }
33
+
34
+ // src/client/ui/primitives.tsx
35
+
36
+
37
+ var _react = require('react');
38
+ var _jsxruntime = require('react/jsx-runtime');
39
+ function TapButton({
40
+ variant = "primary",
41
+ size = "md",
42
+ loading = false,
43
+ disabled,
44
+ className,
45
+ children,
46
+ ...rest
47
+ }) {
48
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
49
+ "button",
50
+ {
51
+ type: "button",
52
+ ...rest,
53
+ disabled: disabled === true || loading,
54
+ "aria-busy": loading || void 0,
55
+ className: cn(
56
+ "tap-btn",
57
+ `tap-btn--${variant}`,
58
+ size === "sm" && "tap-btn--sm",
59
+ className
60
+ ),
61
+ children
62
+ }
63
+ );
64
+ }
65
+ function TapCard({
66
+ title,
67
+ action,
68
+ footer,
69
+ className,
70
+ children
71
+ }) {
72
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { className: cn("tap-card", className), children: [
73
+ (title !== void 0 || action !== void 0) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "header", { className: "tap-card__head", children: [
74
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: title }),
75
+ action
76
+ ] }),
77
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tap-card__body", children }),
78
+ footer !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "footer", { className: "tap-card__foot", children: footer })
79
+ ] });
80
+ }
81
+ function TapPageHeader({
82
+ title,
83
+ description,
84
+ actions
85
+ }) {
86
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tap-page-header", children: [
87
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
88
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "tap-page-header__title", children: title }),
89
+ description !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "tap-page-header__description", children: description })
90
+ ] }),
91
+ actions !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tap-row", children: actions })
92
+ ] });
93
+ }
94
+ function TapSkeleton({
95
+ lines = 1,
96
+ width,
97
+ className
98
+ }) {
99
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { "aria-hidden": "true", children: Array.from({ length: lines }, (_, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
100
+ "span",
101
+ {
102
+ className: cn("tap-skeleton", className),
103
+ style: { width: _nullishCoalesce(width, () => ( `${String(100 - index * 12)}%`)) }
104
+ },
105
+ index
106
+ )) });
107
+ }
108
+ function TapEmptyState({
109
+ title,
110
+ description,
111
+ action
112
+ }) {
113
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tap-state", children: [
114
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-state__title", children: title }),
115
+ description !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: description }),
116
+ action
117
+ ] });
118
+ }
119
+ function TapErrorState({
120
+ title,
121
+ description,
122
+ code,
123
+ onRetry
124
+ }) {
125
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tap-state tap-state--error", role: "alert", children: [
126
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-state__title", children: title }),
127
+ description !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: description }),
128
+ code !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-state__code", children: code }),
129
+ onRetry !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TapButton, { variant: "secondary", size: "sm", onClick: onRetry, children: "Retry" })
130
+ ] });
131
+ }
132
+ function TapStat({
133
+ label,
134
+ value,
135
+ delta,
136
+ hint
137
+ }) {
138
+ const percent = delta === void 0 ? void 0 : `${delta > 0 ? "+" : ""}${String(Math.round(delta * 100))}%`;
139
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tap-stat", children: [
140
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-stat__label", children: label }),
141
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-stat__value", children: value }),
142
+ percent !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
143
+ "span",
144
+ {
145
+ className: cn(
146
+ delta !== void 0 && delta < 0 ? "tap-stat__delta--down" : "tap-stat__delta--up"
147
+ ),
148
+ children: percent
149
+ }
150
+ ),
151
+ hint !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-field__hint", children: hint })
152
+ ] });
153
+ }
154
+ function FieldFrame({
155
+ id,
156
+ label,
157
+ hint,
158
+ error,
159
+ hintId,
160
+ errorId,
161
+ children
162
+ }) {
163
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tap-field", children: [
164
+ label !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { className: "tap-field__label", htmlFor: id, children: label }),
165
+ children,
166
+ hint !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-field__hint", id: hintId, children: hint }),
167
+ error !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tap-field__error", id: errorId, children: error })
168
+ ] });
169
+ }
170
+ function describedByOf(fieldId, hint, error) {
171
+ const value = cn(
172
+ hint !== void 0 && `${fieldId}-hint`,
173
+ error !== void 0 && `${fieldId}-error`
174
+ );
175
+ return value === "" ? void 0 : value;
176
+ }
177
+ function TapSingleLineInput({
178
+ label,
179
+ error,
180
+ hint,
181
+ className,
182
+ id,
183
+ ...rest
184
+ }) {
185
+ const generated = _react.useId.call(void 0, );
186
+ const fieldId = _nullishCoalesce(id, () => ( generated));
187
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
188
+ FieldFrame,
189
+ {
190
+ id: fieldId,
191
+ label,
192
+ hint,
193
+ error,
194
+ hintId: `${fieldId}-hint`,
195
+ errorId: `${fieldId}-error`,
196
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
197
+ "input",
198
+ {
199
+ ...rest,
200
+ id: fieldId,
201
+ className: cn(
202
+ "tap-control",
203
+ error !== void 0 && "tap-control--invalid",
204
+ className
205
+ ),
206
+ "aria-invalid": error !== void 0 || void 0,
207
+ "aria-describedby": describedByOf(fieldId, hint, error)
208
+ }
209
+ )
210
+ }
211
+ );
212
+ }
213
+ function TapTextarea({
214
+ label,
215
+ error,
216
+ hint,
217
+ className,
218
+ id,
219
+ rows,
220
+ ...rest
221
+ }) {
222
+ const generated = _react.useId.call(void 0, );
223
+ const fieldId = _nullishCoalesce(id, () => ( generated));
224
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
225
+ FieldFrame,
226
+ {
227
+ id: fieldId,
228
+ label,
229
+ hint,
230
+ error,
231
+ hintId: `${fieldId}-hint`,
232
+ errorId: `${fieldId}-error`,
233
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
234
+ "textarea",
235
+ {
236
+ ...rest,
237
+ id: fieldId,
238
+ rows: _nullishCoalesce(rows, () => ( 4)),
239
+ className: cn(
240
+ "tap-control",
241
+ error !== void 0 && "tap-control--invalid",
242
+ className
243
+ ),
244
+ "aria-invalid": error !== void 0 || void 0,
245
+ "aria-describedby": describedByOf(fieldId, hint, error)
246
+ }
247
+ )
248
+ }
249
+ );
250
+ }
251
+ function TapInput(props) {
252
+ if (props.multiline === true) {
253
+ const { multiline: _multiline2, ...rest2 } = props;
254
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TapTextarea, { ...rest2 });
255
+ }
256
+ const { multiline: _multiline, ...rest } = props;
257
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TapSingleLineInput, { ...rest });
258
+ }
259
+ function TapSelect({
260
+ label,
261
+ error,
262
+ hint,
263
+ options,
264
+ className,
265
+ id,
266
+ ...rest
267
+ }) {
268
+ const generated = _react.useId.call(void 0, );
269
+ const fieldId = _nullishCoalesce(id, () => ( generated));
270
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
271
+ FieldFrame,
272
+ {
273
+ id: fieldId,
274
+ label,
275
+ hint,
276
+ error,
277
+ hintId: `${fieldId}-hint`,
278
+ errorId: `${fieldId}-error`,
279
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
280
+ "select",
281
+ {
282
+ ...rest,
283
+ id: fieldId,
284
+ className: cn(
285
+ "tap-control",
286
+ error !== void 0 && "tap-control--invalid",
287
+ className
288
+ ),
289
+ "aria-invalid": error !== void 0 || void 0,
290
+ "aria-describedby": describedByOf(fieldId, hint, error),
291
+ children: options.map((option) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "option", { value: option.value, children: option.label }, option.value))
292
+ }
293
+ )
294
+ }
295
+ );
296
+ }
297
+ function cellText(row, key) {
298
+ if (row === null || typeof row !== "object") return "";
299
+ const value = Reflect.get(row, key);
300
+ if (typeof value === "string") return value;
301
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
302
+ return String(value);
303
+ }
304
+ return "";
305
+ }
306
+ function TapTable({
307
+ columns,
308
+ rows,
309
+ rowKey,
310
+ empty,
311
+ onRowClick
312
+ }) {
313
+ if (rows.length === 0 && empty !== void 0) {
314
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: empty });
315
+ }
316
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tap-table-wrap", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "table", { className: "tap-table", children: [
317
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tr", { children: columns.map((column) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
318
+ "th",
319
+ {
320
+ className: cn(column.align === "end" && "tap-table__end"),
321
+ scope: "col",
322
+ children: column.label
323
+ },
324
+ column.key
325
+ )) }) }),
326
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { children: rows.map((row) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
327
+ "tr",
328
+ {
329
+ "data-clickable": onRowClick !== void 0,
330
+ tabIndex: onRowClick === void 0 ? void 0 : 0,
331
+ onClick: onRowClick === void 0 ? void 0 : () => onRowClick(row),
332
+ onKeyDown: onRowClick === void 0 ? void 0 : (event) => {
333
+ if (event.key !== "Enter" && event.key !== " ") return;
334
+ event.preventDefault();
335
+ onRowClick(row);
336
+ },
337
+ children: columns.map((column) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
338
+ "td",
339
+ {
340
+ className: cn(column.align === "end" && "tap-table__end"),
341
+ children: column.render ? column.render(row) : cellText(row, column.key)
342
+ },
343
+ column.key
344
+ ))
345
+ },
346
+ rowKey(row)
347
+ )) })
348
+ ] }) });
349
+ }
350
+
351
+ // src/client/ui/TapDialog.tsx
352
+
353
+
354
+
355
+
356
+
357
+
358
+ var _reactdom = require('react-dom');
359
+
360
+ var DIALOG_CLOSE_EVENT = "tap:dialog-close";
361
+ var FOCUSABLE = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
362
+ function activeElementNear(node) {
363
+ const root = _optionalChain([node, 'optionalAccess', _2 => _2.getRootNode, 'call', _3 => _3()]);
364
+ return root instanceof ShadowRoot ? root.activeElement : document.activeElement;
365
+ }
366
+ function TapDialog({
367
+ open,
368
+ title,
369
+ onClose,
370
+ footer,
371
+ children,
372
+ labelledBy
373
+ }) {
374
+ const tap = _chunkOPPYEA7Fcjs.useTap.call(void 0, );
375
+ const dialogRef = _react.useRef.call(void 0, null);
376
+ const titleId = _react.useId.call(void 0, );
377
+ const focusables = _react.useCallback.call(void 0, () => {
378
+ const root = dialogRef.current;
379
+ if (root === null) return [];
380
+ return Array.from(root.querySelectorAll(FOCUSABLE));
381
+ }, []);
382
+ _react.useEffect.call(void 0, () => {
383
+ if (!open) return;
384
+ const previous = activeElementNear(dialogRef.current);
385
+ _optionalChain([focusables, 'call', _4 => _4(), 'access', _5 => _5[0], 'optionalAccess', _6 => _6.focus, 'call', _7 => _7()]);
386
+ return () => {
387
+ if (previous instanceof HTMLElement) previous.focus();
388
+ };
389
+ }, [open, focusables]);
390
+ _react.useEffect.call(void 0, () => {
391
+ const portal = tap.__portal;
392
+ if (!open || portal === null) return;
393
+ const close = () => {
394
+ onClose();
395
+ };
396
+ portal.addEventListener(DIALOG_CLOSE_EVENT, close);
397
+ return () => {
398
+ portal.removeEventListener(DIALOG_CLOSE_EVENT, close);
399
+ };
400
+ }, [open, tap, onClose]);
401
+ if (!open) return null;
402
+ if (tap.__portal === null) {
403
+ throw new (0, _chunk2DBSVKAUcjs.TapError)(
404
+ "TAP_NO_PORTAL",
405
+ "TapDialog needs the host portal node, which the mount sets inside its shadow root. Render this dialog from a contribution entry, or use renderWithTap() in tests."
406
+ );
407
+ }
408
+ const onKeyDown = (event) => {
409
+ if (event.key === "Escape") {
410
+ event.stopPropagation();
411
+ event.preventDefault();
412
+ onClose();
413
+ return;
414
+ }
415
+ if (event.key !== "Tab") return;
416
+ const items = focusables();
417
+ if (items.length === 0) return;
418
+ const first = items[0];
419
+ const last = items[items.length - 1];
420
+ const active = activeElementNear(dialogRef.current);
421
+ if (event.shiftKey && active === first) {
422
+ event.preventDefault();
423
+ last.focus();
424
+ return;
425
+ }
426
+ if (!event.shiftKey && active === last) {
427
+ event.preventDefault();
428
+ first.focus();
429
+ }
430
+ };
431
+ return _reactdom.createPortal.call(void 0,
432
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
433
+ "div",
434
+ {
435
+ className: "tap-dialog-scrim",
436
+ onKeyDown,
437
+ onMouseDown: (event) => {
438
+ if (event.target === event.currentTarget) onClose();
439
+ },
440
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
441
+ "div",
442
+ {
443
+ ref: dialogRef,
444
+ className: "tap-dialog",
445
+ role: "dialog",
446
+ "aria-modal": "true",
447
+ "aria-labelledby": _nullishCoalesce(labelledBy, () => ( titleId)),
448
+ children: [
449
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "header", { className: "tap-dialog__head", id: titleId, children: title }),
450
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tap-dialog__body", children }),
451
+ footer !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "footer", { className: "tap-dialog__foot", children: footer })
452
+ ]
453
+ }
454
+ )
455
+ }
456
+ ),
457
+ tap.__portal
458
+ );
459
+ }
460
+
461
+ // src/client/ui/TapForm.tsx
462
+
463
+
464
+
465
+
466
+ var _zod = require('zod');
467
+
468
+ function humanise(name) {
469
+ const spaced = name.replace(/[_-]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim();
470
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
471
+ }
472
+ function readString(source, key) {
473
+ const value = source[key];
474
+ return typeof value === "string" ? value : void 0;
475
+ }
476
+ function kindOf(property) {
477
+ if (Array.isArray(property.enum)) return "enum";
478
+ const type = readString(property, "type");
479
+ if (type === "boolean") return "boolean";
480
+ if (type === "number" || type === "integer") return "number";
481
+ const format = readString(property, "format");
482
+ if (format === "textarea") return "textarea";
483
+ if (format === "date") return "date";
484
+ return "text";
485
+ }
486
+ function formFields(schema) {
487
+ const properties = schema.properties;
488
+ if (typeof properties !== "object" || properties === null) return [];
489
+ const required = new Set(
490
+ Array.isArray(schema.required) ? schema.required.filter(
491
+ (name) => typeof name === "string"
492
+ ) : []
493
+ );
494
+ return Object.entries(properties).flatMap(([name, raw]) => {
495
+ if (typeof raw !== "object" || raw === null) return [];
496
+ const property = { ...raw };
497
+ const kind = kindOf(property);
498
+ const field = {
499
+ name,
500
+ label: _nullishCoalesce(readString(property, "title"), () => ( humanise(name))),
501
+ kind,
502
+ required: required.has(name)
503
+ };
504
+ const hint = readString(property, "description");
505
+ if (hint !== void 0) field.hint = hint;
506
+ if (kind === "enum" && Array.isArray(property.enum)) {
507
+ field.options = property.enum.filter((option) => typeof option === "string").map((option) => ({ value: option, label: option }));
508
+ }
509
+ return [field];
510
+ });
511
+ }
512
+ function requiredErrors(fields, values) {
513
+ const errors = {};
514
+ for (const field of fields) {
515
+ const value = values[field.name];
516
+ if (field.required && (value === void 0 || value === "")) {
517
+ errors[field.name] = `${field.label} is required.`;
518
+ }
519
+ }
520
+ return errors;
521
+ }
522
+ function compile(schema) {
523
+ try {
524
+ return _zod.z.fromJSONSchema(schema);
525
+ } catch (e) {
526
+ return null;
527
+ }
528
+ }
529
+ function validate(fields, compiled, values) {
530
+ const errors = requiredErrors(fields, values);
531
+ if (compiled === null) return errors;
532
+ const result = compiled.safeParse(values);
533
+ if (result.success) return errors;
534
+ for (const issue of result.error.issues) {
535
+ const key = issue.path[0];
536
+ if (typeof key === "string" && errors[key] === void 0) {
537
+ errors[key] = issue.message;
538
+ }
539
+ }
540
+ return errors;
541
+ }
542
+ function clean(fields, values) {
543
+ const output = {};
544
+ for (const field of fields) {
545
+ const value = values[field.name];
546
+ if (value === void 0 || value === "") continue;
547
+ output[field.name] = value;
548
+ }
549
+ return output;
550
+ }
551
+ function TapForm({
552
+ schema,
553
+ value,
554
+ submitLabel = "Submit",
555
+ cancelLabel = "Cancel",
556
+ busy = false,
557
+ onSubmit,
558
+ onCancel
559
+ }) {
560
+ const fields = _react.useMemo.call(void 0, () => formFields(schema), [schema]);
561
+ const compiled = _react.useMemo.call(void 0, () => compile(schema), [schema]);
562
+ const [values, setValues] = _react.useState.call(void 0, () => ({ ...value }));
563
+ const [errors, setErrors] = _react.useState.call(void 0, {});
564
+ const set = (name, next) => {
565
+ setValues((current) => ({ ...current, [name]: next }));
566
+ setErrors((current) => {
567
+ if (current[name] === void 0) return current;
568
+ const { [name]: _cleared, ...rest } = current;
569
+ return rest;
570
+ });
571
+ };
572
+ const submit = (event) => {
573
+ event.preventDefault();
574
+ const candidate = clean(fields, values);
575
+ const found = validate(fields, compiled, candidate);
576
+ setErrors(found);
577
+ if (Object.keys(found).length > 0) return;
578
+ void onSubmit(candidate);
579
+ };
580
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "form", { className: "tap-form", onSubmit: submit, noValidate: true, children: [
581
+ fields.map((field) => {
582
+ const raw = values[field.name];
583
+ if (field.kind === "enum") {
584
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
585
+ TapSelect,
586
+ {
587
+ label: field.label,
588
+ hint: field.hint,
589
+ error: errors[field.name],
590
+ required: field.required,
591
+ value: typeof raw === "string" ? raw : "",
592
+ options: [
593
+ { value: "", label: "Choose one" },
594
+ ..._nullishCoalesce(field.options, () => ( []))
595
+ ],
596
+ onChange: (event) => {
597
+ set(field.name, event.target.value);
598
+ }
599
+ },
600
+ field.name
601
+ );
602
+ }
603
+ if (field.kind === "boolean") {
604
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
605
+ TapInput,
606
+ {
607
+ type: "checkbox",
608
+ label: field.label,
609
+ hint: field.hint,
610
+ error: errors[field.name],
611
+ className: "tap-control--checkbox",
612
+ checked: raw === true,
613
+ onChange: (event) => {
614
+ set(field.name, event.target.checked);
615
+ }
616
+ },
617
+ field.name
618
+ );
619
+ }
620
+ if (field.kind === "textarea") {
621
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
622
+ TapInput,
623
+ {
624
+ multiline: true,
625
+ label: field.label,
626
+ hint: field.hint,
627
+ error: errors[field.name],
628
+ required: field.required,
629
+ value: typeof raw === "string" ? raw : "",
630
+ onChange: (event) => {
631
+ set(field.name, event.target.value);
632
+ }
633
+ },
634
+ field.name
635
+ );
636
+ }
637
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
638
+ TapInput,
639
+ {
640
+ type: field.kind === "number" ? "number" : field.kind === "date" ? "date" : "text",
641
+ label: field.label,
642
+ hint: field.hint,
643
+ error: errors[field.name],
644
+ required: field.required,
645
+ value: typeof raw === "string" || typeof raw === "number" ? String(raw) : "",
646
+ onChange: (event) => {
647
+ set(
648
+ field.name,
649
+ field.kind === "number" ? event.target.value === "" ? "" : Number(event.target.value) : event.target.value
650
+ );
651
+ }
652
+ },
653
+ field.name
654
+ );
655
+ }),
656
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tap-form__actions", children: [
657
+ onCancel !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TapButton, { variant: "secondary", onClick: onCancel, children: cancelLabel }),
658
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, TapButton, { type: "submit", loading: busy, children: submitLabel })
659
+ ] })
660
+ ] });
661
+ }
662
+
663
+
664
+
665
+
666
+
667
+
668
+
669
+
670
+
671
+
672
+
673
+
674
+
675
+
676
+
677
+
678
+
679
+
680
+
681
+
682
+
683
+
684
+
685
+
686
+
687
+
688
+
689
+
690
+
691
+
692
+
693
+
694
+
695
+
696
+
697
+ exports.TAP_ERROR_CODES = _chunk2DBSVKAUcjs.TAP_ERROR_CODES; exports.TapButton = TapButton; exports.TapCard = TapCard; exports.TapDialog = TapDialog; exports.TapEmptyState = TapEmptyState; exports.TapError = _chunk2DBSVKAUcjs.TapError; exports.TapErrorState = TapErrorState; exports.TapForm = TapForm; exports.TapInput = TapInput; exports.TapPageHeader = TapPageHeader; exports.TapSelect = TapSelect; exports.TapServerError = _chunk2DBSVKAUcjs.TapServerError; exports.TapSkeleton = TapSkeleton; exports.TapStat = TapStat; exports.TapTable = TapTable; exports.cn = cn; exports.dataQueryKey = _chunk5AAPD5WVcjs.dataQueryKey; exports.formFields = formFields; exports.installPrefix = _chunk5AAPD5WVcjs.installPrefix; exports.procedurePrefix = _chunk5AAPD5WVcjs.procedurePrefix; exports.procedureQueryKey = _chunk5AAPD5WVcjs.procedureQueryKey; exports.storageQueryKey = _chunk5AAPD5WVcjs.storageQueryKey; exports.useTap = _chunkOPPYEA7Fcjs.useTap; exports.useTapAuth = _chunk5AAPD5WVcjs.useTapAuth; exports.useTapContext = _chunk5AAPD5WVcjs.useTapContext; exports.useTapFilters = _chunk5AAPD5WVcjs.useTapFilters; exports.useTapParams = _chunk5AAPD5WVcjs.useTapParams; exports.useTapProject = _chunk5AAPD5WVcjs.useTapProject; exports.useTapQuery = _chunk5AAPD5WVcjs.useTapQuery; exports.useTapServer = _chunk5AAPD5WVcjs.useTapServer; exports.useTapSize = _chunk5AAPD5WVcjs.useTapSize; exports.useTapState = _chunk5AAPD5WVcjs.useTapState; exports.useTapStorage = _chunk5AAPD5WVcjs.useTapStorage; exports.useTapTheme = _chunk5AAPD5WVcjs.useTapTheme;
698
+ //# sourceMappingURL=index.cjs.map