@petrarca/sonnet-playground 0.2.0 → 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 (75) hide show
  1. package/README.md +142 -0
  2. package/dist/PlayAdvancedComponents-ZYK66UII.js +8 -0
  3. package/dist/PlayColorPalette-IWECRZUS.js +8 -0
  4. package/dist/PlayCoreComponents-GXFMB24T.js +8 -0
  5. package/dist/PlayDataComponents-M4SJ4XEL.js +8 -0
  6. package/dist/PlayFormComponents-4E2A2Y2W.js +8 -0
  7. package/dist/PlayFormWidgets-IWJJQ5XL.js +8 -0
  8. package/dist/PlayForms-FOF3XE6G.js +7 -0
  9. package/dist/PlayGraph-3F56PREG.js +7 -0
  10. package/dist/PlayJsonEditor-SYZYEJEA.js +7 -0
  11. package/dist/PlayShellApi-5O6VYR2X.js +8 -0
  12. package/dist/PlayShellApi-5O6VYR2X.js.map +1 -0
  13. package/dist/PlayTypography-T6SMPHUB.js +8 -0
  14. package/dist/PlayTypography-T6SMPHUB.js.map +1 -0
  15. package/dist/chunk-32DDRRWU.js +617 -0
  16. package/dist/chunk-32DDRRWU.js.map +1 -0
  17. package/dist/chunk-4Y4JFKAK.js +240 -0
  18. package/dist/chunk-4Y4JFKAK.js.map +1 -0
  19. package/dist/{chunk-QIETZUEN.js → chunk-6DZ3TSV4.js} +66 -71
  20. package/dist/chunk-6DZ3TSV4.js.map +1 -0
  21. package/dist/{chunk-CYNK2P2Q.js → chunk-7IBZEHLI.js} +14 -13
  22. package/dist/chunk-7IBZEHLI.js.map +1 -0
  23. package/dist/chunk-C2EZ2ECG.js +40 -0
  24. package/dist/chunk-C2EZ2ECG.js.map +1 -0
  25. package/dist/chunk-CQ6PGFRV.js +341 -0
  26. package/dist/chunk-CQ6PGFRV.js.map +1 -0
  27. package/dist/{chunk-A3IK3CVW.js → chunk-DA3BIB5N.js} +24 -25
  28. package/dist/{chunk-A3IK3CVW.js.map → chunk-DA3BIB5N.js.map} +1 -1
  29. package/dist/chunk-DZB6WFHA.js +401 -0
  30. package/dist/chunk-DZB6WFHA.js.map +1 -0
  31. package/dist/{chunk-KAT24CQQ.js → chunk-FZ3ZC7VM.js} +8 -6
  32. package/dist/chunk-FZ3ZC7VM.js.map +1 -0
  33. package/dist/{chunk-PGI54O43.js → chunk-VOC5VZG2.js} +84 -46
  34. package/dist/chunk-VOC5VZG2.js.map +1 -0
  35. package/dist/{chunk-TZGJH7YS.js → chunk-YEBK2TUW.js} +325 -331
  36. package/dist/chunk-YEBK2TUW.js.map +1 -0
  37. package/dist/chunk-YOOWJORD.js +934 -0
  38. package/dist/chunk-YOOWJORD.js.map +1 -0
  39. package/dist/index.d.ts +10 -6
  40. package/dist/index.js +41 -17
  41. package/dist/index.js.map +1 -1
  42. package/dist/pages/index.d.ts +15 -11
  43. package/dist/pages/index.js +20 -12
  44. package/package.json +6 -6
  45. package/dist/PlayColorPalette-UFMTJTUB.js +0 -8
  46. package/dist/PlayCoreComponents-7QCDFQLT.js +0 -7
  47. package/dist/PlayDataComponents-GZSRTW4F.js +0 -7
  48. package/dist/PlayFormComponents-RJB6WZHD.js +0 -7
  49. package/dist/PlayFormWidgets-OFV7TJKH.js +0 -7
  50. package/dist/PlayForms-24XX5DC6.js +0 -7
  51. package/dist/PlayGraph-FLGLSUWV.js +0 -8
  52. package/dist/PlayJsonEditor-4L5INQPU.js +0 -7
  53. package/dist/PlayTypography-ID6DLFZD.js +0 -8
  54. package/dist/chunk-5V27QDAY.js +0 -617
  55. package/dist/chunk-5V27QDAY.js.map +0 -1
  56. package/dist/chunk-CYNK2P2Q.js.map +0 -1
  57. package/dist/chunk-FTN2A5YL.js +0 -20
  58. package/dist/chunk-FTN2A5YL.js.map +0 -1
  59. package/dist/chunk-GYKEPHHA.js +0 -1154
  60. package/dist/chunk-GYKEPHHA.js.map +0 -1
  61. package/dist/chunk-KAT24CQQ.js.map +0 -1
  62. package/dist/chunk-P7I5IDXA.js +0 -432
  63. package/dist/chunk-P7I5IDXA.js.map +0 -1
  64. package/dist/chunk-PGI54O43.js.map +0 -1
  65. package/dist/chunk-QIETZUEN.js.map +0 -1
  66. package/dist/chunk-TZGJH7YS.js.map +0 -1
  67. /package/dist/{PlayColorPalette-UFMTJTUB.js.map → PlayAdvancedComponents-ZYK66UII.js.map} +0 -0
  68. /package/dist/{PlayCoreComponents-7QCDFQLT.js.map → PlayColorPalette-IWECRZUS.js.map} +0 -0
  69. /package/dist/{PlayDataComponents-GZSRTW4F.js.map → PlayCoreComponents-GXFMB24T.js.map} +0 -0
  70. /package/dist/{PlayFormComponents-RJB6WZHD.js.map → PlayDataComponents-M4SJ4XEL.js.map} +0 -0
  71. /package/dist/{PlayFormWidgets-OFV7TJKH.js.map → PlayFormComponents-4E2A2Y2W.js.map} +0 -0
  72. /package/dist/{PlayForms-24XX5DC6.js.map → PlayFormWidgets-IWJJQ5XL.js.map} +0 -0
  73. /package/dist/{PlayGraph-FLGLSUWV.js.map → PlayForms-FOF3XE6G.js.map} +0 -0
  74. /package/dist/{PlayJsonEditor-4L5INQPU.js.map → PlayGraph-3F56PREG.js.map} +0 -0
  75. /package/dist/{PlayTypography-ID6DLFZD.js.map → PlayJsonEditor-SYZYEJEA.js.map} +0 -0
@@ -1,3 +1,7 @@
1
+ import {
2
+ PlaygroundSection
3
+ } from "./chunk-C2EZ2ECG.js";
4
+
1
5
  // src/pages/PlayDataComponents.tsx
2
6
  import { useState, useMemo, useCallback } from "react";
3
7
  import { ArrowRight, ArrowUp } from "lucide-react";
@@ -9,16 +13,14 @@ import {
9
13
  Tabs,
10
14
  TabsContent,
11
15
  TabsList,
12
- TabsTrigger
13
- } from "@petrarca/sonnet-ui";
14
- import { FormTextarea } from "@petrarca/sonnet-forms";
15
- import {
16
+ TabsTrigger,
16
17
  SearchInput,
17
18
  EntitySelect,
18
19
  EntityTable,
19
20
  createRenderer,
20
21
  EntityTree
21
22
  } from "@petrarca/sonnet-ui";
23
+ import { FormTextarea } from "@petrarca/sonnet-forms";
22
24
  import { JsonEditor } from "@petrarca/sonnet-ui/json-editor";
23
25
  import {
24
26
  EMPTY_FILTER,
@@ -27,6 +29,7 @@ import {
27
29
  serializeFilterExpr
28
30
  } from "@petrarca/sonnet-core/search";
29
31
  import { toJsonSchema } from "@petrarca/sonnet-core/schema";
32
+ import { useTreeExpansion } from "@petrarca/sonnet-core/hooks";
30
33
  import { z } from "zod/v4";
31
34
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
32
35
  var MOCK_PATIENTS = [
@@ -190,7 +193,7 @@ var CUSTOM_RENDERERS = {
190
193
  (Date.now() - new Date(row.joined).getTime()) / 864e5
191
194
  );
192
195
  const isRecent = days < threshold;
193
- return /* @__PURE__ */ jsxs("span", { className: isRecent ? "text-blue-600" : "text-muted-foreground", children: [
196
+ return /* @__PURE__ */ jsxs("span", { className: isRecent ? "text-primary" : "text-muted-foreground", children: [
194
197
  days,
195
198
  "d"
196
199
  ] });
@@ -235,6 +238,7 @@ var CUSTOM_RENDERER_SCHEMA = {
235
238
  }
236
239
  }
237
240
  };
241
+ var SUBMIT_COUNT_RESET = -1;
238
242
  var SEARCH_FIELD_PRESETS = [
239
243
  { label: "name, role", fields: ["name", "role"] },
240
244
  { label: "name (single)", fields: ["name"] },
@@ -285,15 +289,6 @@ function FlatTermsInspector({ expr }) {
285
289
  const terms = flattenFilterExpr(expr);
286
290
  return /* @__PURE__ */ jsx("pre", { className: "mt-3 rounded-md bg-muted px-4 py-3 text-xs overflow-auto max-h-40", children: JSON.stringify(terms, null, 2) });
287
291
  }
288
- function SectionHeader({
289
- title,
290
- description
291
- }) {
292
- return /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
293
- /* @__PURE__ */ jsx("h2", { className: "heading-section mb-1", children: title }),
294
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
295
- ] });
296
- }
297
292
  function PlayDataComponents() {
298
293
  const [simpleExpr, setSimpleExpr] = useState(EMPTY_FILTER);
299
294
  const [simpleMode, setSimpleMode] = useState("explicit");
@@ -328,7 +323,7 @@ function PlayDataComponents() {
328
323
  const parsed = JSON.parse(schemaText);
329
324
  setActiveSchema(parsed);
330
325
  setFacetedExpr(EMPTY_FILTER);
331
- setFacetedSubmitCount(-1);
326
+ setFacetedSubmitCount(SUBMIT_COUNT_RESET);
332
327
  setSchemaError("");
333
328
  } catch {
334
329
  setSchemaError("Invalid JSON -- cannot load");
@@ -400,330 +395,331 @@ function PlayDataComponents() {
400
395
  [filteredRows]
401
396
  );
402
397
  const [selectedPatient, setSelectedPatient] = useState(null);
403
- return /* @__PURE__ */ jsxs("div", { className: "w-full py-12 px-4 max-w-4xl", children: [
404
- /* @__PURE__ */ jsx("h1", { className: "mb-1", children: "Data Components" }),
405
- /* @__PURE__ */ jsx("p", { className: "text-lg text-muted-foreground mb-10", children: "Interactive sandbox for SearchInput, EntitySelect, and EntityTable." }),
406
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
407
- /* @__PURE__ */ jsx(
408
- SectionHeader,
409
- {
410
- title: "SearchInput \u2014 simple mode",
411
- description: "No fields prop. Produces a single search term under the key 'search'."
412
- }
413
- ),
414
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-4 mb-3", children: [
415
- /* @__PURE__ */ jsx(
416
- ToggleStrip,
417
- {
418
- label: "Mode",
419
- options: MODE_OPTIONS,
420
- value: simpleMode,
421
- onChange: (m) => {
422
- setSimpleMode(m);
423
- setSimpleExpr(EMPTY_FILTER);
424
- },
425
- format: (m) => MODE_LABELS[m]
426
- }
427
- ),
428
- /* @__PURE__ */ jsx(
429
- ToggleStrip,
430
- {
431
- label: "Min chars",
432
- options: MIN_CHARS_OPTIONS,
433
- value: simpleMinChars,
434
- onChange: setSimpleMinChars,
435
- format: (n) => n === 0 ? "off" : String(n)
436
- }
437
- )
438
- ] }),
439
- /* @__PURE__ */ jsx(
440
- SearchInput,
441
- {
442
- value: simpleExpr,
443
- onChange: setSimpleExpr,
444
- mode: simpleMode,
445
- minChars: simpleMinChars,
446
- placeholder: "Search...",
447
- className: "max-w-sm"
448
- }
449
- ),
450
- /* @__PURE__ */ jsx(FlatTermsInspector, { expr: simpleExpr })
451
- ] }),
452
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
453
- /* @__PURE__ */ jsx(
454
- SectionHeader,
455
- {
456
- title: "SearchInput \u2014 searchFields (multi-field OR)",
457
- description: "Simple mode with searchFields prop. Typing text produces a FilterOr with one term per field. buildListParams serializes it as a q= expression for the server. Toggle field sets, mode, and minChars to explore different behaviours."
458
- }
459
- ),
460
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-4 mb-2", children: /* @__PURE__ */ jsx(
461
- ToggleStrip,
462
- {
463
- label: "Fields",
464
- options: FIELD_PRESET_INDICES,
465
- value: fieldsPresetIdx,
466
- onChange: (idx) => {
467
- setFieldsPresetIdx(idx);
468
- setFieldsExpr(EMPTY_FILTER);
469
- },
470
- format: (idx) => SEARCH_FIELD_PRESETS[idx].label
471
- }
472
- ) }),
473
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-4 mb-3", children: [
474
- /* @__PURE__ */ jsx(
475
- ToggleStrip,
476
- {
477
- label: "Mode",
478
- options: MODE_OPTIONS,
479
- value: fieldsMode,
480
- onChange: (m) => {
481
- setFieldsMode(m);
482
- setFieldsExpr(EMPTY_FILTER);
483
- },
484
- format: (m) => MODE_LABELS[m]
485
- }
486
- ),
487
- /* @__PURE__ */ jsx(
488
- ToggleStrip,
489
- {
490
- label: "Min chars",
491
- options: MIN_CHARS_OPTIONS,
492
- value: fieldsMinChars,
493
- onChange: setFieldsMinChars,
494
- format: (n) => n === 0 ? "off" : String(n)
495
- }
496
- )
497
- ] }),
498
- /* @__PURE__ */ jsx(
499
- SearchInput,
500
- {
501
- value: fieldsExpr,
502
- onChange: setFieldsExpr,
503
- searchFields: activeSearchFields,
504
- mode: fieldsMode,
505
- minChars: fieldsMinChars,
506
- placeholder: `Search by ${activeSearchFields.join(" or ")}...`,
507
- className: "max-w-sm"
508
- }
509
- ),
510
- /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2", children: [
511
- /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
512
- "searchFields: [",
513
- activeSearchFields.map((f) => `"${f}"`).join(", "),
514
- "]"
515
- ] }),
516
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "FilterExpr AST:" }),
517
- /* @__PURE__ */ jsx(FilterExprInspector, { expr: fieldsExpr }),
518
- !isEmptyFilterExpr(fieldsExpr) && /* @__PURE__ */ jsxs(Fragment, { children: [
519
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Serialized q= string:" }),
520
- /* @__PURE__ */ jsx("pre", { className: "rounded-md bg-muted px-4 py-3 text-xs overflow-auto", children: serializeFilterExpr(fieldsExpr) })
521
- ] })
522
- ] })
398
+ return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-4xl space-y-6", children: [
399
+ /* @__PURE__ */ jsxs("div", { children: [
400
+ /* @__PURE__ */ jsx("h1", { children: "Data Components" }),
401
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Interactive sandbox for SearchInput (simple, multi-field, faceted), EntityTable (with schema editor and custom renderers), EntitySelect, and EntityTree." })
523
402
  ] }),
524
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
525
- /* @__PURE__ */ jsx(
526
- SectionHeader,
527
- {
528
- title: "SearchInput \u2014 faceted mode",
529
- description: "Edit the JSON Schema on the left and load it into the search input. Add chips by picking a field and typing a value. Press Enter on empty input to fire onChange."
530
- }
531
- ),
532
- /* @__PURE__ */ jsxs("div", { className: "flex gap-4 items-start", children: [
533
- /* @__PURE__ */ jsxs(Card, { className: "flex-1 min-w-0 p-3 flex flex-col gap-2", children: [
534
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "JSON Schema" }),
535
- schemaError && /* @__PURE__ */ jsx(Badge, { variant: "destructive", className: "text-xs self-start", children: schemaError }),
403
+ /* @__PURE__ */ jsxs(
404
+ PlaygroundSection,
405
+ {
406
+ title: "SearchInput \u2014 simple mode",
407
+ description: "No fields prop. Produces a single search term under the key 'search'.",
408
+ variant: "card",
409
+ children: [
410
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-4 mb-3", children: [
411
+ /* @__PURE__ */ jsx(
412
+ ToggleStrip,
413
+ {
414
+ label: "Mode",
415
+ options: MODE_OPTIONS,
416
+ value: simpleMode,
417
+ onChange: (m) => {
418
+ setSimpleMode(m);
419
+ setSimpleExpr(EMPTY_FILTER);
420
+ },
421
+ format: (m) => MODE_LABELS[m]
422
+ }
423
+ ),
424
+ /* @__PURE__ */ jsx(
425
+ ToggleStrip,
426
+ {
427
+ label: "Min chars",
428
+ options: MIN_CHARS_OPTIONS,
429
+ value: simpleMinChars,
430
+ onChange: setSimpleMinChars,
431
+ format: (n) => n === 0 ? "off" : String(n)
432
+ }
433
+ )
434
+ ] }),
536
435
  /* @__PURE__ */ jsx(
537
- FormTextarea,
436
+ SearchInput,
538
437
  {
539
- value: schemaText,
540
- onChange: (e) => handleSchemaTextChange(e.target.value),
541
- className: "font-mono text-xs",
542
- rows: 18
438
+ value: simpleExpr,
439
+ onChange: setSimpleExpr,
440
+ mode: simpleMode,
441
+ minChars: simpleMinChars,
442
+ placeholder: "Search...",
443
+ className: "max-w-sm"
543
444
  }
544
- )
545
- ] }),
546
- /* @__PURE__ */ jsx("div", { className: "flex items-center self-center", children: /* @__PURE__ */ jsx(SimpleTooltip, { label: "Load schema into search", children: /* @__PURE__ */ jsx(
547
- Button,
548
- {
549
- variant: "default",
550
- size: "icon",
551
- onClick: handleLoadSchema,
552
- disabled: !!schemaError,
553
- children: /* @__PURE__ */ jsx(ArrowRight, { size: 18 })
554
- }
555
- ) }) }),
556
- /* @__PURE__ */ jsxs(Card, { className: "flex-1 min-w-0 p-3 flex flex-col gap-3", children: [
557
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Live search" }),
445
+ ),
446
+ /* @__PURE__ */ jsx(FlatTermsInspector, { expr: simpleExpr })
447
+ ]
448
+ }
449
+ ),
450
+ /* @__PURE__ */ jsxs(
451
+ PlaygroundSection,
452
+ {
453
+ title: "SearchInput \u2014 searchFields (multi-field OR)",
454
+ description: "Produces a FilterOr with one term per field. Toggle field sets, mode, and minChars to explore different behaviours.",
455
+ variant: "card",
456
+ children: [
457
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-4 mb-3", children: [
458
+ /* @__PURE__ */ jsx(
459
+ ToggleStrip,
460
+ {
461
+ label: "Fields",
462
+ options: FIELD_PRESET_INDICES,
463
+ value: fieldsPresetIdx,
464
+ onChange: (idx) => {
465
+ setFieldsPresetIdx(idx);
466
+ setFieldsExpr(EMPTY_FILTER);
467
+ },
468
+ format: (idx) => SEARCH_FIELD_PRESETS[idx].label
469
+ }
470
+ ),
471
+ /* @__PURE__ */ jsx(
472
+ ToggleStrip,
473
+ {
474
+ label: "Mode",
475
+ options: MODE_OPTIONS,
476
+ value: fieldsMode,
477
+ onChange: (m) => {
478
+ setFieldsMode(m);
479
+ setFieldsExpr(EMPTY_FILTER);
480
+ },
481
+ format: (m) => MODE_LABELS[m]
482
+ }
483
+ ),
484
+ /* @__PURE__ */ jsx(
485
+ ToggleStrip,
486
+ {
487
+ label: "Min chars",
488
+ options: MIN_CHARS_OPTIONS,
489
+ value: fieldsMinChars,
490
+ onChange: setFieldsMinChars,
491
+ format: (n) => n === 0 ? "off" : String(n)
492
+ }
493
+ )
494
+ ] }),
558
495
  /* @__PURE__ */ jsx(
559
496
  SearchInput,
560
497
  {
561
- value: facetedExpr,
562
- onChange: handleFacetedChange,
563
- schema: activeSchema,
564
- mode: "explicit",
565
- placeholder: "Add filter..."
498
+ value: fieldsExpr,
499
+ onChange: setFieldsExpr,
500
+ searchFields: activeSearchFields,
501
+ mode: fieldsMode,
502
+ minChars: fieldsMinChars,
503
+ placeholder: `Search by ${activeSearchFields.join(" or ")}...`,
504
+ className: "max-w-sm"
566
505
  }
567
506
  ),
568
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
569
- /* @__PURE__ */ jsx("span", { children: "onChange fired:" }),
570
- /* @__PURE__ */ jsxs("span", { className: "font-mono font-medium text-foreground", children: [
571
- facetedSubmitCount,
572
- "x"
507
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2", children: [
508
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
509
+ "searchFields: [",
510
+ activeSearchFields.map((f) => `"${f}"`).join(", "),
511
+ "]"
512
+ ] }),
513
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "FilterExpr AST:" }),
514
+ /* @__PURE__ */ jsx(FilterExprInspector, { expr: fieldsExpr }),
515
+ !isEmptyFilterExpr(fieldsExpr) && /* @__PURE__ */ jsxs(Fragment, { children: [
516
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Serialized q= string:" }),
517
+ /* @__PURE__ */ jsx("pre", { className: "rounded-md bg-muted px-4 py-3 text-xs overflow-auto", children: serializeFilterExpr(fieldsExpr) })
573
518
  ] })
519
+ ] })
520
+ ]
521
+ }
522
+ ),
523
+ /* @__PURE__ */ jsx(
524
+ PlaygroundSection,
525
+ {
526
+ title: "SearchInput \u2014 faceted mode",
527
+ description: "Edit the JSON Schema on the left and load it into the search input. Add chips by picking a field and typing a value. Press Enter on empty input to fire onChange.",
528
+ variant: "card",
529
+ children: /* @__PURE__ */ jsxs("div", { className: "flex gap-4 items-start", children: [
530
+ /* @__PURE__ */ jsxs(Card, { className: "flex-1 min-w-0 p-3 flex flex-col gap-2", children: [
531
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "JSON Schema" }),
532
+ schemaError && /* @__PURE__ */ jsx(Badge, { variant: "destructive", className: "text-xs self-start", children: schemaError }),
533
+ /* @__PURE__ */ jsx(
534
+ FormTextarea,
535
+ {
536
+ value: schemaText,
537
+ onChange: (e) => handleSchemaTextChange(e.target.value),
538
+ className: "font-mono text-xs",
539
+ rows: 18
540
+ }
541
+ )
574
542
  ] }),
575
- /* @__PURE__ */ jsx(FilterExprInspector, { expr: facetedExpr })
543
+ /* @__PURE__ */ jsx("div", { className: "flex items-center self-center", children: /* @__PURE__ */ jsx(SimpleTooltip, { label: "Load schema into search", children: /* @__PURE__ */ jsx(
544
+ Button,
545
+ {
546
+ variant: "default",
547
+ size: "icon",
548
+ onClick: handleLoadSchema,
549
+ disabled: !!schemaError,
550
+ children: /* @__PURE__ */ jsx(ArrowRight, { size: 18 })
551
+ }
552
+ ) }) }),
553
+ /* @__PURE__ */ jsxs(Card, { className: "flex-1 min-w-0 p-3 flex flex-col gap-3", children: [
554
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Live search" }),
555
+ /* @__PURE__ */ jsx(
556
+ SearchInput,
557
+ {
558
+ value: facetedExpr,
559
+ onChange: handleFacetedChange,
560
+ schema: activeSchema,
561
+ mode: "explicit",
562
+ placeholder: "Add filter..."
563
+ }
564
+ ),
565
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
566
+ /* @__PURE__ */ jsx("span", { children: "onChange fired:" }),
567
+ /* @__PURE__ */ jsxs("span", { className: "font-mono font-medium text-foreground", children: [
568
+ facetedSubmitCount,
569
+ "x"
570
+ ] })
571
+ ] }),
572
+ /* @__PURE__ */ jsx(FilterExprInspector, { expr: facetedExpr })
573
+ ] })
576
574
  ] })
577
- ] })
578
- ] }),
579
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
580
- /* @__PURE__ */ jsx(
581
- SectionHeader,
582
- {
583
- title: "EntityTable with SearchInput",
584
- description: "Faceted search wired to EntityTable. onChange fires only on submit (Enter on empty input) -- table filters when the user presses Enter. Edit the JSON Schema or UI Schema below and press Apply to see column changes live."
585
- }
586
- ),
587
- /* @__PURE__ */ jsx(
588
- SearchInput,
589
- {
590
- value: tableExpr,
591
- onChange: setTableExpr,
592
- schema: SEARCH_FACET_SCHEMA,
593
- mode: "explicit",
594
- placeholder: "Filter users... (press Enter to apply)",
595
- className: "mb-4 max-w-sm"
596
- }
597
- ),
598
- /* @__PURE__ */ jsx(
599
- EntityTable,
600
- {
601
- schema: activeTableSchema,
602
- uiSchema: activeTableUiSchema,
603
- data: tableData,
604
- isLoading: false,
605
- isError: false,
606
- entityLabel: "users",
607
- isFiltered: !isEmptyFilterExpr(tableExpr)
608
- }
609
- ),
610
- /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Card, { className: "border shadow-sm p-4 flex flex-col", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs(
611
- Tabs,
612
- {
613
- value: tableSchemaTab,
614
- onValueChange: setTableSchemaTab,
615
- className: "flex flex-col flex-1",
616
- children: [
617
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
618
- /* @__PURE__ */ jsxs(TabsList, { children: [
619
- /* @__PURE__ */ jsx(TabsTrigger, { value: "schema", children: "JSON Schema" }),
620
- /* @__PURE__ */ jsx(TabsTrigger, { value: "uischema", children: "UI Schema" })
621
- ] }),
622
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
623
- tableSchemaError && /* @__PURE__ */ jsx(Badge, { variant: "destructive", className: "text-xs", children: tableSchemaError }),
624
- /* @__PURE__ */ jsx(SimpleTooltip, { label: "Apply schema to table above", children: /* @__PURE__ */ jsx(
625
- Button,
575
+ }
576
+ ),
577
+ /* @__PURE__ */ jsxs(
578
+ PlaygroundSection,
579
+ {
580
+ title: "EntityTable with SearchInput",
581
+ description: "Faceted search wired to EntityTable. onChange fires only on submit (Enter on empty input) -- table filters when the user presses Enter. Edit the JSON Schema or UI Schema below and press Apply to see column changes live.",
582
+ variant: "card",
583
+ children: [
584
+ /* @__PURE__ */ jsx(
585
+ SearchInput,
586
+ {
587
+ value: tableExpr,
588
+ onChange: setTableExpr,
589
+ schema: SEARCH_FACET_SCHEMA,
590
+ mode: "explicit",
591
+ placeholder: "Filter users... (press Enter to apply)",
592
+ className: "mb-4 max-w-sm"
593
+ }
594
+ ),
595
+ /* @__PURE__ */ jsx(
596
+ EntityTable,
597
+ {
598
+ schema: activeTableSchema,
599
+ uiSchema: activeTableUiSchema,
600
+ data: tableData,
601
+ isLoading: false,
602
+ isError: false,
603
+ entityLabel: "users",
604
+ isFiltered: !isEmptyFilterExpr(tableExpr)
605
+ }
606
+ ),
607
+ /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Card, { className: "border shadow-sm p-4 flex flex-col", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs(
608
+ Tabs,
609
+ {
610
+ value: tableSchemaTab,
611
+ onValueChange: setTableSchemaTab,
612
+ className: "flex flex-col flex-1",
613
+ children: [
614
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
615
+ /* @__PURE__ */ jsxs(TabsList, { children: [
616
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "schema", children: "JSON Schema" }),
617
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "uischema", children: "UI Schema" })
618
+ ] }),
619
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
620
+ tableSchemaError && /* @__PURE__ */ jsx(Badge, { variant: "destructive", className: "text-xs", children: tableSchemaError }),
621
+ /* @__PURE__ */ jsx(SimpleTooltip, { label: "Apply schema to table above", children: /* @__PURE__ */ jsx(
622
+ Button,
623
+ {
624
+ variant: "default",
625
+ size: "icon",
626
+ onClick: handleApplyTableSchema,
627
+ disabled: !!tableSchemaError,
628
+ children: /* @__PURE__ */ jsx(ArrowUp, { size: 18 })
629
+ }
630
+ ) })
631
+ ] })
632
+ ] }),
633
+ /* @__PURE__ */ jsx(TabsContent, { value: "schema", className: "mt-2", children: /* @__PURE__ */ jsx(
634
+ JsonEditor,
635
+ {
636
+ value: tableSchemaText,
637
+ editablePaths: ["/"],
638
+ onChange: handleTableSchemaTextChange,
639
+ height: "280px",
640
+ className: "rounded-md border overflow-hidden"
641
+ }
642
+ ) }),
643
+ /* @__PURE__ */ jsx(TabsContent, { value: "uischema", className: "mt-2", children: /* @__PURE__ */ jsx(
644
+ JsonEditor,
626
645
  {
627
- variant: "default",
628
- size: "icon",
629
- onClick: handleApplyTableSchema,
630
- disabled: !!tableSchemaError,
631
- children: /* @__PURE__ */ jsx(ArrowUp, { size: 18 })
646
+ value: tableUiSchemaText,
647
+ editablePaths: ["/"],
648
+ onChange: handleTableUiSchemaTextChange,
649
+ height: "280px",
650
+ className: "rounded-md border overflow-hidden"
632
651
  }
633
652
  ) })
634
- ] })
635
- ] }),
636
- /* @__PURE__ */ jsx(TabsContent, { value: "schema", className: "mt-2", children: /* @__PURE__ */ jsx(
637
- JsonEditor,
638
- {
639
- value: tableSchemaText,
640
- editablePaths: ["/"],
641
- onChange: handleTableSchemaTextChange,
642
- height: "280px",
643
- className: "rounded-md border overflow-hidden"
644
- }
645
- ) }),
646
- /* @__PURE__ */ jsx(TabsContent, { value: "uischema", className: "mt-2", children: /* @__PURE__ */ jsx(
647
- JsonEditor,
648
- {
649
- value: tableUiSchemaText,
650
- editablePaths: ["/"],
651
- onChange: handleTableUiSchemaTextChange,
652
- height: "280px",
653
- className: "rounded-md border overflow-hidden"
654
- }
655
- ) })
656
- ]
657
- }
658
- ) }) }) })
659
- ] }),
660
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
661
- /* @__PURE__ */ jsx(
662
- SectionHeader,
663
- {
664
- title: "EntityTable with Local Renderers",
665
- description: "Same sample data rendered with x- prefixed local renderers passed via the renderers prop. The schema is pure data -- renderer functions live in code and are resolved by name. Three custom renderers: x-play-initials (avatar from name), x-play-role-icon (letter prefix from options), x-play-tenure (computed days with threshold)."
666
- }
667
- ),
668
- /* @__PURE__ */ jsx(
669
- EntityTable,
670
- {
671
- schema: CUSTOM_RENDERER_SCHEMA,
672
- renderers: CUSTOM_RENDERERS,
673
- data: {
674
- data: ALL_ROWS,
675
- meta: {
676
- total: ALL_ROWS.length,
677
- limit: ALL_ROWS.length,
678
- offset: 0,
679
- has_next: false,
680
- has_prev: false
653
+ ]
681
654
  }
682
- },
683
- isLoading: false,
684
- isError: false,
685
- entityLabel: "users"
686
- }
687
- )
688
- ] }),
689
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
690
- /* @__PURE__ */ jsx(
691
- SectionHeader,
692
- {
693
- title: "EntitySelect",
694
- description: "Searchable single-select backed by a static mock patient fetcher. Search text is filtered client-side. Available as a form widget via x-ui-widget: 'entity-select'."
695
- }
696
- ),
697
- /* @__PURE__ */ jsxs("div", { className: "flex gap-6 items-start", children: [
698
- /* @__PURE__ */ jsx(
699
- EntitySelect,
655
+ ) }) }) })
656
+ ]
657
+ }
658
+ ),
659
+ /* @__PURE__ */ jsx(
660
+ PlaygroundSection,
661
+ {
662
+ title: "EntityTable with Local Renderers",
663
+ description: "Same sample data rendered with x- prefixed local renderers passed via the renderers prop. The schema is pure data -- renderer functions live in code and are resolved by name. Three custom renderers: x-play-initials (avatar from name), x-play-role-icon (letter prefix from options), x-play-tenure (computed days with threshold).",
664
+ variant: "card",
665
+ children: /* @__PURE__ */ jsx(
666
+ EntityTable,
700
667
  {
701
- fetcher: patientFetcher,
702
- queryKey: "playground-patients",
703
- value: selectedPatient,
704
- onChange: setSelectedPatient,
705
- label: "Patient",
706
- placeholder: "Select patient...",
707
- searchPlaceholder: "Search patients...",
708
- className: "max-w-xs"
668
+ schema: CUSTOM_RENDERER_SCHEMA,
669
+ renderers: CUSTOM_RENDERERS,
670
+ data: {
671
+ data: ALL_ROWS,
672
+ meta: {
673
+ total: ALL_ROWS.length,
674
+ limit: ALL_ROWS.length,
675
+ offset: 0,
676
+ has_next: false,
677
+ has_prev: false
678
+ }
679
+ },
680
+ isLoading: false,
681
+ isError: false,
682
+ entityLabel: "users"
709
683
  }
710
- ),
711
- /* @__PURE__ */ jsxs(Card, { className: "flex-1 min-w-0 p-3", children: [
712
- /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: "Selected value" }),
713
- /* @__PURE__ */ jsx("pre", { className: "rounded-md bg-muted px-4 py-3 text-xs overflow-auto", children: JSON.stringify(selectedPatient, null, 2) })
684
+ )
685
+ }
686
+ ),
687
+ /* @__PURE__ */ jsx(
688
+ PlaygroundSection,
689
+ {
690
+ title: "EntitySelect",
691
+ description: "Searchable single-select backed by a static mock patient fetcher. Search text is filtered client-side. Available as a form widget via x-ui-widget: 'entity-select'.",
692
+ variant: "card",
693
+ children: /* @__PURE__ */ jsxs("div", { className: "flex gap-6 items-start", children: [
694
+ /* @__PURE__ */ jsx(
695
+ EntitySelect,
696
+ {
697
+ fetcher: patientFetcher,
698
+ queryKey: "playground-patients",
699
+ value: selectedPatient,
700
+ onChange: setSelectedPatient,
701
+ label: "Patient",
702
+ placeholder: "Select patient...",
703
+ searchPlaceholder: "Search patients...",
704
+ className: "max-w-xs"
705
+ }
706
+ ),
707
+ /* @__PURE__ */ jsxs(Card, { className: "flex-1 min-w-0 p-3", children: [
708
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: "Selected value" }),
709
+ /* @__PURE__ */ jsx("pre", { className: "rounded-md bg-muted px-4 py-3 text-xs overflow-auto", children: JSON.stringify(selectedPatient, null, 2) })
710
+ ] })
714
711
  ] })
715
- ] })
716
- ] }),
717
- /* @__PURE__ */ jsxs("section", { className: "mb-12", children: [
718
- /* @__PURE__ */ jsx(
719
- SectionHeader,
720
- {
721
- title: "EntityTree",
722
- description: "Schema-driven tree component built on TreeView. Columns are resolved from a JSON Schema using the same resolveColumns pipeline as EntityTable. Supports expand/collapse, row selection, loading/error/empty states, and custom cell renderers."
723
- }
724
- ),
725
- /* @__PURE__ */ jsx(EntityTreeDemo, {})
726
- ] })
712
+ }
713
+ ),
714
+ /* @__PURE__ */ jsx(
715
+ PlaygroundSection,
716
+ {
717
+ title: "EntityTree",
718
+ description: "Schema-driven tree component built on TreeView. Columns are resolved from a JSON Schema using the same resolveColumns pipeline as EntityTable. Supports expand/collapse, row selection, loading/error/empty states, and custom cell renderers.",
719
+ variant: "card",
720
+ children: /* @__PURE__ */ jsx(EntityTreeDemo, {})
721
+ }
722
+ )
727
723
  ] });
728
724
  }
729
725
  var OrgSchema = z.object({
@@ -786,24 +782,22 @@ var ORG_NODES = [
786
782
  }
787
783
  ];
788
784
  function EntityTreeDemo() {
789
- const [expandedIds, setExpandedIds] = useState(/* @__PURE__ */ new Set());
785
+ const {
786
+ expandedIds: treeExpandedIds,
787
+ onExpand: onTreeExpand,
788
+ onCollapse: onTreeCollapse
789
+ } = useTreeExpansion();
790
790
  const [selectedIds, setSelectedIds] = useState(/* @__PURE__ */ new Set());
791
791
  const [activeId, setActiveId] = useState(null);
792
- const handleExpand = (id) => setExpandedIds((prev) => /* @__PURE__ */ new Set([...prev, id]));
793
- const handleCollapse = (id) => setExpandedIds((prev) => {
794
- const next = new Set(prev);
795
- next.delete(id);
796
- return next;
797
- });
798
792
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
799
793
  /* @__PURE__ */ jsx(
800
794
  EntityTree,
801
795
  {
802
796
  schema: ORG_TREE_SCHEMA,
803
797
  nodes: ORG_NODES,
804
- expandedIds,
805
- onExpand: handleExpand,
806
- onCollapse: handleCollapse,
798
+ expandedIds: treeExpandedIds,
799
+ onExpand: onTreeExpand,
800
+ onCollapse: onTreeCollapse,
807
801
  onNodeSelect: (node) => setActiveId(node.id),
808
802
  onNodeEdit: (node) => setActiveId(node.id),
809
803
  activeNodeId: activeId ?? void 0,
@@ -834,4 +828,4 @@ function EntityTreeDemo() {
834
828
  export {
835
829
  PlayDataComponents
836
830
  };
837
- //# sourceMappingURL=chunk-TZGJH7YS.js.map
831
+ //# sourceMappingURL=chunk-YEBK2TUW.js.map