@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,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`);
6
- const RichTextEditor = lazy(() => import("../RichTextEditor-BPilh7Pw.js").then((mod) => ({ default: mod.RichTextEditor })));
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">`);
8
+ const RichTextEditor = lazy(() => import("../RichTextEditor-ComcBFfl.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,204 @@ 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] ?? ctx.fieldWidgets?.[key.slice(key.lastIndexOf(".") + 1)];
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),
383
+ get onUploadFile() {
384
+ return ctx.onUploadFile;
385
+ }
230
386
  });
231
387
  }
232
388
  });
233
389
  default: return null;
234
390
  }
235
391
  }
236
- function renderUploadInput(key, field, value, setField, ctx) {
392
+ function UploadControl(props) {
237
393
  const [uploading, setUploading] = createSignal(false);
238
394
  const [uploadError, setUploadError] = createSignal();
395
+ const value = () => props.fieldApi().state.value;
239
396
  async function handleFileChange(e) {
240
397
  const file = e.currentTarget.files?.[0];
241
398
  if (!file) return;
242
- if (!ctx.onUploadFile) {
399
+ if (!props.ctx.onUploadFile) {
243
400
  setUploadError("No upload handler configured for this form.");
244
401
  return;
245
402
  }
246
403
  setUploading(true);
247
404
  setUploadError(void 0);
248
405
  try {
249
- const { url } = await ctx.onUploadFile(file);
250
- setField(key, url);
406
+ const { url } = await props.ctx.onUploadFile(file);
407
+ props.fieldApi().handleChange(url);
251
408
  } catch (err) {
252
409
  setUploadError(err instanceof Error ? err.message : "Upload failed");
253
410
  } finally {
@@ -255,18 +412,19 @@ function renderUploadInput(key, field, value, setField, ctx) {
255
412
  }
256
413
  }
257
414
  return (() => {
258
- var _el$20 = _tmpl$16(), _el$22 = _el$20.firstChild;
259
- insert(_el$20, createComponent(Show, {
260
- when: value,
415
+ var _el$25 = _tmpl$19(), _el$27 = _el$25.firstChild;
416
+ insert(_el$25, createComponent(Show, {
417
+ get when() {
418
+ return value();
419
+ },
261
420
  get children() {
262
- var _el$21 = _tmpl$14();
263
- insert(_el$21, value);
264
- return _el$21;
421
+ var _el$26 = _tmpl$17();
422
+ insert(_el$26, value);
423
+ return _el$26;
265
424
  }
266
- }), _el$22);
267
- _el$22.addEventListener("change", handleFileChange);
268
- setAttribute(_el$22, "id", key);
269
- insert(_el$20, createComponent(Show, {
425
+ }), _el$27);
426
+ _el$27.addEventListener("change", handleFileChange);
427
+ insert(_el$25, createComponent(Show, {
270
428
  get when() {
271
429
  return uploading();
272
430
  },
@@ -274,124 +432,379 @@ function renderUploadInput(key, field, value, setField, ctx) {
274
432
  return _tmpl$2$3();
275
433
  }
276
434
  }), null);
277
- insert(_el$20, createComponent(Show, {
435
+ insert(_el$25, createComponent(Show, {
278
436
  get when() {
279
437
  return uploadError();
280
438
  },
281
439
  get children() {
282
- var _el$24 = _tmpl$15();
283
- insert(_el$24, uploadError);
284
- return _el$24;
440
+ var _el$29 = _tmpl$18();
441
+ insert(_el$29, uploadError);
442
+ return _el$29;
285
443
  }
286
444
  }), null);
287
445
  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);
446
+ var _v$5 = props.name, _v$6 = props.field.required && !value(), _v$7 = uploading() || props.field.admin?.readOnly;
447
+ _v$5 !== _p$.e && setAttribute(_el$27, "id", _p$.e = _v$5);
448
+ _v$6 !== _p$.t && (_el$27.required = _p$.t = _v$6);
449
+ _v$7 !== _p$.a && (_el$27.disabled = _p$.a = _v$7);
291
450
  return _p$;
292
451
  }, {
293
452
  e: void 0,
294
- t: void 0
453
+ t: void 0,
454
+ a: void 0
295
455
  });
296
- return _el$20;
456
+ return _el$25;
297
457
  })();
298
458
  }
299
- function renderRelationshipInput(key, field, value, setField, ctx) {
300
- if (field.hasMany) return null;
301
- const options = ctx.relationshipOptions?.[field.relationTo] ?? [];
459
+ function RelationshipField(props) {
460
+ const [query, setQuery] = createSignal("");
461
+ const [open, setOpen] = createSignal(false);
462
+ const [active, setActive] = createSignal(0);
463
+ const listId = `${props.name}-listbox`;
464
+ const isMulti = () => props.field.hasMany === true;
465
+ const value = () => props.fieldApi().state.value;
466
+ const selectedIds = () => {
467
+ const v = value();
468
+ if (isMulti()) return Array.isArray(v) ? v : [];
469
+ return v != null ? [v] : [];
470
+ };
471
+ const selectedOptions = () => props.options.filter((o) => selectedIds().includes(o.id));
472
+ const filtered = () => {
473
+ const q = query().toLowerCase();
474
+ return props.options.filter((o) => o.label.toLowerCase().includes(q) && (!isMulti() || !selectedIds().includes(o.id)));
475
+ };
476
+ const singleLabel = () => selectedOptions()[0]?.label ?? "";
477
+ function choose(option) {
478
+ if (isMulti()) {
479
+ props.fieldApi().handleChange([...selectedIds(), option.id]);
480
+ setQuery("");
481
+ } else {
482
+ props.fieldApi().handleChange(option.id);
483
+ setQuery("");
484
+ setOpen(false);
485
+ }
486
+ setActive(0);
487
+ }
488
+ function removeId(id) {
489
+ if (isMulti()) props.fieldApi().handleChange(selectedIds().filter((x) => x !== id));
490
+ else props.fieldApi().handleChange(null);
491
+ }
492
+ function onKeyDown(e) {
493
+ if (e.key === "ArrowDown") {
494
+ e.preventDefault();
495
+ setOpen(true);
496
+ setActive((a) => Math.min(a + 1, filtered().length - 1));
497
+ } else if (e.key === "ArrowUp") {
498
+ e.preventDefault();
499
+ setActive((a) => Math.max(a - 1, 0));
500
+ } else if (e.key === "Enter") {
501
+ e.preventDefault();
502
+ const option = filtered()[active()];
503
+ if (option) choose(option);
504
+ } else if (e.key === "Escape") setOpen(false);
505
+ else if (e.key === "Backspace" && isMulti() && query() === "") {
506
+ const ids = selectedIds();
507
+ if (ids.length > 0) removeId(ids[ids.length - 1]);
508
+ }
509
+ }
302
510
  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
- })()
511
+ var _el$30 = _tmpl$23(), _el$32 = _el$30.firstChild;
512
+ insert(_el$30, createComponent(Show, {
513
+ get when() {
514
+ return memo(() => !!isMulti())() && selectedOptions().length > 0;
515
+ },
516
+ get children() {
517
+ var _el$31 = _tmpl$20();
518
+ insert(_el$31, createComponent(For, {
519
+ get each() {
520
+ return selectedOptions();
521
+ },
522
+ children: (option) => (() => {
523
+ var _el$35 = _tmpl$24(), _el$36 = _el$35.firstChild;
524
+ insert(_el$35, () => option.label, _el$36);
525
+ _el$36.$$click = () => removeId(option.id);
526
+ effect(() => setAttribute(_el$36, "aria-label", `Remove ${option.label}`));
527
+ return _el$35;
528
+ })()
529
+ }));
530
+ return _el$31;
531
+ }
532
+ }), _el$32);
533
+ _el$32.$$keydown = onKeyDown;
534
+ _el$32.addEventListener("blur", () => setTimeout(() => setOpen(false), 120));
535
+ _el$32.addEventListener("focus", () => setOpen(true));
536
+ _el$32.$$input = (e) => {
537
+ setQuery(e.currentTarget.value);
538
+ setOpen(true);
539
+ setActive(0);
540
+ };
541
+ setAttribute(_el$32, "aria-controls", listId);
542
+ insert(_el$30, createComponent(Show, {
543
+ get when() {
544
+ return memo(() => !!(!isMulti() && value() != null))() && !props.field.required;
545
+ },
546
+ get children() {
547
+ var _el$33 = _tmpl$21();
548
+ _el$33.$$click = () => removeId(value());
549
+ _el$33.$$mousedown = (e) => e.preventDefault();
550
+ return _el$33;
551
+ }
315
552
  }), null);
316
- effect(() => _el$25.required = field.required);
317
- effect(() => _el$25.value = value != null ? String(value) : "");
318
- return _el$25;
553
+ insert(_el$30, createComponent(Show, {
554
+ get when() {
555
+ return memo(() => !!open())() && filtered().length > 0;
556
+ },
557
+ get children() {
558
+ var _el$34 = _tmpl$22();
559
+ setAttribute(_el$34, "id", listId);
560
+ insert(_el$34, createComponent(For, {
561
+ get each() {
562
+ return filtered();
563
+ },
564
+ children: (option, i) => (() => {
565
+ var _el$37 = _tmpl$25();
566
+ _el$37.$$click = () => choose(option);
567
+ _el$37.$$mousedown = (e) => e.preventDefault();
568
+ insert(_el$37, () => option.label);
569
+ effect((_p$) => {
570
+ var _v$11 = selectedIds().includes(option.id), _v$12 = !!(i() === active());
571
+ _v$11 !== _p$.e && setAttribute(_el$37, "aria-selected", _p$.e = _v$11);
572
+ _v$12 !== _p$.t && _el$37.classList.toggle("bg-base-200", _p$.t = _v$12);
573
+ return _p$;
574
+ }, {
575
+ e: void 0,
576
+ t: void 0
577
+ });
578
+ return _el$37;
579
+ })()
580
+ }));
581
+ return _el$34;
582
+ }
583
+ }), null);
584
+ effect((_p$) => {
585
+ 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…";
586
+ _v$8 !== _p$.e && setAttribute(_el$32, "id", _p$.e = _v$8);
587
+ _v$9 !== _p$.t && setAttribute(_el$32, "aria-expanded", _p$.t = _v$9);
588
+ _v$0 !== _p$.a && (_el$32.required = _p$.a = _v$0);
589
+ _v$1 !== _p$.o && (_el$32.disabled = _p$.o = _v$1);
590
+ _v$10 !== _p$.i && setAttribute(_el$32, "placeholder", _p$.i = _v$10);
591
+ return _p$;
592
+ }, {
593
+ e: void 0,
594
+ t: void 0,
595
+ a: void 0,
596
+ o: void 0,
597
+ i: void 0
598
+ });
599
+ effect(() => _el$32.value = open() || isMulti() ? query() : singleLabel());
600
+ return _el$30;
319
601
  })();
320
602
  }
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);
603
+ function renderArray(form, ctx, name, field, label) {
604
+ return createComponent(form.Field, {
605
+ name,
606
+ mode: "array",
607
+ children: (fieldApi) => createComponent(BlockEditor, {
608
+ form,
609
+ ctx,
610
+ name,
611
+ field,
612
+ label,
613
+ fieldApi
614
+ })
615
+ });
616
+ }
617
+ function variantLabel(disc, variant) {
618
+ return disc.variantsAdmin?.[variant]?.label ?? humanize(variant);
619
+ }
620
+ function BlockEditor(props) {
621
+ const [collapsed, setCollapsed] = createSignal(/* @__PURE__ */ new Set());
622
+ const [menuOpen, setMenuOpen] = createSignal(false);
623
+ const disc = props.field.discriminator;
624
+ const variants = disc ? Object.keys(disc.variants) : [];
625
+ const items = () => Array.isArray(props.fieldApi().state.value) ? props.fieldApi().state.value : [];
626
+ function addBlock(variant) {
627
+ const seed = variant && disc ? { [disc.key]: variant } : {};
628
+ props.fieldApi().pushValue(seed);
629
+ setMenuOpen(false);
330
630
  }
331
- function addItem() {
332
- setField(key, [...items(), {}]);
631
+ function duplicate(index) {
632
+ props.fieldApi().insertValue(index + 1, { ...items()[index] });
333
633
  }
334
- function removeItem(index) {
335
- setField(key, items().filter((_, i) => i !== index));
634
+ function move(from, to) {
635
+ if (to < 0 || to >= items().length) return;
636
+ props.fieldApi().moveValue(from, to);
336
637
  }
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;
638
+ function toggleCollapse(index) {
639
+ setCollapsed((prev) => {
640
+ const next = new Set(prev);
641
+ if (next.has(index)) next.delete(index);
642
+ else next.add(index);
643
+ return next;
644
+ });
645
+ }
646
+ function blockTitle(item) {
647
+ if (disc) {
648
+ const v = item[disc.key];
649
+ if (typeof v === "string") return variantLabel(disc, v);
650
+ }
651
+ return props.label;
652
+ }
653
+ function blockSummary(item) {
654
+ for (const [key, f] of fieldsForItem(props.field, item)) {
655
+ if (key === disc?.key) continue;
656
+ if ((f.type === "text" || f.type === "select") && item[key]) return String(item[key]);
657
+ }
658
+ return "";
344
659
  }
345
660
  return (() => {
346
- var _el$28 = _tmpl$18(), _el$29 = _el$28.firstChild;
347
- _el$29.firstChild;
348
- insert(_el$28, createComponent(For, {
661
+ var _el$38 = _tmpl$28(), _el$39 = _el$38.firstChild, _el$42 = _el$39.nextSibling;
662
+ insert(_el$39, () => props.label, null);
663
+ insert(_el$39, createComponent(Show, {
664
+ get when() {
665
+ return props.field.required;
666
+ },
667
+ get children() {
668
+ return _tmpl$9$1();
669
+ }
670
+ }), null);
671
+ insert(_el$38, createComponent(Show, {
672
+ get when() {
673
+ return props.field.admin?.description;
674
+ },
675
+ get children() {
676
+ var _el$41 = _tmpl$0$1();
677
+ insert(_el$41, () => props.field.admin?.description);
678
+ return _el$41;
679
+ }
680
+ }), _el$42);
681
+ insert(_el$42, createComponent(Index, {
349
682
  get each() {
350
683
  return items();
351
684
  },
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;
685
+ children: (item, index) => {
686
+ const isCollapsed = () => collapsed().has(index);
687
+ return (() => {
688
+ 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;
689
+ _el$48.$$click = () => toggleCollapse(index);
690
+ insert(_el$49, () => isCollapsed() ? "▸" : "▾");
691
+ insert(_el$50, () => blockTitle(item()));
692
+ insert(_el$47, createComponent(Show, {
693
+ get when() {
694
+ return memo(() => !!isCollapsed())() && blockSummary(item());
695
+ },
696
+ get children() {
697
+ var _el$51 = _tmpl$29();
698
+ insert(_el$51, () => blockSummary(item()));
699
+ return _el$51;
700
+ }
701
+ }), _el$52);
702
+ _el$53.$$click = () => move(index, index - 1);
703
+ _el$53.disabled = index === 0;
704
+ _el$54.$$click = () => move(index, index + 1);
705
+ _el$55.$$click = () => duplicate(index);
706
+ _el$56.$$click = () => props.fieldApi().removeValue(index);
707
+ insert(_el$46, createComponent(Show, {
708
+ get when() {
709
+ return !isCollapsed();
710
+ },
711
+ get children() {
712
+ var _el$57 = _tmpl$30();
713
+ insert(_el$57, createComponent(For, {
714
+ get each() {
715
+ return fieldsForItem(props.field, item());
367
716
  },
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
- })();
717
+ children: ([itemKey, itemField]) => renderField(props.form, props.ctx, `${props.name}[${index}].${itemKey}`, itemField, labelFor(itemKey, itemField))
718
+ }));
719
+ return _el$57;
720
+ }
721
+ }), null);
722
+ effect((_p$) => {
723
+ var _v$13 = !isCollapsed(), _v$14 = index === items().length - 1;
724
+ _v$13 !== _p$.e && setAttribute(_el$48, "aria-expanded", _p$.e = _v$13);
725
+ _v$14 !== _p$.t && (_el$54.disabled = _p$.t = _v$14);
726
+ return _p$;
727
+ }, {
728
+ e: void 0,
729
+ t: void 0
730
+ });
731
+ return _el$46;
732
+ })();
733
+ }
734
+ }), null);
735
+ insert(_el$42, createComponent(Show, {
736
+ get when() {
737
+ return disc && variants.length > 0;
738
+ },
739
+ get fallback() {
740
+ return (() => {
741
+ var _el$58 = _tmpl$32();
742
+ _el$58.firstChild;
743
+ _el$58.$$click = () => addBlock();
744
+ insert(_el$58, () => props.label, null);
745
+ return _el$58;
746
+ })();
747
+ },
748
+ get children() {
749
+ var _el$43 = _tmpl$27(), _el$44 = _el$43.firstChild;
750
+ _el$44.$$click = () => setMenuOpen((o) => !o);
751
+ insert(_el$43, createComponent(Show, {
752
+ get when() {
753
+ return menuOpen();
754
+ },
755
+ get children() {
756
+ var _el$45 = _tmpl$26();
757
+ insert(_el$45, createComponent(For, {
758
+ each: variants,
759
+ children: (variant) => (() => {
760
+ var _el$60 = _tmpl$34();
761
+ _el$60.$$click = () => addBlock(variant);
762
+ insert(_el$60, createComponent(Show, {
763
+ get when() {
764
+ return disc?.variantsAdmin?.[variant]?.icon;
765
+ },
766
+ get children() {
767
+ var _el$61 = _tmpl$33();
768
+ effect(() => className(_el$61, disc?.variantsAdmin?.[variant]?.icon));
769
+ return _el$61;
770
+ }
771
+ }), null);
772
+ insert(_el$60, () => variantLabel(disc, variant), null);
773
+ return _el$60;
774
+ })()
775
+ }));
776
+ return _el$45;
375
777
  }
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;
778
+ }), null);
779
+ effect(() => setAttribute(_el$44, "aria-expanded", menuOpen()));
780
+ return _el$43;
781
+ }
782
+ }), null);
783
+ return _el$38;
384
784
  })();
385
785
  }
786
+ function fieldsForItem(field, item) {
787
+ const base = Object.entries(field.fields);
788
+ const discriminator = field.discriminator;
789
+ if (!discriminator) return base;
790
+ const variantValue = item[discriminator.key];
791
+ const variantFields = typeof variantValue === "string" ? discriminator.variants[variantValue] : void 0;
792
+ return variantFields ? [...base, ...Object.entries(variantFields)] : base;
793
+ }
386
794
  function formatDateValue(value) {
387
795
  if (!value) return "—";
388
796
  const date = value instanceof Date ? value : new Date(value);
389
797
  return Number.isNaN(date.getTime()) ? "—" : date.toLocaleString();
390
798
  }
391
- delegateEvents(["click", "input"]);
799
+ delegateEvents([
800
+ "click",
801
+ "input",
802
+ "keydown",
803
+ "mousedown"
804
+ ]);
392
805
  //#endregion
393
806
  //#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>`);
807
+ 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
808
  function listableFields(config) {
396
809
  const excluded = new Set([
397
810
  "richText",
@@ -409,7 +822,21 @@ function rowId(row) {
409
822
  return typeof row.id === "number" ? row.id : void 0;
410
823
  }
411
824
  function CollectionList(props) {
412
- const columns = () => listableFields(props.config);
825
+ const columns = () => listableFields(props.config).map(([key]) => ({
826
+ id: key,
827
+ accessorFn: (row) => row[key],
828
+ header: key,
829
+ cell: (info) => formatCellValue(info.getValue())
830
+ }));
831
+ const table = createSolidTable({
832
+ get data() {
833
+ return props.rows;
834
+ },
835
+ get columns() {
836
+ return columns();
837
+ },
838
+ getCoreRowModel: getCoreRowModel()
839
+ });
413
840
  const [selectMode, setSelectMode] = createSignal(false);
414
841
  function toggleSelected(id) {
415
842
  const next = new Set(props.selectedIds ?? []);
@@ -426,7 +853,7 @@ function CollectionList(props) {
426
853
  props.onRowClick?.(row);
427
854
  }
428
855
  return (() => {
429
- var _el$ = _tmpl$7(), _el$2 = _el$.firstChild;
856
+ var _el$ = _tmpl$6$1(), _el$2 = _el$.firstChild;
430
857
  insert(_el$2, createComponent(Show, {
431
858
  get when() {
432
859
  return props.selectable;
@@ -447,16 +874,16 @@ function CollectionList(props) {
447
874
  _el$5.addEventListener("change", (e) => props.onSortChange?.(e.currentTarget.value, props.sortDirection ?? "asc"));
448
875
  insert(_el$5, createComponent(For, {
449
876
  get each() {
450
- return columns();
877
+ return table.getAllColumns();
451
878
  },
452
- children: ([key]) => (() => {
453
- var _el$16 = _tmpl$8();
454
- _el$16.value = key;
455
- insert(_el$16, key);
456
- return _el$16;
879
+ children: (column) => (() => {
880
+ var _el$14 = _tmpl$7();
881
+ insert(_el$14, () => column.id);
882
+ effect(() => _el$14.value = column.id);
883
+ return _el$14;
457
884
  })()
458
885
  }));
459
- _el$6.addEventListener("change", (e) => props.onSortChange?.(props.sortField ?? columns()[0]?.[0] ?? "", e.currentTarget.value));
886
+ _el$6.addEventListener("change", (e) => props.onSortChange?.(props.sortField ?? table.getAllColumns()[0]?.id ?? "", e.currentTarget.value));
460
887
  effect(() => _el$5.value = props.sortField ?? "");
461
888
  effect(() => _el$6.value = props.sortDirection ?? "asc");
462
889
  return _el$4;
@@ -468,62 +895,71 @@ function CollectionList(props) {
468
895
  },
469
896
  get fallback() {
470
897
  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;
898
+ var _el$15 = _tmpl$8(), _el$18 = _el$15.firstChild.nextSibling;
899
+ _el$18.nextSibling;
900
+ insert(_el$15, () => props.config.slug, _el$18);
901
+ return _el$15;
475
902
  })();
476
903
  },
477
904
  get children() {
478
905
  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, {
906
+ var _el$7 = _tmpl$3$2(), _el$8 = _el$7.firstChild, _el$9 = _el$8.nextSibling;
907
+ insert(_el$8, createComponent(For, {
489
908
  get each() {
490
- return columns();
909
+ return table.getHeaderGroups();
491
910
  },
492
- children: ([key]) => (() => {
493
- var _el$21 = _tmpl$3$2();
494
- insert(_el$21, key);
495
- return _el$21;
911
+ children: (headerGroup) => (() => {
912
+ var _el$19 = _tmpl$0();
913
+ insert(_el$19, createComponent(Show, {
914
+ get when() {
915
+ return selectMode();
916
+ },
917
+ get children() {
918
+ return _tmpl$9();
919
+ }
920
+ }), null);
921
+ insert(_el$19, createComponent(For, {
922
+ get each() {
923
+ return headerGroup.headers;
924
+ },
925
+ children: (header) => (() => {
926
+ var _el$21 = _tmpl$9();
927
+ insert(_el$21, () => flexRender(header.column.columnDef.header, header.getContext()));
928
+ return _el$21;
929
+ })()
930
+ }), null);
931
+ return _el$19;
496
932
  })()
497
- }), null);
498
- insert(_el$1, createComponent(For, {
933
+ }));
934
+ insert(_el$9, createComponent(For, {
499
935
  get each() {
500
- return props.rows;
936
+ return table.getRowModel().rows;
501
937
  },
502
938
  children: (row) => (() => {
503
- var _el$22 = _tmpl$1();
504
- _el$22.$$click = () => handleRowActivate(row);
939
+ var _el$22 = _tmpl$0();
940
+ _el$22.$$click = () => handleRowActivate(row.original);
505
941
  insert(_el$22, createComponent(Show, {
506
942
  get when() {
507
943
  return selectMode();
508
944
  },
509
945
  get children() {
510
- var _el$23 = _tmpl$0(), _el$24 = _el$23.firstChild;
946
+ var _el$23 = _tmpl$1(), _el$24 = _el$23.firstChild;
511
947
  _el$24.addEventListener("change", () => {
512
- const id = rowId(row);
948
+ const id = rowId(row.original);
513
949
  if (id !== void 0) toggleSelected(id);
514
950
  });
515
951
  _el$24.$$click = (e) => e.stopPropagation();
516
- effect(() => _el$24.checked = rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false));
952
+ effect(() => _el$24.checked = rowId(row.original) !== void 0 && (props.selectedIds?.has(rowId(row.original)) ?? false));
517
953
  return _el$23;
518
954
  }
519
955
  }), null);
520
956
  insert(_el$22, createComponent(For, {
521
957
  get each() {
522
- return columns();
958
+ return row.getVisibleCells();
523
959
  },
524
- children: ([key]) => (() => {
960
+ children: (cell) => (() => {
525
961
  var _el$25 = _tmpl$10();
526
- insert(_el$25, () => formatCellValue(row[key]));
962
+ insert(_el$25, () => flexRender(cell.column.columnDef.cell, cell.getContext()));
527
963
  return _el$25;
528
964
  })()
529
965
  }), null);
@@ -533,20 +969,20 @@ function CollectionList(props) {
533
969
  }));
534
970
  return _el$7;
535
971
  })(), (() => {
536
- var _el$10 = _tmpl$5$1();
537
- insert(_el$10, createComponent(For, {
972
+ var _el$0 = _tmpl$4$2();
973
+ insert(_el$0, createComponent(For, {
538
974
  get each() {
539
- return props.rows;
975
+ return table.getRowModel().rows;
540
976
  },
541
977
  children: (row) => (() => {
542
978
  var _el$26 = _tmpl$12(), _el$27 = _el$26.firstChild, _el$29 = _el$27.firstChild;
543
979
  _el$26.$$keydown = (e) => {
544
980
  if (e.key === "Enter" || e.key === " ") {
545
981
  e.preventDefault();
546
- handleRowActivate(row);
982
+ handleRowActivate(row.original);
547
983
  }
548
984
  };
549
- _el$26.$$click = () => handleRowActivate(row);
985
+ _el$26.$$click = () => handleRowActivate(row.original);
550
986
  insert(_el$27, createComponent(Show, {
551
987
  get when() {
552
988
  return selectMode();
@@ -554,29 +990,29 @@ function CollectionList(props) {
554
990
  get children() {
555
991
  var _el$28 = _tmpl$11();
556
992
  _el$28.addEventListener("change", () => {
557
- const id = rowId(row);
993
+ const id = rowId(row.original);
558
994
  if (id !== void 0) toggleSelected(id);
559
995
  });
560
996
  _el$28.$$click = (e) => e.stopPropagation();
561
- effect(() => _el$28.checked = rowId(row) !== void 0 && (props.selectedIds?.has(rowId(row)) ?? false));
997
+ effect(() => _el$28.checked = rowId(row.original) !== void 0 && (props.selectedIds?.has(rowId(row.original)) ?? false));
562
998
  return _el$28;
563
999
  }
564
1000
  }), _el$29);
565
1001
  insert(_el$29, createComponent(For, {
566
1002
  get each() {
567
- return columns();
1003
+ return row.getVisibleCells();
568
1004
  },
569
- children: ([key]) => (() => {
1005
+ children: (cell) => (() => {
570
1006
  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]));
1007
+ insert(_el$31, () => cell.column.id);
1008
+ insert(_el$32, () => flexRender(cell.column.columnDef.cell, cell.getContext()));
573
1009
  return _el$30;
574
1010
  })()
575
1011
  }));
576
1012
  return _el$26;
577
1013
  })()
578
1014
  }));
579
- return _el$10;
1015
+ return _el$0;
580
1016
  })()];
581
1017
  }
582
1018
  }), null);
@@ -585,22 +1021,22 @@ function CollectionList(props) {
585
1021
  return memo(() => props.page !== void 0)() && props.pageSize !== void 0;
586
1022
  },
587
1023
  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);
1024
+ var _el$1 = _tmpl$5$1(), _el$10 = _el$1.firstChild, _el$11 = _el$10.nextSibling;
1025
+ _el$11.firstChild;
1026
+ var _el$13 = _el$11.nextSibling;
1027
+ _el$10.$$click = () => props.onPageChange?.((props.page ?? 1) - 1);
1028
+ insert(_el$11, () => props.page, null);
1029
+ _el$13.$$click = () => props.onPageChange?.((props.page ?? 1) + 1);
594
1030
  effect((_p$) => {
595
1031
  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);
1032
+ _v$ !== _p$.e && (_el$10.disabled = _p$.e = _v$);
1033
+ _v$2 !== _p$.t && (_el$13.disabled = _p$.t = _v$2);
598
1034
  return _p$;
599
1035
  }, {
600
1036
  e: void 0,
601
1037
  t: void 0
602
1038
  });
603
- return _el$11;
1039
+ return _el$1;
604
1040
  }
605
1041
  }), null);
606
1042
  return _el$;