themelia-react-ui 2.0.2 → 2.0.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 (435) hide show
  1. package/CHANGELOG.md +67 -7
  2. package/README.md +70 -37
  3. package/THIRD_PARTY_NOTICES.md +6 -12
  4. package/dist/{accordion-Cjb6sx0G.js → accordion-96o0pN62.js} +5 -5
  5. package/dist/{accordion-Cjb6sx0G.js.map → accordion-96o0pN62.js.map} +1 -1
  6. package/dist/action-menu-CHgs8vmj.js +281 -0
  7. package/dist/action-menu-CHgs8vmj.js.map +1 -0
  8. package/dist/{affordance-geometry.generated-tF36bREk.js → affordance-geometry.generated-B8yGOr8-.js} +7 -1
  9. package/dist/affordance-geometry.generated-B8yGOr8-.js.map +1 -0
  10. package/dist/{ai-artifact-DvTwDVyL.js → ai-artifact-BZUGwBq6.js} +277 -276
  11. package/dist/ai-artifact-BZUGwBq6.js.map +1 -0
  12. package/dist/{app-shell-C4FhvCqF.js → app-shell-D63ATkIK.js} +84 -83
  13. package/dist/app-shell-D63ATkIK.js.map +1 -0
  14. package/dist/{attachment-BxDfL2mw.js → attachment-DkoqHPPl.js} +7 -7
  15. package/dist/{attachment-BxDfL2mw.js.map → attachment-DkoqHPPl.js.map} +1 -1
  16. package/dist/{auth-ax2BqjrI.js → auth-D2FVZ1MH.js} +10 -10
  17. package/dist/{auth-ax2BqjrI.js.map → auth-D2FVZ1MH.js.map} +1 -1
  18. package/dist/{avatar-DAPlDvhJ.js → avatar-DWO_HHhB.js} +5 -5
  19. package/dist/{avatar-DAPlDvhJ.js.map → avatar-DWO_HHhB.js.map} +1 -1
  20. package/dist/{badge-HpFqoqSY.js → badge-DErMA7ul.js} +4 -4
  21. package/dist/{badge-HpFqoqSY.js.map → badge-DErMA7ul.js.map} +1 -1
  22. package/dist/base/accordion.js +1 -1
  23. package/dist/base/action-menu.js +1 -1
  24. package/dist/base/attachment.js +1 -1
  25. package/dist/base/avatar.js +1 -1
  26. package/dist/base/badge.js +1 -1
  27. package/dist/base/batch-action-bar.js +1 -1
  28. package/dist/base/buttons.js +1 -1
  29. package/dist/base/cards.js +2 -2
  30. package/dist/base/carousel.js +3 -3
  31. package/dist/base/cascader.js +13 -13
  32. package/dist/base/chart.js +1 -1
  33. package/dist/base/choice-inputs.js +2 -2
  34. package/dist/base/code-block.js +1 -1
  35. package/dist/base/combobox.js +2 -2
  36. package/dist/base/command.js +1 -1
  37. package/dist/base/copyable.js +1 -1
  38. package/dist/base/date-pickers.js +2 -2
  39. package/dist/base/display.js +6 -6
  40. package/dist/base/feedback.js +3 -3
  41. package/dist/base/forms-numeric.js +1 -1
  42. package/dist/base/forms.js +3 -3
  43. package/dist/base/inline-edit.js +10 -10
  44. package/dist/base/item.js +1 -1
  45. package/dist/base/media-gallery.js +1 -1
  46. package/dist/base/metadata-list.js +1 -1
  47. package/dist/base/navigation.js +6 -6
  48. package/dist/base/popover-menu.js +1 -1
  49. package/dist/base/popover.js +1 -1
  50. package/dist/base/qr-code.js +1 -1
  51. package/dist/base/repeaters.js +9 -9
  52. package/dist/base/sheet.js +1 -1
  53. package/dist/base/sidebar.js +1 -1
  54. package/dist/base/signature-pad.js +6 -6
  55. package/dist/base/skeleton.js +1 -1
  56. package/dist/base/spinner.js +4 -4
  57. package/dist/base/structure.js +1 -1
  58. package/dist/base/table.js +1 -1
  59. package/dist/base/text-inputs.js +2 -2
  60. package/dist/base/toaster.js +3 -3
  61. package/dist/base/tree.js +1 -1
  62. package/dist/base/upload-queue.js +1 -1
  63. package/dist/base/upload.js +3 -3
  64. package/dist/base/value-inputs.js +1 -1
  65. package/dist/{batch-action-bar-DnUJ21NQ.js → batch-action-bar-CdfIkCsV.js} +4 -4
  66. package/dist/{batch-action-bar-DnUJ21NQ.js.map → batch-action-bar-CdfIkCsV.js.map} +1 -1
  67. package/dist/blocks/admin.js +20 -20
  68. package/dist/blocks/admin.js.map +1 -1
  69. package/dist/blocks/ai.js +15 -15
  70. package/dist/blocks/analytics/usage-card.js +1 -1
  71. package/dist/blocks/analytics.js +17 -17
  72. package/dist/blocks/analytics.js.map +1 -1
  73. package/dist/blocks/collaboration.js +1 -1
  74. package/dist/blocks/commerce/receipt.js +1 -1
  75. package/dist/blocks/commerce.js +570 -567
  76. package/dist/blocks/commerce.js.map +1 -1
  77. package/dist/blocks/data-display.js +2 -2
  78. package/dist/blocks/onboarding.js +5 -5
  79. package/dist/blocks/planning.js +11 -11
  80. package/dist/blocks/timelines.js +1 -1
  81. package/dist/{breadcrumbs-C-oqs1sQ.js → breadcrumbs-B-WFKecD.js} +4 -4
  82. package/dist/{breadcrumbs-C-oqs1sQ.js.map → breadcrumbs-B-WFKecD.js.map} +1 -1
  83. package/dist/{button-DVzspB_G.js → button-DkmK-z8E.js} +2 -2
  84. package/dist/{button-DVzspB_G.js.map → button-DkmK-z8E.js.map} +1 -1
  85. package/dist/{buttons-DPZekJFu.js → buttons-BbfzgczK.js} +8 -8
  86. package/dist/{buttons-DPZekJFu.js.map → buttons-BbfzgczK.js.map} +1 -1
  87. package/dist/{cards-BaBZR-AU.js → cards-4JTWqvVe.js} +10 -10
  88. package/dist/cards-4JTWqvVe.js.map +1 -0
  89. package/dist/{chart-ZOYyK2xG.js → chart-C19flDQb.js} +4 -4
  90. package/dist/{chart-ZOYyK2xG.js.map → chart-C19flDQb.js.map} +1 -1
  91. package/dist/{checkbox-AWIhNhmo.js → checkbox-CzYUTPeJ.js} +9 -5
  92. package/dist/checkbox-CzYUTPeJ.js.map +1 -0
  93. package/dist/{choice-inputs-CNHvARCJ.js → choice-inputs-JLtij2y4.js} +182 -176
  94. package/dist/choice-inputs-JLtij2y4.js.map +1 -0
  95. package/dist/{code-block-DeneBJR_.js → code-block-CGNaUtAE.js} +7 -7
  96. package/dist/{code-block-DeneBJR_.js.map → code-block-CGNaUtAE.js.map} +1 -1
  97. package/dist/{collapsible-C-_l4hpy.js → collapsible-Do4G0zcC.js} +3 -3
  98. package/dist/{collapsible-C-_l4hpy.js.map → collapsible-Do4G0zcC.js.map} +1 -1
  99. package/dist/{collection-content-By56pLog.js → collection-content-C0e8SsTm.js} +3 -3
  100. package/dist/{collection-content-By56pLog.js.map → collection-content-C0e8SsTm.js.map} +1 -1
  101. package/dist/{combobox-C0EQW6dr.js → combobox-CBJDs6w_.js} +349 -347
  102. package/dist/combobox-CBJDs6w_.js.map +1 -0
  103. package/dist/{combobox-xCQ2RMNE.js → combobox-hbhSS18O.js} +158 -112
  104. package/dist/combobox-hbhSS18O.js.map +1 -0
  105. package/dist/{command-C25VMRII.js → command-D8NrBj-b.js} +7 -7
  106. package/dist/{command-C25VMRII.js.map → command-D8NrBj-b.js.map} +1 -1
  107. package/dist/{comments-BYYlTA8E.js → comments-Di4w0H_S.js} +383 -382
  108. package/dist/comments-Di4w0H_S.js.map +1 -0
  109. package/dist/components/base/action-menu/action-menu.d.ts +2 -0
  110. package/dist/components/base/cards/card.recipes.d.ts +12 -5
  111. package/dist/components/base/cards/smart-card.types.d.ts +12 -7
  112. package/dist/components/base/choice-inputs/checkbox.d.ts +7 -2
  113. package/dist/components/base/choice-inputs/switch-card.d.ts +7 -0
  114. package/dist/components/base/choice-inputs/toggle-field.d.ts +7 -0
  115. package/dist/components/base/combobox/combobox-field.d.ts +16 -0
  116. package/dist/components/base/date-pickers/datepicker.types.d.ts +7 -0
  117. package/dist/components/base/forms/controlled-form-field.d.ts +6 -6
  118. package/dist/components/base/forms/form-field.d.ts +5 -3
  119. package/dist/components/base/forms/index.d.ts +1 -0
  120. package/dist/components/base/forms/server-errors.d.ts +16 -0
  121. package/dist/components/base/forms/workflow.d.ts +5 -2
  122. package/dist/components/base/metadata-list/metadata-list.d.ts +3 -1
  123. package/dist/components/base/navigation/page-header/page-header.d.ts +4 -2
  124. package/dist/components/base/structure/composition.recipes.d.ts +17 -0
  125. package/dist/components/base/text-inputs/hooks/use-form-field-state.d.ts +7 -2
  126. package/dist/components/base/text-inputs/input.d.ts +4 -2
  127. package/dist/components/base/text-inputs/textarea.d.ts +4 -2
  128. package/dist/components/base/value-inputs/date-time-input.d.ts +2 -1
  129. package/dist/components/base/value-inputs/slider.d.ts +5 -1
  130. package/dist/components/base/value-inputs/tags-input.d.ts +5 -1
  131. package/dist/components/typography/text.styles.d.ts +26 -1
  132. package/dist/components/ui/combobox-dismiss.d.ts +16 -0
  133. package/dist/components/ui/combobox.d.ts +11 -6
  134. package/dist/components/ui/dialog.d.ts +1 -1
  135. package/dist/components/ui/popover.d.ts +1 -1
  136. package/dist/components/ui/sheet.d.ts +1 -1
  137. package/dist/composition.recipes-COdiFhxB.js +19 -0
  138. package/dist/composition.recipes-COdiFhxB.js.map +1 -0
  139. package/dist/containers-CRmHf7GP.js +104 -0
  140. package/dist/containers-CRmHf7GP.js.map +1 -0
  141. package/dist/{copyable-ClBuk_UK.js → copyable-CnGCZdX4.js} +4 -4
  142. package/dist/{copyable-ClBuk_UK.js.map → copyable-CnGCZdX4.js.map} +1 -1
  143. package/dist/{data-display-DT_khPl_.js → data-display-D4oujtx0.js} +239 -238
  144. package/dist/data-display-D4oujtx0.js.map +1 -0
  145. package/dist/{date-DCrsDTZc.js → date-Q7jnXxpk.js} +5 -5
  146. package/dist/{date-DCrsDTZc.js.map → date-Q7jnXxpk.js.map} +1 -1
  147. package/dist/{date-picker-ay0Pha_a.js → date-picker-zOt1oNss.js} +102 -90
  148. package/dist/date-picker-zOt1oNss.js.map +1 -0
  149. package/dist/date-pickers-cj8IXbDC.js +179 -0
  150. package/dist/date-pickers-cj8IXbDC.js.map +1 -0
  151. package/dist/{display-hAc1HjpI.js → display-BB4BL_-K.js} +8 -8
  152. package/dist/{display-hAc1HjpI.js.map → display-BB4BL_-K.js.map} +1 -1
  153. package/dist/{dropdown-menu-Cl4X7L5S.js → dropdown-menu-CjY8Vt7W.js} +8 -8
  154. package/dist/{dropdown-menu-Cl4X7L5S.js.map → dropdown-menu-CjY8Vt7W.js.map} +1 -1
  155. package/dist/features/activities.js +11 -11
  156. package/dist/features/ai-chat.js +9 -9
  157. package/dist/features/appointment-calendar.js +222 -220
  158. package/dist/features/appointment-calendar.js.map +1 -1
  159. package/dist/features/async-preview.js +8 -8
  160. package/dist/features/combobox.js +1 -1
  161. package/dist/features/comments.js +1 -1
  162. package/dist/features/data-view.js +10 -10
  163. package/dist/features/email-composer.js +275 -274
  164. package/dist/features/email-composer.js.map +1 -1
  165. package/dist/features/event-calendar.js +199 -198
  166. package/dist/features/event-calendar.js.map +1 -1
  167. package/dist/features/filters.js +1 -1
  168. package/dist/features/global-search.js +12 -12
  169. package/dist/features/kanban.js +4 -4
  170. package/dist/features/map.js +7 -7
  171. package/dist/features/media-library.js +623 -622
  172. package/dist/features/media-library.js.map +1 -1
  173. package/dist/features/mentions.js +1 -1
  174. package/dist/features/overlays.js +1 -1
  175. package/dist/features/products.js +973 -969
  176. package/dist/features/products.js.map +1 -1
  177. package/dist/features/questionnaire.js +12 -12
  178. package/dist/features/resource-assignment.js +8 -8
  179. package/dist/features/resource.js +113 -112
  180. package/dist/features/resource.js.map +1 -1
  181. package/dist/features/rich-text-editor.js +2 -2
  182. package/dist/features/schema-form.js +254 -253
  183. package/dist/features/schema-form.js.map +1 -1
  184. package/dist/features/suggestions.js +3 -3
  185. package/dist/features/sync.js +3 -3
  186. package/dist/features/table.js +1 -1
  187. package/dist/features/theme-tweaker.js +19 -19
  188. package/dist/features/theme-tweaker.js.map +1 -1
  189. package/dist/{feedback-BYIhtitP.js → feedback-DZNL5Lg1.js} +9 -9
  190. package/dist/{feedback-BYIhtitP.js.map → feedback-DZNL5Lg1.js.map} +1 -1
  191. package/dist/{field-affordance-recipes-DZhnIL_Y.js → field-affordance-recipes-DjwGx8eM.js} +2 -2
  192. package/dist/{field-affordance-recipes-DZhnIL_Y.js.map → field-affordance-recipes-DjwGx8eM.js.map} +1 -1
  193. package/dist/{filters-BGfvjP4d.js → filters-BcT-uoFy.js} +19 -19
  194. package/dist/{filters-BGfvjP4d.js.map → filters-BcT-uoFy.js.map} +1 -1
  195. package/dist/{form-field-CwH9y77i.js → form-field-CsgRmdit.js} +14 -8
  196. package/dist/form-field-CsgRmdit.js.map +1 -0
  197. package/dist/{form-sizing-BdP_Mf5p.js → form-sizing-NXgjkmBG.js} +3 -3
  198. package/dist/{form-sizing-BdP_Mf5p.js.map → form-sizing-NXgjkmBG.js.map} +1 -1
  199. package/dist/{forms-B9G_xwzi.js → forms-BV5m5aQF.js} +83 -65
  200. package/dist/forms-BV5m5aQF.js.map +1 -0
  201. package/dist/{forms-numeric-B_jraJaQ.js → forms-numeric-Cd33AKbD.js} +288 -288
  202. package/dist/forms-numeric-Cd33AKbD.js.map +1 -0
  203. package/dist/{header-CGXuhcRm.js → header-BA697l4a.js} +14 -14
  204. package/dist/{header-CGXuhcRm.js.map → header-BA697l4a.js.map} +1 -1
  205. package/dist/hooks/useFormErrors.d.ts +1 -1
  206. package/dist/{hooks-Dkz0K2WT.js → hooks-BQ-L7Uu2.js} +2 -2
  207. package/dist/{hooks-Dkz0K2WT.js.map → hooks-BQ-L7Uu2.js.map} +1 -1
  208. package/dist/{icon-badge-DYKIwvOV.js → icon-badge-COWbCCWu.js} +3 -3
  209. package/dist/{icon-badge-DYKIwvOV.js.map → icon-badge-COWbCCWu.js.map} +1 -1
  210. package/dist/index.js +2 -2
  211. package/dist/input-Cdw4k0fb.js +289 -0
  212. package/dist/input-Cdw4k0fb.js.map +1 -0
  213. package/dist/{input-CZw8iU99.js → input-DOPL5_QE.js} +3 -3
  214. package/dist/{input-CZw8iU99.js.map → input-DOPL5_QE.js.map} +1 -1
  215. package/dist/item-BvZ2DR_x.js +277 -0
  216. package/dist/item-BvZ2DR_x.js.map +1 -0
  217. package/dist/layout/app-shell.js +1 -1
  218. package/dist/layout/auth.js +1 -1
  219. package/dist/layout/containers.js +1 -1
  220. package/dist/layout/header.js +1 -1
  221. package/dist/layout/hooks.js +1 -1
  222. package/dist/layout/navigation.js +1 -1
  223. package/dist/layout/page.js +1 -1
  224. package/dist/layout/settings.js +1 -1
  225. package/dist/layout/sidebar.js +2 -2
  226. package/dist/layout/workspace.js +1 -1
  227. package/dist/layout.js +10 -10
  228. package/dist/lib/affordance-geometry.generated.d.ts +6 -0
  229. package/dist/lib/ui-provider/types.d.ts +1 -1
  230. package/dist/lib/use-popup-focus-recovery.d.ts +8 -0
  231. package/dist/lib/utils.js +1 -1
  232. package/dist/{media-gallery-3zIVLMWH.js → media-gallery-CSl5W1Fy.js} +6 -6
  233. package/dist/{media-gallery-3zIVLMWH.js.map → media-gallery-CSl5W1Fy.js.map} +1 -1
  234. package/dist/{mentions-utuUvH1K.js → mentions-RKOQaaIB.js} +8 -8
  235. package/dist/{mentions-utuUvH1K.js.map → mentions-RKOQaaIB.js.map} +1 -1
  236. package/dist/{message-DZ_ruyUV.js → message-INU2xsxu.js} +4 -4
  237. package/dist/{message-DZ_ruyUV.js.map → message-INU2xsxu.js.map} +1 -1
  238. package/dist/metadata-list-qVV7AVxa.js +443 -0
  239. package/dist/metadata-list-qVV7AVxa.js.map +1 -0
  240. package/dist/{navigation-BzhHI3lo.js → navigation-BQNcg1jT.js} +8 -8
  241. package/dist/{navigation-BzhHI3lo.js.map → navigation-BQNcg1jT.js.map} +1 -1
  242. package/dist/{navigation-Bnotn4AQ.js → navigation-DLF3E1IC.js} +7 -7
  243. package/dist/{navigation-Bnotn4AQ.js.map → navigation-DLF3E1IC.js.map} +1 -1
  244. package/dist/{navigation-row-recipes-BFLCk_Aq.js → navigation-row-recipes-WZEs-hYo.js} +2 -2
  245. package/dist/{navigation-row-recipes-BFLCk_Aq.js.map → navigation-row-recipes-WZEs-hYo.js.map} +1 -1
  246. package/dist/{number-DbV1Dija.js → number-E_OiIfJz.js} +5 -5
  247. package/dist/{number-DbV1Dija.js.map → number-E_OiIfJz.js.map} +1 -1
  248. package/dist/{overflow-tab-bar-CWY7Nogn.js → overflow-tab-bar-CrbqMteP.js} +107 -105
  249. package/dist/overflow-tab-bar-CrbqMteP.js.map +1 -0
  250. package/dist/{overlays-DNWmZrJ4.js → overlays-BlKynmde.js} +322 -319
  251. package/dist/overlays-BlKynmde.js.map +1 -0
  252. package/dist/page-CIwNUtGr.js +227 -0
  253. package/dist/page-CIwNUtGr.js.map +1 -0
  254. package/dist/page-header-commands-DFMlNYzN.js +128 -0
  255. package/dist/page-header-commands-DFMlNYzN.js.map +1 -0
  256. package/dist/{pagination-BL25hu2s.js → pagination-Ch8X_47u.js} +5 -5
  257. package/dist/{pagination-BL25hu2s.js.map → pagination-Ch8X_47u.js.map} +1 -1
  258. package/dist/{popover-menu-B9WWygpa.js → popover-menu-BYaCdFhf.js} +6 -6
  259. package/dist/{popover-menu-B9WWygpa.js.map → popover-menu-BYaCdFhf.js.map} +1 -1
  260. package/dist/{popover-7_m66eYW.js → popover-uwzX2vo7.js} +65 -63
  261. package/dist/popover-uwzX2vo7.js.map +1 -0
  262. package/dist/{primitives-BFK08r9M.js → primitives-Du64iDbb.js} +6 -6
  263. package/dist/{primitives-BFK08r9M.js.map → primitives-Du64iDbb.js.map} +1 -1
  264. package/dist/primitives.js +4 -4
  265. package/dist/{progress-B1VnCT0K.js → progress-BvF2oCdV.js} +5 -5
  266. package/dist/{progress-B1VnCT0K.js.map → progress-BvF2oCdV.js.map} +1 -1
  267. package/dist/{receipt-BVSOH3Xo.js → receipt-D789Jwyy.js} +6 -6
  268. package/dist/{receipt-BVSOH3Xo.js.map → receipt-D789Jwyy.js.map} +1 -1
  269. package/dist/{rich-text-GOUyKQ-s.js → rich-text-CLJEf76s.js} +4 -4
  270. package/dist/{rich-text-GOUyKQ-s.js.map → rich-text-CLJEf76s.js.map} +1 -1
  271. package/dist/{rich-text-editor-cRLC-eBK.js → rich-text-editor-Cm1dpUpQ.js} +10 -10
  272. package/dist/{rich-text-editor-cRLC-eBK.js.map → rich-text-editor-Cm1dpUpQ.js.map} +1 -1
  273. package/dist/{rich-text-editor-toolbar-DfXg0-VC.js → rich-text-editor-toolbar-L__e4x47.js} +4 -4
  274. package/dist/{rich-text-editor-toolbar-DfXg0-VC.js.map → rich-text-editor-toolbar-L__e4x47.js.map} +1 -1
  275. package/dist/{scroll-area-DcI-M1UT.js → scroll-area-La5RXsEk.js} +2 -2
  276. package/dist/{scroll-area-DcI-M1UT.js.map → scroll-area-La5RXsEk.js.map} +1 -1
  277. package/dist/{separator-Bom7NsGO.js → separator-DAEV0w65.js} +2 -2
  278. package/dist/{separator-Bom7NsGO.js.map → separator-DAEV0w65.js.map} +1 -1
  279. package/dist/{separator-BDV-Y648.js → separator-GNfPG-90.js} +3 -3
  280. package/dist/{separator-BDV-Y648.js.map → separator-GNfPG-90.js.map} +1 -1
  281. package/dist/services/actions.js +1 -1
  282. package/dist/settings-BA2iboic.js +174 -0
  283. package/dist/settings-BA2iboic.js.map +1 -0
  284. package/dist/{sheet-CGpB3omz.js → sheet-DoAxTb2J.js} +75 -73
  285. package/dist/sheet-DoAxTb2J.js.map +1 -0
  286. package/dist/{sidebar-A0ElHINE.js → sidebar-ByqKR_W5.js} +13 -13
  287. package/dist/{sidebar-A0ElHINE.js.map → sidebar-ByqKR_W5.js.map} +1 -1
  288. package/dist/{sidebar-CPx_7YBa.js → sidebar-D2iSnGJ7.js} +11 -11
  289. package/dist/{sidebar-CPx_7YBa.js.map → sidebar-D2iSnGJ7.js.map} +1 -1
  290. package/dist/{skeleton-Byjnt7qr.js → skeleton-CUj8O5Bd.js} +3 -3
  291. package/dist/{skeleton-Byjnt7qr.js.map → skeleton-CUj8O5Bd.js.map} +1 -1
  292. package/dist/smart-card-CqkzQsK-.js +614 -0
  293. package/dist/smart-card-CqkzQsK-.js.map +1 -0
  294. package/dist/{structure-BmisBK-3.js → structure-C0V0_Fyf.js} +3 -3
  295. package/dist/{structure-BmisBK-3.js.map → structure-C0V0_Fyf.js.map} +1 -1
  296. package/dist/{structure.recipes-EPz60cU8.js → structure.recipes-BB4-n58V.js} +2 -2
  297. package/dist/{structure.recipes-EPz60cU8.js.map → structure.recipes-BB4-n58V.js.map} +1 -1
  298. package/dist/style.css +1 -1
  299. package/dist/{table-DsfzoUia.js → table-CpvnzJn9.js} +3 -3
  300. package/dist/{table-DsfzoUia.js.map → table-CpvnzJn9.js.map} +1 -1
  301. package/dist/{table-BweFy_P9.js → table-DH7rozUv.js} +19 -19
  302. package/dist/{table-BweFy_P9.js.map → table-DH7rozUv.js.map} +1 -1
  303. package/dist/{tabs-CDocW5D1.js → tabs-eqVsJZWO.js} +7 -7
  304. package/dist/{tabs-CDocW5D1.js.map → tabs-eqVsJZWO.js.map} +1 -1
  305. package/dist/{text-inputs-f9Ia-aCi.js → text-inputs-DXItiR0O.js} +101 -98
  306. package/dist/text-inputs-DXItiR0O.js.map +1 -0
  307. package/dist/{text.styles-g4He6UIW.js → text.styles-B64My8RZ.js} +25 -10
  308. package/dist/text.styles-B64My8RZ.js.map +1 -0
  309. package/dist/theme.css +152 -112
  310. package/dist/{timelines-CwM_9IhD.js → timelines-DmtztAY_.js} +10 -10
  311. package/dist/{timelines-CwM_9IhD.js.map → timelines-DmtztAY_.js.map} +1 -1
  312. package/dist/{tooltip-yiRJUFjp.js → tooltip-B4hjKtoV.js} +3 -3
  313. package/dist/{tooltip-yiRJUFjp.js.map → tooltip-B4hjKtoV.js.map} +1 -1
  314. package/dist/{tree-WnKQzwbq.js → tree-CV11PURP.js} +8 -8
  315. package/dist/{tree-WnKQzwbq.js.map → tree-CV11PURP.js.map} +1 -1
  316. package/dist/typography/rich-text.js +1 -1
  317. package/dist/typography-CSyJrh28.js +117 -0
  318. package/dist/typography-CSyJrh28.js.map +1 -0
  319. package/dist/typography.js +1 -1
  320. package/dist/{ui-provider-C_U0Xma4.js → ui-provider-CQCuCBcy.js} +3 -3
  321. package/dist/ui-provider-CQCuCBcy.js.map +1 -0
  322. package/dist/ui-provider.js +1 -1
  323. package/dist/{upload-CXyxmQBP.js → upload-C9SA0X-8.js} +11 -11
  324. package/dist/{upload-CXyxmQBP.js.map → upload-C9SA0X-8.js.map} +1 -1
  325. package/dist/{upload-queue-Boscubn9.js → upload-queue-DhQJiSRc.js} +9 -9
  326. package/dist/{upload-queue-Boscubn9.js.map → upload-queue-DhQJiSRc.js.map} +1 -1
  327. package/dist/{usage-card-BhO5eqkX.js → usage-card-DVTRDmGz.js} +134 -133
  328. package/dist/usage-card-DVTRDmGz.js.map +1 -0
  329. package/dist/use-popup-focus-recovery-C0QPvgOR.js +36 -0
  330. package/dist/use-popup-focus-recovery-C0QPvgOR.js.map +1 -0
  331. package/dist/{utils-BRhFDwuU.js → utils-CF3c95Io.js} +68 -5
  332. package/dist/utils-CF3c95Io.js.map +1 -0
  333. package/dist/value-inputs-C0o70p-U.js +980 -0
  334. package/dist/value-inputs-C0o70p-U.js.map +1 -0
  335. package/dist/{value-typography-BP8OG6h5.js → value-typography-ClupF0Gz.js} +2 -2
  336. package/dist/{value-typography-BP8OG6h5.js.map → value-typography-ClupF0Gz.js.map} +1 -1
  337. package/dist/workspace-9EFVXUyk.js +410 -0
  338. package/dist/workspace-9EFVXUyk.js.map +1 -0
  339. package/docs/consumer-skill/SKILL.md +14 -129
  340. package/docs/consumer-skill/examples/app-layout.tsx +22 -12
  341. package/docs/consumer-skill/examples/authentication.tsx +77 -0
  342. package/docs/consumer-skill/examples/edit.tsx +30 -38
  343. package/docs/consumer-skill/examples/manifest.json +51 -1
  344. package/docs/consumer-skill/examples/rhf-bindings.tsx +86 -0
  345. package/docs/consumer-skill/examples/rhf-edit-page.tsx +141 -0
  346. package/docs/consumer-skill/examples/rhf-overlay-form.tsx +92 -0
  347. package/docs/consumer-skill/examples/rhf-transport.tsx +28 -0
  348. package/docs/consumer-skill/references/agents-md.md +17 -7
  349. package/docs/consumer-skill/references/authentication.md +42 -0
  350. package/docs/consumer-skill/references/component-contracts.json +319824 -0
  351. package/docs/consumer-skill/references/composition-mapping.md +92 -0
  352. package/docs/consumer-skill/references/composition.md +43 -19
  353. package/docs/consumer-skill/references/design-contract.md +32 -0
  354. package/docs/consumer-skill/references/discovery.md +84 -7
  355. package/docs/consumer-skill/references/installation.md +45 -35
  356. package/docs/consumer-skill/references/integration.md +6 -2
  357. package/docs/consumer-skill/references/public-api.json +1520 -66
  358. package/docs/consumer-skill/references/review.md +9 -4
  359. package/docs/consumer-skill/references/rhf-workflows.md +86 -0
  360. package/docs/consumer-skill/references/screen-archetypes.md +22 -0
  361. package/docs/consumer-skill/references/theming.md +8 -9
  362. package/docs/consumer-skill/references/tokens.json +12 -3
  363. package/docs/consumer-skill/references/workflows.md +7 -5
  364. package/docs/consumer-skill/scripts/composition-schema.d.mts +2 -0
  365. package/docs/consumer-skill/scripts/composition-schema.mjs +32 -0
  366. package/docs/consumer-skill/scripts/composition.mjs +198 -0
  367. package/docs/consumer-skill/scripts/discovery.mjs +42 -10
  368. package/docs/consumer-skill/scripts/inspect-component.mjs +11 -0
  369. package/docs/consumer-skill/scripts/inspect-tokens.mjs +11 -0
  370. package/docs/consumer-skill/scripts/inspection.mjs +138 -0
  371. package/docs/consumer-skill/scripts/map-composition.mjs +12 -0
  372. package/docs/consumer-skill/scripts/setup-skills.mjs +76 -0
  373. package/docs/consumer-skills/themelia-components/SKILL.md +30 -0
  374. package/docs/consumer-skills/themelia-composition/SKILL.md +35 -0
  375. package/docs/consumer-skills/themelia-forms/SKILL.md +12 -0
  376. package/docs/consumer-skills/themelia-foundation/SKILL.md +14 -0
  377. package/docs/consumer-skills/themelia-tokenization/SKILL.md +35 -0
  378. package/package.json +6 -4
  379. package/templates/README.md +39 -0
  380. package/templates/admin-shell-template.tsx +382 -0
  381. package/templates/analytics-operations-template.tsx +376 -0
  382. package/templates/customers-template.tsx +509 -0
  383. package/templates/index.ts +29 -0
  384. package/templates/orders-template.tsx +1102 -0
  385. package/templates/products-template.tsx +834 -0
  386. package/templates/user-permissions-template.tsx +450 -0
  387. package/dist/action-menu-CllU52Mm.js +0 -280
  388. package/dist/action-menu-CllU52Mm.js.map +0 -1
  389. package/dist/affordance-geometry.generated-tF36bREk.js.map +0 -1
  390. package/dist/ai-artifact-DvTwDVyL.js.map +0 -1
  391. package/dist/app-shell-C4FhvCqF.js.map +0 -1
  392. package/dist/cards-BaBZR-AU.js.map +0 -1
  393. package/dist/checkbox-AWIhNhmo.js.map +0 -1
  394. package/dist/choice-inputs-CNHvARCJ.js.map +0 -1
  395. package/dist/combobox-C0EQW6dr.js.map +0 -1
  396. package/dist/combobox-xCQ2RMNE.js.map +0 -1
  397. package/dist/comments-BYYlTA8E.js.map +0 -1
  398. package/dist/containers-Mu1LMGV1.js +0 -103
  399. package/dist/containers-Mu1LMGV1.js.map +0 -1
  400. package/dist/data-display-DT_khPl_.js.map +0 -1
  401. package/dist/date-picker-ay0Pha_a.js.map +0 -1
  402. package/dist/date-pickers-Ccw8DL2b.js +0 -175
  403. package/dist/date-pickers-Ccw8DL2b.js.map +0 -1
  404. package/dist/form-field-CwH9y77i.js.map +0 -1
  405. package/dist/forms-B9G_xwzi.js.map +0 -1
  406. package/dist/forms-numeric-B_jraJaQ.js.map +0 -1
  407. package/dist/input-DQdEd0YD.js +0 -263
  408. package/dist/input-DQdEd0YD.js.map +0 -1
  409. package/dist/item-K5_ghvze.js +0 -275
  410. package/dist/item-K5_ghvze.js.map +0 -1
  411. package/dist/metadata-list-8N16ZMW_.js +0 -405
  412. package/dist/metadata-list-8N16ZMW_.js.map +0 -1
  413. package/dist/overflow-tab-bar-CWY7Nogn.js.map +0 -1
  414. package/dist/overlays-DNWmZrJ4.js.map +0 -1
  415. package/dist/page-Bgl1F560.js +0 -224
  416. package/dist/page-Bgl1F560.js.map +0 -1
  417. package/dist/page-header-commands-DOb6WsfD.js +0 -126
  418. package/dist/page-header-commands-DOb6WsfD.js.map +0 -1
  419. package/dist/popover-7_m66eYW.js.map +0 -1
  420. package/dist/settings-ybnjVwbd.js +0 -171
  421. package/dist/settings-ybnjVwbd.js.map +0 -1
  422. package/dist/sheet-CGpB3omz.js.map +0 -1
  423. package/dist/smart-card-DiC5aac3.js +0 -604
  424. package/dist/smart-card-DiC5aac3.js.map +0 -1
  425. package/dist/text-inputs-f9Ia-aCi.js.map +0 -1
  426. package/dist/text.styles-g4He6UIW.js.map +0 -1
  427. package/dist/typography-UTnveOEy.js +0 -117
  428. package/dist/typography-UTnveOEy.js.map +0 -1
  429. package/dist/ui-provider-C_U0Xma4.js.map +0 -1
  430. package/dist/usage-card-BhO5eqkX.js.map +0 -1
  431. package/dist/utils-BRhFDwuU.js.map +0 -1
  432. package/dist/value-inputs-DXPDjvBU.js +0 -963
  433. package/dist/value-inputs-DXPDjvBU.js.map +0 -1
  434. package/dist/workspace-Cdrg7k9f.js +0 -408
  435. package/dist/workspace-Cdrg7k9f.js.map +0 -1
@@ -0,0 +1,1102 @@
1
+ import { useMemo, useState } from 'react';
2
+ import {
3
+ CheckCircle2,
4
+ Mail,
5
+ Package,
6
+ RotateCcw,
7
+ Truck,
8
+ XCircle,
9
+ } from 'lucide-react';
10
+
11
+ import { ActionMenu } from 'themelia-react-ui/base/action-menu';
12
+ import { Badge } from 'themelia-react-ui/base/badge';
13
+ import { Button } from 'themelia-react-ui/base/buttons';
14
+ import { Card } from 'themelia-react-ui/base/cards';
15
+ import { Select, ToggleField } from 'themelia-react-ui/base/choice-inputs';
16
+ import { FormField, FormSection } from 'themelia-react-ui/base/forms';
17
+ import { DecimalInput } from 'themelia-react-ui/base/forms-numeric';
18
+ import {
19
+ Item,
20
+ ItemActions,
21
+ ItemContent,
22
+ ItemDescription,
23
+ ItemGroup,
24
+ ItemTitle,
25
+ } from 'themelia-react-ui/base/item';
26
+ import { Stack } from 'themelia-react-ui/base/structure';
27
+ import { Input, Textarea } from 'themelia-react-ui/base/text-inputs';
28
+ import { AddressCard, PaymentMethod } from 'themelia-react-ui/blocks/commerce';
29
+ import { MetadataList } from 'themelia-react-ui/base/metadata-list';
30
+ import { ActivityLog, type ActivityLogEntry } from 'themelia-react-ui/features/activities';
31
+ import { ActionDialog, useOverlayVisibility } from 'themelia-react-ui/features/overlays';
32
+ import { TwoColumnLayout } from 'themelia-react-ui/layout/containers';
33
+ import { Page } from 'themelia-react-ui/layout/page';
34
+ import { Money, useMoneyFormatter } from 'themelia-react-ui/primitives';
35
+ import { Text } from 'themelia-react-ui/typography';
36
+
37
+ type OrderItemFulfillmentState = 'fulfilled' | 'unfulfilled' | 'digital';
38
+
39
+ interface OrderLineItemRecord {
40
+ id: string;
41
+ name: string;
42
+ variant: string;
43
+ sku: string;
44
+ weightLabel?: string;
45
+ fulfillmentState: OrderItemFulfillmentState;
46
+ unitPrice: number;
47
+ orderedQty: number;
48
+ refundedQty: number;
49
+ canceledQty: number;
50
+ refundReason?: string;
51
+ restockedLocation?: string;
52
+ }
53
+
54
+ const INITIAL_LINE_ITEMS: OrderLineItemRecord[] = [
55
+ {
56
+ id: 'item-sweater',
57
+ name: 'Merino Wool Crewneck Sweater',
58
+ variant: 'Heather Gray / Medium',
59
+ sku: 'MWC-GRY-M',
60
+ weightLabel: '0.42 kg',
61
+ fulfillmentState: 'fulfilled',
62
+ unitPrice: 145,
63
+ orderedQty: 1,
64
+ refundedQty: 0,
65
+ canceledQty: 0,
66
+ },
67
+ {
68
+ id: 'item-shirt',
69
+ name: 'Washed Linen Oxford Shirt',
70
+ variant: 'White / Medium',
71
+ sku: 'WLO-WHT-M',
72
+ weightLabel: '0.32 kg',
73
+ fulfillmentState: 'fulfilled',
74
+ unitPrice: 95,
75
+ orderedQty: 2,
76
+ refundedQty: 0,
77
+ canceledQty: 0,
78
+ },
79
+ {
80
+ id: 'item-scarf',
81
+ name: 'Cashmere Ribbed Scarf',
82
+ variant: 'Oatmeal / One Size',
83
+ sku: 'CRS-OAT-OS',
84
+ weightLabel: '0.24 kg',
85
+ fulfillmentState: 'unfulfilled',
86
+ unitPrice: 110,
87
+ orderedQty: 1,
88
+ refundedQty: 0,
89
+ canceledQty: 0,
90
+ },
91
+ {
92
+ id: 'item-giftcard',
93
+ name: 'Oak & Loom Digital Gift Card',
94
+ variant: '50.00 USD denomination · Recipient: ava.bennett@example.com',
95
+ sku: 'DGC-50-USD',
96
+ fulfillmentState: 'digital',
97
+ unitPrice: 50,
98
+ orderedQty: 1,
99
+ refundedQty: 0,
100
+ canceledQty: 0,
101
+ },
102
+ {
103
+ id: 'item-tote',
104
+ name: 'Everyday Canvas Tote',
105
+ variant: 'Natural / One Size',
106
+ sku: 'ECT-NAT-OS',
107
+ weightLabel: '0.28 kg',
108
+ fulfillmentState: 'fulfilled',
109
+ unitPrice: 45,
110
+ orderedQty: 1,
111
+ refundedQty: 1,
112
+ canceledQty: 0,
113
+ refundReason: 'Customer exchanged size/color',
114
+ restockedLocation: 'Brooklyn Warehouse',
115
+ },
116
+ {
117
+ id: 'item-beanie',
118
+ name: 'Ribbed Merino Beanie',
119
+ variant: 'Charcoal / One Size',
120
+ sku: 'RMB-CHR-OS',
121
+ weightLabel: '0.15 kg',
122
+ fulfillmentState: 'unfulfilled',
123
+ unitPrice: 38,
124
+ orderedQty: 1,
125
+ refundedQty: 0,
126
+ canceledQty: 1,
127
+ refundReason: 'Canceled before fulfillment',
128
+ restockedLocation: 'Brooklyn Warehouse',
129
+ },
130
+ ];
131
+
132
+ const REFUND_REASONS = [
133
+ { value: 'size_exchange', label: 'Size or fit exchange' },
134
+ { value: 'customer_changed_mind', label: 'Customer changed mind' },
135
+ { value: 'damaged_in_transit', label: 'Arrived damaged' },
136
+ { value: 'wrong_item_sent', label: 'Incorrect item shipped' },
137
+ ];
138
+
139
+ const CARRIER_OPTIONS = [
140
+ { value: 'UPS Ground', label: 'UPS Ground' },
141
+ { value: 'UPS 2nd Day Air', label: 'UPS 2nd Day Air' },
142
+ { value: 'FedEx Home Delivery', label: 'FedEx Home Delivery' },
143
+ { value: 'DHL Express', label: 'DHL Express' },
144
+ ];
145
+
146
+ const INITIAL_TIMELINE: ActivityLogEntry[] = [
147
+ {
148
+ id: 'evt-refund-tote',
149
+ kind: 'event',
150
+ label: 'Refund',
151
+ actor: { name: 'Maya Lin', initials: 'ML' },
152
+ action: 'refunded',
153
+ target: '45.00 USD',
154
+ description: '1 × Everyday Canvas Tote returned to Visa •••• 4242 · Restocked at Brooklyn Warehouse',
155
+ timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(),
156
+ icon: RotateCcw,
157
+ tone: 'warning',
158
+ },
159
+ {
160
+ id: 'evt-shipped',
161
+ kind: 'event',
162
+ label: 'Fulfillment #1042-F1',
163
+ actor: { name: 'Brooklyn Warehouse', initials: 'BW' },
164
+ action: 'shipped 3 physical items via',
165
+ target: 'UPS Ground #1Z999AA10123456784',
166
+ timestamp: new Date(Date.now() - 18 * 60 * 60 * 1000).toISOString(),
167
+ icon: Truck,
168
+ tone: 'info',
169
+ },
170
+ {
171
+ id: 'evt-digital',
172
+ kind: 'event',
173
+ label: 'Digital #1042-D1',
174
+ actor: { name: 'Online Store', initials: 'OS' },
175
+ action: 'emailed a 50.00 USD digital gift card to',
176
+ target: 'ava.bennett@example.com',
177
+ timestamp: new Date(Date.now() - 23 * 60 * 60 * 1000).toISOString(),
178
+ icon: Mail,
179
+ tone: 'success',
180
+ },
181
+ {
182
+ id: 'evt-paid',
183
+ kind: 'event',
184
+ label: 'Payment',
185
+ actor: { name: 'Ava Bennett', initials: 'AB' },
186
+ action: 'authorized and captured',
187
+ target: '519.21 USD on Visa ending in 4242',
188
+ timestamp: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
189
+ icon: CheckCircle2,
190
+ tone: 'success',
191
+ },
192
+ ];
193
+
194
+ export function OrdersAdminTemplate() {
195
+ // Sample records are priced in USD; bind that once for every text amount.
196
+ const formatMoney = useMoneyFormatter({ currency: 'USD' });
197
+ const [lineItems, setLineItems] = useState<OrderLineItemRecord[]>(INITIAL_LINE_ITEMS);
198
+ const [timeline, setTimeline] = useState<ActivityLogEntry[]>(INITIAL_TIMELINE);
199
+ const [orderNote, setOrderNote] = useState(
200
+ 'Please leave package with the building doorman if I am not home.',
201
+ );
202
+
203
+ const [noteDraft, setNoteDraft] = useState(orderNote);
204
+ // Shipment tracking state
205
+ const [carrier, setCarrier] = useState('UPS Ground');
206
+ const [trackingNumber, setTrackingNumber] = useState('1Z999AA10123456784');
207
+ const [notifyTrackingCustomer, setNotifyTrackingCustomer] = useState(true);
208
+ const [trackingDraft, setTrackingDraft] = useState({ carrier, trackingNumber, notifyCustomer: notifyTrackingCustomer });
209
+
210
+ // Refund dialog state
211
+ const refundDialog = useOverlayVisibility();
212
+ const trackingDialog = useOverlayVisibility();
213
+ const noteDialog = useOverlayVisibility();
214
+
215
+ const [refundSelection, setRefundSelection] = useState<Record<string, number>>({
216
+ 'item-sweater': 0,
217
+ 'item-shirt': 1,
218
+ 'item-scarf': 0,
219
+ 'item-giftcard': 0,
220
+ });
221
+ const [refundReason, setRefundReason] = useState('size_exchange');
222
+ const [restockInventory, setRestockInventory] = useState(true);
223
+ const [notifyCustomer, setNotifyCustomer] = useState(true);
224
+ const [refundNote, setRefundNote] = useState('');
225
+
226
+ const fulfilledPhysicalItems = useMemo(
227
+ () =>
228
+ lineItems.filter(
229
+ (item) =>
230
+ item.fulfillmentState === 'fulfilled' &&
231
+ item.orderedQty - item.refundedQty - item.canceledQty > 0,
232
+ ),
233
+ [lineItems],
234
+ );
235
+
236
+ const unfulfilledPhysicalItems = useMemo(
237
+ () =>
238
+ lineItems.filter(
239
+ (item) =>
240
+ item.fulfillmentState === 'unfulfilled' &&
241
+ item.orderedQty - item.refundedQty - item.canceledQty > 0,
242
+ ),
243
+ [lineItems],
244
+ );
245
+
246
+ const fulfilledDigitalItems = useMemo(
247
+ () =>
248
+ lineItems.filter(
249
+ (item) =>
250
+ item.fulfillmentState === 'digital' &&
251
+ item.orderedQty - item.refundedQty - item.canceledQty > 0,
252
+ ),
253
+ [lineItems],
254
+ );
255
+
256
+ const removedItems = useMemo(
257
+ () => lineItems.filter((item) => item.refundedQty > 0 || item.canceledQty > 0),
258
+ [lineItems],
259
+ );
260
+
261
+ const activeSubtotal = useMemo(
262
+ () =>
263
+ lineItems.reduce((sum, item) => {
264
+ const activeUnits = item.orderedQty - item.canceledQty;
265
+ return sum + activeUnits * item.unitPrice;
266
+ }, 0),
267
+ [lineItems],
268
+ );
269
+
270
+ const totalRefundedAmount = useMemo(
271
+ () =>
272
+ lineItems.reduce((sum, item) => sum + item.refundedQty * item.unitPrice, 0),
273
+ [lineItems],
274
+ );
275
+
276
+ const discountAmount = 50.25;
277
+ const shippingAmount = 0;
278
+ const taxAmount = 29.46;
279
+ const originalCapturedTotal = INITIAL_LINE_ITEMS.reduce((sum, item) => sum + (item.orderedQty - item.canceledQty) * item.unitPrice, 0) - discountAmount + shippingAmount + taxAmount;
280
+ const netPayment = Math.max(0, originalCapturedTotal - totalRefundedAmount);
281
+
282
+ const draftRefundTotal = useMemo(
283
+ () =>
284
+ lineItems.reduce((sum, item) => {
285
+ const requested = refundSelection[item.id] ?? 0;
286
+ const selectedQty = Number.isFinite(requested) ? Math.min(Math.max(0, Math.floor(requested)), item.orderedQty - item.refundedQty - item.canceledQty) : 0;
287
+ return sum + selectedQty * item.unitPrice;
288
+ }, 0),
289
+ [lineItems, refundSelection],
290
+ );
291
+
292
+ const openRefundForSingleItem = (itemId: string) => {
293
+ setRefundSelection({
294
+ 'item-sweater': 0,
295
+ 'item-shirt': 0,
296
+ 'item-scarf': 0,
297
+ 'item-giftcard': 0,
298
+ [itemId]: 1,
299
+ });
300
+ refundDialog.show();
301
+ };
302
+
303
+ const handleFulfillItem = (itemId: string) => {
304
+ const targetItem = lineItems.find((item) => item.id === itemId);
305
+ if (!targetItem) return;
306
+
307
+ setLineItems((current) =>
308
+ current.map((item) =>
309
+ item.id === itemId ? { ...item, fulfillmentState: 'fulfilled' } : item,
310
+ ),
311
+ );
312
+
313
+ setTimeline((current) => [
314
+ {
315
+ id: `evt-fulfill-${Date.now()}`,
316
+ kind: 'event',
317
+ label: 'Fulfillment #1042-F1',
318
+ actor: { name: 'Maya Lin', initials: 'ML' },
319
+ action: 'fulfilled',
320
+ target: `${targetItem.orderedQty - targetItem.refundedQty - targetItem.canceledQty} × ${targetItem.name}`,
321
+ description: `Added to shipment ${carrier} #${trackingNumber}`,
322
+ timestamp: new Date().toISOString(),
323
+ icon: Package,
324
+ tone: 'success',
325
+ },
326
+ ...current,
327
+ ]);
328
+ };
329
+
330
+ const handleCancelUnfulfilledItem = (itemId: string) => {
331
+ const targetItem = lineItems.find((item) => item.id === itemId);
332
+ if (!targetItem) return;
333
+ const remainingQty =
334
+ targetItem.orderedQty - targetItem.refundedQty - targetItem.canceledQty;
335
+ if (remainingQty <= 0) return;
336
+
337
+ setLineItems((current) =>
338
+ current.map((item) =>
339
+ item.id === itemId
340
+ ? {
341
+ ...item,
342
+ canceledQty: item.canceledQty + remainingQty,
343
+ refundReason: 'Canceled before fulfillment',
344
+ restockedLocation: 'Brooklyn Warehouse',
345
+ }
346
+ : item,
347
+ ),
348
+ );
349
+
350
+ setTimeline((current) => [
351
+ {
352
+ id: `evt-cancel-${Date.now()}`,
353
+ kind: 'event',
354
+ label: 'Cancellation',
355
+ actor: { name: 'Maya Lin', initials: 'ML' },
356
+ action: 'canceled unfulfilled item',
357
+ target: `${remainingQty} × ${targetItem.name}`,
358
+ description: 'Inventory released at Brooklyn Warehouse',
359
+ timestamp: new Date().toISOString(),
360
+ icon: XCircle,
361
+ tone: 'destructive',
362
+ },
363
+ ...current,
364
+ ]);
365
+ };
366
+
367
+ const handleResendGiftCard = () => {
368
+ setTimeline((current) => [
369
+ {
370
+ id: `evt-resend-dgc-${Date.now()}`,
371
+ kind: 'event',
372
+ label: 'Digital #1042-D1',
373
+ actor: { name: 'Maya Lin', initials: 'ML' },
374
+ action: 'resent digital gift card email to',
375
+ target: 'ava.bennett@example.com',
376
+ timestamp: new Date().toISOString(),
377
+ icon: Mail,
378
+ tone: 'info',
379
+ },
380
+ ...current,
381
+ ]);
382
+ };
383
+
384
+ const handleConfirmRefund = () => {
385
+ if (draftRefundTotal <= 0) {
386
+ refundDialog.hide();
387
+ return;
388
+ }
389
+
390
+ const reasonLabel =
391
+ REFUND_REASONS.find((r) => r.value === refundReason)?.label ?? 'Customer return';
392
+ const refundedNames: string[] = [];
393
+
394
+ const nextLineItems = lineItems.map((item) => {
395
+ const requested = refundSelection[item.id] ?? 0;
396
+ const selectedQty = Number.isFinite(requested) ? Math.min(Math.max(0, Math.floor(requested)), item.orderedQty - item.refundedQty - item.canceledQty) : 0;
397
+ if (selectedQty <= 0) return item;
398
+ const maxRefundable = item.orderedQty - item.refundedQty - item.canceledQty;
399
+ const applied = Math.min(selectedQty, maxRefundable);
400
+ if (applied > 0) {
401
+ refundedNames.push(`${applied} × ${item.name}`);
402
+ }
403
+ return {
404
+ ...item,
405
+ refundedQty: item.refundedQty + applied,
406
+ refundReason: reasonLabel,
407
+ restockedLocation: restockInventory ? 'Brooklyn Warehouse' : undefined,
408
+ };
409
+ });
410
+ setLineItems(nextLineItems);
411
+
412
+ setTimeline((current) => [
413
+ {
414
+ id: `evt-refund-${Date.now()}`,
415
+ kind: 'event',
416
+ label: 'Refund',
417
+ actor: { name: 'Maya Lin', initials: 'ML' },
418
+ action: 'refunded',
419
+ target: formatMoney(draftRefundTotal),
420
+ description: `for ${refundedNames.join(', ')} (${reasonLabel}${restockInventory ? ' · Restocked at Brooklyn Warehouse' : ''})${refundNote.trim() ? ` · ${refundNote.trim()}` : ''}${notifyCustomer ? ' · Customer notification requested' : ''}`,
421
+ timestamp: new Date().toISOString(),
422
+ icon: RotateCcw,
423
+ tone: 'warning',
424
+ },
425
+ ...current,
426
+ ]);
427
+
428
+ setRefundSelection({});
429
+ setRefundNote('');
430
+ refundDialog.hide();
431
+ };
432
+
433
+ const unfulfilledUnitCount = unfulfilledPhysicalItems.reduce(
434
+ (sum, item) => sum + (item.orderedQty - item.refundedQty - item.canceledQty),
435
+ 0,
436
+ );
437
+
438
+ const handleFulfillRemaining = () =>
439
+ unfulfilledPhysicalItems.forEach((item) => handleFulfillItem(item.id));
440
+
441
+ return (
442
+ <Page
443
+ header={{
444
+ title: 'Order #1042',
445
+ description: 'October 14, 2026 at 2:14 pm · Online Store',
446
+ titleBadges: [
447
+ {
448
+ label: totalRefundedAmount > 0 ? 'Partially refunded' : 'Paid',
449
+ tone: totalRefundedAmount > 0 ? 'warning' : 'success',
450
+ },
451
+ {
452
+ label: unfulfilledUnitCount > 0 ? 'Partially fulfilled' : 'Fulfilled',
453
+ tone: unfulfilledUnitCount > 0 ? 'info' : 'success',
454
+ },
455
+ ],
456
+ // Fulfillment is the order's next step, so it is the route's one primary command
457
+ // while physical items remain unfulfilled.
458
+ primaryAction: {
459
+ label: `Fulfill ${unfulfilledUnitCount === 1 ? 'item' : 'items'}`,
460
+ visible: unfulfilledUnitCount > 0,
461
+ onClick: handleFulfillRemaining,
462
+ },
463
+ secondaryActions: [{ label: 'Refund items', onClick: refundDialog.show }],
464
+ }}
465
+ >
466
+ <TwoColumnLayout
467
+ stickyAside
468
+ main={
469
+ <Stack gap="2xl">
470
+ {/* Group 1: Fulfilled Physical Shipment */}
471
+ <Card
472
+ title="Fulfilled shipment · #1042-F1"
473
+ headerAction={
474
+ <Button
475
+ size="sm"
476
+ onClick={() => { setTrackingDraft({ carrier, trackingNumber, notifyCustomer: notifyTrackingCustomer }); trackingDialog.show(); }}
477
+ >
478
+ Edit tracking
479
+ </Button>
480
+ }
481
+ >
482
+ <Stack gap="2xl">
483
+ <MetadataList
484
+ columns={3}
485
+ items={[
486
+ {
487
+ id: 'carrier',
488
+ label: 'Carrier',
489
+ value: carrier,
490
+ },
491
+ {
492
+ id: 'tracking',
493
+ label: 'Tracking',
494
+ value: { kind: 'mono', value: trackingNumber },
495
+ },
496
+ {
497
+ id: 'origin',
498
+ label: 'Origin',
499
+ value: 'Brooklyn Warehouse',
500
+ },
501
+ ]}
502
+ />
503
+
504
+ <ItemGroup>
505
+ {fulfilledPhysicalItems.map((item) => {
506
+ const activeQty =
507
+ item.orderedQty - item.refundedQty - item.canceledQty;
508
+ return (
509
+ <Item key={item.id} size="md">
510
+ <ItemContent className="basis-48">
511
+ <ItemTitle>{item.name}</ItemTitle>
512
+ <ItemDescription>
513
+ {item.variant} · SKU {item.sku}
514
+ {item.weightLabel ? ` · ${item.weightLabel}` : ''}
515
+ </ItemDescription>
516
+ </ItemContent>
517
+ <ItemActions>
518
+ <Stack direction="horizontal" gap="md" align="center">
519
+ <Text size="sm" type="secondary">
520
+ {formatMoney(item.unitPrice)} × {activeQty}
521
+ </Text>
522
+ <Money
523
+ amount={item.unitPrice * activeQty}
524
+ currency="USD"
525
+ weight="semibold"
526
+ />
527
+ <ActionMenu
528
+ actions={[
529
+ {
530
+ id: `refund-${item.id}`,
531
+ label: 'Refund item',
532
+ icon: RotateCcw,
533
+ onClick: () => openRefundForSingleItem(item.id),
534
+ },
535
+ ]}
536
+ />
537
+ </Stack>
538
+ </ItemActions>
539
+ </Item>
540
+ );
541
+ })}
542
+ </ItemGroup>
543
+ </Stack>
544
+ </Card>
545
+
546
+ {/* Group 2: Unfulfilled Physical Items (if any remain unfulfilled) */}
547
+ {unfulfilledPhysicalItems.length > 0 && (
548
+ <Card title="Unfulfilled · #1042-U1">
549
+ <Stack gap="2xl">
550
+ <MetadataList
551
+ columns={3}
552
+ items={[
553
+ {
554
+ id: 'location',
555
+ label: 'Location',
556
+ value: 'Brooklyn Warehouse',
557
+ },
558
+ {
559
+ id: 'shipping-method',
560
+ label: 'Delivery method',
561
+ value: 'UPS Ground',
562
+ },
563
+ {
564
+ id: 'stock-status',
565
+ label: 'Stock',
566
+ value: {
567
+ kind: 'badge',
568
+ value: 'Ready to pack',
569
+ badgeTone: 'success',
570
+ },
571
+ },
572
+ ]}
573
+ />
574
+
575
+ <ItemGroup>
576
+ {unfulfilledPhysicalItems.map((item) => {
577
+ const activeQty =
578
+ item.orderedQty - item.refundedQty - item.canceledQty;
579
+ return (
580
+ <Item key={item.id} size="md">
581
+ <ItemContent className="basis-48">
582
+ <ItemTitle>{item.name}</ItemTitle>
583
+ <ItemDescription>
584
+ {item.variant} · SKU {item.sku}
585
+ {item.weightLabel ? ` · ${item.weightLabel}` : ''}
586
+ </ItemDescription>
587
+ </ItemContent>
588
+ <ItemActions>
589
+ <Stack direction="horizontal" gap="md" align="center">
590
+ <Text size="sm" type="secondary">
591
+ {formatMoney(item.unitPrice)} × {activeQty}
592
+ </Text>
593
+ <Money
594
+ amount={item.unitPrice * activeQty}
595
+ currency="USD"
596
+ weight="semibold"
597
+ />
598
+ <ActionMenu
599
+ actions={[
600
+ {
601
+ id: `fulfill-${item.id}`,
602
+ label: 'Mark as fulfilled',
603
+ icon: Package,
604
+ onClick: () => handleFulfillItem(item.id),
605
+ },
606
+ {
607
+ id: `cancel-${item.id}`,
608
+ label: 'Cancel item',
609
+ icon: XCircle,
610
+ tone: 'destructive',
611
+ onClick: () =>
612
+ handleCancelUnfulfilledItem(item.id),
613
+ },
614
+ ]}
615
+ />
616
+ </Stack>
617
+ </ItemActions>
618
+ </Item>
619
+ );
620
+ })}
621
+ </ItemGroup>
622
+ </Stack>
623
+ </Card>
624
+ )}
625
+
626
+ {/* Group 3: Digital Delivery */}
627
+ <Card
628
+ title="Digital delivery · #1042-D1"
629
+ headerAction={
630
+ <Button size="sm" onClick={handleResendGiftCard}>
631
+ Resend gift card
632
+ </Button>
633
+ }
634
+ >
635
+ <Stack gap="2xl">
636
+ <MetadataList
637
+ columns={3}
638
+ items={[
639
+ {
640
+ id: 'recipient',
641
+ label: 'Recipient',
642
+ value: { kind: 'email', value: 'ava.bennett@example.com' },
643
+ },
644
+ {
645
+ id: 'code',
646
+ label: 'Gift card code',
647
+ value: { kind: 'mono', value: '•••• •••• •••• 8F2A' },
648
+ },
649
+ {
650
+ id: 'status',
651
+ label: 'Status',
652
+ value: {
653
+ kind: 'badge',
654
+ value: 'Sent Oct 14',
655
+ badgeTone: 'success',
656
+ },
657
+ },
658
+ ]}
659
+ />
660
+
661
+ <ItemGroup>
662
+ {fulfilledDigitalItems.map((item) => {
663
+ const activeQty =
664
+ item.orderedQty - item.refundedQty - item.canceledQty;
665
+ return (
666
+ <Item key={item.id} size="md">
667
+ <ItemContent className="basis-48">
668
+ <ItemTitle>{item.name}</ItemTitle>
669
+ <ItemDescription>
670
+ {item.variant} · SKU {item.sku}
671
+ </ItemDescription>
672
+ </ItemContent>
673
+ <ItemActions>
674
+ <Stack direction="horizontal" gap="md" align="center">
675
+ <Text size="sm" type="secondary">
676
+ {formatMoney(item.unitPrice)} × {activeQty}
677
+ </Text>
678
+ <Money
679
+ amount={item.unitPrice * activeQty}
680
+ currency="USD"
681
+ weight="semibold"
682
+ />
683
+ <ActionMenu
684
+ actions={[
685
+ {
686
+ id: `resend-${item.id}`,
687
+ label: 'Resend email',
688
+ icon: Mail,
689
+ onClick: handleResendGiftCard,
690
+ },
691
+ {
692
+ id: `refund-${item.id}`,
693
+ label: 'Refund gift card',
694
+ icon: RotateCcw,
695
+ onClick: () => openRefundForSingleItem(item.id),
696
+ },
697
+ ]}
698
+ />
699
+ </Stack>
700
+ </ItemActions>
701
+ </Item>
702
+ );
703
+ })}
704
+ </ItemGroup>
705
+ </Stack>
706
+ </Card>
707
+
708
+ {/* Group 4: Refunded & Canceled Items */}
709
+ {removedItems.length > 0 && (
710
+ <Card
711
+ title="Refunded & canceled"
712
+ headerAction={
713
+ <Button size="sm" onClick={refundDialog.show}>
714
+ Refund more items
715
+ </Button>
716
+ }
717
+ >
718
+ <ItemGroup>
719
+ {removedItems.map((item) => {
720
+ const isCanceled = item.canceledQty > 0 && item.refundedQty === 0;
721
+ const qty = isCanceled ? item.canceledQty : item.refundedQty;
722
+ return (
723
+ <Item key={`removed-${item.id}`} size="md">
724
+ <ItemContent className="basis-48">
725
+ <ItemTitle>
726
+ <Stack direction="horizontal" gap="sm" align="center" wrap>
727
+ <Text tag="span" size="inherit" weight="semibold" lineHeight="tight">{item.name}</Text>
728
+ <Badge tone={isCanceled ? 'destructive' : 'warning'}>
729
+ {isCanceled ? 'Canceled' : 'Refunded'}
730
+ </Badge>
731
+ </Stack>
732
+ </ItemTitle>
733
+ <ItemDescription>
734
+ {item.variant} · SKU {item.sku}
735
+ {item.refundReason ? ` · ${item.refundReason}` : ''}
736
+ {item.restockedLocation
737
+ ? ` · Restocked at ${item.restockedLocation}`
738
+ : ''}
739
+ </ItemDescription>
740
+ </ItemContent>
741
+ <ItemActions>
742
+ <Stack direction="horizontal" gap="lg" align="center">
743
+ <Text size="sm" type="secondary">
744
+ {formatMoney(item.unitPrice)} × {qty}
745
+ </Text>
746
+ <Money
747
+ amount={isCanceled ? 0 : -(item.unitPrice * qty)}
748
+ currency="USD"
749
+ weight="semibold"
750
+ />
751
+ </Stack>
752
+ </ItemActions>
753
+ </Item>
754
+ );
755
+ })}
756
+ </ItemGroup>
757
+ </Card>
758
+ )}
759
+
760
+ {/* Payment Summary Card: the page header's badge states the payment status once. */}
761
+ <Card title="Payment">
762
+ <Stack gap="2xl">
763
+ <MetadataList
764
+ layout="rows"
765
+ density="compact"
766
+ valueAlign="end"
767
+ items={[
768
+ {
769
+ id: 'subtotal',
770
+ label: 'Subtotal (5 active items)',
771
+ value: { kind: 'money', value: activeSubtotal, currency: 'USD' },
772
+ },
773
+ {
774
+ id: 'discount',
775
+ label: 'Discount · AUTUMN15 (15% off apparel)',
776
+ value: { kind: 'money', value: -discountAmount, currency: 'USD' },
777
+ },
778
+ {
779
+ id: 'shipping',
780
+ label: `Shipping · ${carrier} (1.4 kg)`,
781
+ value: { kind: 'money', value: shippingAmount, currency: 'USD' },
782
+ },
783
+ {
784
+ id: 'taxes',
785
+ label: 'Taxes · NY State & NYC Local 8.875%',
786
+ value: { kind: 'money', value: taxAmount, currency: 'USD' },
787
+ },
788
+ {
789
+ id: 'total',
790
+ label: <Text weight="semibold">Total</Text>,
791
+ value: (
792
+ <Money
793
+ amount={originalCapturedTotal}
794
+ currency="USD"
795
+ weight="bold"
796
+ />
797
+ ),
798
+ },
799
+ ]}
800
+ />
801
+
802
+ <MetadataList
803
+ layout="rows"
804
+ density="compact"
805
+ valueAlign="end"
806
+ items={[
807
+ {
808
+ id: 'paid',
809
+ label: 'Paid by customer (Visa •••• 4242)',
810
+ value: {
811
+ kind: 'money' as const,
812
+ value: originalCapturedTotal,
813
+ currency: 'USD',
814
+ },
815
+ },
816
+ ...(totalRefundedAmount > 0
817
+ ? [
818
+ {
819
+ id: 'refunded',
820
+ label: 'Refunded to Visa •••• 4242',
821
+ value: {
822
+ kind: 'money' as const,
823
+ value: -totalRefundedAmount,
824
+ currency: 'USD',
825
+ },
826
+ },
827
+ ]
828
+ : []),
829
+ {
830
+ id: 'net',
831
+ label: <Text weight="semibold">Net payment</Text>,
832
+ value: <Money amount={netPayment} currency="USD" weight="bold" />,
833
+ },
834
+ ]}
835
+ />
836
+ </Stack>
837
+ </Card>
838
+
839
+ {/* Order Timeline */}
840
+ <Card title="Timeline">
841
+ <ActivityLog bare entries={timeline} itemSpacing="compact" />
842
+ </Card>
843
+ </Stack>
844
+ }
845
+ aside={
846
+ <Stack gap="2xl">
847
+ {/* Customer Metadata Card */}
848
+ <Card title="Customer">
849
+ <MetadataList
850
+ columns={1}
851
+ items={[
852
+ {
853
+ id: 'customer-name',
854
+ label: 'Name',
855
+ value: {
856
+ kind: 'text',
857
+ value: 'Ava Bennett',
858
+ },
859
+ },
860
+ {
861
+ id: 'customer-orders',
862
+ label: 'Orders',
863
+ value: `12 orders (${formatMoney(1840)} spent)`,
864
+ },
865
+ {
866
+ id: 'customer-email',
867
+ label: 'Email',
868
+ value: {
869
+ kind: 'email',
870
+ value: 'ava.bennett@example.com',
871
+ },
872
+ },
873
+ {
874
+ id: 'customer-phone',
875
+ label: 'Phone',
876
+ value: {
877
+ kind: 'phone',
878
+ value: '+12125550148',
879
+ display: '+1 (212) 555-0148',
880
+ },
881
+ },
882
+ ]}
883
+ />
884
+ </Card>
885
+
886
+ {/* Shipping Address Card */}
887
+ <AddressCard
888
+ surface="card"
889
+ kind="shipping"
890
+ default
891
+ name="Ava Bennett"
892
+ line1="214 Mercer Street"
893
+ line2="Apt 4B"
894
+ city="New York, NY"
895
+ postalCode="10012"
896
+ country="United States"
897
+ phone="+1 (212) 555-0148"
898
+ />
899
+
900
+ {/* Billing Address Card */}
901
+ <AddressCard
902
+ surface="card"
903
+ kind="billing"
904
+ name="Ava Bennett"
905
+ line1="214 Mercer Street"
906
+ line2="Apt 4B"
907
+ city="New York, NY"
908
+ postalCode="10012"
909
+ country="United States"
910
+ />
911
+
912
+ {/* Payment Method Card */}
913
+ <PaymentMethod
914
+ surface="card"
915
+ brand="visa"
916
+ last4="4242"
917
+ expiry="08/28"
918
+ holderName="Ava Bennett"
919
+ default
920
+ />
921
+
922
+ {/* Customer Delivery Note */}
923
+ <Card
924
+ title="Notes"
925
+ headerAction={
926
+ <Button
927
+ tone="secondary"
928
+ buttonStyle="ghost"
929
+ size="sm"
930
+ onClick={() => { setNoteDraft(orderNote); noteDialog.show(); }}
931
+ >
932
+ Edit
933
+ </Button>
934
+ }
935
+ >
936
+ <Text size="sm" type="secondary">
937
+ {orderNote}
938
+ </Text>
939
+ </Card>
940
+ </Stack>
941
+ }
942
+ />
943
+
944
+ {/* Edit Tracking Dialog */}
945
+ <ActionDialog
946
+ {...trackingDialog.overlayProps}
947
+ title="Edit tracking · Shipment #1042-F1"
948
+ description="Update carrier and tracking details for this fulfilled shipment."
949
+ strings={{
950
+ confirm: 'Save tracking',
951
+ cancel: 'Cancel',
952
+ }}
953
+ onConfirm={() => { setCarrier(trackingDraft.carrier); setTrackingNumber(trackingDraft.trackingNumber); setNotifyTrackingCustomer(trackingDraft.notifyCustomer); trackingDialog.hide(); }}
954
+ >
955
+ <FormSection title="Shipment tracking">
956
+ <FormField label="Shipping carrier" required>
957
+ <Select
958
+ aria-label="Shipping carrier"
959
+ options={CARRIER_OPTIONS}
960
+ value={trackingDraft.carrier}
961
+ onValueChange={(value) => setTrackingDraft((draft) => ({ ...draft, carrier: String(value) }))}
962
+ />
963
+ </FormField>
964
+ <FormField label="Tracking number" required>
965
+ <Input
966
+ aria-label="Tracking number"
967
+ value={trackingDraft.trackingNumber}
968
+ onChange={(event) => setTrackingDraft((draft) => ({ ...draft, trackingNumber: event.target.value }))}
969
+ />
970
+ </FormField>
971
+ <ToggleField
972
+ kind="checkbox"
973
+ value={trackingDraft.notifyCustomer}
974
+ onValueChange={(checked) => setTrackingDraft((draft) => ({ ...draft, notifyCustomer: Boolean(checked) }))}
975
+ label="Send tracking update email to customer"
976
+ />
977
+ </FormSection>
978
+ </ActionDialog>
979
+
980
+ {/* Edit Order Note Dialog */}
981
+ <ActionDialog
982
+ {...noteDialog.overlayProps}
983
+ title="Edit order note"
984
+ description="Update delivery instructions or internal notes for Order #1042."
985
+ strings={{
986
+ confirm: 'Save note',
987
+ cancel: 'Cancel',
988
+ }}
989
+ onConfirm={() => { setOrderNote(noteDraft); noteDialog.hide(); }}
990
+ >
991
+ <FormSection title="Order note">
992
+ <FormField label="Note">
993
+ <Textarea
994
+ aria-label="Order note"
995
+ rows={3}
996
+ value={noteDraft}
997
+ onChange={(event) => setNoteDraft(event.target.value)}
998
+ />
999
+ </FormField>
1000
+ </FormSection>
1001
+ </ActionDialog>
1002
+
1003
+ {/* Refund Items Dialog */}
1004
+ <ActionDialog
1005
+ {...refundDialog.overlayProps}
1006
+ title="Refund items · Order #1042"
1007
+ description="Select quantities to refund and return to inventory."
1008
+ strings={{
1009
+ confirm:
1010
+ draftRefundTotal > 0
1011
+ ? `Refund ${formatMoney(draftRefundTotal)}`
1012
+ : 'Select items to refund',
1013
+ cancel: 'Cancel',
1014
+ }}
1015
+ onConfirm={handleConfirmRefund}
1016
+ >
1017
+ <Stack gap="2xl">
1018
+ <FormSection title="Refundable line items">
1019
+ <Stack gap="md">
1020
+ {lineItems
1021
+ .filter((item) => item.orderedQty - item.refundedQty - item.canceledQty > 0)
1022
+ .map((item) => {
1023
+ const maxQty = item.orderedQty - item.refundedQty - item.canceledQty;
1024
+ const currentQty = refundSelection[item.id] ?? 0;
1025
+ return (
1026
+ <Stack
1027
+ key={item.id}
1028
+ direction="horizontal"
1029
+ justify="between"
1030
+ align="center"
1031
+ gap="md"
1032
+ >
1033
+ <Stack gap="xs">
1034
+ <Text weight="medium">{item.name}</Text>
1035
+ <Text size="xs" type="secondary">
1036
+ {item.variant} · {formatMoney(item.unitPrice)} × {maxQty} available
1037
+ </Text>
1038
+ </Stack>
1039
+ <DecimalInput
1040
+ aria-label={`Refund quantity for ${item.name}`}
1041
+ decimalPlaces={0}
1042
+ step={1}
1043
+ min={0}
1044
+ max={maxQty}
1045
+ value={String(currentQty)}
1046
+ onChange={(event) =>
1047
+ setRefundSelection((prev) => ({
1048
+ ...prev,
1049
+ [item.id]: Math.max(
1050
+ 0,
1051
+ Math.min(maxQty, Number(event.target.value || 0)),
1052
+ ),
1053
+ }))
1054
+ }
1055
+ />
1056
+ </Stack>
1057
+ );
1058
+ })}
1059
+ </Stack>
1060
+ </FormSection>
1061
+ <FormSection title="Refund details">
1062
+ <Stack gap="md">
1063
+ <FormField label="Reason for refund" required>
1064
+ <Select
1065
+ aria-label="Reason for refund"
1066
+ options={REFUND_REASONS}
1067
+ value={refundReason}
1068
+ onValueChange={(value) => setRefundReason(String(value))}
1069
+ />
1070
+ </FormField>
1071
+
1072
+ <FormField label="Staff note (optional)">
1073
+ <Textarea
1074
+ aria-label="Staff note"
1075
+ value={refundNote}
1076
+ onChange={(event) => setRefundNote(event.target.value)}
1077
+ placeholder="Reason for refund or inspection note..."
1078
+ rows={2}
1079
+ />
1080
+ </FormField>
1081
+
1082
+ <ToggleField
1083
+ kind="checkbox"
1084
+ value={restockInventory}
1085
+ onValueChange={(checked) => setRestockInventory(Boolean(checked))}
1086
+ label="Restock returned items at Brooklyn Warehouse"
1087
+ />
1088
+ <ToggleField
1089
+ kind="checkbox"
1090
+ value={notifyCustomer}
1091
+ onValueChange={(checked) => setNotifyCustomer(Boolean(checked))}
1092
+ label="Send refund notification email to customer"
1093
+ />
1094
+ </Stack>
1095
+ </FormSection>
1096
+ </Stack>
1097
+ </ActionDialog>
1098
+ </Page>
1099
+ );
1100
+ }
1101
+
1102
+ export default OrdersAdminTemplate;