themelia-react-ui 1.0.0 → 1.0.1

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 (257) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/README.md +39 -6
  3. package/dist/{accordion-BRWh3BM1.js → accordion-B-5Focs8.js} +2 -2
  4. package/dist/{accordion-BRWh3BM1.js.map → accordion-B-5Focs8.js.map} +1 -1
  5. package/dist/{affordance-geometry.generated-DXl-Zb3Z.js → affordance-geometry.generated-D8Jcfb0G.js} +10 -1
  6. package/dist/affordance-geometry.generated-D8Jcfb0G.js.map +1 -0
  7. package/dist/{ai-artifact-DkOArd3-.js → ai-artifact-B5tPpXnS.js} +5 -5
  8. package/dist/{ai-artifact-DkOArd3-.js.map → ai-artifact-B5tPpXnS.js.map} +1 -1
  9. package/dist/{app-shell-BH_bGcE2.js → app-shell-at8Kt4l_.js} +3 -3
  10. package/dist/{app-shell-BH_bGcE2.js.map → app-shell-at8Kt4l_.js.map} +1 -1
  11. package/dist/{attachment-DsLgNHXt.js → attachment-BO2R47wn.js} +2 -2
  12. package/dist/{attachment-DsLgNHXt.js.map → attachment-BO2R47wn.js.map} +1 -1
  13. package/dist/{auth-BDB1V_2q.js → auth-OFwWSAap.js} +4 -4
  14. package/dist/{auth-BDB1V_2q.js.map → auth-OFwWSAap.js.map} +1 -1
  15. package/dist/{avatar-CsnWaYmt.js → avatar-Bpzty83c.js} +73 -68
  16. package/dist/avatar-Bpzty83c.js.map +1 -0
  17. package/dist/base/accordion.js +1 -1
  18. package/dist/base/attachment.js +1 -1
  19. package/dist/base/avatar.js +1 -1
  20. package/dist/base/cards.js +2 -2
  21. package/dist/base/cascader.js +6 -6
  22. package/dist/base/choice-inputs.js +3 -2
  23. package/dist/base/code-block.js +1 -1
  24. package/dist/base/combobox.js +1 -1
  25. package/dist/base/command.js +1 -1
  26. package/dist/base/date-pickers.js +2 -2
  27. package/dist/base/display.js +1 -1
  28. package/dist/base/feedback.js +4 -3
  29. package/dist/base/forms-numeric.js +1 -1
  30. package/dist/base/forms.js +2 -2
  31. package/dist/base/inline-edit.js +236 -0
  32. package/dist/base/inline-edit.js.map +1 -0
  33. package/dist/base/media-gallery.js +1 -1
  34. package/dist/base/navigation.js +3 -3
  35. package/dist/base/popover-menu.js +1 -1
  36. package/dist/base/popover.js +1 -1
  37. package/dist/base/repeaters.js +4 -4
  38. package/dist/base/sheet.js +1 -1
  39. package/dist/base/sidebar.js +1 -1
  40. package/dist/base/signature-pad.js +3 -3
  41. package/dist/base/skeleton.js +1 -1
  42. package/dist/base/spinner.js +1 -1
  43. package/dist/base/structure.js +1 -1
  44. package/dist/base/text-inputs.js +2 -2
  45. package/dist/base/tree.js +1 -1
  46. package/dist/base/upload-queue.js +1 -1
  47. package/dist/base/upload.js +3 -3
  48. package/dist/base/value-inputs.js +1 -1
  49. package/dist/blocks/admin.js +6 -6
  50. package/dist/blocks/ai.js +6 -6
  51. package/dist/blocks/analytics/usage-card.js +3 -0
  52. package/dist/blocks/analytics.js +361 -360
  53. package/dist/blocks/analytics.js.map +1 -1
  54. package/dist/blocks/collaboration.js +1 -1
  55. package/dist/blocks/commerce/receipt.js +1 -1
  56. package/dist/blocks/commerce.js +15 -15
  57. package/dist/blocks/data-display.js +1 -1
  58. package/dist/blocks/onboarding.js +3 -3
  59. package/dist/blocks/planning.js +311 -0
  60. package/dist/blocks/planning.js.map +1 -0
  61. package/dist/blocks/timelines.js +1 -1
  62. package/dist/{cards-BMB0laLG.js → cards-Cum56XOF.js} +3 -3
  63. package/dist/{cards-BMB0laLG.js.map → cards-Cum56XOF.js.map} +1 -1
  64. package/dist/checkbox-BavDRjF7.js +34 -0
  65. package/dist/checkbox-BavDRjF7.js.map +1 -0
  66. package/dist/{choice-inputs-CavA-SGV.js → choice-inputs-CC7XqPQO.js} +166 -191
  67. package/dist/choice-inputs-CC7XqPQO.js.map +1 -0
  68. package/dist/{code-block-DIlqzoiD.js → code-block-xHKbAJDj.js} +2 -2
  69. package/dist/{code-block-DIlqzoiD.js.map → code-block-xHKbAJDj.js.map} +1 -1
  70. package/dist/{combobox-HDftpzxt.js → combobox-DEbdr-3u.js} +2 -2
  71. package/dist/{combobox-HDftpzxt.js.map → combobox-DEbdr-3u.js.map} +1 -1
  72. package/dist/{combobox-CHD750do.js → combobox-xv3yJbzl.js} +7 -7
  73. package/dist/{combobox-CHD750do.js.map → combobox-xv3yJbzl.js.map} +1 -1
  74. package/dist/{command-D0kWBZfd.js → command-C0xe7u9B.js} +2 -2
  75. package/dist/{command-D0kWBZfd.js.map → command-C0xe7u9B.js.map} +1 -1
  76. package/dist/{comments-CvYeglMS.js → comments-DviPLnwy.js} +8 -8
  77. package/dist/{comments-CvYeglMS.js.map → comments-DviPLnwy.js.map} +1 -1
  78. package/dist/components/base/cards/smart-card.types.d.ts +2 -0
  79. package/dist/components/base/inline-edit/index.d.ts +2 -0
  80. package/dist/components/base/inline-edit/inline-edit.d.ts +81 -0
  81. package/dist/components/base/inline-edit/inline-edit.recipes.d.ts +6 -0
  82. package/dist/components/base/structure/structure.recipes.d.ts +6 -0
  83. package/dist/components/blocks/analytics/index.d.ts +1 -0
  84. package/dist/components/blocks/analytics/usage-card/index.d.ts +3 -0
  85. package/dist/components/blocks/analytics/usage-card/types.d.ts +52 -0
  86. package/dist/components/blocks/analytics/usage-card/usage-card.d.ts +6 -0
  87. package/dist/components/blocks/analytics/usage-card/usage-card.data.d.ts +19 -0
  88. package/dist/components/blocks/analytics/usage-card/usage-card.strings.d.ts +22 -0
  89. package/dist/components/blocks/planning/index.d.ts +3 -0
  90. package/dist/components/blocks/planning/task-card.d.ts +3 -0
  91. package/dist/components/blocks/planning/task-card.strings.d.ts +15 -0
  92. package/dist/components/blocks/planning/task-card.types.d.ts +66 -0
  93. package/dist/{containers-CPNyNo1_.js → containers-6s-ucRQQ.js} +3 -2
  94. package/dist/containers-6s-ucRQQ.js.map +1 -0
  95. package/dist/{data-display-b3d1TfL4.js → data-display-cWIRdeaf.js} +8 -8
  96. package/dist/{data-display-b3d1TfL4.js.map → data-display-cWIRdeaf.js.map} +1 -1
  97. package/dist/{date-picker-DI6kPNof.js → date-picker-CA6ogMQB.js} +5 -5
  98. package/dist/{date-picker-DI6kPNof.js.map → date-picker-CA6ogMQB.js.map} +1 -1
  99. package/dist/{date-pickers-ByP6Cv2z.js → date-pickers-BPIKLdsD.js} +4 -4
  100. package/dist/{date-pickers-ByP6Cv2z.js.map → date-pickers-BPIKLdsD.js.map} +1 -1
  101. package/dist/{display-ByI5tkqy.js → display-CFM5myut.js} +3 -3
  102. package/dist/{display-ByI5tkqy.js.map → display-CFM5myut.js.map} +1 -1
  103. package/dist/features/activities.js +4 -4
  104. package/dist/features/ai-chat.js +4 -4
  105. package/dist/features/async-preview.js +4 -4
  106. package/dist/features/combobox.js +1 -1
  107. package/dist/features/comments.js +1 -1
  108. package/dist/features/data-view.js +5 -5
  109. package/dist/features/email-composer.js +11 -11
  110. package/dist/features/event-calendar.js +2 -2
  111. package/dist/features/event-calendar.js.map +1 -1
  112. package/dist/features/filters.js +1 -1
  113. package/dist/features/global-search.js +6 -6
  114. package/dist/features/map.js +3 -3
  115. package/dist/features/media-library.js +8 -8
  116. package/dist/features/mentions.js +1 -1
  117. package/dist/features/overlays.js +1 -1
  118. package/dist/features/products.js +43 -42
  119. package/dist/features/products.js.map +1 -1
  120. package/dist/features/questionnaire.js +107 -106
  121. package/dist/features/questionnaire.js.map +1 -1
  122. package/dist/features/resource-assignment.js +5 -5
  123. package/dist/features/resource.js +7 -7
  124. package/dist/features/rich-text-editor.js +1 -1
  125. package/dist/features/schema-form.js +11 -11
  126. package/dist/features/schema-form.js.map +1 -1
  127. package/dist/features/suggestions.js +2 -2
  128. package/dist/features/sync.js +2 -2
  129. package/dist/features/table.js +1 -1
  130. package/dist/features/theme-tweaker.js +11 -11
  131. package/dist/feedback-DWUkgEjR.js +233 -0
  132. package/dist/feedback-DWUkgEjR.js.map +1 -0
  133. package/dist/{field-affordance-recipes-CHdUtn2Z.js → field-affordance-recipes-IjzPrCTw.js} +2 -2
  134. package/dist/{field-affordance-recipes-CHdUtn2Z.js.map → field-affordance-recipes-IjzPrCTw.js.map} +1 -1
  135. package/dist/{filters-qtrcv1hf.js → filters-BhsUtsxW.js} +9 -9
  136. package/dist/{filters-qtrcv1hf.js.map → filters-BhsUtsxW.js.map} +1 -1
  137. package/dist/{form-field-C6W-y2hR.js → form-field-Bn7ZH1rA.js} +2 -2
  138. package/dist/{form-field-C6W-y2hR.js.map → form-field-Bn7ZH1rA.js.map} +1 -1
  139. package/dist/{form-sizing-39NohSqn.js → form-sizing-BWs70_a2.js} +4 -3
  140. package/dist/{form-sizing-39NohSqn.js.map → form-sizing-BWs70_a2.js.map} +1 -1
  141. package/dist/{forms-BF-HSbff.js → forms-B7pzS25o.js} +5 -5
  142. package/dist/{forms-BF-HSbff.js.map → forms-B7pzS25o.js.map} +1 -1
  143. package/dist/{forms-numeric-Y15Bg5Nr.js → forms-numeric-BUBxELBv.js} +18 -18
  144. package/dist/{forms-numeric-Y15Bg5Nr.js.map → forms-numeric-BUBxELBv.js.map} +1 -1
  145. package/dist/{header-B8ex54cY.js → header-C59QZyxV.js} +6 -6
  146. package/dist/{header-B8ex54cY.js.map → header-C59QZyxV.js.map} +1 -1
  147. package/dist/{hooks-D6UBVzf2.js → hooks-CM1Vp9Pe.js} +2 -2
  148. package/dist/{hooks-D6UBVzf2.js.map → hooks-CM1Vp9Pe.js.map} +1 -1
  149. package/dist/{input-DMorJiTI.js → input-WwYQZJzG.js} +3 -3
  150. package/dist/{input-DMorJiTI.js.map → input-WwYQZJzG.js.map} +1 -1
  151. package/dist/layout/app-shell.js +1 -1
  152. package/dist/layout/auth.js +1 -1
  153. package/dist/layout/containers.js +1 -1
  154. package/dist/layout/header.js +1 -1
  155. package/dist/layout/hooks.js +1 -1
  156. package/dist/layout/navigation.js +1 -1
  157. package/dist/layout/page.js +1 -1
  158. package/dist/layout/settings.js +1 -1
  159. package/dist/layout/sidebar.js +2 -2
  160. package/dist/layout/workspace.js +1 -1
  161. package/dist/layout.js +10 -10
  162. package/dist/lib/affordance-geometry.generated.d.ts +9 -0
  163. package/dist/{media-gallery-Ca4YmvBi.js → media-gallery-DhDRgnVZ.js} +2 -2
  164. package/dist/{media-gallery-Ca4YmvBi.js.map → media-gallery-DhDRgnVZ.js.map} +1 -1
  165. package/dist/{mentions-CRio8mTm.js → mentions-B8Ko-fhS.js} +4 -4
  166. package/dist/{mentions-CRio8mTm.js.map → mentions-B8Ko-fhS.js.map} +1 -1
  167. package/dist/{message-B5-6LeYl.js → message-COsdEvXT.js} +2 -2
  168. package/dist/{message-B5-6LeYl.js.map → message-COsdEvXT.js.map} +1 -1
  169. package/dist/{navigation-DqEITuD2.js → navigation-BUIn2Qxx.js} +2 -2
  170. package/dist/{navigation-DqEITuD2.js.map → navigation-BUIn2Qxx.js.map} +1 -1
  171. package/dist/{navigation-BTrEb5u4.js → navigation-DBEu4POU.js} +3 -3
  172. package/dist/{navigation-BTrEb5u4.js.map → navigation-DBEu4POU.js.map} +1 -1
  173. package/dist/{navigation-row-recipes-BFpvGPGE.js → navigation-row-recipes-GVh11KiT.js} +2 -2
  174. package/dist/{navigation-row-recipes-BFpvGPGE.js.map → navigation-row-recipes-GVh11KiT.js.map} +1 -1
  175. package/dist/{overlays-DBqV0J_V.js → overlays-B11wZka6.js} +4 -4
  176. package/dist/{overlays-DBqV0J_V.js.map → overlays-B11wZka6.js.map} +1 -1
  177. package/dist/{page-BMBGjJY8.js → page-BV6ioQg3.js} +5 -5
  178. package/dist/{page-BMBGjJY8.js.map → page-BV6ioQg3.js.map} +1 -1
  179. package/dist/{page-header-BH41wCyY.js → page-header-DQRa0jug.js} +2 -2
  180. package/dist/{page-header-BH41wCyY.js.map → page-header-DQRa0jug.js.map} +1 -1
  181. package/dist/{popover-TInGXsjg.js → popover-CoLDEg19.js} +2 -2
  182. package/dist/{popover-TInGXsjg.js.map → popover-CoLDEg19.js.map} +1 -1
  183. package/dist/{popover-menu-BzqXqE72.js → popover-menu-GLIQTJTx.js} +4 -4
  184. package/dist/{popover-menu-BzqXqE72.js.map → popover-menu-GLIQTJTx.js.map} +1 -1
  185. package/dist/progress-BOe8l_FZ.js +168 -0
  186. package/dist/progress-BOe8l_FZ.js.map +1 -0
  187. package/dist/{receipt-DYWTQGEc.js → receipt-BM8xsGFy.js} +3 -3
  188. package/dist/{receipt-DYWTQGEc.js.map → receipt-BM8xsGFy.js.map} +1 -1
  189. package/dist/{rich-text-editor-BZSJchAF.js → rich-text-editor-CoVrTiSv.js} +2 -2
  190. package/dist/{rich-text-editor-BZSJchAF.js.map → rich-text-editor-CoVrTiSv.js.map} +1 -1
  191. package/dist/services/actions.js +1 -1
  192. package/dist/{settings-D9f_wdIC.js → settings-BnCyyPOJ.js} +3 -3
  193. package/dist/{settings-D9f_wdIC.js.map → settings-BnCyyPOJ.js.map} +1 -1
  194. package/dist/{sheet-vOUloJ4O.js → sheet-B-q914Ad.js} +2 -2
  195. package/dist/{sheet-vOUloJ4O.js.map → sheet-B-q914Ad.js.map} +1 -1
  196. package/dist/{sidebar-C3UKkbC5.js → sidebar-C_2p3Tfj.js} +6 -6
  197. package/dist/{sidebar-C3UKkbC5.js.map → sidebar-C_2p3Tfj.js.map} +1 -1
  198. package/dist/{sidebar-CNBKFDRW.js → sidebar-DPR7fmqN.js} +4 -4
  199. package/dist/{sidebar-CNBKFDRW.js.map → sidebar-DPR7fmqN.js.map} +1 -1
  200. package/dist/{skeleton-BvRhK8y-.js → skeleton-CmT1ppqb.js} +2 -2
  201. package/dist/{skeleton-BvRhK8y-.js.map → skeleton-CmT1ppqb.js.map} +1 -1
  202. package/dist/{smart-card-B5FcKODh.js → smart-card-CYLn46e6.js} +119 -118
  203. package/dist/smart-card-CYLn46e6.js.map +1 -0
  204. package/dist/{spinner-JtlFJ7Nc.js → spinner-BY9HbUEh.js} +2 -2
  205. package/dist/{spinner-JtlFJ7Nc.js.map → spinner-BY9HbUEh.js.map} +1 -1
  206. package/dist/{structure-BvW4vG4H.js → structure-MvKVq-oL.js} +13 -13
  207. package/dist/{structure-BvW4vG4H.js.map → structure-MvKVq-oL.js.map} +1 -1
  208. package/dist/{structure.recipes-DjqnBpwz.js → structure.recipes-Bqhf9oIh.js} +2 -2
  209. package/dist/structure.recipes-Bqhf9oIh.js.map +1 -0
  210. package/dist/style.css +1 -1
  211. package/dist/{table-ghtAQ-JJ.js → table-BS39xnlq.js} +6 -6
  212. package/dist/{table-ghtAQ-JJ.js.map → table-BS39xnlq.js.map} +1 -1
  213. package/dist/{tabs-DY09eoZg.js → tabs-B5cNMWiP.js} +2 -2
  214. package/dist/{tabs-DY09eoZg.js.map → tabs-B5cNMWiP.js.map} +1 -1
  215. package/dist/{text-inputs-BhOcedTo.js → text-inputs-Dh9XGyiS.js} +4 -4
  216. package/dist/{text-inputs-BhOcedTo.js.map → text-inputs-Dh9XGyiS.js.map} +1 -1
  217. package/dist/{timelines-CnZ2S_Gr.js → timelines-B9ICkQcV.js} +2 -2
  218. package/dist/{timelines-CnZ2S_Gr.js.map → timelines-B9ICkQcV.js.map} +1 -1
  219. package/dist/{tree-COD9BGdU.js → tree-BdWSaoFT.js} +2 -2
  220. package/dist/{tree-COD9BGdU.js.map → tree-BdWSaoFT.js.map} +1 -1
  221. package/dist/{upload-DIzw1dx1.js → upload-D8Za5x_c.js} +4 -4
  222. package/dist/{upload-DIzw1dx1.js.map → upload-D8Za5x_c.js.map} +1 -1
  223. package/dist/{upload-queue-xRJ3qDmd.js → upload-queue-hIIYBLS7.js} +3 -3
  224. package/dist/{upload-queue-xRJ3qDmd.js.map → upload-queue-hIIYBLS7.js.map} +1 -1
  225. package/dist/usage-card-DnmnJ58D.js +458 -0
  226. package/dist/usage-card-DnmnJ58D.js.map +1 -0
  227. package/dist/{value-inputs-Co1fu-xv.js → value-inputs-DX2dbxjj.js} +7 -7
  228. package/dist/{value-inputs-Co1fu-xv.js.map → value-inputs-DX2dbxjj.js.map} +1 -1
  229. package/dist/{workspace-Cbqz4FzN.js → workspace-C1PZmk8L.js} +4 -4
  230. package/dist/{workspace-Cbqz4FzN.js.map → workspace-C1PZmk8L.js.map} +1 -1
  231. package/docs/consumer-skill/SKILL.md +120 -17
  232. package/docs/consumer-skill/examples/detail.tsx +7 -8
  233. package/docs/consumer-skill/examples/manifest.json +14 -0
  234. package/docs/consumer-skill/examples/planning-usage-edit.tsx +29 -0
  235. package/docs/consumer-skill/examples/scoped-directory.tsx +77 -0
  236. package/docs/consumer-skill/references/composition.md +103 -0
  237. package/docs/consumer-skill/references/design-contract.md +4 -3
  238. package/docs/consumer-skill/references/discovery.md +17 -0
  239. package/docs/consumer-skill/references/installation.md +20 -3
  240. package/docs/consumer-skill/references/integration.md +12 -0
  241. package/docs/consumer-skill/references/public-api.json +452 -229
  242. package/docs/consumer-skill/references/review.md +74 -0
  243. package/docs/consumer-skill/references/tokens.json +1 -1
  244. package/docs/consumer-skill/references/workflows.md +97 -1
  245. package/docs/consumer-skill/scripts/check-composition.mjs +31 -0
  246. package/docs/consumer-skill/scripts/composition-policy.mjs +155 -0
  247. package/docs/consumer-skill/scripts/discovery.mjs +6 -1
  248. package/docs/consumer-skill/scripts/surface-policy.mjs +22 -0
  249. package/package.json +24 -3
  250. package/dist/affordance-geometry.generated-DXl-Zb3Z.js.map +0 -1
  251. package/dist/avatar-CsnWaYmt.js.map +0 -1
  252. package/dist/choice-inputs-CavA-SGV.js.map +0 -1
  253. package/dist/containers-CPNyNo1_.js.map +0 -1
  254. package/dist/feedback-a9j9J-9A.js +0 -391
  255. package/dist/feedback-a9j9J-9A.js.map +0 -1
  256. package/dist/smart-card-B5FcKODh.js.map +0 -1
  257. package/dist/structure.recipes-DjqnBpwz.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-Cbqz4FzN.js","names":["Icon","React","_Fragment","Text","DisplayLabel","Stack","Progress","Value","SecondaryValue","Badge","ItemMedia","ItemDescription","ItemActions","ItemGroup","ItemContent","Item","ItemTitle","useLayoutLinkRenderer","React$1","Fragment$1","defaultWorkspaceRecordHeaderStrings","defaultWorkspaceNavStrings","value","defaultWorkspaceLocaleStripStrings","CONTENT_WIDTH_CLASS","STATUS_ICON","Check","Circle","CircleAlert","STATUS_CLASS","clampPercent","DynamicWorkspaceIcon","icon","getStatus","item","active","WorkspaceLayout","props","hasSidebar","sidebar","hasRail","rail","ariaLabel","cn","contentWidth","className","header","headerClassName","bodyClassName","sidebarClassName","mainClassName","contentClassName","railClassName","WorkspaceRecordHeader","stringsProp","strings","useStrings","hasMetadata","metadata","media","titleSlot","Heading","title","badges","status","description","index","actions","secondaryActions","headerEnd","WorkspaceNav","resolvedRenderLink","groups","group","activeId","StatusIcon","completion","handleSelect","context","renderItem","rowContent","itemClassName","linkNode","footerSlot","WorkspaceLocaleStrip","handleLocaleClick","locale","onLocaleChange","locales","activeLocale","Button"],"sources":["../src/components/layout/workspace/workspace.strings.ts","../src/components/layout/workspace/workspace.tsx"],"sourcesContent":["export interface WorkspaceRecordHeaderStrings {\n\tmetadataLabel: string;\n\tactionsLabel: string;\n\tsecondaryActionsLabel: string;\n}\n\nexport const defaultWorkspaceRecordHeaderStrings: WorkspaceRecordHeaderStrings = {\n\tmetadataLabel: 'Record metadata',\n\tactionsLabel: 'Record actions',\n\tsecondaryActionsLabel: 'Secondary actions',\n};\n\nexport interface WorkspaceNavStrings {\n\tariaLabel: string;\n\tcompletionLabel: (value: number) => string;\n\tcurrentLabel: string;\n}\n\nexport const defaultWorkspaceNavStrings: WorkspaceNavStrings = {\n\tariaLabel: 'Workspace navigation',\n\tcompletionLabel: (value) => `${value}% complete`,\n\tcurrentLabel: 'Current',\n};\n\nexport interface WorkspaceLocaleStripStrings {\n\tariaLabel: string;\n\tactiveLabel: string;\n\tcompletionLabel: (value: number) => string;\n}\n\nexport const defaultWorkspaceLocaleStripStrings: WorkspaceLocaleStripStrings = {\n\tariaLabel: 'Workspace locales',\n\tactiveLabel: 'Active',\n\tcompletionLabel: (value) => `${value}% complete`,\n};\n","import * as React from 'react';\nimport {\n\tCheck,\n\tCircle,\n\tCircleAlert,\n\ttype LucideIcon,\n\t} from 'lucide-react';\n\nimport { Badge } from '../../base/badge';\nimport { Button } from '../../base/buttons';\nimport { Progress } from '../../base/feedback';\nimport {\n\tItem,\n\tItemActions,\n\tItemContent,\n\tItemDescription,\n\tItemGroup,\n\tItemMedia,\n\tItemTitle,\n} from '../../base/item';\nimport { Stack } from '../../base/structure';\nimport { SecondaryValue, Value } from '../../primitives';\nimport { DisplayLabel, Heading, Text } from '../../typography';\nimport { useStrings } from '../../../lib/strings';\nimport { cn } from '../../../lib/utils';\n\nimport { useLayoutLinkRenderer } from '../hooks';\nimport type { LayoutIconComponent } from '../layout.types';\nimport {\n\tdefaultWorkspaceLocaleStripStrings,\n\tdefaultWorkspaceNavStrings,\n\tdefaultWorkspaceRecordHeaderStrings,\n} from './workspace.strings';\nimport type {\n\tWorkspaceContentWidth,\n\tWorkspaceLayoutProps,\n\tWorkspaceLocaleItem,\n\tWorkspaceLocaleStripProps,\n\tWorkspaceNavItem,\n\tWorkspaceNavItemStatus,\n\tWorkspaceNavProps,\n\tWorkspaceRecordHeaderProps,\n} from './workspace.types';\n\nconst CONTENT_WIDTH_CLASS: Record<WorkspaceContentWidth, string> = {\n\tdefault: '[--workspace-content-max-width:58rem]',\n\twide: '[--workspace-content-max-width:86rem]',\n\tfull: '[--workspace-content-max-width:none]',\n};\n\nconst STATUS_ICON: Record<WorkspaceNavItemStatus, LucideIcon> = {\n\tcomplete: Check,\n\tcurrent: Circle,\n\tattention: CircleAlert,\n\tdisabled: Circle,\n\tidle: Circle,\n};\n\nconst STATUS_CLASS: Record<WorkspaceNavItemStatus, string> = {\n\tcomplete: 'text-success',\n\tcurrent: 'text-primary-accent',\n\tattention: 'text-warning',\n\tdisabled: 'text-muted-foreground/40',\n\tidle: 'text-muted-foreground',\n};\n\nfunction clampPercent(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.min(100, Math.max(0, Math.round(value)));\n}\n\nfunction DynamicWorkspaceIcon({\n\ticon,\n\tclassName,\n}: {\n\t/** Leading glyph. */\n\ticon?: LayoutIconComponent;\n\tclassName?: string;\n}) {\n\tif (!icon) return null;\n\tconst Icon = icon;\n\treturn <Icon className={className} aria-hidden=\"true\" />;\n}\n\nfunction getStatus(item: WorkspaceNavItem, active: boolean): WorkspaceNavItemStatus {\n\tif (item.disabled) return 'disabled';\n\tif (item.status) return item.status;\n\tif (item.warning) return 'attention';\n\tif (active) return 'current';\n\tif (item.completion !== undefined && clampPercent(item.completion) >= 100) return 'complete';\n\treturn 'idle';\n}\n\nexport const WorkspaceLayout = React.forwardRef<HTMLDivElement, WorkspaceLayoutProps>(function WorkspaceLayout({\n\theader,\n\tsidebar,\n\trail,\n\tchildren,\n\tcontentWidth = 'wide',\n\tclassName,\n\theaderClassName,\n\tbodyClassName,\n\tsidebarClassName,\n\tmainClassName,\n\tcontentClassName,\n\trailClassName,\n\tariaLabel,\n\tstyle,\n\t...props\n}, ref) {\n\tconst hasSidebar = !!sidebar;\n\tconst hasRail = !!rail;\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\taria-label={ariaLabel}\n\t\t\tclassName={cn(\n\t\t\t\t'workspace-layout--component flex h-full min-h-0 w-full flex-col overflow-hidden rounded-radius-md border border-border bg-background text-foreground',\n\t\t\t\t'[--workspace-sidebar-width:16rem] [--workspace-rail-width:20rem]',\n\t\t\t\tCONTENT_WIDTH_CLASS[contentWidth],\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tstyle={style}\n\t\t\t{...props}\n\t\t>\n\t\t\t{!!header && (\n\t\t\t\t<header className={cn('workspace-layout--header shrink-0 border-b border-border bg-background', headerClassName)}>\n\t\t\t\t\t{header}\n\t\t\t\t</header>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'workspace-layout--body grid min-h-0 flex-1 grid-cols-1 bg-muted/20',\n\t\t\t\t\thasSidebar && !hasRail && 'min-[80rem]:grid-cols-[var(--workspace-sidebar-width)_minmax(0,1fr)]',\n\t\t\t\t\thasSidebar && hasRail && 'min-[80rem]:grid-cols-[var(--workspace-sidebar-width)_minmax(0,1fr)] min-[96rem]:grid-cols-[var(--workspace-sidebar-width)_minmax(0,1fr)_var(--workspace-rail-width)]',\n\t\t\t\t\t!hasSidebar && hasRail && 'min-[96rem]:grid-cols-[minmax(0,1fr)_var(--workspace-rail-width)]',\n\t\t\t\t\tbodyClassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{!!hasSidebar && (\n\t\t\t\t\t<aside\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'workspace-layout--sidebar hidden min-h-0 border-r border-border bg-background min-[80rem]:block',\n\t\t\t\t\t\t\tsidebarClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"h-full overflow-y-auto overscroll-contain p-space-lg\">\n\t\t\t\t\t\t\t{sidebar}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</aside>\n\t\t\t\t)}\n\t\t\t\t<main\n\t\t\t\t\ttabIndex={0}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'workspace-layout--main min-h-0 min-w-0 overflow-y-auto overscroll-contain focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/70 focus-visible:ring-inset',\n\t\t\t\t\t\tmainClassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'workspace-layout--content mx-auto flex min-h-full w-full max-w-[var(--workspace-content-max-width)] flex-col gap-space-xl p-4 min-[64rem]:p-5',\n\t\t\t\t\t\t\tcontentWidth === 'full' && 'max-w-none',\n\t\t\t\t\t\t\tcontentClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</div>\n\t\t\t\t</main>\n\t\t\t\t{!!hasRail && (\n\t\t\t\t\t<aside\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'workspace-layout--rail hidden min-h-0 border-l border-border bg-background min-[96rem]:block',\n\t\t\t\t\t\t\trailClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"h-full overflow-y-auto overscroll-contain p-space-lg\">\n\t\t\t\t\t\t\t{rail}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</aside>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n});\n\nWorkspaceLayout.displayName = 'WorkspaceLayout';\n\nexport const WorkspaceRecordHeader = React.forwardRef<HTMLDivElement, WorkspaceRecordHeaderProps>(function WorkspaceRecordHeader({\n\ttitle,\n\tdescription,\n\tbadges,\n\tmetadata,\n\tactions,\n\tsecondaryActions,\n\tstatus,\n\tmedia,\n\theaderEnd,\n\ttitleSlot,\n\tclassName,\n\tstrings: stringsProp,\n\t...props\n}, ref) {\n\tconst strings = useStrings(defaultWorkspaceRecordHeaderStrings, stringsProp);\n\tconst hasMetadata = !!metadata?.length;\n\n\treturn (\n\t\t<Stack\n\t\t\tref={ref}\n\t\t\tdirection={{ base: 'vertical', lg: 'horizontal' }}\n\t\t\tgap=\"xl\"\n\t\t\talign={{ lg: 'start' }}\n\t\t\tjustify={{ lg: 'between' }}\n\t\t\twrap={{ base: false, lg: false }}\n\t\t\tclassName={cn(\n\t\t\t\t'workspace-record-header--component px-4 py-4 lg:px-5',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t\t<Stack direction=\"horizontal\" gap=\"lg\" align=\"start\" wrap={false} className=\"workspace-record-header--identity flex-1\">\n\t\t\t\t{!!media && (\n\t\t\t\t\t<div className=\"workspace-record-header--media flex size-12 shrink-0 items-center justify-center overflow-hidden rounded-radius-md border border-border bg-muted/40\">\n\t\t\t\t\t\t{media}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t\t<Stack gap=\"md\" className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t<Stack direction=\"horizontal\" gap=\"md\" className=\"workspace-record-header--title-row\">\n\t\t\t\t\t\t{titleSlot ?? (\n\t\t\t\t\t\t\t<Heading tag=\"h4\" className=\"leading-tight\">\n\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t</Heading>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{!!badges && <Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" className=\"workspace-record-header--badges\">{badges}</Stack>}\n\t\t\t\t\t\t\t{!!status && <div className=\"workspace-record-header--status\">{status}</div>}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t{!!description && (\n\t\t\t\t\t\t<Text type=\"secondary\" className=\"workspace-record-header--description max-w-4xl leading-relaxed\">\n\t\t\t\t\t\t\t{description}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!hasMetadata && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\taria-label={strings.metadataLabel}\n\t\t\t\t\t\t\tclassName=\"workspace-record-header--metadata flex flex-wrap items-center gap-x-space-xl gap-y-space-xs\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{metadata.map((item, index) => (\n\t\t\t\t\t\t\t\t<div key={item.id ?? index} className=\"flex items-baseline gap-space-sm\">\n\t\t\t\t\t\t\t\t\t<DisplayLabel>\n\t\t\t\t\t\t\t\t\t\t{item.label}\n\t\t\t\t\t\t\t\t\t</DisplayLabel>\n\t\t\t\t\t\t\t\t\t<Value weight=\"medium\" className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t\t\t{item.value}\n\t\t\t\t\t\t\t\t\t</Value>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t{!!(actions || secondaryActions || headerEnd) && (\n\t\t\t\t<div className=\"workspace-record-header--actions flex shrink-0 flex-wrap items-center gap-space-md min-[64rem]:justify-end\">\n\t\t\t\t\t{!!secondaryActions && (\n\t\t\t\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" aria-label={strings.secondaryActionsLabel}>\n\t\t\t\t\t\t\t{secondaryActions}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!actions && (\n\t\t\t\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" aria-label={strings.actionsLabel}>\n\t\t\t\t\t\t\t{actions}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!headerEnd && <div className=\"workspace-record-header--end\">{headerEnd}</div>}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</Stack>\n\t);\n});\n\nWorkspaceRecordHeader.displayName = 'WorkspaceRecordHeader';\n\nexport const WorkspaceNav = React.forwardRef<HTMLElement, WorkspaceNavProps>(function WorkspaceNav({\n\tgroups,\n\tactiveId,\n\tonSelect,\n\trenderItem,\n\tfooterSlot,\n\trenderLink,\n\tclassName,\n\tstrings: stringsProp,\n\t...props\n}, ref) {\n\tconst strings = useStrings(defaultWorkspaceNavStrings, stringsProp);\n\tconst resolvedRenderLink = useLayoutLinkRenderer({ renderLink });\n\n\treturn (\n\t\t<Stack\n\t\t\trender={(\n\t\t\t\t<nav\n\t\t\t\t\tref={ref}\n\t\t\t\t\taria-label={props['aria-label'] ?? strings.ariaLabel}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\tgap=\"xl\"\n\t\t\tclassName={cn('workspace-nav--component h-full', className)}\n\t\t>\n\t\t\t<Stack gap=\"xl\" className=\"workspace-nav--groups min-h-0 flex-1\">\n\t\t\t\t{groups.map((group) => (\n\t\t\t\t\t<Stack key={group.id} gap=\"md\" className=\"workspace-nav--group\">\n\t\t\t\t\t\t{!!group.label && (\n\t\t\t\t\t\t\t<div className=\"workspace-nav--group-header px-space-xs\">\n\t\t\t\t\t\t\t\t<DisplayLabel>\n\t\t\t\t\t\t\t\t\t{group.label}\n\t\t\t\t\t\t\t\t</DisplayLabel>\n\t\t\t\t\t\t\t\t{!!group.description && (\n\t\t\t\t\t\t\t\t\t<Text size=\"xs\" type=\"secondary\" className=\"mt-0.5 leading-snug\">\n\t\t\t\t\t\t\t\t\t\t{group.description}\n\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<ItemGroup className=\"workspace-nav--items gap-space-xs\">\n\t\t\t\t\t\t\t{group.items.map((item, index) => {\n\t\t\t\t\t\t\t\tconst active = item.id === activeId;\n\t\t\t\t\t\t\t\tconst status = getStatus(item, active);\n\t\t\t\t\t\t\t\tconst StatusIcon = STATUS_ICON[status];\n\t\t\t\t\t\t\t\tconst completion = item.completion === undefined ? undefined : clampPercent(item.completion);\n\t\t\t\t\t\t\t\tconst handleSelect = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\t\t\t\t\t\t\tif (item.disabled) {\n\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonSelect?.(item);\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tconst context = { active, group, index, onSelect: handleSelect };\n\n\t\t\t\t\t\t\t\tif (renderItem) {\n\t\t\t\t\t\t\t\t\treturn <React.Fragment key={item.id}>{renderItem(item, context)}</React.Fragment>;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst rowContent = (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<ItemMedia variant=\"icon\" className={cn(active && 'bg-primary/10 text-primary-accent')}>\n\t\t\t\t\t\t\t\t\t\t\t{item.icon ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<DynamicWorkspaceIcon icon={item.icon} className=\"size-icon\" />\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<StatusIcon className={cn('size-icon-md', STATUS_CLASS[status])} aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ItemMedia>\n\t\t\t\t\t\t\t\t\t\t<ItemContent>\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-space-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ItemTitle>{item.label}</ItemTitle>\n\t\t\t\t\t\t\t\t\t\t\t\t{active && (\n\t\t\t\t\t\t\t\t\t\t\t<Text tag=\"span\" size=\"inherit\" className=\"sr-only\">{strings.currentLabel}</Text>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t{!!item.description && <ItemDescription clamp={2}>{item.description}</ItemDescription>}\n\t\t\t\t\t\t\t\t\t\t\t{completion !== undefined && (\n\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mt-1.5 flex items-center gap-space-md\">\n\t\t\t\t\t\t\t\t\t\t\t<Progress\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={completion}\n\t\t\t\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-label={strings.completionLabel(completion)}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"flex-1\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<SecondaryValue size=\"xs\" className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{strings.completionLabel(completion)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</SecondaryValue>\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ItemContent>\n\t\t\t\t\t\t\t\t\t\t{!!item.badge && <ItemActions>{item.badge}</ItemActions>}\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tconst itemClassName = cn(\n\t\t\t\t\t\t\t\t\t'workspace-nav--item w-full border border-transparent px-2 py-2 text-left transition-colors',\n\t\t\t\t\t\t\t\t\tactive && 'border-primary/20 bg-primary/5',\n\t\t\t\t\t\t\t\t\titem.warning && !active && 'border-warning/30 bg-warning/5',\n\t\t\t\t\t\t\t\t\titem.disabled && 'pointer-events-none opacity-50',\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tif (item.href) {\n\t\t\t\t\t\t\t\t\tconst linkNode = resolvedRenderLink({\n\t\t\t\t\t\t\t\t\t\thref: item.href,\n\t\t\t\t\t\t\t\t\t\tchildren: rowContent,\n\t\t\t\t\t\t\t\t\t\tclassName: 'block',\n\t\t\t\t\t\t\t\t\t\tactive,\n\t\t\t\t\t\t\t\t\t\tdisabled: item.disabled,\n\t\t\t\t\t\t\t\t\t\texternal: item.external,\n\t\t\t\t\t\t\t\t\t\ttarget: item.target,\n\t\t\t\t\t\t\t\t\t\trel: item.rel,\n\t\t\t\t\t\t\t\t\t\tonClick: handleSelect as React.MouseEventHandler<HTMLAnchorElement>,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<Item key={item.id} size=\"md\" render={linkNode as React.ReactElement} className={itemClassName}>\n\t\t\t\t\t\t\t\t\t\t\t{rowContent}\n\t\t\t\t\t\t\t\t\t\t</Item>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<Item\n\t\t\t\t\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\t\t\t\t\tsize=\"md\"\n\t\t\t\t\t\t\t\t\t\trender={<button type=\"button\" onClick={handleSelect} disabled={item.disabled} />}\n\t\t\t\t\t\t\t\t\t\tclassName={itemClassName}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{rowContent}\n\t\t\t\t\t\t\t\t\t</Item>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</ItemGroup>\n\t\t\t\t\t</Stack>\n\t\t\t\t))}\n\t\t\t</Stack>\n\t\t\t{!!footerSlot && <div className=\"workspace-nav--footer shrink-0 border-t border-border pt-space-lg\">{footerSlot}</div>}\n\t\t</Stack>\n\t);\n});\n\nWorkspaceNav.displayName = 'WorkspaceNav';\n\nexport const WorkspaceLocaleStrip = React.forwardRef<HTMLDivElement, WorkspaceLocaleStripProps>(function WorkspaceLocaleStrip({\n\tlocales,\n\tactiveLocale,\n\tonLocaleChange,\n\tactions,\n\tstatus,\n\tclassName,\n\tstrings: stringsProp,\n\t...props\n}, ref) {\n\tconst strings = useStrings(defaultWorkspaceLocaleStripStrings, stringsProp);\n\n\tconst handleLocaleClick = (locale: WorkspaceLocaleItem) => {\n\t\tif (locale.disabled) return;\n\t\tonLocaleChange?.(locale);\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={cn('workspace-locale-strip--component flex flex-col gap-space-lg border-t border-border bg-muted/20 px-4 py-3 min-[64rem]:flex-row min-[64rem]:items-center min-[64rem]:justify-between min-[64rem]:px-5', className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"md\" className=\"workspace-locale-strip--locales min-w-0\" role=\"group\" aria-label={strings.ariaLabel}>\n\t\t\t\t{locales.map((locale) => {\n\t\t\t\t\tconst active = locale.id === activeLocale;\n\t\t\t\t\tconst completion = locale.completion === undefined ? undefined : clampPercent(locale.completion);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tkey={locale.id}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\ttone={active ? 'primary' : 'secondary'}\n\t\t\t\t\t\t\tbuttonStyle={active ? 'solid' : 'ghost'}\n\t\t\t\t\t\t\tonClick={() => handleLocaleClick(locale)}\n\t\t\t\t\t\t\tdisabled={locale.disabled}\n\t\t\t\t\t\t\taria-pressed={active}\n\t\t\t\t\t\t\tclassName={cn('workspace-locale-strip--item h-auto min-h-action-sm justify-start px-control-sm py-1.5')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Stack direction=\"horizontal\" align=\"center\" gap=\"md\" render={<span />} className=\"min-w-0\">\n\t\t\t\t\t\t\t<Text tag=\"span\" size=\"inherit\" className=\"truncate text-inherit\">{locale.label}</Text>\n\t\t\t\t\t\t\t{active && <Text tag=\"span\" size=\"inherit\" className=\"sr-only\">{strings.activeLabel}</Text>}\n\t\t\t\t\t\t\t\t{completion !== undefined && (\n\t\t\t\t\t\t\t\t\t/* On an active pill the button surface is solid, so the tonal\n\t\t\t\t\t\t\t\t\t badge variants land coloured-on-coloured. Derive the nested\n\t\t\t\t\t\t\t\t\t badge from the primary foreground pair so it remains legible\n\t\t\t\t\t\t\t\t\t when dark themes intentionally lighten `--primary`. */\n\t\t\t\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\t\t\t\ttone={completion >= 100 ? 'success' : 'secondary'}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t'shrink-0',\n\t\t\t\t\t\t\t\t\t\t\tactive && 'border-primary-foreground/20 bg-primary-foreground/10 text-primary-foreground',\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{strings.completionLabel(completion)}\n\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{!!locale.status && <span className=\"shrink-0\">{locale.status}</span>}\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</Stack>\n\t\t\t{!!(status || actions) && (\n\t\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"md\" className=\"workspace-locale-strip--actions shrink-0\">\n\t\t\t\t\t{!!status && <div className=\"workspace-locale-strip--status\">{status}</div>}\n\t\t\t\t\t{!!actions && <Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" className=\"\">{actions}</Stack>}\n\t\t\t\t</Stack>\n\t\t\t)}\n\t\t</div>\n\t);\n});\n\nWorkspaceLocaleStrip.displayName = 'WorkspaceLocaleStrip';\n"],"mappings":"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"}
1
+ {"version":3,"file":"workspace-C1PZmk8L.js","names":["Icon","React","_Fragment","Text","DisplayLabel","Stack","Progress","Value","SecondaryValue","Badge","ItemMedia","ItemDescription","ItemActions","ItemGroup","ItemContent","Item","ItemTitle","useLayoutLinkRenderer","React$1","Fragment$1","defaultWorkspaceRecordHeaderStrings","defaultWorkspaceNavStrings","value","defaultWorkspaceLocaleStripStrings","CONTENT_WIDTH_CLASS","STATUS_ICON","Check","Circle","CircleAlert","STATUS_CLASS","clampPercent","DynamicWorkspaceIcon","icon","getStatus","item","active","WorkspaceLayout","props","hasSidebar","sidebar","hasRail","rail","ariaLabel","cn","contentWidth","className","header","headerClassName","bodyClassName","sidebarClassName","mainClassName","contentClassName","railClassName","WorkspaceRecordHeader","stringsProp","strings","useStrings","hasMetadata","metadata","media","titleSlot","Heading","title","badges","status","description","index","actions","secondaryActions","headerEnd","WorkspaceNav","resolvedRenderLink","groups","group","activeId","StatusIcon","completion","handleSelect","context","renderItem","rowContent","itemClassName","linkNode","footerSlot","WorkspaceLocaleStrip","handleLocaleClick","locale","onLocaleChange","locales","activeLocale","Button"],"sources":["../src/components/layout/workspace/workspace.strings.ts","../src/components/layout/workspace/workspace.tsx"],"sourcesContent":["export interface WorkspaceRecordHeaderStrings {\n\tmetadataLabel: string;\n\tactionsLabel: string;\n\tsecondaryActionsLabel: string;\n}\n\nexport const defaultWorkspaceRecordHeaderStrings: WorkspaceRecordHeaderStrings = {\n\tmetadataLabel: 'Record metadata',\n\tactionsLabel: 'Record actions',\n\tsecondaryActionsLabel: 'Secondary actions',\n};\n\nexport interface WorkspaceNavStrings {\n\tariaLabel: string;\n\tcompletionLabel: (value: number) => string;\n\tcurrentLabel: string;\n}\n\nexport const defaultWorkspaceNavStrings: WorkspaceNavStrings = {\n\tariaLabel: 'Workspace navigation',\n\tcompletionLabel: (value) => `${value}% complete`,\n\tcurrentLabel: 'Current',\n};\n\nexport interface WorkspaceLocaleStripStrings {\n\tariaLabel: string;\n\tactiveLabel: string;\n\tcompletionLabel: (value: number) => string;\n}\n\nexport const defaultWorkspaceLocaleStripStrings: WorkspaceLocaleStripStrings = {\n\tariaLabel: 'Workspace locales',\n\tactiveLabel: 'Active',\n\tcompletionLabel: (value) => `${value}% complete`,\n};\n","import * as React from 'react';\nimport {\n\tCheck,\n\tCircle,\n\tCircleAlert,\n\ttype LucideIcon,\n\t} from 'lucide-react';\n\nimport { Badge } from '../../base/badge';\nimport { Button } from '../../base/buttons';\nimport { Progress } from '../../base/feedback';\nimport {\n\tItem,\n\tItemActions,\n\tItemContent,\n\tItemDescription,\n\tItemGroup,\n\tItemMedia,\n\tItemTitle,\n} from '../../base/item';\nimport { Stack } from '../../base/structure';\nimport { SecondaryValue, Value } from '../../primitives';\nimport { DisplayLabel, Heading, Text } from '../../typography';\nimport { useStrings } from '../../../lib/strings';\nimport { cn } from '../../../lib/utils';\n\nimport { useLayoutLinkRenderer } from '../hooks';\nimport type { LayoutIconComponent } from '../layout.types';\nimport {\n\tdefaultWorkspaceLocaleStripStrings,\n\tdefaultWorkspaceNavStrings,\n\tdefaultWorkspaceRecordHeaderStrings,\n} from './workspace.strings';\nimport type {\n\tWorkspaceContentWidth,\n\tWorkspaceLayoutProps,\n\tWorkspaceLocaleItem,\n\tWorkspaceLocaleStripProps,\n\tWorkspaceNavItem,\n\tWorkspaceNavItemStatus,\n\tWorkspaceNavProps,\n\tWorkspaceRecordHeaderProps,\n} from './workspace.types';\n\nconst CONTENT_WIDTH_CLASS: Record<WorkspaceContentWidth, string> = {\n\tdefault: '[--workspace-content-max-width:58rem]',\n\twide: '[--workspace-content-max-width:86rem]',\n\tfull: '[--workspace-content-max-width:none]',\n};\n\nconst STATUS_ICON: Record<WorkspaceNavItemStatus, LucideIcon> = {\n\tcomplete: Check,\n\tcurrent: Circle,\n\tattention: CircleAlert,\n\tdisabled: Circle,\n\tidle: Circle,\n};\n\nconst STATUS_CLASS: Record<WorkspaceNavItemStatus, string> = {\n\tcomplete: 'text-success',\n\tcurrent: 'text-primary-accent',\n\tattention: 'text-warning',\n\tdisabled: 'text-muted-foreground/40',\n\tidle: 'text-muted-foreground',\n};\n\nfunction clampPercent(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.min(100, Math.max(0, Math.round(value)));\n}\n\nfunction DynamicWorkspaceIcon({\n\ticon,\n\tclassName,\n}: {\n\t/** Leading glyph. */\n\ticon?: LayoutIconComponent;\n\tclassName?: string;\n}) {\n\tif (!icon) return null;\n\tconst Icon = icon;\n\treturn <Icon className={className} aria-hidden=\"true\" />;\n}\n\nfunction getStatus(item: WorkspaceNavItem, active: boolean): WorkspaceNavItemStatus {\n\tif (item.disabled) return 'disabled';\n\tif (item.status) return item.status;\n\tif (item.warning) return 'attention';\n\tif (active) return 'current';\n\tif (item.completion !== undefined && clampPercent(item.completion) >= 100) return 'complete';\n\treturn 'idle';\n}\n\nexport const WorkspaceLayout = React.forwardRef<HTMLDivElement, WorkspaceLayoutProps>(function WorkspaceLayout({\n\theader,\n\tsidebar,\n\trail,\n\tchildren,\n\tcontentWidth = 'wide',\n\tclassName,\n\theaderClassName,\n\tbodyClassName,\n\tsidebarClassName,\n\tmainClassName,\n\tcontentClassName,\n\trailClassName,\n\tariaLabel,\n\tstyle,\n\t...props\n}, ref) {\n\tconst hasSidebar = !!sidebar;\n\tconst hasRail = !!rail;\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\taria-label={ariaLabel}\n\t\t\tclassName={cn(\n\t\t\t\t'workspace-layout--component flex h-full min-h-0 w-full flex-col overflow-hidden rounded-radius-md border border-border bg-background text-foreground',\n\t\t\t\t'[--workspace-sidebar-width:16rem] [--workspace-rail-width:20rem]',\n\t\t\t\tCONTENT_WIDTH_CLASS[contentWidth],\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tstyle={style}\n\t\t\t{...props}\n\t\t>\n\t\t\t{!!header && (\n\t\t\t\t<header className={cn('workspace-layout--header shrink-0 border-b border-border bg-background', headerClassName)}>\n\t\t\t\t\t{header}\n\t\t\t\t</header>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'workspace-layout--body grid min-h-0 flex-1 grid-cols-1 bg-muted/20',\n\t\t\t\t\thasSidebar && !hasRail && 'min-[80rem]:grid-cols-[var(--workspace-sidebar-width)_minmax(0,1fr)]',\n\t\t\t\t\thasSidebar && hasRail && 'min-[80rem]:grid-cols-[var(--workspace-sidebar-width)_minmax(0,1fr)] min-[96rem]:grid-cols-[var(--workspace-sidebar-width)_minmax(0,1fr)_var(--workspace-rail-width)]',\n\t\t\t\t\t!hasSidebar && hasRail && 'min-[96rem]:grid-cols-[minmax(0,1fr)_var(--workspace-rail-width)]',\n\t\t\t\t\tbodyClassName,\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{!!hasSidebar && (\n\t\t\t\t\t<aside\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'workspace-layout--sidebar hidden min-h-0 border-r border-border bg-background min-[80rem]:block',\n\t\t\t\t\t\t\tsidebarClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"h-full overflow-y-auto overscroll-contain p-space-lg\">\n\t\t\t\t\t\t\t{sidebar}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</aside>\n\t\t\t\t)}\n\t\t\t\t<main\n\t\t\t\t\ttabIndex={0}\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t'workspace-layout--main min-h-0 min-w-0 overflow-y-auto overscroll-contain focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/70 focus-visible:ring-inset',\n\t\t\t\t\t\tmainClassName,\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'workspace-layout--content mx-auto flex min-h-full w-full max-w-[var(--workspace-content-max-width)] flex-col gap-space-xl p-4 min-[64rem]:p-5',\n\t\t\t\t\t\t\tcontentWidth === 'full' && 'max-w-none',\n\t\t\t\t\t\t\tcontentClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</div>\n\t\t\t\t</main>\n\t\t\t\t{!!hasRail && (\n\t\t\t\t\t<aside\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'workspace-layout--rail hidden min-h-0 border-l border-border bg-background min-[96rem]:block',\n\t\t\t\t\t\t\trailClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"h-full overflow-y-auto overscroll-contain p-space-lg\">\n\t\t\t\t\t\t\t{rail}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</aside>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</div>\n\t);\n});\n\nWorkspaceLayout.displayName = 'WorkspaceLayout';\n\nexport const WorkspaceRecordHeader = React.forwardRef<HTMLDivElement, WorkspaceRecordHeaderProps>(function WorkspaceRecordHeader({\n\ttitle,\n\tdescription,\n\tbadges,\n\tmetadata,\n\tactions,\n\tsecondaryActions,\n\tstatus,\n\tmedia,\n\theaderEnd,\n\ttitleSlot,\n\tclassName,\n\tstrings: stringsProp,\n\t...props\n}, ref) {\n\tconst strings = useStrings(defaultWorkspaceRecordHeaderStrings, stringsProp);\n\tconst hasMetadata = !!metadata?.length;\n\n\treturn (\n\t\t<Stack\n\t\t\tref={ref}\n\t\t\tdirection={{ base: 'vertical', lg: 'horizontal' }}\n\t\t\tgap=\"xl\"\n\t\t\talign={{ lg: 'start' }}\n\t\t\tjustify={{ lg: 'between' }}\n\t\t\twrap={{ base: false, lg: false }}\n\t\t\tclassName={cn(\n\t\t\t\t'workspace-record-header--component px-4 py-4 lg:px-5',\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t\t<Stack direction=\"horizontal\" gap=\"lg\" align=\"start\" wrap={false} className=\"workspace-record-header--identity flex-1\">\n\t\t\t\t{!!media && (\n\t\t\t\t\t<div className=\"workspace-record-header--media flex size-12 shrink-0 items-center justify-center overflow-hidden rounded-radius-md border border-border bg-muted/40\">\n\t\t\t\t\t\t{media}\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t\t<Stack gap=\"md\" className=\"min-w-0 flex-1\">\n\t\t\t\t\t\t<Stack direction=\"horizontal\" gap=\"md\" className=\"workspace-record-header--title-row\">\n\t\t\t\t\t\t{titleSlot ?? (\n\t\t\t\t\t\t\t<Heading tag=\"h4\" className=\"leading-tight\">\n\t\t\t\t\t\t\t\t{title}\n\t\t\t\t\t\t\t</Heading>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{!!badges && <Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" className=\"workspace-record-header--badges\">{badges}</Stack>}\n\t\t\t\t\t\t\t{!!status && <div className=\"workspace-record-header--status\">{status}</div>}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t{!!description && (\n\t\t\t\t\t\t<Text type=\"secondary\" className=\"workspace-record-header--description max-w-4xl leading-relaxed\">\n\t\t\t\t\t\t\t{description}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!hasMetadata && (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\taria-label={strings.metadataLabel}\n\t\t\t\t\t\t\tclassName=\"workspace-record-header--metadata flex flex-wrap items-center gap-x-space-xl gap-y-space-xs\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{metadata.map((item, index) => (\n\t\t\t\t\t\t\t\t<div key={item.id ?? index} className=\"flex items-baseline gap-space-sm\">\n\t\t\t\t\t\t\t\t\t<DisplayLabel>\n\t\t\t\t\t\t\t\t\t\t{item.label}\n\t\t\t\t\t\t\t\t\t</DisplayLabel>\n\t\t\t\t\t\t\t\t\t<Value weight=\"medium\" className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t\t\t{item.value}\n\t\t\t\t\t\t\t\t\t</Value>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t{!!(actions || secondaryActions || headerEnd) && (\n\t\t\t\t<div className=\"workspace-record-header--actions flex shrink-0 flex-wrap items-center gap-space-md min-[64rem]:justify-end\">\n\t\t\t\t\t{!!secondaryActions && (\n\t\t\t\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" aria-label={strings.secondaryActionsLabel}>\n\t\t\t\t\t\t\t{secondaryActions}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!actions && (\n\t\t\t\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" aria-label={strings.actionsLabel}>\n\t\t\t\t\t\t\t{actions}\n\t\t\t\t\t\t</Stack>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!headerEnd && <div className=\"workspace-record-header--end\">{headerEnd}</div>}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</Stack>\n\t);\n});\n\nWorkspaceRecordHeader.displayName = 'WorkspaceRecordHeader';\n\nexport const WorkspaceNav = React.forwardRef<HTMLElement, WorkspaceNavProps>(function WorkspaceNav({\n\tgroups,\n\tactiveId,\n\tonSelect,\n\trenderItem,\n\tfooterSlot,\n\trenderLink,\n\tclassName,\n\tstrings: stringsProp,\n\t...props\n}, ref) {\n\tconst strings = useStrings(defaultWorkspaceNavStrings, stringsProp);\n\tconst resolvedRenderLink = useLayoutLinkRenderer({ renderLink });\n\n\treturn (\n\t\t<Stack\n\t\t\trender={(\n\t\t\t\t<nav\n\t\t\t\t\tref={ref}\n\t\t\t\t\taria-label={props['aria-label'] ?? strings.ariaLabel}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\tgap=\"xl\"\n\t\t\tclassName={cn('workspace-nav--component h-full', className)}\n\t\t>\n\t\t\t<Stack gap=\"xl\" className=\"workspace-nav--groups min-h-0 flex-1\">\n\t\t\t\t{groups.map((group) => (\n\t\t\t\t\t<Stack key={group.id} gap=\"md\" className=\"workspace-nav--group\">\n\t\t\t\t\t\t{!!group.label && (\n\t\t\t\t\t\t\t<div className=\"workspace-nav--group-header px-space-xs\">\n\t\t\t\t\t\t\t\t<DisplayLabel>\n\t\t\t\t\t\t\t\t\t{group.label}\n\t\t\t\t\t\t\t\t</DisplayLabel>\n\t\t\t\t\t\t\t\t{!!group.description && (\n\t\t\t\t\t\t\t\t\t<Text size=\"xs\" type=\"secondary\" className=\"mt-0.5 leading-snug\">\n\t\t\t\t\t\t\t\t\t\t{group.description}\n\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<ItemGroup className=\"workspace-nav--items gap-space-xs\">\n\t\t\t\t\t\t\t{group.items.map((item, index) => {\n\t\t\t\t\t\t\t\tconst active = item.id === activeId;\n\t\t\t\t\t\t\t\tconst status = getStatus(item, active);\n\t\t\t\t\t\t\t\tconst StatusIcon = STATUS_ICON[status];\n\t\t\t\t\t\t\t\tconst completion = item.completion === undefined ? undefined : clampPercent(item.completion);\n\t\t\t\t\t\t\t\tconst handleSelect = (event: React.MouseEvent<HTMLElement>) => {\n\t\t\t\t\t\t\t\t\tif (item.disabled) {\n\t\t\t\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tonSelect?.(item);\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tconst context = { active, group, index, onSelect: handleSelect };\n\n\t\t\t\t\t\t\t\tif (renderItem) {\n\t\t\t\t\t\t\t\t\treturn <React.Fragment key={item.id}>{renderItem(item, context)}</React.Fragment>;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tconst rowContent = (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<ItemMedia variant=\"icon\" className={cn(active && 'bg-primary/10 text-primary-accent')}>\n\t\t\t\t\t\t\t\t\t\t\t{item.icon ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<DynamicWorkspaceIcon icon={item.icon} className=\"size-icon\" />\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<StatusIcon className={cn('size-icon-md', STATUS_CLASS[status])} aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ItemMedia>\n\t\t\t\t\t\t\t\t\t\t<ItemContent>\n\t\t\t\t\t\t\t\t\t\t\t<div className=\"flex items-center gap-space-sm\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ItemTitle>{item.label}</ItemTitle>\n\t\t\t\t\t\t\t\t\t\t\t\t{active && (\n\t\t\t\t\t\t\t\t\t\t\t<Text tag=\"span\" size=\"inherit\" className=\"sr-only\">{strings.currentLabel}</Text>\n\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t{!!item.description && <ItemDescription clamp={2}>{item.description}</ItemDescription>}\n\t\t\t\t\t\t\t\t\t\t\t{completion !== undefined && (\n\t\t\t\t\t\t\t\t\t\t\t\t<div className=\"mt-1.5 flex items-center gap-space-md\">\n\t\t\t\t\t\t\t\t\t\t\t<Progress\n\t\t\t\t\t\t\t\t\t\t\t\tvalue={completion}\n\t\t\t\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\t\t\t\taria-label={strings.completionLabel(completion)}\n\t\t\t\t\t\t\t\t\t\t\t\tclassName=\"flex-1\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<SecondaryValue size=\"xs\" className=\"tabular-nums\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t{strings.completionLabel(completion)}\n\t\t\t\t\t\t\t\t\t\t\t\t\t</SecondaryValue>\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</ItemContent>\n\t\t\t\t\t\t\t\t\t\t{!!item.badge && <ItemActions>{item.badge}</ItemActions>}\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tconst itemClassName = cn(\n\t\t\t\t\t\t\t\t\t'workspace-nav--item w-full border border-transparent px-2 py-2 text-left transition-colors',\n\t\t\t\t\t\t\t\t\tactive && 'border-primary/20 bg-primary/5',\n\t\t\t\t\t\t\t\t\titem.warning && !active && 'border-warning/30 bg-warning/5',\n\t\t\t\t\t\t\t\t\titem.disabled && 'pointer-events-none opacity-50',\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\tif (item.href) {\n\t\t\t\t\t\t\t\t\tconst linkNode = resolvedRenderLink({\n\t\t\t\t\t\t\t\t\t\thref: item.href,\n\t\t\t\t\t\t\t\t\t\tchildren: rowContent,\n\t\t\t\t\t\t\t\t\t\tclassName: 'block',\n\t\t\t\t\t\t\t\t\t\tactive,\n\t\t\t\t\t\t\t\t\t\tdisabled: item.disabled,\n\t\t\t\t\t\t\t\t\t\texternal: item.external,\n\t\t\t\t\t\t\t\t\t\ttarget: item.target,\n\t\t\t\t\t\t\t\t\t\trel: item.rel,\n\t\t\t\t\t\t\t\t\t\tonClick: handleSelect as React.MouseEventHandler<HTMLAnchorElement>,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t\t<Item key={item.id} size=\"md\" render={linkNode as React.ReactElement} className={itemClassName}>\n\t\t\t\t\t\t\t\t\t\t\t{rowContent}\n\t\t\t\t\t\t\t\t\t\t</Item>\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\t<Item\n\t\t\t\t\t\t\t\t\t\tkey={item.id}\n\t\t\t\t\t\t\t\t\t\tsize=\"md\"\n\t\t\t\t\t\t\t\t\t\trender={<button type=\"button\" onClick={handleSelect} disabled={item.disabled} />}\n\t\t\t\t\t\t\t\t\t\tclassName={itemClassName}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{rowContent}\n\t\t\t\t\t\t\t\t\t</Item>\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</ItemGroup>\n\t\t\t\t\t</Stack>\n\t\t\t\t))}\n\t\t\t</Stack>\n\t\t\t{!!footerSlot && <div className=\"workspace-nav--footer shrink-0 border-t border-border pt-space-lg\">{footerSlot}</div>}\n\t\t</Stack>\n\t);\n});\n\nWorkspaceNav.displayName = 'WorkspaceNav';\n\nexport const WorkspaceLocaleStrip = React.forwardRef<HTMLDivElement, WorkspaceLocaleStripProps>(function WorkspaceLocaleStrip({\n\tlocales,\n\tactiveLocale,\n\tonLocaleChange,\n\tactions,\n\tstatus,\n\tclassName,\n\tstrings: stringsProp,\n\t...props\n}, ref) {\n\tconst strings = useStrings(defaultWorkspaceLocaleStripStrings, stringsProp);\n\n\tconst handleLocaleClick = (locale: WorkspaceLocaleItem) => {\n\t\tif (locale.disabled) return;\n\t\tonLocaleChange?.(locale);\n\t};\n\n\treturn (\n\t\t<div\n\t\t\tref={ref}\n\t\t\tclassName={cn('workspace-locale-strip--component flex flex-col gap-space-lg border-t border-border bg-muted/20 px-4 py-3 min-[64rem]:flex-row min-[64rem]:items-center min-[64rem]:justify-between min-[64rem]:px-5', className)}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"md\" className=\"workspace-locale-strip--locales min-w-0\" role=\"group\" aria-label={strings.ariaLabel}>\n\t\t\t\t{locales.map((locale) => {\n\t\t\t\t\tconst active = locale.id === activeLocale;\n\t\t\t\t\tconst completion = locale.completion === undefined ? undefined : clampPercent(locale.completion);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tkey={locale.id}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\ttone={active ? 'primary' : 'secondary'}\n\t\t\t\t\t\t\tbuttonStyle={active ? 'solid' : 'ghost'}\n\t\t\t\t\t\t\tonClick={() => handleLocaleClick(locale)}\n\t\t\t\t\t\t\tdisabled={locale.disabled}\n\t\t\t\t\t\t\taria-pressed={active}\n\t\t\t\t\t\t\tclassName={cn('workspace-locale-strip--item h-auto min-h-action-sm justify-start px-control-sm py-1.5')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Stack direction=\"horizontal\" align=\"center\" gap=\"md\" render={<span />} className=\"min-w-0\">\n\t\t\t\t\t\t\t<Text tag=\"span\" size=\"inherit\" className=\"truncate text-inherit\">{locale.label}</Text>\n\t\t\t\t\t\t\t{active && <Text tag=\"span\" size=\"inherit\" className=\"sr-only\">{strings.activeLabel}</Text>}\n\t\t\t\t\t\t\t\t{completion !== undefined && (\n\t\t\t\t\t\t\t\t\t/* On an active pill the button surface is solid, so the tonal\n\t\t\t\t\t\t\t\t\t badge variants land coloured-on-coloured. Derive the nested\n\t\t\t\t\t\t\t\t\t badge from the primary foreground pair so it remains legible\n\t\t\t\t\t\t\t\t\t when dark themes intentionally lighten `--primary`. */\n\t\t\t\t\t\t\t\t\t<Badge\n\t\t\t\t\t\t\t\t\t\ttone={completion >= 100 ? 'success' : 'secondary'}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\t'shrink-0',\n\t\t\t\t\t\t\t\t\t\t\tactive && 'border-primary-foreground/20 bg-primary-foreground/10 text-primary-foreground',\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{strings.completionLabel(completion)}\n\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t{!!locale.status && <span className=\"shrink-0\">{locale.status}</span>}\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</Stack>\n\t\t\t{!!(status || actions) && (\n\t\t\t\t<Stack direction=\"horizontal\" wrap align=\"center\" gap=\"md\" className=\"workspace-locale-strip--actions shrink-0\">\n\t\t\t\t\t{!!status && <div className=\"workspace-locale-strip--status\">{status}</div>}\n\t\t\t\t\t{!!actions && <Stack direction=\"horizontal\" wrap align=\"center\" gap=\"sm\" className=\"\">{actions}</Stack>}\n\t\t\t\t</Stack>\n\t\t\t)}\n\t\t</div>\n\t);\n});\n\nWorkspaceLocaleStrip.displayName = 'WorkspaceLocaleStrip';\n"],"mappings":"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"}
@@ -5,28 +5,131 @@ description: Use when building, integrating, theming or migrating a React consum
5
5
 
6
6
  # Themelia React UI consumer
7
7
 
8
- Start with [installed setup](references/installation.md): resolve the package from the app, check installed or copied guidance identity, and read version-matched declarations. Use [discovery](references/discovery.md) to find exact imports, symbols and responsibilities. The [public index](references/public-api.json) derives from actual exports and catalogue owners.
8
+ Build application-specific screens from supported public owners. This skill
9
+ routes the shipped references, indexes, recipes and read-only helpers; it is
10
+ not an API replacement or a requirement to imitate one example layout.
9
11
 
10
- Choose the smallest owner: typography for display roles, primitives for formatted values, base for controls/surfaces, layout for page regions, blocks for reusable presentation, features for interaction lifecycles. Routing, data, permissions, translation, storage and backend effects belong to the app.
12
+ ## Resolve the installed contract
11
13
 
12
- Read only the relevant reference:
14
+ Start with [installed setup](references/installation.md). Resolve the package
15
+ from the app, check installed/copied guidance identity, and read matching
16
+ declarations. Refresh the complete skill after upgrades, including prose.
17
+ Read current sibling pages and app adapters; keep local product policy separate.
13
18
 
14
- - [Discovery](references/discovery.md): portable Node finder, selection metadata, optional peers and version-matched declarations.
15
- - [Installed setup](references/installation.md): package resolution, copied-skill freshness and manual installation.
16
- - [Composition](references/composition.md): card anatomy, responsive structures, spacing and menu/display ownership.
17
- - [Design contract](references/design-contract.md): application freedom, library-owned geometry, independent variants and enforcement limits.
18
- - [Integration](references/integration.md): installation, CSS, state, routing, overlays and verification.
19
- - [Theme extension](references/theming.md): compact tokens, scoped portals, radius and drift prevention.
20
- - [Generated tokens](references/tokens.json): current structural roots/defaults, advanced settings and utility vocabulary.
21
- - [Workflows](references/workflows.md): collection/navigation, detail, validated edit and destructive confirmation; callback ownership, optional peers and verification.
22
- - [Typed example](examples/composition.tsx): public-import composition verified against the packed package.
19
+ Use [discovery](references/discovery.md) and the [public index](references/public-api.json)
20
+ for exact imports, symbols, responsibilities, alternatives and optional peers.
21
+ Search the task or exact symbol; shorten an empty query instead of guessing APIs.
22
+ For conventional node_modules layouts, run from the app:
23
23
 
24
- Prefer public props/slots and structures. Typography owns no margins; every gap/inset has one owner. rounded-radius is the default everywhere; rounded-inner is only for intentional nested bodies/items. Do not locally restyle control typography, height, corners or menu padding to hide a shared mismatch.
24
+ ```sh
25
+ node node_modules/themelia-react-ui/docs/consumer-skill/scripts/find-components.mjs record directory --limit 5
26
+ ```
25
27
 
26
- Use Card for headed content, including flat/no-padding composition inside an existing boundary. Choose PopoverMenu for routine searchable selection; type/inset belong to PopoverContent when custom anatomy is needed. Keep row density, control size, surface inset and title/description textGap independent; inspect the exact declaration before assigning a variant.
28
+ Inspect the chosen declaration and its re-exports before assigning props.
29
+ Prefer the focused published family; inspect optional peers for its whole-family
30
+ types as well as runtime use. Catalogue URLs and private source are not imports.
27
31
 
28
- Import themelia-react-ui/style.css once. Compiled component CSS requires no source scanning. Apps using semantic Tailwind classes also process theme.css with their own Tailwind v4 build. CSS owns appearance, UIProvider stable defaults, callbacks app state.
32
+ ## Compose from the task
29
33
 
30
- Async integrations must show real pending/failure/success and update data; a toast alone is not persistence. Use library overlays for modal workflows. Verify consuming-app types/tests/build and opened popovers, menus and tooltips in narrow/light/dark states.
34
+ Before JSX, identify fixed context, editable criteria, the user's next decision,
35
+ leading information, command scope and required states. Keep this proportional
36
+ to the task; ordinary edits do not need an approval ceremony or planning report.
31
37
 
32
- This skill ships with the package but is not installed automatically. No theme-publish/skill-install CLI exists. It grants no authorization to publish, deploy, message users or change other repositories.
38
+ Choose the most complete existing owner whose lifecycle fits. Typography owns
39
+ display roles; primitives own formatted values; base owns controls and surfaces;
40
+ layout owns page regions; blocks own reusable subjects; features own workflows.
41
+ Compose lower owners when a feature's coordination does not fit the product.
42
+
43
+ Use Page for route identity and commands, Card for an independently framed subject,
44
+ ResourceCell for table identity, Item for independent entries and MetadataList for
45
+ facts about one subject. Compare DataView, DataTable and base Table by their actual
46
+ query/selection/paging contracts. Keep fixed parent scope through query clearing.
47
+ Use native table query, utility, bulk-action and row-action seams where they fit.
48
+
49
+ Give commands explicit tone and page/collection/record scope. Card status/count
50
+ badges use titleSuffix; headerStart is context, and actions use action slots.
51
+ Prioritize identity and decision facts; preserve access to other facts through
52
+ detail/disclosure rather than appending every hidden column to compact rows.
53
+ Product-specific columns, form arrangements and richer rows remain app decisions.
54
+
55
+ ## Preserve structure, typography and appearance
56
+
57
+ Assign each gap/inset once: shell/container owns gutters, surface owns padding,
58
+ section owns rhythm, Stack/Grid owns sibling gaps, and typography owns no margins.
59
+ Use public props/slots before adding local appearance overrides. A nested framed
60
+ table or Card needs a distinct subject; use supported flat composition otherwise.
61
+
62
+ Use shared Heading/Text/DisplayLabel/Label/TextLink roles and value primitives such
63
+ as Money, Date and Email. Semantic element choice is separate from visual size.
64
+ Primary row text stays at the shared default; compact supporting metadata uses
65
+ the smaller secondary role. Density alone does not shrink primary content.
66
+ Native editable text keeps its responsive control recipe. For rich HTML display
67
+ use RichText; editing belongs to RichTextEditor. Preserve sanitization and scoped
68
+ content rhythm; structural UI labels do not inherit prose margins.
69
+
70
+ Keep copy textGap normal/dense, row density, control size and surface inset
71
+ independent. Use gap-normal/gap-dense through the headed owner or Stack/Grid;
72
+ avoid adding description margins. rounded-radius is the default, rounded-inner
73
+ is for intentional nested regions. Do not replace control geometry/typography
74
+ or anchored-region padding through classes, contentClassName or inline styles.
75
+ PopoverMenu owns routine searchable selection; custom popups use public regions.
76
+
77
+ ## Integrate themes, layouts and workflows
78
+
79
+ Import themelia-react-ui/style.css once; shipped components need no source scanning.
80
+ Apps authoring semantic utilities process theme.css in their Tailwind v4 build.
81
+ Keep broad resets in the lower-priority base layer. Retheme existing semantic
82
+ surface/foreground pairs and structural roots; derived utilities are not new knobs.
83
+ CSS owns appearance, UIProvider stable defaults, callbacks per-mount app state.
84
+ Use ThemeScope for scoped portals, and native dir plus DirectionProvider for RTL.
85
+
86
+ Reuse public shells/sidebars/headers. Constrain app-shell height and preserve one
87
+ scroll owner, useful gutters, DOM/focus order and action wrapping. Check usable
88
+ parent width as well as viewport width; embedded layouts may need container
89
+ adaptation. Placement, alignment and overflow remain valid app-owned mechanics.
90
+
91
+ Keep controlled values authoritative and accept callback proposals in the parent.
92
+ Keep state mode fixed while mounted; choose explicit reset/remount behavior when
93
+ the subject changes. Stabilize lifecycle-sensitive loader/schema/column inputs
94
+ when their meaning is unchanged. The app owns routing, permissions, translation,
95
+ transport, cancellation and persistence; use href/callback/render integration.
96
+
97
+ Show relevant loading, empty, missing, error/retry, disabled, validation and success
98
+ states. Preserve rejected drafts and ignore superseded results. A toast alone is
99
+ not persistence; UI cancellation does not prove a server operation stopped.
100
+ Use library overlays for modal workflows and their pending/dismissal contracts.
101
+ Keep labels, field associations, icon-action names and translated strings meaningful.
102
+ In server-component apps, mount interactive families from a client wrapper;
103
+ use a family's published pure helpers where provided, without assuming SSR support.
104
+
105
+ ## Read the relevant detail and recipe
106
+
107
+ | Task | Reference and example |
108
+ | --- | --- |
109
+ | Owner selection, Card, menu anatomy | [Composition](references/composition.md), [basic composition](examples/composition.tsx) |
110
+ | Display roles, formatted values and rich HTML | [Typography and rich content](references/composition.md#typography-and-rich-content) |
111
+ | Geometry ownership and independent variants | [Design contract](references/design-contract.md) |
112
+ | CSS, providers, RTL, routers, async/editor integration | [Integration](references/integration.md) |
113
+ | Theme roots, density, radius and portal inheritance | [Theming](references/theming.md), [generated tokens](references/tokens.json) |
114
+ | Collection, fixed context, detail, edit and delete | [Workflows](references/workflows.md), [directory](examples/scoped-directory.tsx), [detail](examples/detail.tsx), [edit](examples/edit.tsx), [confirmation](examples/destructive-confirm.tsx) |
115
+ | Application shells, navigation and parent adaptation | [Layout composition](references/composition.md#application-layouts), [workspace](examples/app-layout.tsx) |
116
+ | TaskCard, UsageCard, InlineEdit and persistence | [Workflow contracts](references/workflows.md#task-summaries-usage-and-inline-editing), [summary](examples/planning-usage-edit.tsx) |
117
+ | Email/templates, receipts, hierarchy/capture, files/messages | [Domain composition](references/composition.md#receipts), [all recipe exports and peers](examples/manifest.json) |
118
+ | Whole-screen review and optional source checker | [Review and checks](references/review.md) |
119
+
120
+ The manifest lists every runnable recipe, including ordinary/template emails,
121
+ receipt, hierarchy/guided forms, message/files and the index table. Copy only the
122
+ relevant recipe, adapt product labels/callbacks, and read its actual declarations.
123
+
124
+ ## Verify the integrated result
125
+
126
+ Run the app's types/lint/tests/build. The optional check-composition.mjs script
127
+ uses app TypeScript and checks direct imports/static anatomy; errors, warnings
128
+ and unresolved expressions are distinct. It is not a full visual/accessibility audit.
129
+ Separately inspect long copy, missing values, narrow/desktop and light/dark/RTL
130
+ states. Open menus/overlays, execute callbacks and failure/retry, check keyboard
131
+ selection/dismissal/focus return and reduced motion, and report unverified limits.
132
+
133
+ This skill ships with the package and requires separate manual installation.
134
+ No theme-publish/skill-install CLI exists. It grants no authorization to publish,
135
+ deploy, message users or change other repositories.
@@ -1,8 +1,7 @@
1
1
  import { Button } from 'themelia-react-ui/base/buttons';
2
2
  import { Card } from 'themelia-react-ui/base/cards';
3
- import { Grid, Stack } from 'themelia-react-ui/base/structure';
3
+ import { MetadataList } from 'themelia-react-ui/blocks/data-display';
4
4
  import { Date, Email, Money, Value } from 'themelia-react-ui/primitives';
5
- import { Text } from 'themelia-react-ui/typography';
6
5
 
7
6
  export interface AccountDetailRecord {
8
7
  id: string; name: string; email: string | null;
@@ -18,11 +17,11 @@ export function AccountDetail({ account, onEdit, onBack }: AccountDetailProps) {
18
17
  return <Card title={account.name} surface="card" headerPlacement="frame"
19
18
  headerAction={<Button onClick={() => onEdit(account.id)}>Edit account</Button>}
20
19
  footerSlot={<Button tone="secondary" buttonStyle="outline" onClick={onBack}>Back to accounts</Button>}>
21
- <Grid columns={{ base: 1, md: 2 }} gap="lg">
22
- <Stack gap="xs"><Text type="secondary">Account ID</Text><Value>{account.id}</Value></Stack>
23
- <Stack gap="xs"><Text type="secondary">Email</Text><Email value={account.email} /></Stack>
24
- <Stack gap="xs"><Text type="secondary">Created</Text><Date value={account.createdAt} /></Stack>
25
- <Stack gap="xs"><Text type="secondary">Balance</Text><Money amount={account.balanceMinor} currency={account.currency} unit="minor" /></Stack>
26
- </Grid>
20
+ <MetadataList columns={{ base: 1, md: 2 }} items={[
21
+ { id: 'id', label: 'Account ID', value: <Value>{account.id}</Value> },
22
+ { id: 'email', label: 'Email', value: <Email value={account.email} /> },
23
+ { id: 'created', label: 'Created', value: <Date value={account.createdAt} /> },
24
+ { id: 'balance', label: 'Balance', value: <Money amount={account.balanceMinor} currency={account.currency} unit="minor" /> },
25
+ ]} />
27
26
  </Card>;
28
27
  }
@@ -19,6 +19,12 @@
19
19
  "@tanstack/react-table"
20
20
  ]
21
21
  },
22
+ {
23
+ "file": "scoped-directory.tsx",
24
+ "exports": ["ScopedDirectory"],
25
+ "phase": "optional",
26
+ "optionalPeers": ["@tanstack/react-table", "react-day-picker"]
27
+ },
22
28
  {
23
29
  "file": "detail.tsx",
24
30
  "exports": [
@@ -89,6 +95,14 @@
89
95
  ],
90
96
  "phase": "basic",
91
97
  "optionalPeers": []
98
+ },
99
+ {
100
+ "file": "planning-usage-edit.tsx",
101
+ "exports": [
102
+ "WorkspaceSummary"
103
+ ],
104
+ "phase": "basic",
105
+ "optionalPeers": []
92
106
  }
93
107
  ]
94
108
  }
@@ -0,0 +1,29 @@
1
+ import { useState } from 'react';
2
+ import { InlineEdit } from 'themelia-react-ui/base/inline-edit';
3
+ import { Card } from 'themelia-react-ui/base/cards';
4
+ import { AdaptiveGrid, Stack } from 'themelia-react-ui/base/structure';
5
+ import { TaskCard, type TaskCardItem } from 'themelia-react-ui/blocks/planning';
6
+ import { UsageCard, type UsageCardData } from 'themelia-react-ui/blocks/analytics/usage-card';
7
+
8
+ /** The application supplies persistence, authoritative tasks and usage. */
9
+ export function WorkspaceSummary({
10
+ initialName, tasks, usage, saveName, completeTask,
11
+ }: {
12
+ initialName: string;
13
+ tasks: readonly TaskCardItem[];
14
+ usage: UsageCardData;
15
+ saveName: (name: string, signal: AbortSignal) => Promise<void>;
16
+ completeTask: (id: string, completed: boolean) => void;
17
+ }) {
18
+ const [name, setName] = useState(initialName);
19
+ return <Stack gap="xl">
20
+ <Card title="Workspace">
21
+ <InlineEdit label="Project name" value={name} onValueChange={setName} required
22
+ onSave={(draft, {signal}) => saveName(draft, signal)} />
23
+ </Card>
24
+ <AdaptiveGrid minColumnWidth="md" gap="xl">
25
+ <TaskCard title="Release checklist" items={tasks} defaultExpanded onItemCompletedChange={completeTask} />
26
+ <UsageCard title="Workspace usage" data={usage} />
27
+ </AdaptiveGrid>
28
+ </Stack>;
29
+ }
@@ -0,0 +1,77 @@
1
+ import { useMemo, type ReactNode } from 'react';
2
+ import { Button } from 'themelia-react-ui/base/buttons';
3
+ import { Stack } from 'themelia-react-ui/base/structure';
4
+ import { FilterLayout, FilterProvider, FilterType, type ActiveFilter, type FilterConfig } from 'themelia-react-ui/features/filters';
5
+ import { DataTable, ResourceCell, type DataTableProps } from 'themelia-react-ui/features/table';
6
+ import { Page } from 'themelia-react-ui/layout/page';
7
+ import { Email } from 'themelia-react-ui/primitives';
8
+ import { Text } from 'themelia-react-ui/typography';
9
+
10
+ export interface DirectoryContact { id: string; name: string; role: string; email: string | null; }
11
+ export type DirectoryState =
12
+ | { status: 'loading' }
13
+ | { status: 'error'; message: string }
14
+ | { status: 'ready'; records: DirectoryContact[] };
15
+ export interface ScopedDirectoryProps {
16
+ scope: { id: string; label: string };
17
+ state: DirectoryState;
18
+ filters: ActiveFilter[];
19
+ onQueryChange: (query: { scopeId: string; filters: ActiveFilter[] }) => void;
20
+ onRetry: () => void;
21
+ onBack: () => void;
22
+ onCreate?: () => void;
23
+ onOpen: (id: string) => void;
24
+ exportAction?: ReactNode;
25
+ /** App chooses from available parent width; compact identity retains contact reach. */
26
+ compact?: boolean;
27
+ // Authoritative server pagination; the app preserves scope/query in its URLs.
28
+ pagination?: DataTableProps<DirectoryContact, unknown>['pagination'];
29
+ onPageChange?: DataTableProps<DirectoryContact, unknown>['onPageChange'];
30
+ }
31
+ const criteria: FilterConfig[] = [{
32
+ key: 'q', label: 'Search contacts', placeholder: 'Name, email or role',
33
+ type: FilterType.SEARCH, icon: null, operator: 'contains', delay: 0,
34
+ displayConfig: { display: 'always' },
35
+ }];
36
+ const columns: DataTableProps<DirectoryContact, unknown>['columns'] = [
37
+ { id: 'identity', header: 'Contact', cell: ({ row }) => <ResourceCell title={row.original.name}
38
+ subtitle={<Text size="xs" type="secondary">{row.original.role}</Text>} /> },
39
+ { accessorKey: 'email', header: 'Email', cell: ({ row }) => <Email value={row.original.email} /> },
40
+ ];
41
+ const compactColumns: DataTableProps<DirectoryContact, unknown>['columns'] = [
42
+ { id: 'identity', header: 'Contact', cell: ({ row }) => <ResourceCell title={row.original.name}
43
+ subtitle={<Text size="xs" type="secondary">{row.original.role}</Text>}
44
+ metadata={<Email value={row.original.email} />} /> },
45
+ ];
46
+
47
+ // Parent scope is navigation context, never a removable filter. The app loads
48
+ // matching records. Its detail view keeps other operational facts available.
49
+ export function ScopedDirectory(props: ScopedDirectoryProps) {
50
+ const rowActions = useMemo<DataTableProps<DirectoryContact, unknown>['rowActions']>(() => [
51
+ { id: 'open', label: 'Open contact', onClick: contact => props.onOpen(contact.id) },
52
+ ], [props.onOpen]);
53
+ return <Page header={{ title: 'Contacts', headingTag: 'h1',
54
+ description: 'People responsible for bookings, billing and operations.',
55
+ onBack: props.onBack, backLabel: 'All businesses',
56
+ slots: { beforeTitle: <Text type="secondary">Business: {props.scope.label}</Text> },
57
+ actions: props.onCreate ? <Button tone="primary" onClick={props.onCreate}>New contact</Button> : undefined,
58
+ }}>
59
+ <FilterProvider filters={criteria} activeFilters={props.filters}
60
+ navigating={props.state.status === 'loading'}
61
+ onFilterChange={filters => props.onQueryChange({ scopeId: props.scope.id,
62
+ // A cleared search can emit ['']; it is not an applied criterion here.
63
+ filters: filters.filter(filter => filter.key !== 'q' || filter.value.some(value => value.trim() !== '')),
64
+ })}>
65
+ <DataTable columns={props.compact ? compactColumns : columns} data={props.state.status === 'ready' ? props.state.records : []}
66
+ getRowId={contact => contact.id} enableSorting={false} enableColumnVisibility={false}
67
+ showFullscreenToggle={false} manualPagination pagination={props.state.status === 'ready' ? props.pagination : undefined} onPageChange={props.onPageChange}
68
+ topbarContent={<FilterLayout variant="compact" showClearFilters />} topbarEnd={props.exportAction}
69
+ emptyStateMessage={props.state.status === 'loading' ? 'Loading contacts…' :
70
+ props.state.status === 'error' ? 'Contacts could not be loaded.' :
71
+ props.filters.length ? 'No contacts match these criteria.' : 'No contacts in this business yet.'}
72
+ emptyStateAction={props.state.status === 'error' ? <Stack gap="dense"><Text role="alert" type="error">{props.state.message}</Text>
73
+ <Button tone="secondary" buttonStyle="outline" onClick={props.onRetry}>Retry contacts</Button></Stack> : undefined}
74
+ rowActions={rowActions} />
75
+ </FilterProvider>
76
+ </Page>;
77
+ }
@@ -16,12 +16,100 @@ keep placement, width, wrapping and overflow with the surrounding composition.
16
16
  | Reusable subject presentation | Blocks |
17
17
  | Editing/selection/async lifecycle | Features with app callbacks |
18
18
 
19
+ ## Compose from the task
20
+
21
+ Identify the user's next decision before selecting components. Establish fixed
22
+ context (account, parent entity, workspace), editable query criteria, leading
23
+ information, page/collection/record commands, and loading/empty/error/edit states.
24
+ Then assign owners. A task may require a comparison table, a compact directory,
25
+ a detail workspace or a form; they need different information hierarchies.
26
+
27
+ | Decision | Use when | Alternative / boundary |
28
+ | --- | --- | --- |
29
+ | DataView | Its coordinated query, view and collection lifecycle fits | DataTable with app-owned query transport and native toolbar slots when coordination differs; base Table for presentation without TanStack behavior |
30
+ | ResourceCell | Identity inside a table cell | Item for independent list entries; MetadataList for label/value facts about one subject |
31
+ | Page / application shell | Route identity, navigation, content bounds and page commands | Card for an independent subject within that route; do not repeat the same heading merely to frame a table |
32
+ | Card | One subject needs a frame and headed regions | `surface="flat" padding="none"` inside an existing boundary; nested DataTable uses its own `surface="flat"` |
33
+ | FormField / InlineEdit | A field needs label/hint/error, or isolated save/cancel | Complete feature/overlay for a workflow; app form owns whole-record submission |
34
+
35
+ For a DataTable composition, put queries in `topbarContent`, exports or collection
36
+ tools in `topbarEnd`, selection commands in `bulkActions`, and record commands
37
+ in `rowActions`. Other arrangements are valid when the product has a distinct
38
+ query region; choose one owner deliberately and keep queries close to their
39
+ results. DataView already owns coordinated filtering; do not add a second filter
40
+ store around it without inspecting its contract.
41
+
42
+ Fixed scope and mutable criteria are different states. A collection reached
43
+ inside one business can show that business as context/navigation; query controls
44
+ then narrow that scope. If business is an editable filter, clearing it may widen
45
+ the collection. The app owns this meaning and transport. Do not accidentally
46
+ present fixed scope as a removable criterion or repeat it in every region.
47
+
48
+ Use primary identity plus task-critical supporting facts in compact rows.
49
+ When columns disappear, preserve access to other facts through detail/disclosure
50
+ or supported comparison controls. Avoid automatically appending every hidden
51
+ column to identity metadata. There is no universal row-line limit: long names,
52
+ accessibility needs and the task can justify richer rows. Explain the priority.
53
+ Custom ResourceCell metadata is caller content; use shared supporting typography
54
+ and CellStack where its smaller secondary-value contract fits.
55
+
56
+ Commands need explicit importance as well as scope. PageActions does not infer
57
+ primary tone from a label such as “New contact”; choose `tone="primary"` when
58
+ that is the route's main command. Permissions and destructive intent remain
59
+ application decisions. A back link, export and destructive command should not
60
+ all inherit the same visual emphasis by accident.
61
+
62
+ | Drift | Better decision |
63
+ | --- | --- |
64
+ | Same parent named in header, context strip and fixed filter | One contextual lead; repeat only where it clarifies a separate task |
65
+ | Every hidden column becomes identity metadata | Prioritize visible facts and retain access to the rest |
66
+ | Repeated route title on an otherwise untitled table Card | Route header plus native collection surface |
67
+ | Child and parent both add the same gutter/inset | Assign visible space once at its owner |
68
+ | New local controls to imitate an existing workflow | Inspect the public feature/parts/callback seams first |
69
+
70
+ See the [scoped directory recipe](../examples/scoped-directory.tsx) and
71
+ [workflow explanation](workflows.md#scoped-directory). Review decisions using
72
+ [review and checks](review.md); valid alternatives should preserve task semantics
73
+ and public anatomy, not imitate one screenshot.
74
+
19
75
  Use the exact family declarations from public-api.json. Catalogue URLs and source folders are not import contracts.
20
76
 
77
+ ## Typography and rich content
78
+
79
+ Choose Heading, Text, DisplayLabel, Label and TextLink from the published
80
+ typography family by role. Set semantic tags independently of visual variants;
81
+ heading order describes the document, not a desired font size. Labels associate
82
+ controls with stable IDs. Money, Date, Email and other value primitives own
83
+ formatting, locale/unit handling and empty-value fallbacks; zero is real data.
84
+ The app owns accounting, timezone policy and the meaning of unavailable values.
85
+
86
+ Primary row values and labels use the shared default text size. Compact metadata,
87
+ form hints and row descriptions use smaller secondary copy; structural panel
88
+ descriptions use default-sized secondary text. Typography adds no outer margins.
89
+ Native editable text retains its responsive field recipe. Do not resize it to
90
+ imitate a display label or use density to make all text smaller.
91
+
92
+ RichText from `themelia-react-ui/typography/rich-text` displays sanitized HTML,
93
+ with a scoped reading rhythm inherited from typography and theme roots. Use
94
+ `tag="div"` for HTML containing paragraphs/headings/lists; its default `p` tag
95
+ is appropriate only for inline content. The allowlist strips arbitrary styling,
96
+ embedded media and unsafe links; it is not a Markdown parser or email-layout
97
+ renderer. Keep outer width/padding on the surrounding structure. RichTextEditor
98
+ owns editing; EmailComposer owns structured email/variable/delivery contracts.
99
+ Read the relevant declarations and [integration](integration.md) before choosing
100
+ the content owner. Embedded React UI can opt out of reading rhythm through
101
+ `not-typeset` or `data-not-typeset` on its subtree; those opt-outs do not bypass
102
+ HTML sanitization or establish a separate typography system.
103
+
21
104
  ## Card anatomy
22
105
 
23
106
  Card surface="card" is the ordinary bordered surface; surface="framed" retains its ring recipe; surface="flat" padding="none" composes within an existing boundary. headerPlacement="frame" places title/icon/actions above an inset body, retaining default corners and using rounded-inner on that body.
24
107
 
108
+ Card `gap` owns spacing between regions; `contentGap` owns direct body-child
109
+ spacing; `textGap` owns title/supporting-copy rhythm. Region spacing defaults to
110
+ `xl` (`md` for `padding="none"`). Use a semantic region gap for compact cards
111
+ instead of resetting padding or adding local margins.
112
+
25
113
  Use titleSuffix for status/count/version badges. Long titles/suffixes wrap through the shared owner; no literal spaces/local margins to manufacture gaps. headerAction/actions are trailing controls, headerStart pre-title context. footerSlot/footer definitions own card-level actions; footerDivider owns the rule and inset. Do not simulate a footer inside children. SmartCard and ContentBlock are deprecated migration names; use Card in new code.
26
114
 
27
115
  Reusable blocks/features stay card-free unless their explicit purpose is a card. Frame them at the composition boundary.
@@ -168,3 +256,18 @@ adaptTo="container" inside Container/PageViewport to adapt at 48rem of usable
168
256
  parent width while preserving main-before-aside DOM/focus order.
169
257
 
170
258
  See the installed [workspace recipe](../examples/app-layout.tsx).
259
+
260
+ ## Task and usage summaries, editable fields
261
+
262
+ | Intent | Public owner | Composition boundary |
263
+ | --- | --- | --- |
264
+ | Task summary and expandable checklist | `TaskCard` from `themelia-react-ui/blocks/planning` | Owns one Card and its header/body/footer; supply authoritative items and callbacks. |
265
+ | Quotas, category/daily analytics and period selection | `UsageCard` from `themelia-react-ui/blocks/analytics/usage-card` | Owns one Card; supply data/request state and optional app footer action. |
266
+ | Edit one saved field in place | `InlineEdit` from `themelia-react-ui/base/inline-edit` | Owns FormField and native control/action anatomy; place it inside the app's chosen surface. |
267
+
268
+ Use Card's `gap` for region rhythm and `textGap` for title/supporting-copy rhythm;
269
+ neither changes Card insets. These blocks use the canonical surface, typography,
270
+ formatted-value and structure owners. Drawn rings and mini charts retain private
271
+ geometry and semantic chart/status colors. Read the
272
+ [workflow contracts](workflows.md#task-summaries-usage-and-inline-editing) and
273
+ [typed workspace recipe](../examples/planning-usage-edit.tsx) for integration.
@@ -133,9 +133,10 @@ overrides, semantic borders, and new raw spacing/control drift. The shipped
133
133
  typed examples go through the same design checks as library compositions.
134
134
 
135
135
  Those repository checks do not run automatically in a consuming application.
136
- Adopt equivalent component-import-aware lint rules in the application's CI, and
137
- run its types, build and interaction tests. The package does not strip arbitrary
138
- CSS at runtime or advertise a consumer audit/install CLI.
136
+ The opt-in source checker in [review and checks](review.md) covers a smaller,
137
+ documented set of direct-import/static-anatomy rules. Run the app's lint, types,
138
+ build and interaction tests for broader coverage. The package does not strip
139
+ arbitrary CSS at runtime or install audit/skill tooling globally.
139
140
 
140
141
  Static lint cannot prove alignment, readable wrapping, CSS authored elsewhere,
141
142
  unknown dynamic styles, focus restoration or callback behavior. Verify long