@thebes/cadmea 1.1.0 → 1.2.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,40 +1,79 @@
1
1
  import { className, createComponent, delegateEvents, effect, insert, memo, setAttribute, setStyleProperty, template, use } from "solid-js/web";
2
- import { For, Show, Suspense, createEffect, createMemo, createSignal, lazy, onCleanup, onMount } from "solid-js";
3
- import { VISUAL_EDIT_MESSAGE } from "@thebes/cadmus/cms";
2
+ import { createForm } from "@tanstack/solid-form";
3
+ import { VISUAL_EDIT_MESSAGE, validateDocument } from "@thebes/cadmus/cms";
4
+ import { For, Index, Show, Suspense, createEffect, createMemo, createSignal, lazy, onCleanup, onMount } from "solid-js";
5
+ import { createSolidTable, flexRender, getCoreRowModel } from "@tanstack/solid-table";
4
6
  //#region src/CollectionEdit.tsx
5
- 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$3 = /*#__PURE__*/ template(`<button type=button class="btn flex-1">`), _tmpl$4$3 = /*#__PURE__*/ template(`<button type=button class="btn btn-primary flex-1">`), _tmpl$5$2 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline flex-1">`), _tmpl$6$2 = /*#__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
+ 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$3 = /*#__PURE__*/ template(`<button type=button class="btn flex-1">`), _tmpl$4$3 = /*#__PURE__*/ template(`<button type=button class="btn btn-primary flex-1">`), _tmpl$5$2 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline flex-1">`), _tmpl$6$2 = /*#__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">`);
6
8
  const RichTextEditor = lazy(() => import("../RichTextEditor-BPilh7Pw.js").then((mod) => ({ default: mod.RichTextEditor })));
7
9
  function editableFields(config) {
8
10
  return Object.entries(config.fields).filter(([key]) => key !== "id");
9
11
  }
10
- function CollectionEdit(props) {
11
- const initialSnapshot = JSON.stringify(props.initialValues ?? {});
12
- const [values, setValues] = createSignal(props.initialValues ?? {});
13
- createEffect(() => {
14
- props.onDirtyChange?.(JSON.stringify(values()) !== initialSnapshot);
15
- });
16
- function setField(key, value) {
17
- setValues((prev) => ({
18
- ...prev,
19
- [key]: value
20
- }));
12
+ function humanize(key) {
13
+ const spaced = key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
14
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();
15
+ }
16
+ function labelFor(key, field) {
17
+ return field.admin?.label ?? humanize(key);
18
+ }
19
+ function groupFields(entries) {
20
+ const groups = [];
21
+ const byName = /* @__PURE__ */ new Map();
22
+ for (const entry of entries) {
23
+ const name = entry[1].admin?.group;
24
+ let group = byName.get(name);
25
+ if (!group) {
26
+ group = {
27
+ name,
28
+ fields: []
29
+ };
30
+ byName.set(name, group);
31
+ groups.push(group);
32
+ }
33
+ group.fields.push(entry);
21
34
  }
22
- function editablePayload() {
23
- return Object.fromEntries(Object.entries(values()).filter(([key]) => props.config.fields[key]?.type !== "date"));
35
+ return groups;
36
+ }
37
+ function CollectionEdit(props) {
38
+ const operation = props.initialValues?.id != null ? "update" : "create";
39
+ async function validateForm(value) {
40
+ const violations = await validateDocument(props.config, value, { operation });
41
+ const fields = {};
42
+ for (const v of violations) if (v.severity === "error" && !(v.path in fields)) fields[v.path] = v.message;
43
+ return Object.keys(fields).length > 0 ? { fields } : void 0;
24
44
  }
25
- function handleSubmit(event) {
26
- event.preventDefault();
27
- props.onSubmit(editablePayload());
45
+ const form = createForm(() => ({
46
+ defaultValues: props.initialValues ?? {},
47
+ validators: { onSubmitAsync: ({ value }) => validateForm(value) },
48
+ onSubmit: async ({ value }) => {
49
+ await props.onSubmit(editablePayload(value));
50
+ }
51
+ }));
52
+ const isDefaultValue = form.useStore((s) => s.isDefaultValue);
53
+ createEffect(() => props.onDirtyChange?.(!isDefaultValue()));
54
+ const formValues = form.useStore((s) => s.values);
55
+ function editablePayload(value) {
56
+ return Object.fromEntries(Object.entries(value).filter(([key]) => props.config.fields[key]?.type !== "date"));
28
57
  }
29
58
  const ctx = {
30
- onUploadFile: props.onUploadFile,
31
- relationshipOptions: props.relationshipOptions,
32
- fieldWidgets: props.fieldWidgets
59
+ get onUploadFile() {
60
+ return props.onUploadFile;
61
+ },
62
+ get relationshipOptions() {
63
+ return props.relationshipOptions;
64
+ },
65
+ get fieldWidgets() {
66
+ return props.fieldWidgets;
67
+ }
33
68
  };
69
+ const fieldGroups = groupFields(editableFields(props.config));
34
70
  const versioned = () => props.config.versions?.drafts && props.draftActions;
35
71
  return (() => {
36
72
  var _el$ = _tmpl$6$2(), _el$3 = _el$.firstChild;
37
- _el$.addEventListener("submit", handleSubmit);
73
+ _el$.addEventListener("submit", (event) => {
74
+ event.preventDefault();
75
+ form.handleSubmit();
76
+ });
38
77
  insert(_el$, createComponent(Show, {
39
78
  get when() {
40
79
  return props.error;
@@ -46,24 +85,35 @@ function CollectionEdit(props) {
46
85
  }
47
86
  }), _el$3);
48
87
  insert(_el$, createComponent(For, {
49
- get each() {
50
- return editableFields(props.config);
51
- },
52
- children: ([key, field]) => (() => {
53
- var _el$0 = _tmpl$8$1(), _el$1 = _el$0.firstChild;
54
- setAttribute(_el$1, "for", key);
55
- insert(_el$1, key, null);
56
- insert(_el$1, createComponent(Show, {
57
- get when() {
58
- return field.required;
59
- },
60
- get children() {
61
- return _tmpl$7$1();
62
- }
63
- }), null);
64
- insert(_el$0, () => renderInput(key, field, values()[key], setField, ctx), null);
65
- return _el$0;
66
- })()
88
+ each: fieldGroups,
89
+ children: (group) => createComponent(Show, {
90
+ get when() {
91
+ return group.name;
92
+ },
93
+ get fallback() {
94
+ return createComponent(FieldsGrid, {
95
+ form,
96
+ ctx,
97
+ get fields() {
98
+ return group.fields;
99
+ },
100
+ values: formValues
101
+ });
102
+ },
103
+ get children() {
104
+ var _el$0 = _tmpl$7$1(), _el$1 = _el$0.firstChild;
105
+ insert(_el$1, () => group.name);
106
+ insert(_el$0, createComponent(FieldsGrid, {
107
+ form,
108
+ ctx,
109
+ get fields() {
110
+ return group.fields;
111
+ },
112
+ values: formValues
113
+ }), null);
114
+ return _el$0;
115
+ }
116
+ })
67
117
  }), _el$3);
68
118
  insert(_el$3, createComponent(Show, {
69
119
  get when() {
@@ -75,8 +125,9 @@ function CollectionEdit(props) {
75
125
  return props.capabilities?.canUpdate !== false;
76
126
  },
77
127
  get children() {
78
- var _el$11 = _tmpl$9$1();
79
- insert(_el$11, createComponent(Show, {
128
+ var _el$10 = _tmpl$4$3();
129
+ _el$10.$$click = () => void form.handleSubmit();
130
+ insert(_el$10, createComponent(Show, {
80
131
  get when() {
81
132
  return props.saving;
82
133
  },
@@ -87,8 +138,8 @@ function CollectionEdit(props) {
87
138
  return _tmpl$2$3();
88
139
  }
89
140
  }));
90
- effect(() => _el$11.disabled = props.saving);
91
- return _el$11;
141
+ effect(() => _el$10.disabled = props.saving);
142
+ return _el$10;
92
143
  }
93
144
  });
94
145
  },
@@ -96,7 +147,7 @@ function CollectionEdit(props) {
96
147
  return [
97
148
  (() => {
98
149
  var _el$4 = _tmpl$3$3();
99
- _el$4.$$click = () => void props.draftActions?.onSaveDraft(editablePayload());
150
+ _el$4.$$click = () => void props.draftActions?.onSaveDraft(editablePayload(formValues()));
100
151
  insert(_el$4, createComponent(Show, {
101
152
  get when() {
102
153
  return props.draftActions?.saving;
@@ -156,98 +207,201 @@ function CollectionEdit(props) {
156
207
  return _el$;
157
208
  })();
158
209
  }
159
- function renderInput(key, field, value, setField, ctx) {
160
- const Widget = ctx.fieldWidgets?.[key];
210
+ function FieldsGrid(props) {
211
+ return (() => {
212
+ var _el$12 = _tmpl$8$1();
213
+ insert(_el$12, createComponent(For, {
214
+ get each() {
215
+ return props.fields;
216
+ },
217
+ children: ([key, field]) => createComponent(Show, {
218
+ get when() {
219
+ return !field.admin?.condition || field.admin.condition(props.values());
220
+ },
221
+ get children() {
222
+ return renderField(props.form, props.ctx, key, field, labelFor(key, field));
223
+ }
224
+ })
225
+ }));
226
+ return _el$12;
227
+ })();
228
+ }
229
+ function renderField(form, ctx, name, field, label) {
230
+ if (field.type === "array") return renderArray(form, ctx, name, field, label);
231
+ const spanClass = field.admin?.width === "half" ? "md:col-span-1" : "md:col-span-2";
232
+ return createComponent(form.Field, {
233
+ name,
234
+ children: (fieldApi) => (() => {
235
+ var _el$13 = _tmpl$10$1(), _el$14 = _el$13.firstChild;
236
+ className(_el$13, `form-control ${spanClass}`);
237
+ setAttribute(_el$14, "for", name);
238
+ insert(_el$14, label, null);
239
+ insert(_el$14, createComponent(Show, {
240
+ get when() {
241
+ return field.required;
242
+ },
243
+ get children() {
244
+ return _tmpl$9$1();
245
+ }
246
+ }), null);
247
+ insert(_el$13, createComponent(Show, {
248
+ get when() {
249
+ return field.admin?.description;
250
+ },
251
+ get children() {
252
+ var _el$16 = _tmpl$0$1();
253
+ insert(_el$16, () => field.admin?.description);
254
+ return _el$16;
255
+ }
256
+ }), null);
257
+ insert(_el$13, () => renderControl(ctx, name, field, fieldApi), null);
258
+ insert(_el$13, createComponent(Show, {
259
+ get when() {
260
+ return (fieldApi().state.meta.errors?.length ?? 0) > 0;
261
+ },
262
+ get children() {
263
+ var _el$17 = _tmpl$1$1();
264
+ insert(_el$17, () => fieldApi().state.meta.errors.filter(Boolean).join(", "));
265
+ return _el$17;
266
+ }
267
+ }), null);
268
+ return _el$13;
269
+ })()
270
+ });
271
+ }
272
+ function renderControl(ctx, name, field, fieldApi) {
273
+ const Widget = ctx.fieldWidgets?.[name] ?? ctx.fieldWidgets?.[name.slice(name.lastIndexOf(".") + 1)];
161
274
  if (Widget) return createComponent(Widget, {
162
- fieldKey: key,
163
- value,
164
- setValue: (v) => setField(key, v),
275
+ fieldKey: name,
276
+ get value() {
277
+ return fieldApi().state.value;
278
+ },
279
+ setValue: (v) => fieldApi().handleChange(v),
165
280
  get onUploadFile() {
166
281
  return ctx.onUploadFile;
167
282
  }
168
283
  });
284
+ const readOnly = field.admin?.readOnly;
285
+ const change = (v) => fieldApi().handleChange(v);
169
286
  switch (field.type) {
170
287
  case "text": return (() => {
171
- var _el$13 = _tmpl$0$1();
172
- _el$13.$$input = (e) => setField(key, e.currentTarget.value);
173
- setAttribute(_el$13, "id", key);
174
- _el$13.value = value ?? "";
175
- effect(() => _el$13.required = field.required);
176
- return _el$13;
288
+ var _el$18 = _tmpl$11$1();
289
+ _el$18.addEventListener("blur", () => fieldApi().handleBlur());
290
+ _el$18.$$input = (e) => change(e.currentTarget.value);
291
+ setAttribute(_el$18, "id", name);
292
+ _el$18.readOnly = readOnly;
293
+ effect((_p$) => {
294
+ var _v$ = field.admin?.placeholder, _v$2 = field.required;
295
+ _v$ !== _p$.e && setAttribute(_el$18, "placeholder", _p$.e = _v$);
296
+ _v$2 !== _p$.t && (_el$18.required = _p$.t = _v$2);
297
+ return _p$;
298
+ }, {
299
+ e: void 0,
300
+ t: void 0
301
+ });
302
+ effect(() => _el$18.value = fieldApi().state.value ?? "");
303
+ return _el$18;
177
304
  })();
178
305
  case "select": return (() => {
179
- var _el$14 = _tmpl$1$1();
180
- _el$14.addEventListener("change", (e) => setField(key, e.currentTarget.value));
181
- setAttribute(_el$14, "id", key);
182
- _el$14.value = value ?? "";
183
- insert(_el$14, createComponent(For, {
306
+ var _el$19 = _tmpl$12$1();
307
+ _el$19.addEventListener("blur", () => fieldApi().handleBlur());
308
+ _el$19.addEventListener("change", (e) => change(e.currentTarget.value));
309
+ setAttribute(_el$19, "id", name);
310
+ _el$19.disabled = readOnly;
311
+ insert(_el$19, createComponent(For, {
184
312
  get each() {
185
313
  return field.options;
186
314
  },
187
315
  children: (option) => (() => {
188
- var _el$15 = _tmpl$10$1();
189
- _el$15.value = option;
190
- insert(_el$15, option);
191
- return _el$15;
316
+ var _el$20 = _tmpl$13$1();
317
+ _el$20.value = option;
318
+ insert(_el$20, option);
319
+ return _el$20;
192
320
  })()
193
321
  }));
194
- effect(() => _el$14.required = field.required);
195
- return _el$14;
322
+ effect(() => _el$19.required = field.required);
323
+ effect(() => _el$19.value = fieldApi().state.value ?? "");
324
+ return _el$19;
196
325
  })();
197
326
  case "number": return (() => {
198
- var _el$16 = _tmpl$11$1();
199
- _el$16.$$input = (e) => setField(key, e.currentTarget.valueAsNumber);
200
- setAttribute(_el$16, "id", key);
201
- _el$16.value = value ?? "";
202
- effect(() => _el$16.required = field.required);
203
- return _el$16;
327
+ var _el$21 = _tmpl$14();
328
+ _el$21.addEventListener("blur", () => fieldApi().handleBlur());
329
+ _el$21.$$input = (e) => change(e.currentTarget.valueAsNumber);
330
+ setAttribute(_el$21, "id", name);
331
+ _el$21.readOnly = readOnly;
332
+ effect((_p$) => {
333
+ var _v$3 = field.admin?.placeholder, _v$4 = field.required;
334
+ _v$3 !== _p$.e && setAttribute(_el$21, "placeholder", _p$.e = _v$3);
335
+ _v$4 !== _p$.t && (_el$21.required = _p$.t = _v$4);
336
+ return _p$;
337
+ }, {
338
+ e: void 0,
339
+ t: void 0
340
+ });
341
+ effect(() => _el$21.value = fieldApi().state.value ?? "");
342
+ return _el$21;
204
343
  })();
205
344
  case "date": return (() => {
206
- var _el$17 = _tmpl$12$1();
207
- setAttribute(_el$17, "id", key);
208
- effect(() => _el$17.value = formatDateValue(value));
209
- return _el$17;
345
+ var _el$22 = _tmpl$15();
346
+ setAttribute(_el$22, "id", name);
347
+ effect(() => _el$22.value = formatDateValue(fieldApi().state.value));
348
+ return _el$22;
210
349
  })();
211
350
  case "checkbox": return (() => {
212
- var _el$18 = _tmpl$13$1();
213
- _el$18.addEventListener("change", (e) => setField(key, e.currentTarget.checked));
214
- setAttribute(_el$18, "id", key);
215
- _el$18.checked = value ?? false;
216
- return _el$18;
351
+ var _el$23 = _tmpl$16();
352
+ _el$23.addEventListener("change", (e) => change(e.currentTarget.checked));
353
+ setAttribute(_el$23, "id", name);
354
+ _el$23.disabled = readOnly;
355
+ effect(() => _el$23.checked = fieldApi().state.value ?? false);
356
+ return _el$23;
217
357
  })();
218
- case "upload": return renderUploadInput(key, field, value, setField, ctx);
219
- case "relationship": return renderRelationshipInput(key, field, value, setField, ctx);
220
- case "array": return renderArrayInput(key, field, value, setField, ctx);
358
+ case "upload": return createComponent(UploadControl, {
359
+ name,
360
+ field,
361
+ fieldApi,
362
+ ctx
363
+ });
364
+ case "relationship": return createComponent(RelationshipField, {
365
+ name,
366
+ field,
367
+ fieldApi,
368
+ get options() {
369
+ return ctx.relationshipOptions?.[field.relationTo] ?? [];
370
+ }
371
+ });
221
372
  case "richText": return createComponent(Suspense, {
222
373
  get fallback() {
223
374
  return _tmpl$2$3();
224
375
  },
225
376
  get children() {
226
377
  return createComponent(RichTextEditor, {
227
- id: key,
228
- content: value,
229
- onChange: (doc) => setField(key, doc)
378
+ id: name,
379
+ get content() {
380
+ return fieldApi().state.value;
381
+ },
382
+ onChange: (doc) => change(doc)
230
383
  });
231
384
  }
232
385
  });
233
386
  default: return null;
234
387
  }
235
388
  }
236
- function renderUploadInput(key, field, value, setField, ctx) {
389
+ function UploadControl(props) {
237
390
  const [uploading, setUploading] = createSignal(false);
238
391
  const [uploadError, setUploadError] = createSignal();
392
+ const value = () => props.fieldApi().state.value;
239
393
  async function handleFileChange(e) {
240
394
  const file = e.currentTarget.files?.[0];
241
395
  if (!file) return;
242
- if (!ctx.onUploadFile) {
396
+ if (!props.ctx.onUploadFile) {
243
397
  setUploadError("No upload handler configured for this form.");
244
398
  return;
245
399
  }
246
400
  setUploading(true);
247
401
  setUploadError(void 0);
248
402
  try {
249
- const { url } = await ctx.onUploadFile(file);
250
- setField(key, url);
403
+ const { url } = await props.ctx.onUploadFile(file);
404
+ props.fieldApi().handleChange(url);
251
405
  } catch (err) {
252
406
  setUploadError(err instanceof Error ? err.message : "Upload failed");
253
407
  } finally {
@@ -255,18 +409,19 @@ function renderUploadInput(key, field, value, setField, ctx) {
255
409
  }
256
410
  }
257
411
  return (() => {
258
- var _el$20 = _tmpl$16(), _el$22 = _el$20.firstChild;
259
- insert(_el$20, createComponent(Show, {
260
- when: value,
412
+ var _el$25 = _tmpl$19(), _el$27 = _el$25.firstChild;
413
+ insert(_el$25, createComponent(Show, {
414
+ get when() {
415
+ return value();
416
+ },
261
417
  get children() {
262
- var _el$21 = _tmpl$14();
263
- insert(_el$21, value);
264
- return _el$21;
418
+ var _el$26 = _tmpl$17();
419
+ insert(_el$26, value);
420
+ return _el$26;
265
421
  }
266
- }), _el$22);
267
- _el$22.addEventListener("change", handleFileChange);
268
- setAttribute(_el$22, "id", key);
269
- insert(_el$20, createComponent(Show, {
422
+ }), _el$27);
423
+ _el$27.addEventListener("change", handleFileChange);
424
+ insert(_el$25, createComponent(Show, {
270
425
  get when() {
271
426
  return uploading();
272
427
  },
@@ -274,124 +429,379 @@ function renderUploadInput(key, field, value, setField, ctx) {
274
429
  return _tmpl$2$3();
275
430
  }
276
431
  }), null);
277
- insert(_el$20, createComponent(Show, {
432
+ insert(_el$25, createComponent(Show, {
278
433
  get when() {
279
434
  return uploadError();
280
435
  },
281
436
  get children() {
282
- var _el$24 = _tmpl$15();
283
- insert(_el$24, uploadError);
284
- return _el$24;
437
+ var _el$29 = _tmpl$18();
438
+ insert(_el$29, uploadError);
439
+ return _el$29;
285
440
  }
286
441
  }), null);
287
442
  effect((_p$) => {
288
- var _v$ = field.required && !value, _v$2 = uploading();
289
- _v$ !== _p$.e && (_el$22.required = _p$.e = _v$);
290
- _v$2 !== _p$.t && (_el$22.disabled = _p$.t = _v$2);
443
+ var _v$5 = props.name, _v$6 = props.field.required && !value(), _v$7 = uploading() || props.field.admin?.readOnly;
444
+ _v$5 !== _p$.e && setAttribute(_el$27, "id", _p$.e = _v$5);
445
+ _v$6 !== _p$.t && (_el$27.required = _p$.t = _v$6);
446
+ _v$7 !== _p$.a && (_el$27.disabled = _p$.a = _v$7);
291
447
  return _p$;
292
448
  }, {
293
449
  e: void 0,
294
- t: void 0
450
+ t: void 0,
451
+ a: void 0
295
452
  });
296
- return _el$20;
453
+ return _el$25;
297
454
  })();
298
455
  }
299
- function renderRelationshipInput(key, field, value, setField, ctx) {
300
- if (field.hasMany) return null;
301
- const options = ctx.relationshipOptions?.[field.relationTo] ?? [];
456
+ function RelationshipField(props) {
457
+ const [query, setQuery] = createSignal("");
458
+ const [open, setOpen] = createSignal(false);
459
+ const [active, setActive] = createSignal(0);
460
+ const listId = `${props.name}-listbox`;
461
+ const isMulti = () => props.field.hasMany === true;
462
+ const value = () => props.fieldApi().state.value;
463
+ const selectedIds = () => {
464
+ const v = value();
465
+ if (isMulti()) return Array.isArray(v) ? v : [];
466
+ return v != null ? [v] : [];
467
+ };
468
+ const selectedOptions = () => props.options.filter((o) => selectedIds().includes(o.id));
469
+ const filtered = () => {
470
+ const q = query().toLowerCase();
471
+ return props.options.filter((o) => o.label.toLowerCase().includes(q) && (!isMulti() || !selectedIds().includes(o.id)));
472
+ };
473
+ const singleLabel = () => selectedOptions()[0]?.label ?? "";
474
+ function choose(option) {
475
+ if (isMulti()) {
476
+ props.fieldApi().handleChange([...selectedIds(), option.id]);
477
+ setQuery("");
478
+ } else {
479
+ props.fieldApi().handleChange(option.id);
480
+ setQuery("");
481
+ setOpen(false);
482
+ }
483
+ setActive(0);
484
+ }
485
+ function removeId(id) {
486
+ if (isMulti()) props.fieldApi().handleChange(selectedIds().filter((x) => x !== id));
487
+ else props.fieldApi().handleChange(null);
488
+ }
489
+ function onKeyDown(e) {
490
+ if (e.key === "ArrowDown") {
491
+ e.preventDefault();
492
+ setOpen(true);
493
+ setActive((a) => Math.min(a + 1, filtered().length - 1));
494
+ } else if (e.key === "ArrowUp") {
495
+ e.preventDefault();
496
+ setActive((a) => Math.max(a - 1, 0));
497
+ } else if (e.key === "Enter") {
498
+ e.preventDefault();
499
+ const option = filtered()[active()];
500
+ if (option) choose(option);
501
+ } else if (e.key === "Escape") setOpen(false);
502
+ else if (e.key === "Backspace" && isMulti() && query() === "") {
503
+ const ids = selectedIds();
504
+ if (ids.length > 0) removeId(ids[ids.length - 1]);
505
+ }
506
+ }
302
507
  return (() => {
303
- var _el$25 = _tmpl$17();
304
- _el$25.firstChild;
305
- _el$25.addEventListener("change", (e) => setField(key, e.currentTarget.value === "" ? null : Number(e.currentTarget.value)));
306
- setAttribute(_el$25, "id", key);
307
- insert(_el$25, createComponent(For, {
308
- each: options,
309
- children: (option) => (() => {
310
- var _el$27 = _tmpl$10$1();
311
- insert(_el$27, () => option.label);
312
- effect(() => _el$27.value = option.id);
313
- return _el$27;
314
- })()
508
+ var _el$30 = _tmpl$23(), _el$32 = _el$30.firstChild;
509
+ insert(_el$30, createComponent(Show, {
510
+ get when() {
511
+ return memo(() => !!isMulti())() && selectedOptions().length > 0;
512
+ },
513
+ get children() {
514
+ var _el$31 = _tmpl$20();
515
+ insert(_el$31, createComponent(For, {
516
+ get each() {
517
+ return selectedOptions();
518
+ },
519
+ children: (option) => (() => {
520
+ var _el$35 = _tmpl$24(), _el$36 = _el$35.firstChild;
521
+ insert(_el$35, () => option.label, _el$36);
522
+ _el$36.$$click = () => removeId(option.id);
523
+ effect(() => setAttribute(_el$36, "aria-label", `Remove ${option.label}`));
524
+ return _el$35;
525
+ })()
526
+ }));
527
+ return _el$31;
528
+ }
529
+ }), _el$32);
530
+ _el$32.$$keydown = onKeyDown;
531
+ _el$32.addEventListener("blur", () => setTimeout(() => setOpen(false), 120));
532
+ _el$32.addEventListener("focus", () => setOpen(true));
533
+ _el$32.$$input = (e) => {
534
+ setQuery(e.currentTarget.value);
535
+ setOpen(true);
536
+ setActive(0);
537
+ };
538
+ setAttribute(_el$32, "aria-controls", listId);
539
+ insert(_el$30, createComponent(Show, {
540
+ get when() {
541
+ return memo(() => !!(!isMulti() && value() != null))() && !props.field.required;
542
+ },
543
+ get children() {
544
+ var _el$33 = _tmpl$21();
545
+ _el$33.$$click = () => removeId(value());
546
+ _el$33.$$mousedown = (e) => e.preventDefault();
547
+ return _el$33;
548
+ }
315
549
  }), null);
316
- effect(() => _el$25.required = field.required);
317
- effect(() => _el$25.value = value != null ? String(value) : "");
318
- return _el$25;
550
+ insert(_el$30, createComponent(Show, {
551
+ get when() {
552
+ return memo(() => !!open())() && filtered().length > 0;
553
+ },
554
+ get children() {
555
+ var _el$34 = _tmpl$22();
556
+ setAttribute(_el$34, "id", listId);
557
+ insert(_el$34, createComponent(For, {
558
+ get each() {
559
+ return filtered();
560
+ },
561
+ children: (option, i) => (() => {
562
+ var _el$37 = _tmpl$25();
563
+ _el$37.$$click = () => choose(option);
564
+ _el$37.$$mousedown = (e) => e.preventDefault();
565
+ insert(_el$37, () => option.label);
566
+ effect((_p$) => {
567
+ var _v$11 = selectedIds().includes(option.id), _v$12 = !!(i() === active());
568
+ _v$11 !== _p$.e && setAttribute(_el$37, "aria-selected", _p$.e = _v$11);
569
+ _v$12 !== _p$.t && _el$37.classList.toggle("bg-base-200", _p$.t = _v$12);
570
+ return _p$;
571
+ }, {
572
+ e: void 0,
573
+ t: void 0
574
+ });
575
+ return _el$37;
576
+ })()
577
+ }));
578
+ return _el$34;
579
+ }
580
+ }), null);
581
+ effect((_p$) => {
582
+ 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…";
583
+ _v$8 !== _p$.e && setAttribute(_el$32, "id", _p$.e = _v$8);
584
+ _v$9 !== _p$.t && setAttribute(_el$32, "aria-expanded", _p$.t = _v$9);
585
+ _v$0 !== _p$.a && (_el$32.required = _p$.a = _v$0);
586
+ _v$1 !== _p$.o && (_el$32.disabled = _p$.o = _v$1);
587
+ _v$10 !== _p$.i && setAttribute(_el$32, "placeholder", _p$.i = _v$10);
588
+ return _p$;
589
+ }, {
590
+ e: void 0,
591
+ t: void 0,
592
+ a: void 0,
593
+ o: void 0,
594
+ i: void 0
595
+ });
596
+ effect(() => _el$32.value = open() || isMulti() ? query() : singleLabel());
597
+ return _el$30;
319
598
  })();
320
599
  }
321
- function renderArrayInput(key, field, value, setField, ctx) {
322
- const items = () => Array.isArray(value) ? value : [];
323
- function updateItem(index, itemKey, itemValue) {
324
- const next = items().slice();
325
- next[index] = {
326
- ...next[index],
327
- [itemKey]: itemValue
328
- };
329
- setField(key, next);
600
+ function renderArray(form, ctx, name, field, label) {
601
+ return createComponent(form.Field, {
602
+ name,
603
+ mode: "array",
604
+ children: (fieldApi) => createComponent(BlockEditor, {
605
+ form,
606
+ ctx,
607
+ name,
608
+ field,
609
+ label,
610
+ fieldApi
611
+ })
612
+ });
613
+ }
614
+ function variantLabel(disc, variant) {
615
+ return disc.variantsAdmin?.[variant]?.label ?? humanize(variant);
616
+ }
617
+ function BlockEditor(props) {
618
+ const [collapsed, setCollapsed] = createSignal(/* @__PURE__ */ new Set());
619
+ const [menuOpen, setMenuOpen] = createSignal(false);
620
+ const disc = props.field.discriminator;
621
+ const variants = disc ? Object.keys(disc.variants) : [];
622
+ const items = () => Array.isArray(props.fieldApi().state.value) ? props.fieldApi().state.value : [];
623
+ function addBlock(variant) {
624
+ const seed = variant && disc ? { [disc.key]: variant } : {};
625
+ props.fieldApi().pushValue(seed);
626
+ setMenuOpen(false);
627
+ }
628
+ function duplicate(index) {
629
+ props.fieldApi().insertValue(index + 1, { ...items()[index] });
330
630
  }
331
- function addItem() {
332
- setField(key, [...items(), {}]);
631
+ function move(from, to) {
632
+ if (to < 0 || to >= items().length) return;
633
+ props.fieldApi().moveValue(from, to);
333
634
  }
334
- function removeItem(index) {
335
- setField(key, items().filter((_, i) => i !== index));
635
+ function toggleCollapse(index) {
636
+ setCollapsed((prev) => {
637
+ const next = new Set(prev);
638
+ if (next.has(index)) next.delete(index);
639
+ else next.add(index);
640
+ return next;
641
+ });
336
642
  }
337
- function fieldsForItem(item) {
338
- const base = Object.entries(field.fields);
339
- const discriminator = field.discriminator;
340
- if (!discriminator) return base;
341
- const variantValue = item[discriminator.key];
342
- const variantFields = typeof variantValue === "string" ? discriminator.variants[variantValue] : void 0;
343
- return variantFields ? [...base, ...Object.entries(variantFields)] : base;
643
+ function blockTitle(item) {
644
+ if (disc) {
645
+ const v = item[disc.key];
646
+ if (typeof v === "string") return variantLabel(disc, v);
647
+ }
648
+ return props.label;
649
+ }
650
+ function blockSummary(item) {
651
+ for (const [key, f] of fieldsForItem(props.field, item)) {
652
+ if (key === disc?.key) continue;
653
+ if ((f.type === "text" || f.type === "select") && item[key]) return String(item[key]);
654
+ }
655
+ return "";
344
656
  }
345
657
  return (() => {
346
- var _el$28 = _tmpl$18(), _el$29 = _el$28.firstChild;
347
- _el$29.firstChild;
348
- insert(_el$28, createComponent(For, {
658
+ var _el$38 = _tmpl$28(), _el$39 = _el$38.firstChild, _el$42 = _el$39.nextSibling;
659
+ insert(_el$39, () => props.label, null);
660
+ insert(_el$39, createComponent(Show, {
661
+ get when() {
662
+ return props.field.required;
663
+ },
664
+ get children() {
665
+ return _tmpl$9$1();
666
+ }
667
+ }), null);
668
+ insert(_el$38, createComponent(Show, {
669
+ get when() {
670
+ return props.field.admin?.description;
671
+ },
672
+ get children() {
673
+ var _el$41 = _tmpl$0$1();
674
+ insert(_el$41, () => props.field.admin?.description);
675
+ return _el$41;
676
+ }
677
+ }), _el$42);
678
+ insert(_el$42, createComponent(Index, {
349
679
  get each() {
350
680
  return items();
351
681
  },
352
- children: (item, index) => (() => {
353
- var _el$31 = _tmpl$19(), _el$32 = _el$31.firstChild;
354
- insert(_el$31, createComponent(For, {
355
- get each() {
356
- return fieldsForItem(item);
357
- },
358
- children: ([itemKey, itemField]) => {
359
- const inputId = `${key}.${index()}.${itemKey}`;
360
- return (() => {
361
- var _el$33 = _tmpl$8$1(), _el$34 = _el$33.firstChild;
362
- setAttribute(_el$34, "for", inputId);
363
- insert(_el$34, itemKey, null);
364
- insert(_el$34, createComponent(Show, {
365
- get when() {
366
- return itemField.required;
682
+ children: (item, index) => {
683
+ const isCollapsed = () => collapsed().has(index);
684
+ return (() => {
685
+ 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;
686
+ _el$48.$$click = () => toggleCollapse(index);
687
+ insert(_el$49, () => isCollapsed() ? "▸" : "▾");
688
+ insert(_el$50, () => blockTitle(item()));
689
+ insert(_el$47, createComponent(Show, {
690
+ get when() {
691
+ return memo(() => !!isCollapsed())() && blockSummary(item());
692
+ },
693
+ get children() {
694
+ var _el$51 = _tmpl$29();
695
+ insert(_el$51, () => blockSummary(item()));
696
+ return _el$51;
697
+ }
698
+ }), _el$52);
699
+ _el$53.$$click = () => move(index, index - 1);
700
+ _el$53.disabled = index === 0;
701
+ _el$54.$$click = () => move(index, index + 1);
702
+ _el$55.$$click = () => duplicate(index);
703
+ _el$56.$$click = () => props.fieldApi().removeValue(index);
704
+ insert(_el$46, createComponent(Show, {
705
+ get when() {
706
+ return !isCollapsed();
707
+ },
708
+ get children() {
709
+ var _el$57 = _tmpl$30();
710
+ insert(_el$57, createComponent(For, {
711
+ get each() {
712
+ return fieldsForItem(props.field, item());
367
713
  },
368
- get children() {
369
- return _tmpl$7$1();
370
- }
371
- }), null);
372
- insert(_el$33, () => renderInput(inputId, itemField, item[itemKey], (_, v) => updateItem(index(), itemKey, v), ctx), null);
373
- return _el$33;
374
- })();
714
+ children: ([itemKey, itemField]) => renderField(props.form, props.ctx, `${props.name}[${index}].${itemKey}`, itemField, labelFor(itemKey, itemField))
715
+ }));
716
+ return _el$57;
717
+ }
718
+ }), null);
719
+ effect((_p$) => {
720
+ var _v$13 = !isCollapsed(), _v$14 = index === items().length - 1;
721
+ _v$13 !== _p$.e && setAttribute(_el$48, "aria-expanded", _p$.e = _v$13);
722
+ _v$14 !== _p$.t && (_el$54.disabled = _p$.t = _v$14);
723
+ return _p$;
724
+ }, {
725
+ e: void 0,
726
+ t: void 0
727
+ });
728
+ return _el$46;
729
+ })();
730
+ }
731
+ }), null);
732
+ insert(_el$42, createComponent(Show, {
733
+ get when() {
734
+ return disc && variants.length > 0;
735
+ },
736
+ get fallback() {
737
+ return (() => {
738
+ var _el$58 = _tmpl$32();
739
+ _el$58.firstChild;
740
+ _el$58.$$click = () => addBlock();
741
+ insert(_el$58, () => props.label, null);
742
+ return _el$58;
743
+ })();
744
+ },
745
+ get children() {
746
+ var _el$43 = _tmpl$27(), _el$44 = _el$43.firstChild;
747
+ _el$44.$$click = () => setMenuOpen((o) => !o);
748
+ insert(_el$43, createComponent(Show, {
749
+ get when() {
750
+ return menuOpen();
751
+ },
752
+ get children() {
753
+ var _el$45 = _tmpl$26();
754
+ insert(_el$45, createComponent(For, {
755
+ each: variants,
756
+ children: (variant) => (() => {
757
+ var _el$60 = _tmpl$34();
758
+ _el$60.$$click = () => addBlock(variant);
759
+ insert(_el$60, createComponent(Show, {
760
+ get when() {
761
+ return disc?.variantsAdmin?.[variant]?.icon;
762
+ },
763
+ get children() {
764
+ var _el$61 = _tmpl$33();
765
+ effect(() => className(_el$61, disc?.variantsAdmin?.[variant]?.icon));
766
+ return _el$61;
767
+ }
768
+ }), null);
769
+ insert(_el$60, () => variantLabel(disc, variant), null);
770
+ return _el$60;
771
+ })()
772
+ }));
773
+ return _el$45;
375
774
  }
376
- }), _el$32);
377
- _el$32.$$click = () => removeItem(index());
378
- return _el$31;
379
- })()
380
- }), _el$29);
381
- _el$29.$$click = addItem;
382
- insert(_el$29, key, null);
383
- return _el$28;
775
+ }), null);
776
+ effect(() => setAttribute(_el$44, "aria-expanded", menuOpen()));
777
+ return _el$43;
778
+ }
779
+ }), null);
780
+ return _el$38;
384
781
  })();
385
782
  }
783
+ function fieldsForItem(field, item) {
784
+ const base = Object.entries(field.fields);
785
+ const discriminator = field.discriminator;
786
+ if (!discriminator) return base;
787
+ const variantValue = item[discriminator.key];
788
+ const variantFields = typeof variantValue === "string" ? discriminator.variants[variantValue] : void 0;
789
+ return variantFields ? [...base, ...Object.entries(variantFields)] : base;
790
+ }
386
791
  function formatDateValue(value) {
387
792
  if (!value) return "—";
388
793
  const date = value instanceof Date ? value : new Date(value);
389
794
  return Number.isNaN(date.getTime()) ? "—" : date.toLocaleString();
390
795
  }
391
- delegateEvents(["click", "input"]);
796
+ delegateEvents([
797
+ "click",
798
+ "input",
799
+ "keydown",
800
+ "mousedown"
801
+ ]);
392
802
  //#endregion
393
803
  //#region src/CollectionList.tsx
394
- var _tmpl$$3 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline btn-sm">`), _tmpl$2$2 = /*#__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$2 = /*#__PURE__*/ template(`<th>`), _tmpl$4$2 = /*#__PURE__*/ template(`<table class="table hidden md:table"><thead><tr></tr></thead><tbody>`), _tmpl$5$1 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2 md:hidden">`), _tmpl$6$1 = /*#__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>`);
804
+ var _tmpl$$3 = /*#__PURE__*/ template(`<button type=button class="btn btn-outline btn-sm">`), _tmpl$2$2 = /*#__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$2 = /*#__PURE__*/ template(`<table class="table hidden md:table"><thead></thead><tbody>`), _tmpl$4$2 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2 md:hidden">`), _tmpl$5$1 = /*#__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$1 = /*#__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>`);
395
805
  function listableFields(config) {
396
806
  const excluded = new Set([
397
807
  "richText",
@@ -409,7 +819,21 @@ function rowId(row) {
409
819
  return typeof row.id === "number" ? row.id : void 0;
410
820
  }
411
821
  function CollectionList(props) {
412
- const columns = () => listableFields(props.config);
822
+ const columns = () => listableFields(props.config).map(([key]) => ({
823
+ id: key,
824
+ accessorFn: (row) => row[key],
825
+ header: key,
826
+ cell: (info) => formatCellValue(info.getValue())
827
+ }));
828
+ const table = createSolidTable({
829
+ get data() {
830
+ return props.rows;
831
+ },
832
+ get columns() {
833
+ return columns();
834
+ },
835
+ getCoreRowModel: getCoreRowModel()
836
+ });
413
837
  const [selectMode, setSelectMode] = createSignal(false);
414
838
  function toggleSelected(id) {
415
839
  const next = new Set(props.selectedIds ?? []);
@@ -426,7 +850,7 @@ function CollectionList(props) {
426
850
  props.onRowClick?.(row);
427
851
  }
428
852
  return (() => {
429
- var _el$ = _tmpl$7(), _el$2 = _el$.firstChild;
853
+ var _el$ = _tmpl$6$1(), _el$2 = _el$.firstChild;
430
854
  insert(_el$2, createComponent(Show, {
431
855
  get when() {
432
856
  return props.selectable;
@@ -447,16 +871,16 @@ function CollectionList(props) {
447
871
  _el$5.addEventListener("change", (e) => props.onSortChange?.(e.currentTarget.value, props.sortDirection ?? "asc"));
448
872
  insert(_el$5, createComponent(For, {
449
873
  get each() {
450
- return columns();
874
+ return table.getAllColumns();
451
875
  },
452
- children: ([key]) => (() => {
453
- var _el$16 = _tmpl$8();
454
- _el$16.value = key;
455
- insert(_el$16, key);
456
- return _el$16;
876
+ children: (column) => (() => {
877
+ var _el$14 = _tmpl$7();
878
+ insert(_el$14, () => column.id);
879
+ effect(() => _el$14.value = column.id);
880
+ return _el$14;
457
881
  })()
458
882
  }));
459
- _el$6.addEventListener("change", (e) => props.onSortChange?.(props.sortField ?? columns()[0]?.[0] ?? "", e.currentTarget.value));
883
+ _el$6.addEventListener("change", (e) => props.onSortChange?.(props.sortField ?? table.getAllColumns()[0]?.id ?? "", e.currentTarget.value));
460
884
  effect(() => _el$5.value = props.sortField ?? "");
461
885
  effect(() => _el$6.value = props.sortDirection ?? "asc");
462
886
  return _el$4;
@@ -468,62 +892,71 @@ function CollectionList(props) {
468
892
  },
469
893
  get fallback() {
470
894
  return (() => {
471
- var _el$17 = _tmpl$9(), _el$20 = _el$17.firstChild.nextSibling;
472
- _el$20.nextSibling;
473
- insert(_el$17, () => props.config.slug, _el$20);
474
- return _el$17;
895
+ var _el$15 = _tmpl$8(), _el$18 = _el$15.firstChild.nextSibling;
896
+ _el$18.nextSibling;
897
+ insert(_el$15, () => props.config.slug, _el$18);
898
+ return _el$15;
475
899
  })();
476
900
  },
477
901
  get children() {
478
902
  return [(() => {
479
- var _el$7 = _tmpl$4$2(), _el$8 = _el$7.firstChild, _el$9 = _el$8.firstChild, _el$1 = _el$8.nextSibling;
480
- insert(_el$9, createComponent(Show, {
481
- get when() {
482
- return selectMode();
483
- },
484
- get children() {
485
- return _tmpl$3$2();
486
- }
487
- }), null);
488
- insert(_el$9, createComponent(For, {
903
+ var _el$7 = _tmpl$3$2(), _el$8 = _el$7.firstChild, _el$9 = _el$8.nextSibling;
904
+ insert(_el$8, createComponent(For, {
489
905
  get each() {
490
- return columns();
906
+ return table.getHeaderGroups();
491
907
  },
492
- children: ([key]) => (() => {
493
- var _el$21 = _tmpl$3$2();
494
- insert(_el$21, key);
495
- return _el$21;
908
+ children: (headerGroup) => (() => {
909
+ var _el$19 = _tmpl$0();
910
+ insert(_el$19, createComponent(Show, {
911
+ get when() {
912
+ return selectMode();
913
+ },
914
+ get children() {
915
+ return _tmpl$9();
916
+ }
917
+ }), null);
918
+ insert(_el$19, createComponent(For, {
919
+ get each() {
920
+ return headerGroup.headers;
921
+ },
922
+ children: (header) => (() => {
923
+ var _el$21 = _tmpl$9();
924
+ insert(_el$21, () => flexRender(header.column.columnDef.header, header.getContext()));
925
+ return _el$21;
926
+ })()
927
+ }), null);
928
+ return _el$19;
496
929
  })()
497
- }), null);
498
- insert(_el$1, createComponent(For, {
930
+ }));
931
+ insert(_el$9, createComponent(For, {
499
932
  get each() {
500
- return props.rows;
933
+ return table.getRowModel().rows;
501
934
  },
502
935
  children: (row) => (() => {
503
- var _el$22 = _tmpl$1();
504
- _el$22.$$click = () => handleRowActivate(row);
936
+ var _el$22 = _tmpl$0();
937
+ _el$22.$$click = () => handleRowActivate(row.original);
505
938
  insert(_el$22, createComponent(Show, {
506
939
  get when() {
507
940
  return selectMode();
508
941
  },
509
942
  get children() {
510
- var _el$23 = _tmpl$0(), _el$24 = _el$23.firstChild;
943
+ var _el$23 = _tmpl$1(), _el$24 = _el$23.firstChild;
511
944
  _el$24.addEventListener("change", () => {
512
- const id = rowId(row);
945
+ const id = rowId(row.original);
513
946
  if (id !== void 0) toggleSelected(id);
514
947
  });
515
948
  _el$24.$$click = (e) => e.stopPropagation();
516
- effect(() => _el$24.checked = rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false));
949
+ effect(() => _el$24.checked = rowId(row.original) !== void 0 && (props.selectedIds?.has(rowId(row.original)) ?? false));
517
950
  return _el$23;
518
951
  }
519
952
  }), null);
520
953
  insert(_el$22, createComponent(For, {
521
954
  get each() {
522
- return columns();
955
+ return row.getVisibleCells();
523
956
  },
524
- children: ([key]) => (() => {
957
+ children: (cell) => (() => {
525
958
  var _el$25 = _tmpl$10();
526
- insert(_el$25, () => formatCellValue(row[key]));
959
+ insert(_el$25, () => flexRender(cell.column.columnDef.cell, cell.getContext()));
527
960
  return _el$25;
528
961
  })()
529
962
  }), null);
@@ -533,20 +966,20 @@ function CollectionList(props) {
533
966
  }));
534
967
  return _el$7;
535
968
  })(), (() => {
536
- var _el$10 = _tmpl$5$1();
537
- insert(_el$10, createComponent(For, {
969
+ var _el$0 = _tmpl$4$2();
970
+ insert(_el$0, createComponent(For, {
538
971
  get each() {
539
- return props.rows;
972
+ return table.getRowModel().rows;
540
973
  },
541
974
  children: (row) => (() => {
542
975
  var _el$26 = _tmpl$12(), _el$27 = _el$26.firstChild, _el$29 = _el$27.firstChild;
543
976
  _el$26.$$keydown = (e) => {
544
977
  if (e.key === "Enter" || e.key === " ") {
545
978
  e.preventDefault();
546
- handleRowActivate(row);
979
+ handleRowActivate(row.original);
547
980
  }
548
981
  };
549
- _el$26.$$click = () => handleRowActivate(row);
982
+ _el$26.$$click = () => handleRowActivate(row.original);
550
983
  insert(_el$27, createComponent(Show, {
551
984
  get when() {
552
985
  return selectMode();
@@ -554,29 +987,29 @@ function CollectionList(props) {
554
987
  get children() {
555
988
  var _el$28 = _tmpl$11();
556
989
  _el$28.addEventListener("change", () => {
557
- const id = rowId(row);
990
+ const id = rowId(row.original);
558
991
  if (id !== void 0) toggleSelected(id);
559
992
  });
560
993
  _el$28.$$click = (e) => e.stopPropagation();
561
- effect(() => _el$28.checked = rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false));
994
+ effect(() => _el$28.checked = rowId(row.original) !== void 0 && (props.selectedIds?.has(rowId(row.original)) ?? false));
562
995
  return _el$28;
563
996
  }
564
997
  }), _el$29);
565
998
  insert(_el$29, createComponent(For, {
566
999
  get each() {
567
- return columns();
1000
+ return row.getVisibleCells();
568
1001
  },
569
- children: ([key]) => (() => {
1002
+ children: (cell) => (() => {
570
1003
  var _el$30 = _tmpl$13(), _el$31 = _el$30.firstChild, _el$32 = _el$31.nextSibling;
571
- insert(_el$31, key);
572
- insert(_el$32, () => formatCellValue(row[key]));
1004
+ insert(_el$31, () => cell.column.id);
1005
+ insert(_el$32, () => flexRender(cell.column.columnDef.cell, cell.getContext()));
573
1006
  return _el$30;
574
1007
  })()
575
1008
  }));
576
1009
  return _el$26;
577
1010
  })()
578
1011
  }));
579
- return _el$10;
1012
+ return _el$0;
580
1013
  })()];
581
1014
  }
582
1015
  }), null);
@@ -585,22 +1018,22 @@ function CollectionList(props) {
585
1018
  return memo(() => props.page !== void 0)() && props.pageSize !== void 0;
586
1019
  },
587
1020
  get children() {
588
- var _el$11 = _tmpl$6$1(), _el$12 = _el$11.firstChild, _el$13 = _el$12.nextSibling;
589
- _el$13.firstChild;
590
- var _el$15 = _el$13.nextSibling;
591
- _el$12.$$click = () => props.onPageChange?.((props.page ?? 1) - 1);
592
- insert(_el$13, () => props.page, null);
593
- _el$15.$$click = () => props.onPageChange?.((props.page ?? 1) + 1);
1021
+ var _el$1 = _tmpl$5$1(), _el$10 = _el$1.firstChild, _el$11 = _el$10.nextSibling;
1022
+ _el$11.firstChild;
1023
+ var _el$13 = _el$11.nextSibling;
1024
+ _el$10.$$click = () => props.onPageChange?.((props.page ?? 1) - 1);
1025
+ insert(_el$11, () => props.page, null);
1026
+ _el$13.$$click = () => props.onPageChange?.((props.page ?? 1) + 1);
594
1027
  effect((_p$) => {
595
1028
  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);
596
- _v$ !== _p$.e && (_el$12.disabled = _p$.e = _v$);
597
- _v$2 !== _p$.t && (_el$15.disabled = _p$.t = _v$2);
1029
+ _v$ !== _p$.e && (_el$10.disabled = _p$.e = _v$);
1030
+ _v$2 !== _p$.t && (_el$13.disabled = _p$.t = _v$2);
598
1031
  return _p$;
599
1032
  }, {
600
1033
  e: void 0,
601
1034
  t: void 0
602
1035
  });
603
- return _el$11;
1036
+ return _el$1;
604
1037
  }
605
1038
  }), null);
606
1039
  return _el$;