@kozou/svelte-ui 0.2.1 → 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/README.md +28 -8
- package/build/client/_app/immutable/assets/0._vgqT-Ja.css +2 -0
- package/build/client/_app/immutable/assets/0._vgqT-Ja.css.br +0 -0
- package/build/client/_app/immutable/assets/{0.B45CfnXC.css.gz → 0._vgqT-Ja.css.gz} +0 -0
- package/build/client/_app/immutable/chunks/BgT5WiOF.js +2 -0
- package/build/client/_app/immutable/chunks/BgT5WiOF.js.br +0 -0
- package/build/client/_app/immutable/chunks/BgT5WiOF.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CCUVvlTa.js +214 -0
- package/build/client/_app/immutable/chunks/CCUVvlTa.js.br +0 -0
- package/build/client/_app/immutable/chunks/CCUVvlTa.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D5sfkRNZ.js +1 -0
- package/build/client/_app/immutable/chunks/D5sfkRNZ.js.br +0 -0
- package/build/client/_app/immutable/chunks/D5sfkRNZ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{nlrTAAdT.js → DdJtfEcD.js} +3 -3
- package/build/client/_app/immutable/chunks/DdJtfEcD.js.br +0 -0
- package/build/client/_app/immutable/chunks/DdJtfEcD.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CNJ9qNKc.js → De8foa1z.js} +1 -1
- package/build/client/_app/immutable/chunks/De8foa1z.js.br +0 -0
- package/build/client/_app/immutable/chunks/De8foa1z.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DxikiVqj.js +1 -0
- package/build/client/_app/immutable/chunks/DxikiVqj.js.br +0 -0
- package/build/client/_app/immutable/chunks/DxikiVqj.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.BkKlOvdn.js +2 -0
- package/build/client/_app/immutable/entry/app.BkKlOvdn.js.br +0 -0
- package/build/client/_app/immutable/entry/app.BkKlOvdn.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.Cjh4JaF7.js +1 -0
- package/build/client/_app/immutable/entry/start.Cjh4JaF7.js.br +0 -0
- package/build/client/_app/immutable/entry/start.Cjh4JaF7.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.BTi1ueXu.js +1 -0
- package/build/client/_app/immutable/nodes/0.BTi1ueXu.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.BTi1ueXu.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.CrygsmaA.js +1 -0
- package/build/client/_app/immutable/nodes/1.CrygsmaA.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.CrygsmaA.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.CWOXCYvQ.js +1 -0
- package/build/client/_app/immutable/nodes/2.CWOXCYvQ.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.CWOXCYvQ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.BfuWEZdX.js +1 -0
- package/build/client/_app/immutable/nodes/3.BfuWEZdX.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.BfuWEZdX.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.TqsoTNiI.js +1 -0
- package/build/client/_app/immutable/nodes/4.TqsoTNiI.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.TqsoTNiI.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.6savDm4D.js +1 -0
- package/build/client/_app/immutable/nodes/5.6savDm4D.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.6savDm4D.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.B6xlqPuj.js +1 -0
- package/build/client/_app/immutable/nodes/6.B6xlqPuj.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.B6xlqPuj.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{7.zir-jrfl.js → 7.CjEmXoAF.js} +1 -1
- package/build/client/_app/immutable/nodes/7.CjEmXoAF.js.br +1 -0
- package/build/client/_app/immutable/nodes/7.CjEmXoAF.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/{0-D3i8OEah.js → 0-C4CgvBlc.js} +3 -3
- package/build/server/chunks/{0-D3i8OEah.js.map → 0-C4CgvBlc.js.map} +1 -1
- package/build/server/chunks/{1-BYbo_Ryk.js → 1-B5tolhxt.js} +3 -3
- package/build/server/chunks/{1-BYbo_Ryk.js.map → 1-B5tolhxt.js.map} +1 -1
- package/build/server/chunks/{2-CE6m9qid.js → 2-D9il_3ty.js} +2 -2
- package/build/server/chunks/{2-CE6m9qid.js.map → 2-D9il_3ty.js.map} +1 -1
- package/build/server/chunks/{3-C50aWcyD.js → 3-DfrqlU53.js} +5 -5
- package/build/server/chunks/3-DfrqlU53.js.map +1 -0
- package/build/server/chunks/{4-C8kXW-9J.js → 4-D6Y076hP.js} +53 -8
- package/build/server/chunks/4-D6Y076hP.js.map +1 -0
- package/build/server/chunks/5-DOvvx6kj.js +85 -0
- package/build/server/chunks/5-DOvvx6kj.js.map +1 -0
- package/build/server/chunks/6-BJn_aKxy.js +79 -0
- package/build/server/chunks/6-BJn_aKxy.js.map +1 -0
- package/build/server/chunks/{7-BAhFrC8Z.js → 7-CKkRKfs8.js} +5 -5
- package/build/server/chunks/7-CKkRKfs8.js.map +1 -0
- package/build/server/chunks/{ListTable-BxIw_RVF.js → ListTable-CkfkQNdN.js} +3 -7
- package/build/server/chunks/ListTable-CkfkQNdN.js.map +1 -0
- package/build/server/chunks/{_page.svelte-hNlfE_-R.js → _page.svelte-BWAo_bI_.js} +3 -3
- package/build/server/chunks/{_page.svelte-hNlfE_-R.js.map → _page.svelte-BWAo_bI_.js.map} +1 -1
- package/build/server/chunks/_page.svelte-D_706hfC.js +167 -0
- package/build/server/chunks/_page.svelte-D_706hfC.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CUhqt56V.js → _page.svelte-Dabtpyl9.js} +3 -2
- package/build/server/chunks/{_page.svelte-CUhqt56V.js.map → _page.svelte-Dabtpyl9.js.map} +1 -1
- package/build/server/chunks/_page.svelte-DpoimUgp.js +167 -0
- package/build/server/chunks/_page.svelte-DpoimUgp.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CRH5Ib1y.js → _page.svelte-j2Tqrjlb.js} +3 -2
- package/build/server/chunks/{_page.svelte-CRH5Ib1y.js.map → _page.svelte-j2Tqrjlb.js.map} +1 -1
- package/build/server/chunks/_server.ts-C-Wy675T.js +19 -0
- package/build/server/chunks/_server.ts-C-Wy675T.js.map +1 -0
- package/build/server/chunks/{adapter-BGid8Q1v.js → adapter-CXNsjV1V.js} +97 -14
- package/build/server/chunks/adapter-CXNsjV1V.js.map +1 -0
- package/build/server/chunks/{client-PK7K0DFj.js → client-_87vxA9R.js} +2 -2
- package/build/server/chunks/{client-PK7K0DFj.js.map → client-_87vxA9R.js.map} +1 -1
- package/build/server/chunks/{zod-from-table-CCy3rZQi.js → composite-form-C6ci57iZ.js} +248 -6
- package/build/server/chunks/composite-form-C6ci57iZ.js.map +1 -0
- package/build/server/chunks/{error.svelte-CKswtdNj.js → error.svelte-CsN316oS.js} +3 -3
- package/build/server/chunks/{error.svelte-CKswtdNj.js.map → error.svelte-CsN316oS.js.map} +1 -1
- package/build/server/chunks/{hooks.server-_7e7MfY9.js → hooks.server-O5zJccZI.js} +36 -14
- package/build/server/chunks/hooks.server-O5zJccZI.js.map +1 -0
- package/build/server/chunks/{internal-BERZdLJL.js → internal-Cuea68jL.js} +3 -3
- package/build/server/chunks/{internal-BERZdLJL.js.map → internal-Cuea68jL.js.map} +1 -1
- package/build/server/chunks/relation-options-Dzy9DaQG.js +87 -0
- package/build/server/chunks/relation-options-Dzy9DaQG.js.map +1 -0
- package/build/server/chunks/resource-id-PDcQeAnc.js +41 -0
- package/build/server/chunks/resource-id-PDcQeAnc.js.map +1 -0
- package/build/server/chunks/{widget-registry-CYJ6dCZP.js → widget-registry-CohQ23di.js} +282 -42
- package/build/server/chunks/widget-registry-CohQ23di.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/manifest.js +16 -9
- package/build/server/manifest.js.map +1 -1
- package/package.json +5 -5
- package/build/client/_app/immutable/assets/0.B45CfnXC.css +0 -2
- package/build/client/_app/immutable/assets/0.B45CfnXC.css.br +0 -0
- package/build/client/_app/immutable/chunks/1PNfJiP5.js +0 -2
- package/build/client/_app/immutable/chunks/1PNfJiP5.js.br +0 -0
- package/build/client/_app/immutable/chunks/1PNfJiP5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CLOztVuN.js +0 -214
- package/build/client/_app/immutable/chunks/CLOztVuN.js.br +0 -0
- package/build/client/_app/immutable/chunks/CLOztVuN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CNJ9qNKc.js.br +0 -0
- package/build/client/_app/immutable/chunks/CNJ9qNKc.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cj8LiudX.js +0 -1
- package/build/client/_app/immutable/chunks/Cj8LiudX.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cj8LiudX.js.gz +0 -0
- package/build/client/_app/immutable/chunks/nlrTAAdT.js.br +0 -0
- package/build/client/_app/immutable/chunks/nlrTAAdT.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.Bv8sjgxu.js +0 -2
- package/build/client/_app/immutable/entry/app.Bv8sjgxu.js.br +0 -0
- package/build/client/_app/immutable/entry/app.Bv8sjgxu.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.mcTncYkV.js +0 -1
- package/build/client/_app/immutable/entry/start.mcTncYkV.js.br +0 -0
- package/build/client/_app/immutable/entry/start.mcTncYkV.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.DAriStmJ.js +0 -1
- package/build/client/_app/immutable/nodes/0.DAriStmJ.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.DAriStmJ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.B_iETXYV.js +0 -1
- package/build/client/_app/immutable/nodes/1.B_iETXYV.js.br +0 -2
- package/build/client/_app/immutable/nodes/1.B_iETXYV.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.C3ChRVrO.js +0 -1
- package/build/client/_app/immutable/nodes/2.C3ChRVrO.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.C3ChRVrO.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.CL9ksnmY.js +0 -1
- package/build/client/_app/immutable/nodes/3.CL9ksnmY.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.CL9ksnmY.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.wRTS68Ip.js +0 -1
- package/build/client/_app/immutable/nodes/4.wRTS68Ip.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.wRTS68Ip.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.sOvoAy14.js +0 -1
- package/build/client/_app/immutable/nodes/5.sOvoAy14.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.sOvoAy14.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.QhxyVDh4.js +0 -1
- package/build/client/_app/immutable/nodes/6.QhxyVDh4.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.QhxyVDh4.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.zir-jrfl.js.br +0 -4
- package/build/client/_app/immutable/nodes/7.zir-jrfl.js.gz +0 -0
- package/build/server/chunks/3-C50aWcyD.js.map +0 -1
- package/build/server/chunks/4-C8kXW-9J.js.map +0 -1
- package/build/server/chunks/5-D-0L-X8y.js +0 -69
- package/build/server/chunks/5-D-0L-X8y.js.map +0 -1
- package/build/server/chunks/6-D-SbXeTH.js +0 -70
- package/build/server/chunks/6-D-SbXeTH.js.map +0 -1
- package/build/server/chunks/7-BAhFrC8Z.js.map +0 -1
- package/build/server/chunks/ListTable-BxIw_RVF.js.map +0 -1
- package/build/server/chunks/_page.svelte-6neDahmr.js +0 -70
- package/build/server/chunks/_page.svelte-6neDahmr.js.map +0 -1
- package/build/server/chunks/_page.svelte-rW7yzEet.js +0 -70
- package/build/server/chunks/_page.svelte-rW7yzEet.js.map +0 -1
- package/build/server/chunks/adapter-BGid8Q1v.js.map +0 -1
- package/build/server/chunks/hooks.server-_7e7MfY9.js.map +0 -1
- package/build/server/chunks/widget-registry-CYJ6dCZP.js.map +0 -1
- package/build/server/chunks/zod-from-table-CCy3rZQi.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { y as noop, G as parse, C as onDestroy, X as tick, S as stringify$1, c as __toESM, _ as __commonJSMin, a as __exportAll } from './internal-
|
|
1
|
+
import { y as noop, G as parse, C as onDestroy, X as tick, S as stringify$1, c as __toESM, _ as __commonJSMin, a as __exportAll } from './internal-Cuea68jL.js';
|
|
2
2
|
import { u as get$1, ad as writable, n as derived$1, Y as readonly, x as getContext } from './dev-yFiAtg5l.js';
|
|
3
|
-
import { i as invalidateAll, b as applyAction, a as afterNavigate } from './client-
|
|
3
|
+
import { i as invalidateAll, b as applyAction, a as afterNavigate } from './client-_87vxA9R.js';
|
|
4
4
|
import { a as app } from './app-DST8OmzT.js';
|
|
5
5
|
import './index-5kYmxIr9.js';
|
|
6
6
|
import { toJSONSchema, config, safeParseAsync } from 'zod/v4/core';
|
|
@@ -2388,6 +2388,191 @@ async function superValidate(data, adapter, options) {
|
|
|
2388
2388
|
}
|
|
2389
2389
|
return output;
|
|
2390
2390
|
}
|
|
2391
|
+
//#endregion
|
|
2392
|
+
//#region src/lib/form/relation-field-config.ts
|
|
2393
|
+
/**
|
|
2394
|
+
* Whether an option can round-trip through the picker contract. A key
|
|
2395
|
+
* containing an EMPTY-STRING component collides with the contract's ''
|
|
2396
|
+
* unselected sentinel — picking it would corrupt the write (the component
|
|
2397
|
+
* would be normalized to null) — so such options are not offered (a
|
|
2398
|
+
* documented limitation, see {@link promoteCompositeMemberWidgets}).
|
|
2399
|
+
*/
|
|
2400
|
+
function isPickableOption(option) {
|
|
2401
|
+
return (Array.isArray(option.id) ? option.id : [option.id]).every((part) => part !== "");
|
|
2402
|
+
}
|
|
2403
|
+
/**
|
|
2404
|
+
* The composite picker's explicit clear value. The empty string cannot mean
|
|
2405
|
+
* "clear" on the native path: an unselected (e.g. partial-null) current
|
|
2406
|
+
* value renders the select at '' too, and an untouched no-JS save must keep
|
|
2407
|
+
* the baseline values rather than erase them. A real composite option value
|
|
2408
|
+
* always contains a comma (two or more components), so this marker cannot
|
|
2409
|
+
* collide with one.
|
|
2410
|
+
*/
|
|
2411
|
+
var COMPOSITE_CLEAR_VALUE = "__clear__";
|
|
2412
|
+
/**
|
|
2413
|
+
* Name of the single form control a composite picker submits. A no-JS
|
|
2414
|
+
* (non-enhanced) submission cannot fan the selection out to the component
|
|
2415
|
+
* fields itself, so the picker's `<select>` carries the canonical encoded id
|
|
2416
|
+
* under this synthetic name and the server decodes it into the component
|
|
2417
|
+
* fields ahead of validation (see `readFormWithCompositePicks`). The enhanced
|
|
2418
|
+
* path ignores it (the form store travels in superforms' JSON envelope).
|
|
2419
|
+
*/
|
|
2420
|
+
function compositeParamName(field) {
|
|
2421
|
+
return `__composite__${field}`;
|
|
2422
|
+
}
|
|
2423
|
+
var TEXT_LIKE_BASE_TYPES = new Set([
|
|
2424
|
+
"text",
|
|
2425
|
+
"character varying",
|
|
2426
|
+
"varchar",
|
|
2427
|
+
"character",
|
|
2428
|
+
"char",
|
|
2429
|
+
"bpchar",
|
|
2430
|
+
"citext",
|
|
2431
|
+
"name"
|
|
2432
|
+
]);
|
|
2433
|
+
function isTextSearchable(dataType) {
|
|
2434
|
+
const lower = dataType.trim().toLowerCase();
|
|
2435
|
+
if (lower.includes("[")) return false;
|
|
2436
|
+
const paren = lower.indexOf("(");
|
|
2437
|
+
const base = (paren === -1 ? lower : lower.slice(0, paren)).trim();
|
|
2438
|
+
return TEXT_LIKE_BASE_TYPES.has(base);
|
|
2439
|
+
}
|
|
2440
|
+
/** Resolve the searchable label column of a picker target, or `null` when the
|
|
2441
|
+
* picker would be unusable (no text-searchable label). */
|
|
2442
|
+
function searchableLabel(target) {
|
|
2443
|
+
const labelField = target.displayField ?? target.primaryKey[0];
|
|
2444
|
+
const labelColumn = target.columns.find((c) => c.name === labelField);
|
|
2445
|
+
if (labelColumn === void 0 || !isTextSearchable(labelColumn.dataType)) return null;
|
|
2446
|
+
return {
|
|
2447
|
+
labelField,
|
|
2448
|
+
searchFields: [labelField]
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
function relationFieldConfigs(table, schema) {
|
|
2452
|
+
const configs = [];
|
|
2453
|
+
for (const relation of table.relations) {
|
|
2454
|
+
const fields = relation.fields ?? [relation.field];
|
|
2455
|
+
const referencedColumns = relation.references.columns ?? [relation.references.column];
|
|
2456
|
+
if (referencedColumns.length !== fields.length) continue;
|
|
2457
|
+
const resource = `${relation.references.schema}.${relation.references.table}`;
|
|
2458
|
+
const target = schema.tables.find((t) => t.qualifiedName === resource);
|
|
2459
|
+
if (target === void 0) continue;
|
|
2460
|
+
const primaryKey = target.primaryKey;
|
|
2461
|
+
if (primaryKey.length !== referencedColumns.length || !primaryKey.every((column) => referencedColumns.includes(column))) continue;
|
|
2462
|
+
const label = searchableLabel(target);
|
|
2463
|
+
if (label === null) continue;
|
|
2464
|
+
if (fields.length === 1) {
|
|
2465
|
+
configs.push({
|
|
2466
|
+
field: fields[0],
|
|
2467
|
+
resource,
|
|
2468
|
+
...label
|
|
2469
|
+
});
|
|
2470
|
+
continue;
|
|
2471
|
+
}
|
|
2472
|
+
if (table.columns.some((c) => c.name === compositeParamName(fields[0]))) continue;
|
|
2473
|
+
const keyFields = primaryKey.map((column) => fields[referencedColumns.indexOf(column)]);
|
|
2474
|
+
configs.push({
|
|
2475
|
+
field: fields[0],
|
|
2476
|
+
fields: [...fields],
|
|
2477
|
+
keyFields,
|
|
2478
|
+
resource,
|
|
2479
|
+
...label
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
const claims = /* @__PURE__ */ new Map();
|
|
2483
|
+
for (const relation of table.relations) for (const field of relation.fields ?? [relation.field]) claims.set(field, (claims.get(field) ?? 0) + 1);
|
|
2484
|
+
return configs.filter((config) => {
|
|
2485
|
+
const fields = config.fields ?? [config.field];
|
|
2486
|
+
if (fields.length === 1) return true;
|
|
2487
|
+
return fields.every((field) => claims.get(field) === 1);
|
|
2488
|
+
});
|
|
2489
|
+
}
|
|
2490
|
+
/**
|
|
2491
|
+
* Pick a scalar input widget for a column from its `dataType`.
|
|
2492
|
+
*
|
|
2493
|
+
* Used to demote a single-column foreign key that core marked `relation-select`
|
|
2494
|
+
* but that has no usable picker config (it references a non-PK unique column).
|
|
2495
|
+
* Without this it would render an empty, unselectable relation dropdown; the
|
|
2496
|
+
* scalar input lets the operator type the raw value instead. Mirrors the
|
|
2497
|
+
* type-based arm of core's widget inference, but keyed on the formatted
|
|
2498
|
+
* `dataType` exposed on `ColumnContext`.
|
|
2499
|
+
*/
|
|
2500
|
+
function scalarWidgetForDataType(dataType) {
|
|
2501
|
+
const type = dataType.toLowerCase();
|
|
2502
|
+
if (type === "uuid") return "uuid";
|
|
2503
|
+
if (type === "boolean" || type === "bool") return "boolean";
|
|
2504
|
+
if (type === "date") return "date";
|
|
2505
|
+
if (type.includes("timestamp") || type.startsWith("time")) return "datetime";
|
|
2506
|
+
if (type === "json" || type === "jsonb") return "json";
|
|
2507
|
+
if (type.includes("int") || type.includes("numeric") || type.includes("decimal") || type.includes("double") || type === "real") return "number";
|
|
2508
|
+
return "text";
|
|
2509
|
+
}
|
|
2510
|
+
/**
|
|
2511
|
+
* Return a copy of `table` with each unpickable single-column relation-select
|
|
2512
|
+
* column demoted to a scalar widget (see {@link scalarWidgetForDataType}).
|
|
2513
|
+
*
|
|
2514
|
+
* The create / edit routes build BOTH the rendered widget and the zod
|
|
2515
|
+
* validation schema from this, so a demoted field validates as the scalar type
|
|
2516
|
+
* the operator actually sees rather than the loose relation-select union.
|
|
2517
|
+
* Composite foreign-key columns are untouched: core never marks them
|
|
2518
|
+
* `relation-select` (they carry type-based scalar widgets), and the composite
|
|
2519
|
+
* picker writes through those scalar fields rather than replacing them.
|
|
2520
|
+
*/
|
|
2521
|
+
function demoteUnpickableRelations(table, relations) {
|
|
2522
|
+
const pickable = new Set(relations.filter((r) => (r.fields ?? [r.field]).length === 1).map((r) => r.field));
|
|
2523
|
+
return {
|
|
2524
|
+
...table,
|
|
2525
|
+
columns: table.columns.map((c) => c.widget === "relation-select" && !pickable.has(c.name) ? {
|
|
2526
|
+
...c,
|
|
2527
|
+
widget: scalarWidgetForDataType(c.dataType)
|
|
2528
|
+
} : c)
|
|
2529
|
+
};
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* Return a copy of `table` with every composite-picker component column
|
|
2533
|
+
* switched to the `relation-select` widget, so the form layer treats it as a
|
|
2534
|
+
* picker-held value rather than a typed scalar input:
|
|
2535
|
+
*
|
|
2536
|
+
* - zodFromColumn applies the picker semantics: the unselected default is
|
|
2537
|
+
* `''` and a required component rejects an empty submission — without
|
|
2538
|
+
* this, superforms initializes an absent required numeric component to
|
|
2539
|
+
* `0`, and the suppressed (never-rendered) member columns would silently
|
|
2540
|
+
* submit a fabricated `(0, 0, ...)` reference;
|
|
2541
|
+
* - buildMutationPayload normalizes `''` to null (or drops it for a
|
|
2542
|
+
* DB-supplied column) instead of letting it coerce.
|
|
2543
|
+
*
|
|
2544
|
+
* The columns themselves are never rendered — the composite picker replaces
|
|
2545
|
+
* them — so the widget change is purely a validation / payload contract.
|
|
2546
|
+
* Apply AFTER {@link demoteUnpickableRelations} (which would demote the
|
|
2547
|
+
* promoted members straight back).
|
|
2548
|
+
*
|
|
2549
|
+
* Known limitation: the contract reserves '' as the unselected sentinel
|
|
2550
|
+
* (matching the single-column picker), so a key that contains an
|
|
2551
|
+
* EMPTY-STRING component cannot round-trip through the form — a required
|
|
2552
|
+
* component rejects it and an optional one normalizes it to null. The
|
|
2553
|
+
* picker therefore does not offer such options ({@link isPickableOption}),
|
|
2554
|
+
* the native decoder treats them as malformed, and the current-value seeding
|
|
2555
|
+
* skips them; an untouched edit save of a row already holding such a key
|
|
2556
|
+
* still normalizes the '' component (this predates composite support — the
|
|
2557
|
+
* single-column picker has the same property). Such keys are pathological
|
|
2558
|
+
* schema design and remain manageable through the API.
|
|
2559
|
+
*/
|
|
2560
|
+
function promoteCompositeMemberWidgets(table, relations) {
|
|
2561
|
+
const members = /* @__PURE__ */ new Set();
|
|
2562
|
+
for (const config of relations) {
|
|
2563
|
+
const fields = config.fields ?? [config.field];
|
|
2564
|
+
if (fields.length < 2) continue;
|
|
2565
|
+
for (const field of fields) members.add(field);
|
|
2566
|
+
}
|
|
2567
|
+
if (members.size === 0) return table;
|
|
2568
|
+
return {
|
|
2569
|
+
...table,
|
|
2570
|
+
columns: table.columns.map((c) => members.has(c.name) ? {
|
|
2571
|
+
...c,
|
|
2572
|
+
widget: "relation-select"
|
|
2573
|
+
} : c)
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2391
2576
|
|
|
2392
2577
|
//#region ../../node_modules/.pnpm/memoize-weak@1.0.2/node_modules/memoize-weak/lib/memoize.js
|
|
2393
2578
|
var require_memoize = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -6869,6 +7054,11 @@ function dbCanSupplyColumn(column) {
|
|
|
6869
7054
|
return column.defaultExpr !== null || column.readonly;
|
|
6870
7055
|
}
|
|
6871
7056
|
function zodFromColumn(column) {
|
|
7057
|
+
if (column.widget === "relation-select") {
|
|
7058
|
+
const required = !column.nullable && !dbCanSupplyColumn(column);
|
|
7059
|
+
const id = z.union([required ? z.string().min(1) : z.string(), z.number()]);
|
|
7060
|
+
return (column.nullable ? id.nullable() : id).default("");
|
|
7061
|
+
}
|
|
6872
7062
|
const base = pickBase(column);
|
|
6873
7063
|
if (dbCanSupplyColumn(column)) {
|
|
6874
7064
|
const inner = column.nullable ? base.nullable() : base;
|
|
@@ -6887,7 +7077,6 @@ function pickBase(column) {
|
|
|
6887
7077
|
case "enum-select":
|
|
6888
7078
|
if (column.enumValues && column.enumValues.length > 0) return z.enum(column.enumValues);
|
|
6889
7079
|
return z.string();
|
|
6890
|
-
case "relation-select": return z.union([z.string(), z.number()]);
|
|
6891
7080
|
case "uuid": return z.guid();
|
|
6892
7081
|
case "json": return z.unknown();
|
|
6893
7082
|
case "image-url":
|
|
@@ -6901,11 +7090,17 @@ function pickBase(column) {
|
|
|
6901
7090
|
function isEmpty(value) {
|
|
6902
7091
|
return value === "" || value === void 0;
|
|
6903
7092
|
}
|
|
6904
|
-
function buildMutationPayload(table, data) {
|
|
7093
|
+
function buildMutationPayload(table, data, mode = "create") {
|
|
6905
7094
|
const byName = new Map(table.columns.map((c) => [c.name, c]));
|
|
6906
7095
|
const payload = {};
|
|
6907
7096
|
for (const [key, value] of Object.entries(data)) {
|
|
6908
7097
|
const column = byName.get(key);
|
|
7098
|
+
if (column?.widget === "relation-select" && value === "") {
|
|
7099
|
+
if (!(dbCanSupplyColumn(column) && (mode === "create" || column.readonly))) {
|
|
7100
|
+
payload[key] = null;
|
|
7101
|
+
continue;
|
|
7102
|
+
}
|
|
7103
|
+
}
|
|
6909
7104
|
if (column && dbCanSupplyColumn(column) && isEmpty(value)) continue;
|
|
6910
7105
|
payload[key] = value;
|
|
6911
7106
|
}
|
|
@@ -6918,6 +7113,53 @@ function zodFromTable(table) {
|
|
|
6918
7113
|
for (const column of table.columns) shape[column.name] = zodFromColumn(column);
|
|
6919
7114
|
return z.object(shape);
|
|
6920
7115
|
}
|
|
7116
|
+
//#endregion
|
|
7117
|
+
//#region src/lib/server/composite-form.ts
|
|
7118
|
+
/**
|
|
7119
|
+
* Return what the route action should hand to `superValidate`: the request
|
|
7120
|
+
* itself when the table has no pickers, the raw FormData when it carries the
|
|
7121
|
+
* enhanced JSON envelope, or a plain object holding the native submission
|
|
7122
|
+
* with each composite pick decoded into its component fields. Returns `null`
|
|
7123
|
+
* for a malformed composite control — wrong arity, invalid percent-encoding,
|
|
7124
|
+
* or an empty-string component — so the action can reject the submission:
|
|
7125
|
+
* letting it fall through to the schema defaults would silently CLEAR an
|
|
7126
|
+
* optional relation instead of reporting the bad value (a required one
|
|
7127
|
+
* already fails validation through the '' defaults).
|
|
7128
|
+
*/
|
|
7129
|
+
async function readFormWithCompositePicks(request, relations) {
|
|
7130
|
+
if (relations.length === 0) return request;
|
|
7131
|
+
const contentType = request.headers.get("content-type") ?? "";
|
|
7132
|
+
if (!contentType.includes("application/x-www-form-urlencoded") && !contentType.includes("multipart/form-data")) return request;
|
|
7133
|
+
const data = await request.formData();
|
|
7134
|
+
if (data.has("__superform_json")) return data;
|
|
7135
|
+
const fields = {};
|
|
7136
|
+
for (const [key, value] of data.entries()) if (typeof value === "string" && value !== "") fields[key] = value;
|
|
7137
|
+
for (const config of relations) {
|
|
7138
|
+
const keyFields = config.keyFields ?? [config.field];
|
|
7139
|
+
if (keyFields.length < 2) continue;
|
|
7140
|
+
const param = compositeParamName(config.field);
|
|
7141
|
+
const raw = fields[param];
|
|
7142
|
+
if (typeof raw !== "string") continue;
|
|
7143
|
+
delete fields[param];
|
|
7144
|
+
if (raw === "") continue;
|
|
7145
|
+
if (raw === "__clear__") {
|
|
7146
|
+
for (const field of keyFields) delete fields[field];
|
|
7147
|
+
continue;
|
|
7148
|
+
}
|
|
7149
|
+
let components;
|
|
7150
|
+
try {
|
|
7151
|
+
components = raw.split(",").map((part) => decodeURIComponent(part));
|
|
7152
|
+
} catch {
|
|
7153
|
+
return null;
|
|
7154
|
+
}
|
|
7155
|
+
if (components.length !== keyFields.length) return null;
|
|
7156
|
+
if (components.some((part) => part === "")) return null;
|
|
7157
|
+
keyFields.forEach((field, i) => {
|
|
7158
|
+
fields[field] = components[i];
|
|
7159
|
+
});
|
|
7160
|
+
}
|
|
7161
|
+
return fields;
|
|
7162
|
+
}
|
|
6921
7163
|
|
|
6922
|
-
export {
|
|
6923
|
-
//# sourceMappingURL=
|
|
7164
|
+
export { COMPOSITE_CLEAR_VALUE as C, relationFieldConfigs as a, buildMutationPayload as b, compositeParamName as c, demoteUnpickableRelations as d, superValidate as e, zodFromTable as f, isPickableOption as i, promoteCompositeMemberWidgets as p, readFormWithCompositePicks as r, superForm as s, zod as z };
|
|
7165
|
+
//# sourceMappingURL=composite-form-C6ci57iZ.js.map
|