@exponential-at/ui 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +54 -0
  3. package/README.md +360 -2
  4. package/catalog/a11y.json +668 -0
  5. package/catalog/basic-map.json +104 -0
  6. package/catalog/code.json +58 -0
  7. package/catalog/core.catalog.json +4752 -0
  8. package/catalog/core.schema.json +22667 -0
  9. package/catalog/host.json +64 -0
  10. package/catalog/layout.json +20 -0
  11. package/catalog/limits.json +9 -0
  12. package/catalog/locale.json +48 -0
  13. package/catalog/macros.json +3417 -0
  14. package/catalog/recipes.json +61 -0
  15. package/catalog/strings.json +72 -0
  16. package/catalog/style.json +128 -0
  17. package/catalog/theme.schema.json +42543 -0
  18. package/catalog/tokens.json +47 -0
  19. package/conformance/README.md +217 -0
  20. package/conformance/baseline.ts +101 -0
  21. package/conformance/browser-page.ts +146 -0
  22. package/conformance/browser-suites.ts +683 -0
  23. package/conformance/compare.ts +201 -0
  24. package/conformance/dom.ts +96 -0
  25. package/conformance/dump.ts +163 -0
  26. package/conformance/fonts.json +154 -0
  27. package/conformance/manifest.json +224 -0
  28. package/conformance/parity-compare.ts +191 -0
  29. package/conformance/parity-report.schema.json +73 -0
  30. package/conformance/parity.ts +412 -0
  31. package/conformance/pixel.ts +177 -0
  32. package/conformance/primitives-page.ts +49 -0
  33. package/conformance/report.schema.json +66 -0
  34. package/conformance/run.ts +118 -0
  35. package/dist/chunks/index-98npjvsd.js +3940 -0
  36. package/dist/chunks/index-98npjvsd.js.map +27 -0
  37. package/dist/chunks/index-gwkt14w3.js +7314 -0
  38. package/dist/chunks/index-gwkt14w3.js.map +10 -0
  39. package/dist/chunks/index-njt7yzzm.js +134 -0
  40. package/dist/chunks/index-njt7yzzm.js.map +9 -0
  41. package/dist/chunks/index-we7va6v6.js +7984 -0
  42. package/dist/chunks/index-we7va6v6.js.map +15 -0
  43. package/dist/chunks/index-xrm6f7wc.js +2563 -0
  44. package/dist/chunks/index-xrm6f7wc.js.map +10 -0
  45. package/dist/conformance.js +182749 -0
  46. package/dist/conformance.js.map +10 -0
  47. package/dist/entries/prompt.js +251 -0
  48. package/dist/entries/prompt.js.map +11 -0
  49. package/dist/entries/schema.js +1725 -0
  50. package/dist/entries/schema.js.map +11 -0
  51. package/dist/host/index.js +122 -0
  52. package/dist/host/index.js.map +9 -0
  53. package/dist/index.js +3213 -0
  54. package/dist/index.js.map +27 -0
  55. package/dist/types/src/a11y.d.ts +21 -0
  56. package/dist/types/src/animation.d.ts +76 -0
  57. package/dist/types/src/basic-map.d.ts +38 -0
  58. package/dist/types/src/builder.d.ts +50 -0
  59. package/dist/types/src/catalog.d.ts +54 -0
  60. package/dist/types/src/catalog.described.d.ts +33 -0
  61. package/dist/types/src/catalog.generated.d.ts +829 -0
  62. package/dist/types/src/chart.d.ts +46 -0
  63. package/dist/types/src/code.d.ts +44 -0
  64. package/dist/types/src/color.d.ts +20 -0
  65. package/dist/types/src/conformance.d.ts +39 -0
  66. package/dist/types/src/connector/app.d.ts +14 -0
  67. package/dist/types/src/connector/connector.d.ts +77 -0
  68. package/dist/types/src/connector/index.d.ts +4 -0
  69. package/dist/types/src/css.d.ts +29 -0
  70. package/dist/types/src/define.d.ts +66 -0
  71. package/dist/types/src/direction.d.ts +16 -0
  72. package/dist/types/src/dynamic.d.ts +159 -0
  73. package/dist/types/src/entries/prompt.d.ts +11 -0
  74. package/dist/types/src/entries/schema.d.ts +8 -0
  75. package/dist/types/src/expr.d.ts +71 -0
  76. package/dist/types/src/extension.d.ts +4 -0
  77. package/dist/types/src/format.d.ts +112 -0
  78. package/dist/types/src/geometry.d.ts +40 -0
  79. package/dist/types/src/host/contract.d.ts +188 -0
  80. package/dist/types/src/host/decoders.d.ts +61 -0
  81. package/dist/types/src/host/index.d.ts +11 -0
  82. package/dist/types/src/host/package.d.ts +58 -0
  83. package/dist/types/src/host/policy.d.ts +105 -0
  84. package/dist/types/src/host/router.d.ts +34 -0
  85. package/dist/types/src/host/runtime.d.ts +205 -0
  86. package/dist/types/src/host/sources.d.ts +15 -0
  87. package/dist/types/src/host/transports.d.ts +109 -0
  88. package/dist/types/src/index.d.ts +63 -0
  89. package/dist/types/src/layout.d.ts +20 -0
  90. package/dist/types/src/limits.d.ts +21 -0
  91. package/dist/types/src/list.d.ts +133 -0
  92. package/dist/types/src/locale.d.ts +22 -0
  93. package/dist/types/src/macros.d.ts +29 -0
  94. package/dist/types/src/overlay.d.ts +27 -0
  95. package/dist/types/src/prompt.d.ts +44 -0
  96. package/dist/types/src/recipes.d.ts +17 -0
  97. package/dist/types/src/reducer.d.ts +41 -0
  98. package/dist/types/src/resizable.d.ts +38 -0
  99. package/dist/types/src/schema.d.ts +7 -0
  100. package/dist/types/src/strings.d.ts +13 -0
  101. package/dist/types/src/style.d.ts +201 -0
  102. package/dist/types/src/test-preload.d.ts +1 -0
  103. package/dist/types/src/text-shimmer.d.ts +24 -0
  104. package/dist/types/src/theme-types.d.ts +162 -0
  105. package/dist/types/src/theme.d.ts +73 -0
  106. package/dist/types/src/themes.d.ts +22 -0
  107. package/dist/types/src/tree-guides.d.ts +17 -0
  108. package/dist/types/src/types.d.ts +314 -0
  109. package/dist/types/src/validate.d.ts +31 -0
  110. package/dist/types/src/web/base-css.d.ts +1 -0
  111. package/dist/types/src/web/box-css.d.ts +55 -0
  112. package/dist/types/src/web/coerce.d.ts +32 -0
  113. package/dist/types/src/web/data.d.ts +105 -0
  114. package/dist/types/src/web/dates.d.ts +12 -0
  115. package/dist/types/src/web/form.d.ts +44 -0
  116. package/dist/types/src/web/host-types.d.ts +119 -0
  117. package/dist/types/src/web/index.d.ts +28 -0
  118. package/dist/types/src/web/inputs.d.ts +55 -0
  119. package/dist/types/src/web/list.d.ts +13 -0
  120. package/dist/types/src/web/listbox.d.ts +14 -0
  121. package/dist/types/src/web/markdown.d.ts +96 -0
  122. package/dist/types/src/web/media.d.ts +62 -0
  123. package/dist/types/src/web/parts.d.ts +4 -0
  124. package/dist/types/src/web/primitives/alert-dialog.d.ts +10 -0
  125. package/dist/types/src/web/primitives/alert.d.ts +9 -0
  126. package/dist/types/src/web/primitives/avatar-color.d.ts +2 -0
  127. package/dist/types/src/web/primitives/avatar.d.ts +13 -0
  128. package/dist/types/src/web/primitives/badge.d.ts +10 -0
  129. package/dist/types/src/web/primitives/breadcrumb.d.ts +10 -0
  130. package/dist/types/src/web/primitives/button.d.ts +6 -0
  131. package/dist/types/src/web/primitives/calendar.d.ts +43 -0
  132. package/dist/types/src/web/primitives/card.d.ts +9 -0
  133. package/dist/types/src/web/primitives/checkbox.d.ts +5 -0
  134. package/dist/types/src/web/primitives/choice-tiles.d.ts +32 -0
  135. package/dist/types/src/web/primitives/cn.d.ts +3 -0
  136. package/dist/types/src/web/primitives/code-block.d.ts +24 -0
  137. package/dist/types/src/web/primitives/command.d.ts +134 -0
  138. package/dist/types/src/web/primitives/context-ring.d.ts +24 -0
  139. package/dist/types/src/web/primitives/dialog-arms.d.ts +6 -0
  140. package/dist/types/src/web/primitives/dialog.d.ts +24 -0
  141. package/dist/types/src/web/primitives/disclosure-header.d.ts +5 -0
  142. package/dist/types/src/web/primitives/dock.d.ts +42 -0
  143. package/dist/types/src/web/primitives/dropdown-menu.d.ts +14 -0
  144. package/dist/types/src/web/primitives/empty-state.d.ts +15 -0
  145. package/dist/types/src/web/primitives/glass-card.d.ts +4 -0
  146. package/dist/types/src/web/primitives/hover-card.d.ts +7 -0
  147. package/dist/types/src/web/primitives/icon-disc.d.ts +12 -0
  148. package/dist/types/src/web/primitives/index.d.ts +48 -0
  149. package/dist/types/src/web/primitives/input.d.ts +5 -0
  150. package/dist/types/src/web/primitives/kbd.d.ts +4 -0
  151. package/dist/types/src/web/primitives/label.d.ts +3 -0
  152. package/dist/types/src/web/primitives/menu-surface.d.ts +17 -0
  153. package/dist/types/src/web/primitives/meter.d.ts +21 -0
  154. package/dist/types/src/web/primitives/popover.d.ts +3 -0
  155. package/dist/types/src/web/primitives/progress-ring.d.ts +5 -0
  156. package/dist/types/src/web/primitives/progress.d.ts +8 -0
  157. package/dist/types/src/web/primitives/scroll-area.d.ts +49 -0
  158. package/dist/types/src/web/primitives/segmented-control.d.ts +5 -0
  159. package/dist/types/src/web/primitives/select.d.ts +47 -0
  160. package/dist/types/src/web/primitives/separator.d.ts +3 -0
  161. package/dist/types/src/web/primitives/sheet-chrome.d.ts +4 -0
  162. package/dist/types/src/web/primitives/sheet.d.ts +20 -0
  163. package/dist/types/src/web/primitives/skeleton.d.ts +3 -0
  164. package/dist/types/src/web/primitives/spinner.d.ts +3 -0
  165. package/dist/types/src/web/primitives/switch.d.ts +4 -0
  166. package/dist/types/src/web/primitives/table.d.ts +11 -0
  167. package/dist/types/src/web/primitives/tabs.d.ts +13 -0
  168. package/dist/types/src/web/primitives/textarea.d.ts +3 -0
  169. package/dist/types/src/web/primitives/toast.d.ts +163 -0
  170. package/dist/types/src/web/primitives/tooltip.d.ts +3 -0
  171. package/dist/types/src/web/primitives/truncate.d.ts +7 -0
  172. package/dist/types/src/web/primitives/typeahead-portal.d.ts +12 -0
  173. package/dist/types/src/web/share.d.ts +6 -0
  174. package/dist/types/src/web/table.d.ts +20 -0
  175. package/dist/types/src/web/theme-css.d.ts +69 -0
  176. package/dist/types/src/web/urls.d.ts +21 -0
  177. package/dist/web/index.js +2303 -0
  178. package/dist/web/index.js.map +26 -0
  179. package/dist/web/primitives/index.js +1450 -0
  180. package/dist/web/primitives/index.js.map +57 -0
  181. package/docs/components.generated.json +6238 -0
  182. package/docs/round-1-contract.md +679 -0
  183. package/docs/round-2-contract.md +476 -0
  184. package/docs/round-3-contract.md +174 -0
  185. package/docs/themes.generated.json +3503 -0
  186. package/fixtures/animations.json +2890 -0
  187. package/fixtures/bench-list.json +58 -0
  188. package/fixtures/bind-time.json +30664 -0
  189. package/fixtures/catalog-basic-map.json +1692 -0
  190. package/fixtures/catalog-components.json +9323 -0
  191. package/fixtures/catalog-extension.json +620 -0
  192. package/fixtures/catalog-macros.json +36370 -0
  193. package/fixtures/code-tokens.json +1993 -0
  194. package/fixtures/conformance-baseline.json +55544 -0
  195. package/fixtures/conformance-cases.json +49 -0
  196. package/fixtures/conformance-known.json +2123 -0
  197. package/fixtures/control-geometry.json +4200 -0
  198. package/fixtures/dashboard.data.json +74 -0
  199. package/fixtures/dashboard.json +752 -0
  200. package/fixtures/demo-surface.json +47 -0
  201. package/fixtures/format.json +870 -0
  202. package/fixtures/host-policy.json +1067 -0
  203. package/fixtures/host-router.json +1152 -0
  204. package/fixtures/host-transport.json +590 -0
  205. package/fixtures/interactions-round1.json +773 -0
  206. package/fixtures/kitchen-sink.expanded.json +10844 -0
  207. package/fixtures/kitchen-sink.json +3049 -0
  208. package/fixtures/layout-geometry-round1.json +7278 -0
  209. package/fixtures/layout-geometry.json +2072 -0
  210. package/fixtures/overlay-geometry.json +272 -0
  211. package/fixtures/primitive-specimens.json +58 -0
  212. package/fixtures/prompt-budget.json +33 -0
  213. package/fixtures/resizable.json +714 -0
  214. package/fixtures/round4-contract.json +2985 -0
  215. package/fixtures/specimens.json +9832 -0
  216. package/fixtures/style-conditions.json +336 -0
  217. package/fixtures/template-items.json +2215 -0
  218. package/fixtures/text-direction.json +309 -0
  219. package/fixtures/text-shimmer.json +96 -0
  220. package/fixtures/theme-extends.json +573 -0
  221. package/fixtures/theme-invalid.json +1296 -0
  222. package/fixtures/theme-recipes.json +58600 -0
  223. package/fixtures/theme-resolved.json +23949 -0
  224. package/fixtures/toast-stack.json +215 -0
  225. package/fixtures/tree-guides.json +224 -0
  226. package/fixtures/virtual-list.json +733 -0
  227. package/generated/ExponentialUICatalog.generated.kt +67 -0
  228. package/generated/ExponentialUICatalog.generated.swift +67 -0
  229. package/generated/ExponentialUIThemes.generated.kt +23 -0
  230. package/generated/ExponentialUIThemes.generated.swift +23 -0
  231. package/generated/catalog.descriptions.generated.rs +6 -0
  232. package/generated/catalog.generated.rs +80 -0
  233. package/generated/catalog.themes.generated.rs +34 -0
  234. package/generated/core.descriptions.json +2505 -0
  235. package/generated/core.runtime.json +3609 -0
  236. package/package.json +87 -4
  237. package/themes/exponential.recipes.json +49 -0
  238. package/themes/exponential.theme.json +755 -0
  239. package/themes/neutral.theme.json +5676 -0
  240. package/themes/orange.theme.json +43 -0
  241. package/themes/playful.theme.json +219 -0
  242. package/vendor/a2ui/LICENSE.txt +203 -0
  243. package/vendor/a2ui/README.md +27 -0
  244. package/vendor/a2ui/v0_9/basic_catalog.json +1387 -0
  245. package/vendor/a2ui/v0_9/basic_catalog_rules.txt +5 -0
  246. package/vendor/a2ui/v0_9/client_capabilities.json +97 -0
  247. package/vendor/a2ui/v0_9/client_to_server.json +104 -0
  248. package/vendor/a2ui/v0_9/common_types.json +315 -0
  249. package/vendor/a2ui/v0_9/server_to_client.json +132 -0
  250. package/vendor/json-render/LICENSE.txt +201 -0
  251. package/vendor/json-render/README.md +13 -0
package/dist/index.js ADDED
@@ -0,0 +1,3213 @@
1
+ import {
2
+ coreCatalog2,
3
+ CORE_CATALOG_ID2,
4
+ CORE_LITE_CATALOG_ID2,
5
+ A2UI_BASIC_CATALOG_ID2,
6
+ A2UI_VERSION2,
7
+ SUPPORTED_CATALOG_IDS2,
8
+ UNKNOWN_COMPONENT2,
9
+ coreMacros2,
10
+ TOKEN_GROUPS2,
11
+ parseTokenRef2,
12
+ isKnownToken2,
13
+ catalogView2,
14
+ sharedCatalogView2,
15
+ componentDef2,
16
+ isOffered2,
17
+ componentNames2,
18
+ coreLite2
19
+ } from "./chunks/index-gwkt14w3.js";
20
+ import {
21
+ STYLE_KEYS2,
22
+ STYLE_LAYOUT_KEYS2,
23
+ STYLE_VISUAL_KEYS2,
24
+ STYLE_LAYOUT_EFFECT_KEYS2,
25
+ STYLE_MEDIA2,
26
+ STYLE_TRANSFORM2,
27
+ STYLE_STATES2,
28
+ styleKeyEnum2,
29
+ styleKeyType2,
30
+ validateStyle2,
31
+ create2,
32
+ props2,
33
+ parseMediaCondition2,
34
+ mediaMatches2,
35
+ resolveConditions2,
36
+ activeBreakpoint2,
37
+ parseColor2,
38
+ toHex2,
39
+ isThemeHex2,
40
+ toThemeHex2,
41
+ luminance2,
42
+ contrast2,
43
+ RECIPE_STATES2,
44
+ RECIPE_KEYS2,
45
+ macroParts2,
46
+ recipeParts2,
47
+ nativeRecipeProps2,
48
+ MODES2,
49
+ DENSITIES2,
50
+ THEME_SCHEMA_ID2,
51
+ ThemeError2,
52
+ validateTheme2,
53
+ tryLoadTheme2,
54
+ loadTheme2,
55
+ resolveMode2,
56
+ applyDensity2,
57
+ applyContrast2,
58
+ resolveToken2,
59
+ resolveConditionKey2,
60
+ resolveStyleValues2,
61
+ recipeStyle2,
62
+ resolveRecipe2,
63
+ nodeRecipeQuery2,
64
+ resolveNodeStyle2,
65
+ shadowCss2,
66
+ easingCss2,
67
+ neutralTheme2,
68
+ exponentialTheme2,
69
+ playfulTheme2,
70
+ orangeTheme2,
71
+ BUILTIN_THEMES2,
72
+ BUILTIN_THEME_IDS2,
73
+ DEFAULT_THEME_ID2,
74
+ builtinTheme2,
75
+ themeOrDefault2,
76
+ builtinThemes2,
77
+ HOST_CONTRACT2,
78
+ HOST_CONTRACT_VERSION2,
79
+ A2UI_MESSAGE_KINDS2,
80
+ EXTENSION_MESSAGE_KINDS2,
81
+ MESSAGE_KINDS2,
82
+ HOST_ERROR_CODES2,
83
+ DEFAULT_URL_SCHEMES2,
84
+ DEFAULT_MEDIA_SCHEMES2,
85
+ MEDIA_LIMITS2,
86
+ PAINT_ERROR_HOOK2,
87
+ RENDER_FAILED2,
88
+ MCP_MIME_TYPES2,
89
+ MCP_ACTION_TOOL2,
90
+ SSE_EVENTS2,
91
+ SURFACE_SETTING_KEYS2,
92
+ FORMATTER_METHODS2,
93
+ SURFACE_COMMANDS2,
94
+ errorMessage2,
95
+ actionMessage2
96
+ } from "./chunks/index-we7va6v6.js";
97
+ import {
98
+ CATALOG_ID2,
99
+ LITE_CATALOG_ID2,
100
+ BASIC_CATALOG_ID2,
101
+ BASIC_VERSION2,
102
+ CATALOG_VERSION2,
103
+ UNKNOWN_COMPONENT_NAME2,
104
+ COMPONENT_NAMES2,
105
+ NATIVE_COMPONENTS2,
106
+ MACRO_COMPONENTS2,
107
+ LITE_COMPONENTS2,
108
+ COMPONENT_GROUPS2,
109
+ SPECIMEN_IDS2,
110
+ ENUMS2,
111
+ TOKEN_NAMES2,
112
+ STYLE_KEY_NAMES2,
113
+ STYLE_STATE_NAMES2,
114
+ ICON_NAMES2,
115
+ FUNCTION_NAMES2,
116
+ BASIC_COMPONENT_MAP2,
117
+ BASIC_ICON_MAP2,
118
+ BASIC_PLACEHOLDER_ICON2,
119
+ DEFAULT_STRINGS2,
120
+ STRING_IDS2,
121
+ parseStringRef2,
122
+ isStringRef2,
123
+ stringTable2,
124
+ formatString2,
125
+ resolveString2,
126
+ locale_default,
127
+ displayString2,
128
+ currencyDigits2,
129
+ parseDateValue2,
130
+ formatPattern2,
131
+ ENGLISH_DATE_PATTERNS2,
132
+ ENGLISH_TIME_PATTERN2,
133
+ ENGLISH_DATE_TIME_JOIN2,
134
+ fixedOffset2,
135
+ intlZoneOffset2,
136
+ relativeTimeUnit2,
137
+ englishFormatter2,
138
+ intlFormatter2,
139
+ FORMAT_FUNCTION_NAMES2,
140
+ formatFunctions2,
141
+ ENGLISH_FORMAT_FUNCTIONS2,
142
+ isBinding2,
143
+ isCall2,
144
+ isDynamic2,
145
+ truthy2,
146
+ valuesEqual2,
147
+ clampNumber2,
148
+ fillTemplate2,
149
+ evalExpr2,
150
+ evalConditionValue2,
151
+ evalCondition2,
152
+ evalValue2,
153
+ percent2,
154
+ filterItems2,
155
+ CORE_FUNCTIONS2,
156
+ CORE_FUNCTION_NAMES2,
157
+ LIMITS2,
158
+ MAX_COMPONENTS2,
159
+ MAX_DEPTH2,
160
+ MAX_MESSAGE_BYTES2,
161
+ MAX_TEMPLATE_ITEMS2,
162
+ MAX_POINTER_BYTES2,
163
+ MAX_POINTER_SEGMENTS2,
164
+ LIMIT_ISSUES2,
165
+ absolutePath2,
166
+ hasItem2,
167
+ readPath2,
168
+ readPointer2,
169
+ writeTokens2,
170
+ POINTER_ISSUES2,
171
+ writePointer2,
172
+ BIND_FUNCTIONS2,
173
+ BIND_FUNCTION_NAMES2,
174
+ resolveDynamic2,
175
+ isVisible2,
176
+ withOwnWrites2,
177
+ submitClosesOverlay2,
178
+ runAction2,
179
+ isDataSchema2,
180
+ resolveProp2,
181
+ resolveNodeProps2,
182
+ hasRowSlots2,
183
+ rowScope2,
184
+ bindRowSlot2,
185
+ sectionScope2,
186
+ bindSectionHeader2,
187
+ bindTree2,
188
+ treeGuides2,
189
+ isRowRoot2,
190
+ applyTreeGuides2,
191
+ BREAKPOINTS2,
192
+ isResponsiveValue2,
193
+ responsiveAt2,
194
+ propsAt2,
195
+ expandMacros2,
196
+ isCallableName2,
197
+ validateNode2,
198
+ validateProps2,
199
+ basicMap2,
200
+ mapBasicIcon2,
201
+ mapBasicComponent2,
202
+ BASIC_TRANSFORM_NAMES2,
203
+ RESERVED_KEYS2,
204
+ validVisible2,
205
+ childTemplate2,
206
+ reduceSurface2,
207
+ slotAllowed2,
208
+ reduceNested2,
209
+ preorder2,
210
+ BUILTIN_FUNCTIONS2,
211
+ matchesPattern2,
212
+ decideFunction2,
213
+ combineDecisions2,
214
+ packagePolicy2,
215
+ isPrivateHost2,
216
+ decideUrl2,
217
+ mediaRequest2,
218
+ safeHref2,
219
+ sortKeys2,
220
+ imageDimensions2,
221
+ svgDimensions2,
222
+ imageFrames2,
223
+ mediaImageWithinLimits2,
224
+ parseSource2,
225
+ JsonlDecoder2,
226
+ decodeJsonl2,
227
+ SseDecoder2,
228
+ messagesFromMcpResult2,
229
+ mcpActionCall2,
230
+ supportedCatalogIds2,
231
+ clientCapabilities2,
232
+ validatePackage2,
233
+ sourceAllowed2,
234
+ templateMessages2,
235
+ mergeData2,
236
+ HostRouter2,
237
+ normalizePath2,
238
+ PackageError2,
239
+ resolveSurfaceTheme2,
240
+ SurfaceStore2,
241
+ ExponentialHost2,
242
+ MemoryTransport2,
243
+ JsonlStreamTransport2,
244
+ SseTransport2,
245
+ WebSocketTransport2,
246
+ McpTransport2
247
+ } from "./chunks/index-98npjvsd.js";
248
+ import {
249
+ style_default
250
+ } from "./chunks/index-njt7yzzm.js";
251
+ // packages/exponential-ui/catalog/layout.json
252
+ var layout_default = {
253
+ $comment: "Round 2 (docs/round-2-contract.md §7): the layout NUMBERS every painter shares where no theme token decides (px unless noted). `windowThreshold` = items past which List and Table window; `windowOverscan` = items rendered beyond each viewport edge; `resizeStep` = percentage points per arrow key on a Resizable handle; `panelMin` = a panel's min (percent) when unset; `resizeHandleHit` = a handle's hit area across its hairline; `fieldIntrinsicWidth` = the max-content width of a text field (Input, Textarea, NumberField, ChipInput: never the browser's `size` default) — picker triggers (Select, DatePicker, DateRangePicker, TimePicker) size to their content; `mediaIntrinsicWidth` = the max-content width of an Image/Video without a width (its min-content is 0); `mediaAspectRatio` = width/height of an Image without `aspectRatio` or a height (Video: its `aspectRatio` default); `treeGuideColumn` = one TreeGuides gutter column (the recipe's `line` width is the STROKE; round 3: 14, the ×4 app indent, the elbow lands on the parent's lead glyph); `treeGuideRadius` = the elbow's corner radius; `treeGuideBridge` = how far the guide verticals overshoot the row's TOP edge (paint only) so a Section's hairline divider never breaks the line. EXP-1259 (packages/domain-contract/fixtures/feedback-states.json + search-list.json): `pendingDelayMs` = how long a `loading` Button waits before it shows the spinner and its `pendingLabel` (a fast action never flashes; presses are refused at once); `skeletonPulseMs` / `skeletonOpacityLow` / `skeletonOpacityHigh` = the placeholder's ONE opacity pulse (low → high → low, ease-in-out), `skeletonReducedOpacity` = its static opacity under reduce motion; `searchListFade` = the bottom fade over a SearchList (or a searchable submenu) while more rows sit below. Generated into every target; src/layout.ts reads it.",
254
+ windowThreshold: 50,
255
+ windowOverscan: 5,
256
+ resizeStep: 10,
257
+ panelMin: 10,
258
+ resizeHandleHit: 8,
259
+ fieldIntrinsicWidth: 160,
260
+ mediaIntrinsicWidth: 320,
261
+ mediaAspectRatio: 1.7777778,
262
+ treeGuideColumn: 14,
263
+ treeGuideRadius: 3,
264
+ treeGuideBridge: 1,
265
+ pendingDelayMs: 150,
266
+ skeletonPulseMs: 1600,
267
+ skeletonOpacityLow: 0.45,
268
+ skeletonOpacityHigh: 0.9,
269
+ skeletonReducedOpacity: 0.6,
270
+ searchListFade: 24
271
+ };
272
+
273
+ // packages/exponential-ui/src/layout.ts
274
+ var LAYOUT_CONSTANTS = Object.fromEntries(Object.entries(layout_default).filter(([k]) => !k.startsWith(`$`)));
275
+ var WINDOW_THRESHOLD = layout_default.windowThreshold;
276
+ var WINDOW_OVERSCAN = layout_default.windowOverscan;
277
+ var RESIZE_STEP = layout_default.resizeStep;
278
+ var PANEL_MIN = layout_default.panelMin;
279
+ var RESIZE_HANDLE_HIT = layout_default.resizeHandleHit;
280
+ var FIELD_INTRINSIC_WIDTH = layout_default.fieldIntrinsicWidth;
281
+ var MEDIA_INTRINSIC_WIDTH = layout_default.mediaIntrinsicWidth;
282
+ var MEDIA_ASPECT_RATIO = layout_default.mediaAspectRatio;
283
+ var TREE_GUIDE_COLUMN = layout_default.treeGuideColumn;
284
+ var TREE_GUIDE_RADIUS = layout_default.treeGuideRadius;
285
+ var TREE_GUIDE_BRIDGE = layout_default.treeGuideBridge;
286
+ var PENDING_DELAY_MS = layout_default.pendingDelayMs;
287
+ var SKELETON_PULSE_MS = layout_default.skeletonPulseMs;
288
+ var SKELETON_OPACITY_LOW = layout_default.skeletonOpacityLow;
289
+ var SKELETON_OPACITY_HIGH = layout_default.skeletonOpacityHigh;
290
+ var SKELETON_REDUCED_OPACITY = layout_default.skeletonReducedOpacity;
291
+ var SEARCH_LIST_FADE = layout_default.searchListFade;
292
+
293
+ // packages/exponential-ui/src/list.ts
294
+ function templateItemKeys(items, keyPointer) {
295
+ const seen = new Set;
296
+ return items.map((item, index) => {
297
+ let key = String(index);
298
+ if (keyPointer !== undefined) {
299
+ const v = readPointer2(item, keyPointer.startsWith(`/`) ? keyPointer : `/${keyPointer}`);
300
+ const own = v === undefined || v === null || v === `` ? null : typeof v === `object` ? JSON.stringify(v) : String(v);
301
+ key = own !== null && !seen.has(own) ? own : `#${index}`;
302
+ while (seen.has(key))
303
+ key = `#${key}`;
304
+ }
305
+ seen.add(key);
306
+ return key;
307
+ });
308
+ }
309
+ var escapeToken = (token) => token.replace(/~/g, `~0`).replace(/\//g, `~1`);
310
+ function tableRowKeys(rows, rowKey = `id`) {
311
+ return templateItemKeys(rows, `/${escapeToken(rowKey)}`);
312
+ }
313
+ var instanceSegment = (key) => key.replace(/~/g, `~0`).replace(/\./g, `~1`);
314
+ function templateInstances(data, template, scope = ``, instance = ``) {
315
+ const path = absolutePath2(template.path, { base: scope });
316
+ const list = readPointer2(data, path);
317
+ if (!Array.isArray(list))
318
+ return [];
319
+ const keys = templateItemKeys(list, template.key);
320
+ return list.slice(0, MAX_TEMPLATE_ITEMS2).map((_, index) => ({ key: keys[index], path: `${path}/${index}`, index, instance: `${instance}.${instanceSegment(keys[index])}` }));
321
+ }
322
+ var templateSiteKey = (nodeId, scope) => `${nodeId}\x00${scope}`;
323
+ function staticSize(root) {
324
+ let n = 0;
325
+ const stack = [root];
326
+ while (stack.length) {
327
+ const node = stack.pop();
328
+ n++;
329
+ for (const slot of Object.values(node.slots ?? {}))
330
+ stack.push(slot);
331
+ for (const child of node.children)
332
+ stack.push(child);
333
+ }
334
+ return n;
335
+ }
336
+ function templateBudget(root, data, templateNode) {
337
+ const allowed = new Map;
338
+ const sizes = new Map;
339
+ const sizeOf = (tpl) => {
340
+ let n = sizes.get(tpl);
341
+ if (n === undefined)
342
+ sizes.set(tpl, n = staticSize(tpl));
343
+ return n;
344
+ };
345
+ let items = 0;
346
+ let nodes = staticSize(root);
347
+ let issue = null;
348
+ const stack = [{ node: root, scope: `` }];
349
+ while (stack.length) {
350
+ const entry = stack.pop();
351
+ if (`site` in entry) {
352
+ if (issue || entry.index >= entry.length)
353
+ continue;
354
+ if (items >= MAX_TEMPLATE_ITEMS2)
355
+ issue = { id: entry.component, message: LIMIT_ISSUES2.templateItems };
356
+ else if (nodes + entry.size > MAX_COMPONENTS2)
357
+ issue = { id: entry.component, message: LIMIT_ISSUES2.components };
358
+ if (issue)
359
+ continue;
360
+ items++;
361
+ nodes += entry.size;
362
+ allowed.set(entry.site, entry.index + 1);
363
+ stack.push({ ...entry, index: entry.index + 1 });
364
+ stack.push({ node: entry.tpl, scope: `${entry.path}/${entry.index}` });
365
+ continue;
366
+ }
367
+ const { node, scope } = entry;
368
+ const next = [];
369
+ for (const slot of Object.values(node.slots ?? {}))
370
+ next.push({ node: slot, scope });
371
+ for (const child of node.children)
372
+ next.push({ node: child, scope });
373
+ const template = node.template;
374
+ const tpl = template ? templateNode(template.component) : undefined;
375
+ if (template && tpl) {
376
+ const path = absolutePath2(template.path, { base: scope });
377
+ const list = readPointer2(data, path);
378
+ const windowed = Array.isArray(list) && node.component === `List` && node.children.length + list.length > WINDOW_THRESHOLD;
379
+ if (Array.isArray(list) && !windowed) {
380
+ const site = templateSiteKey(node.id, scope);
381
+ allowed.set(site, 0);
382
+ next.push({ site, component: template.component, tpl, path, size: sizeOf(tpl), index: 0, length: list.length });
383
+ }
384
+ }
385
+ for (let i = next.length - 1;i >= 0; i--)
386
+ stack.push(next[i]);
387
+ }
388
+ return { allowed, issue };
389
+ }
390
+ function itemOffsets(extents, gap = 0) {
391
+ const out = new Array(extents.length + 1);
392
+ let at = 0;
393
+ for (let i = 0;i < extents.length; i++) {
394
+ out[i] = at;
395
+ at += extents[i] + (i < extents.length - 1 ? gap : 0);
396
+ }
397
+ out[extents.length] = at;
398
+ return out;
399
+ }
400
+ function itemExtents(measured, row) {
401
+ let sum = 0;
402
+ let n = 0;
403
+ for (const m of measured) {
404
+ if (typeof m === `number`) {
405
+ sum += m;
406
+ n++;
407
+ }
408
+ }
409
+ const estimate = n ? sum / n : row;
410
+ return measured.map((m) => typeof m === `number` ? m : estimate);
411
+ }
412
+ function firstWhere(lo, hi, test) {
413
+ while (lo < hi) {
414
+ const mid = lo + hi >>> 1;
415
+ if (test(mid))
416
+ hi = mid;
417
+ else
418
+ lo = mid + 1;
419
+ }
420
+ return lo;
421
+ }
422
+ function virtualWindow(extents, gap, scroll, viewport, overscan = WINDOW_OVERSCAN, offsets) {
423
+ const count = extents.length;
424
+ const off = offsets ?? itemOffsets(extents, gap);
425
+ const total = off[count];
426
+ let start = firstWhere(0, count, (i) => off[i] + extents[i] >= scroll);
427
+ let end = firstWhere(start, count, (i) => off[i] >= scroll + viewport);
428
+ start = Math.max(0, start - overscan);
429
+ end = Math.min(count, end + overscan);
430
+ if (end <= start)
431
+ return { start, end: start, before: 0, after: total, total };
432
+ const before = off[start];
433
+ const after = total - (off[end - 1] + extents[end - 1]);
434
+ return { start, end, before, after, total };
435
+ }
436
+ function scrollOffsetForIndex(extents, gap, index, viewport, scroll, align = `nearest`, inset = 0, offsets) {
437
+ const off = offsets ?? itemOffsets(extents, gap);
438
+ const total = off[extents.length];
439
+ if (index < 0 || index >= extents.length)
440
+ return scroll;
441
+ const top = off[index];
442
+ const size = extents[index];
443
+ let next = scroll;
444
+ if (align === `start`)
445
+ next = top - inset;
446
+ else if (align === `end`)
447
+ next = top + size - viewport;
448
+ else if (align === `center`)
449
+ next = top + size / 2 - (viewport + inset) / 2;
450
+ else if (top - inset < scroll)
451
+ next = top - inset;
452
+ else if (top + size > scroll + viewport)
453
+ next = top + size - viewport;
454
+ return Math.max(0, Math.min(Math.max(0, total - viewport), next));
455
+ }
456
+ function listSections(items, sectionBy) {
457
+ const out = [];
458
+ const pointer = sectionBy.startsWith(`/`) ? sectionBy : `/${sectionBy}`;
459
+ items.forEach((item, index) => {
460
+ const v = readPointer2(item, pointer);
461
+ const value = v === undefined || v === null ? `` : typeof v === `object` ? JSON.stringify(v) : String(v);
462
+ const last = out[out.length - 1];
463
+ if (last && last.value === value)
464
+ last.count++;
465
+ else
466
+ out.push({ value, start: index, count: 1 });
467
+ });
468
+ return out;
469
+ }
470
+ function sectionRows(sections) {
471
+ const rows = [];
472
+ sections.forEach((s, i) => {
473
+ rows.push({ header: i });
474
+ for (let k = 0;k < s.count; k++)
475
+ rows.push({ item: s.start + k });
476
+ });
477
+ return rows;
478
+ }
479
+ function scrollOffsetForItem(rows, rowExtents, gap, dataIndex, viewport, scroll, align = `nearest`, stickyHeaders = false, offsets) {
480
+ const row = rows.findIndex((r) => (`item` in r) && r.item === dataIndex);
481
+ if (row < 0)
482
+ return scroll;
483
+ let header = row;
484
+ while (header >= 0 && !(`header` in rows[header]))
485
+ header--;
486
+ const inset = stickyHeaders && header >= 0 ? rowExtents[header] : 0;
487
+ return scrollOffsetForIndex(rowExtents, gap, row, viewport, scroll, align, inset, offsets);
488
+ }
489
+ function stickyHeader(rowOffsets, rowExtents, headerRows, scroll) {
490
+ const pinned = firstWhere(0, headerRows.length, (h) => rowOffsets[headerRows[h]] > scroll) - 1;
491
+ if (pinned < 0)
492
+ return null;
493
+ const row = headerRows[pinned];
494
+ const next = headerRows[pinned + 1];
495
+ const extent = rowExtents[row];
496
+ const offset = next === undefined ? scroll : Math.min(scroll, rowOffsets[next] - extent);
497
+ return { row, offset };
498
+ }
499
+ // packages/exponential-ui/src/resizable.ts
500
+ var EPS = 0.000000001;
501
+ var clampN = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
502
+ var tidy = (v) => {
503
+ const r = Math.round(v * 1e6) / 1e6;
504
+ return Object.is(r, -0) ? 0 : r;
505
+ };
506
+ function limitsOf(limits, i, count) {
507
+ const l = limits?.[i] ?? {};
508
+ const cap = 100 / Math.max(1, count);
509
+ const min = clampN(typeof l.min === `number` && Number.isFinite(l.min) ? l.min : PANEL_MIN, 0, cap);
510
+ const max = clampN(typeof l.max === `number` && Number.isFinite(l.max) ? l.max : 100, min, 100);
511
+ return { min, max, collapsible: l.collapsible === true };
512
+ }
513
+ function normalizeSizes(sizes, count, limits) {
514
+ if (count <= 0)
515
+ return [];
516
+ const given = Array.from({ length: count }, (_, i) => {
517
+ const v = sizes?.[i];
518
+ return typeof v === `number` && Number.isFinite(v) && v >= 0 ? v : null;
519
+ });
520
+ const missing = given.filter((v) => v === null).length;
521
+ let out;
522
+ if (missing === count)
523
+ out = given.map(() => 100 / count);
524
+ else {
525
+ const sum = given.reduce((s, v) => s + (v ?? 0), 0);
526
+ const rest = Math.max(0, 100 - sum);
527
+ out = given.map((v) => v ?? rest / missing);
528
+ }
529
+ const total = out.reduce((s, v) => s + v, 0);
530
+ out = total > EPS ? out.map((v) => v * 100 / total) : out.map(() => 100 / count);
531
+ const lim = out.map((_, i) => limitsOf(limits, i, count));
532
+ out = out.map((v, i) => lim[i].collapsible && v <= EPS ? 0 : clampN(v, lim[i].min, lim[i].max));
533
+ let diff = 100 - out.reduce((s, v) => s + v, 0);
534
+ for (let i = 0;i < count && Math.abs(diff) > EPS; i++) {
535
+ if (lim[i].collapsible && out[i] === 0)
536
+ continue;
537
+ const room = diff > 0 ? lim[i].max - out[i] : lim[i].min - out[i];
538
+ const take = diff > 0 ? Math.min(diff, room) : Math.max(diff, room);
539
+ out[i] += take;
540
+ diff -= take;
541
+ }
542
+ return out.map(tidy);
543
+ }
544
+ function resizePanels(sizes, handle, delta, limits) {
545
+ const out = [...sizes];
546
+ const a = handle;
547
+ const b = handle + 1;
548
+ if (a < 0 || b >= sizes.length || !Number.isFinite(delta))
549
+ return out.map(tidy);
550
+ const la = limitsOf(limits, a, sizes.length);
551
+ const lb = limitsOf(limits, b, sizes.length);
552
+ const lo = Math.max(la.min - sizes[a], sizes[b] - lb.max);
553
+ const hi = Math.min(la.max - sizes[a], sizes[b] - lb.min);
554
+ let d = clampN(delta, Math.min(lo, 0), Math.max(hi, 0));
555
+ if (la.collapsible && delta < 0 && sizes[a] > 0 && sizes[a] + delta < la.min / 2 && sizes[b] + sizes[a] <= lb.max + EPS)
556
+ d = -sizes[a];
557
+ else if (lb.collapsible && delta > 0 && sizes[b] > 0 && sizes[b] - delta < lb.min / 2 && sizes[a] + sizes[b] <= la.max + EPS)
558
+ d = sizes[b];
559
+ else if (la.collapsible && sizes[a] === 0)
560
+ d = delta >= la.min / 2 && hi >= la.min - EPS ? clampN(delta, la.min, hi) : 0;
561
+ else if (lb.collapsible && sizes[b] === 0)
562
+ d = -delta >= lb.min / 2 && -lo >= lb.min - EPS ? -clampN(-delta, lb.min, -lo) : 0;
563
+ out[a] = sizes[a] + d;
564
+ out[b] = sizes[b] - d;
565
+ return out.map(tidy);
566
+ }
567
+ function keyboardResize(sizes, handle, key, orientation, direction = `ltr`, limits) {
568
+ const a = handle;
569
+ const b = handle + 1;
570
+ if (a < 0 || b >= sizes.length)
571
+ return sizes.map(tidy);
572
+ const la = limitsOf(limits, a, sizes.length);
573
+ const lb = limitsOf(limits, b, sizes.length);
574
+ const flip = orientation === `horizontal` && direction === `rtl` ? -1 : 1;
575
+ const step = (sign) => resizePanels(sizes, handle, sign * RESIZE_STEP, limits);
576
+ switch (key) {
577
+ case `ArrowRight`:
578
+ return orientation === `horizontal` ? step(flip) : sizes.map(tidy);
579
+ case `ArrowLeft`:
580
+ return orientation === `horizontal` ? step(-flip) : sizes.map(tidy);
581
+ case `ArrowDown`:
582
+ return orientation === `vertical` ? step(1) : sizes.map(tidy);
583
+ case `ArrowUp`:
584
+ return orientation === `vertical` ? step(-1) : sizes.map(tidy);
585
+ case `Home`:
586
+ return resizePanels(sizes, handle, la.min - sizes[a], limits);
587
+ case `End`:
588
+ return resizePanels(sizes, handle, la.max - sizes[a], limits);
589
+ case `Enter`: {
590
+ const out = [...sizes];
591
+ if (la.collapsible) {
592
+ const d = sizes[a] > 0 ? -sizes[a] : Math.min(la.min, sizes[b] - lb.min);
593
+ if (sizes[b] - d > lb.max + EPS || d === 0)
594
+ return sizes.map(tidy);
595
+ out[a] += d;
596
+ out[b] -= d;
597
+ } else if (lb.collapsible) {
598
+ const d = sizes[b] > 0 ? sizes[b] : -Math.min(lb.min, sizes[a] - la.min);
599
+ if (sizes[a] + d > la.max + EPS || d === 0)
600
+ return sizes.map(tidy);
601
+ out[a] += d;
602
+ out[b] -= d;
603
+ }
604
+ return out.map(tidy);
605
+ }
606
+ default:
607
+ return sizes.map(tidy);
608
+ }
609
+ }
610
+ function panelExtents(sizes, container, handleExtent = 1) {
611
+ const avail = Math.max(0, container - Math.max(0, sizes.length - 1) * handleExtent);
612
+ return sizes.map((s) => tidy(avail * s / 100));
613
+ }
614
+ function dragDelta(px, container, panelCount, orientation, direction = `ltr`, handleExtent = 1) {
615
+ const avail = Math.max(1, container - Math.max(0, panelCount - 1) * handleExtent);
616
+ const flip = orientation === `horizontal` && direction === `rtl` ? -1 : 1;
617
+ return tidy(px * 100 / avail * flip);
618
+ }
619
+ // packages/exponential-ui/src/direction.ts
620
+ function ownDirection(node, ctx) {
621
+ if (!node.style)
622
+ return;
623
+ const style = ctx ? resolveConditions2(node.style, ctx) : node.style;
624
+ const d = style.direction;
625
+ return d === `ltr` || d === `rtl` ? d : undefined;
626
+ }
627
+ function nodeDirections(root, surface, ctx) {
628
+ const out = {};
629
+ const walk = (n, inherited) => {
630
+ const dir = ownDirection(n, ctx) ?? inherited;
631
+ out[n.id] = dir;
632
+ for (const slot of Object.values(n.slots ?? {}))
633
+ walk(slot, dir);
634
+ for (const child of n.children)
635
+ walk(child, dir);
636
+ };
637
+ walk(root, surface);
638
+ return out;
639
+ }
640
+ function physicalTextAlign(align, direction) {
641
+ switch (align) {
642
+ case `left`:
643
+ case `right`:
644
+ case `center`:
645
+ case `justify`:
646
+ return align;
647
+ case `end`:
648
+ return direction === `rtl` ? `left` : `right`;
649
+ default:
650
+ return direction === `rtl` ? `right` : `left`;
651
+ }
652
+ }
653
+ function nodeTextAlign(node, direction, ctx) {
654
+ const style = node.style ? ctx ? resolveConditions2(node.style, ctx) : node.style : {};
655
+ return physicalTextAlign(style.textAlign ?? node.props.align, direction);
656
+ }
657
+ // packages/exponential-ui/src/animation.ts
658
+ var ANIMATIONS = Object.fromEntries(Object.entries(style_default.animations).filter(([k]) => !k.startsWith(`$`)));
659
+ var ANIMATION_NAMES = Object.keys(ANIMATIONS);
660
+ var LINEAR = `linear`;
661
+ function animationTiming(name, theme, durationToken) {
662
+ const def = ANIMATIONS[name];
663
+ if (!def)
664
+ return null;
665
+ const token = parseTokenRef2(durationToken ?? def.duration);
666
+ const base = token && token.group === `motion` ? theme.tokens.motion[token.name] : undefined;
667
+ const fallback = parseTokenRef2(def.duration);
668
+ const ms = (base ?? (fallback ? theme.tokens.motion[fallback.name] : 0) ?? 0) * def.factor;
669
+ const ease = parseTokenRef2(def.easing);
670
+ const easing = def.easing === LINEAR ? LINEAR : ease && ease.group === `ease` ? theme.tokens.ease[ease.name] ?? LINEAR : LINEAR;
671
+ return { durationMs: ms, easing, iterations: def.iterations };
672
+ }
673
+ function cubicBezier(curve, x) {
674
+ const [x1, y1, x2, y2] = curve;
675
+ if (x <= 0)
676
+ return 0;
677
+ if (x >= 1)
678
+ return 1;
679
+ const bx = (t) => 3 * x1 * t * (1 - t) ** 2 + 3 * x2 * t * t * (1 - t) + t ** 3;
680
+ const by = (t) => 3 * y1 * t * (1 - t) ** 2 + 3 * y2 * t * t * (1 - t) + t ** 3;
681
+ let lo = 0;
682
+ let hi = 1;
683
+ for (let i = 0;i < 60; i++) {
684
+ const mid = (lo + hi) / 2;
685
+ if (bx(mid) < x)
686
+ lo = mid;
687
+ else
688
+ hi = mid;
689
+ }
690
+ return by((lo + hi) / 2);
691
+ }
692
+ var CHANNELS = [`opacity`, `translateX`, `translateY`, `rotate`, `scale`];
693
+ var REST = { opacity: 1, translateX: 0, translateY: 0, rotate: 0, scale: 1, band: null };
694
+ var r4 = (v) => {
695
+ const r = Math.round(v * 1e4) / 1e4;
696
+ return Object.is(r, -0) ? 0 : r;
697
+ };
698
+ function frameAt(def, progress, easing) {
699
+ const ks = def.keyframes;
700
+ let k = 0;
701
+ while (k < ks.length - 2 && progress > ks[k + 1].offset)
702
+ k++;
703
+ const a = ks[k];
704
+ const b = ks[Math.min(k + 1, ks.length - 1)];
705
+ const span = b.offset - a.offset;
706
+ const local = span > 0 ? Math.max(0, Math.min(1, (progress - a.offset) / span)) : 1;
707
+ const t = easing === LINEAR ? local : cubicBezier(easing, local);
708
+ const out = { ...REST };
709
+ for (const ch of CHANNELS) {
710
+ const va = a[ch] ?? REST[ch];
711
+ const vb = b[ch] ?? REST[ch];
712
+ out[ch] = r4(va + (vb - va) * t);
713
+ }
714
+ if (a.band !== undefined && b.band !== undefined)
715
+ out.band = r4(a.band + (b.band - a.band) * t);
716
+ return out;
717
+ }
718
+ function animationFrame(name, elapsedMs, theme, options = {}) {
719
+ const def = ANIMATIONS[name];
720
+ const timing = animationTiming(name, theme, options.durationToken);
721
+ if (!def || !timing)
722
+ return null;
723
+ if (options.reducedMotion) {
724
+ const rest = frameAt(def, def.rest, LINEAR);
725
+ return { ...rest, band: null };
726
+ }
727
+ const d = timing.durationMs;
728
+ if (d <= 0)
729
+ return frameAt(def, 1, LINEAR);
730
+ const iterations = timing.iterations === `infinite` ? Infinity : timing.iterations;
731
+ const t = Math.max(0, elapsedMs);
732
+ if (t >= d * iterations)
733
+ return frameAt(def, 1, timing.easing);
734
+ return frameAt(def, t % d / d, timing.easing);
735
+ }
736
+ function paintedOpacity(own, frame) {
737
+ return r4((own ?? 1) * (frame?.opacity ?? 1));
738
+ }
739
+ var css = (n) => String(r4(n));
740
+ var ANIMATION_PROPERTIES_CSS = `@property --xui-a-opacity{syntax:"<number>";inherits:false;initial-value:1}@property --xui-band{syntax:"<number>";inherits:true;initial-value:1}`;
741
+ function animatesOpacity(name) {
742
+ return ANIMATIONS[name]?.keyframes.some((k) => k.opacity !== undefined) ?? false;
743
+ }
744
+ function keyframesCss(name) {
745
+ const def = ANIMATIONS[name];
746
+ if (!def)
747
+ return ``;
748
+ const steps = def.keyframes.map((k) => {
749
+ const decl = [];
750
+ if (k.opacity !== undefined)
751
+ decl.push(`--xui-a-opacity:${css(k.opacity)}`);
752
+ if (k.translateX !== undefined || k.translateY !== undefined)
753
+ decl.push(`translate:${css(k.translateX ?? 0)}px ${css(k.translateY ?? 0)}px`);
754
+ if (k.rotate !== undefined)
755
+ decl.push(`rotate:${css(k.rotate)}deg`);
756
+ if (k.scale !== undefined)
757
+ decl.push(`scale:${css(k.scale)}`);
758
+ if (k.band !== undefined)
759
+ decl.push(`--xui-band:${css(k.band)}`);
760
+ return `${css(k.offset * 100)}%{${decl.join(`;`)}}`;
761
+ });
762
+ return `@keyframes xui-${name}{${steps.join(``)}}`;
763
+ }
764
+ function animationCss(name, timing) {
765
+ const easing = timing.easing === LINEAR ? `linear` : `cubic-bezier(${timing.easing.join(`, `)})`;
766
+ const iterations = timing.iterations === `infinite` ? `infinite` : String(timing.iterations);
767
+ return `xui-${name} ${timing.durationMs}ms ${easing} ${iterations} both`;
768
+ }
769
+ // packages/exponential-ui/src/locale.ts
770
+ var DEFAULT_LOCALE = locale_default.default;
771
+ var ALIASES = locale_default.languageAliases;
772
+ function parseLocale(locale) {
773
+ const tags = locale.replace(/_/g, `-`).split(`-`).filter(Boolean);
774
+ const raw = (tags[0] ?? ``).toLowerCase();
775
+ const language = ALIASES[raw] ?? raw;
776
+ const region = tags.slice(1).find((t) => /^[A-Za-z]{2}$|^\d{3}$/.test(t));
777
+ return { language, region: region ? region.toUpperCase() : null };
778
+ }
779
+ var WEEK_START_BY_REGION = (() => {
780
+ const out = {};
781
+ for (const [day, regions] of Object.entries(locale_default.weekStart.regions))
782
+ for (const r of regions)
783
+ out[r] = Number(day);
784
+ return out;
785
+ })();
786
+ function localeRegion(locale) {
787
+ const { language, region } = parseLocale(locale);
788
+ return region ?? locale_default.likelyRegion[language] ?? null;
789
+ }
790
+ function weekStart(locale) {
791
+ const r = localeRegion(locale);
792
+ return r !== null && r in WEEK_START_BY_REGION ? WEEK_START_BY_REGION[r] : locale_default.weekStart.default;
793
+ }
794
+ function textDirection(locale) {
795
+ return locale_default.rtl.includes(parseLocale(locale).language) ? `rtl` : `ltr`;
796
+ }
797
+ var RTL_MIRRORED_ICONS = locale_default.rtlMirroredIcons;
798
+ function mirrorsInRtl(icon, direction) {
799
+ return direction === `rtl` && RTL_MIRRORED_ICONS.includes(icon);
800
+ }
801
+ // packages/exponential-ui/catalog/code.json
802
+ var code_default = {
803
+ $comment: "Round 1 (docs/round-1-contract.md §3, CodeBlock): the BUILT-IN tokenizer every renderer mirrors so a CodeBlock colours the same on every platform (a host may still supply its own tokenizer; its kinds must be the `codeToken` enum). ONE scanner over the source (CRLF → LF), first rule that matches at the position wins: (1) `lineKinds` — at a line start (after spaces/tabs) a listed prefix makes the rest of the line that kind; (2) `lineComment` prefixes → comment to the end of the line; (3) `blockComment` [open, close] pairs → comment through close (or the end); (4) a quote in `strings` → string through the same unescaped quote (`\\` escapes the next char), stopping before a line break unless the quote is in `multiline`; with `keyStrings` a string followed by optional spaces and `:` is a `property`; (5) with `markup`, `<` followed by a letter, `/` or `!` opens a tag: `<`/`</` punctuation, the name `tag`, then whitespace plain, quotes string, `=` operator, names `attribute`, until `>`/`/>` punctuation (text outside tags is plain); (6) numbers (unless `numbers` is false): a digit, or `.` before a digit, then every [0-9A-Za-z_.]; (7) identifiers: [A-Za-z_$] plus `identExtra`, then the same plus digits: `keywords` (lower-cased first when `caseInsensitive`) → keyword; with `keyIdents` followed by spaces and a single `:` → property; followed by spaces and `(` → function; right after a `.` punctuation → property; in `typeNames` or (with `types: capitalized`) starting A–Z → type; else plain; (8) a run of spaces/tabs → plain; (9) a run of `operators` chars → operator; (10) one `punctuation` char → punctuation; (11) anything else, one char → plain. Then tokens split at line breaks into LINES and adjacent tokens of one kind merge; a line's tokens concatenate to exactly its text. src/code.ts is the reference, fixtures/code-tokens.json locks it. EXP-1324 `ansi` (the Terminal pattern: command output): BEFORE the scanner, every ANSI CSI escape (ESC `[` params 0x30-0x3F, intermediates 0x20-0x2F, one final 0x40-0x7E) is REMOVED from the source and the remaining text is split into runs by SGR (final `m`) colour: params 31/91 → `error`, 32/92 → `success`, 33/93 → `warning`, 2/90 → `comment`, 0/39/none → no colour, every other param leaves the colour as it was (params apply left to right). A run WITH a colour is that kind, verbatim (no rules). Runs without a colour go through the ordinary scanner with this language spec — which has only `lineKinds` (longest listed prefix wins), so an uncoloured line is either one lineKinds kind from its prefix on, or plain. Tokens then split into lines and merge as usual. The escapes never reach the text: a line's tokens concatenate to its text WITHOUT them (copy copies that text).",
804
+ defaults: { operators: "+-*/%=&|<>!?^~:@#", punctuation: "()[]{},.;" },
805
+ languages: {
806
+ plain: { plain: true },
807
+ json: { strings: ['"'], keywords: ["true", "false", "null"], keyStrings: true },
808
+ js: {
809
+ lineComment: ["//"],
810
+ blockComment: [["/*", "*/"]],
811
+ strings: ['"', "'", "`"],
812
+ multiline: ["`"],
813
+ types: "capitalized",
814
+ keywords: ["async", "await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete", "do", "else", "export", "extends", "false", "finally", "for", "from", "function", "if", "import", "in", "instanceof", "let", "new", "null", "of", "return", "static", "super", "switch", "this", "throw", "true", "try", "typeof", "undefined", "var", "void", "while", "with", "yield"]
815
+ },
816
+ ts: {
817
+ lineComment: ["//"],
818
+ blockComment: [["/*", "*/"]],
819
+ strings: ['"', "'", "`"],
820
+ multiline: ["`"],
821
+ types: "capitalized",
822
+ typeNames: ["any", "bigint", "boolean", "never", "number", "object", "string", "symbol", "unknown"],
823
+ keywords: ["abstract", "as", "async", "await", "break", "case", "catch", "class", "const", "continue", "declare", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "from", "function", "if", "implements", "import", "in", "infer", "instanceof", "interface", "is", "keyof", "let", "namespace", "new", "null", "of", "private", "protected", "public", "readonly", "return", "satisfies", "static", "super", "switch", "this", "throw", "true", "try", "type", "typeof", "undefined", "var", "void", "while", "yield"]
824
+ },
825
+ tsx: {
826
+ lineComment: ["//"],
827
+ blockComment: [["/*", "*/"]],
828
+ strings: ['"', "'", "`"],
829
+ multiline: ["`"],
830
+ types: "capitalized",
831
+ typeNames: ["any", "bigint", "boolean", "never", "number", "object", "string", "symbol", "unknown"],
832
+ keywords: ["abstract", "as", "async", "await", "break", "case", "catch", "class", "const", "continue", "declare", "default", "delete", "do", "else", "enum", "export", "extends", "false", "finally", "for", "from", "function", "if", "implements", "import", "in", "infer", "instanceof", "interface", "is", "keyof", "let", "namespace", "new", "null", "of", "private", "protected", "public", "readonly", "return", "satisfies", "static", "super", "switch", "this", "throw", "true", "try", "type", "typeof", "undefined", "var", "void", "while", "yield"]
833
+ },
834
+ rust: {
835
+ lineComment: ["//"],
836
+ blockComment: [["/*", "*/"]],
837
+ strings: ['"'],
838
+ multiline: ['"'],
839
+ types: "capitalized",
840
+ typeNames: ["bool", "char", "f32", "f64", "i8", "i16", "i32", "i64", "i128", "isize", "str", "u8", "u16", "u32", "u64", "u128", "usize"],
841
+ keywords: ["as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", "false", "fn", "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "Self", "static", "struct", "super", "trait", "true", "type", "unsafe", "use", "where", "while"]
842
+ },
843
+ swift: {
844
+ lineComment: ["//"],
845
+ blockComment: [["/*", "*/"]],
846
+ strings: ['"'],
847
+ types: "capitalized",
848
+ keywords: ["any", "as", "associatedtype", "async", "await", "break", "case", "catch", "class", "continue", "default", "defer", "do", "else", "enum", "extension", "fallthrough", "false", "for", "func", "guard", "if", "import", "in", "init", "inout", "internal", "is", "let", "nil", "private", "protocol", "public", "repeat", "rethrows", "return", "self", "Self", "some", "static", "struct", "subscript", "super", "switch", "throw", "throws", "true", "try", "typealias", "var", "where", "while"]
849
+ },
850
+ kotlin: {
851
+ lineComment: ["//"],
852
+ blockComment: [["/*", "*/"]],
853
+ strings: ['"', "'"],
854
+ types: "capitalized",
855
+ keywords: ["as", "break", "by", "catch", "class", "companion", "constructor", "continue", "data", "do", "else", "enum", "false", "finally", "for", "fun", "if", "import", "in", "init", "interface", "internal", "is", "lateinit", "null", "object", "open", "override", "package", "private", "protected", "public", "return", "sealed", "super", "suspend", "this", "throw", "true", "try", "typealias", "val", "var", "when", "while"]
856
+ },
857
+ python: {
858
+ lineComment: ["#"],
859
+ strings: ['"', "'"],
860
+ types: "capitalized",
861
+ keywords: ["False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "self", "try", "while", "with", "yield"]
862
+ },
863
+ bash: {
864
+ lineComment: ["#"],
865
+ strings: ['"', "'"],
866
+ multiline: ['"', "'"],
867
+ keywords: ["case", "do", "done", "echo", "elif", "else", "esac", "exit", "export", "fi", "for", "function", "if", "in", "local", "readonly", "return", "then", "until", "while"]
868
+ },
869
+ html: { markup: true, blockComment: [["<!--", "-->"]], strings: ['"', "'"], numbers: false },
870
+ css: {
871
+ blockComment: [["/*", "*/"]],
872
+ strings: ['"', "'"],
873
+ identExtra: "-@",
874
+ keyIdents: true,
875
+ operators: "+*/%=&|<>!?^~:#",
876
+ keywords: ["@container", "@font-face", "@import", "@keyframes", "@layer", "@media", "@supports", "auto", "important", "inherit", "initial", "none", "unset"]
877
+ },
878
+ sql: {
879
+ lineComment: ["--"],
880
+ blockComment: [["/*", "*/"]],
881
+ strings: ["'", '"'],
882
+ caseInsensitive: true,
883
+ keywords: ["all", "alter", "and", "as", "asc", "between", "by", "case", "create", "default", "delete", "desc", "distinct", "drop", "else", "end", "exists", "foreign", "from", "group", "having", "in", "index", "inner", "insert", "into", "is", "join", "key", "left", "like", "limit", "not", "null", "offset", "on", "or", "order", "outer", "primary", "references", "returning", "right", "select", "set", "table", "then", "union", "update", "values", "when", "where", "with"]
884
+ },
885
+ yaml: { lineComment: ["#"], strings: ['"', "'"], keyIdents: true, identExtra: "-", keywords: ["true", "false", "null", "yes", "no"] },
886
+ markdown: { lineKinds: { "#": "keyword", ">": "comment" }, strings: ["`"], numbers: false, operators: "", punctuation: "" },
887
+ ansi: {
888
+ ansi: true,
889
+ numbers: false,
890
+ operators: "",
891
+ punctuation: "",
892
+ lineKinds: { "$ ": "comment", "> ": "comment", "BUILD SUCCESSFUL": "success", "BUILD FAILED": "error", "PASS ": "success", "FAIL ": "error", FAILED: "error", "(pass)": "success", "(fail)": "error", "test result: ok": "success", "test result: FAILED": "error", "error:": "error", "error[": "error", "Error:": "error", "warning:": "warning", "✓": "success", "✔": "success", "✗": "error", "✘": "error" }
893
+ }
894
+ }
895
+ };
896
+
897
+ // packages/exponential-ui/src/code.ts
898
+ var CODE_LANGUAGES = code_default.languages;
899
+ var CODE_LANGUAGE_NAMES = Object.keys(CODE_LANGUAGES);
900
+ var isDigit = (c) => c !== undefined && c >= `0` && c <= `9`;
901
+ var isAlpha = (c) => c !== undefined && (c >= `a` && c <= `z` || c >= `A` && c <= `Z`);
902
+ var isSpace = (c) => c === ` ` || c === ` `;
903
+ function nextNonSpace(code, j) {
904
+ let k = j;
905
+ while (isSpace(code[k]))
906
+ k++;
907
+ return code[k];
908
+ }
909
+ function scan(code, spec, lineStart = true) {
910
+ const out = [];
911
+ const n = code.length;
912
+ const operators = spec.operators ?? code_default.defaults.operators;
913
+ const punctuation = spec.punctuation ?? code_default.defaults.punctuation;
914
+ const extra = spec.identExtra ?? ``;
915
+ const identStart = (c) => isAlpha(c) || c === `_` || c === `$` || c !== undefined && extra.includes(c);
916
+ const identPart = (c) => identStart(c) || isDigit(c);
917
+ const keywords = new Set(spec.keywords ?? []);
918
+ const typeNames = new Set(spec.typeNames ?? []);
919
+ const push = (kind, text) => out.push({ kind, text });
920
+ const lastSignificant = () => {
921
+ for (let k = out.length - 1;k >= 0; k--)
922
+ if (out[k].text.trim() !== ``)
923
+ return out[k];
924
+ return;
925
+ };
926
+ if (spec.plain)
927
+ return code ? [{ kind: `plain`, text: code }] : [];
928
+ let i = 0;
929
+ let inTag = false;
930
+ while (i < n) {
931
+ const c = code[i];
932
+ if (c === `
933
+ `) {
934
+ push(`plain`, c);
935
+ i++;
936
+ continue;
937
+ }
938
+ if (spec.lineKinds && (i === 0 ? lineStart : code[i - 1] === `
939
+ ` || isSpaceRunToLineStart(code, i, lineStart))) {
940
+ let prefix;
941
+ for (const p of Object.keys(spec.lineKinds))
942
+ if (code.startsWith(p, i) && (!prefix || p.length > prefix.length))
943
+ prefix = p;
944
+ if (prefix && !isSpace(c)) {
945
+ let j = i;
946
+ while (j < n && code[j] !== `
947
+ `)
948
+ j++;
949
+ push(spec.lineKinds[prefix], code.slice(i, j));
950
+ i = j;
951
+ continue;
952
+ }
953
+ }
954
+ const line = !inTag ? (spec.lineComment ?? []).find((p) => code.startsWith(p, i)) : undefined;
955
+ if (line) {
956
+ let j = i;
957
+ while (j < n && code[j] !== `
958
+ `)
959
+ j++;
960
+ push(`comment`, code.slice(i, j));
961
+ i = j;
962
+ continue;
963
+ }
964
+ const block = !inTag ? (spec.blockComment ?? []).find(([open]) => code.startsWith(open, i)) : undefined;
965
+ if (block) {
966
+ const end = code.indexOf(block[1], i + block[0].length);
967
+ const j = end < 0 ? n : end + block[1].length;
968
+ push(`comment`, code.slice(i, j));
969
+ i = j;
970
+ continue;
971
+ }
972
+ if ((spec.strings ?? []).includes(c) && (!spec.markup || inTag)) {
973
+ const multi = (spec.multiline ?? []).includes(c);
974
+ let j = i + 1;
975
+ while (j < n) {
976
+ if (code[j] === `\\`) {
977
+ j += 2;
978
+ continue;
979
+ }
980
+ if (code[j] === c) {
981
+ j++;
982
+ break;
983
+ }
984
+ if (code[j] === `
985
+ ` && !multi)
986
+ break;
987
+ j++;
988
+ }
989
+ j = Math.min(j, n);
990
+ const kind = spec.keyStrings && nextNonSpace(code, j) === `:` ? `property` : `string`;
991
+ push(kind, code.slice(i, j));
992
+ i = j;
993
+ continue;
994
+ }
995
+ if (spec.markup) {
996
+ if (!inTag) {
997
+ if (c === `<` && (isAlpha(code[i + 1]) || code[i + 1] === `/` || code[i + 1] === `!`)) {
998
+ const open = code[i + 1] === `/` ? `</` : `<`;
999
+ push(`punctuation`, open);
1000
+ let j = i + open.length;
1001
+ const start = j;
1002
+ while (j < n && (isAlpha(code[j]) || isDigit(code[j]) || code[j] === `-` || code[j] === `:` || code[j] === `!`))
1003
+ j++;
1004
+ if (j > start)
1005
+ push(`tag`, code.slice(start, j));
1006
+ inTag = true;
1007
+ i = j;
1008
+ continue;
1009
+ }
1010
+ let j = i;
1011
+ while (j < n && code[j] !== `<` && code[j] !== `
1012
+ `)
1013
+ j++;
1014
+ if (j === i)
1015
+ j = i + 1;
1016
+ push(`plain`, code.slice(i, j));
1017
+ i = j;
1018
+ continue;
1019
+ }
1020
+ if (c === `>` || code.startsWith(`/>`, i)) {
1021
+ const close = c === `>` ? `>` : `/>`;
1022
+ push(`punctuation`, close);
1023
+ inTag = false;
1024
+ i += close.length;
1025
+ continue;
1026
+ }
1027
+ if (c === `=`) {
1028
+ push(`operator`, c);
1029
+ i++;
1030
+ continue;
1031
+ }
1032
+ if (isAlpha(c) || c === `_` || c === `:` || c === `@`) {
1033
+ let j = i;
1034
+ while (j < n && (isAlpha(code[j]) || isDigit(code[j]) || `_:@.-`.includes(code[j])))
1035
+ j++;
1036
+ push(`attribute`, code.slice(i, j));
1037
+ i = j;
1038
+ continue;
1039
+ }
1040
+ if (isSpace(c)) {
1041
+ let j = i;
1042
+ while (isSpace(code[j]))
1043
+ j++;
1044
+ push(`plain`, code.slice(i, j));
1045
+ i = j;
1046
+ continue;
1047
+ }
1048
+ push(`plain`, c);
1049
+ i++;
1050
+ continue;
1051
+ }
1052
+ if (spec.numbers !== false && (isDigit(c) || c === `.` && isDigit(code[i + 1]))) {
1053
+ let j = i + 1;
1054
+ while (j < n && (isDigit(code[j]) || isAlpha(code[j]) || code[j] === `_` || code[j] === `.`))
1055
+ j++;
1056
+ push(`number`, code.slice(i, j));
1057
+ i = j;
1058
+ continue;
1059
+ }
1060
+ if (identStart(c)) {
1061
+ let j = i + 1;
1062
+ while (j < n && identPart(code[j]))
1063
+ j++;
1064
+ const word = code.slice(i, j);
1065
+ const key = spec.caseInsensitive ? word.toLowerCase() : word;
1066
+ const next = nextNonSpace(code, j);
1067
+ const after = (() => {
1068
+ let k = j;
1069
+ while (isSpace(code[k]))
1070
+ k++;
1071
+ return code[k + 1];
1072
+ })();
1073
+ const prev = lastSignificant();
1074
+ let kind = `plain`;
1075
+ if (keywords.has(key))
1076
+ kind = `keyword`;
1077
+ else if (spec.keyIdents && next === `:` && after !== `:`)
1078
+ kind = `property`;
1079
+ else if (next === `(`)
1080
+ kind = `function`;
1081
+ else if (prev && prev.kind === `punctuation` && prev.text.endsWith(`.`))
1082
+ kind = `property`;
1083
+ else if (typeNames.has(word) || spec.types === `capitalized` && word[0] >= `A` && word[0] <= `Z`)
1084
+ kind = `type`;
1085
+ push(kind, word);
1086
+ i = j;
1087
+ continue;
1088
+ }
1089
+ if (isSpace(c)) {
1090
+ let j = i;
1091
+ while (isSpace(code[j]))
1092
+ j++;
1093
+ push(`plain`, code.slice(i, j));
1094
+ i = j;
1095
+ continue;
1096
+ }
1097
+ if (operators.includes(c)) {
1098
+ let j = i;
1099
+ while (j < n && operators.includes(code[j]))
1100
+ j++;
1101
+ push(`operator`, code.slice(i, j));
1102
+ i = j;
1103
+ continue;
1104
+ }
1105
+ push(punctuation.includes(c) ? `punctuation` : `plain`, c);
1106
+ i++;
1107
+ }
1108
+ return out;
1109
+ }
1110
+ function isSpaceRunToLineStart(code, i, lineStart = true) {
1111
+ let k = i - 1;
1112
+ while (k >= 0 && isSpace(code[k]))
1113
+ k--;
1114
+ return k < 0 ? lineStart : code[k] === `
1115
+ `;
1116
+ }
1117
+ var isCsiParam = (c) => c >= 48 && c <= 63;
1118
+ var isCsiIntermediate = (c) => c >= 32 && c <= 47;
1119
+ var isCsiFinal = (c) => c >= 64 && c <= 126;
1120
+ function sgrKind(params, kind) {
1121
+ let out = kind;
1122
+ for (const raw of params.split(`;`)) {
1123
+ const p = raw === `` ? 0 : Number(raw);
1124
+ if (p === 0 || p === 39)
1125
+ out = null;
1126
+ else if (p === 31 || p === 91)
1127
+ out = `error`;
1128
+ else if (p === 32 || p === 92)
1129
+ out = `success`;
1130
+ else if (p === 33 || p === 93)
1131
+ out = `warning`;
1132
+ else if (p === 2 || p === 90)
1133
+ out = `comment`;
1134
+ }
1135
+ return out;
1136
+ }
1137
+ function ansiRuns(source) {
1138
+ const runs = [];
1139
+ let kind = null;
1140
+ let text = ``;
1141
+ const flush = () => {
1142
+ if (text === ``)
1143
+ return;
1144
+ const last = runs[runs.length - 1];
1145
+ if (last && last.kind === kind)
1146
+ last.text += text;
1147
+ else
1148
+ runs.push({ kind, text });
1149
+ text = ``;
1150
+ };
1151
+ let i = 0;
1152
+ const n = source.length;
1153
+ while (i < n) {
1154
+ if (source.charCodeAt(i) === 27 && source[i + 1] === `[`) {
1155
+ let j = i + 2;
1156
+ while (j < n && isCsiParam(source.charCodeAt(j)))
1157
+ j++;
1158
+ const params = source.slice(i + 2, j);
1159
+ while (j < n && isCsiIntermediate(source.charCodeAt(j)))
1160
+ j++;
1161
+ if (j < n && isCsiFinal(source.charCodeAt(j))) {
1162
+ if (source[j] === `m`) {
1163
+ const next = sgrKind(params, kind);
1164
+ if (next !== kind) {
1165
+ flush();
1166
+ kind = next;
1167
+ }
1168
+ }
1169
+ i = j + 1;
1170
+ continue;
1171
+ }
1172
+ }
1173
+ text += source[i];
1174
+ i++;
1175
+ }
1176
+ flush();
1177
+ return runs;
1178
+ }
1179
+ function scanAnsi(code, spec) {
1180
+ const out = [];
1181
+ let atLine = true;
1182
+ for (const run of ansiRuns(code)) {
1183
+ if (run.kind)
1184
+ out.push({ kind: run.kind, text: run.text });
1185
+ else
1186
+ out.push(...scan(run.text, spec, atLine));
1187
+ atLine = isSpaceRunToLineStart(run.text, run.text.length, atLine);
1188
+ }
1189
+ return out;
1190
+ }
1191
+ function codeText(source, language) {
1192
+ const code = source.replace(/\r\n?/g, `
1193
+ `);
1194
+ return CODE_LANGUAGES[language]?.ansi ? ansiRuns(code).map((r) => r.text).join(``) : code;
1195
+ }
1196
+ function tokenizeCode(source, language) {
1197
+ const code = source.replace(/\r\n?/g, `
1198
+ `);
1199
+ const spec = CODE_LANGUAGES[language] ?? CODE_LANGUAGES.plain;
1200
+ const lines = [[]];
1201
+ for (const token of spec.ansi ? scanAnsi(code, spec) : scan(code, spec)) {
1202
+ const pieces = token.text.split(`
1203
+ `);
1204
+ pieces.forEach((piece, index) => {
1205
+ if (index > 0)
1206
+ lines.push([]);
1207
+ if (piece === ``)
1208
+ return;
1209
+ const line = lines[lines.length - 1];
1210
+ const last = line[line.length - 1];
1211
+ if (last && last.kind === token.kind)
1212
+ last.text += piece;
1213
+ else
1214
+ line.push({ kind: token.kind, text: piece });
1215
+ });
1216
+ }
1217
+ return lines;
1218
+ }
1219
+ // packages/exponential-ui/src/text-shimmer.ts
1220
+ var TEXT_SHIMMER = style_default.textShimmer;
1221
+ var toLinear = (c) => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
1222
+ var toGamma = (c) => {
1223
+ const x = Math.max(0, Math.min(1, c));
1224
+ return x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
1225
+ };
1226
+ function rgbToOklab(r, g, b) {
1227
+ const [lr, lg, lb] = [toLinear(r / 255), toLinear(g / 255), toLinear(b / 255)];
1228
+ const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
1229
+ const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
1230
+ const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
1231
+ return [
1232
+ 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
1233
+ 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
1234
+ 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
1235
+ ];
1236
+ }
1237
+ function oklabToRgb([L, a, b]) {
1238
+ const l = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
1239
+ const m = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
1240
+ const s = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
1241
+ return [
1242
+ toGamma(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s) * 255,
1243
+ toGamma(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s) * 255,
1244
+ toGamma(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s) * 255
1245
+ ];
1246
+ }
1247
+ var hex = (lab, alpha) => {
1248
+ const [r, g, b] = oklabToRgb(lab);
1249
+ return toHex2({ r, g, b, a: alpha });
1250
+ };
1251
+ function textShimmer(color, dark) {
1252
+ const t = TEXT_SHIMMER;
1253
+ const c = parseColor2(color) ?? { r: 0, g: 0, b: 0, a: 1 };
1254
+ const base = rgbToOklab(c.r, c.g, c.b);
1255
+ let high = base;
1256
+ let highAlpha = c.a * t.lightAlphaFactor;
1257
+ if (dark) {
1258
+ high = [Math.min(1, Math.max(t.highlightLightnessMin, base[0] + t.highlightLightnessBoost)), base[1], base[2]];
1259
+ highAlpha = Math.min(1, c.a + t.highlightAlphaBoost);
1260
+ }
1261
+ const sum = c.a + highAlpha;
1262
+ const mid = sum > 0 ? [0, 1, 2].map((i) => (base[i] * c.a + high[i] * highAlpha) / sum) : base;
1263
+ return {
1264
+ base: toHex2(c),
1265
+ highlight: hex(high, highAlpha),
1266
+ mid: hex(mid, sum / 2),
1267
+ durationMs: t.durationMs,
1268
+ angleDeg: t.angleDeg,
1269
+ spreadPx: t.spreadPx
1270
+ };
1271
+ }
1272
+ // packages/exponential-ui/catalog/a11y.json
1273
+ var a11y_default = {
1274
+ $comment: "Round 1 (docs/round-1-contract.md §6): the ACCESSIBILITY contract every renderer keeps. `roles` = the MACHINE-READABLE role vocabulary (ARIA names, plus `text` = static text and `hidden` = out of the accessibility tree; SwiftUI traits / Compose semantics / AccessKit roles map from them), used by every `role` here and by the expanded tree's `accessibility.role`. `components` = per component its `role` (one of `roles`: the role of the component's main accessible object), `notes` (prose: composite parts, states, which strings name it) and the KEYBOARD expectations, one line per key group (arrows flip in RTL; a roving tab stop = one Tab stop for the group, arrows move inside it). Every component is listed (round1.test.ts gates it). `commands` = what a HOST may ask of a surface at runtime. `rules` = what holds for every component. Round 2 (docs/round-2-contract.md): Resizable, `scrollToIndex`, sections, the per-node direction rule. Append-only; docs/components.generated.json carries each component's entry.",
1275
+ roles: [
1276
+ "alert",
1277
+ "alertdialog",
1278
+ "banner",
1279
+ "button",
1280
+ "checkbox",
1281
+ "combobox",
1282
+ "dialog",
1283
+ "document",
1284
+ "form",
1285
+ "group",
1286
+ "heading",
1287
+ "hidden",
1288
+ "img",
1289
+ "link",
1290
+ "list",
1291
+ "listitem",
1292
+ "main",
1293
+ "menu",
1294
+ "meter",
1295
+ "navigation",
1296
+ "none",
1297
+ "progressbar",
1298
+ "radio",
1299
+ "radiogroup",
1300
+ "region",
1301
+ "separator",
1302
+ "slider",
1303
+ "spinbutton",
1304
+ "status",
1305
+ "switch",
1306
+ "tablist",
1307
+ "table",
1308
+ "text",
1309
+ "textbox",
1310
+ "tooltip",
1311
+ "tree",
1312
+ "treeitem"
1313
+ ],
1314
+ rules: [
1315
+ "Every interactive node is reachable by Tab in reading order (tree order; a node's resolved `direction` flips its rows) and shows a focus ring only for keyboard focus (`:focus-visible`, recipe state `focus`).",
1316
+ "A field's label, description and every error are linked to it (aria-labelledby / aria-describedby, contentDescription, accessibilityLabel/Hint); an error has the id `<node id>.error`.",
1317
+ "`visible: false` removes the node from the accessibility tree; `visibility: hidden` hides it too; `display: none` likewise.",
1318
+ "Icon-only buttons and standalone Icons take their `label` (or `accessibility.label`) as the accessible name; decorative icons are hidden.",
1319
+ "`accessibility.label`/`description` on any node override the computed name/description.",
1320
+ "Animations honour reduced motion: with `prefers-reduced-motion: reduce` transitions run at 0 ms, the Spinner/Skeleton shimmer stops and every style `animation` shows its rest keyframe.",
1321
+ "Text and accessible names follow the NODE's direction (an inner `direction` box included): reading order, `textAlign` start/end and the bidi paragraph direction."
1322
+ ],
1323
+ commands: {
1324
+ focus: {
1325
+ args: [
1326
+ "id"
1327
+ ],
1328
+ description: "Moves keyboard focus to the node with this id (the first focusable descendant of a non-focusable node); ignored when it is not rendered."
1329
+ },
1330
+ announce: {
1331
+ args: [
1332
+ "text",
1333
+ "live"
1334
+ ],
1335
+ description: "Speaks the text through the platform's live region (`polite` waits, `assertive` interrupts) without showing anything."
1336
+ },
1337
+ scrollIntoView: {
1338
+ args: [
1339
+ "id"
1340
+ ],
1341
+ description: "Scrolls the nearest scrolling ancestor (List, ScrollArea, the surface) so the node is visible."
1342
+ },
1343
+ scrollToIndex: {
1344
+ args: [
1345
+ "id",
1346
+ "index",
1347
+ "align"
1348
+ ],
1349
+ description: "Scrolls the List or Table `id` so its item (data index, before any local sort) is in view: `align` start | center | end | nearest (default), the pinned section header subtracted; a windowed list renders it first (src/list.ts scrollOffsetForIndex)."
1350
+ }
1351
+ },
1352
+ components: {
1353
+ Box: {
1354
+ role: "none",
1355
+ notes: "group (button when pressable). A pressable Box is a button.",
1356
+ keys: [
1357
+ "Enter, Space: press (pressable only)"
1358
+ ]
1359
+ },
1360
+ Stack: {
1361
+ role: "none",
1362
+ notes: "none (layout only)",
1363
+ keys: []
1364
+ },
1365
+ Grid: {
1366
+ role: "none",
1367
+ notes: "none (layout only)",
1368
+ keys: []
1369
+ },
1370
+ Card: {
1371
+ role: "group",
1372
+ notes: "group labelled by its title",
1373
+ keys: []
1374
+ },
1375
+ Separator: {
1376
+ role: "separator",
1377
+ notes: "separator",
1378
+ keys: []
1379
+ },
1380
+ ScrollArea: {
1381
+ role: "region",
1382
+ notes: "region (scrollable, focusable when it overflows)",
1383
+ keys: [
1384
+ "Arrow keys, PageUp/PageDown, Home/End scroll while focused"
1385
+ ]
1386
+ },
1387
+ Section: {
1388
+ role: "group",
1389
+ notes: "group; the header a heading (level 3) with the caption and count in its name, or a button with aria-expanded when collapsible; the rows a list (a tree when `tree`) of listitems",
1390
+ keys: [
1391
+ "Enter, Space: fold when collapsible"
1392
+ ]
1393
+ },
1394
+ Group: {
1395
+ role: "group",
1396
+ notes: "group labelled by its title, described by its footer",
1397
+ keys: []
1398
+ },
1399
+ Heading: {
1400
+ role: "heading",
1401
+ notes: "heading (level from h1–h4)",
1402
+ keys: []
1403
+ },
1404
+ Kbd: {
1405
+ role: "text",
1406
+ notes: "text (the shortcut spelled out)",
1407
+ keys: []
1408
+ },
1409
+ Label: {
1410
+ role: "text",
1411
+ notes: "label of the control named by `for`",
1412
+ keys: [
1413
+ "Pressing it focuses that control"
1414
+ ]
1415
+ },
1416
+ Badge: {
1417
+ role: "text",
1418
+ notes: "text (status)",
1419
+ keys: []
1420
+ },
1421
+ Alert: {
1422
+ role: "alert",
1423
+ notes: "alert for warning/error, status otherwise. alert for warning/error, status otherwise ($a11y).",
1424
+ keys: []
1425
+ },
1426
+ EmptyState: {
1427
+ role: "status",
1428
+ notes: "status; the action = button",
1429
+ keys: [
1430
+ "Enter, Space on the action"
1431
+ ]
1432
+ },
1433
+ Progress: {
1434
+ role: "progressbar",
1435
+ notes: "progressbar (valuenow/valuemax, labelled by its label)",
1436
+ keys: []
1437
+ },
1438
+ Meter: {
1439
+ role: "meter",
1440
+ notes: "meter (value of max, labelled by its label)",
1441
+ keys: []
1442
+ },
1443
+ Sparkline: {
1444
+ role: "img",
1445
+ notes: "img with a generated summary (first, last, min, max). The Chart painter names it with `sparklineSummary` (first, last, min, max).",
1446
+ keys: []
1447
+ },
1448
+ List: {
1449
+ role: "list",
1450
+ notes: "list; each item a listitem with its position in the WHOLE list (aria-setsize/posinset, also when windowed); a section header is a heading (level 3) and stays first in reading order while pinned",
1451
+ keys: [
1452
+ "Tab moves through the rows' controls; the list itself is one scroll region"
1453
+ ]
1454
+ },
1455
+ Resizable: {
1456
+ role: "group",
1457
+ notes: "group; each handle a focusable separator (aria-orientation = the line's, valuenow = the size of the panel before it, valuemin/max = its limits, controls = that panel), named `$string.resize`",
1458
+ keys: [
1459
+ "Arrow keys on a handle: move it on screen by 10 points (Left/Right horizontal, Up/Down vertical; rtl: ArrowRight shrinks the first panel)",
1460
+ "Home / End: the panel before the handle to its min / max",
1461
+ "Enter: collapse or reopen a collapsible panel"
1462
+ ]
1463
+ },
1464
+ Text: {
1465
+ role: "text",
1466
+ notes: "text (a live region when `live` is not off)",
1467
+ keys: []
1468
+ },
1469
+ Markdown: {
1470
+ role: "document",
1471
+ notes: "document fragment (headings, lists, links, tables keep their roles)",
1472
+ keys: [
1473
+ "Tab moves through the links"
1474
+ ]
1475
+ },
1476
+ CodeBlock: {
1477
+ role: "region",
1478
+ notes: "region (code), copy = button",
1479
+ keys: [
1480
+ "Tab reaches the copy button; Enter, Space: copy and announce `copied`"
1481
+ ]
1482
+ },
1483
+ Image: {
1484
+ role: "img",
1485
+ notes: "img (alt = name; decorative when alt is empty)",
1486
+ keys: []
1487
+ },
1488
+ Icon: {
1489
+ role: "img",
1490
+ notes: "img when labelled, hidden otherwise",
1491
+ keys: []
1492
+ },
1493
+ Video: {
1494
+ role: "group",
1495
+ notes: "video with the platform's controls",
1496
+ keys: [
1497
+ "Space: play/pause; ArrowLeft/ArrowRight: seek 5 s"
1498
+ ]
1499
+ },
1500
+ AudioPlayer: {
1501
+ role: "group",
1502
+ notes: "audio with the platform's controls",
1503
+ keys: [
1504
+ "Space: play/pause; ArrowLeft/ArrowRight: seek 5 s"
1505
+ ]
1506
+ },
1507
+ Avatar: {
1508
+ role: "img",
1509
+ notes: "img (name)",
1510
+ keys: []
1511
+ },
1512
+ Carousel: {
1513
+ role: "region",
1514
+ notes: "region, roledescription carousel; each page a group `page i of n`",
1515
+ keys: [
1516
+ "ArrowLeft/ArrowRight: previous/next page while focus is inside",
1517
+ "Home/End: first/last page"
1518
+ ]
1519
+ },
1520
+ Tabs: {
1521
+ role: "tablist",
1522
+ notes: "tablist / tab / tabpanel",
1523
+ keys: [
1524
+ "Roving tab stop on the tabs",
1525
+ "ArrowLeft/ArrowRight: previous/next tab, activating it (wraps)",
1526
+ "Home/End: first/last tab",
1527
+ "Tab: into the active panel",
1528
+ "Each close glyph (labelled `closeTab`, revealed by keyboard focus too) is a button after its tab; the + button (labelled `newTab`) follows the last tab"
1529
+ ]
1530
+ },
1531
+ Segmented: {
1532
+ role: "radiogroup",
1533
+ notes: "radiogroup (single) or toolbar of toggle buttons (multiple); `bar` = navigation of buttons, the selected one aria-current=page",
1534
+ keys: [
1535
+ "Roving tab stop",
1536
+ "ArrowLeft/ArrowRight (ArrowUp/ArrowDown): move focus (wraps)",
1537
+ "Home/End: first/last",
1538
+ "Space, Enter: toggle the focused item"
1539
+ ]
1540
+ },
1541
+ Accordion: {
1542
+ role: "group",
1543
+ notes: "headers = buttons with aria-expanded controlling regions",
1544
+ keys: [
1545
+ "Enter, Space: toggle the focused section",
1546
+ "ArrowDown/ArrowUp: next/previous header",
1547
+ "Home/End: first/last header"
1548
+ ]
1549
+ },
1550
+ Dialog: {
1551
+ role: "dialog",
1552
+ notes: "dialog (modal)",
1553
+ keys: [
1554
+ "Opening moves focus to the first focusable child (else the dialog)",
1555
+ "Tab cycles inside the dialog (focus trap)",
1556
+ "Escape: close when dismissible",
1557
+ "Closing returns focus to the trigger"
1558
+ ]
1559
+ },
1560
+ Drawer: {
1561
+ role: "dialog",
1562
+ notes: "dialog (modal)",
1563
+ keys: [
1564
+ "As Dialog; a swipe toward the edge closes when dragToDismiss"
1565
+ ]
1566
+ },
1567
+ DockCard: {
1568
+ role: "button",
1569
+ notes: "trigger = button named `label: title` ($a11y); the sheet is a Drawer (dialog, modal).",
1570
+ keys: [
1571
+ "Enter, Space: open the sheet",
1572
+ "As Drawer once open"
1573
+ ]
1574
+ },
1575
+ Popover: {
1576
+ role: "dialog",
1577
+ notes: "dialog (non-modal)",
1578
+ keys: [
1579
+ "Enter, Space on the trigger: open",
1580
+ "Escape: close and return focus to the trigger",
1581
+ "openOn hover also opens on trigger focus"
1582
+ ]
1583
+ },
1584
+ Tooltip: {
1585
+ role: "tooltip",
1586
+ notes: "tooltip describing its anchor",
1587
+ keys: [
1588
+ "Shows on hover AND keyboard focus of the anchor (after the platform delay); Escape hides"
1589
+ ]
1590
+ },
1591
+ Menu: {
1592
+ role: "menu",
1593
+ notes: "menu / menuitem / menuitemcheckbox / group / separator; `openOn: contextmenu` opens at the pointer",
1594
+ keys: [
1595
+ "Enter, Space, ArrowDown on the trigger: open on the first item; ArrowUp: open on the last",
1596
+ "Shift+F10 or the Menu key on the focused child (contextmenu): open at the child",
1597
+ "ArrowDown/ArrowUp: next/previous item (wraps, skips disabled)",
1598
+ "Home/End: first/last item",
1599
+ "Enter, Space: run the item (a checkbox item toggles and stays open)",
1600
+ "ArrowRight on a submenu: open it; ArrowLeft or Escape inside: close it",
1601
+ "A searchable submenu opens with its filter input focused: typing filters, ArrowDown/ArrowUp move the active row, Enter picks it, ArrowLeft with the caret at the start or Escape closes it",
1602
+ "Escape: close and return focus to the trigger",
1603
+ "Typing a letter: the next item starting with it"
1604
+ ]
1605
+ },
1606
+ Toast: {
1607
+ role: "status",
1608
+ notes: "status (polite); alert (assertive) for type error",
1609
+ keys: [
1610
+ "Never takes focus on appear; Tab reaches its action and close",
1611
+ "Escape on a focused toast: dismiss",
1612
+ "Hover or focus pauses the duration timer"
1613
+ ]
1614
+ },
1615
+ Ring: {
1616
+ role: "progressbar",
1617
+ notes: "progressbar (value 0..1 as percent)",
1618
+ keys: []
1619
+ },
1620
+ Spinner: {
1621
+ role: "progressbar",
1622
+ notes: "progressbar (indeterminate) labelled `loading` by default",
1623
+ keys: []
1624
+ },
1625
+ Skeleton: {
1626
+ role: "hidden",
1627
+ notes: "hidden (the parent announces busy)",
1628
+ keys: []
1629
+ },
1630
+ Table: {
1631
+ role: "table",
1632
+ notes: "table (grid when selectable): columnheader with aria-sort, row with aria-selected",
1633
+ keys: [
1634
+ "Enter, Space on a sortable header: cycle the sort (asc, desc)",
1635
+ "Space on a row checkbox: toggle the row; on the header checkbox: select all",
1636
+ "Enter on a focused row: rowPress",
1637
+ "Tab moves through headers, checkboxes and cell controls"
1638
+ ]
1639
+ },
1640
+ Chart: {
1641
+ role: "img",
1642
+ notes: "img with a generated summary (kind, series, ranges); a data table fallback for screen readers. The painter names it with `chartSummary` (series, min, max) and offers a data table fallback.",
1643
+ keys: [
1644
+ "ArrowLeft/ArrowRight while focused: move the tooltip between categories"
1645
+ ]
1646
+ },
1647
+ Button: {
1648
+ role: "button",
1649
+ notes: "button (aria-busy while loading)",
1650
+ keys: [
1651
+ "Enter, Space: press",
1652
+ "A `submit` button submits the enclosing Form"
1653
+ ]
1654
+ },
1655
+ Link: {
1656
+ role: "link",
1657
+ notes: "link",
1658
+ keys: [
1659
+ "Enter: open / press"
1660
+ ]
1661
+ },
1662
+ Toggle: {
1663
+ role: "button",
1664
+ notes: "button with aria-pressed",
1665
+ keys: [
1666
+ "Enter, Space: toggle"
1667
+ ]
1668
+ },
1669
+ Form: {
1670
+ role: "form",
1671
+ notes: "form",
1672
+ keys: [
1673
+ "Enter in a single-line field: submit",
1674
+ "A failed submit focuses the first invalid field and announces `invalidFields`"
1675
+ ]
1676
+ },
1677
+ Input: {
1678
+ role: "textbox",
1679
+ notes: "textbox",
1680
+ keys: [
1681
+ "Enter: submit (fires `submit`, submits the Form)"
1682
+ ]
1683
+ },
1684
+ Textarea: {
1685
+ role: "textbox",
1686
+ notes: "textbox (multiline)",
1687
+ keys: [
1688
+ "Enter: newline"
1689
+ ]
1690
+ },
1691
+ NumberField: {
1692
+ role: "spinbutton",
1693
+ notes: "spinbutton (valuemin/valuemax/valuenow)",
1694
+ keys: [
1695
+ "ArrowUp/ArrowDown: ± step (Shift: ×10)",
1696
+ "PageUp/PageDown: ± 10 steps",
1697
+ "Home/End: min/max",
1698
+ "Enter or blur: commit and clamp"
1699
+ ]
1700
+ },
1701
+ Checkbox: {
1702
+ role: "checkbox",
1703
+ notes: "checkbox",
1704
+ keys: [
1705
+ "Space: toggle"
1706
+ ]
1707
+ },
1708
+ Radio: {
1709
+ role: "radiogroup",
1710
+ notes: "radiogroup / radio",
1711
+ keys: [
1712
+ "Roving tab stop on the checked option",
1713
+ "ArrowDown/ArrowRight: next option, selecting it (wraps)",
1714
+ "ArrowUp/ArrowLeft: previous option"
1715
+ ]
1716
+ },
1717
+ ChoiceTiles: {
1718
+ role: "radiogroup",
1719
+ notes: "radiogroup of radio tiles (single) or a group of checkbox tiles (multiple); the picture is decorative, the label names the tile",
1720
+ keys: [
1721
+ "Roving tab stop on the picked tile (the first when none)",
1722
+ "ArrowRight/ArrowLeft, ArrowDown/ArrowUp: move focus (wraps); single: picks",
1723
+ "Space, Enter: toggle the focused tile"
1724
+ ]
1725
+ },
1726
+ Switch: {
1727
+ role: "switch",
1728
+ notes: "switch; the label (and description) first, the switch at the end; the whole row toggles",
1729
+ keys: [
1730
+ "Space, Enter: toggle"
1731
+ ]
1732
+ },
1733
+ Slider: {
1734
+ role: "slider",
1735
+ notes: "slider",
1736
+ keys: [
1737
+ "ArrowRight/ArrowUp: + step; ArrowLeft/ArrowDown: - step",
1738
+ "PageUp/PageDown: ± 10 steps",
1739
+ "Home/End: min/max"
1740
+ ]
1741
+ },
1742
+ Select: {
1743
+ role: "combobox",
1744
+ notes: "combobox + listbox / option",
1745
+ keys: [
1746
+ "Enter, Space, ArrowDown: open on the selected option",
1747
+ "ArrowDown/ArrowUp: move the active option; Home/End: first/last",
1748
+ "Enter: choose (multiple: toggle and stay open)",
1749
+ "Escape: close without change",
1750
+ "Typing: jump to the next matching option; with `searchable`, typing filters, focus stays in the search field and arrows move the active option (aria-activedescendant)"
1751
+ ]
1752
+ },
1753
+ SearchList: {
1754
+ role: "combobox",
1755
+ notes: "combobox (the input) controlling a listbox of options; the highlighted row = aria-activedescendant, the count a polite status",
1756
+ keys: [
1757
+ "Focus stays in the input",
1758
+ "ArrowDown/ArrowUp: move the highlighted row (no wrap, no animation)",
1759
+ "Enter or Tab: pick the highlighted row (fires `select`)",
1760
+ "Typing: filters; the top row is highlighted again"
1761
+ ]
1762
+ },
1763
+ ChipInput: {
1764
+ role: "textbox",
1765
+ notes: "textbox with a list of removable chips",
1766
+ keys: [
1767
+ "Enter or comma: add the typed entry",
1768
+ "Backspace in an empty field: focus the last chip, again: remove it",
1769
+ "ArrowLeft/ArrowRight: move between chips; Delete, Backspace: remove the focused chip",
1770
+ "ArrowDown: open the suggestions (as Select)"
1771
+ ]
1772
+ },
1773
+ DatePicker: {
1774
+ role: "combobox",
1775
+ notes: "combobox opening a dialog with a grid of days",
1776
+ keys: [
1777
+ "Enter, Space, ArrowDown: open on the selected (else today's) day",
1778
+ "Arrow keys: ± 1 day / ± 1 week",
1779
+ "PageUp/PageDown: previous/next month (Shift: year)",
1780
+ "Home/End: start/end of the week (locale week start)",
1781
+ "Enter, Space: choose; Escape: close"
1782
+ ]
1783
+ },
1784
+ DateRangePicker: {
1785
+ role: "combobox",
1786
+ notes: "as DatePicker; the second choice ends the range",
1787
+ keys: [
1788
+ "As DatePicker; the first Enter sets the start, the second the end"
1789
+ ]
1790
+ },
1791
+ TimePicker: {
1792
+ role: "combobox",
1793
+ notes: "combobox + listbox",
1794
+ keys: [
1795
+ "As Select; typing `HH:mm` into the field commits on Enter or blur"
1796
+ ]
1797
+ },
1798
+ FileUpload: {
1799
+ role: "button",
1800
+ notes: "button (the drop zone) + a list of files with remove buttons",
1801
+ keys: [
1802
+ "Enter, Space on the drop zone: open the file picker",
1803
+ "Tab reaches each file's remove button"
1804
+ ]
1805
+ },
1806
+ Composer: {
1807
+ role: "textbox",
1808
+ notes: "textbox (multiline) + send button",
1809
+ keys: [
1810
+ "Enter: submit; Shift+Enter: newline",
1811
+ "Escape while busy: stop"
1812
+ ]
1813
+ },
1814
+ TreeGuides: {
1815
+ role: "hidden",
1816
+ notes: "hidden (decorative; a Row part)",
1817
+ keys: []
1818
+ },
1819
+ Unknown: {
1820
+ role: "group",
1821
+ notes: "group labelled `unknownComponent`",
1822
+ keys: []
1823
+ },
1824
+ Collapsible: {
1825
+ role: "group",
1826
+ notes: "trigger = button with aria-expanded. The trigger is a button with aria-expanded = open ($a11y).",
1827
+ keys: [
1828
+ "Enter, Space: toggle"
1829
+ ]
1830
+ },
1831
+ Pagination: {
1832
+ role: "navigation",
1833
+ notes: "navigation of two buttons and a status. Labelled `pagination`; previous/next buttons and a status labelled `pageOf` ($a11y).",
1834
+ keys: [
1835
+ "Enter, Space on previous/next"
1836
+ ]
1837
+ },
1838
+ Breadcrumb: {
1839
+ role: "navigation",
1840
+ notes: "navigation (breadcrumb); the last item aria-current=page. Labelled `breadcrumb`; the last item aria-current=page ($a11y).",
1841
+ keys: [
1842
+ "Tab through the links; Enter: select"
1843
+ ]
1844
+ },
1845
+ Stepper: {
1846
+ role: "list",
1847
+ notes: "list; the current step aria-current=step. Each step a listitem labelled `stepDone`/`stepCurrent`/`stepUpcoming`; the current one aria-current=step ($a11y).",
1848
+ keys: []
1849
+ },
1850
+ Rating: {
1851
+ role: "group",
1852
+ notes: 'A group of star buttons: each labelled `ratingStar` ("3 of 5"), the chosen one aria-pressed; read-only stars leave the tree and the group is an img labelled `ratingValue` ($a11y).',
1853
+ keys: [
1854
+ "Tab through the stars; Enter, Space: rate"
1855
+ ]
1856
+ },
1857
+ AlertDialog: {
1858
+ role: "alertdialog",
1859
+ notes: "alertdialog. The cancel button takes focus on open (`autoFocus`, $a11y).",
1860
+ keys: [
1861
+ "Opening focuses the cancel button",
1862
+ "Escape: cancel; clicks outside are ignored"
1863
+ ]
1864
+ },
1865
+ Sidebar: {
1866
+ role: "none",
1867
+ notes: "navigation landmark (the sidebar slot) beside main. Layout only; its `sidebar` part is a navigation landmark, its `main` part the main landmark ($a11y).",
1868
+ keys: []
1869
+ },
1870
+ AppBar: {
1871
+ role: "banner",
1872
+ notes: "banner (heading level 1 = the title). The title is heading level 1; the back button is labelled `back` ($a11y).",
1873
+ keys: [
1874
+ "Enter, Space on back"
1875
+ ]
1876
+ },
1877
+ Row: {
1878
+ role: "button",
1879
+ notes: "button (aria-selected when selected) when pressable, a group of its texts otherwise ($a11y); the guides are decorative",
1880
+ keys: [
1881
+ "Enter, Space: press (pressable only)"
1882
+ ]
1883
+ },
1884
+ Trace: {
1885
+ role: "none",
1886
+ notes: "Layout only: a column of TraceItem lines.",
1887
+ keys: []
1888
+ },
1889
+ TraceItem: {
1890
+ role: "group",
1891
+ notes: "A collapsible line is a button with aria-expanded = open ($a11y); a plain line is text; the icon is decorative.",
1892
+ keys: [
1893
+ "Enter, Space: toggle (collapsible only)"
1894
+ ]
1895
+ },
1896
+ Chip: {
1897
+ role: "button",
1898
+ notes: "button with aria-pressed (= selected) when pressable, text otherwise ($a11y); remove = button labelled `remove`",
1899
+ keys: [
1900
+ "Enter, Space: press; Delete, Backspace: remove when removable"
1901
+ ]
1902
+ },
1903
+ Page: {
1904
+ role: "none",
1905
+ notes: "Layout only: its header is the AppBar (banner, the title heading level 1), its body the main landmark ($a11y).",
1906
+ keys: [
1907
+ "Enter, Space on back"
1908
+ ]
1909
+ },
1910
+ Toolbar: {
1911
+ role: "group",
1912
+ notes: "group of controls in reading order; the trailing action last",
1913
+ keys: []
1914
+ },
1915
+ SplitView: {
1916
+ role: "none",
1917
+ notes: "Layout only: the `list` part is a navigation landmark, the `detail` part the main landmark; the phone back button is labelled `back` ($a11y).",
1918
+ keys: [
1919
+ "Enter, Space on back"
1920
+ ]
1921
+ },
1922
+ FieldGroup: {
1923
+ role: "group",
1924
+ notes: "group of fields; each field keeps its own label",
1925
+ keys: []
1926
+ },
1927
+ FormActions: {
1928
+ role: "group",
1929
+ notes: "group: Cancel, then the submit (the last in focus order)",
1930
+ keys: [
1931
+ "Enter, Space on a button"
1932
+ ]
1933
+ },
1934
+ StatTile: {
1935
+ role: "group",
1936
+ notes: "group labelled by its label; the sparkline is an img with the generated summary",
1937
+ keys: []
1938
+ }
1939
+ }
1940
+ };
1941
+
1942
+ // packages/exponential-ui/src/a11y.ts
1943
+ var A11Y_ROLES = a11y_default.roles;
1944
+ var A11Y_RULES = a11y_default.rules;
1945
+ var A11Y_COMMANDS = a11y_default.commands;
1946
+ var COMPONENT_A11Y = a11y_default.components;
1947
+ function componentA11y(name) {
1948
+ return COMPONENT_A11Y[name];
1949
+ }
1950
+ function isA11yRole(value) {
1951
+ return typeof value === `string` && A11Y_ROLES.includes(value);
1952
+ }
1953
+ // packages/exponential-ui/src/chart.ts
1954
+ function chartExtent(kind, series, min, max) {
1955
+ let lo = Infinity;
1956
+ let hi = -Infinity;
1957
+ if (kind === `stackedBar`) {
1958
+ let n = 0;
1959
+ for (const s of series)
1960
+ n = Math.max(n, s.values.length);
1961
+ for (let i = 0;i < n; i++) {
1962
+ let pos = 0;
1963
+ let neg = 0;
1964
+ for (const s of series) {
1965
+ const v = s.values[i];
1966
+ if (!Number.isFinite(v))
1967
+ continue;
1968
+ if (v > 0)
1969
+ pos += v;
1970
+ else
1971
+ neg += v;
1972
+ }
1973
+ if (pos > hi)
1974
+ hi = pos;
1975
+ if (neg < lo)
1976
+ lo = neg;
1977
+ }
1978
+ } else {
1979
+ for (const s of series)
1980
+ for (const v of s.values) {
1981
+ if (!Number.isFinite(v))
1982
+ continue;
1983
+ if (v < lo)
1984
+ lo = v;
1985
+ if (v > hi)
1986
+ hi = v;
1987
+ }
1988
+ }
1989
+ if (kind !== `sparkline`) {
1990
+ lo = Math.min(0, lo);
1991
+ hi = Math.max(0, hi);
1992
+ }
1993
+ if (!Number.isFinite(lo))
1994
+ lo = 0;
1995
+ if (!Number.isFinite(hi))
1996
+ hi = 0;
1997
+ lo = min ?? lo;
1998
+ hi = max ?? hi;
1999
+ if (hi <= lo)
2000
+ hi = lo + 1;
2001
+ return { min: lo, max: hi };
2002
+ }
2003
+ function chartSummaryParams(series) {
2004
+ let lo = Infinity;
2005
+ let hi = -Infinity;
2006
+ for (const s of series)
2007
+ for (const v of s.values) {
2008
+ if (!Number.isFinite(v))
2009
+ continue;
2010
+ if (v < lo)
2011
+ lo = v;
2012
+ if (v > hi)
2013
+ hi = v;
2014
+ }
2015
+ return { series: series.map((s) => s.name).filter(Boolean).join(`, `), min: Number.isFinite(lo) ? lo : 0, max: Number.isFinite(hi) ? hi : 0 };
2016
+ }
2017
+ function sparklineSummaryParams(values) {
2018
+ const finite = values.filter((v) => Number.isFinite(v));
2019
+ if (finite.length === 0)
2020
+ return { first: 0, last: 0, min: 0, max: 0 };
2021
+ let lo = Infinity;
2022
+ let hi = -Infinity;
2023
+ for (const v of finite) {
2024
+ if (v < lo)
2025
+ lo = v;
2026
+ if (v > hi)
2027
+ hi = v;
2028
+ }
2029
+ return { first: finite[0], last: finite[finite.length - 1], min: lo, max: hi };
2030
+ }
2031
+ function niceNum(x, round) {
2032
+ const exp = Math.floor(Math.log10(x));
2033
+ const f = x / 10 ** exp;
2034
+ const nf = round ? f < 1.5 ? 1 : f < 3 ? 2 : f < 7 ? 5 : 10 : f <= 1 ? 1 : f <= 2 ? 2 : f <= 5 ? 5 : 10;
2035
+ return nf * 10 ** exp;
2036
+ }
2037
+ function niceTicks(min, max, target = 5) {
2038
+ const lo = Math.min(min, max);
2039
+ const hi = max === min ? min + 1 : Math.max(min, max);
2040
+ const range = niceNum(hi - lo, false);
2041
+ const step = niceNum(range / Math.max(1, target - 1), true);
2042
+ const decimals = Math.max(0, -Math.floor(Math.log10(step)));
2043
+ const fix = (v) => Number(v.toFixed(decimals));
2044
+ const niceMin = fix(Math.floor(lo / step) * step);
2045
+ const niceMax = fix(Math.ceil(hi / step) * step);
2046
+ const ticks = [];
2047
+ for (let v = niceMin, i = 0;v <= niceMax + step / 2 && i < 100; i++, v = niceMin + i * step)
2048
+ ticks.push(fix(v));
2049
+ return { min: niceMin, max: niceMax, step, ticks };
2050
+ }
2051
+ function seriesColor(index, tone) {
2052
+ if (tone)
2053
+ return tone === `danger` ? `$color.destructive` : tone === `neutral` ? `$color.mutedForeground` : `$color.${tone}`;
2054
+ return `$color.chart${index % 8 + 1}`;
2055
+ }
2056
+ var DONUT_HOLE = 0.6;
2057
+ // packages/exponential-ui/src/extension.ts
2058
+ var CATALOG_ID = /^https?:\/\/[^\s]+$/;
2059
+ var NAME = /^[A-Z][A-Za-z0-9]*$/;
2060
+ function validateExtension(def) {
2061
+ const errors = [];
2062
+ if (!CATALOG_ID.test(def.id))
2063
+ errors.push(`id must be a URL-shaped catalog id`);
2064
+ if (def.extends !== CORE_CATALOG_ID2)
2065
+ errors.push(`extends must be ${CORE_CATALOG_ID2}`);
2066
+ if (!def.name)
2067
+ errors.push(`name is required`);
2068
+ const names = Object.keys(def.components);
2069
+ if (names.length === 0)
2070
+ errors.push(`an extension defines at least one component`);
2071
+ for (const [name, component] of Object.entries(def.components)) {
2072
+ if (!NAME.test(name))
2073
+ errors.push(`${name}: component names are PascalCase`);
2074
+ if (name in coreCatalog2.components)
2075
+ errors.push(`${name}: shadows a core component`);
2076
+ if (!component.description)
2077
+ errors.push(`${name}: description is required`);
2078
+ for (const [prop, schema] of Object.entries(component.props)) {
2079
+ if (!schema.description)
2080
+ errors.push(`${name}.${prop}: description is required`);
2081
+ if (schema.type === `enum` && schema.enum && !(schema.enum in coreCatalog2.enums) && !(schema.enum in (def.enums ?? {})))
2082
+ errors.push(`${name}.${prop}: enum ${schema.enum} is not defined`);
2083
+ if (schema.type === `object` && schema.shape && !(schema.shape in coreCatalog2.defs) && !(schema.shape in (def.defs ?? {})))
2084
+ errors.push(`${name}.${prop}: shape ${schema.shape} is not defined`);
2085
+ }
2086
+ if (component.kind === `macro` && !def.macros?.[name])
2087
+ errors.push(`${name}: a macro needs a template in macros`);
2088
+ }
2089
+ for (const name of Object.keys(def.macros ?? {})) {
2090
+ if (def.components[name]?.kind !== `macro`)
2091
+ errors.push(`macros.${name}: no macro component of that name`);
2092
+ }
2093
+ for (const name of Object.keys(def.enums ?? {})) {
2094
+ if (name in coreCatalog2.enums)
2095
+ errors.push(`enums.${name}: shadows a core enum`);
2096
+ }
2097
+ return errors;
2098
+ }
2099
+ function defineExtension(def) {
2100
+ const errors = validateExtension(def);
2101
+ if (errors.length > 0)
2102
+ throw new Error(`extension ${def.id}:
2103
+ ${errors.join(`
2104
+ `)}`);
2105
+ return def;
2106
+ }
2107
+ // packages/exponential-ui/src/define.ts
2108
+ var bind = (path) => ({ path });
2109
+ var call = (name, args) => ({ call: name, ...args ? { args } : {} });
2110
+ var event = (name, context) => ({ event: { name, ...context ? { context } : {} } });
2111
+ var run = (name, args) => ({ functionCall: call(name, args) });
2112
+ var ui = Object.fromEntries(COMPONENT_NAMES2.map((name) => [name, (props, children, extra) => ({ component: name, props, ...children ? { children } : {}, ...extra })]));
2113
+ function el(component, props, children, extra) {
2114
+ return { component, props, ...children ? { children } : {}, ...extra };
2115
+ }
2116
+ function flattenSurface(tree, rootId = `root`) {
2117
+ const out = [];
2118
+ const taken = new Set;
2119
+ const counters = new Map;
2120
+ const nameOf = (n, isRoot) => {
2121
+ if (n.id) {
2122
+ if (taken.has(n.id))
2123
+ throw new Error(`defineSurface: duplicate id "${n.id}"`);
2124
+ taken.add(n.id);
2125
+ return n.id;
2126
+ }
2127
+ if (isRoot && !taken.has(rootId)) {
2128
+ taken.add(rootId);
2129
+ return rootId;
2130
+ }
2131
+ const base = n.component.charAt(0).toLowerCase() + n.component.slice(1);
2132
+ let id;
2133
+ do {
2134
+ const next = (counters.get(base) ?? 0) + 1;
2135
+ counters.set(base, next);
2136
+ id = `${base}-${next}`;
2137
+ } while (taken.has(id));
2138
+ taken.add(id);
2139
+ return id;
2140
+ };
2141
+ const walk = (n, isRoot) => {
2142
+ const id = nameOf(n, isRoot);
2143
+ const flat = { id, component: n.component, ...n.props };
2144
+ if (n.style)
2145
+ flat.style = n.style;
2146
+ if (n.on)
2147
+ flat.on = n.on;
2148
+ if (n.visible !== undefined)
2149
+ flat.visible = n.visible;
2150
+ if (n.accessibility)
2151
+ flat.accessibility = n.accessibility;
2152
+ out.push(flat);
2153
+ if (Array.isArray(n.children))
2154
+ flat.children = n.children.map((c) => walk(c, false));
2155
+ else if (n.children) {
2156
+ const t = walk(n.children.template, false);
2157
+ flat.children = { componentId: t, path: n.children.path, ...n.children.key ? { key: n.children.key } : {} };
2158
+ }
2159
+ if (n.slots)
2160
+ flat.slots = Object.fromEntries(Object.entries(n.slots).map(([slot, child]) => [slot, walk(child, false)]));
2161
+ return id;
2162
+ };
2163
+ walk(tree, true);
2164
+ return out;
2165
+ }
2166
+ function defineSurface(tree, options = {}) {
2167
+ const surfaceId = options.surfaceId ?? `main`;
2168
+ const catalogId = options.catalogId ?? CORE_CATALOG_ID2;
2169
+ const components = flattenSurface(tree);
2170
+ const { root, issues } = reduceSurface2(components, { catalogId, extensions: options.extensions });
2171
+ const messages = [
2172
+ { version: `v0.9`, createSurface: { surfaceId, catalogId } },
2173
+ { version: `v0.9`, updateComponents: { surfaceId, components } },
2174
+ ...Object.entries(options.data ?? {}).map(([path, value]) => ({ version: `v0.9`, updateDataModel: { surfaceId, path, value } }))
2175
+ ];
2176
+ return { surfaceId, catalogId, components, issues, root, messages, jsonl: messages.map((m) => JSON.stringify(m)).join(`
2177
+ `) };
2178
+ }
2179
+ // packages/exponential-ui/src/css.ts
2180
+ var UNITLESS = new Set([`flexGrow`, `flexShrink`, `opacity`, `fontWeight`, `aspectRatio`]);
2181
+ var SHORTHANDS = {
2182
+ paddingHorizontal: [`padding-left`, `padding-right`],
2183
+ paddingVertical: [`padding-top`, `padding-bottom`],
2184
+ paddingInlineStart: [`padding-inline-start`],
2185
+ paddingInlineEnd: [`padding-inline-end`],
2186
+ marginHorizontal: [`margin-left`, `margin-right`],
2187
+ marginVertical: [`margin-top`, `margin-bottom`],
2188
+ marginInlineStart: [`margin-inline-start`],
2189
+ marginInlineEnd: [`margin-inline-end`],
2190
+ insetInlineStart: [`inset-inline-start`],
2191
+ insetInlineEnd: [`inset-inline-end`],
2192
+ insetBlockStart: [`inset-block-start`],
2193
+ insetBlockEnd: [`inset-block-end`],
2194
+ backgroundGradient: [`background-image`],
2195
+ backdropBlur: [`backdrop-filter`]
2196
+ };
2197
+ var FOLDED = new Set([`transitionEasing`, `native`, `animationDuration`]);
2198
+ var kebab = (key) => key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
2199
+ function gradientCss(gradient) {
2200
+ return `linear-gradient(${gradient.angle}deg, ${gradient.stops.map((s) => `${s.color} ${Math.round(s.offset * 1e4) / 100}%`).join(`, `)})`;
2201
+ }
2202
+ function cssString(text) {
2203
+ return `"${text.replace(/\\/g, `\\\\`).replace(/"/g, `\\"`)}"`;
2204
+ }
2205
+ function fontStack(family, fonts) {
2206
+ const fallback = fonts[family]?.fallback;
2207
+ return fallback ? `${cssString(family)}, ${fallback}` : cssString(family);
2208
+ }
2209
+ function cssValue(key, value, fonts, style) {
2210
+ if (key === `boxShadow`)
2211
+ return Array.isArray(value) ? shadowCss2(value) : String(value);
2212
+ if (key === `fontFamily`)
2213
+ return fontStack(String(value), fonts);
2214
+ if (key === `gridTemplateAreas` && Array.isArray(value))
2215
+ return value.map((row) => `"${row}"`).join(` `);
2216
+ if (key === `backgroundGradient`)
2217
+ return typeof value === `object` && value !== null ? gradientCss(value) : null;
2218
+ if (key === `backdropBlur`)
2219
+ return typeof value === `number` ? `blur(${value}px)` : null;
2220
+ if (key === `transition`) {
2221
+ if (typeof value !== `number`)
2222
+ return null;
2223
+ const easing = style.transitionEasing;
2224
+ return `all ${value}ms${Array.isArray(easing) ? ` ${easingCss2(easing)}` : ``}`;
2225
+ }
2226
+ if (typeof value === `number`)
2227
+ return UNITLESS.has(key) ? String(value) : `${value}px`;
2228
+ if (typeof value === `boolean`)
2229
+ return null;
2230
+ return String(value);
2231
+ }
2232
+ function styleToCss(style, fonts = {}, theme) {
2233
+ const out = {};
2234
+ for (const [key, value] of Object.entries(style)) {
2235
+ if (value === undefined || FOLDED.has(key))
2236
+ continue;
2237
+ if (key === `animation`) {
2238
+ const timing = theme && typeof value === `string` ? animationTiming(value, theme) : null;
2239
+ if (!timing)
2240
+ continue;
2241
+ const duration = style.animationDuration;
2242
+ const durationMs = typeof duration === `number` ? duration * (ANIMATIONS[value]?.factor ?? 1) : timing.durationMs;
2243
+ out.animation = animationCss(value, { ...timing, durationMs });
2244
+ continue;
2245
+ }
2246
+ if (key.startsWith(`@`) || key.startsWith(`:`))
2247
+ continue;
2248
+ if (typeof value === `object` && value !== null && !Array.isArray(value) && key !== `backgroundGradient`)
2249
+ continue;
2250
+ const css = cssValue(key, value, fonts, style);
2251
+ if (css === null)
2252
+ continue;
2253
+ const targets = SHORTHANDS[key] ?? [kebab(key)];
2254
+ for (const target of targets)
2255
+ out[target] = css;
2256
+ }
2257
+ if (out.animation && animatesOpacity(String(style.animation)))
2258
+ out.opacity = out.opacity ? `calc(${out.opacity} * var(--xui-a-opacity, 1))` : `var(--xui-a-opacity, 1)`;
2259
+ if (out[`backdrop-filter`])
2260
+ out[`-webkit-backdrop-filter`] = out[`backdrop-filter`];
2261
+ const anyBorder = [`border-width`, `border-top-width`, `border-right-width`, `border-bottom-width`, `border-left-width`].some((k) => out[k] && out[k] !== `0px`);
2262
+ if (anyBorder && !out[`border-style`])
2263
+ out[`border-style`] = `solid`;
2264
+ if (anyBorder && !out[`border-color`])
2265
+ out[`border-color`] = `transparent`;
2266
+ return out;
2267
+ }
2268
+ function styleAttribute(style, fonts = {}) {
2269
+ return Object.entries(styleToCss(style, fonts)).map(([k, v]) => `${k}:${v}`).join(`;`);
2270
+ }
2271
+ // packages/exponential-ui/src/builder.ts
2272
+ var SHADCN_COLOR_VARS = {
2273
+ background: `background`,
2274
+ foreground: `foreground`,
2275
+ card: `card`,
2276
+ "card-foreground": `cardForeground`,
2277
+ popover: `popover`,
2278
+ "popover-foreground": `popoverForeground`,
2279
+ primary: `primary`,
2280
+ "primary-foreground": `primaryForeground`,
2281
+ secondary: `secondary`,
2282
+ "secondary-foreground": `secondaryForeground`,
2283
+ muted: `muted`,
2284
+ "muted-foreground": `mutedForeground`,
2285
+ accent: `accent`,
2286
+ "accent-foreground": `accentForeground`,
2287
+ destructive: `destructive`,
2288
+ "destructive-foreground": `destructiveForeground`,
2289
+ success: `success`,
2290
+ "success-foreground": `successForeground`,
2291
+ warning: `warning`,
2292
+ "warning-foreground": `warningForeground`,
2293
+ info: `info`,
2294
+ "info-foreground": `infoForeground`,
2295
+ border: `border`,
2296
+ input: `input`,
2297
+ ring: `ring`,
2298
+ "chart-1": `chart1`,
2299
+ "chart-2": `chart2`,
2300
+ "chart-3": `chart3`,
2301
+ "chart-4": `chart4`,
2302
+ "chart-5": `chart5`
2303
+ };
2304
+ var BLOCK = /([^{}]+)\{([^{}]*)\}/g;
2305
+ var DECL = /--([a-zA-Z0-9-]+)\s*:\s*([^;]+);?/g;
2306
+ function selectorMode(selector) {
2307
+ const s = selector.trim();
2308
+ if (/\.dark\b|\[data-theme=["']?dark|prefers-color-scheme:\s*dark/.test(s))
2309
+ return `dark`;
2310
+ if (/^(:root|:host|html|body)(\s*,\s*(:root|:host|html|body))*$/.test(s) || /\.light\b/.test(s))
2311
+ return `light`;
2312
+ return null;
2313
+ }
2314
+ function px(value) {
2315
+ const v = value.trim();
2316
+ if (v.endsWith(`rem`))
2317
+ return Math.round(parseFloat(v) * 16 * 100) / 100;
2318
+ if (v.endsWith(`px`))
2319
+ return parseFloat(v);
2320
+ if (v.endsWith(`em`))
2321
+ return Math.round(parseFloat(v) * 16 * 100) / 100;
2322
+ const n = parseFloat(v);
2323
+ return Number.isFinite(n) && /^-?[\d.]+$/.test(v) ? n : null;
2324
+ }
2325
+ function parseShadow(value) {
2326
+ const v = value.trim();
2327
+ if (v === `none`)
2328
+ return [];
2329
+ const layers = [];
2330
+ let depth = 0;
2331
+ let start = 0;
2332
+ const parts = [];
2333
+ for (let i = 0;i < v.length; i++) {
2334
+ if (v[i] === `(`)
2335
+ depth++;
2336
+ else if (v[i] === `)`)
2337
+ depth--;
2338
+ else if (v[i] === `,` && depth === 0) {
2339
+ parts.push(v.slice(start, i));
2340
+ start = i + 1;
2341
+ }
2342
+ }
2343
+ parts.push(v.slice(start));
2344
+ for (const part of parts) {
2345
+ const m = /^\s*(-?[\d.]+(?:px)?)\s+(-?[\d.]+(?:px)?)\s+(-?[\d.]+(?:px)?)(?:\s+(-?[\d.]+(?:px)?))?\s+(.+?)\s*$/.exec(part);
2346
+ if (!m)
2347
+ return null;
2348
+ const color = toThemeHex2(m[5]);
2349
+ if (!color)
2350
+ return null;
2351
+ layers.push({ x: parseFloat(m[1]), y: parseFloat(m[2]), blur: parseFloat(m[3]), spread: m[4] ? parseFloat(m[4]) : 0, color });
2352
+ }
2353
+ return layers;
2354
+ }
2355
+ function firstFamily(value) {
2356
+ const parts = value.split(`,`).map((s) => s.trim().replace(/^["']|["']$/g, ``)).filter(Boolean);
2357
+ return { family: parts[0] ?? value.trim(), fallback: parts.length > 1 ? parts.slice(1).join(`, `) : undefined };
2358
+ }
2359
+ function importShadcnCss(css) {
2360
+ const out = { modes: {}, tokens: {}, fonts: {}, unmapped: [] };
2361
+ const unmapped = new Set;
2362
+ const text = css.replace(/\/\*[\s\S]*?\*\//g, ``);
2363
+ const addFamily = (slot, value) => {
2364
+ const { family, fallback } = firstFamily(value);
2365
+ ((out.tokens.type ??= {}).family ??= {})[slot] = family;
2366
+ out.fonts[family] = { ...fallback ? { fallback } : {}, source: `host` };
2367
+ };
2368
+ for (const block of text.matchAll(BLOCK)) {
2369
+ const mode = selectorMode(block[1]);
2370
+ for (const decl of block[2].matchAll(DECL)) {
2371
+ const name = decl[1];
2372
+ const value = decl[2].trim();
2373
+ const colorName = SHADCN_COLOR_VARS[name];
2374
+ if (colorName) {
2375
+ const hex = toThemeHex2(value);
2376
+ if (!hex || !mode) {
2377
+ unmapped.add(`--${name}`);
2378
+ continue;
2379
+ }
2380
+ (out.modes[mode] ??= { color: {} }).color[colorName] = hex;
2381
+ continue;
2382
+ }
2383
+ if (name === `radius`) {
2384
+ const base = px(value);
2385
+ if (base === null) {
2386
+ unmapped.add(`--${name}`);
2387
+ continue;
2388
+ }
2389
+ out.tokens.radius = {
2390
+ none: 0,
2391
+ sm: Math.max(0, base - 4),
2392
+ md: Math.max(0, base - 2),
2393
+ lg: base,
2394
+ xl: base + 4,
2395
+ xl2: base + 8,
2396
+ xl3: base + 12,
2397
+ full: 9999
2398
+ };
2399
+ continue;
2400
+ }
2401
+ if (name === `font-sans` || name === `font-mono`) {
2402
+ if (value.includes(`var(`))
2403
+ unmapped.add(`--${name}`);
2404
+ else
2405
+ addFamily(name.slice(5), value);
2406
+ continue;
2407
+ }
2408
+ const shadow = /^shadow-(sm|md|lg)$/.exec(name);
2409
+ if (shadow && mode) {
2410
+ const layers = parseShadow(value);
2411
+ if (!layers) {
2412
+ unmapped.add(`--${name}`);
2413
+ continue;
2414
+ }
2415
+ const m = out.modes[mode] ??= { color: {} };
2416
+ (m.shadow ??= {})[shadow[1]] = layers;
2417
+ continue;
2418
+ }
2419
+ unmapped.add(`--${name}`);
2420
+ }
2421
+ }
2422
+ out.unmapped = [...unmapped].sort();
2423
+ return out;
2424
+ }
2425
+ function themeFromImport(imp, meta) {
2426
+ const theme = { $schema: THEME_SCHEMA_ID2, id: meta.id, name: meta.name };
2427
+ if (meta.extends)
2428
+ theme.extends = meta.extends;
2429
+ const modes = {};
2430
+ for (const mode of MODES2) {
2431
+ const m = imp.modes[mode];
2432
+ if (!m)
2433
+ continue;
2434
+ modes[mode] = { color: m.color, ...m.shadow ? { shadow: m.shadow } : {} };
2435
+ if (m.shadow && !m.shadow.none)
2436
+ modes[mode].shadow = { none: [], ...m.shadow };
2437
+ }
2438
+ if (Object.keys(modes).length > 0)
2439
+ theme.modes = modes;
2440
+ const tokens = {};
2441
+ if (imp.tokens.radius)
2442
+ tokens.radius = imp.tokens.radius;
2443
+ if (imp.tokens.type?.family)
2444
+ tokens.type = { family: imp.tokens.type.family };
2445
+ if (Object.keys(tokens).length > 0)
2446
+ theme.tokens = tokens;
2447
+ if (Object.keys(imp.fonts).length > 0)
2448
+ theme.fonts = imp.fonts;
2449
+ return theme;
2450
+ }
2451
+ var same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
2452
+ function diffTheme(full, base, meta) {
2453
+ const resolved = `chain` in full ? full : loadTheme2(full, { themes: [base] });
2454
+ const out = { $schema: THEME_SCHEMA_ID2, id: meta?.id ?? resolved.id, name: meta?.name ?? resolved.name, extends: base.id };
2455
+ const modes = {};
2456
+ for (const mode of MODES2) {
2457
+ const color = {};
2458
+ const shadow = {};
2459
+ for (const [k, v] of Object.entries(resolved.modes[mode].color))
2460
+ if (base.modes[mode].color[k] !== v)
2461
+ color[k] = v;
2462
+ for (const [k, v] of Object.entries(resolved.modes[mode].shadow))
2463
+ if (!same(base.modes[mode].shadow[k], v))
2464
+ shadow[k] = v;
2465
+ const m = {};
2466
+ if (Object.keys(color).length > 0)
2467
+ m.color = color;
2468
+ if (Object.keys(shadow).length > 0)
2469
+ m.shadow = shadow;
2470
+ if (Object.keys(m).length > 0)
2471
+ modes[mode] = m;
2472
+ }
2473
+ if (Object.keys(modes).length > 0)
2474
+ out.modes = modes;
2475
+ const contrast = {};
2476
+ for (const mode of MODES2) {
2477
+ const mine = resolved.contrast?.[mode] ?? { color: {}, shadow: {} };
2478
+ const theirs = base.contrast?.[mode] ?? { color: {}, shadow: {} };
2479
+ const color = {};
2480
+ const shadow = {};
2481
+ for (const [k, v] of Object.entries(mine.color))
2482
+ if (theirs.color[k] !== v)
2483
+ color[k] = v;
2484
+ for (const [k, v] of Object.entries(mine.shadow))
2485
+ if (!same(theirs.shadow[k], v))
2486
+ shadow[k] = v;
2487
+ const m = {};
2488
+ if (Object.keys(color).length > 0)
2489
+ m.color = color;
2490
+ if (Object.keys(shadow).length > 0)
2491
+ m.shadow = shadow;
2492
+ if (Object.keys(m).length > 0)
2493
+ contrast[mode] = m;
2494
+ }
2495
+ if (Object.keys(contrast).length > 0)
2496
+ out.contrast = contrast;
2497
+ const tokens = {};
2498
+ for (const group of Object.keys(TOKEN_GROUPS2)) {
2499
+ if (group === `color` || group === `shadow`)
2500
+ continue;
2501
+ const [top, sub] = group.split(`.`);
2502
+ const mine = sub ? resolved.tokens.type[sub] : resolved.tokens[top];
2503
+ const theirs = sub ? base.tokens.type[sub] : base.tokens[top];
2504
+ const diff = {};
2505
+ for (const [k, v] of Object.entries(mine ?? {}))
2506
+ if (!same(theirs?.[k], v))
2507
+ diff[k] = v;
2508
+ if (Object.keys(diff).length === 0)
2509
+ continue;
2510
+ if (sub)
2511
+ (tokens.type ??= {})[sub] = diff;
2512
+ else
2513
+ tokens[top] = diff;
2514
+ }
2515
+ if (Object.keys(tokens).length > 0)
2516
+ out.tokens = tokens;
2517
+ const fonts = {};
2518
+ for (const [k, v] of Object.entries(resolved.fonts))
2519
+ if (!same(base.fonts[k], v))
2520
+ fonts[k] = v;
2521
+ if (Object.keys(fonts).length > 0)
2522
+ out.fonts = fonts;
2523
+ if (`chain` in full) {
2524
+ const recipes = {};
2525
+ for (const [component, byPart] of Object.entries(resolved.recipes)) {
2526
+ for (const [part, rules] of Object.entries(byPart)) {
2527
+ const baseRules = base.recipes[component]?.[part] ?? [];
2528
+ const tail = rules.slice(baseRules.length);
2529
+ if (tail.length > 0)
2530
+ (recipes[component] ??= {})[part] = tail;
2531
+ }
2532
+ }
2533
+ if (Object.keys(recipes).length > 0)
2534
+ out.recipes = recipes;
2535
+ } else if (full.recipes && Object.keys(full.recipes).length > 0)
2536
+ out.recipes = full.recipes;
2537
+ return out;
2538
+ }
2539
+ function exportThemeJson(theme) {
2540
+ const { $schema: _ignored, ...rest } = theme;
2541
+ return `${JSON.stringify({ $schema: `https://ui.exponential.at/schemas/theme/v1.json`, ...rest }, null, 2)}
2542
+ `;
2543
+ }
2544
+ function parseThemeJson(text, themes) {
2545
+ let source;
2546
+ try {
2547
+ source = JSON.parse(text);
2548
+ } catch (error) {
2549
+ return { theme: null, source: null, issues: [{ path: `theme`, message: `not JSON: ${error.message}` }] };
2550
+ }
2551
+ try {
2552
+ return { theme: loadTheme2(source, { themes }), source, issues: [] };
2553
+ } catch (error) {
2554
+ const issues = error.issues ?? [{ path: `theme`, message: error.message }];
2555
+ return { theme: null, source, issues };
2556
+ }
2557
+ }
2558
+ // packages/exponential-ui/src/geometry.ts
2559
+ var CONTROL_PARTS = {
2560
+ Button: `root`,
2561
+ Toggle: `root`,
2562
+ Segmented: `item`,
2563
+ Input: `field`,
2564
+ Textarea: `field`,
2565
+ Select: `trigger`,
2566
+ DatePicker: `trigger`,
2567
+ Checkbox: `box`,
2568
+ Radio: `item`,
2569
+ Switch: `track`,
2570
+ Slider: `thumb`,
2571
+ Avatar: `root`,
2572
+ Icon: `root`,
2573
+ Spinner: `root`,
2574
+ Ring: `root`,
2575
+ Tabs: `tab`,
2576
+ NumberField: `field`,
2577
+ ChipInput: `field`,
2578
+ TimePicker: `trigger`,
2579
+ DateRangePicker: `trigger`
2580
+ };
2581
+ var GEOMETRY_KEYS = [`width`, `height`, `minWidth`, `minHeight`, `paddingHorizontal`, `paddingVertical`, `padding`, `gap`, `borderWidth`, `borderRadius`];
2582
+ function controlGeometry(theme, component, props = {}, states = []) {
2583
+ const part = CONTROL_PARTS[component] ?? `root`;
2584
+ const style = resolveRecipe2(theme, { component, part, props, states }, `light`);
2585
+ const out = {};
2586
+ for (const key of GEOMETRY_KEYS) {
2587
+ const v = style[key];
2588
+ if (typeof v === `number`)
2589
+ out[key] = v;
2590
+ }
2591
+ return out;
2592
+ }
2593
+ function checkGeometry(expected, measured, tolerance = 0.5) {
2594
+ const issues = [];
2595
+ const probe = (key, actual) => {
2596
+ const want = expected[key];
2597
+ if (want === undefined)
2598
+ return;
2599
+ if (actual === undefined || Math.abs(actual - want) > tolerance)
2600
+ issues.push({ key, expected: want, actual });
2601
+ };
2602
+ probe(`width`, measured.width);
2603
+ if (expected.minHeight === undefined)
2604
+ probe(`height`, measured.height);
2605
+ probe(`paddingHorizontal`, measured.paddingHorizontal);
2606
+ probe(`paddingVertical`, measured.paddingVertical);
2607
+ probe(`borderWidth`, measured.borderWidth);
2608
+ probe(`borderRadius`, measured.borderRadius);
2609
+ if (expected.minHeight !== undefined && (measured.height === undefined || measured.height + tolerance < expected.minHeight))
2610
+ issues.push({ key: `minHeight`, expected: expected.minHeight, actual: measured.height });
2611
+ return issues;
2612
+ }
2613
+ function verifyPainterGeometry(override, theme, cases) {
2614
+ return cases.map((c) => ({
2615
+ name: Object.entries(c.props).map(([k, v]) => `${k}=${String(v)}`).join(`,`) || `default`,
2616
+ issues: checkGeometry(controlGeometry(theme, override.component, c.props, c.states), override.measure(theme, c.props, c.states))
2617
+ })).filter((r) => r.issues.length > 0);
2618
+ }
2619
+ // packages/exponential-ui/src/overlay.ts
2620
+ var OVERLAY_OFFSET = 4;
2621
+ var OVERLAY_PADDING = 8;
2622
+ var OPPOSITE = { top: `bottom`, bottom: `top`, left: `right`, right: `left` };
2623
+ function room(side, anchor, viewport, padding) {
2624
+ switch (side) {
2625
+ case `top`:
2626
+ return anchor.y - padding;
2627
+ case `bottom`:
2628
+ return viewport.height - (anchor.y + anchor.height) - padding;
2629
+ case `left`:
2630
+ return anchor.x - padding;
2631
+ case `right`:
2632
+ return viewport.width - (anchor.x + anchor.width) - padding;
2633
+ }
2634
+ }
2635
+ function placeOverlay(anchor, size, viewport, options = {}) {
2636
+ const preferred = options.side ?? `bottom`;
2637
+ const align = options.align ?? `center`;
2638
+ const offset = options.offset ?? OVERLAY_OFFSET;
2639
+ const padding = options.padding ?? OVERLAY_PADDING;
2640
+ const vertical = preferred === `top` || preferred === `bottom`;
2641
+ const needed = (vertical ? size.height : size.width) + offset;
2642
+ let side = preferred;
2643
+ let flipped = false;
2644
+ if (room(preferred, anchor, viewport, padding) < needed && room(OPPOSITE[preferred], anchor, viewport, padding) > room(preferred, anchor, viewport, padding)) {
2645
+ side = OPPOSITE[preferred];
2646
+ flipped = true;
2647
+ }
2648
+ let x;
2649
+ let y;
2650
+ const alongX = () => align === `start` ? anchor.x : align === `end` ? anchor.x + anchor.width - size.width : anchor.x + anchor.width / 2 - size.width / 2;
2651
+ const alongY = () => align === `start` ? anchor.y : align === `end` ? anchor.y + anchor.height - size.height : anchor.y + anchor.height / 2 - size.height / 2;
2652
+ switch (side) {
2653
+ case `top`:
2654
+ x = alongX();
2655
+ y = anchor.y - offset - size.height;
2656
+ break;
2657
+ case `bottom`:
2658
+ x = alongX();
2659
+ y = anchor.y + anchor.height + offset;
2660
+ break;
2661
+ case `left`:
2662
+ x = anchor.x - offset - size.width;
2663
+ y = alongY();
2664
+ break;
2665
+ case `right`:
2666
+ x = anchor.x + anchor.width + offset;
2667
+ y = alongY();
2668
+ break;
2669
+ }
2670
+ if (vertical === (side === `top` || side === `bottom`)) {
2671
+ if (side === `top` || side === `bottom`)
2672
+ x = Math.min(Math.max(x, padding), Math.max(padding, viewport.width - padding - size.width));
2673
+ else
2674
+ y = Math.min(Math.max(y, padding), Math.max(padding, viewport.height - padding - size.height));
2675
+ } else if (side === `top` || side === `bottom`)
2676
+ x = Math.min(Math.max(x, padding), Math.max(padding, viewport.width - padding - size.width));
2677
+ else
2678
+ y = Math.min(Math.max(y, padding), Math.max(padding, viewport.height - padding - size.height));
2679
+ return { x: round(x), y: round(y), side, flipped };
2680
+ }
2681
+ var round = (n) => Math.round(n * 1000) / 1000;
2682
+ // packages/exponential-ui/src/connector/connector.ts
2683
+ var b64url = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/\+/g, `-`).replace(/\//g, `_`).replace(/=+$/, ``);
2684
+ async function pkcePair() {
2685
+ const verifier = b64url(crypto.getRandomValues(new Uint8Array(32)));
2686
+ const digest = new Uint8Array(await crypto.subtle.digest(`SHA-256`, new TextEncoder().encode(verifier)));
2687
+ return { verifier, challenge: b64url(digest) };
2688
+ }
2689
+
2690
+ class ExponentialConnector {
2691
+ options;
2692
+ metadata;
2693
+ clientId;
2694
+ tokens;
2695
+ rpcId = 0;
2696
+ constructor(options) {
2697
+ this.options = options;
2698
+ this.clientId = options.clientId;
2699
+ this.tokens = options.tokens;
2700
+ }
2701
+ get fetch() {
2702
+ return this.options.fetch ?? fetch;
2703
+ }
2704
+ url(path) {
2705
+ return new URL(path, this.options.baseUrl).href;
2706
+ }
2707
+ async discover() {
2708
+ if (this.metadata)
2709
+ return this.metadata;
2710
+ const res = await this.fetch(this.url(`/.well-known/oauth-authorization-server`));
2711
+ if (!res.ok)
2712
+ throw new Error(`discovery failed: HTTP ${res.status}`);
2713
+ this.metadata = await res.json();
2714
+ return this.metadata;
2715
+ }
2716
+ async register() {
2717
+ if (this.clientId)
2718
+ return this.clientId;
2719
+ const meta = await this.discover();
2720
+ if (!meta.registration_endpoint)
2721
+ throw new Error(`the instance offers no dynamic client registration; pass clientId`);
2722
+ const res = await this.fetch(meta.registration_endpoint, {
2723
+ method: `POST`,
2724
+ headers: { "content-type": `application/json` },
2725
+ body: JSON.stringify({ client_name: this.options.clientName ?? `Exponential UI host`, redirect_uris: [this.options.redirectUri], grant_types: [`authorization_code`, `refresh_token`], response_types: [`code`], token_endpoint_auth_method: `none` })
2726
+ });
2727
+ if (!res.ok)
2728
+ throw new Error(`registration failed: HTTP ${res.status}`);
2729
+ this.clientId = (await res.json()).client_id;
2730
+ return this.clientId;
2731
+ }
2732
+ async authorizeUrl() {
2733
+ const meta = await this.discover();
2734
+ const clientId = await this.register();
2735
+ const { verifier, challenge } = await pkcePair();
2736
+ const state = b64url(crypto.getRandomValues(new Uint8Array(16)));
2737
+ const url = new URL(meta.authorization_endpoint);
2738
+ url.search = new URLSearchParams({ response_type: `code`, client_id: clientId, redirect_uri: this.options.redirectUri, code_challenge: challenge, code_challenge_method: `S256`, state, scope: `openid profile email offline_access` }).toString();
2739
+ return { url: url.href, verifier, state, clientId };
2740
+ }
2741
+ async token(body) {
2742
+ const meta = await this.discover();
2743
+ const res = await this.fetch(meta.token_endpoint, { method: `POST`, headers: { "content-type": `application/x-www-form-urlencoded` }, body: new URLSearchParams({ client_id: this.clientId ?? ``, ...body }).toString() });
2744
+ if (!res.ok)
2745
+ throw new Error(`token request failed: HTTP ${res.status}`);
2746
+ const json = await res.json();
2747
+ this.tokens = { accessToken: json.access_token, refreshToken: json.refresh_token ?? this.tokens?.refreshToken, expiresAt: json.expires_in ? Date.now() + json.expires_in * 1000 : undefined };
2748
+ this.options.onTokens?.(this.tokens);
2749
+ return this.tokens;
2750
+ }
2751
+ async exchange(code, verifier, clientId) {
2752
+ if (clientId)
2753
+ this.clientId = clientId;
2754
+ if (!this.clientId)
2755
+ throw new Error(`no client id for the token exchange; pass the clientId authorizeUrl returned`);
2756
+ return this.token({ grant_type: `authorization_code`, code, code_verifier: verifier, redirect_uri: this.options.redirectUri });
2757
+ }
2758
+ async refresh() {
2759
+ if (!this.tokens?.refreshToken)
2760
+ throw new Error(`no refresh token; authorize again`);
2761
+ return this.token({ grant_type: `refresh_token`, refresh_token: this.tokens.refreshToken });
2762
+ }
2763
+ async callTool(name, args = {}) {
2764
+ if (!this.tokens)
2765
+ throw new Error(`not connected; authorize first`);
2766
+ if (this.tokens.expiresAt && this.tokens.expiresAt < Date.now() + 30000 && this.tokens.refreshToken)
2767
+ await this.refresh();
2768
+ const res = await this.fetch(this.url(`/api/mcp`), {
2769
+ method: `POST`,
2770
+ headers: { "content-type": `application/json`, accept: `application/json, text/event-stream`, authorization: `Bearer ${this.tokens.accessToken}` },
2771
+ body: JSON.stringify({ jsonrpc: `2.0`, id: ++this.rpcId, method: `tools/call`, params: { name, arguments: args } })
2772
+ });
2773
+ if (!res.ok)
2774
+ throw new Error(`MCP HTTP ${res.status}`);
2775
+ const text = await res.text();
2776
+ const line = text.trimStart().startsWith(`{`) ? text : text.split(`
2777
+ `).find((l) => l.startsWith(`data:`))?.slice(5) ?? `{}`;
2778
+ const reply = JSON.parse(line);
2779
+ if (reply.error)
2780
+ throw new Error(reply.error.message ?? `MCP error`);
2781
+ const result = reply.result ?? {};
2782
+ const body = result.structuredContent ?? (result.content ?? []).filter((c) => c.type === `text`).map((c) => c.text ?? ``).join(``);
2783
+ if (result.isError)
2784
+ throw new Error(typeof body === `string` ? body : `tool error`);
2785
+ if (typeof body !== `string`)
2786
+ return body;
2787
+ try {
2788
+ return JSON.parse(body);
2789
+ } catch {
2790
+ return body;
2791
+ }
2792
+ }
2793
+ sources() {
2794
+ return { exp: (source, emit) => this.follow(source, emit) };
2795
+ }
2796
+ follow(source, emit) {
2797
+ const p = source.params;
2798
+ const read = async () => {
2799
+ switch (source.name) {
2800
+ case `issues`: {
2801
+ const args = { limit: Number(p.limit ?? 50) };
2802
+ if (p.board)
2803
+ args.boardId = p.board;
2804
+ if (p.team)
2805
+ args.teamId = p.team;
2806
+ if (p.search)
2807
+ args.search = p.search;
2808
+ return this.callTool(`exponential_issues_list`, args);
2809
+ }
2810
+ case `boards`:
2811
+ return this.callTool(`exponential_boards_list`, p.team ? { teamId: p.team } : {});
2812
+ case `teams`:
2813
+ return this.callTool(`exponential_teams_list`, {});
2814
+ case `members`:
2815
+ return this.callTool(`exponential_members_list`, p.team ? { teamId: p.team } : {});
2816
+ default:
2817
+ return null;
2818
+ }
2819
+ };
2820
+ let live = true;
2821
+ let timer;
2822
+ const seconds = Number(p.poll ?? this.options.pollSeconds ?? 30);
2823
+ const tick = async () => {
2824
+ try {
2825
+ const value = await read();
2826
+ if (!live)
2827
+ return;
2828
+ const rows = Array.isArray(value) ? value : value?.rows;
2829
+ emit(rows ? { rows, count: rows.length } : value);
2830
+ } catch (e) {
2831
+ if (live)
2832
+ emit({ rows: [], count: 0, error: e instanceof Error ? e.message : String(e) });
2833
+ }
2834
+ if (live && seconds > 0)
2835
+ timer = setTimeout(tick, seconds * 1000);
2836
+ };
2837
+ tick();
2838
+ return () => {
2839
+ live = false;
2840
+ if (timer)
2841
+ clearTimeout(timer);
2842
+ };
2843
+ }
2844
+ functions() {
2845
+ return { "exponential.mcp": (args) => this.callTool(String(args.tool ?? ``), args.arguments ?? {}) };
2846
+ }
2847
+ }
2848
+ // packages/exponential-ui/src/connector/app.ts
2849
+ function createAppHost(options) {
2850
+ const { package: pkg, ...rest } = options;
2851
+ const host = new ExponentialHost2(rest);
2852
+ const issues = host.installPackage(pkg);
2853
+ return {
2854
+ host,
2855
+ issues,
2856
+ open(surfaceId, templateId = Object.keys(pkg.templates)[0], data) {
2857
+ const message = { version: `v0.9`, applyTemplate: { surfaceId, templateId, packageId: pkg.id, ...data === undefined ? {} : { data } } };
2858
+ host.receive(message);
2859
+ }
2860
+ };
2861
+ }
2862
+ export {
2863
+ A11Y_COMMANDS,
2864
+ A11Y_ROLES,
2865
+ A11Y_RULES,
2866
+ A2UI_BASIC_CATALOG_ID2 as A2UI_BASIC_CATALOG_ID,
2867
+ A2UI_MESSAGE_KINDS2 as A2UI_MESSAGE_KINDS,
2868
+ A2UI_VERSION2 as A2UI_VERSION,
2869
+ ANIMATIONS,
2870
+ ANIMATION_NAMES,
2871
+ ANIMATION_PROPERTIES_CSS,
2872
+ BASIC_CATALOG_ID2 as BASIC_CATALOG_ID,
2873
+ BASIC_COMPONENT_MAP2 as BASIC_COMPONENT_MAP,
2874
+ BASIC_ICON_MAP2 as BASIC_ICON_MAP,
2875
+ BASIC_PLACEHOLDER_ICON2 as BASIC_PLACEHOLDER_ICON,
2876
+ BASIC_TRANSFORM_NAMES2 as BASIC_TRANSFORM_NAMES,
2877
+ BASIC_VERSION2 as BASIC_VERSION,
2878
+ BIND_FUNCTIONS2 as BIND_FUNCTIONS,
2879
+ BIND_FUNCTION_NAMES2 as BIND_FUNCTION_NAMES,
2880
+ BREAKPOINTS2 as BREAKPOINTS,
2881
+ BUILTIN_FUNCTIONS2 as BUILTIN_FUNCTIONS,
2882
+ BUILTIN_THEMES2 as BUILTIN_THEMES,
2883
+ BUILTIN_THEME_IDS2 as BUILTIN_THEME_IDS,
2884
+ CATALOG_ID2 as CATALOG_ID,
2885
+ CATALOG_VERSION2 as CATALOG_VERSION,
2886
+ CODE_LANGUAGES,
2887
+ CODE_LANGUAGE_NAMES,
2888
+ COMPONENT_A11Y,
2889
+ COMPONENT_GROUPS2 as COMPONENT_GROUPS,
2890
+ COMPONENT_NAMES2 as COMPONENT_NAMES,
2891
+ CONTROL_PARTS,
2892
+ CORE_CATALOG_ID2 as CORE_CATALOG_ID,
2893
+ CORE_FUNCTIONS2 as CORE_FUNCTIONS,
2894
+ CORE_FUNCTION_NAMES2 as CORE_FUNCTION_NAMES,
2895
+ CORE_LITE_CATALOG_ID2 as CORE_LITE_CATALOG_ID,
2896
+ DEFAULT_LOCALE,
2897
+ DEFAULT_MEDIA_SCHEMES2 as DEFAULT_MEDIA_SCHEMES,
2898
+ DEFAULT_STRINGS2 as DEFAULT_STRINGS,
2899
+ DEFAULT_THEME_ID2 as DEFAULT_THEME_ID,
2900
+ DEFAULT_URL_SCHEMES2 as DEFAULT_URL_SCHEMES,
2901
+ DENSITIES2 as DENSITIES,
2902
+ DONUT_HOLE,
2903
+ ENGLISH_DATE_PATTERNS2 as ENGLISH_DATE_PATTERNS,
2904
+ ENGLISH_DATE_TIME_JOIN2 as ENGLISH_DATE_TIME_JOIN,
2905
+ ENGLISH_FORMAT_FUNCTIONS2 as ENGLISH_FORMAT_FUNCTIONS,
2906
+ ENGLISH_TIME_PATTERN2 as ENGLISH_TIME_PATTERN,
2907
+ ENUMS2 as ENUMS,
2908
+ EXTENSION_MESSAGE_KINDS2 as EXTENSION_MESSAGE_KINDS,
2909
+ ExponentialConnector,
2910
+ ExponentialHost2 as ExponentialHost,
2911
+ FIELD_INTRINSIC_WIDTH,
2912
+ FORMATTER_METHODS2 as FORMATTER_METHODS,
2913
+ FORMAT_FUNCTION_NAMES2 as FORMAT_FUNCTION_NAMES,
2914
+ FUNCTION_NAMES2 as FUNCTION_NAMES,
2915
+ GEOMETRY_KEYS,
2916
+ HOST_CONTRACT2 as HOST_CONTRACT,
2917
+ HOST_CONTRACT_VERSION2 as HOST_CONTRACT_VERSION,
2918
+ HOST_ERROR_CODES2 as HOST_ERROR_CODES,
2919
+ HostRouter2 as HostRouter,
2920
+ ICON_NAMES2 as ICON_NAMES,
2921
+ JsonlDecoder2 as JsonlDecoder,
2922
+ JsonlStreamTransport2 as JsonlStreamTransport,
2923
+ LAYOUT_CONSTANTS,
2924
+ LIMITS2 as LIMITS,
2925
+ LIMIT_ISSUES2 as LIMIT_ISSUES,
2926
+ LITE_CATALOG_ID2 as LITE_CATALOG_ID,
2927
+ LITE_COMPONENTS2 as LITE_COMPONENTS,
2928
+ MACRO_COMPONENTS2 as MACRO_COMPONENTS,
2929
+ MAX_COMPONENTS2 as MAX_COMPONENTS,
2930
+ MAX_DEPTH2 as MAX_DEPTH,
2931
+ MAX_MESSAGE_BYTES2 as MAX_MESSAGE_BYTES,
2932
+ MAX_POINTER_BYTES2 as MAX_POINTER_BYTES,
2933
+ MAX_POINTER_SEGMENTS2 as MAX_POINTER_SEGMENTS,
2934
+ MAX_TEMPLATE_ITEMS2 as MAX_TEMPLATE_ITEMS,
2935
+ MCP_ACTION_TOOL2 as MCP_ACTION_TOOL,
2936
+ MCP_MIME_TYPES2 as MCP_MIME_TYPES,
2937
+ MEDIA_ASPECT_RATIO,
2938
+ MEDIA_INTRINSIC_WIDTH,
2939
+ MEDIA_LIMITS2 as MEDIA_LIMITS,
2940
+ MESSAGE_KINDS2 as MESSAGE_KINDS,
2941
+ MODES2 as MODES,
2942
+ McpTransport2 as McpTransport,
2943
+ MemoryTransport2 as MemoryTransport,
2944
+ NATIVE_COMPONENTS2 as NATIVE_COMPONENTS,
2945
+ OVERLAY_OFFSET,
2946
+ OVERLAY_PADDING,
2947
+ PAINT_ERROR_HOOK2 as PAINT_ERROR_HOOK,
2948
+ PANEL_MIN,
2949
+ PENDING_DELAY_MS,
2950
+ POINTER_ISSUES2 as POINTER_ISSUES,
2951
+ PackageError2 as PackageError,
2952
+ RECIPE_KEYS2 as RECIPE_KEYS,
2953
+ RECIPE_STATES2 as RECIPE_STATES,
2954
+ RENDER_FAILED2 as RENDER_FAILED,
2955
+ RESERVED_KEYS2 as RESERVED_KEYS,
2956
+ RESIZE_HANDLE_HIT,
2957
+ RESIZE_STEP,
2958
+ RTL_MIRRORED_ICONS,
2959
+ SEARCH_LIST_FADE,
2960
+ SHADCN_COLOR_VARS,
2961
+ SKELETON_OPACITY_HIGH,
2962
+ SKELETON_OPACITY_LOW,
2963
+ SKELETON_PULSE_MS,
2964
+ SKELETON_REDUCED_OPACITY,
2965
+ SPECIMEN_IDS2 as SPECIMEN_IDS,
2966
+ SSE_EVENTS2 as SSE_EVENTS,
2967
+ STRING_IDS2 as STRING_IDS,
2968
+ STYLE_KEYS2 as STYLE_KEYS,
2969
+ STYLE_KEY_NAMES2 as STYLE_KEY_NAMES,
2970
+ STYLE_LAYOUT_EFFECT_KEYS2 as STYLE_LAYOUT_EFFECT_KEYS,
2971
+ STYLE_LAYOUT_KEYS2 as STYLE_LAYOUT_KEYS,
2972
+ STYLE_MEDIA2 as STYLE_MEDIA,
2973
+ STYLE_STATES2 as STYLE_STATES,
2974
+ STYLE_STATE_NAMES2 as STYLE_STATE_NAMES,
2975
+ STYLE_TRANSFORM2 as STYLE_TRANSFORM,
2976
+ STYLE_VISUAL_KEYS2 as STYLE_VISUAL_KEYS,
2977
+ SUPPORTED_CATALOG_IDS2 as SUPPORTED_CATALOG_IDS,
2978
+ SURFACE_COMMANDS2 as SURFACE_COMMANDS,
2979
+ SURFACE_SETTING_KEYS2 as SURFACE_SETTING_KEYS,
2980
+ SseDecoder2 as SseDecoder,
2981
+ SseTransport2 as SseTransport,
2982
+ SurfaceStore2 as SurfaceStore,
2983
+ TEXT_SHIMMER,
2984
+ THEME_SCHEMA_ID2 as THEME_SCHEMA_ID,
2985
+ TOKEN_GROUPS2 as TOKEN_GROUPS,
2986
+ TOKEN_NAMES2 as TOKEN_NAMES,
2987
+ TREE_GUIDE_BRIDGE,
2988
+ TREE_GUIDE_COLUMN,
2989
+ TREE_GUIDE_RADIUS,
2990
+ ThemeError2 as ThemeError,
2991
+ UNKNOWN_COMPONENT2 as UNKNOWN_COMPONENT,
2992
+ UNKNOWN_COMPONENT_NAME2 as UNKNOWN_COMPONENT_NAME,
2993
+ WINDOW_OVERSCAN,
2994
+ WINDOW_THRESHOLD,
2995
+ WebSocketTransport2 as WebSocketTransport,
2996
+ absolutePath2 as absolutePath,
2997
+ actionMessage2 as actionMessage,
2998
+ activeBreakpoint2 as activeBreakpoint,
2999
+ animatesOpacity,
3000
+ animationCss,
3001
+ animationFrame,
3002
+ animationTiming,
3003
+ ansiRuns,
3004
+ applyContrast2 as applyContrast,
3005
+ applyDensity2 as applyDensity,
3006
+ applyTreeGuides2 as applyTreeGuides,
3007
+ basicMap2 as basicMap,
3008
+ bind,
3009
+ bindRowSlot2 as bindRowSlot,
3010
+ bindSectionHeader2 as bindSectionHeader,
3011
+ bindTree2 as bindTree,
3012
+ builtinTheme2 as builtinTheme,
3013
+ builtinThemes2 as builtinThemes,
3014
+ call,
3015
+ catalogView2 as catalogView,
3016
+ chartExtent,
3017
+ chartSummaryParams,
3018
+ checkGeometry,
3019
+ childTemplate2 as childTemplate,
3020
+ clampNumber2 as clampNumber,
3021
+ clientCapabilities2 as clientCapabilities,
3022
+ codeText,
3023
+ combineDecisions2 as combineDecisions,
3024
+ componentA11y,
3025
+ componentDef2 as componentDef,
3026
+ componentNames2 as componentNames,
3027
+ contrast2 as contrast,
3028
+ controlGeometry,
3029
+ coreCatalog2 as coreCatalog,
3030
+ coreLite2 as coreLite,
3031
+ coreMacros2 as coreMacros,
3032
+ create2 as create,
3033
+ createAppHost,
3034
+ cubicBezier,
3035
+ currencyDigits2 as currencyDigits,
3036
+ decideFunction2 as decideFunction,
3037
+ decideUrl2 as decideUrl,
3038
+ decodeJsonl2 as decodeJsonl,
3039
+ defineExtension,
3040
+ defineSurface,
3041
+ diffTheme,
3042
+ displayString2 as displayString,
3043
+ dragDelta,
3044
+ easingCss2 as easingCss,
3045
+ el,
3046
+ englishFormatter2 as englishFormatter,
3047
+ errorMessage2 as errorMessage,
3048
+ evalCondition2 as evalCondition,
3049
+ evalConditionValue2 as evalConditionValue,
3050
+ evalExpr2 as evalExpr,
3051
+ evalValue2 as evalValue,
3052
+ event,
3053
+ expandMacros2 as expandMacros,
3054
+ exponentialTheme2 as exponentialTheme,
3055
+ exportThemeJson,
3056
+ fillTemplate2 as fillTemplate,
3057
+ filterItems2 as filterItems,
3058
+ fixedOffset2 as fixedOffset,
3059
+ flattenSurface,
3060
+ formatFunctions2 as formatFunctions,
3061
+ formatPattern2 as formatPattern,
3062
+ formatString2 as formatString,
3063
+ gradientCss,
3064
+ hasItem2 as hasItem,
3065
+ hasRowSlots2 as hasRowSlots,
3066
+ imageDimensions2 as imageDimensions,
3067
+ imageFrames2 as imageFrames,
3068
+ importShadcnCss,
3069
+ instanceSegment,
3070
+ intlFormatter2 as intlFormatter,
3071
+ intlZoneOffset2 as intlZoneOffset,
3072
+ isA11yRole,
3073
+ isBinding2 as isBinding,
3074
+ isCall2 as isCall,
3075
+ isCallableName2 as isCallableName,
3076
+ isDataSchema2 as isDataSchema,
3077
+ isDynamic2 as isDynamic,
3078
+ isKnownToken2 as isKnownToken,
3079
+ isOffered2 as isOffered,
3080
+ isPrivateHost2 as isPrivateHost,
3081
+ isResponsiveValue2 as isResponsiveValue,
3082
+ isRowRoot2 as isRowRoot,
3083
+ isStringRef2 as isStringRef,
3084
+ isThemeHex2 as isThemeHex,
3085
+ isVisible2 as isVisible,
3086
+ itemExtents,
3087
+ itemOffsets,
3088
+ keyboardResize,
3089
+ keyframesCss,
3090
+ listSections,
3091
+ loadTheme2 as loadTheme,
3092
+ localeRegion,
3093
+ luminance2 as luminance,
3094
+ macroParts2 as macroParts,
3095
+ mapBasicComponent2 as mapBasicComponent,
3096
+ mapBasicIcon2 as mapBasicIcon,
3097
+ matchesPattern2 as matchesPattern,
3098
+ mcpActionCall2 as mcpActionCall,
3099
+ mediaImageWithinLimits2 as mediaImageWithinLimits,
3100
+ mediaMatches2 as mediaMatches,
3101
+ mediaRequest2 as mediaRequest,
3102
+ mergeData2 as mergeData,
3103
+ messagesFromMcpResult2 as messagesFromMcpResult,
3104
+ mirrorsInRtl,
3105
+ nativeRecipeProps2 as nativeRecipeProps,
3106
+ neutralTheme2 as neutralTheme,
3107
+ niceTicks,
3108
+ nodeDirections,
3109
+ nodeRecipeQuery2 as nodeRecipeQuery,
3110
+ nodeTextAlign,
3111
+ normalizePath2 as normalizePath,
3112
+ normalizeSizes,
3113
+ orangeTheme2 as orangeTheme,
3114
+ packagePolicy2 as packagePolicy,
3115
+ paintedOpacity,
3116
+ panelExtents,
3117
+ parseColor2 as parseColor,
3118
+ parseDateValue2 as parseDateValue,
3119
+ parseLocale,
3120
+ parseMediaCondition2 as parseMediaCondition,
3121
+ parseShadow,
3122
+ parseSource2 as parseSource,
3123
+ parseStringRef2 as parseStringRef,
3124
+ parseThemeJson,
3125
+ parseTokenRef2 as parseTokenRef,
3126
+ percent2 as percent,
3127
+ physicalTextAlign,
3128
+ pkcePair,
3129
+ placeOverlay,
3130
+ playfulTheme2 as playfulTheme,
3131
+ preorder2 as preorder,
3132
+ props2 as props,
3133
+ propsAt2 as propsAt,
3134
+ readPath2 as readPath,
3135
+ readPointer2 as readPointer,
3136
+ recipeParts2 as recipeParts,
3137
+ recipeStyle2 as recipeStyle,
3138
+ reduceNested2 as reduceNested,
3139
+ reduceSurface2 as reduceSurface,
3140
+ relativeTimeUnit2 as relativeTimeUnit,
3141
+ resizePanels,
3142
+ resolveConditionKey2 as resolveConditionKey,
3143
+ resolveConditions2 as resolveConditions,
3144
+ resolveDynamic2 as resolveDynamic,
3145
+ resolveMode2 as resolveMode,
3146
+ resolveNodeProps2 as resolveNodeProps,
3147
+ resolveNodeStyle2 as resolveNodeStyle,
3148
+ resolveProp2 as resolveProp,
3149
+ resolveRecipe2 as resolveRecipe,
3150
+ resolveString2 as resolveString,
3151
+ resolveStyleValues2 as resolveStyleValues,
3152
+ resolveSurfaceTheme2 as resolveSurfaceTheme,
3153
+ resolveToken2 as resolveToken,
3154
+ responsiveAt2 as responsiveAt,
3155
+ rowScope2 as rowScope,
3156
+ run,
3157
+ runAction2 as runAction,
3158
+ safeHref2 as safeHref,
3159
+ scrollOffsetForIndex,
3160
+ scrollOffsetForItem,
3161
+ sectionRows,
3162
+ sectionScope2 as sectionScope,
3163
+ seriesColor,
3164
+ shadowCss2 as shadowCss,
3165
+ sharedCatalogView2 as sharedCatalogView,
3166
+ slotAllowed2 as slotAllowed,
3167
+ sortKeys2 as sortKeys,
3168
+ sourceAllowed2 as sourceAllowed,
3169
+ sparklineSummaryParams,
3170
+ stickyHeader,
3171
+ stringTable2 as stringTable,
3172
+ styleAttribute,
3173
+ styleKeyEnum2 as styleKeyEnum,
3174
+ styleKeyType2 as styleKeyType,
3175
+ styleToCss,
3176
+ submitClosesOverlay2 as submitClosesOverlay,
3177
+ supportedCatalogIds2 as supportedCatalogIds,
3178
+ svgDimensions2 as svgDimensions,
3179
+ tableRowKeys,
3180
+ templateBudget,
3181
+ templateInstances,
3182
+ templateItemKeys,
3183
+ templateMessages2 as templateMessages,
3184
+ templateSiteKey,
3185
+ textDirection,
3186
+ textShimmer,
3187
+ themeFromImport,
3188
+ themeOrDefault2 as themeOrDefault,
3189
+ toHex2 as toHex,
3190
+ toThemeHex2 as toThemeHex,
3191
+ tokenizeCode,
3192
+ treeGuides2 as treeGuides,
3193
+ truthy2 as truthy,
3194
+ tryLoadTheme2 as tryLoadTheme,
3195
+ ui,
3196
+ validVisible2 as validVisible,
3197
+ validateExtension,
3198
+ validateNode2 as validateNode,
3199
+ validatePackage2 as validatePackage,
3200
+ validateProps2 as validateProps,
3201
+ validateStyle2 as validateStyle,
3202
+ validateTheme2 as validateTheme,
3203
+ valuesEqual2 as valuesEqual,
3204
+ verifyPainterGeometry,
3205
+ virtualWindow,
3206
+ weekStart,
3207
+ withOwnWrites2 as withOwnWrites,
3208
+ writePointer2 as writePointer,
3209
+ writeTokens2 as writeTokens
3210
+ };
3211
+
3212
+ //# debugId=B7BF51E65B713F9764756E2164756E21
3213
+ //# sourceMappingURL=index.js.map