@thebes/cadmea 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index/index.d.ts +77 -3
- package/dist/index/index.js +226 -26
- package/dist/index/index.js.map +1 -1
- package/dist/index/server.js +146 -30
- package/dist/index/server.js.map +1 -1
- package/dist/tanstack-start/index.d.ts +116 -16
- package/dist/tanstack-start/index.js +17 -1
- package/dist/tanstack-start/index.js.map +1 -1
- package/dist/tanstack-start/server.js +17 -1
- package/dist/tanstack-start/server.js.map +1 -1
- package/package.json +3 -3
package/dist/index/server.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
import { createComponent, escape, ssr, ssrAttribute } from "solid-js/web";
|
|
2
|
-
import { For, Show, Suspense, createEffect, createSignal, lazy, onCleanup } from "solid-js";
|
|
1
|
+
import { createComponent, escape, ssr, ssrAttribute, ssrStyleProperty } 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";
|
|
3
4
|
//#region src/CollectionEdit.tsx
|
|
4
|
-
var _tmpl$$
|
|
5
|
+
var _tmpl$$4 = ["<p class=\"text-sm text-error\" role=\"alert\">", "</p>"], _tmpl$2$3 = "<span class=\"loading loading-spinner loading-sm\"></span>", _tmpl$3$3 = [
|
|
5
6
|
"<button type=\"button\" class=\"btn flex-1\"",
|
|
6
7
|
">",
|
|
7
8
|
"</button>"
|
|
8
|
-
], _tmpl$4$
|
|
9
|
+
], _tmpl$4$3 = [
|
|
9
10
|
"<button type=\"button\" class=\"btn btn-primary flex-1\"",
|
|
10
11
|
">",
|
|
11
12
|
"</button>"
|
|
12
|
-
], _tmpl$5$
|
|
13
|
+
], _tmpl$5$2 = [
|
|
13
14
|
"<button type=\"button\" class=\"btn btn-outline flex-1\"",
|
|
14
15
|
">",
|
|
15
16
|
"</button>"
|
|
16
|
-
], _tmpl$6$
|
|
17
|
+
], _tmpl$6$2 = [
|
|
17
18
|
"<form class=\"flex flex-col gap-4\">",
|
|
18
19
|
"",
|
|
19
20
|
"<div class=\"bg-base-100 sticky bottom-0 flex gap-2 border-t py-3\">",
|
|
@@ -93,15 +94,16 @@ function CollectionEdit(props) {
|
|
|
93
94
|
}
|
|
94
95
|
const ctx = {
|
|
95
96
|
onUploadFile: props.onUploadFile,
|
|
96
|
-
relationshipOptions: props.relationshipOptions
|
|
97
|
+
relationshipOptions: props.relationshipOptions,
|
|
98
|
+
fieldWidgets: props.fieldWidgets
|
|
97
99
|
};
|
|
98
100
|
const versioned = () => props.config.versions?.drafts && props.draftActions;
|
|
99
|
-
return ssr(_tmpl$6$
|
|
101
|
+
return ssr(_tmpl$6$2, escape(createComponent(Show, {
|
|
100
102
|
get when() {
|
|
101
103
|
return props.error;
|
|
102
104
|
},
|
|
103
105
|
get children() {
|
|
104
|
-
return ssr(_tmpl$$
|
|
106
|
+
return ssr(_tmpl$$4, escape(props.error));
|
|
105
107
|
}
|
|
106
108
|
})), escape(createComponent(For, {
|
|
107
109
|
get each() {
|
|
@@ -133,7 +135,7 @@ function CollectionEdit(props) {
|
|
|
133
135
|
return props.submitLabel ?? "Save";
|
|
134
136
|
},
|
|
135
137
|
get children() {
|
|
136
|
-
return ssr(_tmpl$2$
|
|
138
|
+
return ssr(_tmpl$2$3);
|
|
137
139
|
}
|
|
138
140
|
})));
|
|
139
141
|
}
|
|
@@ -141,7 +143,7 @@ function CollectionEdit(props) {
|
|
|
141
143
|
},
|
|
142
144
|
get children() {
|
|
143
145
|
return [
|
|
144
|
-
ssr(_tmpl$3$
|
|
146
|
+
ssr(_tmpl$3$3, ssrAttribute("disabled", props.draftActions?.saving, true), escape(createComponent(Show, {
|
|
145
147
|
get when() {
|
|
146
148
|
return props.draftActions?.saving;
|
|
147
149
|
},
|
|
@@ -149,10 +151,10 @@ function CollectionEdit(props) {
|
|
|
149
151
|
return props.draftActions?.saveDraftLabel ?? "Save draft";
|
|
150
152
|
},
|
|
151
153
|
get children() {
|
|
152
|
-
return ssr(_tmpl$2$
|
|
154
|
+
return ssr(_tmpl$2$3);
|
|
153
155
|
}
|
|
154
156
|
}))),
|
|
155
|
-
ssr(_tmpl$4$
|
|
157
|
+
ssr(_tmpl$4$3, ssrAttribute("disabled", !props.draftActions?.canPublish || props.draftActions?.publishing, true), escape(createComponent(Show, {
|
|
156
158
|
get when() {
|
|
157
159
|
return props.draftActions?.publishing;
|
|
158
160
|
},
|
|
@@ -160,7 +162,7 @@ function CollectionEdit(props) {
|
|
|
160
162
|
return props.draftActions?.publishLabel ?? "Publish";
|
|
161
163
|
},
|
|
162
164
|
get children() {
|
|
163
|
-
return ssr(_tmpl$2$
|
|
165
|
+
return ssr(_tmpl$2$3);
|
|
164
166
|
}
|
|
165
167
|
}))),
|
|
166
168
|
createComponent(Show, {
|
|
@@ -168,7 +170,7 @@ function CollectionEdit(props) {
|
|
|
168
170
|
return props.draftActions?.onPreview;
|
|
169
171
|
},
|
|
170
172
|
get children() {
|
|
171
|
-
return ssr(_tmpl$5$
|
|
173
|
+
return ssr(_tmpl$5$2, ssrAttribute("disabled", !props.draftActions?.canPreview || props.draftActions?.previewing, true), escape(createComponent(Show, {
|
|
172
174
|
get when() {
|
|
173
175
|
return props.draftActions?.previewing;
|
|
174
176
|
},
|
|
@@ -176,7 +178,7 @@ function CollectionEdit(props) {
|
|
|
176
178
|
return props.draftActions?.previewLabel ?? "Preview";
|
|
177
179
|
},
|
|
178
180
|
get children() {
|
|
179
|
-
return ssr(_tmpl$2$
|
|
181
|
+
return ssr(_tmpl$2$3);
|
|
180
182
|
}
|
|
181
183
|
})));
|
|
182
184
|
}
|
|
@@ -186,6 +188,15 @@ function CollectionEdit(props) {
|
|
|
186
188
|
})));
|
|
187
189
|
}
|
|
188
190
|
function renderInput(key, field, value, setField, ctx) {
|
|
191
|
+
const Widget = ctx.fieldWidgets?.[key];
|
|
192
|
+
if (Widget) return createComponent(Widget, {
|
|
193
|
+
fieldKey: key,
|
|
194
|
+
value,
|
|
195
|
+
setValue: (v) => setField(key, v),
|
|
196
|
+
get onUploadFile() {
|
|
197
|
+
return ctx.onUploadFile;
|
|
198
|
+
}
|
|
199
|
+
});
|
|
189
200
|
switch (field.type) {
|
|
190
201
|
case "text": return ssr(_tmpl$0$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", escape(value ?? "", true), false), ssrAttribute("required", field.required, true));
|
|
191
202
|
case "select": return ssr(_tmpl$1$1, ssrAttribute("id", escape(key, true), false), ssrAttribute("value", escape(value ?? "", true), false), ssrAttribute("required", field.required, true), escape(createComponent(For, {
|
|
@@ -202,7 +213,7 @@ function renderInput(key, field, value, setField, ctx) {
|
|
|
202
213
|
case "array": return renderArrayInput(key, field, value, setField, ctx);
|
|
203
214
|
case "richText": return createComponent(Suspense, {
|
|
204
215
|
get fallback() {
|
|
205
|
-
return ssr(_tmpl$2$
|
|
216
|
+
return ssr(_tmpl$2$3);
|
|
206
217
|
},
|
|
207
218
|
get children() {
|
|
208
219
|
return createComponent(RichTextEditor, {
|
|
@@ -228,7 +239,7 @@ function renderUploadInput(key, field, value, setField, ctx) {
|
|
|
228
239
|
return uploading();
|
|
229
240
|
},
|
|
230
241
|
get children() {
|
|
231
|
-
return ssr(_tmpl$2$
|
|
242
|
+
return ssr(_tmpl$2$3);
|
|
232
243
|
}
|
|
233
244
|
})), escape(createComponent(Show, {
|
|
234
245
|
get when() {
|
|
@@ -294,17 +305,17 @@ function formatDateValue(value) {
|
|
|
294
305
|
}
|
|
295
306
|
//#endregion
|
|
296
307
|
//#region src/CollectionList.tsx
|
|
297
|
-
var _tmpl$$
|
|
308
|
+
var _tmpl$$3 = ["<button type=\"button\" class=\"btn btn-outline btn-sm\">", "</button>"], _tmpl$2$2 = [
|
|
298
309
|
"<div class=\"join\"><select aria-label=\"Sort by\" class=\"select select-sm join-item\"",
|
|
299
310
|
">",
|
|
300
311
|
"</select><select aria-label=\"Sort direction\" class=\"select select-sm join-item\"",
|
|
301
312
|
"><option value=\"asc\">Ascending</option><option value=\"desc\">Descending</option></select></div>"
|
|
302
|
-
], _tmpl$3$
|
|
313
|
+
], _tmpl$3$2 = "<th></th>", _tmpl$4$2 = [
|
|
303
314
|
"<table class=\"table hidden md:table\"><thead><tr>",
|
|
304
315
|
"",
|
|
305
316
|
"</tr></thead><tbody>",
|
|
306
317
|
"</tbody></table>"
|
|
307
|
-
], _tmpl$5 = ["<div class=\"flex flex-col gap-2 md:hidden\">", "</div>"], _tmpl$6 = [
|
|
318
|
+
], _tmpl$5$1 = ["<div class=\"flex flex-col gap-2 md:hidden\">", "</div>"], _tmpl$6$1 = [
|
|
308
319
|
"<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\"",
|
|
309
320
|
">Prev</button><span class=\"text-sm opacity-70\">Page ",
|
|
310
321
|
"</span><button type=\"button\" class=\"btn btn-sm\"",
|
|
@@ -357,14 +368,14 @@ function CollectionList(props) {
|
|
|
357
368
|
return props.selectable;
|
|
358
369
|
},
|
|
359
370
|
get children() {
|
|
360
|
-
return ssr(_tmpl$$
|
|
371
|
+
return ssr(_tmpl$$3, selectMode() ? "Done" : "Select");
|
|
361
372
|
}
|
|
362
373
|
})), escape(createComponent(Show, {
|
|
363
374
|
get when() {
|
|
364
375
|
return props.onSortChange;
|
|
365
376
|
},
|
|
366
377
|
get children() {
|
|
367
|
-
return ssr(_tmpl$2$
|
|
378
|
+
return ssr(_tmpl$2$2, ssrAttribute("value", escape(props.sortField ?? "", true), false), escape(createComponent(For, {
|
|
368
379
|
get each() {
|
|
369
380
|
return columns();
|
|
370
381
|
},
|
|
@@ -379,12 +390,12 @@ function CollectionList(props) {
|
|
|
379
390
|
return ssr(_tmpl$9, escape(props.config.slug));
|
|
380
391
|
},
|
|
381
392
|
get children() {
|
|
382
|
-
return [ssr(_tmpl$4$
|
|
393
|
+
return [ssr(_tmpl$4$2, escape(createComponent(Show, {
|
|
383
394
|
get when() {
|
|
384
395
|
return selectMode();
|
|
385
396
|
},
|
|
386
397
|
get children() {
|
|
387
|
-
return ssr(_tmpl$3$
|
|
398
|
+
return ssr(_tmpl$3$2);
|
|
388
399
|
}
|
|
389
400
|
})), escape(createComponent(For, {
|
|
390
401
|
get each() {
|
|
@@ -408,7 +419,7 @@ function CollectionList(props) {
|
|
|
408
419
|
},
|
|
409
420
|
children: ([key]) => ssr(_tmpl$11, escape(formatCellValue(row[key])))
|
|
410
421
|
})))
|
|
411
|
-
}))), ssr(_tmpl$5, escape(createComponent(For, {
|
|
422
|
+
}))), ssr(_tmpl$5$1, escape(createComponent(For, {
|
|
412
423
|
get each() {
|
|
413
424
|
return props.rows;
|
|
414
425
|
},
|
|
@@ -432,13 +443,95 @@ function CollectionList(props) {
|
|
|
432
443
|
return props.page !== void 0 && props.pageSize !== void 0;
|
|
433
444
|
},
|
|
434
445
|
get children() {
|
|
435
|
-
return ssr(_tmpl$6, ssrAttribute("disabled", (props.page ?? 1) <= 1, true), escape(props.page), ssrAttribute("disabled", props.totalCount !== void 0 ? (props.page ?? 1) * (props.pageSize ?? 0) >= props.totalCount : props.rows.length < (props.pageSize ?? 0), true));
|
|
446
|
+
return ssr(_tmpl$6$1, ssrAttribute("disabled", (props.page ?? 1) <= 1, true), escape(props.page), ssrAttribute("disabled", props.totalCount !== void 0 ? (props.page ?? 1) * (props.pageSize ?? 0) >= props.totalCount : props.rows.length < (props.pageSize ?? 0), true));
|
|
447
|
+
}
|
|
448
|
+
})));
|
|
449
|
+
}
|
|
450
|
+
//#endregion
|
|
451
|
+
//#region src/ImageHotspotField.tsx
|
|
452
|
+
var _tmpl$$2 = "<span class=\"loading loading-spinner loading-sm\"></span>", _tmpl$2$1 = ["<p class=\"text-sm text-error\">", "</p>"], _tmpl$3$1 = [
|
|
453
|
+
"<div class=\"flex flex-col gap-3\"><input",
|
|
454
|
+
" class=\"file-input\" type=\"file\" accept=\"image/*\"",
|
|
455
|
+
">",
|
|
456
|
+
"",
|
|
457
|
+
"",
|
|
458
|
+
"</div>"
|
|
459
|
+
], _tmpl$4$1 = [
|
|
460
|
+
"<div class=\"flex flex-col gap-2\"><p class=\"text-xs opacity-60\">Click the image to set the focal point.</p><div class=\"relative inline-block max-w-md\"><img",
|
|
461
|
+
" alt=\"Set focal point\" class=\"block w-full cursor-crosshair rounded\">",
|
|
462
|
+
"</div><details class=\"text-sm\"><summary class=\"cursor-pointer opacity-70\">Crop (advanced)</summary><div class=\"mt-2 grid grid-cols-4 gap-2\">",
|
|
463
|
+
"</div></details><p class=\"break-all text-xs opacity-50\">",
|
|
464
|
+
"</p></div>"
|
|
465
|
+
], _tmpl$5 = ["<span class=\"pointer-events-none absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white bg-[var(--accent,#56c6be)] shadow\" style=\"", "\"></span>"], _tmpl$6 = [
|
|
466
|
+
"<label class=\"flex flex-col gap-1 text-xs\"><span class=\"capitalize opacity-70\">",
|
|
467
|
+
"</span><input class=\"input input-sm\" type=\"number\" min=\"0\" max=\"1\" step=\"0.05\"",
|
|
468
|
+
"></label>"
|
|
469
|
+
];
|
|
470
|
+
/**
|
|
471
|
+
* Parse an upload-field value into `{ url, hotspot?, crop? }`. Accepts the
|
|
472
|
+
* JSON object this widget writes, an already-parsed object, or a bare URL
|
|
473
|
+
* string (legacy / non-hotspot uploads). Returns null for empty values.
|
|
474
|
+
*/
|
|
475
|
+
function parseImageHotspotValue(value) {
|
|
476
|
+
if (!value) return null;
|
|
477
|
+
if (typeof value === "object") return value;
|
|
478
|
+
if (typeof value === "string") {
|
|
479
|
+
const trimmed = value.trim();
|
|
480
|
+
if (trimmed.startsWith("{")) try {
|
|
481
|
+
return JSON.parse(trimmed);
|
|
482
|
+
} catch {}
|
|
483
|
+
return trimmed ? { url: trimmed } : null;
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
/** Serialize an {@link ImageWithHotspot} for storage in an upload field. */
|
|
488
|
+
function serializeImageHotspotValue(value) {
|
|
489
|
+
return JSON.stringify(value);
|
|
490
|
+
}
|
|
491
|
+
function ImageHotspotField(props) {
|
|
492
|
+
const parsed = createMemo(() => parseImageHotspotValue(props.value));
|
|
493
|
+
const [uploading, setUploading] = createSignal(false);
|
|
494
|
+
const [error, setError] = createSignal();
|
|
495
|
+
const crop = () => parsed()?.crop ?? {
|
|
496
|
+
top: 0,
|
|
497
|
+
right: 0,
|
|
498
|
+
bottom: 0,
|
|
499
|
+
left: 0
|
|
500
|
+
};
|
|
501
|
+
return ssr(_tmpl$3$1, ssrAttribute("id", escape(props.fieldKey, true), false), ssrAttribute("disabled", uploading(), true), escape(createComponent(Show, {
|
|
502
|
+
get when() {
|
|
503
|
+
return uploading();
|
|
504
|
+
},
|
|
505
|
+
get children() {
|
|
506
|
+
return ssr(_tmpl$$2);
|
|
507
|
+
}
|
|
508
|
+
})), escape(createComponent(Show, {
|
|
509
|
+
get when() {
|
|
510
|
+
return error();
|
|
511
|
+
},
|
|
512
|
+
get children() {
|
|
513
|
+
return ssr(_tmpl$2$1, escape(error()));
|
|
436
514
|
}
|
|
515
|
+
})), escape(createComponent(Show, {
|
|
516
|
+
get when() {
|
|
517
|
+
return parsed()?.url;
|
|
518
|
+
},
|
|
519
|
+
children: (url) => ssr(_tmpl$4$1, ssrAttribute("src", escape(url(), true), false), escape(createComponent(Show, {
|
|
520
|
+
get when() {
|
|
521
|
+
return parsed()?.hotspot;
|
|
522
|
+
},
|
|
523
|
+
children: (hs) => ssr(_tmpl$5, ssrStyleProperty("left:", `${escape(hs().x, true) * 100}%`) + ssrStyleProperty(";top:", `${escape(hs().y, true) * 100}%`))
|
|
524
|
+
})), escape([
|
|
525
|
+
"top",
|
|
526
|
+
"right",
|
|
527
|
+
"bottom",
|
|
528
|
+
"left"
|
|
529
|
+
].map((edge) => ssr(_tmpl$6, escape(edge), ssrAttribute("value", escape(crop()[edge], true), false)))), escape(url()))
|
|
437
530
|
})));
|
|
438
531
|
}
|
|
439
532
|
//#endregion
|
|
440
533
|
//#region src/SearchPalette.tsx
|
|
441
|
-
var _tmpl
|
|
534
|
+
var _tmpl$$1 = ["<ul class=\"max-h-80 overflow-y-auto py-2\">", "</ul>"], _tmpl$2 = [
|
|
442
535
|
"<div aria-hidden=\"true\" class=\"fixed inset-0 z-50 flex items-start justify-center bg-[var(--color-backdrop)] px-4 pt-[15vh]\"><div role=\"dialog\" aria-modal=\"true\" aria-label=\"Search\" class=\"w-full max-w-lg overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--surface-strong)] shadow-2xl\"><div class=\"flex items-center gap-2 border-b border-[var(--line)] px-4 py-3\"><i class=\"ph ph-magnifying-glass text-lg text-[var(--sea-ink-soft)]\" aria-hidden=\"true\"></i><input type=\"text\"",
|
|
443
536
|
" placeholder=\"Search…\" aria-label=\"Search\" class=\"flex-1 bg-transparent text-base text-[var(--sea-ink)] outline-none placeholder:text-[var(--sea-ink-soft)]\"><kbd class=\"rounded border border-[var(--chip-line)] bg-[var(--chip-bg)] px-1.5 py-0.5 text-xs text-[var(--sea-ink-soft)]\">Esc</kbd></div>",
|
|
444
537
|
"</div></div>"
|
|
@@ -491,7 +584,7 @@ function SearchPalette(props) {
|
|
|
491
584
|
return ssr(_tmpl$3, query().trim().length < 2 ? "Keep typing to search…" : "No results");
|
|
492
585
|
},
|
|
493
586
|
get children() {
|
|
494
|
-
return ssr(_tmpl
|
|
587
|
+
return ssr(_tmpl$$1, escape(createComponent(For, {
|
|
495
588
|
get each() {
|
|
496
589
|
return results();
|
|
497
590
|
},
|
|
@@ -503,6 +596,29 @@ function SearchPalette(props) {
|
|
|
503
596
|
});
|
|
504
597
|
}
|
|
505
598
|
//#endregion
|
|
506
|
-
|
|
599
|
+
//#region src/VisualEditingPane.tsx
|
|
600
|
+
var _tmpl$ = ["<iframe", "></iframe>"];
|
|
601
|
+
function originOf(url) {
|
|
602
|
+
try {
|
|
603
|
+
return new URL(url).origin;
|
|
604
|
+
} catch {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function VisualEditingPane(props) {
|
|
609
|
+
onMount(() => {
|
|
610
|
+
const expected = props.allowedOrigin ?? originOf(props.src);
|
|
611
|
+
const handler = (event) => {
|
|
612
|
+
if (expected && event.origin !== expected) return;
|
|
613
|
+
const data = event.data;
|
|
614
|
+
if (data?.type === VISUAL_EDIT_MESSAGE && data.ref) props.onEdit?.(data.ref);
|
|
615
|
+
};
|
|
616
|
+
window.addEventListener("message", handler);
|
|
617
|
+
onCleanup(() => window.removeEventListener("message", handler));
|
|
618
|
+
});
|
|
619
|
+
return ssr(_tmpl$, ssrAttribute("src", escape(props.src, true), false) + ssrAttribute("title", escape(props.title ?? "Preview", true), false) + ssrAttribute("class", escape(props.class ?? "h-full w-full border-0", true), false));
|
|
620
|
+
}
|
|
621
|
+
//#endregion
|
|
622
|
+
export { CollectionEdit, CollectionList, ImageHotspotField, SearchPalette, VisualEditingPane, parseImageHotspotValue, serializeImageHotspotValue };
|
|
507
623
|
|
|
508
624
|
//# sourceMappingURL=server.js.map
|