@thebes/cadmea 1.1.1 → 1.3.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.
@@ -1,41 +1,81 @@
1
1
  import { className, createComponent, delegateEvents, effect, insert, memo, setAttribute, template } from "solid-js/web";
2
2
  import { createMutation, createQuery, useQueryClient } from "@tanstack/solid-query";
3
- import { For, Show, Suspense, createEffect, createSignal, lazy } from "solid-js";
3
+ import { For, Index, Show, Suspense, createEffect, createSignal, lazy } from "solid-js";
4
+ import { createForm } from "@tanstack/solid-form";
5
+ import { validateDocument } from "@thebes/cadmus/cms";
4
6
  import { Link, useBlocker } from "@tanstack/solid-router";
7
+ import { createSolidTable, flexRender, getCoreRowModel } from "@tanstack/solid-table";
5
8
  //#region src/CollectionEdit.tsx
6
- var _tmpl$$4 = /*#__PURE__*/ template(`<p class="text-sm text-error"role=alert>`), _tmpl$2$3 = /*#__PURE__*/ template(`<span class="loading loading-spinner loading-sm">`), _tmpl$3$1 = /*#__PURE__*/ template(`<button type=button class="btn flex-1">`), _tmpl$4$1 = /*#__PURE__*/ template(`<button type=button class="btn btn-primary flex-1">`), _tmpl$5$1 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline flex-1">`), _tmpl$6$1 = /*#__PURE__*/ template(`<form class="flex flex-col gap-4"><div class="bg-base-100 sticky bottom-0 flex gap-2 border-t py-3">`), _tmpl$7$1 = /*#__PURE__*/ template(`<span class=text-error> *`), _tmpl$8$1 = /*#__PURE__*/ template(`<div class=form-control><label class=label>`), _tmpl$9$1 = /*#__PURE__*/ template(`<button type=submit class="btn btn-primary flex-1">`), _tmpl$0$1 = /*#__PURE__*/ template(`<input class=input type=text>`), _tmpl$1$1 = /*#__PURE__*/ template(`<select class=select>`), _tmpl$10$1 = /*#__PURE__*/ template(`<option>`), _tmpl$11$1 = /*#__PURE__*/ template(`<input class=input type=number>`), _tmpl$12$1 = /*#__PURE__*/ template(`<input class=input type=text readonly>`), _tmpl$13$1 = /*#__PURE__*/ template(`<input class=checkbox type=checkbox>`), _tmpl$14 = /*#__PURE__*/ template(`<p class="text-sm opacity-70 break-all">`), _tmpl$15 = /*#__PURE__*/ template(`<p class="text-sm text-error">`), _tmpl$16 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2"><input class=file-input type=file>`), _tmpl$17 = /*#__PURE__*/ template(`<select class=select><option value>—`), _tmpl$18 = /*#__PURE__*/ template(`<div class="flex flex-col gap-3"><button type=button class="btn btn-outline btn-sm self-start">Add `), _tmpl$19 = /*#__PURE__*/ template(`<div class="card bg-base-200 flex flex-col gap-2 p-3"><button type=button class="btn btn-error btn-outline btn-sm self-start">Remove`);
7
- const RichTextEditor = lazy(() => import("../RichTextEditor-BPilh7Pw.js").then((mod) => ({ default: mod.RichTextEditor })));
9
+ var _tmpl$$4 = /*#__PURE__*/ template(`<p class="text-sm text-error"role=alert>`), _tmpl$2$3 = /*#__PURE__*/ template(`<span class="loading loading-spinner loading-sm">`), _tmpl$3$1 = /*#__PURE__*/ template(`<button type=button class="btn flex-1">`), _tmpl$4$1 = /*#__PURE__*/ template(`<button type=button class="btn btn-primary flex-1">`), _tmpl$5$1 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline flex-1">`), _tmpl$6$1 = /*#__PURE__*/ template(`<form class="flex flex-col gap-4"><div class="bg-base-100 sticky bottom-0 flex gap-2 border-t py-3">`), _tmpl$7$1 = /*#__PURE__*/ template(`<fieldset class="border-base-300 rounded-box border p-4"><legend class="px-2 text-sm font-semibold">`), _tmpl$8$1 = /*#__PURE__*/ template(`<div class="grid grid-cols-1 gap-4 md:grid-cols-2">`), _tmpl$9$1 = /*#__PURE__*/ template(`<span class=text-error> *`), _tmpl$0$1 = /*#__PURE__*/ template(`<p class="text-base-content/60 mb-1 text-xs">`), _tmpl$1$1 = /*#__PURE__*/ template(`<p class="text-error mt-1 text-sm"role=alert>`), _tmpl$10$1 = /*#__PURE__*/ template(`<div><label class=label>`), _tmpl$11$1 = /*#__PURE__*/ template(`<input class=input type=text>`), _tmpl$12$1 = /*#__PURE__*/ template(`<select class=select>`), _tmpl$13$1 = /*#__PURE__*/ template(`<option>`), _tmpl$14 = /*#__PURE__*/ template(`<input class=input type=number>`), _tmpl$15 = /*#__PURE__*/ template(`<input class=input type=text readonly>`), _tmpl$16 = /*#__PURE__*/ template(`<input class=checkbox type=checkbox>`), _tmpl$17 = /*#__PURE__*/ template(`<p class="text-sm opacity-70 break-all">`), _tmpl$18 = /*#__PURE__*/ template(`<p class="text-sm text-error">`), _tmpl$19 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2"><input class=file-input type=file>`), _tmpl$20 = /*#__PURE__*/ template(`<div class="mb-1 flex flex-wrap gap-1">`), _tmpl$21 = /*#__PURE__*/ template(`<button type=button aria-label=Clear class="absolute top-2 right-2 cursor-pointer opacity-60">×`), _tmpl$22 = /*#__PURE__*/ template(`<div role=listbox class="bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex max-h-56 w-full flex-col overflow-auto border p-1 shadow">`), _tmpl$23 = /*#__PURE__*/ template(`<div class=relative><input type=text role=combobox autocomplete=off class=input>`), _tmpl$24 = /*#__PURE__*/ template(`<span class="badge badge-primary gap-1"><button type=button class=cursor-pointer>×`), _tmpl$25 = /*#__PURE__*/ template(`<button type=button role=option class="rounded px-3 py-2 text-left">`), _tmpl$26 = /*#__PURE__*/ template(`<div role=menu class="bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex flex-col border p-1 shadow">`), _tmpl$27 = /*#__PURE__*/ template(`<div class="relative self-start"><button type=button class="btn btn-outline btn-sm"aria-haspopup=menu>Add block`), _tmpl$28 = /*#__PURE__*/ template(`<div class="form-control md:col-span-2"><div class="label font-medium"></div><div class="flex flex-col gap-3">`), _tmpl$29 = /*#__PURE__*/ template(`<span class="text-base-content/60 truncate text-sm">`), _tmpl$30 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2">`), _tmpl$31 = /*#__PURE__*/ template(`<div class="card bg-base-200 flex flex-col gap-2 p-3"><div class="flex items-center gap-2"><button type=button class="btn btn-ghost btn-sm gap-2"><span aria-hidden=true></span><span class=font-semibold></span></button><div class="ml-auto flex gap-1"><button type=button class="btn btn-ghost btn-xs"aria-label="Move up">↑</button><button type=button class="btn btn-ghost btn-xs"aria-label="Move down">↓</button><button type=button class="btn btn-ghost btn-xs"aria-label=Duplicate>⧉</button><button type=button class="btn btn-ghost btn-xs text-error"aria-label=Remove>Remove`), _tmpl$32 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline btn-sm self-start">Add `), _tmpl$33 = /*#__PURE__*/ template(`<i aria-hidden=true>`), _tmpl$34 = /*#__PURE__*/ template(`<button type=button role=menuitem class="flex items-center gap-2 rounded px-3 py-2 text-left">`);
10
+ const RichTextEditor = lazy(() => import("../RichTextEditor-ComcBFfl.js").then((mod) => ({ default: mod.RichTextEditor })));
8
11
  function editableFields(config) {
9
12
  return Object.entries(config.fields).filter(([key]) => key !== "id");
10
13
  }
11
- function CollectionEdit(props) {
12
- const initialSnapshot = JSON.stringify(props.initialValues ?? {});
13
- const [values, setValues] = createSignal(props.initialValues ?? {});
14
- createEffect(() => {
15
- props.onDirtyChange?.(JSON.stringify(values()) !== initialSnapshot);
16
- });
17
- function setField(key, value) {
18
- setValues((prev) => ({
19
- ...prev,
20
- [key]: value
21
- }));
14
+ function humanize(key) {
15
+ const spaced = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
16
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
17
+ }
18
+ function labelFor(key, field) {
19
+ return field.admin?.label ?? humanize(key);
20
+ }
21
+ function groupFields(entries) {
22
+ const groups = [];
23
+ const byName = /* @__PURE__ */ new Map();
24
+ for (const entry of entries) {
25
+ const name = entry[1].admin?.group;
26
+ let group = byName.get(name);
27
+ if (!group) {
28
+ group = {
29
+ name,
30
+ fields: []
31
+ };
32
+ byName.set(name, group);
33
+ groups.push(group);
34
+ }
35
+ group.fields.push(entry);
22
36
  }
23
- function editablePayload() {
24
- return Object.fromEntries(Object.entries(values()).filter(([key]) => props.config.fields[key]?.type !== "date"));
37
+ return groups;
38
+ }
39
+ function CollectionEdit(props) {
40
+ const operation = props.initialValues?.id != null ? "update" : "create";
41
+ async function validateForm(value) {
42
+ const violations = await validateDocument(props.config, value, { operation });
43
+ const fields = {};
44
+ for (const v of violations) if (v.severity === "error" && !(v.path in fields)) fields[v.path] = v.message;
45
+ return Object.keys(fields).length > 0 ? { fields } : void 0;
25
46
  }
26
- function handleSubmit(event) {
27
- event.preventDefault();
28
- props.onSubmit(editablePayload());
47
+ const form = createForm(() => ({
48
+ defaultValues: props.initialValues ?? {},
49
+ validators: { onSubmitAsync: ({ value }) => validateForm(value) },
50
+ onSubmit: async ({ value }) => {
51
+ await props.onSubmit(editablePayload(value));
52
+ }
53
+ }));
54
+ const isDefaultValue = form.useStore((s) => s.isDefaultValue);
55
+ createEffect(() => props.onDirtyChange?.(!isDefaultValue()));
56
+ const formValues = form.useStore((s) => s.values);
57
+ function editablePayload(value) {
58
+ return Object.fromEntries(Object.entries(value).filter(([key]) => props.config.fields[key]?.type !== "date"));
29
59
  }
30
60
  const ctx = {
31
- onUploadFile: props.onUploadFile,
32
- relationshipOptions: props.relationshipOptions,
33
- fieldWidgets: props.fieldWidgets
61
+ get onUploadFile() {
62
+ return props.onUploadFile;
63
+ },
64
+ get relationshipOptions() {
65
+ return props.relationshipOptions;
66
+ },
67
+ get fieldWidgets() {
68
+ return props.fieldWidgets;
69
+ }
34
70
  };
71
+ const fieldGroups = groupFields(editableFields(props.config));
35
72
  const versioned = () => props.config.versions?.drafts && props.draftActions;
36
73
  return (() => {
37
74
  var _el$ = _tmpl$6$1(), _el$3 = _el$.firstChild;
38
- _el$.addEventListener("submit", handleSubmit);
75
+ _el$.addEventListener("submit", (event) => {
76
+ event.preventDefault();
77
+ form.handleSubmit();
78
+ });
39
79
  insert(_el$, createComponent(Show, {
40
80
  get when() {
41
81
  return props.error;
@@ -47,24 +87,35 @@ function CollectionEdit(props) {
47
87
  }
48
88
  }), _el$3);
49
89
  insert(_el$, createComponent(For, {
50
- get each() {
51
- return editableFields(props.config);
52
- },
53
- children: ([key, field]) => (() => {
54
- var _el$0 = _tmpl$8$1(), _el$1 = _el$0.firstChild;
55
- setAttribute(_el$1, "for", key);
56
- insert(_el$1, key, null);
57
- insert(_el$1, createComponent(Show, {
58
- get when() {
59
- return field.required;
60
- },
61
- get children() {
62
- return _tmpl$7$1();
63
- }
64
- }), null);
65
- insert(_el$0, () => renderInput(key, field, values()[key], setField, ctx), null);
66
- return _el$0;
67
- })()
90
+ each: fieldGroups,
91
+ children: (group) => createComponent(Show, {
92
+ get when() {
93
+ return group.name;
94
+ },
95
+ get fallback() {
96
+ return createComponent(FieldsGrid, {
97
+ form,
98
+ ctx,
99
+ get fields() {
100
+ return group.fields;
101
+ },
102
+ values: formValues
103
+ });
104
+ },
105
+ get children() {
106
+ var _el$0 = _tmpl$7$1(), _el$1 = _el$0.firstChild;
107
+ insert(_el$1, () => group.name);
108
+ insert(_el$0, createComponent(FieldsGrid, {
109
+ form,
110
+ ctx,
111
+ get fields() {
112
+ return group.fields;
113
+ },
114
+ values: formValues
115
+ }), null);
116
+ return _el$0;
117
+ }
118
+ })
68
119
  }), _el$3);
69
120
  insert(_el$3, createComponent(Show, {
70
121
  get when() {
@@ -76,8 +127,9 @@ function CollectionEdit(props) {
76
127
  return props.capabilities?.canUpdate !== false;
77
128
  },
78
129
  get children() {
79
- var _el$11 = _tmpl$9$1();
80
- insert(_el$11, createComponent(Show, {
130
+ var _el$10 = _tmpl$4$1();
131
+ _el$10.$$click = () => void form.handleSubmit();
132
+ insert(_el$10, createComponent(Show, {
81
133
  get when() {
82
134
  return props.saving;
83
135
  },
@@ -88,8 +140,8 @@ function CollectionEdit(props) {
88
140
  return _tmpl$2$3();
89
141
  }
90
142
  }));
91
- effect(() => _el$11.disabled = props.saving);
92
- return _el$11;
143
+ effect(() => _el$10.disabled = props.saving);
144
+ return _el$10;
93
145
  }
94
146
  });
95
147
  },
@@ -97,7 +149,7 @@ function CollectionEdit(props) {
97
149
  return [
98
150
  (() => {
99
151
  var _el$4 = _tmpl$3$1();
100
- _el$4.$$click = () => void props.draftActions?.onSaveDraft(editablePayload());
152
+ _el$4.$$click = () => void props.draftActions?.onSaveDraft(editablePayload(formValues()));
101
153
  insert(_el$4, createComponent(Show, {
102
154
  get when() {
103
155
  return props.draftActions?.saving;
@@ -157,98 +209,204 @@ function CollectionEdit(props) {
157
209
  return _el$;
158
210
  })();
159
211
  }
160
- function renderInput(key, field, value, setField, ctx) {
161
- const Widget = ctx.fieldWidgets?.[key] ?? ctx.fieldWidgets?.[key.slice(key.lastIndexOf(".") + 1)];
212
+ function FieldsGrid(props) {
213
+ return (() => {
214
+ var _el$12 = _tmpl$8$1();
215
+ insert(_el$12, createComponent(For, {
216
+ get each() {
217
+ return props.fields;
218
+ },
219
+ children: ([key, field]) => createComponent(Show, {
220
+ get when() {
221
+ return !field.admin?.condition || field.admin.condition(props.values());
222
+ },
223
+ get children() {
224
+ return renderField(props.form, props.ctx, key, field, labelFor(key, field));
225
+ }
226
+ })
227
+ }));
228
+ return _el$12;
229
+ })();
230
+ }
231
+ function renderField(form, ctx, name, field, label) {
232
+ if (field.type === "array") return renderArray(form, ctx, name, field, label);
233
+ const spanClass = field.admin?.width === "half" ? "md:col-span-1" : "md:col-span-2";
234
+ return createComponent(form.Field, {
235
+ name,
236
+ children: (fieldApi) => (() => {
237
+ var _el$13 = _tmpl$10$1(), _el$14 = _el$13.firstChild;
238
+ className(_el$13, `form-control ${spanClass}`);
239
+ setAttribute(_el$14, "for", name);
240
+ insert(_el$14, label, null);
241
+ insert(_el$14, createComponent(Show, {
242
+ get when() {
243
+ return field.required;
244
+ },
245
+ get children() {
246
+ return _tmpl$9$1();
247
+ }
248
+ }), null);
249
+ insert(_el$13, createComponent(Show, {
250
+ get when() {
251
+ return field.admin?.description;
252
+ },
253
+ get children() {
254
+ var _el$16 = _tmpl$0$1();
255
+ insert(_el$16, () => field.admin?.description);
256
+ return _el$16;
257
+ }
258
+ }), null);
259
+ insert(_el$13, () => renderControl(ctx, name, field, fieldApi), null);
260
+ insert(_el$13, createComponent(Show, {
261
+ get when() {
262
+ return (fieldApi().state.meta.errors?.length ?? 0) > 0;
263
+ },
264
+ get children() {
265
+ var _el$17 = _tmpl$1$1();
266
+ insert(_el$17, () => fieldApi().state.meta.errors.filter(Boolean).join(", "));
267
+ return _el$17;
268
+ }
269
+ }), null);
270
+ return _el$13;
271
+ })()
272
+ });
273
+ }
274
+ function renderControl(ctx, name, field, fieldApi) {
275
+ const Widget = ctx.fieldWidgets?.[name] ?? ctx.fieldWidgets?.[name.slice(name.lastIndexOf(".") + 1)];
162
276
  if (Widget) return createComponent(Widget, {
163
- fieldKey: key,
164
- value,
165
- setValue: (v) => setField(key, v),
277
+ fieldKey: name,
278
+ get value() {
279
+ return fieldApi().state.value;
280
+ },
281
+ setValue: (v) => fieldApi().handleChange(v),
166
282
  get onUploadFile() {
167
283
  return ctx.onUploadFile;
168
284
  }
169
285
  });
286
+ const readOnly = field.admin?.readOnly;
287
+ const change = (v) => fieldApi().handleChange(v);
170
288
  switch (field.type) {
171
289
  case "text": return (() => {
172
- var _el$13 = _tmpl$0$1();
173
- _el$13.$$input = (e) => setField(key, e.currentTarget.value);
174
- setAttribute(_el$13, "id", key);
175
- _el$13.value = value ?? "";
176
- effect(() => _el$13.required = field.required);
177
- return _el$13;
290
+ var _el$18 = _tmpl$11$1();
291
+ _el$18.addEventListener("blur", () => fieldApi().handleBlur());
292
+ _el$18.$$input = (e) => change(e.currentTarget.value);
293
+ setAttribute(_el$18, "id", name);
294
+ _el$18.readOnly = readOnly;
295
+ effect((_p$) => {
296
+ var _v$ = field.admin?.placeholder, _v$2 = field.required;
297
+ _v$ !== _p$.e && setAttribute(_el$18, "placeholder", _p$.e = _v$);
298
+ _v$2 !== _p$.t && (_el$18.required = _p$.t = _v$2);
299
+ return _p$;
300
+ }, {
301
+ e: void 0,
302
+ t: void 0
303
+ });
304
+ effect(() => _el$18.value = fieldApi().state.value ?? "");
305
+ return _el$18;
178
306
  })();
179
307
  case "select": return (() => {
180
- var _el$14 = _tmpl$1$1();
181
- _el$14.addEventListener("change", (e) => setField(key, e.currentTarget.value));
182
- setAttribute(_el$14, "id", key);
183
- _el$14.value = value ?? "";
184
- insert(_el$14, createComponent(For, {
308
+ var _el$19 = _tmpl$12$1();
309
+ _el$19.addEventListener("blur", () => fieldApi().handleBlur());
310
+ _el$19.addEventListener("change", (e) => change(e.currentTarget.value));
311
+ setAttribute(_el$19, "id", name);
312
+ _el$19.disabled = readOnly;
313
+ insert(_el$19, createComponent(For, {
185
314
  get each() {
186
315
  return field.options;
187
316
  },
188
317
  children: (option) => (() => {
189
- var _el$15 = _tmpl$10$1();
190
- _el$15.value = option;
191
- insert(_el$15, option);
192
- return _el$15;
318
+ var _el$20 = _tmpl$13$1();
319
+ _el$20.value = option;
320
+ insert(_el$20, option);
321
+ return _el$20;
193
322
  })()
194
323
  }));
195
- effect(() => _el$14.required = field.required);
196
- return _el$14;
324
+ effect(() => _el$19.required = field.required);
325
+ effect(() => _el$19.value = fieldApi().state.value ?? "");
326
+ return _el$19;
197
327
  })();
198
328
  case "number": return (() => {
199
- var _el$16 = _tmpl$11$1();
200
- _el$16.$$input = (e) => setField(key, e.currentTarget.valueAsNumber);
201
- setAttribute(_el$16, "id", key);
202
- _el$16.value = value ?? "";
203
- effect(() => _el$16.required = field.required);
204
- return _el$16;
329
+ var _el$21 = _tmpl$14();
330
+ _el$21.addEventListener("blur", () => fieldApi().handleBlur());
331
+ _el$21.$$input = (e) => change(e.currentTarget.valueAsNumber);
332
+ setAttribute(_el$21, "id", name);
333
+ _el$21.readOnly = readOnly;
334
+ effect((_p$) => {
335
+ var _v$3 = field.admin?.placeholder, _v$4 = field.required;
336
+ _v$3 !== _p$.e && setAttribute(_el$21, "placeholder", _p$.e = _v$3);
337
+ _v$4 !== _p$.t && (_el$21.required = _p$.t = _v$4);
338
+ return _p$;
339
+ }, {
340
+ e: void 0,
341
+ t: void 0
342
+ });
343
+ effect(() => _el$21.value = fieldApi().state.value ?? "");
344
+ return _el$21;
205
345
  })();
206
346
  case "date": return (() => {
207
- var _el$17 = _tmpl$12$1();
208
- setAttribute(_el$17, "id", key);
209
- effect(() => _el$17.value = formatDateValue(value));
210
- return _el$17;
347
+ var _el$22 = _tmpl$15();
348
+ setAttribute(_el$22, "id", name);
349
+ effect(() => _el$22.value = formatDateValue(fieldApi().state.value));
350
+ return _el$22;
211
351
  })();
212
352
  case "checkbox": return (() => {
213
- var _el$18 = _tmpl$13$1();
214
- _el$18.addEventListener("change", (e) => setField(key, e.currentTarget.checked));
215
- setAttribute(_el$18, "id", key);
216
- _el$18.checked = value ?? false;
217
- return _el$18;
353
+ var _el$23 = _tmpl$16();
354
+ _el$23.addEventListener("change", (e) => change(e.currentTarget.checked));
355
+ setAttribute(_el$23, "id", name);
356
+ _el$23.disabled = readOnly;
357
+ effect(() => _el$23.checked = fieldApi().state.value ?? false);
358
+ return _el$23;
218
359
  })();
219
- case "upload": return renderUploadInput(key, field, value, setField, ctx);
220
- case "relationship": return renderRelationshipInput(key, field, value, setField, ctx);
221
- case "array": return renderArrayInput(key, field, value, setField, ctx);
360
+ case "upload": return createComponent(UploadControl, {
361
+ name,
362
+ field,
363
+ fieldApi,
364
+ ctx
365
+ });
366
+ case "relationship": return createComponent(RelationshipField, {
367
+ name,
368
+ field,
369
+ fieldApi,
370
+ get options() {
371
+ return ctx.relationshipOptions?.[field.relationTo] ?? [];
372
+ }
373
+ });
222
374
  case "richText": return createComponent(Suspense, {
223
375
  get fallback() {
224
376
  return _tmpl$2$3();
225
377
  },
226
378
  get children() {
227
379
  return createComponent(RichTextEditor, {
228
- id: key,
229
- content: value,
230
- onChange: (doc) => setField(key, doc)
380
+ id: name,
381
+ get content() {
382
+ return fieldApi().state.value;
383
+ },
384
+ onChange: (doc) => change(doc),
385
+ get onUploadFile() {
386
+ return ctx.onUploadFile;
387
+ }
231
388
  });
232
389
  }
233
390
  });
234
391
  default: return null;
235
392
  }
236
393
  }
237
- function renderUploadInput(key, field, value, setField, ctx) {
394
+ function UploadControl(props) {
238
395
  const [uploading, setUploading] = createSignal(false);
239
396
  const [uploadError, setUploadError] = createSignal();
397
+ const value = () => props.fieldApi().state.value;
240
398
  async function handleFileChange(e) {
241
399
  const file = e.currentTarget.files?.[0];
242
400
  if (!file) return;
243
- if (!ctx.onUploadFile) {
401
+ if (!props.ctx.onUploadFile) {
244
402
  setUploadError("No upload handler configured for this form.");
245
403
  return;
246
404
  }
247
405
  setUploading(true);
248
406
  setUploadError(void 0);
249
407
  try {
250
- const { url } = await ctx.onUploadFile(file);
251
- setField(key, url);
408
+ const { url } = await props.ctx.onUploadFile(file);
409
+ props.fieldApi().handleChange(url);
252
410
  } catch (err) {
253
411
  setUploadError(err instanceof Error ? err.message : "Upload failed");
254
412
  } finally {
@@ -256,18 +414,19 @@ function renderUploadInput(key, field, value, setField, ctx) {
256
414
  }
257
415
  }
258
416
  return (() => {
259
- var _el$20 = _tmpl$16(), _el$22 = _el$20.firstChild;
260
- insert(_el$20, createComponent(Show, {
261
- when: value,
417
+ var _el$25 = _tmpl$19(), _el$27 = _el$25.firstChild;
418
+ insert(_el$25, createComponent(Show, {
419
+ get when() {
420
+ return value();
421
+ },
262
422
  get children() {
263
- var _el$21 = _tmpl$14();
264
- insert(_el$21, value);
265
- return _el$21;
423
+ var _el$26 = _tmpl$17();
424
+ insert(_el$26, value);
425
+ return _el$26;
266
426
  }
267
- }), _el$22);
268
- _el$22.addEventListener("change", handleFileChange);
269
- setAttribute(_el$22, "id", key);
270
- insert(_el$20, createComponent(Show, {
427
+ }), _el$27);
428
+ _el$27.addEventListener("change", handleFileChange);
429
+ insert(_el$25, createComponent(Show, {
271
430
  get when() {
272
431
  return uploading();
273
432
  },
@@ -275,121 +434,376 @@ function renderUploadInput(key, field, value, setField, ctx) {
275
434
  return _tmpl$2$3();
276
435
  }
277
436
  }), null);
278
- insert(_el$20, createComponent(Show, {
437
+ insert(_el$25, createComponent(Show, {
279
438
  get when() {
280
439
  return uploadError();
281
440
  },
282
441
  get children() {
283
- var _el$24 = _tmpl$15();
284
- insert(_el$24, uploadError);
285
- return _el$24;
442
+ var _el$29 = _tmpl$18();
443
+ insert(_el$29, uploadError);
444
+ return _el$29;
286
445
  }
287
446
  }), null);
288
447
  effect((_p$) => {
289
- var _v$ = field.required && !value, _v$2 = uploading();
290
- _v$ !== _p$.e && (_el$22.required = _p$.e = _v$);
291
- _v$2 !== _p$.t && (_el$22.disabled = _p$.t = _v$2);
448
+ var _v$5 = props.name, _v$6 = props.field.required && !value(), _v$7 = uploading() || props.field.admin?.readOnly;
449
+ _v$5 !== _p$.e && setAttribute(_el$27, "id", _p$.e = _v$5);
450
+ _v$6 !== _p$.t && (_el$27.required = _p$.t = _v$6);
451
+ _v$7 !== _p$.a && (_el$27.disabled = _p$.a = _v$7);
292
452
  return _p$;
293
453
  }, {
294
454
  e: void 0,
295
- t: void 0
455
+ t: void 0,
456
+ a: void 0
296
457
  });
297
- return _el$20;
458
+ return _el$25;
298
459
  })();
299
460
  }
300
- function renderRelationshipInput(key, field, value, setField, ctx) {
301
- if (field.hasMany) return null;
302
- const options = ctx.relationshipOptions?.[field.relationTo] ?? [];
461
+ function RelationshipField(props) {
462
+ const [query, setQuery] = createSignal("");
463
+ const [open, setOpen] = createSignal(false);
464
+ const [active, setActive] = createSignal(0);
465
+ const listId = `${props.name}-listbox`;
466
+ const isMulti = () => props.field.hasMany === true;
467
+ const value = () => props.fieldApi().state.value;
468
+ const selectedIds = () => {
469
+ const v = value();
470
+ if (isMulti()) return Array.isArray(v) ? v : [];
471
+ return v != null ? [v] : [];
472
+ };
473
+ const selectedOptions = () => props.options.filter((o) => selectedIds().includes(o.id));
474
+ const filtered = () => {
475
+ const q = query().toLowerCase();
476
+ return props.options.filter((o) => o.label.toLowerCase().includes(q) && (!isMulti() || !selectedIds().includes(o.id)));
477
+ };
478
+ const singleLabel = () => selectedOptions()[0]?.label ?? "";
479
+ function choose(option) {
480
+ if (isMulti()) {
481
+ props.fieldApi().handleChange([...selectedIds(), option.id]);
482
+ setQuery("");
483
+ } else {
484
+ props.fieldApi().handleChange(option.id);
485
+ setQuery("");
486
+ setOpen(false);
487
+ }
488
+ setActive(0);
489
+ }
490
+ function removeId(id) {
491
+ if (isMulti()) props.fieldApi().handleChange(selectedIds().filter((x) => x !== id));
492
+ else props.fieldApi().handleChange(null);
493
+ }
494
+ function onKeyDown(e) {
495
+ if (e.key === "ArrowDown") {
496
+ e.preventDefault();
497
+ setOpen(true);
498
+ setActive((a) => Math.min(a + 1, filtered().length - 1));
499
+ } else if (e.key === "ArrowUp") {
500
+ e.preventDefault();
501
+ setActive((a) => Math.max(a - 1, 0));
502
+ } else if (e.key === "Enter") {
503
+ e.preventDefault();
504
+ const option = filtered()[active()];
505
+ if (option) choose(option);
506
+ } else if (e.key === "Escape") setOpen(false);
507
+ else if (e.key === "Backspace" && isMulti() && query() === "") {
508
+ const ids = selectedIds();
509
+ if (ids.length > 0) removeId(ids[ids.length - 1]);
510
+ }
511
+ }
303
512
  return (() => {
304
- var _el$25 = _tmpl$17();
305
- _el$25.firstChild;
306
- _el$25.addEventListener("change", (e) => setField(key, e.currentTarget.value === "" ? null : Number(e.currentTarget.value)));
307
- setAttribute(_el$25, "id", key);
308
- insert(_el$25, createComponent(For, {
309
- each: options,
310
- children: (option) => (() => {
311
- var _el$27 = _tmpl$10$1();
312
- insert(_el$27, () => option.label);
313
- effect(() => _el$27.value = option.id);
314
- return _el$27;
315
- })()
513
+ var _el$30 = _tmpl$23(), _el$32 = _el$30.firstChild;
514
+ insert(_el$30, createComponent(Show, {
515
+ get when() {
516
+ return memo(() => !!isMulti())() && selectedOptions().length > 0;
517
+ },
518
+ get children() {
519
+ var _el$31 = _tmpl$20();
520
+ insert(_el$31, createComponent(For, {
521
+ get each() {
522
+ return selectedOptions();
523
+ },
524
+ children: (option) => (() => {
525
+ var _el$35 = _tmpl$24(), _el$36 = _el$35.firstChild;
526
+ insert(_el$35, () => option.label, _el$36);
527
+ _el$36.$$click = () => removeId(option.id);
528
+ effect(() => setAttribute(_el$36, "aria-label", `Remove ${option.label}`));
529
+ return _el$35;
530
+ })()
531
+ }));
532
+ return _el$31;
533
+ }
534
+ }), _el$32);
535
+ _el$32.$$keydown = onKeyDown;
536
+ _el$32.addEventListener("blur", () => setTimeout(() => setOpen(false), 120));
537
+ _el$32.addEventListener("focus", () => setOpen(true));
538
+ _el$32.$$input = (e) => {
539
+ setQuery(e.currentTarget.value);
540
+ setOpen(true);
541
+ setActive(0);
542
+ };
543
+ setAttribute(_el$32, "aria-controls", listId);
544
+ insert(_el$30, createComponent(Show, {
545
+ get when() {
546
+ return memo(() => !!(!isMulti() && value() != null))() && !props.field.required;
547
+ },
548
+ get children() {
549
+ var _el$33 = _tmpl$21();
550
+ _el$33.$$click = () => removeId(value());
551
+ _el$33.$$mousedown = (e) => e.preventDefault();
552
+ return _el$33;
553
+ }
316
554
  }), null);
317
- effect(() => _el$25.required = field.required);
318
- effect(() => _el$25.value = value != null ? String(value) : "");
319
- return _el$25;
555
+ insert(_el$30, createComponent(Show, {
556
+ get when() {
557
+ return memo(() => !!open())() && filtered().length > 0;
558
+ },
559
+ get children() {
560
+ var _el$34 = _tmpl$22();
561
+ setAttribute(_el$34, "id", listId);
562
+ insert(_el$34, createComponent(For, {
563
+ get each() {
564
+ return filtered();
565
+ },
566
+ children: (option, i) => (() => {
567
+ var _el$37 = _tmpl$25();
568
+ _el$37.$$click = () => choose(option);
569
+ _el$37.$$mousedown = (e) => e.preventDefault();
570
+ insert(_el$37, () => option.label);
571
+ effect((_p$) => {
572
+ var _v$11 = selectedIds().includes(option.id), _v$12 = !!(i() === active());
573
+ _v$11 !== _p$.e && setAttribute(_el$37, "aria-selected", _p$.e = _v$11);
574
+ _v$12 !== _p$.t && _el$37.classList.toggle("bg-base-200", _p$.t = _v$12);
575
+ return _p$;
576
+ }, {
577
+ e: void 0,
578
+ t: void 0
579
+ });
580
+ return _el$37;
581
+ })()
582
+ }));
583
+ return _el$34;
584
+ }
585
+ }), null);
586
+ effect((_p$) => {
587
+ var _v$8 = props.name, _v$9 = open(), _v$0 = props.field.required && selectedIds().length === 0, _v$1 = props.field.admin?.readOnly, _v$10 = props.field.admin?.placeholder ?? "Search…";
588
+ _v$8 !== _p$.e && setAttribute(_el$32, "id", _p$.e = _v$8);
589
+ _v$9 !== _p$.t && setAttribute(_el$32, "aria-expanded", _p$.t = _v$9);
590
+ _v$0 !== _p$.a && (_el$32.required = _p$.a = _v$0);
591
+ _v$1 !== _p$.o && (_el$32.disabled = _p$.o = _v$1);
592
+ _v$10 !== _p$.i && setAttribute(_el$32, "placeholder", _p$.i = _v$10);
593
+ return _p$;
594
+ }, {
595
+ e: void 0,
596
+ t: void 0,
597
+ a: void 0,
598
+ o: void 0,
599
+ i: void 0
600
+ });
601
+ effect(() => _el$32.value = open() || isMulti() ? query() : singleLabel());
602
+ return _el$30;
320
603
  })();
321
604
  }
322
- function renderArrayInput(key, field, value, setField, ctx) {
323
- const items = () => Array.isArray(value) ? value : [];
324
- function updateItem(index, itemKey, itemValue) {
325
- const next = items().slice();
326
- next[index] = {
327
- ...next[index],
328
- [itemKey]: itemValue
329
- };
330
- setField(key, next);
605
+ function renderArray(form, ctx, name, field, label) {
606
+ return createComponent(form.Field, {
607
+ name,
608
+ mode: "array",
609
+ children: (fieldApi) => createComponent(BlockEditor, {
610
+ form,
611
+ ctx,
612
+ name,
613
+ field,
614
+ label,
615
+ fieldApi
616
+ })
617
+ });
618
+ }
619
+ function variantLabel(disc, variant) {
620
+ return disc.variantsAdmin?.[variant]?.label ?? humanize(variant);
621
+ }
622
+ function BlockEditor(props) {
623
+ const [collapsed, setCollapsed] = createSignal(/* @__PURE__ */ new Set());
624
+ const [menuOpen, setMenuOpen] = createSignal(false);
625
+ const disc = props.field.discriminator;
626
+ const variants = disc ? Object.keys(disc.variants) : [];
627
+ const items = () => Array.isArray(props.fieldApi().state.value) ? props.fieldApi().state.value : [];
628
+ function addBlock(variant) {
629
+ const seed = variant && disc ? { [disc.key]: variant } : {};
630
+ props.fieldApi().pushValue(seed);
631
+ setMenuOpen(false);
632
+ }
633
+ function duplicate(index) {
634
+ props.fieldApi().insertValue(index + 1, { ...items()[index] });
635
+ }
636
+ function move(from, to) {
637
+ if (to < 0 || to >= items().length) return;
638
+ props.fieldApi().moveValue(from, to);
331
639
  }
332
- function addItem() {
333
- setField(key, [...items(), {}]);
640
+ function toggleCollapse(index) {
641
+ setCollapsed((prev) => {
642
+ const next = new Set(prev);
643
+ if (next.has(index)) next.delete(index);
644
+ else next.add(index);
645
+ return next;
646
+ });
334
647
  }
335
- function removeItem(index) {
336
- setField(key, items().filter((_, i) => i !== index));
648
+ function blockTitle(item) {
649
+ if (disc) {
650
+ const v = item[disc.key];
651
+ if (typeof v === "string") return variantLabel(disc, v);
652
+ }
653
+ return props.label;
337
654
  }
338
- function fieldsForItem(item) {
339
- const base = Object.entries(field.fields);
340
- const discriminator = field.discriminator;
341
- if (!discriminator) return base;
342
- const variantValue = item[discriminator.key];
343
- const variantFields = typeof variantValue === "string" ? discriminator.variants[variantValue] : void 0;
344
- return variantFields ? [...base, ...Object.entries(variantFields)] : base;
655
+ function blockSummary(item) {
656
+ for (const [key, f] of fieldsForItem(props.field, item)) {
657
+ if (key === disc?.key) continue;
658
+ if ((f.type === "text" || f.type === "select") && item[key]) return String(item[key]);
659
+ }
660
+ return "";
345
661
  }
346
662
  return (() => {
347
- var _el$28 = _tmpl$18(), _el$29 = _el$28.firstChild;
348
- _el$29.firstChild;
349
- insert(_el$28, createComponent(For, {
663
+ var _el$38 = _tmpl$28(), _el$39 = _el$38.firstChild, _el$42 = _el$39.nextSibling;
664
+ insert(_el$39, () => props.label, null);
665
+ insert(_el$39, createComponent(Show, {
666
+ get when() {
667
+ return props.field.required;
668
+ },
669
+ get children() {
670
+ return _tmpl$9$1();
671
+ }
672
+ }), null);
673
+ insert(_el$38, createComponent(Show, {
674
+ get when() {
675
+ return props.field.admin?.description;
676
+ },
677
+ get children() {
678
+ var _el$41 = _tmpl$0$1();
679
+ insert(_el$41, () => props.field.admin?.description);
680
+ return _el$41;
681
+ }
682
+ }), _el$42);
683
+ insert(_el$42, createComponent(Index, {
350
684
  get each() {
351
685
  return items();
352
686
  },
353
- children: (item, index) => (() => {
354
- var _el$31 = _tmpl$19(), _el$32 = _el$31.firstChild;
355
- insert(_el$31, createComponent(For, {
356
- get each() {
357
- return fieldsForItem(item);
358
- },
359
- children: ([itemKey, itemField]) => {
360
- const inputId = `${key}.${index()}.${itemKey}`;
361
- return (() => {
362
- var _el$33 = _tmpl$8$1(), _el$34 = _el$33.firstChild;
363
- setAttribute(_el$34, "for", inputId);
364
- insert(_el$34, itemKey, null);
365
- insert(_el$34, createComponent(Show, {
366
- get when() {
367
- return itemField.required;
687
+ children: (item, index) => {
688
+ const isCollapsed = () => collapsed().has(index);
689
+ return (() => {
690
+ var _el$46 = _tmpl$31(), _el$47 = _el$46.firstChild, _el$48 = _el$47.firstChild, _el$49 = _el$48.firstChild, _el$50 = _el$49.nextSibling, _el$52 = _el$48.nextSibling, _el$53 = _el$52.firstChild, _el$54 = _el$53.nextSibling, _el$55 = _el$54.nextSibling, _el$56 = _el$55.nextSibling;
691
+ _el$48.$$click = () => toggleCollapse(index);
692
+ insert(_el$49, () => isCollapsed() ? "▸" : "▾");
693
+ insert(_el$50, () => blockTitle(item()));
694
+ insert(_el$47, createComponent(Show, {
695
+ get when() {
696
+ return memo(() => !!isCollapsed())() && blockSummary(item());
697
+ },
698
+ get children() {
699
+ var _el$51 = _tmpl$29();
700
+ insert(_el$51, () => blockSummary(item()));
701
+ return _el$51;
702
+ }
703
+ }), _el$52);
704
+ _el$53.$$click = () => move(index, index - 1);
705
+ _el$53.disabled = index === 0;
706
+ _el$54.$$click = () => move(index, index + 1);
707
+ _el$55.$$click = () => duplicate(index);
708
+ _el$56.$$click = () => props.fieldApi().removeValue(index);
709
+ insert(_el$46, createComponent(Show, {
710
+ get when() {
711
+ return !isCollapsed();
712
+ },
713
+ get children() {
714
+ var _el$57 = _tmpl$30();
715
+ insert(_el$57, createComponent(For, {
716
+ get each() {
717
+ return fieldsForItem(props.field, item());
368
718
  },
369
- get children() {
370
- return _tmpl$7$1();
371
- }
372
- }), null);
373
- insert(_el$33, () => renderInput(inputId, itemField, item[itemKey], (_, v) => updateItem(index(), itemKey, v), ctx), null);
374
- return _el$33;
375
- })();
719
+ children: ([itemKey, itemField]) => renderField(props.form, props.ctx, `${props.name}[${index}].${itemKey}`, itemField, labelFor(itemKey, itemField))
720
+ }));
721
+ return _el$57;
722
+ }
723
+ }), null);
724
+ effect((_p$) => {
725
+ var _v$13 = !isCollapsed(), _v$14 = index === items().length - 1;
726
+ _v$13 !== _p$.e && setAttribute(_el$48, "aria-expanded", _p$.e = _v$13);
727
+ _v$14 !== _p$.t && (_el$54.disabled = _p$.t = _v$14);
728
+ return _p$;
729
+ }, {
730
+ e: void 0,
731
+ t: void 0
732
+ });
733
+ return _el$46;
734
+ })();
735
+ }
736
+ }), null);
737
+ insert(_el$42, createComponent(Show, {
738
+ get when() {
739
+ return disc && variants.length > 0;
740
+ },
741
+ get fallback() {
742
+ return (() => {
743
+ var _el$58 = _tmpl$32();
744
+ _el$58.firstChild;
745
+ _el$58.$$click = () => addBlock();
746
+ insert(_el$58, () => props.label, null);
747
+ return _el$58;
748
+ })();
749
+ },
750
+ get children() {
751
+ var _el$43 = _tmpl$27(), _el$44 = _el$43.firstChild;
752
+ _el$44.$$click = () => setMenuOpen((o) => !o);
753
+ insert(_el$43, createComponent(Show, {
754
+ get when() {
755
+ return menuOpen();
756
+ },
757
+ get children() {
758
+ var _el$45 = _tmpl$26();
759
+ insert(_el$45, createComponent(For, {
760
+ each: variants,
761
+ children: (variant) => (() => {
762
+ var _el$60 = _tmpl$34();
763
+ _el$60.$$click = () => addBlock(variant);
764
+ insert(_el$60, createComponent(Show, {
765
+ get when() {
766
+ return disc?.variantsAdmin?.[variant]?.icon;
767
+ },
768
+ get children() {
769
+ var _el$61 = _tmpl$33();
770
+ effect(() => className(_el$61, disc?.variantsAdmin?.[variant]?.icon));
771
+ return _el$61;
772
+ }
773
+ }), null);
774
+ insert(_el$60, () => variantLabel(disc, variant), null);
775
+ return _el$60;
776
+ })()
777
+ }));
778
+ return _el$45;
376
779
  }
377
- }), _el$32);
378
- _el$32.$$click = () => removeItem(index());
379
- return _el$31;
380
- })()
381
- }), _el$29);
382
- _el$29.$$click = addItem;
383
- insert(_el$29, key, null);
384
- return _el$28;
780
+ }), null);
781
+ effect(() => setAttribute(_el$44, "aria-expanded", menuOpen()));
782
+ return _el$43;
783
+ }
784
+ }), null);
785
+ return _el$38;
385
786
  })();
386
787
  }
788
+ function fieldsForItem(field, item) {
789
+ const base = Object.entries(field.fields);
790
+ const discriminator = field.discriminator;
791
+ if (!discriminator) return base;
792
+ const variantValue = item[discriminator.key];
793
+ const variantFields = typeof variantValue === "string" ? discriminator.variants[variantValue] : void 0;
794
+ return variantFields ? [...base, ...Object.entries(variantFields)] : base;
795
+ }
387
796
  function formatDateValue(value) {
388
797
  if (!value) return "—";
389
798
  const date = value instanceof Date ? value : new Date(value);
390
799
  return Number.isNaN(date.getTime()) ? "—" : date.toLocaleString();
391
800
  }
392
- delegateEvents(["click", "input"]);
801
+ delegateEvents([
802
+ "click",
803
+ "input",
804
+ "keydown",
805
+ "mousedown"
806
+ ]);
393
807
  //#endregion
394
808
  //#region src/tanstack-start/create.tsx
395
809
  var _tmpl$$3 = /*#__PURE__*/ template(`<div class="flex flex-col gap-4"><h1 class="text-xl font-semibold">`);
@@ -578,7 +992,7 @@ function createCollectionEditPage(options) {
578
992
  delegateEvents(["click"]);
579
993
  //#endregion
580
994
  //#region src/CollectionList.tsx
581
- var _tmpl$$1 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline btn-sm">`), _tmpl$2$1 = /*#__PURE__*/ template(`<div class=join><select aria-label="Sort by"class="select select-sm join-item"></select><select aria-label="Sort direction"class="select select-sm join-item"><option value=asc>Ascending</option><option value=desc>Descending`), _tmpl$3 = /*#__PURE__*/ template(`<th>`), _tmpl$4 = /*#__PURE__*/ template(`<table class="table hidden md:table"><thead><tr></tr></thead><tbody>`), _tmpl$5 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2 md:hidden">`), _tmpl$6 = /*#__PURE__*/ template(`<div class="bg-base-100 sticky bottom-0 flex items-center justify-between gap-2 border-t py-2"><button type=button class="btn btn-sm">Prev</button><span class="text-sm opacity-70">Page </span><button type=button class="btn btn-sm">Next`), _tmpl$7 = /*#__PURE__*/ template(`<div class="flex flex-col gap-3"><div class="flex flex-wrap items-center justify-between gap-2">`), _tmpl$8 = /*#__PURE__*/ template(`<option>`), _tmpl$9 = /*#__PURE__*/ template(`<p class="text-sm opacity-70">No <!> yet.`), _tmpl$0 = /*#__PURE__*/ template(`<td><input type=checkbox class="checkbox checkbox-sm">`), _tmpl$1 = /*#__PURE__*/ template(`<tr>`), _tmpl$10 = /*#__PURE__*/ template(`<td>`), _tmpl$11 = /*#__PURE__*/ template(`<input type=checkbox class="checkbox checkbox-sm mt-1">`), _tmpl$12 = /*#__PURE__*/ template(`<div class="card bg-base-200 cursor-pointer p-3"role=button tabindex=0><div class="flex items-start gap-3"><div class="flex flex-1 flex-col gap-1">`), _tmpl$13 = /*#__PURE__*/ template(`<div class="flex justify-between gap-2 text-sm"><span class=opacity-60></span><span class=text-right>`);
995
+ var _tmpl$$1 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline btn-sm">`), _tmpl$2$1 = /*#__PURE__*/ template(`<div class=join><select aria-label="Sort by"class="select select-sm join-item"></select><select aria-label="Sort direction"class="select select-sm join-item"><option value=asc>Ascending</option><option value=desc>Descending`), _tmpl$3 = /*#__PURE__*/ template(`<table class="table hidden md:table"><thead></thead><tbody>`), _tmpl$4 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2 md:hidden">`), _tmpl$5 = /*#__PURE__*/ template(`<div class="bg-base-100 sticky bottom-0 flex items-center justify-between gap-2 border-t py-2"><button type=button class="btn btn-sm">Prev</button><span class="text-sm opacity-70">Page </span><button type=button class="btn btn-sm">Next`), _tmpl$6 = /*#__PURE__*/ template(`<div class="flex flex-col gap-3"><div class="flex flex-wrap items-center justify-between gap-2">`), _tmpl$7 = /*#__PURE__*/ template(`<option>`), _tmpl$8 = /*#__PURE__*/ template(`<p class="text-sm opacity-70">No <!> yet.`), _tmpl$9 = /*#__PURE__*/ template(`<th>`), _tmpl$0 = /*#__PURE__*/ template(`<tr>`), _tmpl$1 = /*#__PURE__*/ template(`<td><input type=checkbox class="checkbox checkbox-sm">`), _tmpl$10 = /*#__PURE__*/ template(`<td>`), _tmpl$11 = /*#__PURE__*/ template(`<input type=checkbox class="checkbox checkbox-sm mt-1">`), _tmpl$12 = /*#__PURE__*/ template(`<div class="card bg-base-200 cursor-pointer p-3"role=button tabindex=0><div class="flex items-start gap-3"><div class="flex flex-1 flex-col gap-1">`), _tmpl$13 = /*#__PURE__*/ template(`<div class="flex justify-between gap-2 text-sm"><span class=opacity-60></span><span class=text-right>`);
582
996
  function listableFields(config) {
583
997
  const excluded = new Set([
584
998
  "richText",
@@ -596,7 +1010,21 @@ function rowId(row) {
596
1010
  return typeof row.id === "number" ? row.id : void 0;
597
1011
  }
598
1012
  function CollectionList(props) {
599
- const columns = () => listableFields(props.config);
1013
+ const columns = () => listableFields(props.config).map(([key]) => ({
1014
+ id: key,
1015
+ accessorFn: (row) => row[key],
1016
+ header: key,
1017
+ cell: (info) => formatCellValue(info.getValue())
1018
+ }));
1019
+ const table = createSolidTable({
1020
+ get data() {
1021
+ return props.rows;
1022
+ },
1023
+ get columns() {
1024
+ return columns();
1025
+ },
1026
+ getCoreRowModel: getCoreRowModel()
1027
+ });
600
1028
  const [selectMode, setSelectMode] = createSignal(false);
601
1029
  function toggleSelected(id) {
602
1030
  const next = new Set(props.selectedIds ?? []);
@@ -613,7 +1041,7 @@ function CollectionList(props) {
613
1041
  props.onRowClick?.(row);
614
1042
  }
615
1043
  return (() => {
616
- var _el$ = _tmpl$7(), _el$2 = _el$.firstChild;
1044
+ var _el$ = _tmpl$6(), _el$2 = _el$.firstChild;
617
1045
  insert(_el$2, createComponent(Show, {
618
1046
  get when() {
619
1047
  return props.selectable;
@@ -634,16 +1062,16 @@ function CollectionList(props) {
634
1062
  _el$5.addEventListener("change", (e) => props.onSortChange?.(e.currentTarget.value, props.sortDirection ?? "asc"));
635
1063
  insert(_el$5, createComponent(For, {
636
1064
  get each() {
637
- return columns();
1065
+ return table.getAllColumns();
638
1066
  },
639
- children: ([key]) => (() => {
640
- var _el$16 = _tmpl$8();
641
- _el$16.value = key;
642
- insert(_el$16, key);
643
- return _el$16;
1067
+ children: (column) => (() => {
1068
+ var _el$14 = _tmpl$7();
1069
+ insert(_el$14, () => column.id);
1070
+ effect(() => _el$14.value = column.id);
1071
+ return _el$14;
644
1072
  })()
645
1073
  }));
646
- _el$6.addEventListener("change", (e) => props.onSortChange?.(props.sortField ?? columns()[0]?.[0] ?? "", e.currentTarget.value));
1074
+ _el$6.addEventListener("change", (e) => props.onSortChange?.(props.sortField ?? table.getAllColumns()[0]?.id ?? "", e.currentTarget.value));
647
1075
  effect(() => _el$5.value = props.sortField ?? "");
648
1076
  effect(() => _el$6.value = props.sortDirection ?? "asc");
649
1077
  return _el$4;
@@ -655,62 +1083,71 @@ function CollectionList(props) {
655
1083
  },
656
1084
  get fallback() {
657
1085
  return (() => {
658
- var _el$17 = _tmpl$9(), _el$20 = _el$17.firstChild.nextSibling;
659
- _el$20.nextSibling;
660
- insert(_el$17, () => props.config.slug, _el$20);
661
- return _el$17;
1086
+ var _el$15 = _tmpl$8(), _el$18 = _el$15.firstChild.nextSibling;
1087
+ _el$18.nextSibling;
1088
+ insert(_el$15, () => props.config.slug, _el$18);
1089
+ return _el$15;
662
1090
  })();
663
1091
  },
664
1092
  get children() {
665
1093
  return [(() => {
666
- var _el$7 = _tmpl$4(), _el$8 = _el$7.firstChild, _el$9 = _el$8.firstChild, _el$1 = _el$8.nextSibling;
667
- insert(_el$9, createComponent(Show, {
668
- get when() {
669
- return selectMode();
670
- },
671
- get children() {
672
- return _tmpl$3();
673
- }
674
- }), null);
675
- insert(_el$9, createComponent(For, {
1094
+ var _el$7 = _tmpl$3(), _el$8 = _el$7.firstChild, _el$9 = _el$8.nextSibling;
1095
+ insert(_el$8, createComponent(For, {
676
1096
  get each() {
677
- return columns();
1097
+ return table.getHeaderGroups();
678
1098
  },
679
- children: ([key]) => (() => {
680
- var _el$21 = _tmpl$3();
681
- insert(_el$21, key);
682
- return _el$21;
1099
+ children: (headerGroup) => (() => {
1100
+ var _el$19 = _tmpl$0();
1101
+ insert(_el$19, createComponent(Show, {
1102
+ get when() {
1103
+ return selectMode();
1104
+ },
1105
+ get children() {
1106
+ return _tmpl$9();
1107
+ }
1108
+ }), null);
1109
+ insert(_el$19, createComponent(For, {
1110
+ get each() {
1111
+ return headerGroup.headers;
1112
+ },
1113
+ children: (header) => (() => {
1114
+ var _el$21 = _tmpl$9();
1115
+ insert(_el$21, () => flexRender(header.column.columnDef.header, header.getContext()));
1116
+ return _el$21;
1117
+ })()
1118
+ }), null);
1119
+ return _el$19;
683
1120
  })()
684
- }), null);
685
- insert(_el$1, createComponent(For, {
1121
+ }));
1122
+ insert(_el$9, createComponent(For, {
686
1123
  get each() {
687
- return props.rows;
1124
+ return table.getRowModel().rows;
688
1125
  },
689
1126
  children: (row) => (() => {
690
- var _el$22 = _tmpl$1();
691
- _el$22.$$click = () => handleRowActivate(row);
1127
+ var _el$22 = _tmpl$0();
1128
+ _el$22.$$click = () => handleRowActivate(row.original);
692
1129
  insert(_el$22, createComponent(Show, {
693
1130
  get when() {
694
1131
  return selectMode();
695
1132
  },
696
1133
  get children() {
697
- var _el$23 = _tmpl$0(), _el$24 = _el$23.firstChild;
1134
+ var _el$23 = _tmpl$1(), _el$24 = _el$23.firstChild;
698
1135
  _el$24.addEventListener("change", () => {
699
- const id = rowId(row);
1136
+ const id = rowId(row.original);
700
1137
  if (id !== void 0) toggleSelected(id);
701
1138
  });
702
1139
  _el$24.$$click = (e) => e.stopPropagation();
703
- effect(() => _el$24.checked = rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false));
1140
+ effect(() => _el$24.checked = rowId(row.original) !== void 0 && (props.selectedIds?.has(rowId(row.original)) ?? false));
704
1141
  return _el$23;
705
1142
  }
706
1143
  }), null);
707
1144
  insert(_el$22, createComponent(For, {
708
1145
  get each() {
709
- return columns();
1146
+ return row.getVisibleCells();
710
1147
  },
711
- children: ([key]) => (() => {
1148
+ children: (cell) => (() => {
712
1149
  var _el$25 = _tmpl$10();
713
- insert(_el$25, () => formatCellValue(row[key]));
1150
+ insert(_el$25, () => flexRender(cell.column.columnDef.cell, cell.getContext()));
714
1151
  return _el$25;
715
1152
  })()
716
1153
  }), null);
@@ -720,20 +1157,20 @@ function CollectionList(props) {
720
1157
  }));
721
1158
  return _el$7;
722
1159
  })(), (() => {
723
- var _el$10 = _tmpl$5();
724
- insert(_el$10, createComponent(For, {
1160
+ var _el$0 = _tmpl$4();
1161
+ insert(_el$0, createComponent(For, {
725
1162
  get each() {
726
- return props.rows;
1163
+ return table.getRowModel().rows;
727
1164
  },
728
1165
  children: (row) => (() => {
729
1166
  var _el$26 = _tmpl$12(), _el$27 = _el$26.firstChild, _el$29 = _el$27.firstChild;
730
1167
  _el$26.$$keydown = (e) => {
731
1168
  if (e.key === "Enter" || e.key === " ") {
732
1169
  e.preventDefault();
733
- handleRowActivate(row);
1170
+ handleRowActivate(row.original);
734
1171
  }
735
1172
  };
736
- _el$26.$$click = () => handleRowActivate(row);
1173
+ _el$26.$$click = () => handleRowActivate(row.original);
737
1174
  insert(_el$27, createComponent(Show, {
738
1175
  get when() {
739
1176
  return selectMode();
@@ -741,29 +1178,29 @@ function CollectionList(props) {
741
1178
  get children() {
742
1179
  var _el$28 = _tmpl$11();
743
1180
  _el$28.addEventListener("change", () => {
744
- const id = rowId(row);
1181
+ const id = rowId(row.original);
745
1182
  if (id !== void 0) toggleSelected(id);
746
1183
  });
747
1184
  _el$28.$$click = (e) => e.stopPropagation();
748
- effect(() => _el$28.checked = rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false));
1185
+ effect(() => _el$28.checked = rowId(row.original) !== void 0 && (props.selectedIds?.has(rowId(row.original)) ?? false));
749
1186
  return _el$28;
750
1187
  }
751
1188
  }), _el$29);
752
1189
  insert(_el$29, createComponent(For, {
753
1190
  get each() {
754
- return columns();
1191
+ return row.getVisibleCells();
755
1192
  },
756
- children: ([key]) => (() => {
1193
+ children: (cell) => (() => {
757
1194
  var _el$30 = _tmpl$13(), _el$31 = _el$30.firstChild, _el$32 = _el$31.nextSibling;
758
- insert(_el$31, key);
759
- insert(_el$32, () => formatCellValue(row[key]));
1195
+ insert(_el$31, () => cell.column.id);
1196
+ insert(_el$32, () => flexRender(cell.column.columnDef.cell, cell.getContext()));
760
1197
  return _el$30;
761
1198
  })()
762
1199
  }));
763
1200
  return _el$26;
764
1201
  })()
765
1202
  }));
766
- return _el$10;
1203
+ return _el$0;
767
1204
  })()];
768
1205
  }
769
1206
  }), null);
@@ -772,22 +1209,22 @@ function CollectionList(props) {
772
1209
  return memo(() => props.page !== void 0)() && props.pageSize !== void 0;
773
1210
  },
774
1211
  get children() {
775
- var _el$11 = _tmpl$6(), _el$12 = _el$11.firstChild, _el$13 = _el$12.nextSibling;
776
- _el$13.firstChild;
777
- var _el$15 = _el$13.nextSibling;
778
- _el$12.$$click = () => props.onPageChange?.((props.page ?? 1) - 1);
779
- insert(_el$13, () => props.page, null);
780
- _el$15.$$click = () => props.onPageChange?.((props.page ?? 1) + 1);
1212
+ var _el$1 = _tmpl$5(), _el$10 = _el$1.firstChild, _el$11 = _el$10.nextSibling;
1213
+ _el$11.firstChild;
1214
+ var _el$13 = _el$11.nextSibling;
1215
+ _el$10.$$click = () => props.onPageChange?.((props.page ?? 1) - 1);
1216
+ insert(_el$11, () => props.page, null);
1217
+ _el$13.$$click = () => props.onPageChange?.((props.page ?? 1) + 1);
781
1218
  effect((_p$) => {
782
1219
  var _v$ = (props.page ?? 1) <= 1, _v$2 = props.totalCount !== void 0 ? (props.page ?? 1) * (props.pageSize ?? 0) >= props.totalCount : props.rows.length < (props.pageSize ?? 0);
783
- _v$ !== _p$.e && (_el$12.disabled = _p$.e = _v$);
784
- _v$2 !== _p$.t && (_el$15.disabled = _p$.t = _v$2);
1220
+ _v$ !== _p$.e && (_el$10.disabled = _p$.e = _v$);
1221
+ _v$2 !== _p$.t && (_el$13.disabled = _p$.t = _v$2);
785
1222
  return _p$;
786
1223
  }, {
787
1224
  e: void 0,
788
1225
  t: void 0
789
1226
  });
790
- return _el$11;
1227
+ return _el$1;
791
1228
  }
792
1229
  }), null);
793
1230
  return _el$;