@fluid-app/portal-sdk 0.1.469 → 0.1.471

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 (137) hide show
  1. package/authoring/portal-api/api.md +227 -0
  2. package/authoring/widget-api/api.md +6 -0
  3. package/authoring/widget-api/core/src/registries/property-schema-types.md +3769 -0
  4. package/authoring/widget-api/sdk/src/widgets/worker.md +3683 -0
  5. package/dist/{CarouselWidget-CnjImV4p.cjs → CarouselWidget-B9_YaBRd.cjs} +7 -3
  6. package/dist/{CarouselWidget-CnjImV4p.cjs.map → CarouselWidget-B9_YaBRd.cjs.map} +1 -1
  7. package/dist/{CarouselWidget-xVj0Nl_1.cjs → CarouselWidget-BEPWgTCi.cjs} +1 -1
  8. package/dist/{CarouselWidget-DcoqH7YF.mjs → CarouselWidget-u58GTUD2.mjs} +7 -3
  9. package/dist/{CarouselWidget-DcoqH7YF.mjs.map → CarouselWidget-u58GTUD2.mjs.map} +1 -1
  10. package/dist/{ChartWidget-DhH_Q0e9.cjs → ChartWidget-C6hsftO9.cjs} +1 -1
  11. package/dist/{ChartWidget-CFyWkbfl.mjs → ChartWidget-J_JLCsug.mjs} +9 -2
  12. package/dist/{ChartWidget-CFyWkbfl.mjs.map → ChartWidget-J_JLCsug.mjs.map} +1 -1
  13. package/dist/{ChartWidget-DF-KE_5t.cjs → ChartWidget-q9yjk-79.cjs} +9 -2
  14. package/dist/{ChartWidget-DF-KE_5t.cjs.map → ChartWidget-q9yjk-79.cjs.map} +1 -1
  15. package/dist/{FluidProvider-CHo5kVRs.cjs → FluidProvider-DD1pE8b6.cjs} +2 -2
  16. package/dist/{FluidProvider-CHo5kVRs.cjs.map → FluidProvider-DD1pE8b6.cjs.map} +1 -1
  17. package/dist/{FluidProvider-BUV8QY8z.mjs → FluidProvider-DoJ-j6H-.mjs} +2 -2
  18. package/dist/{FluidProvider-BUV8QY8z.mjs.map → FluidProvider-DoJ-j6H-.mjs.map} +1 -1
  19. package/dist/{ImageWidget-BK_f_L0T.mjs → ImageWidget-B2SfenSC.mjs} +2 -2
  20. package/dist/{ImageWidget-BK_f_L0T.mjs.map → ImageWidget-B2SfenSC.mjs.map} +1 -1
  21. package/dist/{ImageWidget-8WfRzR60.cjs → ImageWidget-BFyfpxLg.cjs} +1 -1
  22. package/dist/{ImageWidget-C9PCTFpZ.cjs → ImageWidget-C7U9t7a3.cjs} +2 -2
  23. package/dist/{ImageWidget-C9PCTFpZ.cjs.map → ImageWidget-C7U9t7a3.cjs.map} +1 -1
  24. package/dist/{LinkWidget-DRMzQhQz.cjs → LinkWidget-Cjzrpnzd.cjs} +4 -1
  25. package/dist/LinkWidget-Cjzrpnzd.cjs.map +1 -0
  26. package/dist/{LinkWidget-BqLCMzfY.cjs → LinkWidget-D3acO4R8.cjs} +1 -1
  27. package/dist/{LinkWidget-C3HRFueg.mjs → LinkWidget-Dlw2rzK6.mjs} +4 -1
  28. package/dist/LinkWidget-Dlw2rzK6.mjs.map +1 -0
  29. package/dist/{ListWidget-BiBx02S8.cjs → ListWidget-DWAtSTK6.cjs} +1 -1
  30. package/dist/{ListWidget-D7Ws1bMu.mjs → ListWidget-W5Tm4mWy.mjs} +7 -3
  31. package/dist/{ListWidget-D7Ws1bMu.mjs.map → ListWidget-W5Tm4mWy.mjs.map} +1 -1
  32. package/dist/{ListWidget-Ge83X2-d.cjs → ListWidget-YrcH5_Ez.cjs} +7 -3
  33. package/dist/{ListWidget-Ge83X2-d.cjs.map → ListWidget-YrcH5_Ez.cjs.map} +1 -1
  34. package/dist/{MessagingScreen-KYbF9U2N.cjs → MessagingScreen-B8Bcy-2V.cjs} +2 -2
  35. package/dist/{MessagingScreen-KYbF9U2N.cjs.map → MessagingScreen-B8Bcy-2V.cjs.map} +1 -1
  36. package/dist/{MessagingScreen-r40mXBJR.mjs → MessagingScreen-BBoYyLPj.mjs} +11 -11
  37. package/dist/{MessagingScreen-CC2FSdcv.cjs → MessagingScreen-BJ7NTczB.cjs} +11 -11
  38. package/dist/{MessagingScreen-B9LmuGG4.mjs → MessagingScreen-vaNfWYeM.mjs} +2 -2
  39. package/dist/{MessagingScreen-B9LmuGG4.mjs.map → MessagingScreen-vaNfWYeM.mjs.map} +1 -1
  40. package/dist/{NestedWidget-nWK5H1NG.cjs → NestedWidget-B5iyFylx.cjs} +6 -2
  41. package/dist/{NestedWidget-nWK5H1NG.cjs.map → NestedWidget-B5iyFylx.cjs.map} +1 -1
  42. package/dist/{NestedWidget-J8fPrBNA.mjs → NestedWidget-Bdll8TLQ.mjs} +6 -2
  43. package/dist/{NestedWidget-J8fPrBNA.mjs.map → NestedWidget-Bdll8TLQ.mjs.map} +1 -1
  44. package/dist/{NestedWidget-Bhltm3Db.cjs → NestedWidget-CBYJ_Qw7.cjs} +1 -1
  45. package/dist/{OrdersScreen-jhkTEp5y.cjs → OrdersScreen-BdtVN1wl.cjs} +11 -11
  46. package/dist/{OrdersScreen-BMslkiOK.mjs → OrdersScreen-ClB_Yor-.mjs} +2 -2
  47. package/dist/{OrdersScreen-BMslkiOK.mjs.map → OrdersScreen-ClB_Yor-.mjs.map} +1 -1
  48. package/dist/{OrdersScreen-CHt2QwB7.mjs → OrdersScreen-D2cymJtp.mjs} +11 -11
  49. package/dist/{OrdersScreen-DkRte66f.cjs → OrdersScreen-DnJa329w.cjs} +2 -2
  50. package/dist/{OrdersScreen-DkRte66f.cjs.map → OrdersScreen-DnJa329w.cjs.map} +1 -1
  51. package/dist/{ProfileScreen-BP5KEyW0.mjs → ProfileScreen-CIjBpDIq.mjs} +12 -12
  52. package/dist/{ProfileScreen-Ba8B0_Bm.cjs → ProfileScreen-CpI9XiZQ.cjs} +9 -4
  53. package/dist/ProfileScreen-CpI9XiZQ.cjs.map +1 -0
  54. package/dist/{ProfileScreen-BAbxbpdQ.cjs → ProfileScreen-DUEVFZqo.cjs} +12 -12
  55. package/dist/{ProfileScreen-Cw1hajhU.mjs → ProfileScreen-TbmOka5D.mjs} +9 -4
  56. package/dist/ProfileScreen-TbmOka5D.mjs.map +1 -0
  57. package/dist/{ShopWidget-jQ-osGyn.mjs → ShopWidget-BH0Pcepg.mjs} +6 -2
  58. package/dist/{ShopWidget-jQ-osGyn.mjs.map → ShopWidget-BH0Pcepg.mjs.map} +1 -1
  59. package/dist/{ShopWidget-Dc3fH_tP.cjs → ShopWidget-RfF5ZRv2.cjs} +6 -2
  60. package/dist/{ShopWidget-Dc3fH_tP.cjs.map → ShopWidget-RfF5ZRv2.cjs.map} +1 -1
  61. package/dist/{ShopWidget-gc_BbyrJ.cjs → ShopWidget-ecp3h54J.cjs} +1 -1
  62. package/dist/{SubscriptionsScreen-BscwpAw8.cjs → SubscriptionsScreen-BiNmEFLP.cjs} +4 -4
  63. package/dist/{SubscriptionsScreen-BscwpAw8.cjs.map → SubscriptionsScreen-BiNmEFLP.cjs.map} +1 -1
  64. package/dist/{SubscriptionsScreen-D2uyJGIE.mjs → SubscriptionsScreen-NCU2I079.mjs} +4 -4
  65. package/dist/{SubscriptionsScreen-D2uyJGIE.mjs.map → SubscriptionsScreen-NCU2I079.mjs.map} +1 -1
  66. package/dist/{SubscriptionsScreen-Nfbt2u5r.cjs → SubscriptionsScreen-cuw6yk56.cjs} +12 -12
  67. package/dist/{SubscriptionsScreen-DU5AKlfR.mjs → SubscriptionsScreen-fv_xxA9j.mjs} +12 -12
  68. package/dist/{TableWidget-B4rGem0e.cjs → TableWidget-B8axD206.cjs} +1 -1
  69. package/dist/{TableWidget-LolaiYXA.mjs → TableWidget-C861T_Ac.mjs} +8 -1
  70. package/dist/{TableWidget-LolaiYXA.mjs.map → TableWidget-C861T_Ac.mjs.map} +1 -1
  71. package/dist/{TableWidget-Dfzx5jaI.cjs → TableWidget-CAgARK2Y.cjs} +8 -1
  72. package/dist/{TableWidget-Dfzx5jaI.cjs.map → TableWidget-CAgARK2Y.cjs.map} +1 -1
  73. package/dist/build-remote-widget-plugin-manifests-BDGS5t6k.d.mts +87 -0
  74. package/dist/build-remote-widget-plugin-manifests-BDGS5t6k.d.mts.map +1 -0
  75. package/dist/build-remote-widget-plugin-manifests-BS2FjZRV.d.cts +87 -0
  76. package/dist/build-remote-widget-plugin-manifests-BS2FjZRV.d.cts.map +1 -0
  77. package/dist/{build-widget-registry-BwiPIMcu.d.mts → build-widget-registry-ByUJk3-B.d.mts} +2 -2
  78. package/dist/{build-widget-registry-BwiPIMcu.d.mts.map → build-widget-registry-ByUJk3-B.d.mts.map} +1 -1
  79. package/dist/{build-widget-registry-BmU54VJb.cjs → build-widget-registry-CCmtBo8w.cjs} +17 -17
  80. package/dist/build-widget-registry-CCmtBo8w.cjs.map +1 -0
  81. package/dist/{build-widget-registry-DSE7CmVe.d.cts → build-widget-registry-Dsp9P8gq.d.cts} +2 -2
  82. package/dist/{build-widget-registry-DSE7CmVe.d.cts.map → build-widget-registry-Dsp9P8gq.d.cts.map} +1 -1
  83. package/dist/{build-widget-registry-Bimd6Pxq.mjs → build-widget-registry-DvCtfn9d.mjs} +17 -17
  84. package/dist/build-widget-registry-DvCtfn9d.mjs.map +1 -0
  85. package/dist/index.cjs +29 -24
  86. package/dist/index.cjs.map +1 -1
  87. package/dist/index.d.cts +40 -13
  88. package/dist/index.d.cts.map +1 -1
  89. package/dist/index.d.mts +40 -13
  90. package/dist/index.d.mts.map +1 -1
  91. package/dist/index.mjs +29 -24
  92. package/dist/index.mjs.map +1 -1
  93. package/dist/{link-type-schema-fields-DJBFdG7t.mjs → link-type-schema-fields-CncR6GKa.mjs} +3 -1
  94. package/dist/link-type-schema-fields-CncR6GKa.mjs.map +1 -0
  95. package/dist/{link-type-schema-fields-CQXXgSqn.cjs → link-type-schema-fields-DvSzjbwD.cjs} +3 -1
  96. package/dist/link-type-schema-fields-DvSzjbwD.cjs.map +1 -0
  97. package/dist/{build-remote-widget-plugin-manifests-CFmLot7p.d.cts → portal-function-DYWFgeRx.d.cts} +826 -796
  98. package/dist/portal-function-DYWFgeRx.d.cts.map +1 -0
  99. package/dist/{build-remote-widget-plugin-manifests-BsgLYqar.d.mts → portal-function-DgqXwF13.d.mts} +932 -902
  100. package/dist/portal-function-DgqXwF13.d.mts.map +1 -0
  101. package/dist/registries-DgzzKX8_.cjs.map +1 -1
  102. package/dist/registries-Dvq4M6wO.mjs.map +1 -1
  103. package/dist/{use-portal-card-add-3ds-flow-BE4p2zYl.cjs → use-portal-card-add-3ds-flow-CRiGY6e0.cjs} +3 -3
  104. package/dist/{use-portal-card-add-3ds-flow-BE4p2zYl.cjs.map → use-portal-card-add-3ds-flow-CRiGY6e0.cjs.map} +1 -1
  105. package/dist/{use-portal-card-add-3ds-flow-DzhPOYGn.mjs → use-portal-card-add-3ds-flow-DjeKiZvQ.mjs} +3 -3
  106. package/dist/{use-portal-card-add-3ds-flow-DzhPOYGn.mjs.map → use-portal-card-add-3ds-flow-DjeKiZvQ.mjs.map} +1 -1
  107. package/dist/utils/build-remote-widget-plugin-manifests.cjs +9 -9
  108. package/dist/utils/build-remote-widget-plugin-manifests.d.cts +1 -1
  109. package/dist/utils/build-remote-widget-plugin-manifests.d.mts +1 -1
  110. package/dist/utils/build-remote-widget-plugin-manifests.mjs +9 -9
  111. package/dist/utils/build-widget-registry.cjs +9 -9
  112. package/dist/utils/build-widget-registry.d.cts +1 -1
  113. package/dist/utils/build-widget-registry.d.mts +1 -1
  114. package/dist/utils/build-widget-registry.mjs +9 -9
  115. package/dist/widgets/worker.cjs +20 -1
  116. package/dist/widgets/worker.cjs.map +1 -1
  117. package/dist/widgets/worker.d.cts +67 -4
  118. package/dist/widgets/worker.d.cts.map +1 -1
  119. package/dist/widgets/worker.d.mts +67 -4
  120. package/dist/widgets/worker.d.mts.map +1 -1
  121. package/dist/widgets/worker.mjs +20 -1
  122. package/dist/widgets/worker.mjs.map +1 -1
  123. package/package.json +18 -17
  124. package/dist/LinkWidget-C3HRFueg.mjs.map +0 -1
  125. package/dist/LinkWidget-DRMzQhQz.cjs.map +0 -1
  126. package/dist/ProfileScreen-Ba8B0_Bm.cjs.map +0 -1
  127. package/dist/ProfileScreen-Cw1hajhU.mjs.map +0 -1
  128. package/dist/build-remote-widget-plugin-manifests-BsgLYqar.d.mts.map +0 -1
  129. package/dist/build-remote-widget-plugin-manifests-CFmLot7p.d.cts.map +0 -1
  130. package/dist/build-widget-registry-Bimd6Pxq.mjs.map +0 -1
  131. package/dist/build-widget-registry-BmU54VJb.cjs.map +0 -1
  132. package/dist/link-type-schema-fields-CQXXgSqn.cjs.map +0 -1
  133. package/dist/link-type-schema-fields-DJBFdG7t.mjs.map +0 -1
  134. package/dist/portal-function-85qUlAVz.d.mts +0 -76
  135. package/dist/portal-function-85qUlAVz.d.mts.map +0 -1
  136. package/dist/portal-function-CW3U6P5p.d.cts +0 -76
  137. package/dist/portal-function-CW3U6P5p.d.cts.map +0 -1
@@ -1,7 +1,6 @@
1
- import { m as RemoteDomWidgetPackageDescriptor } from "./portal-function-85qUlAVz.mjs";
2
- import { r as WidgetRegistryWarningSink, t as RemoteDomWidgetRegistryOptions } from "./build-widget-registry-BwiPIMcu.mjs";
3
1
  import Color from "colorjs.io";
4
2
  import { LucideIcon } from "lucide-react";
3
+ import { RemoteDomSerializableValue } from "@fluid-app/widget-runtime/worker";
5
4
 
6
5
  //#region ../core/src/data-sources/types.d.ts
7
6
  type StaticSourceType = "collections" | "categories" | "tags";
@@ -116,1062 +115,1093 @@ interface DataSourceConfig {
116
115
  };
117
116
  }
118
117
  //#endregion
119
- //#region ../core/src/remote-widget-network-access.d.ts
120
- interface RemoteWidgetNetworkAccessGrant {
121
- readonly packageId: string;
122
- readonly packageVersion: string;
123
- readonly capabilityVersion: string;
124
- }
125
- interface RemoteWidgetCapabilityGrants {
126
- readonly networkAccess?: RemoteWidgetNetworkAccessGrant;
127
- }
128
- //#endregion
129
- //#region ../core/src/types/widget-schema.d.ts
118
+ //#region ../core/src/registries/property-schema-types.d.ts
130
119
  /**
131
- * Generic component type — avoids React dependency in core.
132
- * Accepts both function components and class component constructors.
120
+ * Tab configuration for organizing properties
133
121
  */
134
- type AnyComponent = ((props: any) => any) | (new (props: any) => any);
122
+ interface TabConfig {
123
+ /** Unique identifier for the tab */
124
+ id: string;
125
+ /** Display label for the tab */
126
+ label: string;
127
+ }
135
128
  /**
136
- * Widget type names as a const object.
137
- * This serves as the single source of truth for widget discriminants.
138
- * Use `as const` for literal type inference (safety-as-const-deep-readonly rule).
129
+ * Property field type constant - single source of truth for field types.
130
+ * Use PROPERTY_FIELD_TYPES.text instead of "text" for type-safe comparisons.
139
131
  */
140
- declare const WIDGET_TYPE_NAMES: {
141
- readonly Alert: "AlertWidget";
142
- readonly BulletList: "BulletListWidget";
143
- readonly Calendar: "CalendarWidget";
144
- readonly Card: "CardWidget";
145
- readonly Carousel: "CarouselWidget";
146
- readonly CatchUp: "CatchUpWidget";
147
- readonly Chart: "ChartWidget";
148
- readonly Container: "ContainerWidget";
149
- readonly Embed: "EmbedWidget";
150
- readonly Image: "ImageWidget";
151
- readonly Layout: "LayoutWidget";
152
- readonly Link: "LinkWidget";
153
- readonly List: "ListWidget";
154
- readonly MySite: "MySiteWidget";
155
- readonly Nested: "NestedWidget";
156
- readonly Points: "PointsWidget";
157
- readonly QuickLinks: "QuickLinksWidget";
158
- readonly QuickShare: "QuickShareWidget";
159
- readonly RecentActivity: "RecentActivityWidget";
160
- readonly Separator: "SeparatorWidget";
161
- readonly Shop: "ShopWidget";
162
- readonly Spacer: "SpacerWidget";
163
- readonly Table: "TableWidget";
164
- readonly Text: "TextWidget";
165
- readonly ToDo: "ToDoWidget";
166
- readonly Video: "VideoWidget";
132
+ declare const PROPERTY_FIELD_TYPES: {
133
+ readonly text: "text";
134
+ readonly textarea: "textarea";
135
+ readonly number: "number";
136
+ readonly boolean: "boolean";
137
+ readonly select: "select"; /** @deprecated Use `colorSelect` for semantic portal-theme colors. */
138
+ readonly color: "color";
139
+ readonly range: "range";
140
+ readonly dataSource: "dataSource";
141
+ readonly resource: "resource";
142
+ readonly image: "image";
143
+ readonly alignment: "alignment";
144
+ readonly slider: "slider";
145
+ readonly colorPicker: "colorPicker";
146
+ readonly sectionHeader: "sectionHeader";
147
+ readonly separator: "separator";
148
+ readonly buttonGroup: "buttonGroup";
149
+ readonly colorSelect: "colorSelect";
150
+ readonly sectionLayoutSelect: "sectionLayoutSelect";
151
+ readonly background: "background";
152
+ readonly contentPosition: "contentPosition";
153
+ readonly textSizeSelect: "textSizeSelect";
154
+ readonly cssUnit: "cssUnit";
155
+ readonly fontPicker: "fontPicker";
156
+ readonly stringArray: "stringArray";
157
+ readonly borderRadius: "borderRadius";
158
+ readonly screenPicker: "screenPicker";
167
159
  };
168
160
  /**
169
- * Union of all known widget type names.
170
- * Derived from WIDGET_TYPE_NAMES to avoid duplication (deriving-typeof-for-object-keys rule).
161
+ * Union type of all property field types, derived from PROPERTY_FIELD_TYPES constant.
162
+ * @see deriving-typeof-for-object-keys pattern
171
163
  */
172
- type WidgetTypeName = (typeof WIDGET_TYPE_NAMES)[keyof typeof WIDGET_TYPE_NAMES];
164
+ type PropertyFieldType = (typeof PROPERTY_FIELD_TYPES)[keyof typeof PROPERTY_FIELD_TYPES];
173
165
  /**
174
- * Legacy alias for backwards compatibility.
175
- * Prefer using WidgetTypeName for new code when you need the union type.
166
+ * Runtime validation for property field types.
167
+ * @param value - The value to check
168
+ * @returns true if value is a valid PropertyFieldType
176
169
  */
177
- type WidgetType = string;
178
- type WidgetRegistry = Record<WidgetType, AnyComponent>;
170
+ declare function isPropertyFieldType(value: string): value is PropertyFieldType;
179
171
  /**
180
- * Base widget schema with loose typing for runtime data.
181
- * Use TypedWidgetSchema<T> when you have a known registry for better type safety.
172
+ * Base schema for a property field
182
173
  */
183
- type WidgetSchema = {
184
- readonly type: WidgetType;
185
- readonly props: Readonly<Record<string, unknown>>;
186
- readonly id?: string; /** Optional data source configuration for data-bound widgets */
187
- readonly dataSource?: DataSourceConfig | undefined; /** Column index for masonry layouts (0-indexed) */
188
- readonly columnIndex?: number; /** Host-approved capabilities for a specific remote widget package version. */
189
- readonly capabilityGrants?: RemoteWidgetCapabilityGrants;
190
- };
174
+ interface PropertyFieldSchema {
175
+ /** Property key in the widget props */
176
+ key: string;
177
+ /** Display label for the field */
178
+ label: string;
179
+ /** Field type determines the input control */
180
+ type: PropertyFieldType;
181
+ /** Optional description/help text */
182
+ description?: string;
183
+ /** Optional default value */
184
+ defaultValue?: unknown;
185
+ /** Optional tab ID (must match a TabConfig id if widget has tabsConfig) */
186
+ tab?: string;
187
+ /** Optional group for organizing fields within a tab */
188
+ group?: string;
189
+ /**
190
+ * When true, this field is treated as an override of a value that can
191
+ * otherwise be inherited from the active theme (e.g. border radius,
192
+ * padding, border width). Advanced fields are automatically bucketed
193
+ * into the `CUSTOM_STYLING_GROUP` at the bottom of their tab and
194
+ * rendered collapsed by default so the default surface area stays
195
+ * minimal.
196
+ */
197
+ advanced?: boolean;
198
+ /**
199
+ * @deprecated Use requiresKeyValue instead
200
+ */
201
+ requiresKeyToBeTrue?: string;
202
+ /** Optional requires a specific key to have a specific value. Supports single condition or array (AND logic). */
203
+ requiresKeyValue?: {
204
+ key: string;
205
+ value: unknown;
206
+ } | Array<{
207
+ key: string;
208
+ value: unknown;
209
+ }>;
210
+ }
191
211
  /**
192
- * Type-safe widget schema based on registry.
193
- * Uses discriminated unions - the `type` field serves as discriminant.
194
- * When narrowed (e.g., `if (widget.type === "AlertWidget")`),
195
- * TypeScript automatically knows the correct props type.
212
+ * Text field schema
196
213
  */
197
- type TypedWidgetSchema<T extends Record<string, AnyComponent>> = { [K in keyof T]: {
198
- readonly type: K;
199
- readonly props: Readonly<T[K] extends ((props: infer P) => any) ? P : T[K] extends (new (props: infer P) => any) ? P : never>;
200
- readonly id?: string;
201
- readonly dataSource?: DataSourceConfig | undefined; /** Column index for masonry layouts (0-indexed) */
202
- readonly columnIndex?: number;
203
- readonly capabilityGrants?: RemoteWidgetCapabilityGrants;
204
- } }[keyof T];
214
+ interface TextFieldSchema extends PropertyFieldSchema {
215
+ type: "text";
216
+ placeholder?: string;
217
+ maxLength?: number;
218
+ /**
219
+ * Optional quick-insert chips rendered below the input. Clicking a chip
220
+ * inserts `{{value}}` at the caret. Used for URL template tokens
221
+ * (e.g. `{{username}}`, `{{replicated_url || /signup}}`) so admins
222
+ * don't have to remember the exact spelling.
223
+ */
224
+ tokenSuggestions?: ReadonlyArray<{
225
+ /** Chip label shown to the admin (e.g. `username`). */label: string; /** Token body inserted between `{{` and `}}` (e.g. `username || /signup`). */
226
+ value: string;
227
+ }>;
228
+ }
205
229
  /**
206
- * Widget path in the tree - array of indices.
207
- * Readonly tuple to prevent accidental mutation.
230
+ * Textarea field schema
208
231
  */
209
- type WidgetPath = readonly number[];
232
+ interface TextareaFieldSchema extends PropertyFieldSchema {
233
+ type: "textarea";
234
+ placeholder?: string;
235
+ rows?: number;
236
+ maxLength?: number;
237
+ }
210
238
  /**
211
- * Type predicate to check if a string is a known widget type name.
212
- * Use for runtime validation of widget types.
213
- *
214
- * @example
215
- * if (isWidgetTypeName(widget.type)) {
216
- * // TypeScript knows widget.type is WidgetTypeName
217
- * }
239
+ * Number field schema
218
240
  */
219
- declare function isWidgetTypeName(type: string): type is WidgetTypeName;
241
+ interface NumberFieldSchema extends PropertyFieldSchema {
242
+ type: "number";
243
+ min?: number;
244
+ max?: number;
245
+ step?: number;
246
+ }
220
247
  /**
221
- * Type predicate to check if a widget has a specific type.
222
- * Enables type-safe widget narrowing without `as` assertions.
223
- *
224
- * @example
225
- * if (isWidgetType(widget, "LayoutWidget")) {
226
- * // TypeScript knows widget.type === "LayoutWidget"
227
- * // and widget.props is LayoutWidget props
228
- * }
248
+ * Boolean field schema
229
249
  */
230
- declare function isWidgetType<T extends WidgetTypeName>(widget: WidgetSchema | null | undefined, typeName: T): widget is WidgetSchema & {
231
- readonly type: T;
232
- };
250
+ interface BooleanFieldSchema extends PropertyFieldSchema {
251
+ type: "boolean";
252
+ }
233
253
  /**
234
- * Helper for exhaustive switch statements on widget types.
235
- * Use in the default case to ensure all widget types are handled.
236
- *
237
- * @example
238
- * switch (widget.type) {
239
- * case "AlertWidget": return handleAlert();
240
- * case "TextWidget": return handleText();
241
- * // ... all other widget types
242
- * default: return assertNever(widget.type, "widget type");
243
- * }
254
+ * Select field schema with type-safe option values.
255
+ * Uses StrictOmit to ensure "defaultValue" key exists on PropertyFieldSchema.
244
256
  */
245
- declare function assertNever(value: never, context?: string): never;
257
+ interface SelectFieldSchema<T extends string | number = string | number> extends StrictOmit<PropertyFieldSchema, "defaultValue"> {
258
+ type: "select";
259
+ options: Array<{
260
+ label: string;
261
+ value: T;
262
+ }>;
263
+ defaultValue?: T;
264
+ }
246
265
  /**
247
- * Assertion function that throws if value is undefined.
248
- * Narrows the type to exclude undefined.
266
+ * Legacy free-form color field schema.
249
267
  *
250
- * @example
251
- * const widget = screen[0];
252
- * assertDefined(widget, "widget at index 0");
253
- * // TypeScript knows widget is defined here
268
+ * @deprecated Use {@link ColorSelectFieldSchema} (`type: "colorSelect"`) so
269
+ * widget authors select a semantic color token supplied by the portal theme.
254
270
  */
255
- declare function assertDefined<T>(value: T | undefined | null, name?: string): asserts value is T;
256
- //#endregion
257
- //#region ../../platform/theme-engine/src/types.d.ts
258
- declare const SEMANTIC_COLOR_NAMES: readonly ["background", "foreground", "primary", "secondary", "accent", "muted", "destructive"];
259
- type SemanticColorName = (typeof SEMANTIC_COLOR_NAMES)[number];
260
- declare const FONT_SIZE_KEYS: readonly ["extraSmall", "small", "regular", "large", "extraLarge", "giant"];
261
- type FontSizeKey = (typeof FONT_SIZE_KEYS)[number];
262
- declare const FONT_FAMILY_KEYS: readonly ["header", "body"];
263
- type FontFamilyKey = (typeof FONT_FAMILY_KEYS)[number];
264
- declare const RADIUS_KEYS: readonly ["small", "medium", "large", "extraLarge"];
265
- type RadiusKey = (typeof RADIUS_KEYS)[number];
266
- /** Author-time color input (what the user configures) */
267
- interface ThemeColorInput {
268
- base: Color;
269
- foreground: Color;
271
+ interface ColorFieldSchema extends PropertyFieldSchema {
272
+ type: "color";
270
273
  }
271
- /** Complete theme definition — stored in-memory with Color objects */
272
- interface ThemeDefinition {
273
- id: string;
274
- name: string;
275
- /** Light mode — always fully specified */
276
- light: Record<SemanticColorName, ThemeColorInput>;
277
- /**
278
- * Dark mode — only user-overridden colors.
279
- * Missing keys are auto-derived from `light` at resolve time.
280
- */
281
- dark: Partial<Record<SemanticColorName, Partial<ThemeColorInput>>>;
282
- fontSizes: Record<FontSizeKey, string>;
283
- fontFamilies: Record<FontFamilyKey, string>;
284
- spacing: string;
285
- radii: Record<RadiusKey, string>;
286
- /** When true, theme colors are re-derived from brand guidelines on every load */
287
- syncWithBrandColors?: boolean;
288
- }
289
- /** Resolved semantic color */
290
- interface ResolvedSemanticColor {
291
- base: Color;
292
- foreground: Color;
293
- }
294
- /** Complete resolved color set for one mode */
295
- type ResolvedColorSet = Record<SemanticColorName, ResolvedSemanticColor>;
296
- /** Fully resolved theme — all colors materialised for both modes */
297
- interface ResolvedTheme {
298
- id: string;
299
- name: string;
300
- light: ResolvedColorSet;
301
- dark: ResolvedColorSet;
302
- fontSizes: ThemeDefinition["fontSizes"];
303
- fontFamilies: ThemeDefinition["fontFamilies"];
304
- spacing: string;
305
- radii: ThemeDefinition["radii"];
306
- }
307
- /** Plain OKLCH triplet for JSON serialisation (no Color dependency) */
308
- interface OklchPlain {
309
- l: number;
310
- c: number;
311
- h: number;
274
+ /**
275
+ * Range slider field schema
276
+ */
277
+ interface RangeFieldSchema extends PropertyFieldSchema {
278
+ type: "range";
279
+ min: number;
280
+ max: number;
281
+ step?: number;
312
282
  }
313
- /** Serialised color pair as stored in the backend payload */
314
- interface ThemeColorPlain {
315
- base: OklchPlain;
316
- foreground: OklchPlain;
283
+ /**
284
+ * Data source field schema for configuring widget data sources
285
+ */
286
+ interface DataSourceFieldSchema extends PropertyFieldSchema {
287
+ /** Identifies this field as the data-source editor. */
288
+ type: "dataSource";
289
+ /** Widget props that this data-source editor can populate. */
290
+ targetProps?: ReadonlyArray<{
291
+ /** Widget prop key populated with the resolved data-source result. */key: string; /** Description emitted for this prop in the portal JSON Schema and types. */
292
+ description: string;
293
+ }>;
317
294
  }
318
- /** Backend payload — plain JSON, no Color objects */
319
- interface ThemePayload {
320
- [key: string]: unknown;
321
- id: string;
322
- name: string;
323
- light: Record<SemanticColorName, ThemeColorPlain>;
324
- dark: Partial<Record<SemanticColorName, {
325
- base?: OklchPlain;
326
- foreground?: OklchPlain;
327
- }>>;
328
- fontSizes: Record<FontSizeKey, string>;
329
- fontFamilies: Record<FontFamilyKey, string>;
330
- spacing: string;
331
- radii: Record<RadiusKey, string>;
332
- syncWithBrandColors?: boolean;
295
+ /**
296
+ * Resource field schema for selecting a single resource from the selection modal
297
+ */
298
+ interface ResourceFieldSchema extends PropertyFieldSchema {
299
+ type: "resource";
300
+ /** Optional filter to specific shareable types */
301
+ allowedTypes?: string[];
333
302
  }
334
- //#endregion
335
- //#region ../../platform/theme-engine/src/color-engine.d.ts
336
303
  /**
337
- * Attempt to convert any string into a Color using colorjs.io.
338
- * If the string is exactly 6 hex digits it is assumed to be a bare hex value
339
- * (e.g. "3b82f6") and a "#" prefix is added before parsing. Six-letter
340
- * named colours like "orange" or "maroon" are left untouched.
341
- *
342
- * @returns the parsed Color, or a neutral gray (`oklch(0.5 0 0)`) on failure
304
+ * Image field schema for selecting a single asset (image or video) from the
305
+ * image picker. Despite the legacy "image" name, this field supports video
306
+ * picking via the `accept` parameter — `VideoWidget`, `ListWidget` Featured
307
+ * Asset, and `NestedWidget` Primary Media all use it for video-or-mixed
308
+ * content.
343
309
  */
344
- declare function parseColor(value: string): Color;
310
+ interface ImageFieldSchema extends PropertyFieldSchema {
311
+ type: "image";
312
+ /**
313
+ * Restricts which MIME categories the picker offers. Defaults to "image".
314
+ */
315
+ accept?: "image" | "video" | "any";
316
+ }
345
317
  /**
346
- * Returns either the original foreground or a corrected lightness variant,
347
- * whichever provides better contrast against `color`.
348
- * Inversion triggers when the |APCA contrast| is below 50 — APCA is signed
349
- * (negative for dark-on-light, positive for light-on-dark), so comparing the
350
- * absolute value avoids flipping dark text that already contrasts well on a
351
- * medium background.
318
+ * Alignment field schema
352
319
  */
353
- declare function getForegroundColor(foreground: Color, color: Color): Color;
320
+ interface AlignmentFieldSchema extends PropertyFieldSchema {
321
+ type: "alignment";
322
+ options: {
323
+ verticalEnabled: boolean;
324
+ horizontalEnabled: boolean;
325
+ };
326
+ defaultValue?: AlignOptions;
327
+ }
354
328
  /**
355
- * Derive a dark-mode ThemeColorInput from its light-mode counterpart.
329
+ * Slider field schema with optional unit suffix (e.g., "rem", "px")
356
330
  */
357
- declare function deriveDarkVariant(name: SemanticColorName, light: ThemeColorInput): ThemeColorInput;
331
+ interface SliderFieldSchema extends PropertyFieldSchema {
332
+ type: "slider";
333
+ min: number;
334
+ max: number;
335
+ step?: number;
336
+ unit?: string;
337
+ }
358
338
  /**
359
- * Merge auto-derived dark colors with any user-specified overrides.
360
- * For each semantic color, if the user has fully overridden both base and
361
- * foreground those are used; otherwise the missing channels are derived.
339
+ * Color picker field schema with optional swatches
362
340
  */
363
- declare function mergeDarkOverrides(def: ThemeDefinition): Record<SemanticColorName, ThemeColorInput>;
341
+ interface ColorPickerFieldSchema extends PropertyFieldSchema {
342
+ type: "colorPicker";
343
+ swatches?: string[];
344
+ }
364
345
  /**
365
- * Resolve a ThemeDefinition into a complete ResolvedTheme.
366
- * Dark mode colors are derived from light where not overridden.
346
+ * Section header field schema for visual grouping
367
347
  */
368
- declare function resolveTheme(def: ThemeDefinition): ResolvedTheme;
369
- //#endregion
370
- //#region ../../platform/theme-engine/src/css-generator.d.ts
371
- interface GenerateThemeCSSOptions {
372
- /** Whether or not to allow prefers-color-scheme to choose the theme mode */
373
- disableAutoTheme?: boolean;
374
- /** Whether to emit Tailwind built-in color overrides (default true) */
375
- mapTailwindColors?: boolean;
348
+ interface SectionHeaderFieldSchema extends PropertyFieldSchema {
349
+ type: "sectionHeader";
350
+ subtitle?: string;
376
351
  }
377
352
  /**
378
- * Generate a complete CSS string for a resolved theme.
379
- * Outputs 2–3 blocks: light default, dark explicit via `[data-theme-mode="dark"]`,
380
- * and (unless `disableAutoTheme`) a `prefers-color-scheme: dark` media query block.
353
+ * Separator field schema for visual separation
381
354
  */
382
- declare function generateThemeCSS(theme: ResolvedTheme, options?: GenerateThemeCSSOptions): string;
383
- //#endregion
384
- //#region ../../platform/theme-engine/src/serialisation.d.ts
355
+ interface SeparatorFieldSchema extends PropertyFieldSchema {
356
+ type: "separator";
357
+ }
385
358
  /**
386
- * Serialise a ThemeDefinition (with Color objects) to a plain JSON payload
387
- * suitable for backend storage.
359
+ * Button group field schema.
360
+ * Uses StrictOmit to ensure "defaultValue" key exists on PropertyFieldSchema.
388
361
  */
389
- declare function serialiseTheme(def: ThemeDefinition): ThemePayload;
362
+ interface ButtonGroupFieldSchema<T extends string | number = string | number> extends StrictOmit<PropertyFieldSchema, "defaultValue"> {
363
+ type: "buttonGroup";
364
+ options: Array<{
365
+ label?: string;
366
+ ariaLabel?: string;
367
+ icon?: LucideIcon;
368
+ value: T;
369
+ }>;
370
+ defaultValue?: T;
371
+ }
390
372
  /**
391
- * Deserialise a backend payload into a ThemeDefinition with Color objects.
392
- * Accepts `Record<string, unknown>` because API data is untyped at the boundary.
393
- * Falls back to default colors for any missing light-mode entries.
373
+ * Semantic theme-color token selector. Prefer this field over free-form color
374
+ * controls so widgets continue to work across portal themes and color modes.
394
375
  */
395
- declare function deserialiseTheme(payload: Record<string, unknown>): ThemeDefinition;
396
- //#endregion
397
- //#region ../../platform/theme-engine/src/transforms.d.ts
398
- /** Shape of a raw theme from the FluidOS API */
399
- interface RawApiTheme {
400
- id: number;
401
- config?: Record<string, unknown> | null;
402
- active?: boolean | null;
403
- name?: string | null;
376
+ interface ColorSelectFieldSchema extends PropertyFieldSchema {
377
+ type: "colorSelect";
378
+ defaultValue?: ColorOptions;
379
+ excludeColors?: ColorOptions[];
404
380
  }
405
381
  /**
406
- * Build a ThemeDefinition from a single API theme object.
407
- * Handles both new structured format and legacy flat format.
382
+ * Section layout select field schema for visual masonry layout selector
408
383
  */
409
- declare function buildThemeDefinition(theme: RawApiTheme): ThemeDefinition;
384
+ interface SectionLayoutSelectFieldSchema extends PropertyFieldSchema {
385
+ type: "sectionLayoutSelect";
386
+ defaultValue?: SectionLayoutType;
387
+ }
410
388
  /**
411
- * Transform raw API themes to ThemeDefinition[].
412
- * Catches and logs errors per theme (graceful degradation).
389
+ * Background field combines resource selection and color properties.
390
+ * Uses StrictOmit to exclude conflicting "type" discriminant from parents.
413
391
  */
414
- declare function transformThemes(themes: RawApiTheme[]): ThemeDefinition[];
392
+ interface BackgroundFieldSchema extends StrictOmit<ResourceFieldSchema, "type">, StrictOmit<ColorFieldSchema, "type"> {
393
+ type: "background";
394
+ }
415
395
  /**
416
- * Get the active theme ID from a list of raw API themes.
417
- * Falls back to the first theme if none is marked active.
396
+ * Content position field schema for 3x3 grid position picker
418
397
  */
419
- declare function getActiveThemeId(themes: RawApiTheme[]): string | undefined;
420
- //#endregion
421
- //#region ../../platform/theme-engine/src/theme-applicator.d.ts
398
+ interface ContentPositionFieldSchema extends PropertyFieldSchema {
399
+ type: "contentPosition";
400
+ defaultValue?: string;
401
+ }
422
402
  /**
423
- * Inject or update a `<style>` element in `<head>` for the given theme.
424
- * The element ID is deterministic (`theme-style-{themeId}`) so repeated calls
425
- * for the same theme are idempotent — the existing element is updated in place.
426
- * Also loads Google Fonts referenced by the theme's font families.
427
- * No-op when `document` is unavailable (SSR).
403
+ * Text size select field schema for visual font size selector
428
404
  */
429
- declare function applyTheme(theme: ResolvedTheme, options?: GenerateThemeCSSOptions): void;
430
- /** Remove an injected theme stylesheet and clean up font link ownership. No-op during SSR. */
431
- declare function removeTheme(themeId: string): void;
432
- /** Remove all injected theme stylesheets and font links. No-op during SSR. */
433
- declare function removeAllThemes(): void;
434
- //#endregion
435
- //#region ../../platform/theme-engine/src/defaults.d.ts
436
- declare const DEFAULT_FONT_SIZES: Record<FontSizeKey, string>;
437
- declare const DEFAULT_FONT_FAMILIES: Record<FontFamilyKey, string>;
438
- declare const DEFAULT_SPACING = "0.25rem";
439
- declare const DEFAULT_RADII: Record<RadiusKey, string>;
440
- declare const DEFAULT_COLORS: {
441
- readonly background: "#ffffff";
442
- readonly foreground: "#1a1a1a";
443
- readonly primary: "#3b82f6";
444
- readonly secondary: "#6b7280";
445
- readonly accent: "#10b981";
446
- readonly muted: "#f3f4f6";
447
- readonly destructive: "#ef4444";
448
- readonly mutedForeground: "#6b7280";
449
- };
450
- declare const DEFAULT_THEME_ID = "default";
451
- declare const DEFAULT_THEME_NAME = "Default Theme";
405
+ interface TextSizeSelectFieldSchema extends PropertyFieldSchema {
406
+ type: "textSizeSelect";
407
+ defaultValue?: FontSizeOptions;
408
+ }
452
409
  /**
453
- * Build a fresh ThemeDefinition populated with all defaults.
454
- * Returns a new object each call because Color instances are mutable — do not cache the result.
410
+ * CSS unit type for height/width fields
455
411
  */
456
- declare function getDefaultThemeDefinition(): ThemeDefinition;
457
- //#endregion
458
- //#region ../core/src/types/navigation.d.ts
412
+ type CssUnit = "px" | "rem" | "vh" | "%";
459
413
  /**
460
- * Navigation item in the sidebar/menu structure.
461
- *
462
- * Field types match the FluidOS API schema (`FluidOSNavigationItem`).
463
- * Differences from the raw API type:
464
- * - `id` is optional (system/default items may not have one)
465
- * - `label` is required (transforms default null to "Untitled")
466
- * - `section` is a frontend-only extension (not in API)
467
- * - Nullable fields use `undefined` instead of `null` (except `parent_id`)
414
+ * CSS unit field schema for numeric values with selectable units (px, rem, vh, %)
468
415
  */
469
- interface NavigationItem {
470
- /** Database-generated identifier — optional because system/default items may not have one */
471
- readonly id?: number;
472
- /** URL slug for routing (`| undefined` for exactOptionalPropertyTypes compat) */
473
- slug?: string | undefined;
474
- /** Display label — required; transforms default null API values to "Untitled" */
475
- label: string;
476
- /** Icon identifier (e.g., FontAwesome name) */
477
- icon?: string | undefined;
478
- /** Section grouping for quick links (frontend-only, not in API) */
479
- section?: string;
480
- /** Associated screen ID */
481
- screen_id?: number | undefined;
482
- /** Sort order */
483
- position?: number | undefined;
484
- /** Parent navigation item ID (null for root items) */
485
- parent_id?: number | null;
486
- /** Origin of this navigation item */
487
- source?: "user" | "system" | "code";
488
- /** Nested navigation items */
489
- children: NavigationItem[];
416
+ interface CssUnitFieldSchema extends PropertyFieldSchema {
417
+ type: "cssUnit";
418
+ minByUnit?: Partial<Record<CssUnit, number>>;
419
+ maxByUnit?: Partial<Record<CssUnit, number>>;
420
+ stepByUnit?: Partial<Record<CssUnit, number>>;
421
+ allowedUnits?: CssUnit[];
422
+ defaultUnit?: CssUnit;
490
423
  }
491
424
  /**
492
- * Screen definition with its component tree
425
+ * Font picker field schema for Google Fonts selection
493
426
  */
494
- interface ScreenDefinition {
495
- readonly id: number;
496
- slug: string;
497
- name: string;
498
- component_tree: WidgetSchema[];
427
+ interface FontPickerFieldSchema extends PropertyFieldSchema {
428
+ type: "fontPicker";
429
+ placeholder?: string;
499
430
  }
500
431
  /**
501
- * Navigation configuration for the portal
432
+ * String array field schema for managing lists of text items
502
433
  */
503
- interface Navigation {
504
- readonly definition_id: number;
505
- readonly id: number;
506
- name: string;
507
- navigation_items: NavigationItem[];
508
- screens: ScreenDefinition[];
509
- }
510
- /** A portal app profile — themes, navigation, and definition reference. */
511
- interface RepAppProfile {
512
- name: string;
513
- themes: ThemeDefinition[];
514
- activeThemeId?: string;
515
- navigation: Navigation;
516
- mobile_navigation?: Navigation;
517
- definition_id: number;
518
- }
519
- /** Full portal app data returned by the fluidos API or builder preview. */
520
- interface RepAppData {
521
- definition_id: number;
522
- published_version: number;
523
- screens: ScreenDefinition[];
524
- profile: RepAppProfile;
525
- }
526
- /** Wrapper for the `/fluid_os/definitions/active` API response. */
527
- interface RepAppManifest {
528
- manifest: RepAppData;
434
+ interface StringArrayFieldSchema extends PropertyFieldSchema {
435
+ type: "stringArray";
436
+ placeholder?: string;
437
+ defaultValue?: string[];
529
438
  }
530
- //#endregion
531
- //#region ../core/src/types/shareable-item.d.ts
532
439
  /**
533
- * Base props for a shareable item.
534
- * Uses structural typing to be compatible with various modal implementations.
535
- * The index signature allows additional properties from consuming apps.
440
+ * Border radius composite field schema for controlling 4 corners with a single field.
441
+ * Maps to 4 individual widget prop keys (topLeft, topRight, bottomLeft, bottomRight).
536
442
  */
537
- interface ShareableItem {
538
- id: string | number;
539
- title?: string | null;
540
- image_url?: string | null;
541
- imageUrl?: string | null;
542
- kind?: string | null;
543
- type?: string | null;
544
- shareableType?: string | null;
545
- share_link?: string | null;
546
- videoUrl?: string;
547
- price?: string | number | null;
548
- display_price?: string | null;
549
- [key: string]: unknown;
443
+ interface BorderRadiusFieldSchema extends PropertyFieldSchema {
444
+ type: "borderRadius";
445
+ keys: {
446
+ topLeft: string;
447
+ topRight: string;
448
+ bottomLeft: string;
449
+ bottomRight: string;
450
+ };
451
+ defaultValue?: BorderRadiusOptions;
550
452
  }
551
- //#endregion
552
- //#region ../core/src/types/field-types.d.ts
553
453
  /**
554
- * Color options constant - single source of truth for color values.
555
- * Use COLOR_OPTIONS.primary instead of "primary" for type-safe comparisons.
556
- */
557
- declare const COLOR_OPTIONS: {
558
- readonly background: "background";
559
- readonly foreground: "foreground";
560
- readonly primary: "primary";
561
- readonly secondary: "secondary";
562
- readonly accent: "accent";
563
- readonly muted: "muted";
564
- readonly border: "border";
565
- readonly destructive: "destructive";
566
- readonly transparent: "transparent";
567
- };
568
- /**
569
- * Union type of all color options, derived from COLOR_OPTIONS constant.
570
- * @see deriving-typeof-for-object-keys pattern
454
+ * Screen picker field schema for selecting a portal screen (navigation, system, or available)
571
455
  */
572
- type ColorOptions = (typeof COLOR_OPTIONS)[keyof typeof COLOR_OPTIONS];
573
- declare const FONT_SIZE_OPTIONS: {
574
- readonly "2xl": "2xl";
575
- readonly xl: "xl";
576
- readonly lg: "lg";
577
- readonly md: "md";
578
- readonly sm: "sm";
579
- readonly xs: "xs";
580
- };
581
- type FontSizeOptions = (typeof FONT_SIZE_OPTIONS)[keyof typeof FONT_SIZE_OPTIONS];
582
- declare const FONT_WEIGHT_OPTIONS: {
583
- readonly normal: "normal";
584
- readonly medium: "medium";
585
- readonly semibold: "semibold";
586
- readonly bold: "bold";
587
- };
588
- type FontWeightOptions = (typeof FONT_WEIGHT_OPTIONS)[keyof typeof FONT_WEIGHT_OPTIONS];
589
- declare const BORDER_RADIUS_OPTIONS: {
590
- readonly none: "none";
591
- readonly sm: "sm";
592
- readonly md: "md";
593
- readonly lg: "lg";
594
- readonly xl: "xl";
595
- readonly full: "full";
596
- };
597
- type BorderRadiusOptions = (typeof BORDER_RADIUS_OPTIONS)[keyof typeof BORDER_RADIUS_OPTIONS];
598
- declare const BORDER_WIDTH_OPTIONS: {
599
- readonly none: "none";
600
- readonly thin: "thin";
601
- readonly medium: "medium";
602
- readonly thick: "thick";
603
- };
604
- type BorderWidthOptions = (typeof BORDER_WIDTH_OPTIONS)[keyof typeof BORDER_WIDTH_OPTIONS];
605
- /** Padding values - numeric, so we use a tuple for derivation */
606
- declare const PADDING_VALUES: readonly [0, 2, 4, 6, 8, 10];
607
- type PaddingOptions = (typeof PADDING_VALUES)[number];
608
- declare const BUTTON_SIZE_OPTIONS: {
609
- readonly sm: "sm";
610
- readonly default: "default";
611
- readonly lg: "lg";
612
- readonly xl: "xl";
613
- };
614
- type ButtonSizeOptions = (typeof BUTTON_SIZE_OPTIONS)[keyof typeof BUTTON_SIZE_OPTIONS];
615
- declare const GAP_OPTIONS: {
616
- readonly none: "none";
617
- readonly xs: "xs";
618
- readonly sm: "sm";
619
- readonly md: "md";
620
- readonly lg: "lg";
621
- readonly xl: "xl";
622
- };
623
- type GapOptions = (typeof GAP_OPTIONS)[keyof typeof GAP_OPTIONS];
624
- declare const VERTICAL_ALIGN_OPTIONS: {
625
- readonly top: "top";
626
- readonly center: "center";
627
- readonly bottom: "bottom";
628
- };
629
- type VerticalAlign = (typeof VERTICAL_ALIGN_OPTIONS)[keyof typeof VERTICAL_ALIGN_OPTIONS];
630
- declare const HORIZONTAL_ALIGN_OPTIONS: {
631
- readonly left: "left";
632
- readonly center: "center";
633
- readonly right: "right";
634
- };
635
- type HorizontalAlign = (typeof HORIZONTAL_ALIGN_OPTIONS)[keyof typeof HORIZONTAL_ALIGN_OPTIONS];
636
- type AlignOptions = {
637
- vertical?: VerticalAlign;
638
- horizontal?: HorizontalAlign;
639
- };
640
- declare const BACKGROUND_TYPES: {
641
- readonly solid: "solid";
642
- readonly image: "image";
643
- };
644
- type BackgroundType = (typeof BACKGROUND_TYPES)[keyof typeof BACKGROUND_TYPES];
645
- interface BackgroundValue {
646
- type: BackgroundType;
647
- color?: ColorOptions;
648
- resource?: ShareableItem;
456
+ interface ScreenPickerFieldSchema extends PropertyFieldSchema {
457
+ type: "screenPicker";
458
+ /** Whether to include system navigation items in the picker */
459
+ includeSystemItems?: boolean;
649
460
  }
650
461
  /**
651
- * Section layout configuration - single source of truth for layout types.
652
- * SectionLayoutType is derived from these keys to prevent drift.
653
- */
654
- declare const SECTION_LAYOUT_CONFIG: {
655
- readonly "single-column": {
656
- readonly columns: 1;
657
- readonly widths: readonly ["1fr"];
658
- readonly gridClasses: "";
659
- };
660
- readonly "2c-equal": {
661
- readonly columns: 2;
662
- readonly widths: readonly ["1fr", "1fr"];
663
- readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]";
664
- };
665
- readonly "2c-left-wider": {
666
- readonly columns: 2;
667
- readonly widths: readonly ["2fr", "1fr"];
668
- readonly gridClasses: "@md:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]";
669
- };
670
- readonly "2c-right-wider": {
671
- readonly columns: 2;
672
- readonly widths: readonly ["1fr", "2fr"];
673
- readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]";
674
- };
675
- readonly "2c-left-narrow": {
676
- readonly columns: 2;
677
- readonly widths: readonly ["1fr", "3fr"];
678
- readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,3fr)]";
679
- };
680
- readonly "2c-right-narrow": {
681
- readonly columns: 2;
682
- readonly widths: readonly ["3fr", "1fr"];
683
- readonly gridClasses: "@md:grid-cols-[minmax(0,3fr)_minmax(0,1fr)]";
684
- };
685
- readonly "3c-equal": {
686
- readonly columns: 3;
687
- readonly widths: readonly ["1fr", "1fr", "1fr"];
688
- readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)]";
689
- };
690
- readonly "3c-middle-wider": {
691
- readonly columns: 3;
692
- readonly widths: readonly ["1fr", "2fr", "1fr"];
693
- readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,2fr)_minmax(0,1fr)]";
694
- };
695
- };
696
- /**
697
- * Union type of all section layout types, derived from SECTION_LAYOUT_CONFIG keys.
698
- * @see deriving-typeof-for-object-keys pattern
462
+ * Union of all field schema types
699
463
  */
700
- type SectionLayoutType = keyof typeof SECTION_LAYOUT_CONFIG;
701
- /** @deprecated Use SECTION_LAYOUT_CONFIG instead */
702
- declare const sectionLayoutConfig: typeof SECTION_LAYOUT_CONFIG;
703
- //#endregion
704
- //#region ../core/src/types/index.d.ts
705
- type StrictOmit<T, K extends keyof T> = Omit<T, K>;
706
- //#endregion
707
- //#region ../core/src/registries/property-schema-types.d.ts
464
+ type PropertyField = TextFieldSchema | TextareaFieldSchema | NumberFieldSchema | BooleanFieldSchema | SelectFieldSchema<string | number> | ColorFieldSchema | RangeFieldSchema | DataSourceFieldSchema | ResourceFieldSchema | ImageFieldSchema | AlignmentFieldSchema | SliderFieldSchema | ColorPickerFieldSchema | SectionHeaderFieldSchema | SeparatorFieldSchema | ButtonGroupFieldSchema<string | number> | ColorSelectFieldSchema | SectionLayoutSelectFieldSchema | BackgroundFieldSchema | ContentPositionFieldSchema | TextSizeSelectFieldSchema | CssUnitFieldSchema | FontPickerFieldSchema | StringArrayFieldSchema | BorderRadiusFieldSchema | ScreenPickerFieldSchema;
708
465
  /**
709
- * Tab configuration for organizing properties
466
+ * Schema for per-item configuration in custom data sources.
467
+ * Widgets can define this to allow users to configure widget-specific
468
+ * settings for each selected item (e.g., title, description, button).
710
469
  */
711
- interface TabConfig {
712
- /** Unique identifier for the tab */
713
- id: string;
714
- /** Display label for the tab */
715
- label: string;
470
+ interface ItemConfigSchema {
471
+ /** Fields available for per-item configuration */
472
+ fields: PropertyField[];
473
+ /** Optional description shown at top of item config panel */
474
+ description?: string;
716
475
  }
717
476
  /**
718
- * Property field type constant - single source of truth for field types.
719
- * Use PROPERTY_FIELD_TYPES.text instead of "text" for type-safe comparisons.
720
- */
721
- declare const PROPERTY_FIELD_TYPES: {
722
- readonly text: "text";
723
- readonly textarea: "textarea";
724
- readonly number: "number";
725
- readonly boolean: "boolean";
726
- readonly select: "select";
727
- readonly color: "color";
728
- readonly range: "range";
729
- readonly dataSource: "dataSource";
730
- readonly resource: "resource";
731
- readonly image: "image";
732
- readonly alignment: "alignment";
733
- readonly slider: "slider";
734
- readonly colorPicker: "colorPicker";
735
- readonly sectionHeader: "sectionHeader";
736
- readonly separator: "separator";
737
- readonly buttonGroup: "buttonGroup";
738
- readonly colorSelect: "colorSelect";
739
- readonly sectionLayoutSelect: "sectionLayoutSelect";
740
- readonly background: "background";
741
- readonly contentPosition: "contentPosition";
742
- readonly textSizeSelect: "textSizeSelect";
743
- readonly cssUnit: "cssUnit";
744
- readonly fontPicker: "fontPicker";
745
- readonly stringArray: "stringArray";
746
- readonly borderRadius: "borderRadius";
747
- readonly screenPicker: "screenPicker";
748
- };
749
- /**
750
- * Union type of all property field types, derived from PROPERTY_FIELD_TYPES constant.
751
- * @see deriving-typeof-for-object-keys pattern
752
- */
753
- type PropertyFieldType = (typeof PROPERTY_FIELD_TYPES)[keyof typeof PROPERTY_FIELD_TYPES];
754
- /**
755
- * Runtime validation for property field types.
756
- * @param value - The value to check
757
- * @returns true if value is a valid PropertyFieldType
758
- */
759
- declare function isPropertyFieldType(value: string): value is PropertyFieldType;
760
- /**
761
- * Base schema for a property field
477
+ * Schema for a widget's editable properties
762
478
  */
763
- interface PropertyFieldSchema {
764
- /** Property key in the widget props */
765
- key: string;
766
- /** Display label for the field */
767
- label: string;
768
- /** Field type determines the input control */
769
- type: PropertyFieldType;
770
- /** Optional description/help text */
771
- description?: string;
772
- /** Optional default value */
773
- defaultValue?: unknown;
774
- /** Optional tab ID (must match a TabConfig id if widget has tabsConfig) */
775
- tab?: string;
776
- /** Optional group for organizing fields within a tab */
777
- group?: string;
778
- /**
779
- * When true, this field is treated as an override of a value that can
780
- * otherwise be inherited from the active theme (e.g. border radius,
781
- * padding, border width). Advanced fields are automatically bucketed
782
- * into the `CUSTOM_STYLING_GROUP` at the bottom of their tab and
783
- * rendered collapsed by default so the default surface area stays
784
- * minimal.
785
- */
786
- advanced?: boolean;
787
- /**
788
- * @deprecated Use requiresKeyValue instead
789
- */
790
- requiresKeyToBeTrue?: string;
791
- /** Optional requires a specific key to have a specific value. Supports single condition or array (AND logic). */
792
- requiresKeyValue?: {
793
- key: string;
794
- value: unknown;
795
- } | Array<{
796
- key: string;
797
- value: unknown;
798
- }>;
479
+ interface WidgetPropertySchema {
480
+ /** Widget type this schema applies to */
481
+ widgetType: WidgetType;
482
+ /** Display name for the widget */
483
+ displayName: string;
484
+ /** Optional tab configuration - if present, tabs are enabled */
485
+ tabsConfig?: TabConfig[];
486
+ /** Editable property fields */
487
+ fields: PropertyField[];
488
+ /** Optional custom validator function */
489
+ validate?: (props: Record<string, unknown>) => string | null;
490
+ /** Props that can be populated from data sources */
491
+ dataSourceTargetProps?: string[];
492
+ /** Optional schema for per-item configurations in custom data sources */
493
+ itemConfigSchema?: ItemConfigSchema;
799
494
  }
800
495
  /**
801
- * Text field schema
496
+ * Group property fields by their group property.
497
+ *
498
+ * Fields flagged with `advanced: true` are collected into the
499
+ * `CUSTOM_STYLING_GROUP` bucket regardless of their declared `group`,
500
+ * and that bucket is always placed last so it renders at the bottom of
501
+ * the tab. Non-advanced fields keep their author-declared group and
502
+ * their relative insertion order, including fields that explicitly use
503
+ * `CUSTOM_STYLING_GROUP`.
802
504
  */
803
- interface TextFieldSchema extends PropertyFieldSchema {
804
- type: "text";
805
- placeholder?: string;
806
- maxLength?: number;
807
- /**
808
- * Optional quick-insert chips rendered below the input. Clicking a chip
809
- * inserts `{{value}}` at the caret. Used for URL template tokens
810
- * (e.g. `{{username}}`, `{{replicated_url || /signup}}`) so admins
811
- * don't have to remember the exact spelling.
812
- */
813
- tokenSuggestions?: ReadonlyArray<{
814
- /** Chip label shown to the admin (e.g. `username`). */label: string; /** Token body inserted between `{{` and `}}` (e.g. `username || /signup`). */
815
- value: string;
816
- }>;
817
- }
505
+ declare function groupPropertyFields(fields: readonly PropertyField[]): Record<string, PropertyField[]>;
818
506
  /**
819
- * Textarea field schema
507
+ * Extract current values from widget props based on property fields
820
508
  */
821
- interface TextareaFieldSchema extends PropertyFieldSchema {
822
- type: "textarea";
823
- placeholder?: string;
824
- rows?: number;
825
- maxLength?: number;
826
- }
509
+ declare function extractPropertyValues(widget: Readonly<WidgetSchema>, fields: readonly PropertyField[]): Record<string, unknown>;
827
510
  /**
828
- * Number field schema
511
+ * Apply property values to widget props
829
512
  */
830
- interface NumberFieldSchema extends PropertyFieldSchema {
831
- type: "number";
832
- min?: number;
833
- max?: number;
834
- step?: number;
513
+ declare function applyPropertyValues(widget: Readonly<WidgetSchema>, values: Readonly<Record<string, unknown>>): WidgetSchema;
514
+ //#endregion
515
+ //#region ../core/src/remote-dom-widget-package.d.ts
516
+ declare const REMOTE_DOM_WIDGET_MANIFEST_VERSION: 1;
517
+ declare const REMOTE_DOM_WIDGET_RUNTIME: "remote-dom";
518
+ type JsonPrimitive = string | number | boolean | null;
519
+ type JsonValue = JsonPrimitive | readonly JsonValue[] | JsonObject;
520
+ interface JsonObject {
521
+ readonly [key: string]: JsonValue;
835
522
  }
523
+ type SerializableValue<Value> = unknown extends Value ? JsonValue : Value extends JsonValue ? Value : Value extends readonly (infer Item)[] ? readonly SerializableValue<Item>[] : Value extends object ? { readonly [Key in keyof Value as NonNullable<Value[Key]> extends ((...args: never[]) => unknown) ? never : Key]: SerializableValue<Value[Key]> } : never;
836
524
  /**
837
- * Boolean field schema
838
- */
839
- interface BooleanFieldSchema extends PropertyFieldSchema {
840
- type: "boolean";
525
+ * A property field that can be included in published widget metadata.
526
+ *
527
+ * The legacy `color` field is deprecated. Use `colorSelect` so the value is a
528
+ * semantic color token supplied by the portal theme.
529
+ */
530
+ type WidgetSourcePropertyField = PropertyField extends infer Field ? Field extends ButtonGroupFieldSchema ? Omit<SerializableValue<Field>, "options"> & {
531
+ /** Serializable button choices. Runtime icon components are not supported. */readonly options: readonly {
532
+ readonly label?: string;
533
+ readonly ariaLabel?: string;
534
+ readonly value: string | number;
535
+ }[];
536
+ } : SerializableValue<Field> : never;
537
+ /**
538
+ * JSON-serializable property editor schema accepted by widget source metadata.
539
+ * The build adds `widgetType`; authors must not supply it.
540
+ */
541
+ interface WidgetSourcePropertySchema {
542
+ /** Optional tabs used to organize the property editor. */
543
+ readonly tabsConfig?: SerializableValue<NonNullable<WidgetPropertySchema["tabsConfig"]>>;
544
+ /** Editable fields shown in the property editor. */
545
+ readonly fields: readonly WidgetSourcePropertyField[];
546
+ /** Widget props that data sources can populate. */
547
+ readonly dataSourceTargetProps?: readonly string[];
548
+ /** Optional per-item fields for custom data-source selections. */
549
+ readonly itemConfigSchema?: {
550
+ /** Fields available for each selected item. */readonly fields: readonly WidgetSourcePropertyField[]; /** Help text shown above the per-item editor. */
551
+ readonly description?: string;
552
+ };
553
+ }
554
+ interface RemoteDomWidgetCapabilityDeclaration {
555
+ readonly name: string;
556
+ readonly version: string;
557
+ }
558
+ interface RemoteDomWidgetDefinition {
559
+ readonly type: string;
560
+ readonly displayName: string;
561
+ readonly description: string;
562
+ readonly icon: string;
563
+ readonly category: string;
564
+ readonly propertySchema: JsonObject;
565
+ readonly defaultProps: JsonObject;
566
+ readonly container: "inline" | "block" | "card" | "fullscreen";
567
+ readonly resizable: boolean | "horizontal" | "vertical" | "both";
568
+ readonly minSdkVersion: string;
569
+ readonly capabilities: readonly RemoteDomWidgetCapabilityDeclaration[];
841
570
  }
842
571
  /**
843
- * Select field schema with type-safe option values.
844
- * Uses StrictOmit to ensure "defaultValue" key exists on PropertyFieldSchema.
572
+ * Canonical package contract shared by the CLI, catalog APIs, and portal hosts.
573
+ * Catalog producers resolve every artifact to its public URL before returning
574
+ * this descriptor; consumers do not translate legacy manifest shapes.
845
575
  */
846
- interface SelectFieldSchema<T extends string | number = string | number> extends StrictOmit<PropertyFieldSchema, "defaultValue"> {
847
- type: "select";
848
- options: Array<{
849
- label: string;
850
- value: T;
851
- }>;
852
- defaultValue?: T;
576
+ interface RemoteDomWidgetPackageDescriptor {
577
+ readonly manifestVersion: typeof REMOTE_DOM_WIDGET_MANIFEST_VERSION;
578
+ readonly runtime: typeof REMOTE_DOM_WIDGET_RUNTIME;
579
+ readonly packageId: string;
580
+ readonly source: "company" | "droplet";
581
+ readonly version: string;
582
+ readonly workerEntryUrl: string;
583
+ readonly cssUrls: readonly string[];
584
+ readonly assetUrls: readonly string[];
585
+ readonly widgets: readonly RemoteDomWidgetDefinition[];
586
+ }
587
+ //#endregion
588
+ //#region ../core/src/remote-widget-network-access.d.ts
589
+ interface RemoteWidgetNetworkAccessGrant {
590
+ readonly packageId: string;
591
+ readonly packageVersion: string;
592
+ readonly capabilityVersion: string;
853
593
  }
594
+ interface RemoteWidgetCapabilityGrants {
595
+ readonly networkAccess?: RemoteWidgetNetworkAccessGrant;
596
+ }
597
+ //#endregion
598
+ //#region ../core/src/types/widget-schema.d.ts
854
599
  /**
855
- * Color field schema
600
+ * Generic component type — avoids React dependency in core.
601
+ * Accepts both function components and class component constructors.
856
602
  */
857
- interface ColorFieldSchema extends PropertyFieldSchema {
858
- type: "color";
859
- }
603
+ type AnyComponent = ((props: any) => any) | (new (props: any) => any);
860
604
  /**
861
- * Range slider field schema
605
+ * Widget type names as a const object.
606
+ * This serves as the single source of truth for widget discriminants.
607
+ * Use `as const` for literal type inference (safety-as-const-deep-readonly rule).
862
608
  */
863
- interface RangeFieldSchema extends PropertyFieldSchema {
864
- type: "range";
865
- min: number;
866
- max: number;
867
- step?: number;
868
- }
609
+ declare const WIDGET_TYPE_NAMES: {
610
+ readonly Alert: "AlertWidget";
611
+ readonly BulletList: "BulletListWidget";
612
+ readonly Calendar: "CalendarWidget";
613
+ readonly Card: "CardWidget";
614
+ readonly Carousel: "CarouselWidget";
615
+ readonly CatchUp: "CatchUpWidget";
616
+ readonly Chart: "ChartWidget";
617
+ readonly Container: "ContainerWidget";
618
+ readonly Embed: "EmbedWidget";
619
+ readonly Image: "ImageWidget";
620
+ readonly Layout: "LayoutWidget";
621
+ readonly Link: "LinkWidget";
622
+ readonly List: "ListWidget";
623
+ readonly MySite: "MySiteWidget";
624
+ readonly Nested: "NestedWidget";
625
+ readonly Points: "PointsWidget";
626
+ readonly QuickLinks: "QuickLinksWidget";
627
+ readonly QuickShare: "QuickShareWidget";
628
+ readonly RecentActivity: "RecentActivityWidget";
629
+ readonly Separator: "SeparatorWidget";
630
+ readonly Shop: "ShopWidget";
631
+ readonly Spacer: "SpacerWidget";
632
+ readonly Table: "TableWidget";
633
+ readonly Text: "TextWidget";
634
+ readonly ToDo: "ToDoWidget";
635
+ readonly Video: "VideoWidget";
636
+ };
869
637
  /**
870
- * Data source field schema for configuring widget data sources
638
+ * Union of all known widget type names.
639
+ * Derived from WIDGET_TYPE_NAMES to avoid duplication (deriving-typeof-for-object-keys rule).
871
640
  */
872
- interface DataSourceFieldSchema extends PropertyFieldSchema {
873
- type: "dataSource";
874
- }
641
+ type WidgetTypeName = (typeof WIDGET_TYPE_NAMES)[keyof typeof WIDGET_TYPE_NAMES];
875
642
  /**
876
- * Resource field schema for selecting a single resource from the selection modal
643
+ * Legacy alias for backwards compatibility.
644
+ * Prefer using WidgetTypeName for new code when you need the union type.
877
645
  */
878
- interface ResourceFieldSchema extends PropertyFieldSchema {
879
- type: "resource";
880
- /** Optional filter to specific shareable types */
881
- allowedTypes?: string[];
882
- }
646
+ type WidgetType = string;
647
+ type WidgetRegistry = Record<WidgetType, AnyComponent>;
883
648
  /**
884
- * Image field schema for selecting a single asset (image or video) from the
885
- * image picker. Despite the legacy "image" name, this field supports video
886
- * picking via the `accept` parameter — `VideoWidget`, `ListWidget` Featured
887
- * Asset, and `NestedWidget` Primary Media all use it for video-or-mixed
888
- * content.
649
+ * Base widget schema with loose typing for runtime data.
650
+ * Use TypedWidgetSchema<T> when you have a known registry for better type safety.
889
651
  */
890
- interface ImageFieldSchema extends PropertyFieldSchema {
891
- type: "image";
652
+ type WidgetSchema = {
653
+ readonly type: WidgetType;
654
+ readonly props: Readonly<Record<string, unknown>>;
655
+ readonly id?: string; /** Optional data source configuration for data-bound widgets */
656
+ readonly dataSource?: DataSourceConfig | undefined; /** Column index for masonry layouts (0-indexed) */
657
+ readonly columnIndex?: number; /** Host-approved capabilities for a specific remote widget package version. */
658
+ readonly capabilityGrants?: RemoteWidgetCapabilityGrants;
659
+ };
660
+ /**
661
+ * Type-safe widget schema based on registry.
662
+ * Uses discriminated unions - the `type` field serves as discriminant.
663
+ * When narrowed (e.g., `if (widget.type === "AlertWidget")`),
664
+ * TypeScript automatically knows the correct props type.
665
+ */
666
+ type TypedWidgetSchema<T extends Record<string, AnyComponent>> = { [K in keyof T]: {
667
+ readonly type: K;
668
+ readonly props: Readonly<T[K] extends ((props: infer P) => any) ? P : T[K] extends (new (props: infer P) => any) ? P : never>;
669
+ readonly id?: string;
670
+ readonly dataSource?: DataSourceConfig | undefined; /** Column index for masonry layouts (0-indexed) */
671
+ readonly columnIndex?: number;
672
+ readonly capabilityGrants?: RemoteWidgetCapabilityGrants;
673
+ } }[keyof T];
674
+ /**
675
+ * Widget path in the tree - array of indices.
676
+ * Readonly tuple to prevent accidental mutation.
677
+ */
678
+ type WidgetPath = readonly number[];
679
+ /**
680
+ * Type predicate to check if a string is a known widget type name.
681
+ * Use for runtime validation of widget types.
682
+ *
683
+ * @example
684
+ * if (isWidgetTypeName(widget.type)) {
685
+ * // TypeScript knows widget.type is WidgetTypeName
686
+ * }
687
+ */
688
+ declare function isWidgetTypeName(type: string): type is WidgetTypeName;
689
+ /**
690
+ * Type predicate to check if a widget has a specific type.
691
+ * Enables type-safe widget narrowing without `as` assertions.
692
+ *
693
+ * @example
694
+ * if (isWidgetType(widget, "LayoutWidget")) {
695
+ * // TypeScript knows widget.type === "LayoutWidget"
696
+ * // and widget.props is LayoutWidget props
697
+ * }
698
+ */
699
+ declare function isWidgetType<T extends WidgetTypeName>(widget: WidgetSchema | null | undefined, typeName: T): widget is WidgetSchema & {
700
+ readonly type: T;
701
+ };
702
+ /**
703
+ * Helper for exhaustive switch statements on widget types.
704
+ * Use in the default case to ensure all widget types are handled.
705
+ *
706
+ * @example
707
+ * switch (widget.type) {
708
+ * case "AlertWidget": return handleAlert();
709
+ * case "TextWidget": return handleText();
710
+ * // ... all other widget types
711
+ * default: return assertNever(widget.type, "widget type");
712
+ * }
713
+ */
714
+ declare function assertNever(value: never, context?: string): never;
715
+ /**
716
+ * Assertion function that throws if value is undefined.
717
+ * Narrows the type to exclude undefined.
718
+ *
719
+ * @example
720
+ * const widget = screen[0];
721
+ * assertDefined(widget, "widget at index 0");
722
+ * // TypeScript knows widget is defined here
723
+ */
724
+ declare function assertDefined<T>(value: T | undefined | null, name?: string): asserts value is T;
725
+ //#endregion
726
+ //#region ../../platform/theme-engine/src/types.d.ts
727
+ declare const SEMANTIC_COLOR_NAMES: readonly ["background", "foreground", "primary", "secondary", "accent", "muted", "destructive"];
728
+ type SemanticColorName = (typeof SEMANTIC_COLOR_NAMES)[number];
729
+ declare const FONT_SIZE_KEYS: readonly ["extraSmall", "small", "regular", "large", "extraLarge", "giant"];
730
+ type FontSizeKey = (typeof FONT_SIZE_KEYS)[number];
731
+ declare const FONT_FAMILY_KEYS: readonly ["header", "body"];
732
+ type FontFamilyKey = (typeof FONT_FAMILY_KEYS)[number];
733
+ declare const RADIUS_KEYS: readonly ["small", "medium", "large", "extraLarge"];
734
+ type RadiusKey = (typeof RADIUS_KEYS)[number];
735
+ /** Author-time color input (what the user configures) */
736
+ interface ThemeColorInput {
737
+ base: Color;
738
+ foreground: Color;
739
+ }
740
+ /** Complete theme definition — stored in-memory with Color objects */
741
+ interface ThemeDefinition {
742
+ id: string;
743
+ name: string;
744
+ /** Light mode — always fully specified */
745
+ light: Record<SemanticColorName, ThemeColorInput>;
892
746
  /**
893
- * Restricts which MIME categories the picker offers. Defaults to "image".
747
+ * Dark mode — only user-overridden colors.
748
+ * Missing keys are auto-derived from `light` at resolve time.
894
749
  */
895
- accept?: "image" | "video" | "any";
750
+ dark: Partial<Record<SemanticColorName, Partial<ThemeColorInput>>>;
751
+ fontSizes: Record<FontSizeKey, string>;
752
+ fontFamilies: Record<FontFamilyKey, string>;
753
+ spacing: string;
754
+ radii: Record<RadiusKey, string>;
755
+ /** When true, theme colors are re-derived from brand guidelines on every load */
756
+ syncWithBrandColors?: boolean;
757
+ }
758
+ /** Resolved semantic color */
759
+ interface ResolvedSemanticColor {
760
+ base: Color;
761
+ foreground: Color;
762
+ }
763
+ /** Complete resolved color set for one mode */
764
+ type ResolvedColorSet = Record<SemanticColorName, ResolvedSemanticColor>;
765
+ /** Fully resolved theme — all colors materialised for both modes */
766
+ interface ResolvedTheme {
767
+ id: string;
768
+ name: string;
769
+ light: ResolvedColorSet;
770
+ dark: ResolvedColorSet;
771
+ fontSizes: ThemeDefinition["fontSizes"];
772
+ fontFamilies: ThemeDefinition["fontFamilies"];
773
+ spacing: string;
774
+ radii: ThemeDefinition["radii"];
896
775
  }
897
- /**
898
- * Alignment field schema
899
- */
900
- interface AlignmentFieldSchema extends PropertyFieldSchema {
901
- type: "alignment";
902
- options: {
903
- verticalEnabled: boolean;
904
- horizontalEnabled: boolean;
905
- };
906
- defaultValue?: AlignOptions;
776
+ /** Plain OKLCH triplet for JSON serialisation (no Color dependency) */
777
+ interface OklchPlain {
778
+ l: number;
779
+ c: number;
780
+ h: number;
907
781
  }
908
- /**
909
- * Slider field schema with optional unit suffix (e.g., "rem", "px")
910
- */
911
- interface SliderFieldSchema extends PropertyFieldSchema {
912
- type: "slider";
913
- min: number;
914
- max: number;
915
- step?: number;
916
- unit?: string;
782
+ /** Serialised color pair as stored in the backend payload */
783
+ interface ThemeColorPlain {
784
+ base: OklchPlain;
785
+ foreground: OklchPlain;
786
+ }
787
+ /** Backend payload — plain JSON, no Color objects */
788
+ interface ThemePayload {
789
+ [key: string]: unknown;
790
+ id: string;
791
+ name: string;
792
+ light: Record<SemanticColorName, ThemeColorPlain>;
793
+ dark: Partial<Record<SemanticColorName, {
794
+ base?: OklchPlain;
795
+ foreground?: OklchPlain;
796
+ }>>;
797
+ fontSizes: Record<FontSizeKey, string>;
798
+ fontFamilies: Record<FontFamilyKey, string>;
799
+ spacing: string;
800
+ radii: Record<RadiusKey, string>;
801
+ syncWithBrandColors?: boolean;
917
802
  }
803
+ //#endregion
804
+ //#region ../../platform/theme-engine/src/color-engine.d.ts
918
805
  /**
919
- * Color picker field schema with optional swatches
806
+ * Attempt to convert any string into a Color using colorjs.io.
807
+ * If the string is exactly 6 hex digits it is assumed to be a bare hex value
808
+ * (e.g. "3b82f6") and a "#" prefix is added before parsing. Six-letter
809
+ * named colours like "orange" or "maroon" are left untouched.
810
+ *
811
+ * @returns the parsed Color, or a neutral gray (`oklch(0.5 0 0)`) on failure
920
812
  */
921
- interface ColorPickerFieldSchema extends PropertyFieldSchema {
922
- type: "colorPicker";
923
- swatches?: string[];
924
- }
813
+ declare function parseColor(value: string): Color;
925
814
  /**
926
- * Section header field schema for visual grouping
815
+ * Returns either the original foreground or a corrected lightness variant,
816
+ * whichever provides better contrast against `color`.
817
+ * Inversion triggers when the |APCA contrast| is below 50 — APCA is signed
818
+ * (negative for dark-on-light, positive for light-on-dark), so comparing the
819
+ * absolute value avoids flipping dark text that already contrasts well on a
820
+ * medium background.
927
821
  */
928
- interface SectionHeaderFieldSchema extends PropertyFieldSchema {
929
- type: "sectionHeader";
930
- subtitle?: string;
931
- }
822
+ declare function getForegroundColor(foreground: Color, color: Color): Color;
932
823
  /**
933
- * Separator field schema for visual separation
824
+ * Derive a dark-mode ThemeColorInput from its light-mode counterpart.
934
825
  */
935
- interface SeparatorFieldSchema extends PropertyFieldSchema {
936
- type: "separator";
937
- }
826
+ declare function deriveDarkVariant(name: SemanticColorName, light: ThemeColorInput): ThemeColorInput;
938
827
  /**
939
- * Button group field schema.
940
- * Uses StrictOmit to ensure "defaultValue" key exists on PropertyFieldSchema.
828
+ * Merge auto-derived dark colors with any user-specified overrides.
829
+ * For each semantic color, if the user has fully overridden both base and
830
+ * foreground those are used; otherwise the missing channels are derived.
941
831
  */
942
- interface ButtonGroupFieldSchema<T extends string | number = string | number> extends StrictOmit<PropertyFieldSchema, "defaultValue"> {
943
- type: "buttonGroup";
944
- options: Array<{
945
- label?: string;
946
- ariaLabel?: string;
947
- icon?: LucideIcon;
948
- value: T;
949
- }>;
950
- defaultValue?: T;
951
- }
832
+ declare function mergeDarkOverrides(def: ThemeDefinition): Record<SemanticColorName, ThemeColorInput>;
952
833
  /**
953
- * Color select field schema
834
+ * Resolve a ThemeDefinition into a complete ResolvedTheme.
835
+ * Dark mode colors are derived from light where not overridden.
954
836
  */
955
- interface ColorSelectFieldSchema extends PropertyFieldSchema {
956
- type: "colorSelect";
957
- defaultValue?: ColorOptions;
958
- excludeColors?: ColorOptions[];
837
+ declare function resolveTheme(def: ThemeDefinition): ResolvedTheme;
838
+ //#endregion
839
+ //#region ../../platform/theme-engine/src/css-generator.d.ts
840
+ interface GenerateThemeCSSOptions {
841
+ /** Whether or not to allow prefers-color-scheme to choose the theme mode */
842
+ disableAutoTheme?: boolean;
843
+ /** Whether to emit Tailwind built-in color overrides (default true) */
844
+ mapTailwindColors?: boolean;
959
845
  }
960
846
  /**
961
- * Section layout select field schema for visual masonry layout selector
847
+ * Generate a complete CSS string for a resolved theme.
848
+ * Outputs 2–3 blocks: light default, dark explicit via `[data-theme-mode="dark"]`,
849
+ * and (unless `disableAutoTheme`) a `prefers-color-scheme: dark` media query block.
962
850
  */
963
- interface SectionLayoutSelectFieldSchema extends PropertyFieldSchema {
964
- type: "sectionLayoutSelect";
965
- defaultValue?: SectionLayoutType;
966
- }
851
+ declare function generateThemeCSS(theme: ResolvedTheme, options?: GenerateThemeCSSOptions): string;
852
+ //#endregion
853
+ //#region ../../platform/theme-engine/src/serialisation.d.ts
967
854
  /**
968
- * Background field combines resource selection and color properties.
969
- * Uses StrictOmit to exclude conflicting "type" discriminant from parents.
855
+ * Serialise a ThemeDefinition (with Color objects) to a plain JSON payload
856
+ * suitable for backend storage.
970
857
  */
971
- interface BackgroundFieldSchema extends StrictOmit<ResourceFieldSchema, "type">, StrictOmit<ColorFieldSchema, "type"> {
972
- type: "background";
973
- }
858
+ declare function serialiseTheme(def: ThemeDefinition): ThemePayload;
974
859
  /**
975
- * Content position field schema for 3x3 grid position picker
860
+ * Deserialise a backend payload into a ThemeDefinition with Color objects.
861
+ * Accepts `Record<string, unknown>` because API data is untyped at the boundary.
862
+ * Falls back to default colors for any missing light-mode entries.
976
863
  */
977
- interface ContentPositionFieldSchema extends PropertyFieldSchema {
978
- type: "contentPosition";
979
- defaultValue?: string;
864
+ declare function deserialiseTheme(payload: Record<string, unknown>): ThemeDefinition;
865
+ //#endregion
866
+ //#region ../../platform/theme-engine/src/transforms.d.ts
867
+ /** Shape of a raw theme from the FluidOS API */
868
+ interface RawApiTheme {
869
+ id: number;
870
+ config?: Record<string, unknown> | null;
871
+ active?: boolean | null;
872
+ name?: string | null;
980
873
  }
981
874
  /**
982
- * Text size select field schema for visual font size selector
875
+ * Build a ThemeDefinition from a single API theme object.
876
+ * Handles both new structured format and legacy flat format.
983
877
  */
984
- interface TextSizeSelectFieldSchema extends PropertyFieldSchema {
985
- type: "textSizeSelect";
986
- defaultValue?: FontSizeOptions;
987
- }
878
+ declare function buildThemeDefinition(theme: RawApiTheme): ThemeDefinition;
988
879
  /**
989
- * CSS unit type for height/width fields
880
+ * Transform raw API themes to ThemeDefinition[].
881
+ * Catches and logs errors per theme (graceful degradation).
990
882
  */
991
- type CssUnit = "px" | "rem" | "vh" | "%";
883
+ declare function transformThemes(themes: RawApiTheme[]): ThemeDefinition[];
992
884
  /**
993
- * CSS unit field schema for numeric values with selectable units (px, rem, vh, %)
885
+ * Get the active theme ID from a list of raw API themes.
886
+ * Falls back to the first theme if none is marked active.
994
887
  */
995
- interface CssUnitFieldSchema extends PropertyFieldSchema {
996
- type: "cssUnit";
997
- minByUnit?: Partial<Record<CssUnit, number>>;
998
- maxByUnit?: Partial<Record<CssUnit, number>>;
999
- stepByUnit?: Partial<Record<CssUnit, number>>;
1000
- allowedUnits?: CssUnit[];
1001
- defaultUnit?: CssUnit;
1002
- }
888
+ declare function getActiveThemeId(themes: RawApiTheme[]): string | undefined;
889
+ //#endregion
890
+ //#region ../../platform/theme-engine/src/theme-applicator.d.ts
1003
891
  /**
1004
- * Font picker field schema for Google Fonts selection
892
+ * Inject or update a `<style>` element in `<head>` for the given theme.
893
+ * The element ID is deterministic (`theme-style-{themeId}`) so repeated calls
894
+ * for the same theme are idempotent — the existing element is updated in place.
895
+ * Also loads Google Fonts referenced by the theme's font families.
896
+ * No-op when `document` is unavailable (SSR).
1005
897
  */
1006
- interface FontPickerFieldSchema extends PropertyFieldSchema {
1007
- type: "fontPicker";
1008
- placeholder?: string;
1009
- }
898
+ declare function applyTheme(theme: ResolvedTheme, options?: GenerateThemeCSSOptions): void;
899
+ /** Remove an injected theme stylesheet and clean up font link ownership. No-op during SSR. */
900
+ declare function removeTheme(themeId: string): void;
901
+ /** Remove all injected theme stylesheets and font links. No-op during SSR. */
902
+ declare function removeAllThemes(): void;
903
+ //#endregion
904
+ //#region ../../platform/theme-engine/src/defaults.d.ts
905
+ declare const DEFAULT_FONT_SIZES: Record<FontSizeKey, string>;
906
+ declare const DEFAULT_FONT_FAMILIES: Record<FontFamilyKey, string>;
907
+ declare const DEFAULT_SPACING = "0.25rem";
908
+ declare const DEFAULT_RADII: Record<RadiusKey, string>;
909
+ declare const DEFAULT_COLORS: {
910
+ readonly background: "#ffffff";
911
+ readonly foreground: "#1a1a1a";
912
+ readonly primary: "#3b82f6";
913
+ readonly secondary: "#6b7280";
914
+ readonly accent: "#10b981";
915
+ readonly muted: "#f3f4f6";
916
+ readonly destructive: "#ef4444";
917
+ readonly mutedForeground: "#6b7280";
918
+ };
919
+ declare const DEFAULT_THEME_ID = "default";
920
+ declare const DEFAULT_THEME_NAME = "Default Theme";
1010
921
  /**
1011
- * String array field schema for managing lists of text items
922
+ * Build a fresh ThemeDefinition populated with all defaults.
923
+ * Returns a new object each call because Color instances are mutable — do not cache the result.
1012
924
  */
1013
- interface StringArrayFieldSchema extends PropertyFieldSchema {
1014
- type: "stringArray";
1015
- placeholder?: string;
1016
- defaultValue?: string[];
1017
- }
925
+ declare function getDefaultThemeDefinition(): ThemeDefinition;
926
+ //#endregion
927
+ //#region ../core/src/types/navigation.d.ts
1018
928
  /**
1019
- * Border radius composite field schema for controlling 4 corners with a single field.
1020
- * Maps to 4 individual widget prop keys (topLeft, topRight, bottomLeft, bottomRight).
929
+ * Navigation item in the sidebar/menu structure.
930
+ *
931
+ * Field types match the FluidOS API schema (`FluidOSNavigationItem`).
932
+ * Differences from the raw API type:
933
+ * - `id` is optional (system/default items may not have one)
934
+ * - `label` is required (transforms default null to "Untitled")
935
+ * - `section` is a frontend-only extension (not in API)
936
+ * - Nullable fields use `undefined` instead of `null` (except `parent_id`)
1021
937
  */
1022
- interface BorderRadiusFieldSchema extends PropertyFieldSchema {
1023
- type: "borderRadius";
1024
- keys: {
1025
- topLeft: string;
1026
- topRight: string;
1027
- bottomLeft: string;
1028
- bottomRight: string;
1029
- };
1030
- defaultValue?: BorderRadiusOptions;
938
+ interface NavigationItem {
939
+ /** Database-generated identifier — optional because system/default items may not have one */
940
+ readonly id?: number;
941
+ /** URL slug for routing (`| undefined` for exactOptionalPropertyTypes compat) */
942
+ slug?: string | undefined;
943
+ /** Display label — required; transforms default null API values to "Untitled" */
944
+ label: string;
945
+ /** Icon identifier (e.g., FontAwesome name) */
946
+ icon?: string | undefined;
947
+ /** Section grouping for quick links (frontend-only, not in API) */
948
+ section?: string;
949
+ /** Associated screen ID */
950
+ screen_id?: number | undefined;
951
+ /** Sort order */
952
+ position?: number | undefined;
953
+ /** Parent navigation item ID (null for root items) */
954
+ parent_id?: number | null;
955
+ /** Origin of this navigation item */
956
+ source?: "user" | "system" | "code";
957
+ /** Nested navigation items */
958
+ children: NavigationItem[];
1031
959
  }
1032
960
  /**
1033
- * Screen picker field schema for selecting a portal screen (navigation, system, or available)
961
+ * Screen definition with its component tree
1034
962
  */
1035
- interface ScreenPickerFieldSchema extends PropertyFieldSchema {
1036
- type: "screenPicker";
1037
- /** Whether to include system navigation items in the picker */
1038
- includeSystemItems?: boolean;
963
+ interface ScreenDefinition {
964
+ readonly id: number;
965
+ slug: string;
966
+ name: string;
967
+ component_tree: WidgetSchema[];
1039
968
  }
1040
969
  /**
1041
- * Union of all field schema types
970
+ * Navigation configuration for the portal
1042
971
  */
1043
- type PropertyField = TextFieldSchema | TextareaFieldSchema | NumberFieldSchema | BooleanFieldSchema | SelectFieldSchema<string | number> | ColorFieldSchema | RangeFieldSchema | DataSourceFieldSchema | ResourceFieldSchema | ImageFieldSchema | AlignmentFieldSchema | SliderFieldSchema | ColorPickerFieldSchema | SectionHeaderFieldSchema | SeparatorFieldSchema | ButtonGroupFieldSchema<string | number> | ColorSelectFieldSchema | SectionLayoutSelectFieldSchema | BackgroundFieldSchema | ContentPositionFieldSchema | TextSizeSelectFieldSchema | CssUnitFieldSchema | FontPickerFieldSchema | StringArrayFieldSchema | BorderRadiusFieldSchema | ScreenPickerFieldSchema;
972
+ interface Navigation {
973
+ readonly definition_id: number;
974
+ readonly id: number;
975
+ name: string;
976
+ navigation_items: NavigationItem[];
977
+ screens: ScreenDefinition[];
978
+ }
979
+ /** A portal app profile — themes, navigation, and definition reference. */
980
+ interface RepAppProfile {
981
+ name: string;
982
+ themes: ThemeDefinition[];
983
+ activeThemeId?: string;
984
+ navigation: Navigation;
985
+ mobile_navigation?: Navigation;
986
+ definition_id: number;
987
+ }
988
+ /** Full portal app data returned by the fluidos API or builder preview. */
989
+ interface RepAppData {
990
+ definition_id: number;
991
+ published_version: number;
992
+ screens: ScreenDefinition[];
993
+ profile: RepAppProfile;
994
+ }
995
+ /** Wrapper for the `/fluid_os/definitions/active` API response. */
996
+ interface RepAppManifest {
997
+ manifest: RepAppData;
998
+ }
999
+ //#endregion
1000
+ //#region ../core/src/types/shareable-item.d.ts
1044
1001
  /**
1045
- * Schema for per-item configuration in custom data sources.
1046
- * Widgets can define this to allow users to configure widget-specific
1047
- * settings for each selected item (e.g., title, description, button).
1002
+ * Base props for a shareable item.
1003
+ * Uses structural typing to be compatible with various modal implementations.
1004
+ * The index signature allows additional properties from consuming apps.
1048
1005
  */
1049
- interface ItemConfigSchema {
1050
- /** Fields available for per-item configuration */
1051
- fields: PropertyField[];
1052
- /** Optional description shown at top of item config panel */
1053
- description?: string;
1006
+ interface ShareableItem {
1007
+ id: string | number;
1008
+ title?: string | null;
1009
+ image_url?: string | null;
1010
+ imageUrl?: string | null;
1011
+ kind?: string | null;
1012
+ type?: string | null;
1013
+ shareableType?: string | null;
1014
+ share_link?: string | null;
1015
+ videoUrl?: string;
1016
+ price?: string | number | null;
1017
+ display_price?: string | null;
1018
+ [key: string]: unknown;
1054
1019
  }
1020
+ //#endregion
1021
+ //#region ../core/src/types/field-types.d.ts
1055
1022
  /**
1056
- * Schema for a widget's editable properties
1023
+ * Color options constant - single source of truth for color values.
1024
+ * Use COLOR_OPTIONS.primary instead of "primary" for type-safe comparisons.
1057
1025
  */
1058
- interface WidgetPropertySchema {
1059
- /** Widget type this schema applies to */
1060
- widgetType: WidgetType;
1061
- /** Display name for the widget */
1062
- displayName: string;
1063
- /** Optional tab configuration - if present, tabs are enabled */
1064
- tabsConfig?: TabConfig[];
1065
- /** Editable property fields */
1066
- fields: PropertyField[];
1067
- /** Optional custom validator function */
1068
- validate?: (props: Record<string, unknown>) => string | null;
1069
- /** Props that can be populated from data sources */
1070
- dataSourceTargetProps?: string[];
1071
- /** Optional schema for per-item configurations in custom data sources */
1072
- itemConfigSchema?: ItemConfigSchema;
1073
- }
1026
+ declare const COLOR_OPTIONS: {
1027
+ readonly background: "background";
1028
+ readonly foreground: "foreground";
1029
+ readonly primary: "primary";
1030
+ readonly secondary: "secondary";
1031
+ readonly accent: "accent";
1032
+ readonly muted: "muted";
1033
+ readonly border: "border";
1034
+ readonly destructive: "destructive";
1035
+ readonly transparent: "transparent";
1036
+ };
1074
1037
  /**
1075
- * Group property fields by their group property.
1076
- *
1077
- * Fields flagged with `advanced: true` are collected into the
1078
- * `CUSTOM_STYLING_GROUP` bucket regardless of their declared `group`,
1079
- * and that bucket is always placed last so it renders at the bottom of
1080
- * the tab. Non-advanced fields keep their author-declared group and
1081
- * their relative insertion order, including fields that explicitly use
1082
- * `CUSTOM_STYLING_GROUP`.
1038
+ * Union type of all color options, derived from COLOR_OPTIONS constant.
1039
+ * @see deriving-typeof-for-object-keys pattern
1083
1040
  */
1084
- declare function groupPropertyFields(fields: readonly PropertyField[]): Record<string, PropertyField[]>;
1041
+ type ColorOptions = (typeof COLOR_OPTIONS)[keyof typeof COLOR_OPTIONS];
1042
+ declare const FONT_SIZE_OPTIONS: {
1043
+ readonly "2xl": "2xl";
1044
+ readonly xl: "xl";
1045
+ readonly lg: "lg";
1046
+ readonly md: "md";
1047
+ readonly sm: "sm";
1048
+ readonly xs: "xs";
1049
+ };
1050
+ type FontSizeOptions = (typeof FONT_SIZE_OPTIONS)[keyof typeof FONT_SIZE_OPTIONS];
1051
+ declare const FONT_WEIGHT_OPTIONS: {
1052
+ readonly normal: "normal";
1053
+ readonly medium: "medium";
1054
+ readonly semibold: "semibold";
1055
+ readonly bold: "bold";
1056
+ };
1057
+ type FontWeightOptions = (typeof FONT_WEIGHT_OPTIONS)[keyof typeof FONT_WEIGHT_OPTIONS];
1058
+ declare const BORDER_RADIUS_OPTIONS: {
1059
+ readonly none: "none";
1060
+ readonly sm: "sm";
1061
+ readonly md: "md";
1062
+ readonly lg: "lg";
1063
+ readonly xl: "xl";
1064
+ readonly full: "full";
1065
+ };
1066
+ type BorderRadiusOptions = (typeof BORDER_RADIUS_OPTIONS)[keyof typeof BORDER_RADIUS_OPTIONS];
1067
+ declare const BORDER_WIDTH_OPTIONS: {
1068
+ readonly none: "none";
1069
+ readonly thin: "thin";
1070
+ readonly medium: "medium";
1071
+ readonly thick: "thick";
1072
+ };
1073
+ type BorderWidthOptions = (typeof BORDER_WIDTH_OPTIONS)[keyof typeof BORDER_WIDTH_OPTIONS];
1074
+ /** Padding values - numeric, so we use a tuple for derivation */
1075
+ declare const PADDING_VALUES: readonly [0, 2, 4, 6, 8, 10];
1076
+ type PaddingOptions = (typeof PADDING_VALUES)[number];
1077
+ declare const BUTTON_SIZE_OPTIONS: {
1078
+ readonly sm: "sm";
1079
+ readonly default: "default";
1080
+ readonly lg: "lg";
1081
+ readonly xl: "xl";
1082
+ };
1083
+ type ButtonSizeOptions = (typeof BUTTON_SIZE_OPTIONS)[keyof typeof BUTTON_SIZE_OPTIONS];
1084
+ declare const GAP_OPTIONS: {
1085
+ readonly none: "none";
1086
+ readonly xs: "xs";
1087
+ readonly sm: "sm";
1088
+ readonly md: "md";
1089
+ readonly lg: "lg";
1090
+ readonly xl: "xl";
1091
+ };
1092
+ type GapOptions = (typeof GAP_OPTIONS)[keyof typeof GAP_OPTIONS];
1093
+ declare const VERTICAL_ALIGN_OPTIONS: {
1094
+ readonly top: "top";
1095
+ readonly center: "center";
1096
+ readonly bottom: "bottom";
1097
+ };
1098
+ type VerticalAlign = (typeof VERTICAL_ALIGN_OPTIONS)[keyof typeof VERTICAL_ALIGN_OPTIONS];
1099
+ declare const HORIZONTAL_ALIGN_OPTIONS: {
1100
+ readonly left: "left";
1101
+ readonly center: "center";
1102
+ readonly right: "right";
1103
+ };
1104
+ type HorizontalAlign = (typeof HORIZONTAL_ALIGN_OPTIONS)[keyof typeof HORIZONTAL_ALIGN_OPTIONS];
1105
+ type AlignOptions = {
1106
+ vertical?: VerticalAlign;
1107
+ horizontal?: HorizontalAlign;
1108
+ };
1109
+ declare const BACKGROUND_TYPES: {
1110
+ readonly solid: "solid";
1111
+ readonly image: "image";
1112
+ };
1113
+ type BackgroundType = (typeof BACKGROUND_TYPES)[keyof typeof BACKGROUND_TYPES];
1114
+ interface BackgroundValue {
1115
+ type: BackgroundType;
1116
+ color?: ColorOptions;
1117
+ resource?: ShareableItem;
1118
+ }
1085
1119
  /**
1086
- * Extract current values from widget props based on property fields
1120
+ * Section layout configuration - single source of truth for layout types.
1121
+ * SectionLayoutType is derived from these keys to prevent drift.
1087
1122
  */
1088
- declare function extractPropertyValues(widget: Readonly<WidgetSchema>, fields: readonly PropertyField[]): Record<string, unknown>;
1123
+ declare const SECTION_LAYOUT_CONFIG: {
1124
+ readonly "single-column": {
1125
+ readonly columns: 1;
1126
+ readonly widths: readonly ["1fr"];
1127
+ readonly gridClasses: "";
1128
+ };
1129
+ readonly "2c-equal": {
1130
+ readonly columns: 2;
1131
+ readonly widths: readonly ["1fr", "1fr"];
1132
+ readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]";
1133
+ };
1134
+ readonly "2c-left-wider": {
1135
+ readonly columns: 2;
1136
+ readonly widths: readonly ["2fr", "1fr"];
1137
+ readonly gridClasses: "@md:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]";
1138
+ };
1139
+ readonly "2c-right-wider": {
1140
+ readonly columns: 2;
1141
+ readonly widths: readonly ["1fr", "2fr"];
1142
+ readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]";
1143
+ };
1144
+ readonly "2c-left-narrow": {
1145
+ readonly columns: 2;
1146
+ readonly widths: readonly ["1fr", "3fr"];
1147
+ readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,3fr)]";
1148
+ };
1149
+ readonly "2c-right-narrow": {
1150
+ readonly columns: 2;
1151
+ readonly widths: readonly ["3fr", "1fr"];
1152
+ readonly gridClasses: "@md:grid-cols-[minmax(0,3fr)_minmax(0,1fr)]";
1153
+ };
1154
+ readonly "3c-equal": {
1155
+ readonly columns: 3;
1156
+ readonly widths: readonly ["1fr", "1fr", "1fr"];
1157
+ readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_minmax(0,1fr)]";
1158
+ };
1159
+ readonly "3c-middle-wider": {
1160
+ readonly columns: 3;
1161
+ readonly widths: readonly ["1fr", "2fr", "1fr"];
1162
+ readonly gridClasses: "@md:grid-cols-[minmax(0,1fr)_minmax(0,2fr)_minmax(0,1fr)]";
1163
+ };
1164
+ };
1089
1165
  /**
1090
- * Apply property values to widget props
1166
+ * Union type of all section layout types, derived from SECTION_LAYOUT_CONFIG keys.
1167
+ * @see deriving-typeof-for-object-keys pattern
1091
1168
  */
1092
- declare function applyPropertyValues(widget: Readonly<WidgetSchema>, values: Readonly<Record<string, unknown>>): WidgetSchema;
1169
+ type SectionLayoutType = keyof typeof SECTION_LAYOUT_CONFIG;
1170
+ /** @deprecated Use SECTION_LAYOUT_CONFIG instead */
1171
+ declare const sectionLayoutConfig: typeof SECTION_LAYOUT_CONFIG;
1093
1172
  //#endregion
1094
- //#region ../core/src/registries/field-helpers.d.ts
1095
- /**
1096
- * Gap value mapping - use `as const satisfies` for compile-time validation
1097
- * with literal type preservation.
1098
- */
1099
- declare const gapValues: {
1100
- readonly none: 0;
1101
- readonly xs: 1;
1102
- readonly sm: 2;
1103
- readonly md: 4;
1104
- readonly lg: 6;
1105
- readonly xl: 8;
1106
- };
1173
+ //#region ../core/src/types/index.d.ts
1174
+ type StrictOmit<T, K extends keyof T> = Omit<T, K>;
1107
1175
  //#endregion
1108
- //#region ../core/src/registries/container-types.d.ts
1109
- /**
1110
- * Interface for container widget behavior.
1111
- * Container widgets can hold and manage child widgets.
1112
- * Note: Children can be null for sparse arrays (e.g., grid layouts with empty cells)
1113
- */
1114
- interface ContainerWidgetBehavior {
1115
- /** Identifies this widget type as a container */
1116
- isContainer: true;
1117
- /** Gets children from the widget's props */
1118
- getChildren: (props: Record<string, unknown>) => (WidgetSchema | null)[];
1119
- /** Creates new props with updated children */
1120
- setChildren: (props: Record<string, unknown>, children: (WidgetSchema | null)[]) => Record<string, unknown>;
1121
- /** Optional: Check if this container accepts a specific widget type */
1122
- canAcceptChild?: (childType: string) => boolean;
1176
+ //#region src/widgets/remote/contract/portal-function.d.ts
1177
+ type PortalFunctionJsonValue = RemoteDomSerializableValue;
1178
+ type PortalFunctionJsonPrimitive = null | boolean | number | string;
1179
+ type IsAny<Value> = 0 extends 1 & Value ? true : false;
1180
+ type IsPortalFunctionJsonBranch<Value, Seen> = Value extends PortalFunctionJsonPrimitive ? true : Value extends readonly (infer Item)[] ? IsPortalFunctionJsonValue<Item, Seen> : Value extends ((...args: never[]) => unknown) ? false : Value extends object ? Extract<keyof Value, symbol> extends never ? false extends { [Key in keyof Value]-?: IsPortalFunctionJsonValue<Required<Value>[Key], Seen | Value> }[keyof Value] ? false : true : false : false;
1181
+ type IsPortalFunctionJsonValue<Value, Seen = never> = IsAny<Value> extends true ? false : [Value] extends [never] ? false : [Value] extends [Seen] ? true : false extends (Value extends unknown ? IsPortalFunctionJsonBranch<Value, Seen> : never) ? false : true;
1182
+ type IsExactlyVoid<Value> = [Value] extends [void] ? [void] extends [Value] ? true : false : false;
1183
+ type PortalFunctionContractErrors<Output, Input> = IsPortalFunctionJsonValue<Output> extends true ? IsExactlyVoid<Input> extends true ? [] : IsPortalFunctionJsonValue<Input> extends true ? [] : [error: "Portal function input must contain only JSON values"] : [error: "Portal function output must contain only JSON values"];
1184
+ type PortalFunctionErrorCode = "NOT_MOUNTED" | "NOT_DECLARED" | "INVALID_ARGUMENT" | "UNAVAILABLE" | "UNSUPPORTED" | "HOST_FAILURE" | "INVALID_RESPONSE";
1185
+ /** A stable, serializable failure reported by a Portal function call. */
1186
+ declare class PortalFunctionError extends Error {
1187
+ readonly code: PortalFunctionErrorCode;
1188
+ constructor(code: PortalFunctionErrorCode, message: string);
1123
1189
  }
1124
- //#endregion
1125
- //#region ../core/src/registries/widget-manifest.d.ts
1126
- /**
1127
- * The manifest a plugin author provides to register a custom widget.
1128
- * Required fields ensure the widget works in both builder and SDK contexts.
1129
- * Optional fields enable advanced behavior (containers, min SDK version).
1130
- */
1131
- interface WidgetManifest {
1132
- /** Schema version for forward compatibility. Currently must be 1. */
1133
- manifestVersion: number;
1134
- /** Unique widget type identifier (e.g., "StockTickerWidget"). */
1135
- type: string;
1136
- /** The React component that renders this widget. */
1137
- component: AnyComponent;
1138
- /** Human-readable name shown in the builder palette. */
1139
- displayName: string;
1140
- /** Brief description shown in the builder palette. */
1141
- description: string;
1142
- /** Icon identifier for the builder palette (e.g., "chart-line"). */
1143
- icon: string;
1144
- /** Category ID for palette grouping (e.g., "components", "blocks", "utility"). */
1145
- category: string;
1146
- /** Property schema defining editable fields in the builder's property panel. */
1147
- propertySchema: WidgetPropertySchema;
1148
- /** Default prop values when the widget is first created. */
1149
- defaultProps: Record<string, unknown>;
1150
- /** Container behavior — only if this widget can hold child widgets. */
1151
- container?: ContainerWidgetBehavior;
1152
- /** Minimum SDK version required (e.g., "1.0.0"). */
1153
- minSdkVersion?: string;
1154
- /** Resizable configuration. */
1155
- resizable?: {
1156
- horizontal?: boolean;
1157
- vertical?: boolean;
1158
- minWidth?: number;
1159
- minHeight?: number;
1160
- };
1161
- /** Exact grant the host must approve before this remote widget is added. */
1162
- networkAccessGrant?: RemoteWidgetNetworkAccessGrant;
1190
+ interface PortalFunctionDefinition {
1191
+ readonly capability: string;
1192
+ readonly version: string;
1193
+ readonly method: string;
1163
1194
  }
1164
- //#endregion
1165
- //#region src/utils/build-remote-widget-plugin-manifests.d.ts
1166
- interface RemoteWidgetPluginHostOptions extends RemoteDomWidgetRegistryOptions {
1167
- readonly warningSink?: WidgetRegistryWarningSink;
1195
+ type PortalFunction<Output, Input = void> = [Input] extends [void] ? () => Promise<Output> : (input: Input) => Promise<Output>;
1196
+ type AnyPortalFunction = (...args: never[]) => Promise<unknown>;
1197
+ type PortalFunctionHandler<Output, Input = void> = [Input] extends [void] ? () => Output | Promise<Output> : (input: Input) => Output | Promise<Output>;
1198
+ interface PortalFunctionImplementation {
1199
+ readonly definition: PortalFunctionDefinition;
1200
+ readonly portalFunction: AnyPortalFunction;
1201
+ readonly handler: (...args: never[]) => unknown | Promise<unknown>;
1168
1202
  }
1169
- /**
1170
- * Projects accepted canonical packages into builder manifests using the same
1171
- * package-atomic acceptance pass as the runtime registry.
1172
- */
1173
- declare function buildRemoteWidgetPluginManifests(packages: readonly RemoteDomWidgetPackageDescriptor[], hostOptions?: RemoteWidgetPluginHostOptions): WidgetManifest[];
1174
- declare function getRemoteWidgetPackageCategoryId(remotePackage: Pick<RemoteDomWidgetPackageDescriptor, "packageId" | "source">): string;
1203
+ declare function definePortalFunction<Output, Input = void>(definition: PortalFunctionDefinition, ..._contractErrors: PortalFunctionContractErrors<Output, Input>): PortalFunction<Output, Input>;
1204
+ declare function implementPortalFunction<Output, Input = void>(portalFunction: PortalFunction<Output, Input>, handler: PortalFunctionHandler<NoInfer<Output>, NoInfer<Input>>): PortalFunctionImplementation;
1175
1205
  //#endregion
1176
- export { deriveDarkVariant as $, RepAppData as A, isWidgetType as At, DEFAULT_THEME_NAME as B, FontWeightOptions as C, WidgetPath as Ct, sectionLayoutConfig as D, WidgetTypeName as Dt, SectionLayoutType as E, WidgetType as Et, DEFAULT_FONT_FAMILIES as F, RawApiTheme as G, applyTheme as H, DEFAULT_FONT_SIZES as I, transformThemes as J, buildThemeDefinition as K, DEFAULT_RADII as L, RepAppProfile as M, ScreenDefinition as N, ShareableItem as O, assertDefined as Ot, DEFAULT_COLORS as P, generateThemeCSS as Q, DEFAULT_SPACING as R, FontSizeOptions as S, WIDGET_TYPE_NAMES as St, PaddingOptions as T, WidgetSchema as Tt, removeAllThemes as U, getDefaultThemeDefinition as V, removeTheme as W, serialiseTheme as X, deserialiseTheme as Y, GenerateThemeCSSOptions as Z, BackgroundValue as _, ThemeColorPlain as _t, gapValues as a, FONT_SIZE_KEYS as at, ButtonSizeOptions as b, AnyComponent as bt, PropertyFieldType as c, OklchPlain as ct, applyPropertyValues as d, ResolvedColorSet as dt, getForegroundColor as et, extractPropertyValues as f, ResolvedSemanticColor as ft, BackgroundType as g, ThemeColorInput as gt, AlignOptions as h, SemanticColorName as ht, WidgetManifest as i, FONT_FAMILY_KEYS as it, RepAppManifest as j, isWidgetTypeName as jt, NavigationItem as k, assertNever as kt, TabConfig as l, RADIUS_KEYS as lt, isPropertyFieldType as m, SEMANTIC_COLOR_NAMES as mt, buildRemoteWidgetPluginManifests as n, parseColor as nt, PROPERTY_FIELD_TYPES as o, FontFamilyKey as ot, groupPropertyFields as p, ResolvedTheme as pt, getActiveThemeId as q, getRemoteWidgetPackageCategoryId as r, resolveTheme as rt, PropertyFieldSchema as s, FontSizeKey as st, RemoteWidgetPluginHostOptions as t, mergeDarkOverrides as tt, WidgetPropertySchema as u, RadiusKey as ut, BorderRadiusOptions as v, ThemeDefinition as vt, GapOptions as w, WidgetRegistry as wt, ColorOptions as x, TypedWidgetSchema as xt, BorderWidthOptions as y, ThemePayload as yt, DEFAULT_THEME_ID as z };
1177
- //# sourceMappingURL=build-remote-widget-plugin-manifests-BsgLYqar.d.mts.map
1206
+ export { resolveTheme as $, DEFAULT_COLORS as A, RemoteDomWidgetDefinition as At, removeTheme as B, extractPropertyValues as Bt, sectionLayoutConfig as C, WidgetTypeName as Ct, RepAppManifest as D, isWidgetTypeName as Dt, RepAppData as E, isWidgetType as Et, DEFAULT_THEME_ID as F, PropertyFieldSchema as Ft, deserialiseTheme as G, buildThemeDefinition as H, isPropertyFieldType as Ht, DEFAULT_THEME_NAME as I, PropertyFieldType as It, generateThemeCSS as J, serialiseTheme as K, getDefaultThemeDefinition as L, TabConfig as Lt, DEFAULT_FONT_SIZES as M, WidgetSourcePropertyField as Mt, DEFAULT_RADII as N, WidgetSourcePropertySchema as Nt, RepAppProfile as O, RemoteWidgetNetworkAccessGrant as Ot, DEFAULT_SPACING as P, PROPERTY_FIELD_TYPES as Pt, parseColor as Q, applyTheme as R, WidgetPropertySchema as Rt, SectionLayoutType as S, WidgetType as St, NavigationItem as T, assertNever as Tt, getActiveThemeId as U, RawApiTheme as V, groupPropertyFields as Vt, transformThemes as W, getForegroundColor as X, deriveDarkVariant as Y, mergeDarkOverrides as Z, ColorOptions as _, TypedWidgetSchema as _t, PortalFunctionErrorCode as a, RADIUS_KEYS as at, GapOptions as b, WidgetRegistry as bt, PortalFunctionJsonValue as c, ResolvedSemanticColor as ct, AlignOptions as d, SemanticColorName as dt, FONT_FAMILY_KEYS as et, BackgroundType as f, ThemeColorInput as ft, ButtonSizeOptions as g, AnyComponent as gt, BorderWidthOptions as h, ThemePayload as ht, PortalFunctionError as i, OklchPlain as it, DEFAULT_FONT_FAMILIES as j, RemoteDomWidgetPackageDescriptor as jt, ScreenDefinition as k, JsonValue as kt, definePortalFunction as l, ResolvedTheme as lt, BorderRadiusOptions as m, ThemeDefinition as mt, PortalFunction as n, FontFamilyKey as nt, PortalFunctionHandler as o, RadiusKey as ot, BackgroundValue as p, ThemeColorPlain as pt, GenerateThemeCSSOptions as q, PortalFunctionDefinition as r, FontSizeKey as rt, PortalFunctionImplementation as s, ResolvedColorSet as st, AnyPortalFunction as t, FONT_SIZE_KEYS as tt, implementPortalFunction as u, SEMANTIC_COLOR_NAMES as ut, FontSizeOptions as v, WIDGET_TYPE_NAMES as vt, ShareableItem as w, assertDefined as wt, PaddingOptions as x, WidgetSchema as xt, FontWeightOptions as y, WidgetPath as yt, removeAllThemes as z, applyPropertyValues as zt };
1207
+ //# sourceMappingURL=portal-function-DgqXwF13.d.mts.map