@vertebr/react 0.2.0 → 0.4.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.
Files changed (89) hide show
  1. package/dist/components/admin/VertebrAdmin.d.ts.map +1 -1
  2. package/dist/components/admin/VertebrAdmin.js +26 -4
  3. package/dist/components/config/ConfigForm.d.ts +2 -18
  4. package/dist/components/config/ConfigForm.d.ts.map +1 -1
  5. package/dist/components/config/ConfigForm.js +1 -281
  6. package/dist/components/config/DescriptionInput.d.ts +18 -0
  7. package/dist/components/config/DescriptionInput.d.ts.map +1 -0
  8. package/dist/components/config/DescriptionInput.js +152 -0
  9. package/dist/components/config/EnumInput.d.ts +10 -0
  10. package/dist/components/config/EnumInput.d.ts.map +1 -0
  11. package/dist/components/config/EnumInput.js +19 -0
  12. package/dist/components/config/EnumListInput.d.ts +10 -0
  13. package/dist/components/config/EnumListInput.d.ts.map +1 -0
  14. package/dist/components/config/EnumListInput.js +46 -0
  15. package/dist/components/config/ImagePickerModal.d.ts +18 -0
  16. package/dist/components/config/ImagePickerModal.d.ts.map +1 -0
  17. package/dist/components/config/ImagePickerModal.js +120 -0
  18. package/dist/components/config/PriceInput.d.ts +12 -0
  19. package/dist/components/config/PriceInput.d.ts.map +1 -0
  20. package/dist/components/config/PriceInput.js +20 -0
  21. package/dist/components/config/VisibilityEye.d.ts +8 -0
  22. package/dist/components/config/VisibilityEye.d.ts.map +1 -0
  23. package/dist/components/config/VisibilityEye.js +18 -0
  24. package/dist/components/config/form/ConfigField.d.ts +22 -0
  25. package/dist/components/config/form/ConfigField.d.ts.map +1 -0
  26. package/dist/components/config/form/ConfigField.js +53 -0
  27. package/dist/components/config/form/ConfigForm.d.ts +4 -0
  28. package/dist/components/config/form/ConfigForm.d.ts.map +1 -0
  29. package/dist/components/config/form/ConfigForm.js +75 -0
  30. package/dist/components/config/form/ConfigFormActions.d.ts +11 -0
  31. package/dist/components/config/form/ConfigFormActions.d.ts.map +1 -0
  32. package/dist/components/config/form/ConfigFormActions.js +4 -0
  33. package/dist/components/config/form/RecordConfigForm.d.ts +22 -0
  34. package/dist/components/config/form/RecordConfigForm.d.ts.map +1 -0
  35. package/dist/components/config/form/RecordConfigForm.js +45 -0
  36. package/dist/components/config/form/SettingsConfigForm.d.ts +22 -0
  37. package/dist/components/config/form/SettingsConfigForm.d.ts.map +1 -0
  38. package/dist/components/config/form/SettingsConfigForm.js +7 -0
  39. package/dist/components/config/form/helpers/fields.d.ts +7 -0
  40. package/dist/components/config/form/helpers/fields.d.ts.map +1 -0
  41. package/dist/components/config/form/helpers/fields.js +31 -0
  42. package/dist/components/config/form/helpers/groups.d.ts +4 -0
  43. package/dist/components/config/form/helpers/groups.d.ts.map +1 -0
  44. package/dist/components/config/form/helpers/groups.js +107 -0
  45. package/dist/components/config/form/helpers/images.d.ts +4 -0
  46. package/dist/components/config/form/helpers/images.d.ts.map +1 -0
  47. package/dist/components/config/form/helpers/images.js +27 -0
  48. package/dist/components/config/form/helpers/index.d.ts +7 -0
  49. package/dist/components/config/form/helpers/index.d.ts.map +1 -0
  50. package/dist/components/config/form/helpers/index.js +6 -0
  51. package/dist/components/config/form/helpers/labels.d.ts +5 -0
  52. package/dist/components/config/form/helpers/labels.d.ts.map +1 -0
  53. package/dist/components/config/form/helpers/labels.js +28 -0
  54. package/dist/components/config/form/helpers/schema.d.ts +8 -0
  55. package/dist/components/config/form/helpers/schema.d.ts.map +1 -0
  56. package/dist/components/config/form/helpers/schema.js +30 -0
  57. package/dist/components/config/form/helpers/visibility.d.ts +13 -0
  58. package/dist/components/config/form/helpers/visibility.d.ts.map +1 -0
  59. package/dist/components/config/form/helpers/visibility.js +86 -0
  60. package/dist/components/config/form/types.d.ts +29 -0
  61. package/dist/components/config/form/types.d.ts.map +1 -0
  62. package/dist/components/config/form/types.js +1 -0
  63. package/dist/components/resources/ResourceCell.d.ts.map +1 -1
  64. package/dist/components/resources/ResourceCell.js +5 -19
  65. package/dist/components/resources/ResourceCreateModal.d.ts +18 -0
  66. package/dist/components/resources/ResourceCreateModal.d.ts.map +1 -0
  67. package/dist/components/resources/ResourceCreateModal.js +22 -0
  68. package/dist/components/resources/ResourceTable.d.ts +7 -2
  69. package/dist/components/resources/ResourceTable.d.ts.map +1 -1
  70. package/dist/components/resources/ResourceTable.js +92 -7
  71. package/dist/hooks/useVertebrControls.d.ts.map +1 -1
  72. package/dist/hooks/useVertebrControls.js +5 -4
  73. package/dist/index.d.ts +11 -2
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +6 -1
  76. package/dist/lib/description.d.ts +18 -0
  77. package/dist/lib/description.d.ts.map +1 -0
  78. package/dist/lib/description.js +85 -0
  79. package/dist/lib/images.d.ts +14 -0
  80. package/dist/lib/images.d.ts.map +1 -0
  81. package/dist/lib/images.js +63 -0
  82. package/dist/lib/price.d.ts +15 -0
  83. package/dist/lib/price.d.ts.map +1 -0
  84. package/dist/lib/price.js +50 -0
  85. package/dist/styles/form.css +420 -0
  86. package/dist/styles/modal.css +133 -0
  87. package/dist/styles/panel.css +18 -1
  88. package/dist/styles/table.css +10 -1
  89. package/package.json +10 -3
@@ -0,0 +1,31 @@
1
+ import { isDescriptionField } from "../../../../lib/description";
2
+ import { isImageField } from "../../../../lib/images";
3
+ export function isStockField(key, field) {
4
+ const hay = `${key} ${field?.label ?? ""}`;
5
+ return /(stock|inventory|qty|quantity)/i.test(hay);
6
+ }
7
+ export function isSpecsField(key, field) {
8
+ if (/^show[A-Z]/.test(key))
9
+ return false;
10
+ if (/^specs$/i.test(field?.group ?? ""))
11
+ return true;
12
+ const hay = `${key} ${field?.label ?? ""}`;
13
+ return /(material|fit|care|fabric|composition|^details$)/i.test(hay);
14
+ }
15
+ export function isMultilineField(key, field) {
16
+ const hay = `${key} ${field?.label ?? ""}`;
17
+ return /(detail|notes|bio|bullets)/i.test(hay);
18
+ }
19
+ export function spanFor(key, field, variant) {
20
+ if (field.type === "boolean")
21
+ return "full";
22
+ if (field.type === "enum[]")
23
+ return "full";
24
+ if (field.type === "richtext" || isDescriptionField(key, field))
25
+ return "full";
26
+ if (isMultilineField(key, field))
27
+ return "full";
28
+ if (variant === "record" && isImageField(key, field))
29
+ return "full";
30
+ return undefined;
31
+ }
@@ -0,0 +1,4 @@
1
+ import type { FieldSchema } from "@vertebr/client";
2
+ import type { ConfigFormVariant, FieldGroup } from "../types";
3
+ export declare function groupFields(schema: Record<string, FieldSchema>, variant: ConfigFormVariant): FieldGroup[];
4
+ //# sourceMappingURL=groups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groups.d.ts","sourceRoot":"","sources":["../../../../../src/components/config/form/helpers/groups.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EACV,iBAAiB,EAEjB,UAAU,EACX,MAAM,UAAU,CAAC;AA4ElB,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnC,OAAO,EAAE,iBAAiB,GACzB,UAAU,EAAE,CA6Cd"}
@@ -0,0 +1,107 @@
1
+ import { isSpecsField } from "./fields";
2
+ import { humanizeKey } from "./labels";
3
+ import { isPairedVisibilityField } from "./visibility";
4
+ const RECORD_GROUP_ORDER = [
5
+ "Details",
6
+ "Content",
7
+ "Specs",
8
+ "Pricing",
9
+ "Inventory",
10
+ "Media",
11
+ "Display",
12
+ "Status",
13
+ ];
14
+ function inferConfigGroup(key, field) {
15
+ if (field.group?.trim())
16
+ return field.group.trim();
17
+ const source = field.label?.trim() || humanizeKey(key);
18
+ const words = source.split(/\s+/).filter(Boolean);
19
+ if (words.length >= 2)
20
+ return words[0];
21
+ return "General";
22
+ }
23
+ function inferRecordGroup(key, field) {
24
+ if (field.group?.trim())
25
+ return field.group.trim();
26
+ const k = key.toLowerCase();
27
+ const label = (field.label ?? "").toLowerCase();
28
+ const hay = `${k} ${label}`;
29
+ if (/(image|img|photo|avatar|thumbnail|thumb|cover|media_url)/i.test(hay)) {
30
+ return "Media";
31
+ }
32
+ if (/(price|cost|cents|amount|msrp)/i.test(hay)) {
33
+ return "Pricing";
34
+ }
35
+ if (/(stock|inventory|qty|quantity)/i.test(hay)) {
36
+ return "Inventory";
37
+ }
38
+ if (/^display$/i.test(field.group ?? "") || /^show[A-Z]/.test(key)) {
39
+ return "Display";
40
+ }
41
+ if (field.type === "boolean" ||
42
+ /(^|_)(active|enabled|published|status|visible)(_|$)/i.test(k) ||
43
+ /^(active|enabled|published|status|visible)$/i.test(label)) {
44
+ return "Status";
45
+ }
46
+ if (field.type === "richtext" ||
47
+ /(description|body|content|summary|bio)/i.test(hay)) {
48
+ return "Content";
49
+ }
50
+ if (isSpecsField(key, field)) {
51
+ return "Specs";
52
+ }
53
+ return "Details";
54
+ }
55
+ function sortGroups(groups, variant) {
56
+ if (variant !== "record")
57
+ return groups;
58
+ const rank = (id) => {
59
+ const index = RECORD_GROUP_ORDER.indexOf(id);
60
+ return index === -1 ? RECORD_GROUP_ORDER.length + 1 : index;
61
+ };
62
+ return [...groups].sort((a, b) => rank(a.id) - rank(b.id));
63
+ }
64
+ export function groupFields(schema, variant) {
65
+ const order = [];
66
+ const map = new Map();
67
+ const explicit = new Set();
68
+ for (const entry of Object.entries(schema)) {
69
+ const [key, field] = entry;
70
+ if (isPairedVisibilityField(key, schema))
71
+ continue;
72
+ const group = variant === "record"
73
+ ? inferRecordGroup(key, field)
74
+ : inferConfigGroup(key, field);
75
+ if (field.group?.trim())
76
+ explicit.add(group);
77
+ if (!map.has(group)) {
78
+ map.set(group, []);
79
+ order.push(group);
80
+ }
81
+ map.get(group).push(entry);
82
+ }
83
+ if (variant === "config") {
84
+ for (const [group, fields] of [...map.entries()]) {
85
+ if (fields.length > 1 || explicit.has(group) || group === "General") {
86
+ continue;
87
+ }
88
+ if (!map.has("General")) {
89
+ map.set("General", []);
90
+ order.unshift("General");
91
+ }
92
+ map.get("General").push(...fields);
93
+ map.delete(group);
94
+ const idx = order.indexOf(group);
95
+ if (idx >= 0)
96
+ order.splice(idx, 1);
97
+ }
98
+ }
99
+ const groups = order
100
+ .filter((id) => map.has(id))
101
+ .map((id) => ({
102
+ id,
103
+ label: id,
104
+ fields: map.get(id),
105
+ }));
106
+ return sortGroups(groups, variant);
107
+ }
@@ -0,0 +1,4 @@
1
+ import type { FieldSchema } from "@vertebr/client";
2
+ export declare function firstImageUrl(value: unknown): string | null;
3
+ export declare function findPrimaryImageKey(schema: Record<string, FieldSchema>, values: Record<string, unknown> | undefined): string | null;
4
+ //# sourceMappingURL=images.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"images.d.ts","sourceRoot":"","sources":["../../../../../src/components/config/form/helpers/images.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAU3D;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC1C,MAAM,GAAG,IAAI,CASf"}
@@ -0,0 +1,27 @@
1
+ import { isImageField, looksLikeUrl } from "../../../../lib/images";
2
+ export function firstImageUrl(value) {
3
+ const items = Array.isArray(value) ? value : [value];
4
+ for (const item of items) {
5
+ if (typeof item === "string" && looksLikeUrl(item))
6
+ return item;
7
+ if (item && typeof item === "object" && "url" in item) {
8
+ const url = item.url;
9
+ if (typeof url === "string" && looksLikeUrl(url))
10
+ return url;
11
+ }
12
+ }
13
+ return null;
14
+ }
15
+ export function findPrimaryImageKey(schema, values) {
16
+ for (const [key, field] of Object.entries(schema)) {
17
+ if (!isImageField(key, field))
18
+ continue;
19
+ if (firstImageUrl(values?.[key]))
20
+ return key;
21
+ }
22
+ for (const [key, field] of Object.entries(schema)) {
23
+ if (isImageField(key, field))
24
+ return key;
25
+ }
26
+ return null;
27
+ }
@@ -0,0 +1,7 @@
1
+ export { buildZodSchema } from "./schema";
2
+ export { displayLabel, humanizeKey, optionLabel, } from "./labels";
3
+ export { isMultilineField, isSpecsField, isStockField, spanFor, } from "./fields";
4
+ export { fieldVisibilityKey, groupVisibilityKey, isPairedVisibilityField, showFlagKey, visibilityToggleKey, withSpecVisibility, withSpecVisibilityValues, } from "./visibility";
5
+ export { groupFields } from "./groups";
6
+ export { findPrimaryImageKey, firstImageUrl } from "./images";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/config/form/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,OAAO,GACR,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { buildZodSchema } from "./schema";
2
+ export { displayLabel, humanizeKey, optionLabel, } from "./labels";
3
+ export { isMultilineField, isSpecsField, isStockField, spanFor, } from "./fields";
4
+ export { fieldVisibilityKey, groupVisibilityKey, isPairedVisibilityField, showFlagKey, visibilityToggleKey, withSpecVisibility, withSpecVisibilityValues, } from "./visibility";
5
+ export { groupFields } from "./groups";
6
+ export { findPrimaryImageKey, firstImageUrl } from "./images";
@@ -0,0 +1,5 @@
1
+ import type { FieldSchema } from "@vertebr/client";
2
+ export declare function humanizeKey(key: string): string;
3
+ export declare function optionLabel(value: string, field?: FieldSchema): string;
4
+ export declare function displayLabel(key: string, field: FieldSchema, group: string): string;
5
+ //# sourceMappingURL=labels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"labels.d.ts","sourceRoot":"","sources":["../../../../../src/components/config/form/helpers/labels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAItE;AAMD,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,GACZ,MAAM,CAcR"}
@@ -0,0 +1,28 @@
1
+ export function humanizeKey(key) {
2
+ return key
3
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
4
+ .replace(/[_-]+/g, " ")
5
+ .trim();
6
+ }
7
+ export function optionLabel(value, field) {
8
+ const labeled = field?.optionLabels?.[value]?.trim();
9
+ if (labeled)
10
+ return labeled;
11
+ return humanizeKey(value);
12
+ }
13
+ function escapeRegExp(value) {
14
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15
+ }
16
+ export function displayLabel(key, field, group) {
17
+ const label = field.label?.trim() || humanizeKey(key);
18
+ const stripped = label.replace(new RegExp(`^${escapeRegExp(group)}\\s+`, "i"), "");
19
+ if (/^inventory$/i.test(group)) {
20
+ const stock = label.replace(/^stock\s+/i, "").trim();
21
+ if (stock && stock !== label)
22
+ return stock;
23
+ }
24
+ if (/^pricing$/i.test(group) && /cents/i.test(label)) {
25
+ return label.replace(/\s*\(cents\)/i, "").trim() || label;
26
+ }
27
+ return stripped || label;
28
+ }
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ import type { FieldSchema } from "@vertebr/client";
3
+ export declare function buildZodSchema(schema: Record<string, FieldSchema>): z.ZodObject<Record<string, z.ZodTypeAny>, "strip", z.ZodTypeAny, {
4
+ [x: string]: any;
5
+ }, {
6
+ [x: string]: any;
7
+ }>;
8
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/components/config/form/helpers/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC;;;;GA0BjE"}
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ export function buildZodSchema(schema) {
3
+ const shape = {};
4
+ for (const [key, field] of Object.entries(schema)) {
5
+ let zodField;
6
+ switch (field.type) {
7
+ case "number":
8
+ zodField = z.number();
9
+ if (field.min != null)
10
+ zodField = zodField.min(field.min);
11
+ if (field.max != null)
12
+ zodField = zodField.max(field.max);
13
+ break;
14
+ case "boolean":
15
+ zodField = z.boolean();
16
+ break;
17
+ case "file[]":
18
+ case "enum[]":
19
+ zodField = z.array(z.string());
20
+ break;
21
+ default:
22
+ zodField = z.string();
23
+ }
24
+ if (!field.required) {
25
+ zodField = zodField.optional();
26
+ }
27
+ shape[key] = zodField;
28
+ }
29
+ return z.object(shape);
30
+ }
@@ -0,0 +1,13 @@
1
+ import type { FieldSchema } from "@vertebr/client";
2
+ export declare function showFlagKey(fieldKey: string): string;
3
+ /** Ensure each Specs field has a paired `showX` boolean in the editor schema. */
4
+ export declare function withSpecVisibility(schema: Record<string, FieldSchema>): Record<string, FieldSchema>;
5
+ export declare function withSpecVisibilityValues(schema: Record<string, FieldSchema>, value: Record<string, unknown>): Record<string, unknown>;
6
+ /** `showMaterial` paired with `material`, `showPrice` with `priceCents`. */
7
+ export declare function visibilityToggleKey(fieldKey: string, schema: Record<string, FieldSchema>): string | null;
8
+ export declare function isPairedVisibilityField(key: string, schema: Record<string, FieldSchema>): boolean;
9
+ /** Section-level storefront flag, e.g. Pricing → `showPrice`. */
10
+ export declare function groupVisibilityKey(groupId: string, schema: Record<string, FieldSchema>): string | null;
11
+ /** Field-level flag, skipped when the section header already owns it. */
12
+ export declare function fieldVisibilityKey(fieldKey: string, schema: Record<string, FieldSchema>, groupId?: string): string | null;
13
+ //# sourceMappingURL=visibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../../../../src/components/config/form/helpers/visibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAInD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAc7B;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAMD,4EAA4E;AAC5E,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAClC,MAAM,GAAG,IAAI,CASf;AAcD,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAClC,OAAO,CAMT;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAClC,MAAM,GAAG,IAAI,CAIf;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACnC,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAKf"}
@@ -0,0 +1,86 @@
1
+ import { isSpecsField } from "./fields";
2
+ import { humanizeKey } from "./labels";
3
+ export function showFlagKey(fieldKey) {
4
+ return `show${fieldKey.charAt(0).toUpperCase()}${fieldKey.slice(1)}`;
5
+ }
6
+ /** Ensure each Specs field has a paired `showX` boolean in the editor schema. */
7
+ export function withSpecVisibility(schema) {
8
+ const next = { ...schema };
9
+ for (const [key, field] of Object.entries(schema)) {
10
+ if (field.type === "boolean" || !isSpecsField(key, field))
11
+ continue;
12
+ const flag = showFlagKey(key);
13
+ if (!next[flag]) {
14
+ next[flag] = {
15
+ type: "boolean",
16
+ default: true,
17
+ label: `Show ${field.label ?? humanizeKey(key)}`,
18
+ };
19
+ }
20
+ }
21
+ return next;
22
+ }
23
+ export function withSpecVisibilityValues(schema, value) {
24
+ const next = { ...value };
25
+ for (const [key, field] of Object.entries(schema)) {
26
+ if (field.type === "boolean" || !isSpecsField(key, field))
27
+ continue;
28
+ const flag = showFlagKey(key);
29
+ if (!(flag in next) || next[flag] == null)
30
+ next[flag] = true;
31
+ else
32
+ next[flag] = next[flag] !== false;
33
+ }
34
+ return next;
35
+ }
36
+ function pascalToCamel(value) {
37
+ return value.charAt(0).toLowerCase() + value.slice(1);
38
+ }
39
+ /** `showMaterial` paired with `material`, `showPrice` with `priceCents`. */
40
+ export function visibilityToggleKey(fieldKey, schema) {
41
+ const flag = showFlagKey(fieldKey);
42
+ const candidates = [flag];
43
+ if (fieldKey === "priceCents")
44
+ candidates.push("showPrice");
45
+ for (const key of candidates) {
46
+ if (schema[key]?.type === "boolean")
47
+ return key;
48
+ }
49
+ if (isSpecsField(fieldKey, schema[fieldKey]))
50
+ return flag;
51
+ return null;
52
+ }
53
+ const GROUP_VISIBILITY = {
54
+ Pricing: "showPrice",
55
+ Inventory: "showStock",
56
+ Content: "showDescription",
57
+ };
58
+ function groupVisibilityKeyFromField(key) {
59
+ return Object.keys(GROUP_VISIBILITY).find((group) => GROUP_VISIBILITY[group] === key);
60
+ }
61
+ export function isPairedVisibilityField(key, schema) {
62
+ if (!/^show[A-Z]/.test(key) || schema[key]?.type !== "boolean")
63
+ return false;
64
+ if (groupVisibilityKeyFromField(key))
65
+ return true;
66
+ const target = pascalToCamel(key.slice(4));
67
+ if (schema[target])
68
+ return true;
69
+ return key === "showPrice" && Boolean(schema.priceCents);
70
+ }
71
+ /** Section-level storefront flag, e.g. Pricing → `showPrice`. */
72
+ export function groupVisibilityKey(groupId, schema) {
73
+ const key = GROUP_VISIBILITY[groupId];
74
+ if (key && schema[key]?.type === "boolean")
75
+ return key;
76
+ return null;
77
+ }
78
+ /** Field-level flag, skipped when the section header already owns it. */
79
+ export function fieldVisibilityKey(fieldKey, schema, groupId) {
80
+ const paired = visibilityToggleKey(fieldKey, schema);
81
+ if (!paired)
82
+ return null;
83
+ if (groupId && groupVisibilityKey(groupId, schema) === paired)
84
+ return null;
85
+ return paired;
86
+ }
@@ -0,0 +1,29 @@
1
+ import type { FieldSchema, GalleryItem, ResourceUploadMeta } from "@vertebr/client";
2
+ export type ConfigFormVariant = "config" | "record";
3
+ export type ConfigFormProps = {
4
+ schema: Record<string, FieldSchema>;
5
+ value: Record<string, unknown>;
6
+ onSave: (value: Record<string, unknown>) => Promise<void>;
7
+ /** Primary submit button label. @default "Save changes" */
8
+ submitLabel?: string;
9
+ /** `record` uses a dense product-style editor. */
10
+ variant?: ConfigFormVariant;
11
+ /** Field-keyed upload capabilities from the host resource. */
12
+ uploads?: Record<string, ResourceUploadMeta>;
13
+ /** Upload files for a field; return public URL(s). */
14
+ onUpload?: (field: string, files: File[]) => Promise<Array<{
15
+ url: string;
16
+ name?: string;
17
+ }>>;
18
+ galleryUpload?: Pick<ResourceUploadMeta, "accept" | "maxBytes">;
19
+ onListGallery?: () => Promise<GalleryItem[]>;
20
+ onUploadGallery?: (files: File[]) => Promise<GalleryItem[]>;
21
+ };
22
+ export type FieldEntry = [string, FieldSchema];
23
+ export type FieldGroup = {
24
+ id: string;
25
+ label: string;
26
+ fields: FieldEntry[];
27
+ };
28
+ export type GalleryHandlers = Pick<ConfigFormProps, "galleryUpload" | "onListGallery" | "onUploadGallery">;
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/config/form/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEpD,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC7D,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,eAAe,EACf,eAAe,GAAG,eAAe,GAAG,iBAAiB,CACtD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceCell.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceCell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAuDnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9B,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAK,EACL,KAAK,EACL,OAAiB,GAClB,EAAE,iBAAiB,+BAsInB"}
1
+ {"version":3,"file":"ResourceCell.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceCell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA6CnD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9B,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,KAAK,EACL,KAAK,EACL,OAAiB,GAClB,EAAE,iBAAiB,+BA0InB"}
@@ -1,8 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { formatPrice, isCentsField, isPriceField, } from "../../lib/price";
2
3
  const IMAGE_KEY = /(image|img|photo|avatar|thumbnail|thumb|cover)/i;
3
4
  const URL_KEY = /(url|href|link|src)/i;
4
- const CENTS_KEY = /(cents|priceCents|amountCents)/i;
5
- const PRICE_KEY = /(price|amount|cost|total)/i;
6
5
  const IMAGE_EXT = /\.(png|jpe?g|gif|webp|svg|avif)(\?|#|$)/i;
7
6
  function looksLikeUrl(value) {
8
7
  return /^https?:\/\//i.test(value) || value.startsWith("//");
@@ -37,19 +36,6 @@ function formatDate(value) {
37
36
  }
38
37
  return null;
39
38
  }
40
- function formatMoney(value, asCents) {
41
- const amount = asCents ? value / 100 : value;
42
- try {
43
- return new Intl.NumberFormat(undefined, {
44
- style: "currency",
45
- currency: "USD",
46
- maximumFractionDigits: asCents || !Number.isInteger(amount) ? 2 : 0,
47
- }).format(amount);
48
- }
49
- catch {
50
- return asCents ? `$${(value / 100).toFixed(2)}` : String(value);
51
- }
52
- }
53
39
  export function ResourceCell({ fieldKey, field, value, variant = "table", }) {
54
40
  const detail = variant === "detail";
55
41
  if (value == null || value === "") {
@@ -68,11 +54,11 @@ export function ResourceCell({ fieldKey, field, value, variant = "table", }) {
68
54
  }
69
55
  if (type === "number" || typeof value === "number") {
70
56
  if (typeof value === "number" && Number.isFinite(value)) {
71
- if (CENTS_KEY.test(fieldKey) || /cents/i.test(field?.label ?? "")) {
72
- return (_jsx("span", { className: "vertebr-cell-money", children: formatMoney(value, true) }));
57
+ if (isCentsField(fieldKey, field)) {
58
+ return (_jsx("span", { className: "vertebr-cell-money", children: formatPrice(value, { asCents: true }) }));
73
59
  }
74
- if (PRICE_KEY.test(fieldKey)) {
75
- return (_jsx("span", { className: "vertebr-cell-money", children: formatMoney(value, false) }));
60
+ if (isPriceField(fieldKey, field)) {
61
+ return (_jsx("span", { className: "vertebr-cell-money", children: formatPrice(value, { asCents: false }) }));
76
62
  }
77
63
  return (_jsx("span", { className: "vertebr-cell-number", children: new Intl.NumberFormat().format(value) }));
78
64
  }
@@ -0,0 +1,18 @@
1
+ import type { FieldSchema, GalleryItem, ResourceUploadMeta } from "@vertebr/client";
2
+ export type ResourceCreateModalProps = {
3
+ title: string;
4
+ schema: Record<string, FieldSchema>;
5
+ value: Record<string, unknown>;
6
+ uploads?: Record<string, ResourceUploadMeta>;
7
+ onUpload?: (field: string, files: File[]) => Promise<Array<{
8
+ url: string;
9
+ name?: string;
10
+ }>>;
11
+ galleryUpload?: Pick<ResourceUploadMeta, "accept" | "maxBytes">;
12
+ onListGallery?: () => Promise<GalleryItem[]>;
13
+ onUploadGallery?: (files: File[]) => Promise<GalleryItem[]>;
14
+ onClose: () => void;
15
+ onCreate: (value: Record<string, unknown>) => Promise<void>;
16
+ };
17
+ export declare function ResourceCreateModal({ title, schema, value, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onClose, onCreate, }: ResourceCreateModalProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=ResourceCreateModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResourceCreateModal.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceCreateModal.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAGzB,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,MAAM,EACN,KAAK,EACL,OAAO,EACP,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,EACf,OAAO,EACP,QAAQ,GACT,EAAE,wBAAwB,+BA+D1B"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { ConfigForm } from "../config/ConfigForm";
4
+ export function ResourceCreateModal({ title, schema, value, uploads, onUpload, galleryUpload, onListGallery, onUploadGallery, onClose, onCreate, }) {
5
+ useEffect(() => {
6
+ const onKeyDown = (event) => {
7
+ if (event.key === "Escape")
8
+ onClose();
9
+ };
10
+ window.addEventListener("keydown", onKeyDown);
11
+ const previous = document.body.style.overflow;
12
+ document.body.style.overflow = "hidden";
13
+ return () => {
14
+ window.removeEventListener("keydown", onKeyDown);
15
+ document.body.style.overflow = previous;
16
+ };
17
+ }, [onClose]);
18
+ return (_jsx("div", { className: "vertebr-modal-backdrop", role: "presentation", onClick: onClose, children: _jsxs("div", { className: "vertebr-modal vertebr-modal-form", role: "dialog", "aria-modal": "true", "aria-label": title, onClick: (event) => event.stopPropagation(), children: [_jsxs("header", { className: "vertebr-modal-head", children: [_jsxs("div", { className: "vertebr-modal-heading", children: [_jsx("p", { className: "vertebr-modal-eyebrow", children: "New record" }), _jsx("h2", { children: title })] }), _jsx("div", { className: "vertebr-modal-actions", children: _jsx("button", { type: "button", className: "vertebr-btn", onClick: onClose, "aria-label": "Close", children: "Close" }) })] }), _jsx("div", { className: "vertebr-modal-body", children: _jsx(ConfigForm, { variant: "record", schema: schema, value: value, uploads: uploads, onUpload: onUpload, galleryUpload: galleryUpload, onListGallery: onListGallery, onUploadGallery: onUploadGallery, submitLabel: title, onSave: async (next) => {
19
+ await onCreate(next);
20
+ onClose();
21
+ } }) })] }) }));
22
+ }
@@ -1,4 +1,4 @@
1
- import type { FieldSchema, ResourceActionMeta, ResourceUploadMeta } from "@vertebr/client";
1
+ import type { FieldSchema, GalleryItem, ResourceActionMeta, ResourceUploadMeta } from "@vertebr/client";
2
2
  type ResourcePanelProps = {
3
3
  schema: Record<string, FieldSchema>;
4
4
  items: Record<string, unknown>[];
@@ -8,6 +8,8 @@ type ResourcePanelProps = {
8
8
  delete?: boolean;
9
9
  };
10
10
  actions?: Record<string, ResourceActionMeta>;
11
+ /** Resource label, e.g. `"Products"` → Add product. */
12
+ label?: string;
11
13
  uploads?: Record<string, ResourceUploadMeta>;
12
14
  rowIdKeys?: string[];
13
15
  /** Persist column visibility under this key (e.g. resource id). */
@@ -20,8 +22,11 @@ type ResourcePanelProps = {
20
22
  url: string;
21
23
  name?: string;
22
24
  }>>;
25
+ galleryUpload?: Pick<ResourceUploadMeta, "accept" | "maxBytes">;
26
+ onListGallery?: () => Promise<GalleryItem[]>;
27
+ onUploadGallery?: (files: File[]) => Promise<GalleryItem[]>;
23
28
  };
24
- export declare function ResourcePanel({ schema, items, permissions, actions, uploads, rowIdKeys, storageKey, onUpdate, onCreate, onDelete, onAction, onUpload, }: ResourcePanelProps): import("react").JSX.Element;
29
+ export declare function ResourcePanel({ schema, items, permissions, actions, label, uploads, rowIdKeys, storageKey, onUpdate, onCreate, onDelete, onAction, onUpload, galleryUpload, onListGallery, onUploadGallery, }: ResourcePanelProps): import("react").JSX.Element;
25
30
  /** @deprecated Prefer ResourcePanel */
26
31
  export declare function ResourceTable(props: {
27
32
  schema: Record<string, FieldSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceTable.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceTable.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAMzB,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE;QACZ,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CACrD,CAAC;AA+DF,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,WAAW,EACX,OAAY,EACZ,OAAO,EACP,SAA0C,EAC1C,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,GACT,EAAE,kBAAkB,+BAoVpB;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CAClC,+BAEA"}
1
+ {"version":3,"file":"ResourceTable.d.ts","sourceRoot":"","sources":["../../../src/components/resources/ResourceTable.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAOzB,KAAK,kBAAkB,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE;QACZ,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,EAAE,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpD,aAAa,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;CAC7D,CAAC;AA0EF,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,WAAW,EACX,OAAY,EACZ,KAAK,EACL,OAAO,EACP,SAA0C,EAC1C,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,aAAa,EACb,eAAe,GAChB,EAAE,kBAAkB,+BAqdpB;AAED,uCAAuC;AACvC,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CAClC,+BAEA"}