@fluid-app/rep-core 0.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.
Files changed (45) hide show
  1. package/dist/chunk-6QLUUNJL.cjs +153 -0
  2. package/dist/chunk-6QLUUNJL.cjs.map +1 -0
  3. package/dist/chunk-EWR5EIBP.js +136 -0
  4. package/dist/chunk-EWR5EIBP.js.map +1 -0
  5. package/dist/data-sources/context.cjs +26 -0
  6. package/dist/data-sources/context.cjs.map +1 -0
  7. package/dist/data-sources/context.d.cts +16 -0
  8. package/dist/data-sources/context.d.ts +16 -0
  9. package/dist/data-sources/context.js +23 -0
  10. package/dist/data-sources/context.js.map +1 -0
  11. package/dist/data-sources/types.cjs +4 -0
  12. package/dist/data-sources/types.cjs.map +1 -0
  13. package/dist/data-sources/types.d.cts +122 -0
  14. package/dist/data-sources/types.d.ts +122 -0
  15. package/dist/data-sources/types.js +3 -0
  16. package/dist/data-sources/types.js.map +1 -0
  17. package/dist/registries/index.cjs +156 -0
  18. package/dist/registries/index.cjs.map +1 -0
  19. package/dist/registries/index.d.cts +303 -0
  20. package/dist/registries/index.d.ts +303 -0
  21. package/dist/registries/index.js +143 -0
  22. package/dist/registries/index.js.map +1 -0
  23. package/dist/shareable-item-DPmNZkE1.d.cts +138 -0
  24. package/dist/shareable-item-DPmNZkE1.d.ts +138 -0
  25. package/dist/theme/index.cjs +1013 -0
  26. package/dist/theme/index.cjs.map +1 -0
  27. package/dist/theme/index.d.cts +2680 -0
  28. package/dist/theme/index.d.ts +2680 -0
  29. package/dist/theme/index.js +956 -0
  30. package/dist/theme/index.js.map +1 -0
  31. package/dist/theme-DrMUYZTO.d.cts +22 -0
  32. package/dist/theme-DrMUYZTO.d.ts +22 -0
  33. package/dist/types/index.cjs +72 -0
  34. package/dist/types/index.cjs.map +1 -0
  35. package/dist/types/index.d.cts +227 -0
  36. package/dist/types/index.d.ts +227 -0
  37. package/dist/types/index.js +3 -0
  38. package/dist/types/index.js.map +1 -0
  39. package/dist/widget-utils/index.cjs +123 -0
  40. package/dist/widget-utils/index.cjs.map +1 -0
  41. package/dist/widget-utils/index.d.cts +43 -0
  42. package/dist/widget-utils/index.d.ts +43 -0
  43. package/dist/widget-utils/index.js +111 -0
  44. package/dist/widget-utils/index.js.map +1 -0
  45. package/package.json +99 -0
@@ -0,0 +1,227 @@
1
+ import { a as WidgetSchema, S as ShareableItem } from '../shareable-item-DPmNZkE1.js';
2
+ export { T as TypedWidgetSchema, e as WIDGET_TYPE_NAMES, W as WidgetPath, d as WidgetRegistry, b as WidgetType, c as WidgetTypeName, h as assertDefined, g as assertNever, f as isWidgetType, i as isWidgetTypeName } from '../shareable-item-DPmNZkE1.js';
3
+ export { a as Theme, T as ThemeConfig } from '../theme-DrMUYZTO.js';
4
+ import 'react';
5
+
6
+ /**
7
+ * Navigation item in the sidebar/menu structure
8
+ */
9
+ interface NavigationItem {
10
+ /** Database-generated identifier */
11
+ readonly id?: number;
12
+ /** URL slug for routing */
13
+ slug?: string;
14
+ /** Display label */
15
+ label: string;
16
+ /** Icon identifier (e.g., FontAwesome name) */
17
+ icon?: string;
18
+ /** Section grouping for quick links (e.g., "User", "Shareables") */
19
+ section?: string;
20
+ /** Associated screen ID */
21
+ screen_id?: number;
22
+ /** Sort order */
23
+ position?: number;
24
+ /** Parent navigation item ID (null for root items) */
25
+ parent_id?: number | null;
26
+ /** Nested navigation items */
27
+ children: NavigationItem[];
28
+ }
29
+ /**
30
+ * Screen definition with its component tree
31
+ */
32
+ interface ScreenDefinition {
33
+ readonly id: number;
34
+ slug: string;
35
+ name: string;
36
+ component_tree: WidgetSchema[];
37
+ }
38
+ /**
39
+ * Navigation configuration for the rep portal
40
+ */
41
+ interface Navigation {
42
+ readonly definition_id: number;
43
+ readonly id: number;
44
+ name: string;
45
+ navigation_items: NavigationItem[];
46
+ screens: ScreenDefinition[];
47
+ }
48
+
49
+ /**
50
+ * Color options constant - single source of truth for color values.
51
+ * Use COLOR_OPTIONS.primary instead of "primary" for type-safe comparisons.
52
+ */
53
+ declare const COLOR_OPTIONS: {
54
+ readonly background: "background";
55
+ readonly foreground: "foreground";
56
+ readonly primary: "primary";
57
+ readonly secondary: "secondary";
58
+ readonly accent: "accent";
59
+ readonly muted: "muted";
60
+ readonly destructive: "destructive";
61
+ };
62
+ /**
63
+ * Union type of all color options, derived from COLOR_OPTIONS constant.
64
+ * @see deriving-typeof-for-object-keys pattern
65
+ */
66
+ type ColorOptions = (typeof COLOR_OPTIONS)[keyof typeof COLOR_OPTIONS];
67
+ declare const FONT_SIZE_OPTIONS: {
68
+ readonly "2xl": "2xl";
69
+ readonly xl: "xl";
70
+ readonly lg: "lg";
71
+ readonly md: "md";
72
+ readonly sm: "sm";
73
+ readonly xs: "xs";
74
+ };
75
+ type FontSizeOptions = (typeof FONT_SIZE_OPTIONS)[keyof typeof FONT_SIZE_OPTIONS];
76
+ declare const BORDER_RADIUS_OPTIONS: {
77
+ readonly none: "none";
78
+ readonly sm: "sm";
79
+ readonly md: "md";
80
+ readonly lg: "lg";
81
+ readonly xl: "xl";
82
+ readonly full: "full";
83
+ };
84
+ type BorderRadiusOptions = (typeof BORDER_RADIUS_OPTIONS)[keyof typeof BORDER_RADIUS_OPTIONS];
85
+ /** Padding values - numeric, so we use a tuple for derivation */
86
+ declare const PADDING_VALUES: readonly [0, 2, 4, 6, 8, 10];
87
+ type PaddingOptions = (typeof PADDING_VALUES)[number];
88
+ declare const BUTTON_SIZE_OPTIONS: {
89
+ readonly sm: "sm";
90
+ readonly default: "default";
91
+ readonly lg: "lg";
92
+ readonly xl: "xl";
93
+ };
94
+ type ButtonSizeOptions = (typeof BUTTON_SIZE_OPTIONS)[keyof typeof BUTTON_SIZE_OPTIONS];
95
+ declare const GAP_OPTIONS: {
96
+ readonly none: "none";
97
+ readonly xs: "xs";
98
+ readonly sm: "sm";
99
+ readonly md: "md";
100
+ readonly lg: "lg";
101
+ readonly xl: "xl";
102
+ };
103
+ type GapOptions = (typeof GAP_OPTIONS)[keyof typeof GAP_OPTIONS];
104
+ declare const VERTICAL_ALIGN_OPTIONS: {
105
+ readonly top: "top";
106
+ readonly center: "center";
107
+ readonly bottom: "bottom";
108
+ };
109
+ type VerticalAlign = (typeof VERTICAL_ALIGN_OPTIONS)[keyof typeof VERTICAL_ALIGN_OPTIONS];
110
+ declare const HORIZONTAL_ALIGN_OPTIONS: {
111
+ readonly left: "left";
112
+ readonly center: "center";
113
+ readonly right: "right";
114
+ };
115
+ type HorizontalAlign = (typeof HORIZONTAL_ALIGN_OPTIONS)[keyof typeof HORIZONTAL_ALIGN_OPTIONS];
116
+ type AlignOptions = {
117
+ vertical?: VerticalAlign;
118
+ horizontal?: HorizontalAlign;
119
+ };
120
+ declare const BACKGROUND_TYPES: {
121
+ readonly solid: "solid";
122
+ readonly image: "image";
123
+ };
124
+ type BackgroundType = (typeof BACKGROUND_TYPES)[keyof typeof BACKGROUND_TYPES];
125
+ interface BackgroundValue {
126
+ type: BackgroundType;
127
+ color?: ColorOptions;
128
+ resource?: ShareableItem;
129
+ }
130
+ /**
131
+ * Section layout configuration - single source of truth for layout types.
132
+ * SectionLayoutType is derived from these keys to prevent drift.
133
+ */
134
+ declare const SECTION_LAYOUT_CONFIG: {
135
+ readonly "single-column": {
136
+ readonly columns: 1;
137
+ readonly widths: readonly ["1fr"];
138
+ readonly gridClasses: "";
139
+ };
140
+ readonly "2c-equal": {
141
+ readonly columns: 2;
142
+ readonly widths: readonly ["1fr", "1fr"];
143
+ readonly gridClasses: "@md:grid-cols-2";
144
+ };
145
+ readonly "2c-left-wider": {
146
+ readonly columns: 2;
147
+ readonly widths: readonly ["2fr", "1fr"];
148
+ readonly gridClasses: "@md:grid-cols-[2fr_1fr]";
149
+ };
150
+ readonly "2c-right-wider": {
151
+ readonly columns: 2;
152
+ readonly widths: readonly ["1fr", "2fr"];
153
+ readonly gridClasses: "@md:grid-cols-[1fr_2fr]";
154
+ };
155
+ readonly "2c-left-narrow": {
156
+ readonly columns: 2;
157
+ readonly widths: readonly ["1fr", "3fr"];
158
+ readonly gridClasses: "@md:grid-cols-[1fr_3fr]";
159
+ };
160
+ readonly "2c-right-narrow": {
161
+ readonly columns: 2;
162
+ readonly widths: readonly ["3fr", "1fr"];
163
+ readonly gridClasses: "@md:grid-cols-[3fr_1fr]";
164
+ };
165
+ readonly "3c-equal": {
166
+ readonly columns: 3;
167
+ readonly widths: readonly ["1fr", "1fr", "1fr"];
168
+ readonly gridClasses: "@md:grid-cols-3";
169
+ };
170
+ readonly "3c-middle-wider": {
171
+ readonly columns: 3;
172
+ readonly widths: readonly ["1fr", "2fr", "1fr"];
173
+ readonly gridClasses: "@md:grid-cols-[1fr_2fr_1fr]";
174
+ };
175
+ };
176
+ /**
177
+ * Union type of all section layout types, derived from SECTION_LAYOUT_CONFIG keys.
178
+ * @see deriving-typeof-for-object-keys pattern
179
+ */
180
+ type SectionLayoutType = keyof typeof SECTION_LAYOUT_CONFIG;
181
+ /** @deprecated Use SECTION_LAYOUT_CONFIG instead */
182
+ declare const sectionLayoutConfig: {
183
+ readonly "single-column": {
184
+ readonly columns: 1;
185
+ readonly widths: readonly ["1fr"];
186
+ readonly gridClasses: "";
187
+ };
188
+ readonly "2c-equal": {
189
+ readonly columns: 2;
190
+ readonly widths: readonly ["1fr", "1fr"];
191
+ readonly gridClasses: "@md:grid-cols-2";
192
+ };
193
+ readonly "2c-left-wider": {
194
+ readonly columns: 2;
195
+ readonly widths: readonly ["2fr", "1fr"];
196
+ readonly gridClasses: "@md:grid-cols-[2fr_1fr]";
197
+ };
198
+ readonly "2c-right-wider": {
199
+ readonly columns: 2;
200
+ readonly widths: readonly ["1fr", "2fr"];
201
+ readonly gridClasses: "@md:grid-cols-[1fr_2fr]";
202
+ };
203
+ readonly "2c-left-narrow": {
204
+ readonly columns: 2;
205
+ readonly widths: readonly ["1fr", "3fr"];
206
+ readonly gridClasses: "@md:grid-cols-[1fr_3fr]";
207
+ };
208
+ readonly "2c-right-narrow": {
209
+ readonly columns: 2;
210
+ readonly widths: readonly ["3fr", "1fr"];
211
+ readonly gridClasses: "@md:grid-cols-[3fr_1fr]";
212
+ };
213
+ readonly "3c-equal": {
214
+ readonly columns: 3;
215
+ readonly widths: readonly ["1fr", "1fr", "1fr"];
216
+ readonly gridClasses: "@md:grid-cols-3";
217
+ };
218
+ readonly "3c-middle-wider": {
219
+ readonly columns: 3;
220
+ readonly widths: readonly ["1fr", "2fr", "1fr"];
221
+ readonly gridClasses: "@md:grid-cols-[1fr_2fr_1fr]";
222
+ };
223
+ };
224
+
225
+ type StrictOmit<T, K extends keyof T> = Omit<T, K>;
226
+
227
+ export { type AlignOptions, BACKGROUND_TYPES, BORDER_RADIUS_OPTIONS, BUTTON_SIZE_OPTIONS, type BackgroundType, type BackgroundValue, type BorderRadiusOptions, type ButtonSizeOptions, COLOR_OPTIONS, type ColorOptions, FONT_SIZE_OPTIONS, type FontSizeOptions, GAP_OPTIONS, type GapOptions, HORIZONTAL_ALIGN_OPTIONS, type HorizontalAlign, type Navigation, type NavigationItem, PADDING_VALUES, type PaddingOptions, SECTION_LAYOUT_CONFIG, type ScreenDefinition, type SectionLayoutType, ShareableItem, type StrictOmit, VERTICAL_ALIGN_OPTIONS, type VerticalAlign, WidgetSchema, sectionLayoutConfig };
@@ -0,0 +1,3 @@
1
+ export { BACKGROUND_TYPES, BORDER_RADIUS_OPTIONS, BUTTON_SIZE_OPTIONS, COLOR_OPTIONS, FONT_SIZE_OPTIONS, GAP_OPTIONS, HORIZONTAL_ALIGN_OPTIONS, PADDING_VALUES, SECTION_LAYOUT_CONFIG, VERTICAL_ALIGN_OPTIONS, WIDGET_TYPE_NAMES, assertDefined, assertNever, isWidgetType, isWidgetTypeName, sectionLayoutConfig } from '../chunk-EWR5EIBP.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,123 @@
1
+ 'use strict';
2
+
3
+ var chunk6QLUUNJL_cjs = require('../chunk-6QLUUNJL.cjs');
4
+
5
+ // src/widget-utils/widget-utils.ts
6
+ function generateWidgetId(type) {
7
+ const uuid = crypto.randomUUID();
8
+ return type ? `${type}-${uuid}` : uuid;
9
+ }
10
+ function pathToId(path) {
11
+ return path.join("-");
12
+ }
13
+ function idToPath(id) {
14
+ return id.split("-").map((segment) => parseInt(segment, 10));
15
+ }
16
+ function ensureWidgetIds(widgets) {
17
+ return widgets?.map((widget, index) => {
18
+ if (!widget) return null;
19
+ return {
20
+ ...widget,
21
+ id: widget.id || `widget-${index}-${crypto.randomUUID()}`
22
+ };
23
+ });
24
+ }
25
+ function deepCloneWidget(widget) {
26
+ if (chunk6QLUUNJL_cjs.isWidgetType(widget, chunk6QLUUNJL_cjs.WIDGET_TYPE_NAMES.Layout) && Array.isArray(widget.props.children)) {
27
+ return {
28
+ type: widget.type,
29
+ props: {
30
+ ...widget.props,
31
+ children: widget.props.children.map((child) => child ? deepCloneWidget(child) : null)
32
+ },
33
+ id: generateWidgetId(widget.type)
34
+ };
35
+ }
36
+ return {
37
+ type: widget.type,
38
+ props: { ...widget.props },
39
+ id: generateWidgetId(widget.type)
40
+ };
41
+ }
42
+ function deepCloneWidgets(widgets) {
43
+ return widgets.map((widget) => deepCloneWidget(widget));
44
+ }
45
+ function getWidgetByPath(screen, path) {
46
+ if (path.length === 0 || path[0] === void 0) return null;
47
+ let current = screen[path[0]] ?? null;
48
+ for (let i = 1; i < path.length; i++) {
49
+ if (!chunk6QLUUNJL_cjs.isWidgetType(current, chunk6QLUUNJL_cjs.WIDGET_TYPE_NAMES.Layout)) return null;
50
+ const children = current.props.children ?? [];
51
+ const index = path[i];
52
+ if (index === void 0) return null;
53
+ current = children[index] ?? null;
54
+ }
55
+ return current;
56
+ }
57
+ function groupChildrenByColumn(children, columnCount) {
58
+ const columns = Array.from(
59
+ { length: columnCount },
60
+ () => []
61
+ );
62
+ const nonNullChildren = children.filter(
63
+ (child) => child !== null
64
+ );
65
+ for (const child of nonNullChildren) {
66
+ const colIndex = Math.min(child.columnIndex ?? 0, columnCount - 1);
67
+ const column = columns[colIndex];
68
+ if (column) {
69
+ column.push(child);
70
+ }
71
+ }
72
+ return columns;
73
+ }
74
+
75
+ // src/widget-utils/utils.ts
76
+ function createWidgetRegistry(registry) {
77
+ return registry;
78
+ }
79
+ function createScreen(registry, widgets) {
80
+ widgets.forEach((widget) => {
81
+ if (!(widget.type in registry)) {
82
+ throw new Error(
83
+ `Widget type "${String(widget.type)}" not found in registry`
84
+ );
85
+ }
86
+ });
87
+ return widgets;
88
+ }
89
+ function createWidgetFromShareable(item) {
90
+ const isVideo = item.kind === "video" || !!item.videoUrl;
91
+ if (isVideo && item.videoUrl) {
92
+ return {
93
+ type: "VideoWidget",
94
+ props: {
95
+ src: item.videoUrl,
96
+ poster: item.imageUrl,
97
+ caption: item.title
98
+ }
99
+ };
100
+ }
101
+ return {
102
+ type: "ImageWidget",
103
+ props: {
104
+ src: item.imageUrl,
105
+ alt: item.title || "Image",
106
+ objectFit: "cover"
107
+ }
108
+ };
109
+ }
110
+
111
+ exports.createScreen = createScreen;
112
+ exports.createWidgetFromShareable = createWidgetFromShareable;
113
+ exports.createWidgetRegistry = createWidgetRegistry;
114
+ exports.deepCloneWidget = deepCloneWidget;
115
+ exports.deepCloneWidgets = deepCloneWidgets;
116
+ exports.ensureWidgetIds = ensureWidgetIds;
117
+ exports.generateWidgetId = generateWidgetId;
118
+ exports.getWidgetByPath = getWidgetByPath;
119
+ exports.groupChildrenByColumn = groupChildrenByColumn;
120
+ exports.idToPath = idToPath;
121
+ exports.pathToId = pathToId;
122
+ //# sourceMappingURL=index.cjs.map
123
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/widget-utils/widget-utils.ts","../../src/widget-utils/utils.ts"],"names":["isWidgetType","WIDGET_TYPE_NAMES"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { WidgetSchema, WidgetPath } from \"../types\";\nimport { WIDGET_TYPE_NAMES, isWidgetType } from \"../types\";\n\n/**\n * Generates a unique ID for a widget\n */\nexport function generateWidgetId(type?: string): string {\n const uuid = crypto.randomUUID();\n return type ? `${type}-${uuid}` : uuid;\n}\n\n/**\n * Converts a widget path to a unique string identifier\n */\nexport function pathToId(path: WidgetPath): string {\n return path.join(\"-\");\n}\n\n/**\n * Converts a path string back to a WidgetPath array\n */\nexport function idToPath(id: string): WidgetPath {\n return id.split(\"-\").map((segment) => parseInt(segment, 10));\n}\n\n/**\n * Ensures all widgets in an array have valid IDs\n * Note: Handles null values for sparse arrays (e.g., grid layouts with empty cells)\n */\nexport function ensureWidgetIds(\n widgets: readonly (WidgetSchema | null)[],\n): (WidgetSchema | null)[] {\n return widgets?.map((widget, index) => {\n if (!widget) return null;\n return {\n ...widget,\n id: widget.id || `widget-${index}-${crypto.randomUUID()}`,\n };\n });\n}\n\n/**\n * Deep clones a widget and regenerates all IDs (including nested children)\n */\nexport function deepCloneWidget(widget: WidgetSchema): WidgetSchema {\n // Handle LayoutWidget children recursively\n // Use type guard for discriminated union narrowing (narrowing-discriminated-unions rule)\n if (\n isWidgetType(widget, WIDGET_TYPE_NAMES.Layout) &&\n Array.isArray(widget.props.children)\n ) {\n // Build cloned widget with recursively cloned children\n return {\n type: widget.type,\n props: {\n ...widget.props,\n children: (\n widget.props.children as readonly (WidgetSchema | null)[]\n ).map((child) => (child ? deepCloneWidget(child) : null)),\n },\n id: generateWidgetId(widget.type),\n };\n }\n\n // Clone non-container widget\n return {\n type: widget.type,\n props: { ...widget.props },\n id: generateWidgetId(widget.type),\n };\n}\n\n/**\n * Deep clones an array of widgets and regenerates all IDs\n */\nexport function deepCloneWidgets(\n widgets: readonly WidgetSchema[],\n): WidgetSchema[] {\n return widgets.map((widget) => deepCloneWidget(widget));\n}\n\n/**\n * Gets a widget at a specific path in the widget tree\n */\nexport function getWidgetByPath(\n screen: readonly (WidgetSchema | null)[],\n path: WidgetPath,\n): WidgetSchema | null {\n if (path.length === 0 || path[0] === undefined) return null;\n\n let current: WidgetSchema | null = screen[path[0]] ?? null;\n\n for (let i = 1; i < path.length; i++) {\n // Use type guard for discriminated union narrowing (narrowing-discriminated-unions rule)\n if (!isWidgetType(current, WIDGET_TYPE_NAMES.Layout)) return null;\n\n const children = (current.props.children ??\n []) as readonly (WidgetSchema | null)[];\n const index = path[i];\n if (index === undefined) return null;\n current = children[index] ?? null;\n }\n\n return current;\n}\n\n/**\n * Groups children by column index.\n * Accepts nullable children (sparse arrays from grid layouts) and filters them out.\n */\nexport function groupChildrenByColumn(\n children: readonly (WidgetSchema | null)[],\n columnCount: number,\n): WidgetSchema[][] {\n // Use explicit type annotation to avoid never[] inference (narrowing-empty-array-type rule)\n const columns: WidgetSchema[][] = Array.from(\n { length: columnCount },\n (): WidgetSchema[] => [],\n );\n\n // Filter out nulls first, then process (truthiness narrowing rule)\n // This avoids the narrowing-callback-scope issue since we work with non-null array\n const nonNullChildren = children.filter(\n (child): child is WidgetSchema => child !== null,\n );\n\n for (const child of nonNullChildren) {\n // Default to column 0 if no columnIndex specified\n const colIndex = Math.min(child.columnIndex ?? 0, columnCount - 1);\n const column = columns[colIndex];\n if (column) {\n column.push(child);\n }\n }\n\n return columns;\n}\n","import type { ComponentType } from \"react\";\nimport type { WidgetSchema, TypedWidgetSchema } from \"../types\";\nimport type { ShareableItem } from \"../types/shareable-item\";\n\nexport function createWidgetRegistry<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, ComponentType<any>>,\n>(registry: T): T {\n // Return the registry with its original type intact for type inference\n return registry;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function createScreen<T extends Record<string, ComponentType<any>>>(\n registry: T,\n widgets: TypedWidgetSchema<T>[],\n): TypedWidgetSchema<T>[] {\n // Validate that all widget types exist in the registry at runtime\n widgets.forEach((widget) => {\n if (!(widget.type in registry)) {\n throw new Error(\n `Widget type \"${String(widget.type)}\" not found in registry`,\n );\n }\n });\n return widgets;\n}\n\n// Helper to create WidgetSchema from shareable item\nexport function createWidgetFromShareable(item: ShareableItem): WidgetSchema {\n const isVideo = item.kind === \"video\" || !!item.videoUrl;\n\n if (isVideo && item.videoUrl) {\n return {\n type: \"VideoWidget\",\n props: {\n src: item.videoUrl,\n poster: item.imageUrl,\n caption: item.title,\n },\n };\n }\n\n return {\n type: \"ImageWidget\",\n props: {\n src: item.imageUrl,\n alt: item.title || \"Image\",\n objectFit: \"cover\",\n },\n };\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import { W as WidgetPath, a as WidgetSchema, T as TypedWidgetSchema, S as ShareableItem } from '../shareable-item-DPmNZkE1.cjs';
2
+ import { ComponentType } from 'react';
3
+
4
+ /**
5
+ * Generates a unique ID for a widget
6
+ */
7
+ declare function generateWidgetId(type?: string): string;
8
+ /**
9
+ * Converts a widget path to a unique string identifier
10
+ */
11
+ declare function pathToId(path: WidgetPath): string;
12
+ /**
13
+ * Converts a path string back to a WidgetPath array
14
+ */
15
+ declare function idToPath(id: string): WidgetPath;
16
+ /**
17
+ * Ensures all widgets in an array have valid IDs
18
+ * Note: Handles null values for sparse arrays (e.g., grid layouts with empty cells)
19
+ */
20
+ declare function ensureWidgetIds(widgets: readonly (WidgetSchema | null)[]): (WidgetSchema | null)[];
21
+ /**
22
+ * Deep clones a widget and regenerates all IDs (including nested children)
23
+ */
24
+ declare function deepCloneWidget(widget: WidgetSchema): WidgetSchema;
25
+ /**
26
+ * Deep clones an array of widgets and regenerates all IDs
27
+ */
28
+ declare function deepCloneWidgets(widgets: readonly WidgetSchema[]): WidgetSchema[];
29
+ /**
30
+ * Gets a widget at a specific path in the widget tree
31
+ */
32
+ declare function getWidgetByPath(screen: readonly (WidgetSchema | null)[], path: WidgetPath): WidgetSchema | null;
33
+ /**
34
+ * Groups children by column index.
35
+ * Accepts nullable children (sparse arrays from grid layouts) and filters them out.
36
+ */
37
+ declare function groupChildrenByColumn(children: readonly (WidgetSchema | null)[], columnCount: number): WidgetSchema[][];
38
+
39
+ declare function createWidgetRegistry<T extends Record<string, ComponentType<any>>>(registry: T): T;
40
+ declare function createScreen<T extends Record<string, ComponentType<any>>>(registry: T, widgets: TypedWidgetSchema<T>[]): TypedWidgetSchema<T>[];
41
+ declare function createWidgetFromShareable(item: ShareableItem): WidgetSchema;
42
+
43
+ export { createScreen, createWidgetFromShareable, createWidgetRegistry, deepCloneWidget, deepCloneWidgets, ensureWidgetIds, generateWidgetId, getWidgetByPath, groupChildrenByColumn, idToPath, pathToId };
@@ -0,0 +1,43 @@
1
+ import { W as WidgetPath, a as WidgetSchema, T as TypedWidgetSchema, S as ShareableItem } from '../shareable-item-DPmNZkE1.js';
2
+ import { ComponentType } from 'react';
3
+
4
+ /**
5
+ * Generates a unique ID for a widget
6
+ */
7
+ declare function generateWidgetId(type?: string): string;
8
+ /**
9
+ * Converts a widget path to a unique string identifier
10
+ */
11
+ declare function pathToId(path: WidgetPath): string;
12
+ /**
13
+ * Converts a path string back to a WidgetPath array
14
+ */
15
+ declare function idToPath(id: string): WidgetPath;
16
+ /**
17
+ * Ensures all widgets in an array have valid IDs
18
+ * Note: Handles null values for sparse arrays (e.g., grid layouts with empty cells)
19
+ */
20
+ declare function ensureWidgetIds(widgets: readonly (WidgetSchema | null)[]): (WidgetSchema | null)[];
21
+ /**
22
+ * Deep clones a widget and regenerates all IDs (including nested children)
23
+ */
24
+ declare function deepCloneWidget(widget: WidgetSchema): WidgetSchema;
25
+ /**
26
+ * Deep clones an array of widgets and regenerates all IDs
27
+ */
28
+ declare function deepCloneWidgets(widgets: readonly WidgetSchema[]): WidgetSchema[];
29
+ /**
30
+ * Gets a widget at a specific path in the widget tree
31
+ */
32
+ declare function getWidgetByPath(screen: readonly (WidgetSchema | null)[], path: WidgetPath): WidgetSchema | null;
33
+ /**
34
+ * Groups children by column index.
35
+ * Accepts nullable children (sparse arrays from grid layouts) and filters them out.
36
+ */
37
+ declare function groupChildrenByColumn(children: readonly (WidgetSchema | null)[], columnCount: number): WidgetSchema[][];
38
+
39
+ declare function createWidgetRegistry<T extends Record<string, ComponentType<any>>>(registry: T): T;
40
+ declare function createScreen<T extends Record<string, ComponentType<any>>>(registry: T, widgets: TypedWidgetSchema<T>[]): TypedWidgetSchema<T>[];
41
+ declare function createWidgetFromShareable(item: ShareableItem): WidgetSchema;
42
+
43
+ export { createScreen, createWidgetFromShareable, createWidgetRegistry, deepCloneWidget, deepCloneWidgets, ensureWidgetIds, generateWidgetId, getWidgetByPath, groupChildrenByColumn, idToPath, pathToId };
@@ -0,0 +1,111 @@
1
+ import { isWidgetType, WIDGET_TYPE_NAMES } from '../chunk-EWR5EIBP.js';
2
+
3
+ // src/widget-utils/widget-utils.ts
4
+ function generateWidgetId(type) {
5
+ const uuid = crypto.randomUUID();
6
+ return type ? `${type}-${uuid}` : uuid;
7
+ }
8
+ function pathToId(path) {
9
+ return path.join("-");
10
+ }
11
+ function idToPath(id) {
12
+ return id.split("-").map((segment) => parseInt(segment, 10));
13
+ }
14
+ function ensureWidgetIds(widgets) {
15
+ return widgets?.map((widget, index) => {
16
+ if (!widget) return null;
17
+ return {
18
+ ...widget,
19
+ id: widget.id || `widget-${index}-${crypto.randomUUID()}`
20
+ };
21
+ });
22
+ }
23
+ function deepCloneWidget(widget) {
24
+ if (isWidgetType(widget, WIDGET_TYPE_NAMES.Layout) && Array.isArray(widget.props.children)) {
25
+ return {
26
+ type: widget.type,
27
+ props: {
28
+ ...widget.props,
29
+ children: widget.props.children.map((child) => child ? deepCloneWidget(child) : null)
30
+ },
31
+ id: generateWidgetId(widget.type)
32
+ };
33
+ }
34
+ return {
35
+ type: widget.type,
36
+ props: { ...widget.props },
37
+ id: generateWidgetId(widget.type)
38
+ };
39
+ }
40
+ function deepCloneWidgets(widgets) {
41
+ return widgets.map((widget) => deepCloneWidget(widget));
42
+ }
43
+ function getWidgetByPath(screen, path) {
44
+ if (path.length === 0 || path[0] === void 0) return null;
45
+ let current = screen[path[0]] ?? null;
46
+ for (let i = 1; i < path.length; i++) {
47
+ if (!isWidgetType(current, WIDGET_TYPE_NAMES.Layout)) return null;
48
+ const children = current.props.children ?? [];
49
+ const index = path[i];
50
+ if (index === void 0) return null;
51
+ current = children[index] ?? null;
52
+ }
53
+ return current;
54
+ }
55
+ function groupChildrenByColumn(children, columnCount) {
56
+ const columns = Array.from(
57
+ { length: columnCount },
58
+ () => []
59
+ );
60
+ const nonNullChildren = children.filter(
61
+ (child) => child !== null
62
+ );
63
+ for (const child of nonNullChildren) {
64
+ const colIndex = Math.min(child.columnIndex ?? 0, columnCount - 1);
65
+ const column = columns[colIndex];
66
+ if (column) {
67
+ column.push(child);
68
+ }
69
+ }
70
+ return columns;
71
+ }
72
+
73
+ // src/widget-utils/utils.ts
74
+ function createWidgetRegistry(registry) {
75
+ return registry;
76
+ }
77
+ function createScreen(registry, widgets) {
78
+ widgets.forEach((widget) => {
79
+ if (!(widget.type in registry)) {
80
+ throw new Error(
81
+ `Widget type "${String(widget.type)}" not found in registry`
82
+ );
83
+ }
84
+ });
85
+ return widgets;
86
+ }
87
+ function createWidgetFromShareable(item) {
88
+ const isVideo = item.kind === "video" || !!item.videoUrl;
89
+ if (isVideo && item.videoUrl) {
90
+ return {
91
+ type: "VideoWidget",
92
+ props: {
93
+ src: item.videoUrl,
94
+ poster: item.imageUrl,
95
+ caption: item.title
96
+ }
97
+ };
98
+ }
99
+ return {
100
+ type: "ImageWidget",
101
+ props: {
102
+ src: item.imageUrl,
103
+ alt: item.title || "Image",
104
+ objectFit: "cover"
105
+ }
106
+ };
107
+ }
108
+
109
+ export { createScreen, createWidgetFromShareable, createWidgetRegistry, deepCloneWidget, deepCloneWidgets, ensureWidgetIds, generateWidgetId, getWidgetByPath, groupChildrenByColumn, idToPath, pathToId };
110
+ //# sourceMappingURL=index.js.map
111
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/widget-utils/widget-utils.ts","../../src/widget-utils/utils.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { WidgetSchema, WidgetPath } from \"../types\";\nimport { WIDGET_TYPE_NAMES, isWidgetType } from \"../types\";\n\n/**\n * Generates a unique ID for a widget\n */\nexport function generateWidgetId(type?: string): string {\n const uuid = crypto.randomUUID();\n return type ? `${type}-${uuid}` : uuid;\n}\n\n/**\n * Converts a widget path to a unique string identifier\n */\nexport function pathToId(path: WidgetPath): string {\n return path.join(\"-\");\n}\n\n/**\n * Converts a path string back to a WidgetPath array\n */\nexport function idToPath(id: string): WidgetPath {\n return id.split(\"-\").map((segment) => parseInt(segment, 10));\n}\n\n/**\n * Ensures all widgets in an array have valid IDs\n * Note: Handles null values for sparse arrays (e.g., grid layouts with empty cells)\n */\nexport function ensureWidgetIds(\n widgets: readonly (WidgetSchema | null)[],\n): (WidgetSchema | null)[] {\n return widgets?.map((widget, index) => {\n if (!widget) return null;\n return {\n ...widget,\n id: widget.id || `widget-${index}-${crypto.randomUUID()}`,\n };\n });\n}\n\n/**\n * Deep clones a widget and regenerates all IDs (including nested children)\n */\nexport function deepCloneWidget(widget: WidgetSchema): WidgetSchema {\n // Handle LayoutWidget children recursively\n // Use type guard for discriminated union narrowing (narrowing-discriminated-unions rule)\n if (\n isWidgetType(widget, WIDGET_TYPE_NAMES.Layout) &&\n Array.isArray(widget.props.children)\n ) {\n // Build cloned widget with recursively cloned children\n return {\n type: widget.type,\n props: {\n ...widget.props,\n children: (\n widget.props.children as readonly (WidgetSchema | null)[]\n ).map((child) => (child ? deepCloneWidget(child) : null)),\n },\n id: generateWidgetId(widget.type),\n };\n }\n\n // Clone non-container widget\n return {\n type: widget.type,\n props: { ...widget.props },\n id: generateWidgetId(widget.type),\n };\n}\n\n/**\n * Deep clones an array of widgets and regenerates all IDs\n */\nexport function deepCloneWidgets(\n widgets: readonly WidgetSchema[],\n): WidgetSchema[] {\n return widgets.map((widget) => deepCloneWidget(widget));\n}\n\n/**\n * Gets a widget at a specific path in the widget tree\n */\nexport function getWidgetByPath(\n screen: readonly (WidgetSchema | null)[],\n path: WidgetPath,\n): WidgetSchema | null {\n if (path.length === 0 || path[0] === undefined) return null;\n\n let current: WidgetSchema | null = screen[path[0]] ?? null;\n\n for (let i = 1; i < path.length; i++) {\n // Use type guard for discriminated union narrowing (narrowing-discriminated-unions rule)\n if (!isWidgetType(current, WIDGET_TYPE_NAMES.Layout)) return null;\n\n const children = (current.props.children ??\n []) as readonly (WidgetSchema | null)[];\n const index = path[i];\n if (index === undefined) return null;\n current = children[index] ?? null;\n }\n\n return current;\n}\n\n/**\n * Groups children by column index.\n * Accepts nullable children (sparse arrays from grid layouts) and filters them out.\n */\nexport function groupChildrenByColumn(\n children: readonly (WidgetSchema | null)[],\n columnCount: number,\n): WidgetSchema[][] {\n // Use explicit type annotation to avoid never[] inference (narrowing-empty-array-type rule)\n const columns: WidgetSchema[][] = Array.from(\n { length: columnCount },\n (): WidgetSchema[] => [],\n );\n\n // Filter out nulls first, then process (truthiness narrowing rule)\n // This avoids the narrowing-callback-scope issue since we work with non-null array\n const nonNullChildren = children.filter(\n (child): child is WidgetSchema => child !== null,\n );\n\n for (const child of nonNullChildren) {\n // Default to column 0 if no columnIndex specified\n const colIndex = Math.min(child.columnIndex ?? 0, columnCount - 1);\n const column = columns[colIndex];\n if (column) {\n column.push(child);\n }\n }\n\n return columns;\n}\n","import type { ComponentType } from \"react\";\nimport type { WidgetSchema, TypedWidgetSchema } from \"../types\";\nimport type { ShareableItem } from \"../types/shareable-item\";\n\nexport function createWidgetRegistry<\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n T extends Record<string, ComponentType<any>>,\n>(registry: T): T {\n // Return the registry with its original type intact for type inference\n return registry;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function createScreen<T extends Record<string, ComponentType<any>>>(\n registry: T,\n widgets: TypedWidgetSchema<T>[],\n): TypedWidgetSchema<T>[] {\n // Validate that all widget types exist in the registry at runtime\n widgets.forEach((widget) => {\n if (!(widget.type in registry)) {\n throw new Error(\n `Widget type \"${String(widget.type)}\" not found in registry`,\n );\n }\n });\n return widgets;\n}\n\n// Helper to create WidgetSchema from shareable item\nexport function createWidgetFromShareable(item: ShareableItem): WidgetSchema {\n const isVideo = item.kind === \"video\" || !!item.videoUrl;\n\n if (isVideo && item.videoUrl) {\n return {\n type: \"VideoWidget\",\n props: {\n src: item.videoUrl,\n poster: item.imageUrl,\n caption: item.title,\n },\n };\n }\n\n return {\n type: \"ImageWidget\",\n props: {\n src: item.imageUrl,\n alt: item.title || \"Image\",\n objectFit: \"cover\",\n },\n };\n}\n"]}