@petrarca/sonnet-playground 0.7.0 → 0.9.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.
- package/README.md +10 -8
- package/dist/{PlayAdvancedComponents-ZYK66UII.js → PlayAdvancedComponents-VMUI472R.js} +2 -2
- package/dist/PlayCodeEditor-AMTFE5SW.js +8 -0
- package/dist/PlayCodedValues-G2EVIVMO.js +9 -0
- package/dist/{PlayCoreComponents-YTEAS3GL.js → PlayCoreComponents-EQ2BMY2S.js} +2 -2
- package/dist/{PlayDataComponents-W44OITT5.js → PlayDataComponents-W2KQHOI7.js} +2 -2
- package/dist/PlayFhirQuestionnaire-TO35Q7CP.js +8 -0
- package/dist/{PlayFormWidgets-6JYFRTAL.js → PlayFormWidgets-HP3VF2LK.js} +2 -2
- package/dist/PlayForms-4CQNEBLS.js +7 -0
- package/dist/PlayGraph-25ZKQAQR.js +7 -0
- package/dist/PlayGraph-25ZKQAQR.js.map +1 -0
- package/dist/PlayMarkdownViewer-X6AIFO2U.js +8 -0
- package/dist/PlayMarkdownViewer-X6AIFO2U.js.map +1 -0
- package/dist/PlayQuestionnaireDesigner-IR7TKSOT.js +9 -0
- package/dist/PlayQuestionnaireDesigner-IR7TKSOT.js.map +1 -0
- package/dist/PlaySchemaDesigner-ZQBA7AYO.js +8 -0
- package/dist/PlaySchemaDesigner-ZQBA7AYO.js.map +1 -0
- package/dist/{PlayShellApi-5O6VYR2X.js → PlayShellApi-MMCQ2AKK.js} +2 -2
- package/dist/PlayShellApi-MMCQ2AKK.js.map +1 -0
- package/dist/chunk-3FYM6B3E.js +1163 -0
- package/dist/chunk-3FYM6B3E.js.map +1 -0
- package/dist/{chunk-CQ6PGFRV.js → chunk-3RZHYZRL.js} +57 -1
- package/dist/chunk-3RZHYZRL.js.map +1 -0
- package/dist/chunk-7IMCPUSI.js +100 -0
- package/dist/chunk-7IMCPUSI.js.map +1 -0
- package/dist/{chunk-2XMWOZ5O.js → chunk-EPCUUTBZ.js} +48 -41
- package/dist/chunk-EPCUUTBZ.js.map +1 -0
- package/dist/{chunk-I2FLG6ZD.js → chunk-LDCNLHO2.js} +195 -18
- package/dist/chunk-LDCNLHO2.js.map +1 -0
- package/dist/chunk-LVV32F7G.js +104 -0
- package/dist/chunk-LVV32F7G.js.map +1 -0
- package/dist/chunk-OUL3DN2E.js +510 -0
- package/dist/chunk-OUL3DN2E.js.map +1 -0
- package/dist/chunk-QKFQI4VX.js +83 -0
- package/dist/chunk-QKFQI4VX.js.map +1 -0
- package/dist/{chunk-6WI3N7JI.js → chunk-RGBSHXS5.js} +145 -4
- package/dist/chunk-RGBSHXS5.js.map +1 -0
- package/dist/{chunk-UB7462QG.js → chunk-RLJI5VMP.js} +72 -1
- package/dist/chunk-RLJI5VMP.js.map +1 -0
- package/dist/chunk-VGAS5Z6X.js +543 -0
- package/dist/chunk-VGAS5Z6X.js.map +1 -0
- package/dist/chunk-VKZ2RJFL.js +647 -0
- package/dist/chunk-VKZ2RJFL.js.map +1 -0
- package/dist/chunk-WR74TMW4.js +219 -0
- package/dist/chunk-WR74TMW4.js.map +1 -0
- package/dist/{chunk-E5X7GVLU.js → chunk-XNDD4UN4.js} +2 -2
- package/dist/chunk-XNDD4UN4.js.map +1 -0
- package/dist/chunk-YTGQRDD2.js +343 -0
- package/dist/chunk-YTGQRDD2.js.map +1 -0
- package/dist/index.d.ts +13 -10
- package/dist/index.js +72 -11
- package/dist/index.js.map +1 -1
- package/dist/pages/index.d.ts +56 -20
- package/dist/pages/index.js +39 -17
- package/package.json +15 -14
- package/dist/PlayForms-L532W3JL.js +0 -7
- package/dist/PlayGraph-M4KQSFI7.js +0 -7
- package/dist/PlaySchemaDesigner-S4DBB53G.js +0 -7
- package/dist/chunk-2XMWOZ5O.js.map +0 -1
- package/dist/chunk-4Y4JFKAK.js +0 -240
- package/dist/chunk-4Y4JFKAK.js.map +0 -1
- package/dist/chunk-6WI3N7JI.js.map +0 -1
- package/dist/chunk-CQ6PGFRV.js.map +0 -1
- package/dist/chunk-E5X7GVLU.js.map +0 -1
- package/dist/chunk-I2FLG6ZD.js.map +0 -1
- package/dist/chunk-O2QMWJZI.js +0 -881
- package/dist/chunk-O2QMWJZI.js.map +0 -1
- package/dist/chunk-UB7462QG.js.map +0 -1
- /package/dist/{PlayAdvancedComponents-ZYK66UII.js.map → PlayAdvancedComponents-VMUI472R.js.map} +0 -0
- /package/dist/{PlayCoreComponents-YTEAS3GL.js.map → PlayCodeEditor-AMTFE5SW.js.map} +0 -0
- /package/dist/{PlayDataComponents-W44OITT5.js.map → PlayCodedValues-G2EVIVMO.js.map} +0 -0
- /package/dist/{PlayFormWidgets-6JYFRTAL.js.map → PlayCoreComponents-EQ2BMY2S.js.map} +0 -0
- /package/dist/{PlayForms-L532W3JL.js.map → PlayDataComponents-W2KQHOI7.js.map} +0 -0
- /package/dist/{PlayGraph-M4KQSFI7.js.map → PlayFhirQuestionnaire-TO35Q7CP.js.map} +0 -0
- /package/dist/{PlaySchemaDesigner-S4DBB53G.js.map → PlayFormWidgets-HP3VF2LK.js.map} +0 -0
- /package/dist/{PlayShellApi-5O6VYR2X.js.map → PlayForms-4CQNEBLS.js.map} +0 -0
|
@@ -0,0 +1,1163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PlaygroundSection
|
|
3
|
+
} from "./chunk-C2EZ2ECG.js";
|
|
4
|
+
|
|
5
|
+
// src/pages/PlayDataComponents.tsx
|
|
6
|
+
import React2, { useState as useState2, useMemo as useMemo2, useCallback as useCallback2 } from "react";
|
|
7
|
+
import { ArrowRight, ArrowUp } from "lucide-react";
|
|
8
|
+
import {
|
|
9
|
+
Badge,
|
|
10
|
+
Button,
|
|
11
|
+
Card,
|
|
12
|
+
SimpleTooltip,
|
|
13
|
+
Tabs,
|
|
14
|
+
TabsContent,
|
|
15
|
+
TabsList,
|
|
16
|
+
TabsTrigger,
|
|
17
|
+
SearchInput,
|
|
18
|
+
EntitySelect,
|
|
19
|
+
EntityTable as EntityTable2,
|
|
20
|
+
createRenderer,
|
|
21
|
+
EntityTree,
|
|
22
|
+
PropertyList
|
|
23
|
+
} from "@petrarca/sonnet-ui";
|
|
24
|
+
import { FormTextarea } from "@petrarca/sonnet-forms";
|
|
25
|
+
import { JsonEditor } from "@petrarca/sonnet-ui/json-editor";
|
|
26
|
+
|
|
27
|
+
// src/pages/EntityTableLongListDemo.tsx
|
|
28
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
29
|
+
import {
|
|
30
|
+
EntityTable
|
|
31
|
+
} from "@petrarca/sonnet-ui";
|
|
32
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
33
|
+
var TOTAL = 5e3;
|
|
34
|
+
var PAGE_SIZE = 100;
|
|
35
|
+
var DELAY_MS = 300;
|
|
36
|
+
var ROWS = Array.from({ length: TOTAL }, (_, i) => ({
|
|
37
|
+
id: `f-${i}`,
|
|
38
|
+
name: `file-${String(i).padStart(4, "0")}.ts`,
|
|
39
|
+
folder: `src/module-${i % 37}/part-${i % 7}`,
|
|
40
|
+
size: i * 7919 % 400
|
|
41
|
+
}));
|
|
42
|
+
var SCHEMA = {
|
|
43
|
+
title: "File",
|
|
44
|
+
type: "object",
|
|
45
|
+
properties: {
|
|
46
|
+
name: { type: "string", title: "Name", "x-ui-cell": "code" },
|
|
47
|
+
size: { type: "number", title: "Chunks" },
|
|
48
|
+
folder: { type: "string", title: "Folder", "x-ui-cell": "muted" }
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var PAGINGS = ["pages", "load more", "on scroll"];
|
|
52
|
+
var page = (rows) => ({
|
|
53
|
+
data: rows,
|
|
54
|
+
meta: {
|
|
55
|
+
total: TOTAL,
|
|
56
|
+
limit: rows.length,
|
|
57
|
+
offset: 0,
|
|
58
|
+
has_next: rows.length < TOTAL,
|
|
59
|
+
has_prev: false
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
function useProgressiveRows(paging) {
|
|
63
|
+
const [loaded, setLoaded] = useState(PAGE_SIZE);
|
|
64
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
65
|
+
useEffect(() => setLoaded(PAGE_SIZE), [paging]);
|
|
66
|
+
const onLoadMore = useCallback(() => {
|
|
67
|
+
setIsLoading(true);
|
|
68
|
+
window.setTimeout(() => {
|
|
69
|
+
setLoaded((n) => Math.min(n + PAGE_SIZE, TOTAL));
|
|
70
|
+
setIsLoading(false);
|
|
71
|
+
}, DELAY_MS);
|
|
72
|
+
}, []);
|
|
73
|
+
return {
|
|
74
|
+
rows: ROWS.slice(0, loaded),
|
|
75
|
+
loadMore: {
|
|
76
|
+
hasMore: loaded < TOTAL,
|
|
77
|
+
isLoading,
|
|
78
|
+
onLoadMore,
|
|
79
|
+
auto: paging === "on scroll"
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function Toggle({
|
|
84
|
+
label,
|
|
85
|
+
options,
|
|
86
|
+
value,
|
|
87
|
+
onChange
|
|
88
|
+
}) {
|
|
89
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", role: "group", "aria-label": label, children: [
|
|
90
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
91
|
+
label,
|
|
92
|
+
":"
|
|
93
|
+
] }),
|
|
94
|
+
options.map((option) => /* @__PURE__ */ jsx(
|
|
95
|
+
"button",
|
|
96
|
+
{
|
|
97
|
+
type: "button",
|
|
98
|
+
"aria-pressed": option === value,
|
|
99
|
+
onClick: () => onChange(option),
|
|
100
|
+
className: option === value ? "rounded-full bg-primary px-3 py-1 text-xs font-medium text-primary-foreground" : "rounded-full bg-muted px-3 py-1 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
101
|
+
children: option
|
|
102
|
+
},
|
|
103
|
+
option
|
|
104
|
+
))
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
function EntityTableLongListDemo() {
|
|
108
|
+
const [paging, setPaging] = useState("on scroll");
|
|
109
|
+
const [virtual, setVirtual] = useState("on");
|
|
110
|
+
const [pagination, setPagination] = useState({
|
|
111
|
+
pageIndex: 0,
|
|
112
|
+
pageSize: PAGE_SIZE
|
|
113
|
+
});
|
|
114
|
+
const progressive = useProgressiveRows(paging);
|
|
115
|
+
const paged = useMemo(() => {
|
|
116
|
+
const from = pagination.pageIndex * pagination.pageSize;
|
|
117
|
+
return ROWS.slice(from, from + pagination.pageSize);
|
|
118
|
+
}, [pagination]);
|
|
119
|
+
const byPages = paging === "pages";
|
|
120
|
+
return /* @__PURE__ */ jsxs(
|
|
121
|
+
PlaygroundSection,
|
|
122
|
+
{
|
|
123
|
+
title: "EntityTable on a long list",
|
|
124
|
+
description: "5,000 rows in a fill box (compact). Pages: the page controls. Load more: a footer button adds the next 100 rows. On scroll: the next rows load as the end comes into view (no button needed). Virtual rows: only the rows in view are rendered -- open the DOM inspector and scroll.",
|
|
125
|
+
variant: "card",
|
|
126
|
+
children: [
|
|
127
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-wrap gap-6", children: [
|
|
128
|
+
/* @__PURE__ */ jsx(
|
|
129
|
+
Toggle,
|
|
130
|
+
{
|
|
131
|
+
label: "Rows",
|
|
132
|
+
options: PAGINGS,
|
|
133
|
+
value: paging,
|
|
134
|
+
onChange: setPaging
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
/* @__PURE__ */ jsx(
|
|
138
|
+
Toggle,
|
|
139
|
+
{
|
|
140
|
+
label: "Virtual rows",
|
|
141
|
+
options: ["off", "on"],
|
|
142
|
+
value: virtual,
|
|
143
|
+
onChange: setVirtual
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
] }),
|
|
147
|
+
/* @__PURE__ */ jsx("div", { className: "h-80", children: /* @__PURE__ */ jsx(
|
|
148
|
+
EntityTable,
|
|
149
|
+
{
|
|
150
|
+
schema: SCHEMA,
|
|
151
|
+
data: page(byPages ? paged : progressive.rows),
|
|
152
|
+
isLoading: false,
|
|
153
|
+
isError: false,
|
|
154
|
+
entityLabel: "files",
|
|
155
|
+
density: "compact",
|
|
156
|
+
fill: true,
|
|
157
|
+
virtualize: virtual === "on",
|
|
158
|
+
getRowId: (row) => row.id,
|
|
159
|
+
...byPages ? { pagination, onPaginationChange: setPagination } : { loadMore: progressive.loadMore }
|
|
160
|
+
}
|
|
161
|
+
) })
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/pages/PlayDataComponents.tsx
|
|
168
|
+
import {
|
|
169
|
+
EMPTY_FILTER,
|
|
170
|
+
flattenFilterExpr,
|
|
171
|
+
isEmptyFilterExpr,
|
|
172
|
+
serializeFilterExpr
|
|
173
|
+
} from "@petrarca/sonnet-core/search";
|
|
174
|
+
import { toJsonSchema } from "@petrarca/sonnet-core/schema";
|
|
175
|
+
import { useTreeExpansion } from "@petrarca/sonnet-core/hooks";
|
|
176
|
+
import { z } from "zod/v4";
|
|
177
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
178
|
+
var MOCK_PATIENTS = [
|
|
179
|
+
{ value: "pat_001", label: "Alice Hartmann" },
|
|
180
|
+
{ value: "pat_002", label: "Bob Nguyen" },
|
|
181
|
+
{ value: "pat_003", label: "Carol Smith" },
|
|
182
|
+
{ value: "pat_004", label: "David Okafor" },
|
|
183
|
+
{ value: "pat_005", label: "Eva Larsson" },
|
|
184
|
+
{ value: "pat_006", label: "Frank Torres" },
|
|
185
|
+
{ value: "pat_007", label: "Grace Kim" },
|
|
186
|
+
{ value: "pat_008", label: "Henry Bauer" }
|
|
187
|
+
];
|
|
188
|
+
var patientFetcher = ({ search } = {}) => {
|
|
189
|
+
const q = search?.toLowerCase() ?? "";
|
|
190
|
+
const results = q ? MOCK_PATIENTS.filter((p) => p.label.toLowerCase().includes(q)) : MOCK_PATIENTS;
|
|
191
|
+
return Promise.resolve(results);
|
|
192
|
+
};
|
|
193
|
+
var ALL_ROWS = [
|
|
194
|
+
{
|
|
195
|
+
id: "u-001",
|
|
196
|
+
name: "Alice Hartmann",
|
|
197
|
+
status: "active",
|
|
198
|
+
role: "admin",
|
|
199
|
+
joined: "2024-01-15"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "u-002",
|
|
203
|
+
name: "Bob Nguyen",
|
|
204
|
+
status: "active",
|
|
205
|
+
role: "editor",
|
|
206
|
+
joined: "2024-02-03"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: "u-003",
|
|
210
|
+
name: "Carol Smith",
|
|
211
|
+
status: "inactive",
|
|
212
|
+
role: "viewer",
|
|
213
|
+
joined: "2024-03-20"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: "u-004",
|
|
217
|
+
name: "David Okafor",
|
|
218
|
+
status: "pending",
|
|
219
|
+
role: "editor",
|
|
220
|
+
joined: "2024-04-11"
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
id: "u-005",
|
|
224
|
+
name: "Eva Larsson",
|
|
225
|
+
status: "active",
|
|
226
|
+
role: "admin",
|
|
227
|
+
joined: "2024-05-08"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
id: "u-006",
|
|
231
|
+
name: "Frank Torres",
|
|
232
|
+
status: "inactive",
|
|
233
|
+
role: "viewer",
|
|
234
|
+
joined: "2024-06-22"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
id: "u-007",
|
|
238
|
+
name: "Grace Kim",
|
|
239
|
+
status: "active",
|
|
240
|
+
role: "editor",
|
|
241
|
+
joined: "2024-07-14"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: "u-008",
|
|
245
|
+
name: "Henry Bauer",
|
|
246
|
+
status: "pending",
|
|
247
|
+
role: "viewer",
|
|
248
|
+
joined: "2024-08-30"
|
|
249
|
+
}
|
|
250
|
+
];
|
|
251
|
+
var STATUS_COLOR = {
|
|
252
|
+
active: "green",
|
|
253
|
+
inactive: "violet",
|
|
254
|
+
pending: "yellow"
|
|
255
|
+
};
|
|
256
|
+
var PlaygroundFacets = z.object({
|
|
257
|
+
search: z.string().meta({ "x-ui-title": "Name" }),
|
|
258
|
+
status: z.enum(["active", "inactive", "pending"]).optional().meta({
|
|
259
|
+
"x-ui-title": "Status",
|
|
260
|
+
"x-ui-options": {
|
|
261
|
+
enumNames: {
|
|
262
|
+
active: "Active",
|
|
263
|
+
inactive: "Inactive",
|
|
264
|
+
pending: "Pending"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}),
|
|
268
|
+
// An array facet is repeatable: one chip per role, matching any of them.
|
|
269
|
+
roles: z.array(z.enum(["admin", "editor", "viewer"])).optional().meta({ "x-ui-title": "Role" }),
|
|
270
|
+
joined_from: z.string().optional().meta({
|
|
271
|
+
"x-ui-title": "Joined from",
|
|
272
|
+
"x-ui-widget": "date"
|
|
273
|
+
})
|
|
274
|
+
});
|
|
275
|
+
var SEARCH_FACET_SCHEMA = toJsonSchema(PlaygroundFacets);
|
|
276
|
+
var SAMPLE_SCHEMA = {
|
|
277
|
+
title: "User",
|
|
278
|
+
type: "object",
|
|
279
|
+
properties: {
|
|
280
|
+
name: {
|
|
281
|
+
type: "string",
|
|
282
|
+
title: "Name",
|
|
283
|
+
"x-ui-column": { order: 0, sortable: true },
|
|
284
|
+
"x-ui-cell": "bold"
|
|
285
|
+
},
|
|
286
|
+
status: {
|
|
287
|
+
type: "string",
|
|
288
|
+
title: "Status",
|
|
289
|
+
"x-ui-column": { order: 1 },
|
|
290
|
+
"x-ui-cell": "badge",
|
|
291
|
+
"x-ui-cell-options": { colors: STATUS_COLOR }
|
|
292
|
+
},
|
|
293
|
+
role: {
|
|
294
|
+
type: "string",
|
|
295
|
+
title: "Role",
|
|
296
|
+
"x-ui-column": { order: 2 },
|
|
297
|
+
"x-ui-cell": "muted"
|
|
298
|
+
},
|
|
299
|
+
id: {
|
|
300
|
+
type: "string",
|
|
301
|
+
title: "ID",
|
|
302
|
+
"x-ui-column": { order: 3 },
|
|
303
|
+
"x-ui-cell": "code"
|
|
304
|
+
},
|
|
305
|
+
joined: {
|
|
306
|
+
type: "string",
|
|
307
|
+
format: "date",
|
|
308
|
+
title: "Joined",
|
|
309
|
+
"x-ui-column": { order: 4, sortable: true }
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
var SAMPLE_UI_SCHEMA = {};
|
|
314
|
+
var ROLE_ICONS = {
|
|
315
|
+
admin: "A",
|
|
316
|
+
editor: "E",
|
|
317
|
+
viewer: "V"
|
|
318
|
+
};
|
|
319
|
+
var CUSTOM_RENDERERS = {
|
|
320
|
+
// Extract initials from the name, display as avatar circle + name.
|
|
321
|
+
"x-play-initials": createRenderer((row) => {
|
|
322
|
+
const initials = row.name.split(" ").map((w) => w[0]).join("");
|
|
323
|
+
return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
|
|
324
|
+
/* @__PURE__ */ jsx2("span", { className: "inline-flex items-center justify-center h-7 w-7 rounded-full bg-muted text-xs font-medium shrink-0", children: initials }),
|
|
325
|
+
/* @__PURE__ */ jsx2("span", { className: "font-medium", children: row.name })
|
|
326
|
+
] });
|
|
327
|
+
}),
|
|
328
|
+
// Role with a letter prefix read from options.icons.
|
|
329
|
+
"x-play-role-icon": createRenderer((row, options) => {
|
|
330
|
+
const icons = options.icons ?? {};
|
|
331
|
+
const icon = icons[row.role] ?? "?";
|
|
332
|
+
return /* @__PURE__ */ jsxs2("span", { children: [
|
|
333
|
+
/* @__PURE__ */ jsx2("span", { className: "inline-flex items-center justify-center h-5 w-5 rounded bg-muted text-xs font-mono mr-1.5", children: icon }),
|
|
334
|
+
row.role
|
|
335
|
+
] });
|
|
336
|
+
}),
|
|
337
|
+
// Compute days since joined, color-coded by threshold from options.
|
|
338
|
+
"x-play-tenure": createRenderer((row, options) => {
|
|
339
|
+
const threshold = options.recentDays ?? 365;
|
|
340
|
+
const days = Math.floor(
|
|
341
|
+
(Date.now() - new Date(row.joined).getTime()) / 864e5
|
|
342
|
+
);
|
|
343
|
+
const isRecent = days < threshold;
|
|
344
|
+
return /* @__PURE__ */ jsxs2("span", { className: isRecent ? "text-primary" : "text-muted-foreground", children: [
|
|
345
|
+
days,
|
|
346
|
+
"d"
|
|
347
|
+
] });
|
|
348
|
+
})
|
|
349
|
+
};
|
|
350
|
+
var CUSTOM_RENDERER_SCHEMA = {
|
|
351
|
+
title: "User (custom renderers)",
|
|
352
|
+
type: "object",
|
|
353
|
+
properties: {
|
|
354
|
+
name: {
|
|
355
|
+
type: "string",
|
|
356
|
+
title: "Name",
|
|
357
|
+
"x-ui-column": { order: 0 },
|
|
358
|
+
"x-ui-cell": "x-play-initials"
|
|
359
|
+
},
|
|
360
|
+
role: {
|
|
361
|
+
type: "string",
|
|
362
|
+
title: "Role",
|
|
363
|
+
"x-ui-column": { order: 1 },
|
|
364
|
+
"x-ui-cell": "x-play-role-icon",
|
|
365
|
+
"x-ui-cell-options": { icons: ROLE_ICONS }
|
|
366
|
+
},
|
|
367
|
+
status: {
|
|
368
|
+
type: "string",
|
|
369
|
+
title: "Status",
|
|
370
|
+
"x-ui-column": { order: 2 },
|
|
371
|
+
"x-ui-cell": "badge",
|
|
372
|
+
"x-ui-cell-options": { colors: STATUS_COLOR }
|
|
373
|
+
},
|
|
374
|
+
joined: {
|
|
375
|
+
type: "string",
|
|
376
|
+
title: "Tenure",
|
|
377
|
+
"x-ui-column": { order: 3 },
|
|
378
|
+
"x-ui-cell": "x-play-tenure",
|
|
379
|
+
"x-ui-cell-options": { recentDays: 500 }
|
|
380
|
+
},
|
|
381
|
+
id: {
|
|
382
|
+
type: "string",
|
|
383
|
+
title: "ID",
|
|
384
|
+
"x-ui-column": { order: 4 },
|
|
385
|
+
"x-ui-cell": "code"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
var SUBMIT_COUNT_RESET = -1;
|
|
390
|
+
var SEARCH_FIELD_PRESETS = [
|
|
391
|
+
{ label: "name, role", fields: ["name", "role"] },
|
|
392
|
+
{ label: "name (single)", fields: ["name"] },
|
|
393
|
+
{ label: "name, role, status", fields: ["name", "role", "status"] }
|
|
394
|
+
];
|
|
395
|
+
function ToggleStrip({
|
|
396
|
+
label,
|
|
397
|
+
options,
|
|
398
|
+
value,
|
|
399
|
+
onChange,
|
|
400
|
+
format,
|
|
401
|
+
containerClassName
|
|
402
|
+
}) {
|
|
403
|
+
const fmt = format ?? String;
|
|
404
|
+
return /* @__PURE__ */ jsxs2("div", { className: `flex items-center gap-3 ${containerClassName ?? ""}`, children: [
|
|
405
|
+
/* @__PURE__ */ jsxs2("span", { className: "text-xs text-muted-foreground", children: [
|
|
406
|
+
label,
|
|
407
|
+
":"
|
|
408
|
+
] }),
|
|
409
|
+
options.map((opt) => /* @__PURE__ */ jsx2(
|
|
410
|
+
"button",
|
|
411
|
+
{
|
|
412
|
+
type: "button",
|
|
413
|
+
onClick: () => onChange(opt),
|
|
414
|
+
className: [
|
|
415
|
+
"px-3 py-1 rounded-full text-xs font-medium transition-colors",
|
|
416
|
+
value === opt ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"
|
|
417
|
+
].join(" "),
|
|
418
|
+
children: fmt(opt)
|
|
419
|
+
},
|
|
420
|
+
String(opt)
|
|
421
|
+
))
|
|
422
|
+
] });
|
|
423
|
+
}
|
|
424
|
+
var DENSITY_OPTIONS = [
|
|
425
|
+
"default",
|
|
426
|
+
"compact"
|
|
427
|
+
];
|
|
428
|
+
var LAYOUT_OPTIONS = ["flow", "fill"];
|
|
429
|
+
var MODE_OPTIONS = ["explicit", "debounce"];
|
|
430
|
+
var MODE_LABELS = {
|
|
431
|
+
explicit: "Explicit (Enter)",
|
|
432
|
+
debounce: "Debounce (300 ms)"
|
|
433
|
+
};
|
|
434
|
+
var MIN_CHARS_OPTIONS = [0, 1, 2, 3];
|
|
435
|
+
var FIELD_PRESET_INDICES = SEARCH_FIELD_PRESETS.map(
|
|
436
|
+
(_, i) => i
|
|
437
|
+
);
|
|
438
|
+
function FilterExprInspector({ expr }) {
|
|
439
|
+
return /* @__PURE__ */ jsx2("pre", { className: "mt-3 rounded-md bg-muted px-4 py-3 text-xs overflow-auto max-h-40", children: JSON.stringify(expr, null, 2) });
|
|
440
|
+
}
|
|
441
|
+
function FlatTermsInspector({ expr }) {
|
|
442
|
+
const terms = flattenFilterExpr(expr);
|
|
443
|
+
return /* @__PURE__ */ jsx2("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) });
|
|
444
|
+
}
|
|
445
|
+
var FREE_TEXT_FACETS = toJsonSchema(
|
|
446
|
+
z.object({
|
|
447
|
+
source: z.enum(["billing-api", "billing-web", "handbook"]).optional().meta({ "x-ui-title": "Source" }),
|
|
448
|
+
tags: z.array(z.string()).optional().meta({ "x-ui-title": "Tag" }),
|
|
449
|
+
ranking: z.enum(["rerank", "none"]).optional().meta({
|
|
450
|
+
"x-ui-title": "Ranking",
|
|
451
|
+
"x-ui-options": { enumNames: { rerank: "Rerank", none: "No rerank" } }
|
|
452
|
+
})
|
|
453
|
+
})
|
|
454
|
+
);
|
|
455
|
+
function PlayDataComponents() {
|
|
456
|
+
const [simpleExpr, setSimpleExpr] = useState2(EMPTY_FILTER);
|
|
457
|
+
const [simpleMode, setSimpleMode] = useState2("explicit");
|
|
458
|
+
const [simpleMinChars, setSimpleMinChars] = useState2(0);
|
|
459
|
+
const [fieldsExpr, setFieldsExpr] = useState2(EMPTY_FILTER);
|
|
460
|
+
const [fieldsMode, setFieldsMode] = useState2("explicit");
|
|
461
|
+
const [fieldsMinChars, setFieldsMinChars] = useState2(0);
|
|
462
|
+
const [fieldsPresetIdx, setFieldsPresetIdx] = useState2(0);
|
|
463
|
+
const activeSearchFields = SEARCH_FIELD_PRESETS[fieldsPresetIdx].fields;
|
|
464
|
+
const [freeTextExpr, setFreeTextExpr] = useState2(EMPTY_FILTER);
|
|
465
|
+
const [freeTextMode, setFreeTextMode] = useState2("explicit");
|
|
466
|
+
const [facetedExpr, setFacetedExpr] = useState2(EMPTY_FILTER);
|
|
467
|
+
const [facetedSubmitCount, setFacetedSubmitCount] = useState2(0);
|
|
468
|
+
const handleFacetedChange = useCallback2((expr) => {
|
|
469
|
+
setFacetedExpr(expr);
|
|
470
|
+
setFacetedSubmitCount((n) => n + 1);
|
|
471
|
+
}, []);
|
|
472
|
+
const [schemaText, setSchemaText] = useState2(
|
|
473
|
+
() => JSON.stringify(toJsonSchema(PlaygroundFacets), null, 2)
|
|
474
|
+
);
|
|
475
|
+
const [schemaError, setSchemaError] = useState2("");
|
|
476
|
+
const [activeSchema, setActiveSchema] = useState2(SEARCH_FACET_SCHEMA);
|
|
477
|
+
const handleSchemaTextChange = useCallback2((value) => {
|
|
478
|
+
setSchemaText(value);
|
|
479
|
+
try {
|
|
480
|
+
JSON.parse(value);
|
|
481
|
+
setSchemaError("");
|
|
482
|
+
} catch {
|
|
483
|
+
setSchemaError("Invalid JSON");
|
|
484
|
+
}
|
|
485
|
+
}, []);
|
|
486
|
+
const handleLoadSchema = useCallback2(() => {
|
|
487
|
+
try {
|
|
488
|
+
const parsed = JSON.parse(schemaText);
|
|
489
|
+
setActiveSchema(parsed);
|
|
490
|
+
setFacetedExpr(EMPTY_FILTER);
|
|
491
|
+
setFacetedSubmitCount(SUBMIT_COUNT_RESET);
|
|
492
|
+
setSchemaError("");
|
|
493
|
+
} catch {
|
|
494
|
+
setSchemaError("Invalid JSON -- cannot load");
|
|
495
|
+
}
|
|
496
|
+
}, [schemaText]);
|
|
497
|
+
const [tableSchemaText, setTableSchemaText] = useState2(
|
|
498
|
+
() => JSON.stringify(SAMPLE_SCHEMA, null, 2)
|
|
499
|
+
);
|
|
500
|
+
const [tableUiSchemaText, setTableUiSchemaText] = useState2(
|
|
501
|
+
() => JSON.stringify(SAMPLE_UI_SCHEMA, null, 2)
|
|
502
|
+
);
|
|
503
|
+
const [tableSchemaError, setTableSchemaError] = useState2("");
|
|
504
|
+
const [activeTableSchema, setActiveTableSchema] = useState2(SAMPLE_SCHEMA);
|
|
505
|
+
const [activeTableUiSchema, setActiveTableUiSchema] = useState2(SAMPLE_UI_SCHEMA);
|
|
506
|
+
const [tableSchemaTab, setTableSchemaTab] = useState2("schema");
|
|
507
|
+
const handleTableSchemaTextChange = useCallback2((value) => {
|
|
508
|
+
setTableSchemaText(value);
|
|
509
|
+
try {
|
|
510
|
+
JSON.parse(value);
|
|
511
|
+
setTableSchemaError("");
|
|
512
|
+
} catch {
|
|
513
|
+
setTableSchemaError("Invalid JSON");
|
|
514
|
+
}
|
|
515
|
+
}, []);
|
|
516
|
+
const handleTableUiSchemaTextChange = useCallback2((value) => {
|
|
517
|
+
setTableUiSchemaText(value);
|
|
518
|
+
try {
|
|
519
|
+
JSON.parse(value);
|
|
520
|
+
setTableSchemaError("");
|
|
521
|
+
} catch {
|
|
522
|
+
setTableSchemaError("Invalid JSON");
|
|
523
|
+
}
|
|
524
|
+
}, []);
|
|
525
|
+
const handleApplyTableSchema = useCallback2(() => {
|
|
526
|
+
try {
|
|
527
|
+
const schema = JSON.parse(tableSchemaText);
|
|
528
|
+
const uiSchema = JSON.parse(tableUiSchemaText);
|
|
529
|
+
setActiveTableSchema(schema);
|
|
530
|
+
setActiveTableUiSchema(uiSchema);
|
|
531
|
+
setTableSchemaError("");
|
|
532
|
+
} catch {
|
|
533
|
+
setTableSchemaError("Invalid JSON -- cannot apply");
|
|
534
|
+
}
|
|
535
|
+
}, [tableSchemaText, tableUiSchemaText]);
|
|
536
|
+
const [tableExpr, setTableExpr] = useState2(EMPTY_FILTER);
|
|
537
|
+
const [tableSorting, setTableSorting] = useState2([]);
|
|
538
|
+
const [tableDensity, setTableDensity] = useState2("default");
|
|
539
|
+
const [tableLayout, setTableLayout] = useState2("flow");
|
|
540
|
+
const filteredRows = useMemo2(() => {
|
|
541
|
+
const terms = flattenFilterExpr(tableExpr);
|
|
542
|
+
const roles = terms.filter((t) => t.key === "roles").map((t) => t.value);
|
|
543
|
+
const rows = ALL_ROWS.filter(
|
|
544
|
+
(row) => (roles.length === 0 || roles.includes(row.role)) && terms.every(({ key, value }) => {
|
|
545
|
+
const v = value.toLowerCase();
|
|
546
|
+
if (key === "roles") return true;
|
|
547
|
+
if (key === "status") return row.status.toLowerCase().includes(v);
|
|
548
|
+
if (key === "joined_from") return row.joined >= value;
|
|
549
|
+
return row.name.toLowerCase().includes(v);
|
|
550
|
+
})
|
|
551
|
+
);
|
|
552
|
+
const [order] = tableSorting;
|
|
553
|
+
if (!order) return rows;
|
|
554
|
+
const field = order.id;
|
|
555
|
+
const sorted = [...rows].sort((a, b) => a[field].localeCompare(b[field]));
|
|
556
|
+
return order.desc ? sorted.reverse() : sorted;
|
|
557
|
+
}, [tableExpr, tableSorting]);
|
|
558
|
+
const tableData = useMemo2(
|
|
559
|
+
() => ({
|
|
560
|
+
data: filteredRows,
|
|
561
|
+
meta: {
|
|
562
|
+
total: filteredRows.length,
|
|
563
|
+
limit: filteredRows.length,
|
|
564
|
+
offset: 0,
|
|
565
|
+
has_next: false,
|
|
566
|
+
has_prev: false
|
|
567
|
+
}
|
|
568
|
+
}),
|
|
569
|
+
[filteredRows]
|
|
570
|
+
);
|
|
571
|
+
const [selectedPatient, setSelectedPatient] = useState2(null);
|
|
572
|
+
return /* @__PURE__ */ jsxs2("div", { className: "w-full max-w-4xl space-y-6", children: [
|
|
573
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
574
|
+
/* @__PURE__ */ jsx2("h1", { children: "Data Components" }),
|
|
575
|
+
/* @__PURE__ */ jsx2("p", { className: "text-sm text-muted-foreground mt-1", children: "Interactive sandbox for SearchInput (simple, multi-field, faceted, free text with filters), EntityTable (with schema editor and custom renderers), EntitySelect, and EntityTree." })
|
|
576
|
+
] }),
|
|
577
|
+
/* @__PURE__ */ jsxs2(
|
|
578
|
+
PlaygroundSection,
|
|
579
|
+
{
|
|
580
|
+
title: "SearchInput \u2014 simple mode",
|
|
581
|
+
description: "No fields prop. Produces a single search term under the key 'search'.",
|
|
582
|
+
variant: "card",
|
|
583
|
+
children: [
|
|
584
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap gap-4 mb-3", children: [
|
|
585
|
+
/* @__PURE__ */ jsx2(
|
|
586
|
+
ToggleStrip,
|
|
587
|
+
{
|
|
588
|
+
label: "Mode",
|
|
589
|
+
options: MODE_OPTIONS,
|
|
590
|
+
value: simpleMode,
|
|
591
|
+
onChange: (m) => {
|
|
592
|
+
setSimpleMode(m);
|
|
593
|
+
setSimpleExpr(EMPTY_FILTER);
|
|
594
|
+
},
|
|
595
|
+
format: (m) => MODE_LABELS[m]
|
|
596
|
+
}
|
|
597
|
+
),
|
|
598
|
+
/* @__PURE__ */ jsx2(
|
|
599
|
+
ToggleStrip,
|
|
600
|
+
{
|
|
601
|
+
label: "Min chars",
|
|
602
|
+
options: MIN_CHARS_OPTIONS,
|
|
603
|
+
value: simpleMinChars,
|
|
604
|
+
onChange: setSimpleMinChars,
|
|
605
|
+
format: (n) => n === 0 ? "off" : String(n)
|
|
606
|
+
}
|
|
607
|
+
)
|
|
608
|
+
] }),
|
|
609
|
+
/* @__PURE__ */ jsx2(
|
|
610
|
+
SearchInput,
|
|
611
|
+
{
|
|
612
|
+
value: simpleExpr,
|
|
613
|
+
onChange: setSimpleExpr,
|
|
614
|
+
mode: simpleMode,
|
|
615
|
+
minChars: simpleMinChars,
|
|
616
|
+
placeholder: "Search...",
|
|
617
|
+
className: "max-w-sm"
|
|
618
|
+
}
|
|
619
|
+
),
|
|
620
|
+
/* @__PURE__ */ jsx2(FlatTermsInspector, { expr: simpleExpr })
|
|
621
|
+
]
|
|
622
|
+
}
|
|
623
|
+
),
|
|
624
|
+
/* @__PURE__ */ jsxs2(
|
|
625
|
+
PlaygroundSection,
|
|
626
|
+
{
|
|
627
|
+
title: "SearchInput \u2014 searchFields (multi-field OR)",
|
|
628
|
+
description: "Produces a FilterOr with one term per field. Toggle field sets, mode, and minChars to explore different behaviours.",
|
|
629
|
+
variant: "card",
|
|
630
|
+
children: [
|
|
631
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-wrap gap-4 mb-3", children: [
|
|
632
|
+
/* @__PURE__ */ jsx2(
|
|
633
|
+
ToggleStrip,
|
|
634
|
+
{
|
|
635
|
+
label: "Fields",
|
|
636
|
+
options: FIELD_PRESET_INDICES,
|
|
637
|
+
value: fieldsPresetIdx,
|
|
638
|
+
onChange: (idx) => {
|
|
639
|
+
setFieldsPresetIdx(idx);
|
|
640
|
+
setFieldsExpr(EMPTY_FILTER);
|
|
641
|
+
},
|
|
642
|
+
format: (idx) => SEARCH_FIELD_PRESETS[idx].label
|
|
643
|
+
}
|
|
644
|
+
),
|
|
645
|
+
/* @__PURE__ */ jsx2(
|
|
646
|
+
ToggleStrip,
|
|
647
|
+
{
|
|
648
|
+
label: "Mode",
|
|
649
|
+
options: MODE_OPTIONS,
|
|
650
|
+
value: fieldsMode,
|
|
651
|
+
onChange: (m) => {
|
|
652
|
+
setFieldsMode(m);
|
|
653
|
+
setFieldsExpr(EMPTY_FILTER);
|
|
654
|
+
},
|
|
655
|
+
format: (m) => MODE_LABELS[m]
|
|
656
|
+
}
|
|
657
|
+
),
|
|
658
|
+
/* @__PURE__ */ jsx2(
|
|
659
|
+
ToggleStrip,
|
|
660
|
+
{
|
|
661
|
+
label: "Min chars",
|
|
662
|
+
options: MIN_CHARS_OPTIONS,
|
|
663
|
+
value: fieldsMinChars,
|
|
664
|
+
onChange: setFieldsMinChars,
|
|
665
|
+
format: (n) => n === 0 ? "off" : String(n)
|
|
666
|
+
}
|
|
667
|
+
)
|
|
668
|
+
] }),
|
|
669
|
+
/* @__PURE__ */ jsx2(
|
|
670
|
+
SearchInput,
|
|
671
|
+
{
|
|
672
|
+
value: fieldsExpr,
|
|
673
|
+
onChange: setFieldsExpr,
|
|
674
|
+
searchFields: activeSearchFields,
|
|
675
|
+
mode: fieldsMode,
|
|
676
|
+
minChars: fieldsMinChars,
|
|
677
|
+
placeholder: `Search by ${activeSearchFields.join(" or ")}...`,
|
|
678
|
+
className: "max-w-sm"
|
|
679
|
+
}
|
|
680
|
+
),
|
|
681
|
+
/* @__PURE__ */ jsxs2("div", { className: "mt-3 space-y-2", children: [
|
|
682
|
+
/* @__PURE__ */ jsxs2("p", { className: "text-xs text-muted-foreground", children: [
|
|
683
|
+
"searchFields: [",
|
|
684
|
+
activeSearchFields.map((f) => `"${f}"`).join(", "),
|
|
685
|
+
"]"
|
|
686
|
+
] }),
|
|
687
|
+
/* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground", children: "FilterExpr AST:" }),
|
|
688
|
+
/* @__PURE__ */ jsx2(FilterExprInspector, { expr: fieldsExpr }),
|
|
689
|
+
!isEmptyFilterExpr(fieldsExpr) && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
690
|
+
/* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground", children: "Serialized q= string:" }),
|
|
691
|
+
/* @__PURE__ */ jsx2("pre", { className: "rounded-md bg-muted px-4 py-3 text-xs overflow-auto", children: serializeFilterExpr(fieldsExpr) })
|
|
692
|
+
] })
|
|
693
|
+
] })
|
|
694
|
+
]
|
|
695
|
+
}
|
|
696
|
+
),
|
|
697
|
+
/* @__PURE__ */ jsx2(
|
|
698
|
+
PlaygroundSection,
|
|
699
|
+
{
|
|
700
|
+
title: "SearchInput \u2014 faceted mode",
|
|
701
|
+
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.",
|
|
702
|
+
variant: "card",
|
|
703
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "flex gap-4 items-start", children: [
|
|
704
|
+
/* @__PURE__ */ jsxs2(Card, { className: "flex-1 min-w-0 p-3 flex flex-col gap-2", children: [
|
|
705
|
+
/* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-muted-foreground", children: "JSON Schema" }),
|
|
706
|
+
schemaError && /* @__PURE__ */ jsx2(Badge, { variant: "destructive", className: "text-xs self-start", children: schemaError }),
|
|
707
|
+
/* @__PURE__ */ jsx2(
|
|
708
|
+
FormTextarea,
|
|
709
|
+
{
|
|
710
|
+
value: schemaText,
|
|
711
|
+
onChange: (e) => handleSchemaTextChange(e.target.value),
|
|
712
|
+
className: "font-mono text-xs",
|
|
713
|
+
rows: 18
|
|
714
|
+
}
|
|
715
|
+
)
|
|
716
|
+
] }),
|
|
717
|
+
/* @__PURE__ */ jsx2("div", { className: "flex items-center self-center", children: /* @__PURE__ */ jsx2(SimpleTooltip, { label: "Load schema into search", children: /* @__PURE__ */ jsx2(
|
|
718
|
+
Button,
|
|
719
|
+
{
|
|
720
|
+
variant: "default",
|
|
721
|
+
size: "icon",
|
|
722
|
+
onClick: handleLoadSchema,
|
|
723
|
+
disabled: !!schemaError,
|
|
724
|
+
children: /* @__PURE__ */ jsx2(ArrowRight, { size: 18 })
|
|
725
|
+
}
|
|
726
|
+
) }) }),
|
|
727
|
+
/* @__PURE__ */ jsxs2(Card, { className: "flex-1 min-w-0 p-3 flex flex-col gap-3", children: [
|
|
728
|
+
/* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-muted-foreground", children: "Live search" }),
|
|
729
|
+
/* @__PURE__ */ jsx2(
|
|
730
|
+
SearchInput,
|
|
731
|
+
{
|
|
732
|
+
value: facetedExpr,
|
|
733
|
+
onChange: handleFacetedChange,
|
|
734
|
+
schema: activeSchema,
|
|
735
|
+
mode: "explicit",
|
|
736
|
+
placeholder: "Add filter..."
|
|
737
|
+
}
|
|
738
|
+
),
|
|
739
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
740
|
+
/* @__PURE__ */ jsx2("span", { children: "onChange fired:" }),
|
|
741
|
+
/* @__PURE__ */ jsxs2("span", { className: "font-mono font-medium text-foreground", children: [
|
|
742
|
+
facetedSubmitCount,
|
|
743
|
+
"x"
|
|
744
|
+
] })
|
|
745
|
+
] }),
|
|
746
|
+
/* @__PURE__ */ jsx2(FilterExprInspector, { expr: facetedExpr })
|
|
747
|
+
] })
|
|
748
|
+
] })
|
|
749
|
+
}
|
|
750
|
+
),
|
|
751
|
+
/* @__PURE__ */ jsx2(
|
|
752
|
+
PlaygroundSection,
|
|
753
|
+
{
|
|
754
|
+
title: "SearchInput \u2014 free text with filters (textKey)",
|
|
755
|
+
description: "One field for a query and its filters. Type the query; pick filters with the chevron or ArrowDown. Explicit: Enter submits the text (as the textKey term) with the chips. Debounce: they fire as typing pauses. A removed chip reruns at once; enum chips show their labels.",
|
|
756
|
+
variant: "card",
|
|
757
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-3 max-w-2xl", children: [
|
|
758
|
+
/* @__PURE__ */ jsx2(
|
|
759
|
+
ToggleStrip,
|
|
760
|
+
{
|
|
761
|
+
label: "Mode",
|
|
762
|
+
options: MODE_OPTIONS,
|
|
763
|
+
value: freeTextMode,
|
|
764
|
+
onChange: setFreeTextMode,
|
|
765
|
+
format: (m) => MODE_LABELS[m]
|
|
766
|
+
}
|
|
767
|
+
),
|
|
768
|
+
/* @__PURE__ */ jsx2(
|
|
769
|
+
SearchInput,
|
|
770
|
+
{
|
|
771
|
+
value: freeTextExpr,
|
|
772
|
+
onChange: setFreeTextExpr,
|
|
773
|
+
schema: FREE_TEXT_FACETS,
|
|
774
|
+
textKey: "q",
|
|
775
|
+
mode: freeTextMode,
|
|
776
|
+
showSearchButton: true,
|
|
777
|
+
placeholder: "Search for code or content..."
|
|
778
|
+
}
|
|
779
|
+
),
|
|
780
|
+
/* @__PURE__ */ jsx2(FilterExprInspector, { expr: freeTextExpr })
|
|
781
|
+
] })
|
|
782
|
+
}
|
|
783
|
+
),
|
|
784
|
+
/* @__PURE__ */ jsxs2(
|
|
785
|
+
PlaygroundSection,
|
|
786
|
+
{
|
|
787
|
+
title: "EntityTable with SearchInput",
|
|
788
|
+
description: "Faceted search wired to EntityTable. onChange fires only on submit (Enter on empty input) -- table filters when the user presses Enter. Role is a repeatable facet (one chip per role) and Joined from uses the date widget. Name and Joined are sortable: click a header -- the table reports the order and the page's query applies it. Density compact tightens the rows and drops the lines between them; layout fill puts the table in a fixed-height box where the rows scroll under a header that stays on top. Edit the JSON Schema or UI Schema below and press Apply to see column changes live.",
|
|
789
|
+
variant: "card",
|
|
790
|
+
children: [
|
|
791
|
+
/* @__PURE__ */ jsx2(
|
|
792
|
+
SearchInput,
|
|
793
|
+
{
|
|
794
|
+
value: tableExpr,
|
|
795
|
+
onChange: setTableExpr,
|
|
796
|
+
schema: SEARCH_FACET_SCHEMA,
|
|
797
|
+
mode: "explicit",
|
|
798
|
+
placeholder: "Filter users... (press Enter to apply)",
|
|
799
|
+
className: "mb-4 max-w-sm"
|
|
800
|
+
}
|
|
801
|
+
),
|
|
802
|
+
/* @__PURE__ */ jsxs2("div", { className: "mb-4 flex flex-wrap gap-6", children: [
|
|
803
|
+
/* @__PURE__ */ jsx2(
|
|
804
|
+
ToggleStrip,
|
|
805
|
+
{
|
|
806
|
+
label: "Density",
|
|
807
|
+
options: DENSITY_OPTIONS,
|
|
808
|
+
value: tableDensity,
|
|
809
|
+
onChange: setTableDensity
|
|
810
|
+
}
|
|
811
|
+
),
|
|
812
|
+
/* @__PURE__ */ jsx2(
|
|
813
|
+
ToggleStrip,
|
|
814
|
+
{
|
|
815
|
+
label: "Layout",
|
|
816
|
+
options: LAYOUT_OPTIONS,
|
|
817
|
+
value: tableLayout,
|
|
818
|
+
onChange: setTableLayout
|
|
819
|
+
}
|
|
820
|
+
)
|
|
821
|
+
] }),
|
|
822
|
+
/* @__PURE__ */ jsx2("div", { className: tableLayout === "fill" ? "h-64" : void 0, children: /* @__PURE__ */ jsx2(
|
|
823
|
+
EntityTable2,
|
|
824
|
+
{
|
|
825
|
+
schema: activeTableSchema,
|
|
826
|
+
uiSchema: activeTableUiSchema,
|
|
827
|
+
data: tableData,
|
|
828
|
+
isLoading: false,
|
|
829
|
+
isError: false,
|
|
830
|
+
entityLabel: "users",
|
|
831
|
+
isFiltered: !isEmptyFilterExpr(tableExpr),
|
|
832
|
+
sorting: tableSorting,
|
|
833
|
+
onSortingChange: setTableSorting,
|
|
834
|
+
density: tableDensity,
|
|
835
|
+
fill: tableLayout === "fill"
|
|
836
|
+
}
|
|
837
|
+
) }),
|
|
838
|
+
/* @__PURE__ */ jsx2("div", { className: "mt-4", children: /* @__PURE__ */ jsx2(Card, { className: "border shadow-sm p-4 flex flex-col", children: /* @__PURE__ */ jsx2("div", { className: "flex items-center justify-between mb-2", children: /* @__PURE__ */ jsxs2(
|
|
839
|
+
Tabs,
|
|
840
|
+
{
|
|
841
|
+
value: tableSchemaTab,
|
|
842
|
+
onValueChange: setTableSchemaTab,
|
|
843
|
+
className: "flex flex-col flex-1",
|
|
844
|
+
children: [
|
|
845
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
|
|
846
|
+
/* @__PURE__ */ jsxs2(TabsList, { children: [
|
|
847
|
+
/* @__PURE__ */ jsx2(TabsTrigger, { value: "schema", children: "JSON Schema" }),
|
|
848
|
+
/* @__PURE__ */ jsx2(TabsTrigger, { value: "uischema", children: "UI Schema" })
|
|
849
|
+
] }),
|
|
850
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
851
|
+
tableSchemaError && /* @__PURE__ */ jsx2(Badge, { variant: "destructive", className: "text-xs", children: tableSchemaError }),
|
|
852
|
+
/* @__PURE__ */ jsx2(SimpleTooltip, { label: "Apply schema to table above", children: /* @__PURE__ */ jsx2(
|
|
853
|
+
Button,
|
|
854
|
+
{
|
|
855
|
+
variant: "default",
|
|
856
|
+
size: "icon",
|
|
857
|
+
onClick: handleApplyTableSchema,
|
|
858
|
+
disabled: !!tableSchemaError,
|
|
859
|
+
children: /* @__PURE__ */ jsx2(ArrowUp, { size: 18 })
|
|
860
|
+
}
|
|
861
|
+
) })
|
|
862
|
+
] })
|
|
863
|
+
] }),
|
|
864
|
+
/* @__PURE__ */ jsx2(TabsContent, { value: "schema", className: "mt-2", children: /* @__PURE__ */ jsx2(
|
|
865
|
+
JsonEditor,
|
|
866
|
+
{
|
|
867
|
+
value: tableSchemaText,
|
|
868
|
+
editablePaths: ["/"],
|
|
869
|
+
onChange: handleTableSchemaTextChange,
|
|
870
|
+
height: "280px",
|
|
871
|
+
className: "rounded-md border overflow-hidden"
|
|
872
|
+
}
|
|
873
|
+
) }),
|
|
874
|
+
/* @__PURE__ */ jsx2(TabsContent, { value: "uischema", className: "mt-2", children: /* @__PURE__ */ jsx2(
|
|
875
|
+
JsonEditor,
|
|
876
|
+
{
|
|
877
|
+
value: tableUiSchemaText,
|
|
878
|
+
editablePaths: ["/"],
|
|
879
|
+
onChange: handleTableUiSchemaTextChange,
|
|
880
|
+
height: "280px",
|
|
881
|
+
className: "rounded-md border overflow-hidden"
|
|
882
|
+
}
|
|
883
|
+
) })
|
|
884
|
+
]
|
|
885
|
+
}
|
|
886
|
+
) }) }) })
|
|
887
|
+
]
|
|
888
|
+
}
|
|
889
|
+
),
|
|
890
|
+
/* @__PURE__ */ jsx2(EntityTableLongListDemo, {}),
|
|
891
|
+
/* @__PURE__ */ jsx2(
|
|
892
|
+
PlaygroundSection,
|
|
893
|
+
{
|
|
894
|
+
title: "EntityTable with Local Renderers",
|
|
895
|
+
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).",
|
|
896
|
+
variant: "card",
|
|
897
|
+
children: /* @__PURE__ */ jsx2(
|
|
898
|
+
EntityTable2,
|
|
899
|
+
{
|
|
900
|
+
schema: CUSTOM_RENDERER_SCHEMA,
|
|
901
|
+
renderers: CUSTOM_RENDERERS,
|
|
902
|
+
data: {
|
|
903
|
+
data: ALL_ROWS,
|
|
904
|
+
meta: {
|
|
905
|
+
total: ALL_ROWS.length,
|
|
906
|
+
limit: ALL_ROWS.length,
|
|
907
|
+
offset: 0,
|
|
908
|
+
has_next: false,
|
|
909
|
+
has_prev: false
|
|
910
|
+
}
|
|
911
|
+
},
|
|
912
|
+
isLoading: false,
|
|
913
|
+
isError: false,
|
|
914
|
+
entityLabel: "users"
|
|
915
|
+
}
|
|
916
|
+
)
|
|
917
|
+
}
|
|
918
|
+
),
|
|
919
|
+
/* @__PURE__ */ jsx2(
|
|
920
|
+
PlaygroundSection,
|
|
921
|
+
{
|
|
922
|
+
title: "EntitySelect",
|
|
923
|
+
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'.",
|
|
924
|
+
variant: "card",
|
|
925
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "flex gap-6 items-start", children: [
|
|
926
|
+
/* @__PURE__ */ jsx2(
|
|
927
|
+
EntitySelect,
|
|
928
|
+
{
|
|
929
|
+
fetcher: patientFetcher,
|
|
930
|
+
queryKey: "playground-patients",
|
|
931
|
+
value: selectedPatient,
|
|
932
|
+
onChange: setSelectedPatient,
|
|
933
|
+
label: "Patient",
|
|
934
|
+
placeholder: "Select patient...",
|
|
935
|
+
searchPlaceholder: "Search patients...",
|
|
936
|
+
className: "max-w-xs"
|
|
937
|
+
}
|
|
938
|
+
),
|
|
939
|
+
/* @__PURE__ */ jsxs2(Card, { className: "flex-1 min-w-0 p-3", children: [
|
|
940
|
+
/* @__PURE__ */ jsx2("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: "Selected value" }),
|
|
941
|
+
/* @__PURE__ */ jsx2("pre", { className: "rounded-md bg-muted px-4 py-3 text-xs overflow-auto", children: JSON.stringify(selectedPatient, null, 2) })
|
|
942
|
+
] })
|
|
943
|
+
] })
|
|
944
|
+
}
|
|
945
|
+
),
|
|
946
|
+
/* @__PURE__ */ jsx2(
|
|
947
|
+
PlaygroundSection,
|
|
948
|
+
{
|
|
949
|
+
title: "EntityTree",
|
|
950
|
+
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.",
|
|
951
|
+
variant: "card",
|
|
952
|
+
children: /* @__PURE__ */ jsx2(EntityTreeDemo, {})
|
|
953
|
+
}
|
|
954
|
+
),
|
|
955
|
+
/* @__PURE__ */ jsx2(
|
|
956
|
+
PlaygroundSection,
|
|
957
|
+
{
|
|
958
|
+
title: "PropertyList",
|
|
959
|
+
description: "Read-only property display used by detail pages, panels and graph node/edge cards. With no schema, values render by JS shape; an optional per-property schema refines rendering (date/datetime/boolean/number/x-ui-cell). With an object schema, the schema decides the fields, their order, labels (x-ui-title) and cells (x-ui-cell, or a local x- renderer), as for EntityTable. Density: compact (an inspector) or comfortable (a detail page: label column, no rules between rows).",
|
|
960
|
+
variant: "card",
|
|
961
|
+
children: /* @__PURE__ */ jsx2(PropertyListDemo, {})
|
|
962
|
+
}
|
|
963
|
+
)
|
|
964
|
+
] });
|
|
965
|
+
}
|
|
966
|
+
var PROPERTY_LIST_SAMPLE = {
|
|
967
|
+
name: "acme_server.api",
|
|
968
|
+
description: "Build tools (Maven, Gradle, Webpack, Vite, etc.)",
|
|
969
|
+
is_component: false,
|
|
970
|
+
tags: ["python", "fastapi", "graph"],
|
|
971
|
+
created_at: "2026-01-15T09:30:00Z",
|
|
972
|
+
empty_value: null,
|
|
973
|
+
// Real nested object -> collapsed JSON tree.
|
|
974
|
+
config: {
|
|
975
|
+
retries: 3,
|
|
976
|
+
timeout_s: 30,
|
|
977
|
+
endpoints: ["/a", "/b"],
|
|
978
|
+
nested: { enabled: true }
|
|
979
|
+
},
|
|
980
|
+
// Long text -> clamp + show more.
|
|
981
|
+
notes: "This module exposes the public API surface. It aggregates routers from submodules, wires middleware, and configures CORS. See the architecture doc for the full request lifecycle and the list of mounted sub-applications."
|
|
982
|
+
};
|
|
983
|
+
var PROPERTY_LIST_SCHEMA = {
|
|
984
|
+
is_component: { type: "boolean" },
|
|
985
|
+
created_at: { type: "string", format: "date-time" }
|
|
986
|
+
};
|
|
987
|
+
function PropertyListDemo() {
|
|
988
|
+
return /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2", children: [
|
|
989
|
+
/* @__PURE__ */ jsxs2(Card, { className: "p-4", children: [
|
|
990
|
+
/* @__PURE__ */ jsx2("p", { className: "mb-3 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "No schema (value-shape)" }),
|
|
991
|
+
/* @__PURE__ */ jsx2(PropertyList, { properties: PROPERTY_LIST_SAMPLE })
|
|
992
|
+
] }),
|
|
993
|
+
/* @__PURE__ */ jsxs2(Card, { className: "p-4", children: [
|
|
994
|
+
/* @__PURE__ */ jsx2("p", { className: "mb-3 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "With optional schema (boolean / date-time)" }),
|
|
995
|
+
/* @__PURE__ */ jsx2(
|
|
996
|
+
PropertyList,
|
|
997
|
+
{
|
|
998
|
+
properties: PROPERTY_LIST_SAMPLE,
|
|
999
|
+
propertySchemas: PROPERTY_LIST_SCHEMA,
|
|
1000
|
+
showHeader: true
|
|
1001
|
+
}
|
|
1002
|
+
)
|
|
1003
|
+
] }),
|
|
1004
|
+
/* @__PURE__ */ jsxs2(Card, { className: "p-4 sm:col-span-2", children: [
|
|
1005
|
+
/* @__PURE__ */ jsx2("p", { className: "mb-3 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Object schema, comfortable (a detail page)" }),
|
|
1006
|
+
/* @__PURE__ */ jsx2(
|
|
1007
|
+
PropertyList,
|
|
1008
|
+
{
|
|
1009
|
+
properties: DETAIL_SAMPLE,
|
|
1010
|
+
schema: DETAIL_SCHEMA,
|
|
1011
|
+
renderers: DETAIL_RENDERERS,
|
|
1012
|
+
density: "comfortable",
|
|
1013
|
+
copyable: false
|
|
1014
|
+
}
|
|
1015
|
+
)
|
|
1016
|
+
] })
|
|
1017
|
+
] });
|
|
1018
|
+
}
|
|
1019
|
+
var DetailSchema = z.object({
|
|
1020
|
+
program: z.string().meta({ "x-ui-title": "Program", "x-ui-cell": "code" }),
|
|
1021
|
+
status: z.string().meta({
|
|
1022
|
+
"x-ui-title": "Status",
|
|
1023
|
+
"x-ui-cell": "badge",
|
|
1024
|
+
"x-ui-cell-options": { colors: { available: "green", missing: "red" } }
|
|
1025
|
+
}),
|
|
1026
|
+
exit_codes: z.array(z.number()).meta({ "x-ui-title": "Success exit codes" }),
|
|
1027
|
+
version_args: z.array(z.string()).meta({
|
|
1028
|
+
"x-ui-title": "Version check",
|
|
1029
|
+
"x-ui-cell": "join",
|
|
1030
|
+
"x-ui-cell-options": { separator: " " }
|
|
1031
|
+
}),
|
|
1032
|
+
used_by: z.array(z.string()).meta({ "x-ui-title": "Run by", "x-ui-cell": "x-links" }),
|
|
1033
|
+
updated_at: z.string().meta({ "x-ui-title": "Updated", format: "date-time" }),
|
|
1034
|
+
internal_id: z.string().meta({ "x-ui-column": { hidden: true } })
|
|
1035
|
+
});
|
|
1036
|
+
var DETAIL_SCHEMA = toJsonSchema(DetailSchema);
|
|
1037
|
+
var DETAIL_SAMPLE = {
|
|
1038
|
+
program: "trivy",
|
|
1039
|
+
status: "available",
|
|
1040
|
+
exit_codes: [0, 1],
|
|
1041
|
+
version_args: ["--version"],
|
|
1042
|
+
used_by: ["acme.scan", "acme.nightly"],
|
|
1043
|
+
updated_at: "2026-10-30T14:05:00Z",
|
|
1044
|
+
internal_id: "not shown"
|
|
1045
|
+
};
|
|
1046
|
+
var DETAIL_RENDERERS = {
|
|
1047
|
+
"x-links": createRenderer((row) => {
|
|
1048
|
+
const items = row.used_by ?? [];
|
|
1049
|
+
if (!items.length)
|
|
1050
|
+
return /* @__PURE__ */ jsx2("span", { className: "text-muted-foreground", children: "none" });
|
|
1051
|
+
return items.map((item, i) => /* @__PURE__ */ jsxs2(React2.Fragment, { children: [
|
|
1052
|
+
i > 0 && ", ",
|
|
1053
|
+
/* @__PURE__ */ jsx2("a", { href: "#", className: "text-primary hover:underline", children: item })
|
|
1054
|
+
] }, item));
|
|
1055
|
+
})
|
|
1056
|
+
};
|
|
1057
|
+
var OrgSchema = z.object({
|
|
1058
|
+
name: z.string().meta({ title: "Name", "x-ui-column": { order: 0 } }),
|
|
1059
|
+
type: z.string().meta({ title: "Type", "x-ui-column": { order: 1 } }),
|
|
1060
|
+
headcount: z.number().meta({ title: "Headcount", "x-ui-column": { order: 2 } })
|
|
1061
|
+
});
|
|
1062
|
+
var ORG_TREE_SCHEMA = toJsonSchema(OrgSchema);
|
|
1063
|
+
var ORG_NODES = [
|
|
1064
|
+
{
|
|
1065
|
+
id: "eng",
|
|
1066
|
+
data: { name: "Engineering", type: "Division", headcount: 120 },
|
|
1067
|
+
hasChildren: true,
|
|
1068
|
+
children: [
|
|
1069
|
+
{
|
|
1070
|
+
id: "frontend",
|
|
1071
|
+
data: { name: "Frontend", type: "Team", headcount: 18 },
|
|
1072
|
+
hasChildren: true,
|
|
1073
|
+
children: [
|
|
1074
|
+
{
|
|
1075
|
+
id: "design-sys",
|
|
1076
|
+
data: { name: "Design System", type: "Squad", headcount: 5 },
|
|
1077
|
+
hasChildren: false
|
|
1078
|
+
}
|
|
1079
|
+
]
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
id: "backend",
|
|
1083
|
+
data: { name: "Backend", type: "Team", headcount: 32 },
|
|
1084
|
+
hasChildren: false
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
id: "infra",
|
|
1088
|
+
data: { name: "Infrastructure", type: "Team", headcount: 14 },
|
|
1089
|
+
hasChildren: false
|
|
1090
|
+
}
|
|
1091
|
+
]
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
id: "product",
|
|
1095
|
+
data: { name: "Product", type: "Division", headcount: 45 },
|
|
1096
|
+
hasChildren: true,
|
|
1097
|
+
children: [
|
|
1098
|
+
{
|
|
1099
|
+
id: "research",
|
|
1100
|
+
data: { name: "Research", type: "Team", headcount: 8 },
|
|
1101
|
+
hasChildren: false
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
id: "pm",
|
|
1105
|
+
data: { name: "Product Management", type: "Team", headcount: 12 },
|
|
1106
|
+
hasChildren: false
|
|
1107
|
+
}
|
|
1108
|
+
]
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
id: "ops",
|
|
1112
|
+
data: { name: "Operations", type: "Division", headcount: 30 },
|
|
1113
|
+
hasChildren: false
|
|
1114
|
+
}
|
|
1115
|
+
];
|
|
1116
|
+
function EntityTreeDemo() {
|
|
1117
|
+
const {
|
|
1118
|
+
expandedIds: treeExpandedIds,
|
|
1119
|
+
onExpand: onTreeExpand,
|
|
1120
|
+
onCollapse: onTreeCollapse
|
|
1121
|
+
} = useTreeExpansion();
|
|
1122
|
+
const [selectedIds, setSelectedIds] = useState2(/* @__PURE__ */ new Set());
|
|
1123
|
+
const [activeId, setActiveId] = useState2(null);
|
|
1124
|
+
return /* @__PURE__ */ jsxs2("div", { className: "space-y-4", children: [
|
|
1125
|
+
/* @__PURE__ */ jsx2(
|
|
1126
|
+
EntityTree,
|
|
1127
|
+
{
|
|
1128
|
+
schema: ORG_TREE_SCHEMA,
|
|
1129
|
+
nodes: ORG_NODES,
|
|
1130
|
+
expandedIds: treeExpandedIds,
|
|
1131
|
+
onExpand: onTreeExpand,
|
|
1132
|
+
onCollapse: onTreeCollapse,
|
|
1133
|
+
onNodeSelect: (node) => setActiveId(node.id),
|
|
1134
|
+
onNodeEdit: (node) => setActiveId(node.id),
|
|
1135
|
+
activeNodeId: activeId ?? void 0,
|
|
1136
|
+
selectedIds,
|
|
1137
|
+
onSelectionChange: (id, selected) => setSelectedIds((prev) => {
|
|
1138
|
+
const next = new Set(prev);
|
|
1139
|
+
if (selected) next.add(id);
|
|
1140
|
+
else next.delete(id);
|
|
1141
|
+
return next;
|
|
1142
|
+
}),
|
|
1143
|
+
entityLabel: "departments"
|
|
1144
|
+
}
|
|
1145
|
+
),
|
|
1146
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-6 text-xs text-muted-foreground", children: [
|
|
1147
|
+
activeId && /* @__PURE__ */ jsxs2("span", { children: [
|
|
1148
|
+
"Active: ",
|
|
1149
|
+
/* @__PURE__ */ jsx2("span", { className: "font-mono", children: activeId })
|
|
1150
|
+
] }),
|
|
1151
|
+
selectedIds.size > 0 && /* @__PURE__ */ jsxs2("span", { children: [
|
|
1152
|
+
"Selected:",
|
|
1153
|
+
" ",
|
|
1154
|
+
/* @__PURE__ */ jsx2("span", { className: "font-mono", children: [...selectedIds].join(", ") })
|
|
1155
|
+
] })
|
|
1156
|
+
] })
|
|
1157
|
+
] });
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
export {
|
|
1161
|
+
PlayDataComponents
|
|
1162
|
+
};
|
|
1163
|
+
//# sourceMappingURL=chunk-3FYM6B3E.js.map
|