@phis/ui 0.4.2 → 0.4.4

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 (335) hide show
  1. package/components/cms/phi-cms-layout-renderer.js +4 -3
  2. package/components/cms/phi-cms-page-render-scope.d.ts +4 -5
  3. package/components/cms/phi-cms-page-render-scope.js +43 -22
  4. package/components/cms/phi-cms-render-diagnostic-client.js +7 -3
  5. package/components/cms/phi-cms-render-error-boundary.js +2 -1
  6. package/components/controls/phi-anchor-nav-control.js +4 -1
  7. package/components/controls/phi-background-control.js +21 -6
  8. package/components/controls/phi-bullet-list-control.d.ts +7 -2
  9. package/components/controls/phi-bullet-list-control.js +35 -5
  10. package/components/controls/phi-color-control.js +4 -2
  11. package/components/controls/phi-drawer-control-adapter.js +3 -2
  12. package/components/controls/phi-inline-text-editor.js +7 -1
  13. package/components/controls/phi-length-control.js +1 -1
  14. package/components/controls/phi-ribbon-control.d.ts +38 -0
  15. package/components/controls/phi-ribbon-control.js +57 -0
  16. package/components/controls/phi-ribbon-wrap-control.d.ts +26 -0
  17. package/components/controls/phi-ribbon-wrap-control.js +25 -0
  18. package/components/controls/phi-select-control.js +5 -2
  19. package/components/controls/phi-series-chart-control.d.ts +48 -0
  20. package/components/controls/phi-series-chart-control.js +82 -0
  21. package/components/controls/phi-table-control.d.ts +3 -0
  22. package/components/controls/phi-table-control.js +13 -1
  23. package/components/controls/phi-text-control.js +57 -3
  24. package/components/controls/phi-tree-control.js +4 -4
  25. package/components/controls/phi-truncated-hover-text.d.ts +15 -0
  26. package/components/controls/phi-truncated-hover-text.js +25 -0
  27. package/components/forms/link-target-form-control.d.ts +1 -1
  28. package/components/forms/link-target-form-control.js +2 -45
  29. package/components/forms/phi-form-widget-frame.js +4 -2
  30. package/components/forms/shared-form-provider-registry.js +1 -4
  31. package/components/layouts/clients/phi-three-column-layout-client.js +10 -1
  32. package/components/media/asset-collection-runtime.js +6 -16
  33. package/components/media/media-font-metrics.d.ts +3 -0
  34. package/components/media/media-font-metrics.js +43 -0
  35. package/components/media/phi-area-upload-widget.js +53 -97
  36. package/components/media/phi-image-preview-data.d.ts +13 -0
  37. package/components/media/phi-image-preview-data.js +184 -9
  38. package/components/media/phi-media-picker-binding.js +16 -13
  39. package/components/media/phi-media-upload.d.ts +15 -8
  40. package/components/media/phi-media-upload.js +18 -9
  41. package/components/media/phi-site-font-assets.js +7 -8
  42. package/components/navigation/phi-link.js +6 -1
  43. package/components/overlays/phi-overlay-container-client.js +16 -1
  44. package/components/regions/clients/cms-region-container-client.js +6 -1
  45. package/components/regions/phi-cms-region-container.js +3 -0
  46. package/components/regions/phi-cms-region-shell.d.ts +12 -1
  47. package/components/regions/phi-cms-region-shell.js +81 -19
  48. package/components/regions/presets/phi-settings-page-shell-tree.js +48 -1
  49. package/components/root/phi-config-provider.d.ts +13 -0
  50. package/components/root/phi-config-provider.js +12 -1
  51. package/components/root/phi-root-background.d.ts +7 -0
  52. package/components/root/phi-root-background.js +20 -1
  53. package/components/root/phi-root-theme-resolver.js +3 -0
  54. package/components/root/phi-shell-chrome-overlay.d.ts +12 -1
  55. package/components/root/phi-shell-chrome-overlay.js +19 -3
  56. package/components/runtime/runtime-controller-materialization.js +12 -1
  57. package/components/shell/phi-antd-icon.d.ts +1 -0
  58. package/components/shell/phi-antd-icon.js +3 -0
  59. package/components/shell/use-phi-shell-sticky-top.js +61 -16
  60. package/components/state/scoped-state-store.js +20 -3
  61. package/components/surface/phi-surface-tone.d.ts +13 -0
  62. package/components/surface/phi-surface-tone.js +21 -0
  63. package/components/tables/client/phi-table-binding.d.ts +2 -1
  64. package/components/tables/client/phi-table-binding.js +45 -21
  65. package/components/trees/client/phi-tree-binding.js +19 -11
  66. package/components/widgets/client/bullet-list-entries-editor.d.ts +26 -0
  67. package/components/widgets/client/bullet-list-entries-editor.js +109 -0
  68. package/components/widgets/client/html-editor.js +1 -1
  69. package/components/widgets/client/shared/use-page-reference-options.d.ts +17 -0
  70. package/components/widgets/client/shared/use-page-reference-options.js +57 -0
  71. package/components/widgets/config/background.d.ts +32 -1
  72. package/components/widgets/config/background.js +41 -2
  73. package/components/widgets/config/choice-shared.js +12 -13
  74. package/components/widgets/config/command-buttons.d.ts +5 -1
  75. package/components/widgets/config/command-buttons.js +38 -81
  76. package/components/widgets/config/control-signal-config.d.ts +3 -1
  77. package/components/widgets/config/control-signal-config.js +19 -17
  78. package/components/widgets/config/image-source-parser.d.ts +1 -0
  79. package/components/widgets/config/image-source-parser.js +7 -8
  80. package/components/widgets/config/mask.d.ts +6 -1
  81. package/components/widgets/config/mask.js +24 -1
  82. package/components/widgets/config/parser-primitives.js +72 -0
  83. package/components/widgets/config/stack-tabs.d.ts +1 -1
  84. package/components/widgets/config/stack-tabs.js +2 -3
  85. package/components/widgets/config/strict-config-reader.d.ts +40 -0
  86. package/components/widgets/config/strict-config-reader.js +174 -0
  87. package/components/widgets/label-sets/background.js +2 -0
  88. package/components/widgets/label-sets/effects.js +2 -0
  89. package/components/widgets/label-types/background.d.ts +1 -0
  90. package/components/widgets/label-types/background.js +1 -0
  91. package/components/widgets/label-types/effects.d.ts +1 -0
  92. package/components/widgets/label-types/effects.js +1 -0
  93. package/components/widgets/navigation-descriptor-resolver.server.js +20 -8
  94. package/components/widgets/shared/bullet-list-vocabulary.d.ts +27 -1
  95. package/components/widgets/shared/bullet-list-vocabulary.js +24 -4
  96. package/components/widgets/shared/card-body-client.d.ts +18 -4
  97. package/components/widgets/shared/card-body-client.js +126 -26
  98. package/components/widgets/shared/card-vocabulary.d.ts +31 -4
  99. package/components/widgets/shared/card-vocabulary.js +35 -2
  100. package/components/widgets/shared/markdown-body-client.js +39 -10
  101. package/components/widgets/signals/control-signal-capabilities.d.ts +0 -18
  102. package/components/widgets/signals/control-signal-capabilities.js +10 -22
  103. package/components/workspace/catalog-store.d.ts +4 -3
  104. package/components/workspace/catalog-store.js +6 -5
  105. package/gateway/dashboard-cards-route.js +1 -0
  106. package/gateway/internal-references.d.ts +6 -1
  107. package/gateway/internal-references.js +48 -23
  108. package/gateway/site-cms-write-validation.d.ts +9 -0
  109. package/gateway/site-cms-write-validation.js +78 -0
  110. package/gateway/site-proxy.js +19 -3
  111. package/helpers/cms-container-chrome.js +6 -1
  112. package/helpers/locale.d.ts +8 -0
  113. package/helpers/locale.js +18 -0
  114. package/helpers/renderable-block-serialization.js +1 -1
  115. package/helpers/shell-region-style.js +2 -1
  116. package/helpers/surface-style.d.ts +12 -1
  117. package/helpers/surface-style.js +28 -2
  118. package/module-dashboard-cards.d.ts +1 -1
  119. package/module-dashboard-cards.js +1 -1
  120. package/next/config.d.mts +3 -0
  121. package/next/config.mjs +28 -1
  122. package/package.json +2 -2
  123. package/plugins/runtime/phi-slot-child-viewport-effects-observer.js +5 -1
  124. package/plugins/runtime-modules/accounting/presets.d.ts +9 -0
  125. package/plugins/runtime-modules/accounting/presets.js +37 -0
  126. package/plugins/runtime-modules/accounting/server.d.ts +1 -4
  127. package/plugins/runtime-modules/accounting/server.js +4 -7
  128. package/plugins/runtime-modules/app/presets.d.ts +18 -0
  129. package/plugins/runtime-modules/app/presets.js +67 -0
  130. package/plugins/runtime-modules/app/server.d.ts +1 -4
  131. package/plugins/runtime-modules/app/server.js +4 -7
  132. package/plugins/runtime-modules/area-definitions.d.ts +0 -42
  133. package/plugins/runtime-modules/area-definitions.js +3 -8
  134. package/plugins/runtime-modules/asset/controller/runtime.js +2 -2
  135. package/plugins/runtime-modules/asset/services/collection.js +9 -1
  136. package/plugins/runtime-modules/asset/services/options.js +2 -2
  137. package/plugins/runtime-modules/builder/area-settings-answer.js +2 -1
  138. package/plugins/runtime-modules/builder/authoring-canvas.js +6 -6
  139. package/plugins/runtime-modules/builder/cards.js +3 -5
  140. package/plugins/runtime-modules/builder/clients/builder-region-overrides.js +3 -3
  141. package/plugins/runtime-modules/builder/clients/canvas-widget.js +15 -54
  142. package/plugins/runtime-modules/builder/clients/inspector-config-field.d.ts +4 -1
  143. package/plugins/runtime-modules/builder/clients/inspector-config-field.js +25 -35
  144. package/plugins/runtime-modules/builder/clients/inspector-link-target-field.js +1 -1
  145. package/plugins/runtime-modules/builder/clients/inspector-section-widget.js +8 -8
  146. package/plugins/runtime-modules/builder/clients/inspector-title.js +6 -6
  147. package/plugins/runtime-modules/builder/clients/layout-inspector.d.ts +1 -1
  148. package/plugins/runtime-modules/builder/clients/layout-inspector.js +11 -25
  149. package/plugins/runtime-modules/builder/clients/layout-scaffold-overlays.js +10 -5
  150. package/plugins/runtime-modules/builder/clients/mode-switch.js +1 -1
  151. package/plugins/runtime-modules/builder/clients/pages-header.js +11 -11
  152. package/plugins/runtime-modules/builder/clients/pages-workspace.js +1 -1
  153. package/plugins/runtime-modules/builder/clients/region-visibility-fields.js +1 -1
  154. package/plugins/runtime-modules/builder/clients/runtime-module-authoring-boundary.js +1 -1
  155. package/plugins/runtime-modules/builder/clients/shells-workspace.js +15 -31
  156. package/plugins/runtime-modules/builder/clients/structure-canvas.js +1 -1
  157. package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.d.ts +26 -0
  158. package/plugins/runtime-modules/builder/clients/use-region-draft-hydration.js +36 -0
  159. package/plugins/runtime-modules/builder/clients/widget-effects-editor.js +1 -1
  160. package/plugins/runtime-modules/builder/clients/widget-inspector.js +1 -0
  161. package/plugins/runtime-modules/builder/clients/workspace-scope-boundary.js +2 -2
  162. package/plugins/runtime-modules/builder/cms-instance-allocator.js +8 -28
  163. package/plugins/runtime-modules/builder/controller/client.d.ts +0 -15
  164. package/plugins/runtime-modules/builder/controller/definition.d.ts +0 -15
  165. package/plugins/runtime-modules/builder/controller/definition.js +0 -8
  166. package/plugins/runtime-modules/builder/controller/draft-command-controller.d.ts +1 -2
  167. package/plugins/runtime-modules/builder/controller/draft-command-controller.js +11 -30
  168. package/plugins/runtime-modules/builder/controller/draft-status-controller.js +15 -2
  169. package/plugins/runtime-modules/builder/controller/inspector-controller.d.ts +1 -2
  170. package/plugins/runtime-modules/builder/controller/inspector-controller.js +4 -7
  171. package/plugins/runtime-modules/builder/controller/page-controller.d.ts +1 -2
  172. package/plugins/runtime-modules/builder/controller/page-controller.js +16 -68
  173. package/plugins/runtime-modules/builder/controller/server-definition.d.ts +0 -15
  174. package/plugins/runtime-modules/builder/controller/signal-wiring-controller.d.ts +2 -5
  175. package/plugins/runtime-modules/builder/controller/signal-wiring-controller.js +6 -50
  176. package/plugins/runtime-modules/builder/controller/workspace-controller.d.ts +2 -3
  177. package/plugins/runtime-modules/builder/controller/workspace-controller.js +89 -153
  178. package/plugins/runtime-modules/builder/data-providers.d.ts +1 -0
  179. package/plugins/runtime-modules/builder/data-providers.js +1 -0
  180. package/plugins/runtime-modules/builder/definition.d.ts +1 -0
  181. package/plugins/runtime-modules/builder/developer-workspace-store.d.ts +64 -30
  182. package/plugins/runtime-modules/builder/developer-workspace-store.js +255 -61
  183. package/plugins/runtime-modules/builder/edit-scaffold-drawer.js +4 -3
  184. package/plugins/runtime-modules/builder/history.d.ts +3 -1
  185. package/plugins/runtime-modules/builder/options-providers.js +3 -2
  186. package/plugins/runtime-modules/builder/page-catalog-client.js +19 -7
  187. package/plugins/runtime-modules/builder/page-meta-form.js +1 -0
  188. package/plugins/runtime-modules/builder/page-references-provider.js +1 -1
  189. package/plugins/runtime-modules/builder/persistence.js +33 -69
  190. package/plugins/runtime-modules/builder/public-route-collisions.d.ts +2 -2
  191. package/plugins/runtime-modules/builder/public-route-collisions.js +6 -19
  192. package/plugins/runtime-modules/builder/render-root-node-preview.server.js +20 -3
  193. package/plugins/runtime-modules/builder/render-root-node-scaffold.js +28 -18
  194. package/plugins/runtime-modules/builder/runtime-module-selection.d.ts +2 -12
  195. package/plugins/runtime-modules/builder/runtime-module-selection.js +16 -42
  196. package/plugins/runtime-modules/builder/services/navigation-table.js +9 -15
  197. package/plugins/runtime-modules/builder/services/page-source-tree.js +8 -8
  198. package/plugins/runtime-modules/builder/services/runtime-modules-table.js +10 -10
  199. package/plugins/runtime-modules/builder/services/signal-routes-table.js +3 -3
  200. package/plugins/runtime-modules/builder/signal-route-selection.d.ts +1 -2
  201. package/plugins/runtime-modules/builder/signal-route-selection.js +2 -2
  202. package/plugins/runtime-modules/builder/signal-wiring-options.js +3 -2
  203. package/plugins/runtime-modules/builder/structure-dnd.js +8 -61
  204. package/plugins/runtime-modules/builder/trees/phi-default-builder-area-preset-tree.js +17 -10
  205. package/plugins/runtime-modules/builder/widgets/structure-region/built-in.js +27 -22
  206. package/plugins/runtime-modules/builder/workspace-catalog-actions.d.ts +55 -0
  207. package/plugins/runtime-modules/builder/workspace-catalog-actions.js +142 -0
  208. package/plugins/runtime-modules/client-authoring-module.d.ts +8 -1
  209. package/plugins/runtime-modules/client-authoring-module.js +13 -3
  210. package/plugins/runtime-modules/client-manifests/common.js +1 -1
  211. package/plugins/runtime-modules/{runtime-calendar-adapters.js → core/calendar-adapters.js} +2 -2
  212. package/plugins/runtime-modules/{client-calendar-adapters/core.js → core/client-calendar-adapters.js} +1 -1
  213. package/plugins/runtime-modules/core/content-entries/table.js +1 -1
  214. package/plugins/runtime-modules/core/data-providers.d.ts +3 -0
  215. package/plugins/runtime-modules/core/data-providers.js +2 -1
  216. package/plugins/runtime-modules/core/definition.d.ts +3 -0
  217. package/plugins/runtime-modules/core/definition.js +1 -1
  218. package/plugins/runtime-modules/core/messaging/data-providers.d.ts +1 -0
  219. package/plugins/runtime-modules/core/messaging/data-providers.js +1 -0
  220. package/plugins/runtime-modules/core/messaging/thread-inbox-table.js +1 -1
  221. package/plugins/runtime-modules/core/server.js +1 -1
  222. package/plugins/runtime-modules/core/themes.d.ts +44 -0
  223. package/plugins/runtime-modules/core/themes.js +12 -0
  224. package/plugins/runtime-modules/core/widgets/brand/client.d.ts +12 -3
  225. package/plugins/runtime-modules/core/widgets/brand/client.js +3 -11
  226. package/plugins/runtime-modules/core/widgets/brand/home.d.ts +15 -0
  227. package/plugins/runtime-modules/core/widgets/brand/home.js +18 -0
  228. package/plugins/runtime-modules/core/widgets/brand/plugin.js +3 -2
  229. package/plugins/runtime-modules/core/widgets/brand/server.d.ts +2 -2
  230. package/plugins/runtime-modules/core/widgets/brand/server.js +2 -2
  231. package/plugins/runtime-modules/core/widgets/card/collection-view-binding.js +25 -9
  232. package/plugins/runtime-modules/core/widgets/card/config.d.ts +301 -254
  233. package/plugins/runtime-modules/core/widgets/card/config.js +68 -3
  234. package/plugins/runtime-modules/core/widgets/card/editor.js +41 -4
  235. package/plugins/runtime-modules/core/widgets/card/server.d.ts +3 -0
  236. package/plugins/runtime-modules/core/widgets/card/server.js +32 -3
  237. package/plugins/runtime-modules/core/widgets/collection-view/asset-binding.js +7 -6
  238. package/plugins/runtime-modules/core/widgets/collection-view/config.js +9 -2
  239. package/plugins/runtime-modules/core/widgets/description/client.js +3 -3
  240. package/plugins/runtime-modules/core/widgets/description/config.d.ts +2 -25
  241. package/plugins/runtime-modules/core/widgets/description/editor.js +7 -63
  242. package/plugins/runtime-modules/core/widgets/description/server.js +3 -2
  243. package/plugins/runtime-modules/core/widgets/entry-list/config.d.ts +2 -25
  244. package/plugins/runtime-modules/core/widgets/gallery/config.d.ts +2 -25
  245. package/plugins/runtime-modules/core/widgets/header-navigation/client.js +2 -2
  246. package/plugins/runtime-modules/core/widgets/html/client.js +1 -1
  247. package/plugins/runtime-modules/core/widgets/image/config.js +2 -2
  248. package/plugins/runtime-modules/core/widgets/markdown/config.d.ts +320 -2
  249. package/plugins/runtime-modules/core/widgets/markdown/config.js +18 -4
  250. package/plugins/runtime-modules/core/widgets/markdown/editor.js +11 -4
  251. package/plugins/runtime-modules/core/widgets/markdown-toc/client.js +6 -1
  252. package/plugins/runtime-modules/core/widgets/markdown-toc/config.d.ts +14 -0
  253. package/plugins/runtime-modules/core/widgets/markdown-toc/config.js +14 -2
  254. package/plugins/runtime-modules/core/widgets/quick-links/authoring.js +7 -2
  255. package/plugins/runtime-modules/core/widgets/quick-links/client.js +2 -2
  256. package/plugins/runtime-modules/core/widgets/quick-links/items.d.ts +0 -2
  257. package/plugins/runtime-modules/core/widgets/quick-links/items.js +0 -15
  258. package/plugins/runtime-modules/core/widgets/result/config.d.ts +5 -25
  259. package/plugins/runtime-modules/core/widgets/result/config.js +2 -0
  260. package/plugins/runtime-modules/core/widgets/result/server.js +25 -19
  261. package/plugins/runtime-modules/core/widgets/sidebar-navigation/authoring.js +1 -1
  262. package/plugins/runtime-modules/core/widgets/sidebar-navigation/client.js +1 -1
  263. package/plugins/runtime-modules/core/widgets/simple-text/client.js +8 -3
  264. package/plugins/runtime-modules/core/widgets/simple-text/config.d.ts +2 -25
  265. package/plugins/runtime-modules/core/widgets/simple-text/editor.js +2 -2
  266. package/plugins/runtime-modules/core/widgets/slot-upload/client.js +11 -2
  267. package/plugins/runtime-modules/core/widgets/table/client.js +8 -4
  268. package/plugins/runtime-modules/core/widgets/table/config.d.ts +6 -83
  269. package/plugins/runtime-modules/core/widgets/table/config.js +302 -452
  270. package/plugins/runtime-modules/core/widgets/tree/config.js +5 -2
  271. package/plugins/runtime-modules/dashboard/card-rows.d.ts +7 -0
  272. package/plugins/runtime-modules/dashboard/card-rows.js +87 -0
  273. package/plugins/runtime-modules/dashboard/clients/dashboard-card-view.js +32 -12
  274. package/plugins/runtime-modules/dashboard/services/collection.js +17 -7
  275. package/plugins/runtime-modules/dashboard/trees/phi-default-builder-dashboard-page-tree.js +5 -40
  276. package/plugins/runtime-modules/groups/data-providers.d.ts +2 -0
  277. package/plugins/runtime-modules/groups/data-providers.js +3 -3
  278. package/plugins/runtime-modules/groups/definition.d.ts +2 -0
  279. package/plugins/runtime-modules/localization/data-providers.d.ts +3 -0
  280. package/plugins/runtime-modules/localization/data-providers.js +2 -0
  281. package/plugins/runtime-modules/localization/definition.d.ts +3 -0
  282. package/plugins/runtime-modules/localization/services/table.js +3 -7
  283. package/plugins/runtime-modules/observability/data-providers.d.ts +1 -0
  284. package/plugins/runtime-modules/observability/data-providers.js +1 -0
  285. package/plugins/runtime-modules/observability/definition.d.ts +1 -0
  286. package/plugins/runtime-modules/observability/module.d.ts +1 -0
  287. package/plugins/runtime-modules/observability/services/table.js +1 -1
  288. package/plugins/runtime-modules/phi-default-site-area-preset-tree.js +2 -105
  289. package/plugins/runtime-modules/public/presets.d.ts +115 -0
  290. package/plugins/runtime-modules/{area-base-presets.js → public/presets.js} +19 -119
  291. package/plugins/runtime-modules/public/server.d.ts +1 -4
  292. package/plugins/runtime-modules/public/server.js +4 -7
  293. package/plugins/runtime-modules/public/trees/phi-default-pub-error-page-tree.js +7 -8
  294. package/plugins/runtime-modules/public-base-page-references.d.ts +1 -1
  295. package/plugins/runtime-modules/public-base-page-references.js +1 -1
  296. package/plugins/runtime-modules/revisions/controller/client.js +11 -11
  297. package/plugins/runtime-modules/revisions/services/table.js +3 -3
  298. package/plugins/runtime-modules/theme/trees/phi-default-builder-theme-page-tree.js +22 -0
  299. package/plugins/runtime-modules/theme/widgets/brand-controls/client.d.ts +2 -1
  300. package/plugins/runtime-modules/theme/widgets/brand-controls/client.js +111 -72
  301. package/plugins/runtime-modules/theme/widgets/brand-controls/config.d.ts +2 -1
  302. package/plugins/runtime-modules/theme/widgets/brand-controls/config.js +28 -31
  303. package/plugins/runtime-modules/theme/widgets/brand-controls/plugin.js +1 -1
  304. package/plugins/runtime-modules/theme-descriptors.js +1 -1
  305. package/plugins/runtime-modules/user-management/data-providers.d.ts +2 -0
  306. package/plugins/runtime-modules/user-management/data-providers.js +1 -0
  307. package/plugins/runtime-modules/user-management/definition.d.ts +2 -0
  308. package/server-helpers/cms-link-targets.js +6 -0
  309. package/styles/control-shape.css +11 -11
  310. package/styles/controls.css +67 -5
  311. package/styles/layout.css +61 -9
  312. package/styles/shell.css +73 -0
  313. package/theme/phi-antd-token-resolver.js +20 -1
  314. package/theme/phi-theme-tokens.d.ts +1 -1
  315. package/theme/phi-theme-tokens.js +1 -0
  316. package/theme/phi-theme.d.ts +5 -0
  317. package/theme/phi-theme.js +21 -0
  318. package/theme/phi-tokens.d.ts +16 -15
  319. package/theme/phi-tokens.js +16 -15
  320. package/types/cms-config.js +142 -185
  321. package/types/cms-plugins.d.ts +6 -11
  322. package/types/core-widget-placements.d.ts +14 -3
  323. package/types/dashboard-cards.d.ts +48 -4
  324. package/types/dashboard-cards.js +6 -0
  325. package/types/media.d.ts +0 -3
  326. package/types/renderable-block.d.ts +6 -1
  327. package/types/site-theme.d.ts +10 -2
  328. package/types/table-widget.d.ts +9 -0
  329. package/types/table-widget.js +20 -0
  330. package/types.d.ts +1 -1
  331. package/widget-config.d.ts +2 -0
  332. package/widget-config.js +6 -0
  333. package/plugins/runtime-modules/area-base-presets.d.ts +0 -139
  334. /package/plugins/runtime-modules/{runtime-calendar-adapters.d.ts → core/calendar-adapters.d.ts} +0 -0
  335. /package/plugins/runtime-modules/{client-calendar-adapters/core.d.ts → core/client-calendar-adapters.d.ts} +0 -0
@@ -4,6 +4,8 @@ import { useState } from "react";
4
4
  import { PhiButtonControl } from "../../controls/phi-button-control";
5
5
  import { PhiFlexControl } from "../../controls/phi-flex-control";
6
6
  import { PhiImageControl } from "../../controls/phi-image-control";
7
+ import { PhiRibbonControl } from "../../controls/phi-ribbon-control";
8
+ import { PhiRibbonWrapControl } from "../../controls/phi-ribbon-wrap-control";
7
9
  import { PhiSkeletonControl } from "../../controls/phi-skeleton-control";
8
10
  import { PhiStatisticControl } from "../../controls/phi-statistic-control";
9
11
  import { PhiTypographyControl } from "../../controls/phi-typography-control";
@@ -14,8 +16,10 @@ import { PhiSurfaceGroundLayer } from "../../surface/phi-surface-ground";
14
16
  import { PhiSurfaceTone } from "../../surface/phi-surface-tone";
15
17
  import { resolvePhiSurfaceStyle } from "../../../helpers/surface-style";
16
18
  import { usePhiControlSignalController } from "../client/shared/phi-control-signals";
17
- import { PHI_SPACE } from "../../../theme/antd-css-var-contract";
18
- const PHI_CARD_SIGNAL_TEXT_SLOTS = new Set(["eyebrow", "title", "description", "meta", "value"]);
19
+ import { PHI_COLOR, PHI_SPACE } from "../../../theme/antd-css-var-contract";
20
+ import { PHI_THEME_HEADING_FONT_VARIABLE } from "../../../theme/phi-theme-typography";
21
+ import { PHI_CARD_TEXT_SLOTS, readPhiCardBillingPeriod } from "./card-vocabulary";
22
+ const PHI_CARD_SIGNAL_TEXT_SLOTS = new Set(PHI_CARD_TEXT_SLOTS);
19
23
  /*
20
24
  * What each variant sets, in one row per variant. A further variant -- a featured card -- is a row here
21
25
  * and an entry in `PHI_CARD_VARIANTS`.
@@ -71,13 +75,19 @@ const PHI_CARD_HIDDEN_TEXT = {
71
75
  whiteSpace: "nowrap",
72
76
  border: 0,
73
77
  };
74
- const PHI_CARD_THEME_CORNER = "var(--phi-surface-radius, var(--ant-border-radius-lg))";
78
+ const PHI_CARD_THEME_CORNER = "var(--phi-surface-radius)";
75
79
  /** The box a picture is shown in takes the picture's own proportion; 3:2 where nothing is known. */
76
80
  function resolveMediaAspectRatio(presentation) {
77
81
  return presentation.width && presentation.height
78
82
  ? `${presentation.width} / ${presentation.height}`
79
83
  : "3 / 2";
80
84
  }
85
+ /*
86
+ * Every colour the card paints is the Theme's variable (`PHI_COLOR`), never a token's resolved value: a
87
+ * Surface with a `tone` writes the other mode's variables on the card's box, and only a variable reaches
88
+ * the words inside it. Resolved values were the page's mode written in by hand, and dark words stayed
89
+ * dark on a photograph darkened for light ones.
90
+ */
81
91
  export function PhiCardWidgetClient({ labels: placedLabels, config, binding, listContent, renderText, }) {
82
92
  const { token } = usePhiConfig();
83
93
  const [overrides, setOverrides] = useState({});
@@ -94,6 +104,11 @@ export function PhiCardWidgetClient({ labels: placedLabels, config, binding, lis
94
104
  else if (capabilityId === "loading" || capabilityId === "highlight") {
95
105
  setOverrides((current) => ({ ...current, [capabilityId]: signal.value === true }));
96
106
  }
107
+ else if (capabilityId === "billingPeriod") {
108
+ const billingPeriod = readPhiCardBillingPeriod(signal.value);
109
+ if (billingPeriod)
110
+ setOverrides((current) => ({ ...current, billingPeriod }));
111
+ }
97
112
  return true;
98
113
  },
99
114
  });
@@ -157,15 +172,30 @@ export function PhiCardWidgetClient({ labels: placedLabels, config, binding, lis
157
172
  const title = textOf("title");
158
173
  const description = textOf("description");
159
174
  const meta = textOf("meta");
175
+ const badge = textOf("badge");
160
176
  const eyebrowType = { fontSize: token.fontSizeSM, letterSpacing: "0.04em", textTransform: "uppercase" };
161
177
  /* On the picture's corner where the variant puts it there and there is a picture to put it on. */
162
178
  const eyebrowOnMedia = metrics.eyebrowOnMedia === true && image != null;
163
- const heading = title != null ? (_jsx(PhiTypographyControl, { presentation: "title", level: Number(headingLevel.slice(1)), style: { margin: 0, ...headingType[headingLevel], color: token.colorTextHeading, ...slotWidth }, children: title })) : null;
179
+ const heading = title != null ? (_jsx(PhiTypographyControl, { presentation: "title", level: Number(headingLevel.slice(1)), style: { margin: 0, ...headingType[headingLevel], color: PHI_COLOR.textHeading, ...slotWidth }, children: title })) : null;
164
180
  /*
165
181
  * The icon's colours as custom properties, which `.phi-card__icon` paints (`styles/layout.css`): the
166
182
  * `icon` hover effect turns them round, and a colour stated inline could not be turned by a rule.
167
183
  */
168
- const iconColours = (color, background) => ({ "--phi-card-icon-color": color, "--phi-card-icon-background": background });
184
+ const iconColours = (color, background) => ({
185
+ "--phi-card-icon-color": color,
186
+ "--phi-card-icon-background": background,
187
+ /* The mark's colour once the `icon` effect turns them round: a ground it can be read on. */
188
+ "--phi-card-icon-hover-color": config?.iconBackground ?? PHI_COLOR.bgContainer,
189
+ });
190
+ /*
191
+ * The corner of the icon's ground: the Theme's Control shape at the large size, scaled from a large
192
+ * Control's height to the ground's side. So `square` draws a square, `pill` a circle -- half the large
193
+ * height scaled to the side is half the side -- and the steps between keep their proportion, as a
194
+ * Segmented's items follow their track. The Theme's plain corner did not: a pill Site drew square marks.
195
+ */
196
+ const iconCorner = (side) => `calc(var(--phi-control-radius-lg, ${token.borderRadiusLG}px) * ${side / token.controlHeightLG})`;
197
+ /* The framed box an icon before the title stands in. */
198
+ const inlineIconFrame = iconSize + 16;
169
199
  const iconMark = (size, framed) => iconName ? (_jsx("span", { "aria-hidden": "true", className: "phi-card__icon", style: {
170
200
  display: "inline-flex",
171
201
  flex: "none",
@@ -173,22 +203,62 @@ export function PhiCardWidgetClient({ labels: placedLabels, config, binding, lis
173
203
  justifyContent: "center",
174
204
  width: framed,
175
205
  height: framed,
176
- borderRadius: token.borderRadius,
177
- ...iconColours(config?.iconColor ?? (highlight ? token.colorPrimary : token.colorTextSecondary), config?.iconBackground ?? token.colorFillQuaternary),
206
+ borderRadius: iconCorner(framed),
207
+ ...iconColours(config?.iconColor ?? (highlight ? PHI_COLOR.primary : PHI_COLOR.textSecondary), config?.iconBackground ?? PHI_COLOR.fillQuaternary),
178
208
  }, children: _jsx(PhiIcon, { name: iconName, size: size }) })) : null;
179
209
  /*
180
210
  * A failure stands where the figure would, at body size, because a sentence in figure type is
181
211
  * unreadable. A card whose figure is the only thing it has makes the figure the link.
182
212
  */
183
213
  const valueText = renderText ? renderText("value", labels.value) : null;
184
- const figure = valueText != null ? (_jsx("div", { style: { fontSize: token.fontSizeHeading3, color: highlight ? token.colorPrimary : token.colorTextHeading, ...slotWidth }, children: valueText })) : (_jsx(PhiStatisticControl, { value: binding?.error ?? labels.value ?? "", loading: binding?.loading === true || overrides.loading === true, styles: {
214
+ /*
215
+ * Beside an icon before the title, the figure starts where the title's words do, under them rather
216
+ * than under the icon: the number belongs to the heading, the icon only marks it. On a line set to its
217
+ * start only -- centred or at the end, the figure already stands with the words.
218
+ */
219
+ const figureIndent = iconPlacement === "inline" && iconName && (textAlign === "start" || textAlign === "justify")
220
+ ? { paddingInlineStart: inlineIconFrame + gap }
221
+ : {};
222
+ /*
223
+ * The figure is set like the title it belongs to: in the font the Theme gives headings, and with digits
224
+ * of one width, so a figure that changes does not shift as it counts. No fallback in the `var()`, as for
225
+ * the headings themselves (`styles/layout.css`): a Theme that keeps headings on the body font sets no
226
+ * variable, and the figure inherits the body font.
227
+ */
228
+ const figureType = {
229
+ fontFamily: `var(${PHI_THEME_HEADING_FONT_VARIABLE})`,
230
+ fontVariantNumeric: "tabular-nums",
231
+ };
232
+ const figure = valueText != null ? (_jsx("div", { style: {
233
+ ...figureType,
234
+ fontSize: token.fontSizeHeading3,
235
+ color: highlight ? PHI_COLOR.primary : PHI_COLOR.textHeading,
236
+ ...slotWidth,
237
+ ...figureIndent,
238
+ }, children: valueText })) : (_jsx(PhiStatisticControl, { value: binding?.error ?? labels.value ?? "", loading: binding?.loading === true || overrides.loading === true, style: figureIndent, styles: {
185
239
  content: binding?.error
186
- ? { color: token.colorError, fontSize: token.fontSize }
187
- : { color: highlight ? token.colorPrimary : token.colorTextHeading },
240
+ ? { color: PHI_COLOR.error, fontSize: token.fontSize }
241
+ : { ...figureType, color: highlight ? PHI_COLOR.primary : PHI_COLOR.textHeading },
188
242
  } }));
189
243
  /* A failure stands where the lines would, as it does for a figure; a list still coming is three lines. */
190
- const list = binding?.error ? (_jsx(PhiTypographyControl, { style: { color: token.colorError, ...slotWidth }, children: binding.error })) : binding?.loading === true || overrides.loading === true ? (_jsx(PhiSkeletonControl, { lines: 3 })) : listContent ?? null;
191
- const headingRow = iconPlacement === "inline" && iconName ? (_jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: justify, gap, ...slotWidth }, children: [iconMark(iconSize, iconSize + 16), heading] })) : heading;
244
+ const list = binding?.error ? (_jsx(PhiTypographyControl, { style: { color: PHI_COLOR.error, ...slotWidth }, children: binding.error })) : binding?.loading === true || overrides.loading === true ? (_jsx(PhiSkeletonControl, { lines: 3 })) : listContent ?? null;
245
+ /*
246
+ * A plan's price: the period's own where it states one, the monthly one where it does not, so a switch
247
+ * to yearly never leaves a card without a price. An editor is asked for the shown period's fields.
248
+ */
249
+ const yearly = (overrides.billingPeriod ?? config?.billingPeriod) === "yearly";
250
+ const showsYearly = yearly && (renderText != null || Boolean(labels.priceYearly));
251
+ const priceText = body === "plan" ? textOf(showsYearly ? "priceYearly" : "price") : null;
252
+ const periodText = body === "plan" ? textOf(showsYearly ? "pricePeriodYearly" : "pricePeriod") : null;
253
+ const plan = body === "plan" ? (_jsxs("div", { style: { display: "grid", gap, justifySelf: "stretch", justifyItems, minWidth: 0 }, children: [priceText != null || periodText != null ? (_jsxs("div", { style: { display: "flex", flexWrap: "wrap", alignItems: "baseline", justifyContent: justify, columnGap: PHI_SPACE.xs, ...slotWidth }, children: [priceText != null ? (_jsx("span", { className: "phi-card__price", style: {
254
+ fontSize: token.fontSizeHeading2,
255
+ lineHeight: token.lineHeightHeading2,
256
+ fontWeight: 600,
257
+ fontVariantNumeric: "tabular-nums",
258
+ color: highlight ? PHI_COLOR.primary : PHI_COLOR.textHeading,
259
+ ...slotWidth,
260
+ }, children: priceText })) : null, periodText != null ? (_jsx("span", { style: { color: PHI_COLOR.textSecondary, ...slotWidth }, children: periodText })) : null] })) : null, list != null ? _jsx("div", { style: { justifySelf: "stretch", minWidth: 0, textAlign: "start" }, children: list }) : null] })) : null;
261
+ const headingRow = iconPlacement === "inline" && iconName ? (_jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: justify, gap, ...slotWidth }, children: [iconMark(iconSize, inlineIconFrame), heading] })) : heading;
192
262
  const media = image ? (_jsxs("div", { className: "phi-card__media", style: {
193
263
  position: "relative",
194
264
  aspectRatio: metrics.mediaAspectRatio ?? resolveMediaAspectRatio(image.presentation),
@@ -208,9 +278,9 @@ export function PhiCardWidgetClient({ labels: placedLabels, config, binding, lis
208
278
  justifyContent: "center",
209
279
  width: topIconSize + 24,
210
280
  height: topIconSize + 24,
211
- borderRadius: "50%",
281
+ borderRadius: iconCorner(topIconSize + 24),
212
282
  // A ground of its own, so the mark reads on a bright picture and on a dark one alike.
213
- ...iconColours(config?.iconColor ?? (highlight ? token.colorPrimary : token.colorText), config?.iconBackground ?? `color-mix(in srgb, ${token.colorBgContainer} 88%, transparent)`),
283
+ ...iconColours(config?.iconColor ?? (highlight ? PHI_COLOR.primary : PHI_COLOR.text), config?.iconBackground ?? `color-mix(in srgb, ${PHI_COLOR.bgContainer} 88%, transparent)`),
214
284
  boxShadow: token.boxShadowTertiary,
215
285
  }, children: _jsx(PhiIcon, { name: iconName, size: topIconSize }) })) : null, eyebrowOnMedia && eyebrow != null ? (_jsx(PhiTypographyControl, { type: "secondary", style: {
216
286
  ...eyebrowType,
@@ -222,8 +292,8 @@ export function PhiCardWidgetClient({ labels: placedLabels, config, binding, lis
222
292
  paddingInline: token.paddingXS,
223
293
  borderRadius: token.borderRadiusSM,
224
294
  // A ground of its own, as the icon has, so the words read on any picture.
225
- background: `color-mix(in srgb, ${token.colorBgContainer} 88%, transparent)`,
226
- color: highlight ? token.colorPrimary : token.colorText,
295
+ background: `color-mix(in srgb, ${PHI_COLOR.bgContainer} 88%, transparent)`,
296
+ color: highlight ? PHI_COLOR.primary : PHI_COLOR.text,
227
297
  }, children: eyebrow })) : null] })) : null;
228
298
  const boxStyle = {
229
299
  ...(config?.surface ? {} : { borderRadius: PHI_CARD_THEME_CORNER }),
@@ -235,21 +305,51 @@ export function PhiCardWidgetClient({ labels: placedLabels, config, binding, lis
235
305
  minWidth: 0,
236
306
  overflow: "hidden",
237
307
  textAlign,
238
- color: token.colorText,
308
+ color: PHI_COLOR.text,
239
309
  /* The ring's colour; `.phi-card--highlight` draws it (`styles/layout.css`). */
240
- ...(highlight ? { "--phi-card-highlight-color": token.colorPrimary } : {}),
310
+ ...(highlight ? { "--phi-card-highlight-color": PHI_COLOR.primary } : {}),
241
311
  };
242
- const content = (_jsxs(_Fragment, { children: [media, _jsxs("div", { style: { display: "grid", gap, padding: inset, justifyItems }, children: [iconAtTop && iconName && !image ? (_jsx("div", { style: { justifySelf: markSide === "center" ? "center" : markSide === "end" ? "end" : "start" }, children: iconMark(topIconSize, topIconSize + 24) })) : null, eyebrow != null && !eyebrowOnMedia && !labels.eyebrowEnd ? (_jsx(PhiTypographyControl, { type: "secondary", style: { ...eyebrowType, color: highlight ? token.colorPrimary : token.colorTextTertiary, ...slotWidth }, children: eyebrow })) : null, labels.eyebrowEnd && !eyebrowOnMedia ? (_jsxs(PhiFlexControl, { justify: "space-between", align: "baseline", wrap: true, gap: PHI_SPACE.xs, style: { justifySelf: "stretch", minWidth: 0 }, children: [_jsx(PhiTypographyControl, { type: "secondary", style: { ...eyebrowType, color: highlight ? token.colorPrimary : token.colorTextTertiary }, children: eyebrow ?? "" }), _jsx(PhiTypographyControl, { type: "secondary", style: { ...eyebrowType, color: token.colorTextTertiary }, children: labels.eyebrowEnd })] })) : null, headingRow, body === "stat" ? figure : null, body === "list" && list != null ? (_jsx("div", { style: { justifySelf: "stretch", minWidth: 0 }, children: list })) : null, description != null ? (_jsx(PhiTypographyControl, { presentation: "paragraph", style: {
243
- marginBottom: 0,
244
- color: token.colorTextSecondary,
245
- fontSize: descriptionSize,
246
- ...slotWidth,
247
- }, children: description })) : null, meta != null ? (_jsx(PhiTypographyControl, { type: "secondary", style: { fontSize: token.fontSizeSM, color: token.colorTextTertiary, ...slotWidth }, children: meta })) : null, action ? (_jsx("div", { className: "phi-card__action", children: _jsx(PhiButtonControl, { type: highlight ? "primary" : "default", size: buttonSize, ...(action.href ? { href: action.href, newTab: action.newTab, external: action.external } : {}), label: labels.actionLabel || undefined, ...(labels.actionLabel ? {} : { ariaLabel: action.ariaLabel }), ...(action.icon ? { icon: _jsx(PhiIcon, { name: action.icon, size: "1em" }) } : {}), ...(activates ? { onClick: () => controlSignals.emitCapability("activate", null) } : {}) }) })) : null] }), cardLink] }));
248
- return (_jsxs("article", { className: [
312
+ /*
313
+ * A plan's button stands at the card's foot: plans side by side in a row have lists of different
314
+ * lengths, and their buttons belong on one line. The words keep their grid; the grid and the button
315
+ * stand in a column that fills the card, and the button takes what is left above it.
316
+ */
317
+ const footAction = body === "plan" && action != null;
318
+ const actionButton = action ? (_jsx("div", { className: "phi-card__action",
319
+ /* At the foot, it stands where the words' alignment puts it, as it does among them. */
320
+ style: footAction ? { marginTop: "auto", alignSelf: textAlign === "center" ? "center" : textAlign === "end" ? "flex-end" : "flex-start" } : undefined, children: _jsx(PhiButtonControl, { type: highlight ? "primary" : "default", size: buttonSize, ...(action.href ? { href: action.href, newTab: action.newTab, external: action.external } : {}), label: labels.actionLabel || undefined, ...(labels.actionLabel ? {} : { ariaLabel: action.ariaLabel }), ...(action.icon ? { icon: _jsx(PhiIcon, { name: action.icon, size: "1em" }) } : {}), ...(activates ? { onClick: () => controlSignals.emitCapability("activate", null) } : {}) }) })) : null;
321
+ /*
322
+ * The band in the card's top end corner, floating (`PhiRibbonControl`): the words below it start where
323
+ * they start in a card without one, so plans side by side keep their headings on one line.
324
+ */
325
+ const badgeStyle = config?.badgeStyle ?? "none";
326
+ const ribbon = badge != null && (badgeStyle === "corner" || badgeStyle === "tag") ? (_jsx(PhiRibbonControl, { color: config?.badgeColor, placement: badgeStyle === "tag" ? "edge" : "corner", ...(!renderText && labels.badge
327
+ ? {
328
+ fullText: labels.badge,
329
+ ...(href
330
+ ? {
331
+ onClick: (event) => event.currentTarget.closest(".phi-card")?.querySelector(".phi-card__link")?.click(),
332
+ }
333
+ : {}),
334
+ }
335
+ : {}), ...(renderText ? { style: { pointerEvents: "auto", minWidth: "6em" } } : {}), children: badge })) : null;
336
+ const words = (_jsxs("div", { style: { display: "grid", gap, padding: footAction ? 0 : inset, justifyItems }, children: [iconAtTop && iconName && !image ? (_jsx("div", { style: { justifySelf: markSide === "center" ? "center" : markSide === "end" ? "end" : "start" }, children: iconMark(topIconSize, topIconSize + 24) })) : null, eyebrow != null && !eyebrowOnMedia && !labels.eyebrowEnd ? (_jsx(PhiTypographyControl, { type: "secondary", style: { ...eyebrowType, color: highlight ? PHI_COLOR.primary : PHI_COLOR.textTertiary, ...slotWidth }, children: eyebrow })) : null, labels.eyebrowEnd && !eyebrowOnMedia ? (_jsxs(PhiFlexControl, { justify: "space-between", align: "baseline", wrap: true, gap: PHI_SPACE.xs, style: { justifySelf: "stretch", minWidth: 0 }, children: [_jsx(PhiTypographyControl, { type: "secondary", style: { ...eyebrowType, color: highlight ? PHI_COLOR.primary : PHI_COLOR.textTertiary }, children: eyebrow ?? "" }), _jsx(PhiTypographyControl, { type: "secondary", style: { ...eyebrowType, color: PHI_COLOR.textTertiary }, children: labels.eyebrowEnd })] })) : null, headingRow, body === "stat" ? figure : null, body === "series" ? (_jsxs(_Fragment, { children: [labels.value || binding?.error || binding?.loading === true || overrides.loading === true ? figure : null, list != null && !binding?.error && binding?.loading !== true && overrides.loading !== true ? (_jsx("div", { style: { justifySelf: "stretch", minWidth: 0 }, children: list })) : null] })) : null, body === "list" && list != null ? (_jsx("div", { style: { justifySelf: "stretch", minWidth: 0 }, children: list })) : null, description != null ? (_jsx(PhiTypographyControl, { presentation: "paragraph", style: {
337
+ marginBottom: 0,
338
+ color: PHI_COLOR.textSecondary,
339
+ fontSize: descriptionSize,
340
+ ...slotWidth,
341
+ }, children: description })) : null, plan, meta != null ? (_jsx(PhiTypographyControl, { type: "secondary", style: { fontSize: token.fontSizeSM, color: PHI_COLOR.textTertiary, ...slotWidth }, children: meta })) : null, footAction ? null : actionButton] }));
342
+ const content = (_jsxs(_Fragment, { children: [media, footAction ? (_jsxs("div", { style: { display: "flex", flexDirection: "column", gap, padding: inset, flex: "1 1 auto", minWidth: 0 }, children: [words, actionButton] })) : words, cardLink] }));
343
+ const card = (_jsxs("article", { className: [
249
344
  "phi-card",
250
345
  href ? "phi-card--link" : null,
251
346
  highlight ? "phi-card--highlight" : null,
252
347
  hoverEffect !== "none" ? `phi-card--hover-${hoverEffect}` : null,
253
348
  surface.className,
254
- ].filter(Boolean).join(" "), "data-phi-card-variant": variant, style: boxStyle, children: [_jsx(PhiSurfaceGroundLayer, { ground: surface.ground, className: "phi-card__ground" }), surface.className ? _jsx(PhiSurfaceTone, { tone: config?.surface?.tone, children: content }) : content] }));
349
+ ].filter(Boolean).join(" "), "data-phi-card-variant": variant, style: boxStyle, children: [_jsx(PhiSurfaceGroundLayer, { ground: surface.ground, className: "phi-card__ground" }), ribbon, surface.className ? _jsx(PhiSurfaceTone, { tone: config?.surface?.tone, children: content }) : content] }));
350
+ /*
351
+ * A ribbon hangs over the card's edge, which the card -- clipping for its picture and its zoom -- cannot
352
+ * give a child of its own; it wraps the card instead (`PhiRibbonWrapControl`). An editor writes in it.
353
+ */
354
+ return badge != null && badgeStyle === "ribbon" ? (_jsx(PhiRibbonWrapControl, { text: badge, ...(config?.badgeColor ? { color: config.badgeColor } : {}), interactive: renderText != null, className: hoverEffect === "lift" ? "phi-card-ribbon phi-card-ribbon--lift" : "phi-card-ribbon", children: card })) : card;
255
355
  }
@@ -4,12 +4,26 @@
4
4
  * `text` is a heading. `stat` is a labelled figure: the label is the heading, so a card that counts
5
5
  * something says what it counted in the same place and type a text card says what it is about, and the
6
6
  * figure is drawn by the house's one statistic Control. `list` is a heading over a few lines the caller
7
- * draws and hands in (`listContent`), which only a Dashboard does today.
7
+ * draws and hands in (`listContent`), which only a Dashboard does today. `series` is a figure over time:
8
+ * the headline as a `stat` draws it, over a chart the caller draws and hands in the same way -- a Dashboard
9
+ * again, so the chart Control never loads with a Card on a Public page. `plan` is an offer: a price
10
+ * and what it is paid per, a monthly and a yearly one of each, over a list of what the plan includes and
11
+ * what it does not (`PhiBulletListEntry.state`). Several plan cards side by side are a Layout's row, and
12
+ * the recommended one is the card that is `highlight`ed.
8
13
  *
9
14
  * The body is chosen, never inferred from whether a value happens to have arrived. A card that decided
10
15
  * by presence would draw as text and reflow into a statistic the moment its figure landed.
11
16
  */
12
- export type PhiCardWidgetBody = "text" | "stat" | "list";
17
+ export type PhiCardWidgetBody = "text" | "stat" | "list" | "series" | "plan";
18
+ /**
19
+ * Which of a plan card's two prices it shows. A plan states one, the other, or both; one that states
20
+ * only the monthly price shows it under `yearly` as well, so a period switch on the page never leaves a
21
+ * card without a price. The page switches every plan at once by sending `billingPeriod`.
22
+ */
23
+ export declare const PHI_CARD_BILLING_PERIODS: readonly ["monthly", "yearly"];
24
+ export type PhiCardBillingPeriod = (typeof PHI_CARD_BILLING_PERIODS)[number];
25
+ /** A sent period as one of the two; anything else is not a period and changes nothing. */
26
+ export declare function readPhiCardBillingPeriod(value: unknown): PhiCardBillingPeriod | undefined;
13
27
  /**
14
28
  * The tag of the card's heading, and the step it is drawn at.
15
29
  *
@@ -24,6 +38,14 @@ export type PhiCardHeadingLevel = (typeof PHI_CARD_HEADING_LEVELS)[number];
24
38
  /** Logical, so `start` is the left in a left-to-right page and the right in a right-to-left one. */
25
39
  export declare const PHI_CARD_TEXT_ALIGNS: readonly ["start", "center", "end", "justify"];
26
40
  export type PhiCardTextAlign = (typeof PHI_CARD_TEXT_ALIGNS)[number];
41
+ /**
42
+ * How a card's badge is drawn. `corner` is a band flush in the top end corner, `tag` a rounded mark a
43
+ * little down the end edge -- both inside the card. `ribbon` hangs over the end edge with a fold behind
44
+ * it, and needs room beside the card. `none` draws nothing and keeps the words, to hide a badge for a
45
+ * while. Absent is `none`: a card has a badge once a style is chosen for it.
46
+ */
47
+ export declare const PHI_CARD_BADGE_STYLES: readonly ["none", "corner", "tag", "ribbon"];
48
+ export type PhiCardBadgeStyle = (typeof PHI_CARD_BADGE_STYLES)[number];
27
49
  /**
28
50
  * Where the icon stands: before the heading, small, or at the top, large -- at the start, the middle or
29
51
  * the end of the line, over the picture when the card has one, on a ground of its own so it reads on any
@@ -48,6 +70,11 @@ export type PhiCardHoverEffect = (typeof PHI_CARD_HOVER_EFFECTS)[number];
48
70
  */
49
71
  export declare const PHI_CARD_VARIANTS: readonly ["default", "compact", "center"];
50
72
  export type PhiCardVariant = (typeof PHI_CARD_VARIANTS)[number];
51
- /** The words a card shows, each in its own place; what an editor can put a field in. */
52
- export declare const PHI_CARD_TEXT_SLOTS: readonly ["eyebrow", "title", "description", "meta", "value"];
73
+ /**
74
+ * The words a card shows, each in its own place; what an editor can put a field in, and what a signal can
75
+ * write. `badge` is the band at the card's end edge, any body may carry one. The prices are figures like
76
+ * `value` and are never translated: a price that differs by country is sent by a Controller or comes
77
+ * from a Provider's row, not from a translator. The periods (`/ month`) are words and are.
78
+ */
79
+ export declare const PHI_CARD_TEXT_SLOTS: readonly ["eyebrow", "title", "description", "meta", "value", "badge", "price", "pricePeriod", "priceYearly", "pricePeriodYearly"];
53
80
  export type PhiCardTextSlot = (typeof PHI_CARD_TEXT_SLOTS)[number];
@@ -2,6 +2,16 @@
2
2
  * The Card Widget's words, apart from its Client half: the Widget's definition is read on the server, and
3
3
  * a value imported from the Client file would make that file a client reference of every route.
4
4
  */
5
+ /**
6
+ * Which of a plan card's two prices it shows. A plan states one, the other, or both; one that states
7
+ * only the monthly price shows it under `yearly` as well, so a period switch on the page never leaves a
8
+ * card without a price. The page switches every plan at once by sending `billingPeriod`.
9
+ */
10
+ export const PHI_CARD_BILLING_PERIODS = ["monthly", "yearly"];
11
+ /** A sent period as one of the two; anything else is not a period and changes nothing. */
12
+ export function readPhiCardBillingPeriod(value) {
13
+ return PHI_CARD_BILLING_PERIODS.includes(value) ? value : undefined;
14
+ }
5
15
  /**
6
16
  * The tag of the card's heading, and the step it is drawn at.
7
17
  *
@@ -14,6 +24,13 @@
14
24
  export const PHI_CARD_HEADING_LEVELS = ["h2", "h3", "h4"];
15
25
  /** Logical, so `start` is the left in a left-to-right page and the right in a right-to-left one. */
16
26
  export const PHI_CARD_TEXT_ALIGNS = ["start", "center", "end", "justify"];
27
+ /**
28
+ * How a card's badge is drawn. `corner` is a band flush in the top end corner, `tag` a rounded mark a
29
+ * little down the end edge -- both inside the card. `ribbon` hangs over the end edge with a fold behind
30
+ * it, and needs room beside the card. `none` draws nothing and keeps the words, to hide a badge for a
31
+ * while. Absent is `none`: a card has a badge once a style is chosen for it.
32
+ */
33
+ export const PHI_CARD_BADGE_STYLES = ["none", "corner", "tag", "ribbon"];
17
34
  /**
18
35
  * Where the icon stands: before the heading, small, or at the top, large -- at the start, the middle or
19
36
  * the end of the line, over the picture when the card has one, on a ground of its own so it reads on any
@@ -35,5 +52,21 @@ export const PHI_CARD_HOVER_EFFECTS = ["none", "lift", "zoom", "icon"];
35
52
  * not another branch in every size the card draws. `default` is what a card without one is.
36
53
  */
37
54
  export const PHI_CARD_VARIANTS = ["default", "compact", "center"];
38
- /** The words a card shows, each in its own place; what an editor can put a field in. */
39
- export const PHI_CARD_TEXT_SLOTS = ["eyebrow", "title", "description", "meta", "value"];
55
+ /**
56
+ * The words a card shows, each in its own place; what an editor can put a field in, and what a signal can
57
+ * write. `badge` is the band at the card's end edge, any body may carry one. The prices are figures like
58
+ * `value` and are never translated: a price that differs by country is sent by a Controller or comes
59
+ * from a Provider's row, not from a translator. The periods (`/ month`) are words and are.
60
+ */
61
+ export const PHI_CARD_TEXT_SLOTS = [
62
+ "eyebrow",
63
+ "title",
64
+ "description",
65
+ "meta",
66
+ "value",
67
+ "badge",
68
+ "price",
69
+ "pricePeriod",
70
+ "priceYearly",
71
+ "pricePeriodYearly",
72
+ ];
@@ -68,9 +68,16 @@ function renderInlineNodes(inlines) {
68
68
  }
69
69
  });
70
70
  }
71
- function renderBlocks(blocks, token, paragraphBlockStyle, headingBlockStyle, lists) {
71
+ function renderBlocks(blocks, token, paragraphStyle, headingStyle, lists, atStart = false) {
72
72
  return blocks.map((block, index) => {
73
73
  const key = `${block.kind}-${index}`;
74
+ /*
75
+ * The first block of a text, or of a quote, keeps no space before it: the space before a block
76
+ * parts it from the block above, and there is none -- the Widget's own edge stands there.
77
+ */
78
+ const leading = atStart && index === 0;
79
+ const paragraphBlockStyle = leading ? { ...paragraphStyle, marginBlockStart: 0 } : paragraphStyle;
80
+ const headingBlockStyle = leading ? { ...headingStyle, paddingBlockStart: 0 } : headingStyle;
74
81
  switch (block.kind) {
75
82
  case "heading":
76
83
  return (_jsx(PhiTypographyControl, { presentation: "title", id: block.id, level: block.level, style: headingBlockStyle, children: renderInlineNodes(block.inlines) }, key));
@@ -81,19 +88,31 @@ function renderBlocks(blocks, token, paragraphBlockStyle, headingBlockStyle, lis
81
88
  margin: 0,
82
89
  paddingInlineStart: PHI_SPACE.md,
83
90
  borderInlineStart: `3px solid ${token.colorBorderSecondary}`,
84
- }, children: _jsx("div", { style: { display: "grid", gap: 0 }, children: renderBlocks(block.children, token, paragraphBlockStyle, headingBlockStyle, lists) }) }, key));
91
+ }, children: _jsx("div", { style: { display: "grid", gap: 0 }, children: renderBlocks(block.children, token, paragraphStyle, headingStyle, lists, true) }) }, key));
85
92
  case "list":
86
93
  /*
87
94
  * The house's list, set by the Widget's list settings. A `1.` list counts whatever its level's
88
95
  * marker says: the numbers are the text's, not a look. A list inside an entry is one level down.
89
96
  */
90
- return (_jsx(PhiBulletListControl, { listStyle: lists.style, depth: lists.depth, ordered: block.ordered, start: block.start, items: block.items.map((itemBlocks) => ({
91
- content: (_jsx("div", { style: { display: "grid", gap: PHI_SPACE.xs, minWidth: 0 }, children: renderBlocks(itemBlocks, token, paragraphBlockStyle, headingBlockStyle, { ...lists, depth: lists.depth + 1 }) })),
97
+ return (_jsx(PhiBulletListControl, { listStyle: lists.style, depth: lists.depth, ordered: block.ordered, start: block.start,
98
+ /*
99
+ * The list stands among the text's blocks as a paragraph does: the entries draw close, but the
100
+ * block after the last one keeps the text's spacing. A list inside an entry gets the entry's
101
+ * zeroed spacing, so it sits in its entry's grid.
102
+ */
103
+ blockSpacing: {
104
+ marginBlockStart: paragraphBlockStyle.marginBlockStart,
105
+ marginBlockEnd: paragraphBlockStyle.marginBlockEnd,
106
+ }, items: block.items.map((itemBlocks) => ({
107
+ content: (_jsx("div", { style: { display: "grid", gap: PHI_SPACE.xs, minWidth: 0 }, children: renderBlocks(itemBlocks, token, { ...paragraphStyle, marginBlockStart: 0, marginBlockEnd: 0 }, headingStyle, { ...lists, depth: lists.depth + 1 }) })),
92
108
  })) }, key));
93
109
  case "code":
94
110
  return (_jsx("pre", { "data-phi-code-language": block.language ?? undefined, style: {
95
111
  margin: 0,
96
- padding: PHI_SPACE.md,
112
+ // A code block stands among the text's blocks as a paragraph does, with the text's spacing.
113
+ marginBlockStart: paragraphBlockStyle.marginBlockStart,
114
+ marginBlockEnd: paragraphBlockStyle.marginBlockEnd,
115
+ padding: PHI_SPACE.base,
97
116
  overflowX: "auto",
98
117
  borderRadius: token.borderRadiusSM,
99
118
  background: token.colorFillQuaternary,
@@ -157,15 +176,25 @@ export function PhiMarkdownWidgetClient({ config }) {
157
176
  marginBlockStart: resolvePhiSpacingScaleValue(config?.textBlockSpacingBefore ?? "none"),
158
177
  marginBlockEnd: resolvePhiSpacingScaleValue(config?.textBlockSpacingAfter ?? "sm"),
159
178
  };
179
+ /*
180
+ * The space before a heading is padding, not margin, so it adds to the space after the block above
181
+ * however the text is laid out: in the grid margins never collapse, in the flow that pictures need
182
+ * they would, and the same setting would part a heading from its paragraph by less there.
183
+ */
160
184
  const headingBlockStyle = {
161
185
  margin: 0,
162
- marginBlockStart: resolvePhiSpacingScaleValue(config?.headingBlockSpacingBefore ?? "none"),
186
+ paddingBlockStart: resolvePhiSpacingScaleValue(config?.headingBlockSpacingBefore ?? "sm"),
163
187
  marginBlockEnd: resolvePhiSpacingScaleValue(config?.headingBlockSpacingAfter ?? "sm"),
164
188
  };
165
- return (_jsx("div", { className: config?.imageFloat ? `phi-markdown-body phi-markdown-body--float-${config.imageFloat}` : undefined, style: config?.imageFloat
166
- ? { display: "flow-root", width: "100%", textAlign: config.textAlign, containerType: "inline-size" }
167
- : { display: "grid", gap: 0, width: "100%", textAlign: config?.textAlign }, children: renderBlocks(blocks, token, paragraphBlockStyle, headingBlockStyle, {
189
+ return (_jsx("div", { className: config?.imageFloat
190
+ ? `phi-markdown-text phi-markdown-body phi-markdown-body--float-${config.imageFloat}`
191
+ : "phi-markdown-text",
192
+ // The text's line height for everything in it, lists included: a list entry otherwise takes the
193
+ // browser's `normal`, and its marker centres on a line shorter than the one its words stand on.
194
+ style: config?.imageFloat
195
+ ? { display: "flow-root", width: "100%", textAlign: config.textAlign, containerType: "inline-size", lineHeight: token.lineHeight }
196
+ : { display: "grid", gap: 0, width: "100%", textAlign: config?.textAlign, lineHeight: token.lineHeight }, children: renderBlocks(blocks, token, paragraphBlockStyle, headingBlockStyle, {
168
197
  style: resolvePhiBulletListStyle(config?.list),
169
198
  depth: 1,
170
- }) }));
199
+ }, true) }));
171
200
  }
@@ -328,21 +328,3 @@ export declare const PHI_MULTI_SELECT_CONTROL_SIGNALS: {
328
328
  valueType: "none";
329
329
  })[];
330
330
  };
331
- export declare const PHI_DRAG_SOURCE_CONTROL_SIGNALS: {
332
- emits: ({
333
- id: string;
334
- action: "start";
335
- valueType: "json";
336
- valueSchema: `${string}/signals/${string}`;
337
- } | {
338
- id: string;
339
- action: "change";
340
- valueType: "json";
341
- valueSchema: `${string}/signals/${string}`;
342
- } | {
343
- id: string;
344
- action: "stop";
345
- valueType: "json";
346
- valueSchema: `${string}/signals/${string}`;
347
- })[];
348
- };
@@ -89,6 +89,16 @@ export const PHI_CARD_SIGNALS = {
89
89
  { id: "description", channel: "description", action: "change", valueType: "string" },
90
90
  { id: "meta", channel: "meta", action: "change", valueType: "string" },
91
91
  { id: "highlight", channel: "highlight", action: "change", valueType: "boolean" },
92
+ { id: "badge", channel: "badge", action: "change", valueType: "string" },
93
+ /*
94
+ * A plan's prices, for a Controller that knows them better than the page does -- by the reader's
95
+ * country, say -- and the period a switch on the page shows (`monthly` or `yearly`).
96
+ */
97
+ { id: "price", channel: "price", action: "change", valueType: "string" },
98
+ { id: "pricePeriod", channel: "pricePeriod", action: "change", valueType: "string" },
99
+ { id: "priceYearly", channel: "priceYearly", action: "change", valueType: "string" },
100
+ { id: "pricePeriodYearly", channel: "pricePeriodYearly", action: "change", valueType: "string" },
101
+ { id: "billingPeriod", channel: "billingPeriod", action: "change", valueType: "string" },
92
102
  ],
93
103
  };
94
104
  export const PHI_TEXT_CONTROL_SIGNALS = {
@@ -227,25 +237,3 @@ export const PHI_MULTI_SELECT_CONTROL_SIGNALS = {
227
237
  { ...PHI_CONTROL_CLEAR_SIGNAL, channel: "selection" },
228
238
  ],
229
239
  };
230
- export const PHI_DRAG_SOURCE_CONTROL_SIGNALS = {
231
- emits: [
232
- {
233
- id: "dragStart",
234
- action: "start",
235
- valueType: "json",
236
- valueSchema: PHI_SIGNAL_VALUE_SCHEMAS.dragDrop,
237
- },
238
- {
239
- id: "dragChange",
240
- action: "change",
241
- valueType: "json",
242
- valueSchema: PHI_SIGNAL_VALUE_SCHEMAS.dragDrop,
243
- },
244
- {
245
- id: "dragEnd",
246
- action: "stop",
247
- valueType: "json",
248
- valueSchema: PHI_SIGNAL_VALUE_SCHEMAS.dragDrop,
249
- },
250
- ],
251
- };
@@ -1,9 +1,10 @@
1
1
  import type { PhiWorkspaceCatalogState } from "./catalog-state";
2
2
  export type { PhiWorkspaceCatalogArea, PhiWorkspaceCatalogState } from "./catalog-state";
3
3
  /**
4
- * One scope per workspace host. Both the Builder and, later, the Editor write into "public".
4
+ * One scope per workspace host, not one per Area. Both the Builder and, later, the Editor write into it;
5
+ * which Area is open is `area` inside it, and what belongs to an Area is keyed by Area there.
5
6
  */
6
7
  export declare const PHI_WORKSPACE_CATALOG_SCOPE = "public";
7
8
  export declare const phiWorkspaceCatalogStore: import("../state/plugin-state-store").PhiPluginStateStore<PhiWorkspaceCatalogState>;
8
- export declare function usePhiWorkspaceCatalogValue<TSelected>(scopeKey: string, selector: (state: PhiWorkspaceCatalogState) => TSelected): TSelected;
9
- export declare function getPhiWorkspaceCatalogSnapshot(scopeKey: string): PhiWorkspaceCatalogState;
9
+ export declare function usePhiWorkspaceCatalogValue<TSelected>(selector: (state: PhiWorkspaceCatalogState) => TSelected): TSelected;
10
+ export declare function getPhiWorkspaceCatalogSnapshot(): PhiWorkspaceCatalogState;
@@ -2,7 +2,8 @@
2
2
  import { createEmptyPhiBuilderModulePresetPagesByArea } from "../../helpers/cms-page-catalog";
3
3
  import { createPhiPluginStateStore } from "../state/plugin-state-store";
4
4
  /**
5
- * One scope per workspace host. Both the Builder and, later, the Editor write into "public".
5
+ * One scope per workspace host, not one per Area. Both the Builder and, later, the Editor write into it;
6
+ * which Area is open is `area` inside it, and what belongs to an Area is keyed by Area there.
6
7
  */
7
8
  export const PHI_WORKSPACE_CATALOG_SCOPE = "public";
8
9
  function createDefaultWorkspaceCatalogState(scopeKey) {
@@ -25,9 +26,9 @@ function createDefaultWorkspaceCatalogState(scopeKey) {
25
26
  };
26
27
  }
27
28
  export const phiWorkspaceCatalogStore = createPhiPluginStateStore("@phis/ui/workspace-catalog", createDefaultWorkspaceCatalogState);
28
- export function usePhiWorkspaceCatalogValue(scopeKey, selector) {
29
- return phiWorkspaceCatalogStore.useStoreSelector(scopeKey, selector);
29
+ export function usePhiWorkspaceCatalogValue(selector) {
30
+ return phiWorkspaceCatalogStore.useStoreSelector(PHI_WORKSPACE_CATALOG_SCOPE, selector);
30
31
  }
31
- export function getPhiWorkspaceCatalogSnapshot(scopeKey) {
32
- return phiWorkspaceCatalogStore.getSnapshot(scopeKey);
32
+ export function getPhiWorkspaceCatalogSnapshot() {
33
+ return phiWorkspaceCatalogStore.getSnapshot(PHI_WORKSPACE_CATALOG_SCOPE);
33
34
  }
@@ -79,6 +79,7 @@ async function resolveDashboardCardScope({ bridge, area, locale, path, cookieHea
79
79
  locale,
80
80
  area,
81
81
  viewer: requestContext.viewer,
82
+ runtimeModuleCatalog: bridge.runtimeModuleCatalog,
82
83
  };
83
84
  /*
84
85
  * A route handler has no request runtime bound, and the label sets a card reads for its own title
@@ -11,7 +11,12 @@ export type PhiResolvedInternalReferences = {
11
11
  pages: readonly PhiResolvedPageReference[];
12
12
  assets: ReadonlyMap<number, PhiPublicMediaAssetReference>;
13
13
  };
14
- /** One Asset of the public reference projection, as the server writes it; a shape it does not match throws. */
14
+ /**
15
+ * One Asset of the public reference projection, as the server writes it; a shape it does not match throws.
16
+ *
17
+ * Every field, not five of them: what passed here went straight into a rendered page under a type that
18
+ * promised a focal rectangle and font metrics nobody had looked at.
19
+ */
15
20
  export declare function readPhiPublicMediaAssetReference(entry: unknown): PhiPublicMediaAssetReference;
16
21
  /**
17
22
  * Resolves both internal reference kinds, together with whatever else asks in the same turn.