themelia-react-ui 2.0.3 → 2.0.5
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.
- package/CHANGELOG.md +185 -0
- package/README.md +168 -36
- package/dist/{accordion-Cjb6sx0G.js → accordion-B9MHG0cT.js} +11 -11
- package/dist/accordion-B9MHG0cT.js.map +1 -0
- package/dist/action-menu-Dr8K-ghE.js +284 -0
- package/dist/action-menu-Dr8K-ghE.js.map +1 -0
- package/dist/{affordance-geometry.generated-tF36bREk.js → affordance-geometry.generated-P-aVJisu.js} +42 -36
- package/dist/affordance-geometry.generated-P-aVJisu.js.map +1 -0
- package/dist/{ai-artifact-DvTwDVyL.js → ai-artifact-C58tQcBy.js} +387 -350
- package/dist/ai-artifact-C58tQcBy.js.map +1 -0
- package/dist/app-shell-B_IuNWOo.js +321 -0
- package/dist/app-shell-B_IuNWOo.js.map +1 -0
- package/dist/{attachment-BxDfL2mw.js → attachment-Dg_69lPS.js} +9 -9
- package/dist/{attachment-BxDfL2mw.js.map → attachment-Dg_69lPS.js.map} +1 -1
- package/dist/{auth-BGua8ouh.js → auth-DTkkshS8.js} +44 -47
- package/dist/auth-DTkkshS8.js.map +1 -0
- package/dist/{avatar-DAPlDvhJ.js → avatar-CeZaFmNH.js} +8 -8
- package/dist/avatar-CeZaFmNH.js.map +1 -0
- package/dist/{badge-HpFqoqSY.js → badge-xIiV_E7f.js} +5 -5
- package/dist/{badge-HpFqoqSY.js.map → badge-xIiV_E7f.js.map} +1 -1
- package/dist/base/accordion.js +1 -1
- package/dist/base/action-menu.js +1 -1
- package/dist/base/attachment.js +1 -1
- package/dist/base/avatar.js +1 -1
- package/dist/base/badge.js +1 -1
- package/dist/base/batch-action-bar.js +1 -1
- package/dist/base/buttons.js +1 -1
- package/dist/base/cards.js +2 -2
- package/dist/base/carousel.js +3 -3
- package/dist/base/cascader.js +2 -372
- package/dist/base/chart.js +1 -1
- package/dist/base/choice-inputs.js +2 -2
- package/dist/base/code-block.js +1 -1
- package/dist/base/combobox.js +2 -2
- package/dist/base/command.js +1 -1
- package/dist/base/copyable.js +1 -1
- package/dist/base/date-pickers.js +2 -2
- package/dist/base/display.js +6 -6
- package/dist/base/feedback.js +3 -3
- package/dist/base/forms-numeric.js +1 -1
- package/dist/base/forms.js +3 -3
- package/dist/base/inline-edit.js +10 -10
- package/dist/base/item.js +1 -1
- package/dist/base/media-gallery.js +1 -1
- package/dist/base/metadata-list.js +1 -1
- package/dist/base/navigation.js +7 -7
- package/dist/base/popover-menu.js +1 -1
- package/dist/base/popover.js +1 -1
- package/dist/base/qr-code.js +1 -1
- package/dist/base/repeaters.js +12 -12
- package/dist/base/repeaters.js.map +1 -1
- package/dist/base/sheet.js +1 -1
- package/dist/base/sidebar.js +2 -2
- package/dist/base/signature-pad.js +7 -7
- package/dist/base/signature-pad.js.map +1 -1
- package/dist/base/skeleton.js +1 -1
- package/dist/base/spinner.js +4 -4
- package/dist/base/structure.js +1 -1
- package/dist/base/table.js +1 -1
- package/dist/base/text-inputs.js +2 -2
- package/dist/base/toaster.js +36 -36
- package/dist/base/toaster.js.map +1 -1
- package/dist/base/tree.js +1 -1
- package/dist/base/upload-queue.js +1 -1
- package/dist/base/upload.js +3 -3
- package/dist/base/value-inputs.js +1 -1
- package/dist/{batch-action-bar-DnUJ21NQ.js → batch-action-bar-Cb8cuvyy.js} +6 -6
- package/dist/batch-action-bar-Cb8cuvyy.js.map +1 -0
- package/dist/blocks/admin.js +23 -23
- package/dist/blocks/admin.js.map +1 -1
- package/dist/blocks/ai.js +230 -216
- package/dist/blocks/ai.js.map +1 -1
- package/dist/blocks/analytics/usage-card.js +1 -1
- package/dist/blocks/analytics.js +326 -307
- package/dist/blocks/analytics.js.map +1 -1
- package/dist/blocks/collaboration.js +1 -1
- package/dist/blocks/commerce/receipt.js +1 -1
- package/dist/blocks/commerce.js +1247 -1169
- package/dist/blocks/commerce.js.map +1 -1
- package/dist/blocks/data-display.js +2 -2
- package/dist/blocks/onboarding.js +6 -6
- package/dist/blocks/onboarding.js.map +1 -1
- package/dist/blocks/planning.js +11 -11
- package/dist/blocks/timelines.js +1 -1
- package/dist/{breadcrumbs-C-oqs1sQ.js → breadcrumbs-J-K2kl4c.js} +6 -6
- package/dist/{breadcrumbs-C-oqs1sQ.js.map → breadcrumbs-J-K2kl4c.js.map} +1 -1
- package/dist/{button-DVzspB_G.js → button-S2Cubiiz.js} +3 -3
- package/dist/button-S2Cubiiz.js.map +1 -0
- package/dist/{buttons-DPZekJFu.js → buttons-BedGfygC.js} +16 -16
- package/dist/buttons-BedGfygC.js.map +1 -0
- package/dist/cards-rNX1M4Xn.js +69 -0
- package/dist/cards-rNX1M4Xn.js.map +1 -0
- package/dist/cascader-B1MiqkBq.js +439 -0
- package/dist/cascader-B1MiqkBq.js.map +1 -0
- package/dist/chart-Darg_0Kv.js +162 -0
- package/dist/chart-Darg_0Kv.js.map +1 -0
- package/dist/{checkbox-AWIhNhmo.js → checkbox-fflqmODR.js} +9 -5
- package/dist/checkbox-fflqmODR.js.map +1 -0
- package/dist/choice-inputs-zUgBZfE4.js +777 -0
- package/dist/choice-inputs-zUgBZfE4.js.map +1 -0
- package/dist/{code-block-DeneBJR_.js → code-block-BzmM9Eig.js} +9 -9
- package/dist/code-block-BzmM9Eig.js.map +1 -0
- package/dist/{collapsible-C-_l4hpy.js → collapsible-BkAI_XD4.js} +5 -5
- package/dist/{collapsible-C-_l4hpy.js.map → collapsible-BkAI_XD4.js.map} +1 -1
- package/dist/{collection-content-By56pLog.js → collection-content-gDh1v6O4.js} +3 -3
- package/dist/{collection-content-By56pLog.js.map → collection-content-gDh1v6O4.js.map} +1 -1
- package/dist/combobox-BEx0vJgF.js +362 -0
- package/dist/combobox-BEx0vJgF.js.map +1 -0
- package/dist/{combobox-Dxo2fAYQ.js → combobox-BwzoXFSG.js} +254 -247
- package/dist/combobox-BwzoXFSG.js.map +1 -0
- package/dist/{command-C25VMRII.js → command-CrlPIL6m.js} +12 -12
- package/dist/command-CrlPIL6m.js.map +1 -0
- package/dist/{comments-DD0DUPwJ.js → comments-Dmpp0YIc.js} +380 -379
- package/dist/comments-Dmpp0YIc.js.map +1 -0
- package/dist/components/base/action-menu/action-menu.d.ts +9 -1
- package/dist/components/base/buttons/button-group.recipes.d.ts +2 -2
- package/dist/components/base/cards/card.recipes.d.ts +16 -7
- package/dist/components/base/cards/partials/card-primitives.d.ts +9 -2
- package/dist/components/base/cards/partials/smart-card-header-row.d.ts +3 -1
- package/dist/components/base/cards/smart-card.types.d.ts +11 -7
- package/dist/components/base/cascader/cascader-panel.d.ts +76 -0
- package/dist/components/base/chart/chart.d.ts +6 -1
- package/dist/components/base/choice-inputs/checkbox.d.ts +7 -2
- package/dist/components/base/choice-inputs/choice-types.d.ts +1 -1
- package/dist/components/base/choice-inputs/switch-card.d.ts +7 -0
- package/dist/components/base/choice-inputs/toggle-field.d.ts +7 -0
- package/dist/components/base/combobox/index.d.ts +4 -2
- package/dist/components/base/date-pickers/datepicker.types.d.ts +7 -0
- package/dist/components/base/feedback/alert.d.ts +1 -1
- package/dist/components/base/forms/controlled-form-field.d.ts +6 -6
- package/dist/components/base/forms/form-field.d.ts +5 -3
- package/dist/components/base/forms/form-sizing.d.ts +7 -7
- package/dist/components/base/forms/index.d.ts +1 -0
- package/dist/components/base/forms/server-errors.d.ts +16 -0
- package/dist/components/base/forms/workflow.d.ts +11 -2
- package/dist/components/base/forms-numeric/coordinates-input.d.ts +4 -0
- package/dist/components/base/metadata-list/metadata-list.d.ts +3 -1
- package/dist/components/base/navigation/dropdown-menu.d.ts +1 -1
- package/dist/components/base/navigation/page-header/page-header-commands.d.ts +14 -7
- package/dist/components/base/navigation/page-header/page-header.d.ts +13 -4
- package/dist/components/base/popover/popover.d.ts +3 -3
- package/dist/components/base/popover/popover.recipes.d.ts +10 -6
- package/dist/components/base/sheet/sheet.d.ts +2 -0
- package/dist/components/base/sidebar/index.d.ts +1 -1
- package/dist/components/base/sidebar/sidebar.d.ts +27 -5
- package/dist/components/base/structure/composition.recipes.d.ts +17 -0
- package/dist/components/base/text-inputs/hooks/use-form-field-state.d.ts +7 -2
- package/dist/components/base/text-inputs/input.d.ts +4 -2
- package/dist/components/base/text-inputs/textarea.d.ts +4 -2
- package/dist/components/base/toaster/index.d.ts +1 -0
- package/dist/components/base/value-inputs/date-time-input.d.ts +2 -1
- package/dist/components/base/value-inputs/slider.d.ts +5 -1
- package/dist/components/base/value-inputs/tags-input.d.ts +5 -1
- package/dist/components/blocks/ai/ai-file-tree/types.d.ts +1 -1
- package/dist/components/blocks/ai/ai-tool-call/types.d.ts +3 -1
- package/dist/components/blocks/ai/ai.strings.d.ts +2 -0
- package/dist/components/blocks/analytics/metric-comparison/metric-comparison.d.ts +2 -0
- package/dist/components/blocks/analytics/usage-card/usage-card.strings.d.ts +2 -0
- package/dist/components/blocks/commerce/cart-summary/cart-summary.d.ts +1 -1
- package/dist/components/blocks/commerce/cart-summary/types.d.ts +3 -1
- package/dist/components/blocks/commerce/discount-stack/discount-stack.d.ts +1 -1
- package/dist/components/blocks/commerce/discount-stack/types.d.ts +3 -1
- package/dist/components/blocks/commerce/fulfillment-group/fulfillment-group.d.ts +1 -1
- package/dist/components/blocks/commerce/fulfillment-group/types.d.ts +11 -2
- package/dist/components/blocks/commerce/index.d.ts +7 -6
- package/dist/components/blocks/commerce/inventory-section/inventory-section.d.ts +1 -1
- package/dist/components/blocks/commerce/inventory-section/types.d.ts +7 -2
- package/dist/components/blocks/commerce/invoice-header/index.d.ts +2 -1
- package/dist/components/blocks/commerce/invoice-header/invoice-header.d.ts +1 -1
- package/dist/components/blocks/commerce/invoice-header/types.d.ts +20 -6
- package/dist/components/blocks/commerce/invoice-line-items/invoice-line-items.d.ts +1 -1
- package/dist/components/blocks/commerce/invoice-line-items/types.d.ts +24 -7
- package/dist/components/blocks/commerce/invoice-mini/index.d.ts +2 -1
- package/dist/components/blocks/commerce/invoice-mini/types.d.ts +7 -1
- package/dist/components/blocks/commerce/order-customer/order-customer.d.ts +1 -1
- package/dist/components/blocks/commerce/order-customer/types.d.ts +9 -1
- package/dist/components/blocks/commerce/refund-status/refund-status.d.ts +1 -1
- package/dist/components/blocks/commerce/refund-status/types.d.ts +3 -1
- package/dist/components/blocks/commerce/shipment-tracking/shipment-tracking.d.ts +1 -1
- package/dist/components/blocks/commerce/shipment-tracking/types.d.ts +3 -1
- package/dist/components/blocks/commerce/tax-breakdown/tax-breakdown.d.ts +1 -1
- package/dist/components/blocks/commerce/tax-breakdown/types.d.ts +3 -1
- package/dist/components/features/activities/activities.types.d.ts +8 -2
- package/dist/components/features/activities/partials/activity-marker.d.ts +7 -3
- package/dist/components/features/activities/partials/activity-row.d.ts +24 -0
- package/dist/components/features/event-calendar/colors.d.ts +2 -2
- package/dist/components/features/event-calendar/event-calendar.types.d.ts +4 -0
- package/dist/components/features/filters/facets/select-facet.d.ts +2 -1
- package/dist/components/features/filters/filters.strings.d.ts +4 -0
- package/dist/components/features/filters/filters.types.d.ts +3 -0
- package/dist/components/features/filters/partials/filter-editor-header.d.ts +16 -0
- package/dist/components/features/filters/partials/filter-popover-content.d.ts +1 -1
- package/dist/components/features/filters/partials/nested-filter-options.d.ts +21 -0
- package/dist/components/features/filters/partials/regular-filter-content.d.ts +2 -1
- package/dist/components/features/filters/utils/filter-utils.d.ts +21 -3
- package/dist/components/features/global-search/global-search.types.d.ts +2 -0
- package/dist/components/features/global-search/partials/global-search-input.d.ts +10 -0
- package/dist/components/features/global-search/partials/global-search-result-row.d.ts +7 -1
- package/dist/components/features/media-library/media-library.strings.d.ts +2 -0
- package/dist/components/features/media-library/media-library.types.d.ts +14 -4
- package/dist/components/features/media-library/partials/media-library-partials.d.ts +1 -1
- package/dist/components/features/products/components/product-options-matrix.d.ts +1 -1
- package/dist/components/features/products/components/product-variant-editor.d.ts +1 -1
- package/dist/components/features/products/components/product-variants-manager.d.ts +1 -1
- package/dist/components/features/products/products.strings.d.ts +9 -1
- package/dist/components/features/products/products.types.d.ts +43 -6
- package/dist/components/features/resource/resource.d.ts +5 -1
- package/dist/components/features/resource/resource.types.d.ts +12 -1
- package/dist/components/features/rich-text-editor/partials/image-uploads.d.ts +1 -1
- package/dist/components/features/rich-text-editor/rich-text-editor.recipes.d.ts +12 -2
- package/dist/components/features/table/partials/resource-cell.d.ts +22 -5
- package/dist/components/features/table/table.types.d.ts +1 -1
- package/dist/components/layout/app-shell/app-shell.types.d.ts +35 -6
- package/dist/components/layout/app-shell/index.d.ts +1 -1
- package/dist/components/layout/app-shell/shell-regions.d.ts +27 -0
- package/dist/components/layout/app-shell/sidebar-inset-layout.d.ts +1 -1
- package/dist/components/layout/app-shell/stacked-layout.d.ts +1 -1
- package/dist/components/layout/app-shell/topbar-sidebar-layout.d.ts +1 -1
- package/dist/components/layout/containers/two-column-layout.d.ts +2 -0
- package/dist/components/layout/header/header.recipes.d.ts +6 -0
- package/dist/components/layout/header/header.types.d.ts +6 -6
- package/dist/components/layout/navigation/section-nav/section-nav.d.ts +5 -0
- package/dist/components/layout/page/index.d.ts +2 -1
- package/dist/components/layout/page/page.d.ts +1 -0
- package/dist/components/layout/page/page.strings.d.ts +11 -0
- package/dist/components/layout/page/page.types.d.ts +69 -17
- package/dist/components/layout/page/partials/page-header.d.ts +1 -1
- package/dist/components/layout/settings/settings.d.ts +9 -2
- package/dist/components/layout/sidebar/app-sidebar.d.ts +1 -1
- package/dist/components/layout/sidebar/components/sidebar-grouped-navigation.d.ts +1 -1
- package/dist/components/layout/sidebar/components/sidebar-navigation.d.ts +1 -1
- package/dist/components/layout/sidebar/index.d.ts +2 -1
- package/dist/components/layout/sidebar/sidebar-navigation-rail.d.ts +36 -0
- package/dist/components/layout/sidebar/sidebar.context.d.ts +5 -7
- package/dist/components/layout/sidebar/sidebar.types.d.ts +48 -10
- package/dist/components/layout/sidebar/sidebar.utils.d.ts +9 -1
- package/dist/components/layout/workspace/workspace.types.d.ts +8 -1
- package/dist/components/typography/text.styles.d.ts +26 -1
- package/dist/components/ui/alert-dialog.d.ts +2 -2
- package/dist/components/ui/combobox.d.ts +1 -1
- package/dist/components/ui/dialog.d.ts +2 -2
- package/dist/components/ui/overlay-layer.d.ts +18 -0
- package/dist/components/ui/sheet.d.ts +5 -1
- package/dist/components/ui/sidebar-state.d.ts +82 -0
- package/dist/components/ui/sidebar.d.ts +5 -17
- package/dist/composition.recipes-COdiFhxB.js +19 -0
- package/dist/composition.recipes-COdiFhxB.js.map +1 -0
- package/dist/containers-CIxwbZt5.js +112 -0
- package/dist/containers-CIxwbZt5.js.map +1 -0
- package/dist/{control-group-recipes-DBXmfh2E.js → control-group-recipes-fMuFo0H7.js} +6 -6
- package/dist/control-group-recipes-fMuFo0H7.js.map +1 -0
- package/dist/{copyable-ClBuk_UK.js → copyable-DIznBqiT.js} +7 -7
- package/dist/{copyable-ClBuk_UK.js.map → copyable-DIznBqiT.js.map} +1 -1
- package/dist/{data-display-DT_khPl_.js → data-display-BdgCAw8T.js} +277 -285
- package/dist/data-display-BdgCAw8T.js.map +1 -0
- package/dist/{date-DCrsDTZc.js → date-Cq8ioE4o.js} +5 -5
- package/dist/{date-DCrsDTZc.js.map → date-Cq8ioE4o.js.map} +1 -1
- package/dist/{date-picker-B2K3ucWn.js → date-picker-RlIzKom_.js} +501 -480
- package/dist/date-picker-RlIzKom_.js.map +1 -0
- package/dist/date-pickers-DY-CpXS1.js +179 -0
- package/dist/date-pickers-DY-CpXS1.js.map +1 -0
- package/dist/{display-hAc1HjpI.js → display-KsZLw9Ov.js} +9 -9
- package/dist/{display-hAc1HjpI.js.map → display-KsZLw9Ov.js.map} +1 -1
- package/dist/dropdown-menu-CLs8Lihj.js +194 -0
- package/dist/dropdown-menu-CLs8Lihj.js.map +1 -0
- package/dist/features/activities.js +302 -253
- package/dist/features/activities.js.map +1 -1
- package/dist/features/ai-chat.js +15 -14
- package/dist/features/ai-chat.js.map +1 -1
- package/dist/features/appointment-calendar.js +222 -220
- package/dist/features/appointment-calendar.js.map +1 -1
- package/dist/features/async-preview.js +11 -10
- package/dist/features/async-preview.js.map +1 -1
- package/dist/features/combobox.js +1 -1
- package/dist/features/comments.js +1 -1
- package/dist/features/data-view.js +13 -13
- package/dist/features/data-view.js.map +1 -1
- package/dist/features/email-composer.js +249 -249
- package/dist/features/email-composer.js.map +1 -1
- package/dist/features/event-calendar.js +264 -269
- package/dist/features/event-calendar.js.map +1 -1
- package/dist/features/filters.js +1 -1
- package/dist/features/global-search.js +167 -138
- package/dist/features/global-search.js.map +1 -1
- package/dist/features/kanban.js +6 -7
- package/dist/features/kanban.js.map +1 -1
- package/dist/features/map.js +269 -260
- package/dist/features/map.js.map +1 -1
- package/dist/features/media-library.js +827 -777
- package/dist/features/media-library.js.map +1 -1
- package/dist/features/mentions.js +1 -1
- package/dist/features/overlays.js +1 -1
- package/dist/features/products.js +1246 -1169
- package/dist/features/products.js.map +1 -1
- package/dist/features/questionnaire.js +13 -13
- package/dist/features/questionnaire.js.map +1 -1
- package/dist/features/resource-assignment.js +8 -8
- package/dist/features/resource.js +127 -123
- package/dist/features/resource.js.map +1 -1
- package/dist/features/rich-text-editor.js +2 -2
- package/dist/features/schema-form.js +254 -253
- package/dist/features/schema-form.js.map +1 -1
- package/dist/features/suggestions.js +3 -3
- package/dist/features/sync.js +3 -3
- package/dist/features/table.js +1 -1
- package/dist/features/theme-tweaker.js +95 -96
- package/dist/features/theme-tweaker.js.map +1 -1
- package/dist/{feedback-BYIhtitP.js → feedback-Dm4izqFn.js} +81 -80
- package/dist/feedback-Dm4izqFn.js.map +1 -0
- package/dist/{field-affordance-recipes-DZhnIL_Y.js → field-affordance-recipes-DWcNcOjh.js} +4 -4
- package/dist/field-affordance-recipes-DWcNcOjh.js.map +1 -0
- package/dist/{filters-DJVAveHA.js → filters-DzgSJpMK.js} +693 -645
- package/dist/filters-DzgSJpMK.js.map +1 -0
- package/dist/{form-field-CwH9y77i.js → form-field-BriWAXyg.js} +14 -8
- package/dist/form-field-BriWAXyg.js.map +1 -0
- package/dist/{form-sizing-BdP_Mf5p.js → form-sizing-Bs2qFUeE.js} +4 -4
- package/dist/form-sizing-Bs2qFUeE.js.map +1 -0
- package/dist/forms-C0RGnJTe.js +216 -0
- package/dist/forms-C0RGnJTe.js.map +1 -0
- package/dist/{forms-numeric-B_jraJaQ.js → forms-numeric-DIhghX1Q.js} +295 -291
- package/dist/forms-numeric-DIhghX1Q.js.map +1 -0
- package/dist/{header-BSfIEWbI.js → header-DMMxG__r.js} +67 -63
- package/dist/header-DMMxG__r.js.map +1 -0
- package/dist/header.recipes-BigdJjw1.js +6 -0
- package/dist/header.recipes-BigdJjw1.js.map +1 -0
- package/dist/hooks/useFormErrors.d.ts +1 -1
- package/dist/{hooks-ClH9thn4.js → hooks-DB6CJ4MR.js} +26 -14
- package/dist/hooks-DB6CJ4MR.js.map +1 -0
- package/dist/{icon-badge-DYKIwvOV.js → icon-badge-DZF-YjQp.js} +4 -4
- package/dist/{icon-badge-DYKIwvOV.js.map → icon-badge-DZF-YjQp.js.map} +1 -1
- package/dist/index.js +4 -5
- package/dist/input-CvyDQlY7.js +289 -0
- package/dist/input-CvyDQlY7.js.map +1 -0
- package/dist/input-DMBwAZmr.js +21 -0
- package/dist/input-DMBwAZmr.js.map +1 -0
- package/dist/item-DjCcM18E.js +277 -0
- package/dist/item-DjCcM18E.js.map +1 -0
- package/dist/layout/app-shell.js +1 -1
- package/dist/layout/auth.js +1 -1
- package/dist/layout/containers.js +1 -1
- package/dist/layout/header.js +1 -1
- package/dist/layout/hooks.js +1 -1
- package/dist/layout/navigation.js +1 -1
- package/dist/layout/page.js +2 -2
- package/dist/layout/settings.js +1 -1
- package/dist/layout/sidebar.js +3 -3
- package/dist/layout/workspace.js +1 -1
- package/dist/layout.js +11 -11
- package/dist/lib/affordance-geometry.generated.d.ts +41 -35
- package/dist/lib/control-group-recipes.d.ts +5 -5
- package/dist/lib/field-affordance-recipes.d.ts +2 -2
- package/dist/lib/motion-recipes.d.ts +3 -0
- package/dist/lib/navigation-row-recipes.d.ts +7 -7
- package/dist/lib/overlay-anatomy-recipes.d.ts +3 -3
- package/dist/lib/portal-recipes.d.ts +3 -0
- package/dist/lib/token-merge.generated.d.ts +13 -10
- package/dist/lib/ui-provider/types.d.ts +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/map-demo-tile.svg +1 -1
- package/dist/{media-gallery-3zIVLMWH.js → media-gallery-C-vChPmE.js} +6 -6
- package/dist/{media-gallery-3zIVLMWH.js.map → media-gallery-C-vChPmE.js.map} +1 -1
- package/dist/{mentions-CGlEJ15c.js → mentions-0_4nWuI-.js} +10 -10
- package/dist/{mentions-CGlEJ15c.js.map → mentions-0_4nWuI-.js.map} +1 -1
- package/dist/{message-DZ_ruyUV.js → message-g8p7eVtN.js} +7 -7
- package/dist/message-g8p7eVtN.js.map +1 -0
- package/dist/metadata-list-C3MkU-Om.js +443 -0
- package/dist/metadata-list-C3MkU-Om.js.map +1 -0
- package/dist/{motion-recipes-ChBg4HBq.js → motion-recipes-DitYv6P2.js} +10 -2
- package/dist/motion-recipes-DitYv6P2.js.map +1 -0
- package/dist/navigation-C90-oQFq.js +255 -0
- package/dist/navigation-C90-oQFq.js.map +1 -0
- package/dist/{navigation-BzhHI3lo.js → navigation-DaRjthVk.js} +101 -82
- package/dist/navigation-DaRjthVk.js.map +1 -0
- package/dist/{navigation-row-recipes-BFLCk_Aq.js → navigation-row-recipes-BGVLvU_O.js} +9 -9
- package/dist/navigation-row-recipes-BGVLvU_O.js.map +1 -0
- package/dist/{number-DbV1Dija.js → number-CRU3kGuk.js} +5 -5
- package/dist/{number-DbV1Dija.js.map → number-CRU3kGuk.js.map} +1 -1
- package/dist/overflow-tab-bar-IVFVQFV6.js +172 -0
- package/dist/overflow-tab-bar-IVFVQFV6.js.map +1 -0
- package/dist/overlays-BSgCtM2v.js +1013 -0
- package/dist/overlays-BSgCtM2v.js.map +1 -0
- package/dist/page-DUUKDAjo.js +331 -0
- package/dist/page-DUUKDAjo.js.map +1 -0
- package/dist/page-header-commands-7P3sfE9u.js +193 -0
- package/dist/page-header-commands-7P3sfE9u.js.map +1 -0
- package/dist/{pagination-BL25hu2s.js → pagination-CgCjElfu.js} +7 -7
- package/dist/{pagination-BL25hu2s.js.map → pagination-CgCjElfu.js.map} +1 -1
- package/dist/popover-B85RenIl.js +201 -0
- package/dist/popover-B85RenIl.js.map +1 -0
- package/dist/{popover-menu-Cn9rUkdc.js → popover-menu-DlnQ2zlR.js} +7 -7
- package/dist/{popover-menu-Cn9rUkdc.js.map → popover-menu-DlnQ2zlR.js.map} +1 -1
- package/dist/{popover.recipes-D3j8R8Yp.js → popover.recipes-DdiEp0rd.js} +18 -11
- package/dist/popover.recipes-DdiEp0rd.js.map +1 -0
- package/dist/portal-recipes-BpsV_iRw.js +9 -0
- package/dist/portal-recipes-BpsV_iRw.js.map +1 -0
- package/dist/{primitives-BFK08r9M.js → primitives-ByWgGUgt.js} +6 -6
- package/dist/{primitives-BFK08r9M.js.map → primitives-ByWgGUgt.js.map} +1 -1
- package/dist/primitives.js +4 -4
- package/dist/{progress-B1VnCT0K.js → progress-BJhQP9WX.js} +9 -9
- package/dist/{progress-B1VnCT0K.js.map → progress-BJhQP9WX.js.map} +1 -1
- package/dist/{receipt-BVSOH3Xo.js → receipt-tOc7B3hw.js} +7 -7
- package/dist/receipt-tOc7B3hw.js.map +1 -0
- package/dist/{rich-text-GOUyKQ-s.js → rich-text-Dth5E882.js} +4 -4
- package/dist/{rich-text-GOUyKQ-s.js.map → rich-text-Dth5E882.js.map} +1 -1
- package/dist/{rich-text-editor-cRLC-eBK.js → rich-text-editor-C1fOjBTd.js} +429 -430
- package/dist/rich-text-editor-C1fOjBTd.js.map +1 -0
- package/dist/{rich-text-editor-toolbar-DfXg0-VC.js → rich-text-editor-toolbar-laT3tpBT.js} +33 -29
- package/dist/rich-text-editor-toolbar-laT3tpBT.js.map +1 -0
- package/dist/{scroll-area-DcI-M1UT.js → scroll-area-B0dB2cBi.js} +2 -2
- package/dist/{scroll-area-DcI-M1UT.js.map → scroll-area-B0dB2cBi.js.map} +1 -1
- package/dist/{separator-Bom7NsGO.js → separator-Bb17I4pu.js} +2 -2
- package/dist/{separator-Bom7NsGO.js.map → separator-Bb17I4pu.js.map} +1 -1
- package/dist/{separator-BDV-Y648.js → separator-Ct_WSWTJ.js} +3 -3
- package/dist/{separator-BDV-Y648.js.map → separator-Ct_WSWTJ.js.map} +1 -1
- package/dist/services/actions.js +1 -1
- package/dist/settings-Bar5wiSo.js +167 -0
- package/dist/settings-Bar5wiSo.js.map +1 -0
- package/dist/sheet-BGPERY55.js +250 -0
- package/dist/sheet-BGPERY55.js.map +1 -0
- package/dist/sidebar-D-JYMMbY.js +686 -0
- package/dist/sidebar-D-JYMMbY.js.map +1 -0
- package/dist/sidebar-f9gRWXIR.js +1001 -0
- package/dist/sidebar-f9gRWXIR.js.map +1 -0
- package/dist/skeleton-BapcJd9C.js +265 -0
- package/dist/skeleton-BapcJd9C.js.map +1 -0
- package/dist/smart-card-CW0hjetE.js +617 -0
- package/dist/smart-card-CW0hjetE.js.map +1 -0
- package/dist/{structure-BmisBK-3.js → structure-DuxKl954.js} +3 -3
- package/dist/{structure-BmisBK-3.js.map → structure-DuxKl954.js.map} +1 -1
- package/dist/{structure.recipes-EPz60cU8.js → structure.recipes-BB4-n58V.js} +2 -2
- package/dist/{structure.recipes-EPz60cU8.js.map → structure.recipes-BB4-n58V.js.map} +1 -1
- package/dist/style.css +1 -1
- package/dist/{table-DsfzoUia.js → table-B4TE7iOV.js} +3 -3
- package/dist/{table-DsfzoUia.js.map → table-B4TE7iOV.js.map} +1 -1
- package/dist/{table-BweFy_P9.js → table-CFOWY9pQ.js} +394 -388
- package/dist/table-CFOWY9pQ.js.map +1 -0
- package/dist/{tabs-CDocW5D1.js → tabs-e7ko9S2o.js} +11 -11
- package/dist/tabs-e7ko9S2o.js.map +1 -0
- package/dist/{text-inputs-f9Ia-aCi.js → text-inputs-B1culiSK.js} +107 -104
- package/dist/text-inputs-B1culiSK.js.map +1 -0
- package/dist/{text.styles-g4He6UIW.js → text.styles-B64My8RZ.js} +25 -10
- package/dist/text.styles-B64My8RZ.js.map +1 -0
- package/dist/theme.css +192 -149
- package/dist/{timelines-CwM_9IhD.js → timelines-D3Sl9ueq.js} +13 -12
- package/dist/timelines-D3Sl9ueq.js.map +1 -0
- package/dist/tooltip-8wz5S_Zr.js +113 -0
- package/dist/tooltip-8wz5S_Zr.js.map +1 -0
- package/dist/{tree-WnKQzwbq.js → tree-CzUJHnFs.js} +9 -9
- package/dist/{tree-WnKQzwbq.js.map → tree-CzUJHnFs.js.map} +1 -1
- package/dist/typography/rich-text.js +1 -1
- package/dist/typography-BQnine1k.js +117 -0
- package/dist/typography-BQnine1k.js.map +1 -0
- package/dist/typography.js +1 -1
- package/dist/ui-provider-C-74NVLc.js +178 -0
- package/dist/ui-provider-C-74NVLc.js.map +1 -0
- package/dist/ui-provider.js +2 -3
- package/dist/{upload-CXyxmQBP.js → upload-BOW6U2tI.js} +25 -24
- package/dist/upload-BOW6U2tI.js.map +1 -0
- package/dist/{upload-queue-Boscubn9.js → upload-queue-qUXn1ykN.js} +16 -14
- package/dist/upload-queue-qUXn1ykN.js.map +1 -0
- package/dist/{usage-card-BhO5eqkX.js → usage-card-BeSLY0i0.js} +145 -137
- package/dist/usage-card-BeSLY0i0.js.map +1 -0
- package/dist/{utils-BRhFDwuU.js → utils-B6kKb8jB.js} +303 -144
- package/dist/utils-B6kKb8jB.js.map +1 -0
- package/dist/value-inputs-skdVB2zh.js +980 -0
- package/dist/value-inputs-skdVB2zh.js.map +1 -0
- package/dist/{value-typography-BP8OG6h5.js → value-typography-uAmWUAL1.js} +2 -2
- package/dist/{value-typography-BP8OG6h5.js.map → value-typography-uAmWUAL1.js.map} +1 -1
- package/dist/workspace-DHeHv0qw.js +411 -0
- package/dist/workspace-DHeHv0qw.js.map +1 -0
- package/docs/consumer-skill/SKILL.md +15 -129
- package/docs/consumer-skill/agents/themelia-ui-designer.md +96 -0
- package/docs/consumer-skill/examples/app-layout.tsx +74 -13
- package/docs/consumer-skill/examples/authentication.tsx +77 -0
- package/docs/consumer-skill/examples/commerce-lines.tsx +271 -0
- package/docs/consumer-skill/examples/custom-composition.tsx +21 -0
- package/docs/consumer-skill/examples/detail.tsx +5 -4
- package/docs/consumer-skill/examples/edit.tsx +30 -38
- package/docs/consumer-skill/examples/editable-sections.tsx +38 -0
- package/docs/consumer-skill/examples/index-table.tsx +4 -4
- package/docs/consumer-skill/examples/manifest.json +88 -1
- package/docs/consumer-skill/examples/product-media.tsx +41 -0
- package/docs/consumer-skill/examples/product-parts.tsx +81 -0
- package/docs/consumer-skill/examples/rhf-bindings.tsx +86 -0
- package/docs/consumer-skill/examples/rhf-edit-page.tsx +141 -0
- package/docs/consumer-skill/examples/rhf-overlay-form.tsx +105 -0
- package/docs/consumer-skill/examples/rhf-transport.tsx +28 -0
- package/docs/consumer-skill/examples/token-domain-structure.tsx +68 -0
- package/docs/consumer-skill/references/agents-md.md +23 -11
- package/docs/consumer-skill/references/analytics.md +18 -1
- package/docs/consumer-skill/references/authentication.md +42 -0
- package/docs/consumer-skill/references/commerce-composition.md +97 -0
- package/docs/consumer-skill/references/component-contracts.json +325201 -0
- package/docs/consumer-skill/references/composition-mapping.md +106 -0
- package/docs/consumer-skill/references/composition.md +198 -46
- package/docs/consumer-skill/references/critique-rubric.md +98 -0
- package/docs/consumer-skill/references/custom-composition.md +261 -0
- package/docs/consumer-skill/references/data-reading.md +79 -0
- package/docs/consumer-skill/references/design-contract.md +43 -9
- package/docs/consumer-skill/references/discovery.md +109 -8
- package/docs/consumer-skill/references/domain-structures.md +124 -0
- package/docs/consumer-skill/references/installation.md +51 -36
- package/docs/consumer-skill/references/integration.md +41 -2
- package/docs/consumer-skill/references/product-composition.md +94 -0
- package/docs/consumer-skill/references/public-api.json +4390 -475
- package/docs/consumer-skill/references/review.md +47 -5
- package/docs/consumer-skill/references/rhf-workflows.md +93 -0
- package/docs/consumer-skill/references/screen-archetypes.md +34 -0
- package/docs/consumer-skill/references/screen-decisions.md +126 -0
- package/docs/consumer-skill/references/theming.md +25 -27
- package/docs/consumer-skill/references/tokens.json +20 -11
- package/docs/consumer-skill/references/view-craft.md +153 -0
- package/docs/consumer-skill/references/view-spec.md +73 -0
- package/docs/consumer-skill/references/workflows.md +9 -2
- package/docs/consumer-skill/scripts/composition-policy.mjs +39 -3
- package/docs/consumer-skill/scripts/composition-schema.d.mts +2 -0
- package/docs/consumer-skill/scripts/composition-schema.mjs +32 -0
- package/docs/consumer-skill/scripts/composition.mjs +254 -0
- package/docs/consumer-skill/scripts/discovery.mjs +96 -10
- package/docs/consumer-skill/scripts/inspect-component.mjs +11 -0
- package/docs/consumer-skill/scripts/inspect-tokens.mjs +11 -0
- package/docs/consumer-skill/scripts/inspection.mjs +193 -0
- package/docs/consumer-skill/scripts/map-composition.mjs +12 -0
- package/docs/consumer-skill/scripts/setup-skills.mjs +111 -0
- package/docs/consumer-skill/scripts/surface-policy.mjs +5 -5
- package/docs/consumer-skills/themelia-components/SKILL.md +31 -0
- package/docs/consumer-skills/themelia-composition/SKILL.md +34 -0
- package/docs/consumer-skills/themelia-design/SKILL.md +55 -0
- package/docs/consumer-skills/themelia-forms/SKILL.md +12 -0
- package/docs/consumer-skills/themelia-foundation/SKILL.md +15 -0
- package/docs/consumer-skills/themelia-tokenization/SKILL.md +42 -0
- package/package.json +4 -2
- package/templates/README.md +39 -0
- package/templates/admin-shell-template.tsx +382 -0
- package/templates/analytics-operations-template.tsx +376 -0
- package/templates/customers-template.tsx +509 -0
- package/templates/index.ts +29 -0
- package/templates/orders-template.tsx +1102 -0
- package/templates/products-template.tsx +834 -0
- package/templates/user-permissions-template.tsx +450 -0
- package/dist/accordion-Cjb6sx0G.js.map +0 -1
- package/dist/action-menu-CllU52Mm.js +0 -280
- package/dist/action-menu-CllU52Mm.js.map +0 -1
- package/dist/affordance-geometry.generated-tF36bREk.js.map +0 -1
- package/dist/ai-artifact-DvTwDVyL.js.map +0 -1
- package/dist/app-shell-C4FhvCqF.js +0 -236
- package/dist/app-shell-C4FhvCqF.js.map +0 -1
- package/dist/auth-BGua8ouh.js.map +0 -1
- package/dist/avatar-DAPlDvhJ.js.map +0 -1
- package/dist/base/cascader.js.map +0 -1
- package/dist/batch-action-bar-DnUJ21NQ.js.map +0 -1
- package/dist/button-DVzspB_G.js.map +0 -1
- package/dist/buttons-DPZekJFu.js.map +0 -1
- package/dist/cards-BaBZR-AU.js +0 -68
- package/dist/cards-BaBZR-AU.js.map +0 -1
- package/dist/chart-ZOYyK2xG.js +0 -155
- package/dist/chart-ZOYyK2xG.js.map +0 -1
- package/dist/checkbox-AWIhNhmo.js.map +0 -1
- package/dist/choice-inputs-CNHvARCJ.js +0 -770
- package/dist/choice-inputs-CNHvARCJ.js.map +0 -1
- package/dist/code-block-DeneBJR_.js.map +0 -1
- package/dist/combobox-DaHESuiL.js +0 -355
- package/dist/combobox-DaHESuiL.js.map +0 -1
- package/dist/combobox-Dxo2fAYQ.js.map +0 -1
- package/dist/command-C25VMRII.js.map +0 -1
- package/dist/comments-DD0DUPwJ.js.map +0 -1
- package/dist/containers-Mu1LMGV1.js +0 -103
- package/dist/containers-Mu1LMGV1.js.map +0 -1
- package/dist/control-group-recipes-DBXmfh2E.js.map +0 -1
- package/dist/data-display-DT_khPl_.js.map +0 -1
- package/dist/date-picker-B2K3ucWn.js.map +0 -1
- package/dist/date-pickers-Ds8gLaoP.js +0 -175
- package/dist/date-pickers-Ds8gLaoP.js.map +0 -1
- package/dist/dropdown-menu-Cl4X7L5S.js +0 -193
- package/dist/dropdown-menu-Cl4X7L5S.js.map +0 -1
- package/dist/feedback-BYIhtitP.js.map +0 -1
- package/dist/field-affordance-recipes-DZhnIL_Y.js.map +0 -1
- package/dist/filters-DJVAveHA.js.map +0 -1
- package/dist/form-field-CwH9y77i.js.map +0 -1
- package/dist/form-sizing-BdP_Mf5p.js.map +0 -1
- package/dist/forms-B9G_xwzi.js +0 -194
- package/dist/forms-B9G_xwzi.js.map +0 -1
- package/dist/forms-numeric-B_jraJaQ.js.map +0 -1
- package/dist/header-BSfIEWbI.js.map +0 -1
- package/dist/hooks-ClH9thn4.js.map +0 -1
- package/dist/input-CZw8iU99.js +0 -21
- package/dist/input-CZw8iU99.js.map +0 -1
- package/dist/input-DQdEd0YD.js +0 -263
- package/dist/input-DQdEd0YD.js.map +0 -1
- package/dist/item-K5_ghvze.js +0 -275
- package/dist/item-K5_ghvze.js.map +0 -1
- package/dist/message-DZ_ruyUV.js.map +0 -1
- package/dist/metadata-list-8N16ZMW_.js +0 -405
- package/dist/metadata-list-8N16ZMW_.js.map +0 -1
- package/dist/motion-recipes-ChBg4HBq.js.map +0 -1
- package/dist/navigation-Bnotn4AQ.js +0 -145
- package/dist/navigation-Bnotn4AQ.js.map +0 -1
- package/dist/navigation-BzhHI3lo.js.map +0 -1
- package/dist/navigation-row-recipes-BFLCk_Aq.js.map +0 -1
- package/dist/overflow-tab-bar-CWY7Nogn.js +0 -282
- package/dist/overflow-tab-bar-CWY7Nogn.js.map +0 -1
- package/dist/overlays-tMkF-VAN.js +0 -1003
- package/dist/overlays-tMkF-VAN.js.map +0 -1
- package/dist/page-CL9YeH_V.js +0 -224
- package/dist/page-CL9YeH_V.js.map +0 -1
- package/dist/page-header-commands-DOb6WsfD.js +0 -126
- package/dist/page-header-commands-DOb6WsfD.js.map +0 -1
- package/dist/popover-gnTOhbFM.js +0 -198
- package/dist/popover-gnTOhbFM.js.map +0 -1
- package/dist/popover.recipes-D3j8R8Yp.js.map +0 -1
- package/dist/receipt-BVSOH3Xo.js.map +0 -1
- package/dist/rich-text-editor-cRLC-eBK.js.map +0 -1
- package/dist/rich-text-editor-toolbar-DfXg0-VC.js.map +0 -1
- package/dist/settings-ybnjVwbd.js +0 -171
- package/dist/settings-ybnjVwbd.js.map +0 -1
- package/dist/sheet-ijlsjq-n.js +0 -213
- package/dist/sheet-ijlsjq-n.js.map +0 -1
- package/dist/sidebar-Db6gkh3U.js +0 -619
- package/dist/sidebar-Db6gkh3U.js.map +0 -1
- package/dist/sidebar-DkTO4VTO.js +0 -512
- package/dist/sidebar-DkTO4VTO.js.map +0 -1
- package/dist/skeleton-Byjnt7qr.js +0 -264
- package/dist/skeleton-Byjnt7qr.js.map +0 -1
- package/dist/smart-card-DiC5aac3.js +0 -604
- package/dist/smart-card-DiC5aac3.js.map +0 -1
- package/dist/table-BweFy_P9.js.map +0 -1
- package/dist/tabs-CDocW5D1.js.map +0 -1
- package/dist/text-inputs-f9Ia-aCi.js.map +0 -1
- package/dist/text.styles-g4He6UIW.js.map +0 -1
- package/dist/theme-scope-BJ6eE2xt.js +0 -50
- package/dist/theme-scope-BJ6eE2xt.js.map +0 -1
- package/dist/timelines-CwM_9IhD.js.map +0 -1
- package/dist/tooltip-yiRJUFjp.js +0 -111
- package/dist/tooltip-yiRJUFjp.js.map +0 -1
- package/dist/typography-UTnveOEy.js +0 -117
- package/dist/typography-UTnveOEy.js.map +0 -1
- package/dist/ui-provider-C_U0Xma4.js +0 -136
- package/dist/ui-provider-C_U0Xma4.js.map +0 -1
- package/dist/upload-CXyxmQBP.js.map +0 -1
- package/dist/upload-queue-Boscubn9.js.map +0 -1
- package/dist/usage-card-BhO5eqkX.js.map +0 -1
- package/dist/use-mobile-vaLKwgyf.js +0 -15
- package/dist/use-mobile-vaLKwgyf.js.map +0 -1
- package/dist/utils-BRhFDwuU.js.map +0 -1
- package/dist/value-inputs-TaX4OjNk.js +0 -963
- package/dist/value-inputs-TaX4OjNk.js.map +0 -1
- package/dist/workspace-B-OEm3Kf.js +0 -408
- package/dist/workspace-B-OEm3Kf.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appointment-calendar.js","names":["_Fragment","useFormattingConfig","useDatesConfig","cn","Button","Text","Heading","focusRecipes","Stack","toneRecipes","dotRecipes","AlertDescription","AlertAction","Card","AlertTitle","ErrorState","ActionMenu","Skeleton","interactionRecipes","formatInitials","AvatarFallback","Avatar","AvatarImage","Badge","Select","VisuallyHidden","ScrollArea","ItemDescription","ItemActions","ItemContent","Item","ItemTitle","TabsTrigger","TabsList","Tabs","EmptyState","Fragment$1","defaultAppointmentCalendarStrings","count","staffName","time","start","end","date","title","CHART_SERIES","appointmentCategoryColorClasses","categoryColor","index","categories","category","id","startOfDay","addDays","days","isSameDay","a","b","addMonths","target","months","lastDay","startOfWeek","day","weekStartsOn","weekDays","first","monthGrid","week","occursOn","dayStart","dayEnd","appointment","appointmentsOn","appointments","filterAppointments","staffId","findConflicts","byStaff","list","conflicts","sorted","group","groupEnd","flush","conflictingIds","conflict","staffFrom","seen","formatTime","locale","hour12","options","personName","person","STATUS_TONE","AppointmentRow","useId","client","staff","context","hasActions","labelledBy","openRef","useRef","actionsHadFocus","useLayoutEffect","open","event","AppointmentAgenda","groups","total","sum","dayFormat","grouped","contextFor","actions","appointmentActions","action","strings","onAppointmentClick","items","renderAppointment","body","loading","error","isValidElement","heading","MAX_DOTS","AppointmentMonth","focused","setFocused","useState","selected","gridRef","focusOnRender","today","useMemo","visibleMonth","useEffect","onVisibleMonthChange","weeks","monthFormat","weekdayFormat","monthOptions","month","yearOptions","years","min","max","moveTo","select","onSelect","changeMonth","next","ChevronLeft","value","ChevronRight","move","dayAppointments","dayCategories","isSelected","isFocused","outside","useControllable","local","setLocal","fallback","onChange","AppointmentCalendar","staffProp","dateProp","viewProp","categoryProp","staffIdProp","weekStartsOnProp","stringsProp","useStrings","dates","setDate","defaultDate","onDateChange","view","setView","defaultView","onViewChange","setCategory","defaultCategory","onCategoryChange","setStaffId","defaultStaffId","onStaffChange","dismissed","setDismissed","setVisibleMonth","visible","range","edges","reportedRange","key","onRangeChange","inRange","conflictIds","visibleConflicts","booked","conflictKey","showAlert","headingFormat","rangeFormat","dismissConflicts","onConflictsDismiss","shown","className","option","onCreateAppointment","Plus","Alert","TriangleAlert"],"sources":["../../src/components/features/appointment-calendar/appointment-calendar.types.ts","../../src/components/features/appointment-calendar/appointment-calendar.utils.ts","../../src/components/features/appointment-calendar/partials/appointment-agenda.tsx","../../src/components/features/appointment-calendar/partials/appointment-month.tsx","../../src/components/features/appointment-calendar/appointment-calendar.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport type { ActionMenuAction } from '../../base/action-menu';\nimport type { BadgeTone } from '../../base/badge';\nimport type { StringsProp } from '../../../lib/strings';\n\n/** Where an appointment stands. Conflicts are derived, never a status. */\nexport type AppointmentStatus = 'confirmed' | 'pending' | 'completed' | 'cancelled' | 'noShow';\n\n/** The day agenda or the seven-day week agenda beside the month. */\nexport type AppointmentCalendarView = 'day' | 'week';\n\n/**\n * Categorical colour for a service category. Categories are kinds, not\n * statuses, so they draw from the chart series palette and never from the\n * success, warning or destructive tones that status chips own.\n */\nexport type AppointmentCategoryColor = 'chart-1' | 'chart-2' | 'chart-3' | 'chart-4' | 'chart-5';\n\n/** A service category: its label, filter chip and marker colour. */\nexport interface AppointmentCategory {\n\t/** Stable identity, referenced by `Appointment.category`. */\n\tid: string;\n\t/** Chip and legend label. */\n\tlabel: string;\n\t/** Marker colour. Defaults to the chart series by the category's position. */\n\tcolor?: AppointmentCategoryColor;\n}\n\n/** A person on an appointment: the staff member who delivers it, or the client. */\nexport interface AppointmentPerson {\n\t/** Stable identity. Staff overlap is detected by this id. */\n\tid: string;\n\t/** Display name. */\n\tname: string;\n\t/** Portrait. Initials stand in without one, or when it fails to load. */\n\tavatarUrl?: string;\n}\n\n/** One booked slot. The calendar formats it; it never fetches or saves. */\nexport interface Appointment {\n\t/** Stable identity. */\n\tid: string;\n\t/** The service: \"Cut and blow-dry\". */\n\ttitle: string;\n\t/** Start of the slot. */\n\tstart: Date;\n\t/** End of the slot; later than `start`. */\n\tend: Date;\n\t/** Category id, matching an `AppointmentCategory`. */\n\tcategory: string;\n\t/** Booking state. Cancelled appointments are listed but never conflict. */\n\tstatus: AppointmentStatus;\n\t/** Who the appointment is for, shown after the time. */\n\tclient?: AppointmentPerson | string;\n\t/** Who delivers it. Two overlapping appointments for one staff member conflict. */\n\tstaff?: AppointmentPerson;\n}\n\n/** The days on screen: the month grid and the agenda. `end` is exclusive (midnight after the last day). */\nexport interface AppointmentDateRange {\n\tstart: Date;\n\tend: Date;\n}\n\n/** Overlapping appointments for one staff member. */\nexport interface AppointmentConflict<T extends Appointment = Appointment> {\n\t/** The double-booked staff member. */\n\tstaff: AppointmentPerson;\n\t/** The appointments that overlap, earliest first. */\n\tappointments: T[];\n\t/** When the overlap begins. */\n\tstart: Date;\n}\n\nexport interface AppointmentCalendarStrings {\n\t/** Booked count beside the title: \"8 booked\". */\n\tformatBooked: (count: number) => string;\n\t/** Conflict count beside the title: \"2 conflicts\". */\n\tformatConflicts: (count: number) => string;\n\t/** Accessible name of the Day/Week switch. */\n\tviewLabel: string;\n\tday: string;\n\tweek: string;\n\t/** Accessible name of the staff filter. */\n\tstaffLabel: string;\n\t/** The staff filter's \"everyone\" option. */\n\tallStaff: string;\n\t/** Primary command. */\n\tnewAppointment: string;\n\t/** Conflict alert title. */\n\tconflictTitle: string;\n\t/** One overlapping-booking sentence per double-booked staff member. */\n\tformatConflict: (staffName: string, count: number, time: string) => string;\n\t/** Hides the conflict alert. */\n\tdismiss: string;\n\tpreviousMonth: string;\n\tnextMonth: string;\n\t/** Accessible name of the month select. */\n\tmonthLabel: string;\n\t/** Accessible name of the year select. */\n\tyearLabel: string;\n\t/** Accessible name of the category filter. */\n\tcategoriesLabel: string;\n\t/** The category filter's \"every category\" chip. */\n\tallCategories: string;\n\t/** Count beside the agenda heading: \"8 appointments\". */\n\tformatCount: (count: number) => string;\n\t/** A slot: \"9 AM to 10 AM\". Receives already formatted times. */\n\tformatTimeRange: (start: string, end: string) => string;\n\t/** Accessible day label in the month: \"Tuesday, June 9, 3 appointments\". */\n\tformatDayLabel: (date: string, count: number) => string;\n\t/** Agenda heading for the week view: \"June 8 to 14\". */\n\tformatWeekRange: (start: string, end: string) => string;\n\t/** Status chip words. */\n\tstatus: Record<AppointmentStatus, string>;\n\t/** Chip shown instead of the status when an appointment overlaps another. */\n\tconflict: string;\n\t/** Agenda copy when nothing matches the day or week. */\n\tempty: string;\n\t/** Loading copy for assistive technology. */\n\tloading: string;\n\t/** Default error state title. */\n\terrorTitle: string;\n\t/** Default error state description, when `error` carries no message. */\n\terrorDescription: string;\n\t/** Retry command in the default error state. */\n\tretry: string;\n\t/** Accessible name of an appointment's actions menu: \"Actions for Balayage\". */\n\tformatActionsLabel: (title: string) => string;\n}\n\nexport const defaultAppointmentCalendarStrings: AppointmentCalendarStrings = {\n\tformatBooked: (count) => `${count} booked`,\n\tformatConflicts: (count) => (count === 1 ? '1 conflict' : `${count} conflicts`),\n\tviewLabel: 'View',\n\tday: 'Day',\n\tweek: 'Week',\n\tstaffLabel: 'Staff',\n\tallStaff: 'All staff',\n\tnewAppointment: 'New appointment',\n\tconflictTitle: 'Double-booked',\n\tformatConflict: (staffName, count, time) => `${staffName} has ${count} overlapping bookings at ${time}.`,\n\tdismiss: 'Dismiss',\n\tpreviousMonth: 'Previous month',\n\tnextMonth: 'Next month',\n\tmonthLabel: 'Month',\n\tyearLabel: 'Year',\n\tcategoriesLabel: 'Categories',\n\tallCategories: 'All',\n\tformatCount: (count) => (count === 1 ? '1 appointment' : `${count} appointments`),\n\tformatTimeRange: (start, end) => `${start} to ${end}`,\n\tformatDayLabel: (date, count) => (count === 0 ? date : `${date}, ${count === 1 ? '1 appointment' : `${count} appointments`}`),\n\tformatWeekRange: (start, end) => `${start} to ${end}`,\n\tstatus: { confirmed: 'Confirmed', pending: 'Pending', completed: 'Completed', cancelled: 'Cancelled', noShow: 'No-show' },\n\tconflict: 'Conflict',\n\tempty: 'No appointments',\n\tloading: 'Loading appointments',\n\terrorTitle: 'Appointments unavailable',\n\terrorDescription: 'The appointments could not be loaded.',\n\tretry: 'Retry',\n\tformatActionsLabel: (title) => `Actions for ${title}`,\n};\n\n/** What the calendar has worked out for one appointment, handed to `renderAppointment`. */\nexport interface AppointmentRenderContext {\n\t/** The appointment's category, when one matches. */\n\tcategory?: AppointmentCategory;\n\t/** The category's marker class (`bg-chart-N`), for a stripe or dot of your own. */\n\tcategoryColorClass: string;\n\t/** Whether it overlaps another booking for the same staff member. */\n\tconflict: boolean;\n\t/** The status chip's word, or the conflict word when it overlaps. */\n\tstatusLabel: string;\n\t/** The status chip's tone: destructive for a conflict, otherwise the status tone. */\n\tstatusTone: BadgeTone;\n\t/** The formatted slot: \"09:00 to 10:00\". */\n\ttime: string;\n\t/** Opens it through `onAppointmentClick`. Undefined when rows are not interactive. */\n\topen?: () => void;\n\t/** The visible commands `appointmentActions` returned for it. */\n\tactions: readonly ActionMenuAction[];\n\t/** The built-in actions menu for those commands, or null when there are none. */\n\tactionsMenu: ReactNode;\n\t/** The built-in row, to wrap or extend instead of replacing. */\n\tdefaultRender: () => ReactNode;\n}\n\n/**\n * Props for `AppointmentCalendar`. `T` is the app's own appointment type: extra\n * fields such as a price or notes come back, typed, in every callback.\n */\nexport interface AppointmentCalendarProps<T extends Appointment = Appointment> {\n\t/** Appointments to place. The calendar filters and formats; it never fetches. */\n\tappointments: T[];\n\t/** Service categories: filter chips, markers and day dots. */\n\tcategories: AppointmentCategory[];\n\t/** Staff offered by the staff filter. Defaults to the staff found on appointments. */\n\tstaff?: AppointmentPerson[];\n\t/** Heading above the calendar: the location or calendar name. */\n\ttitle?: ReactNode;\n\t/** Selected day. Controlled with `onDateChange`. */\n\tdate?: Date;\n\t/** Selected day for uncontrolled use. Defaults to today. */\n\tdefaultDate?: Date;\n\t/** Fired when a day is chosen or the month moves. */\n\tonDateChange?: (date: Date) => void;\n\t/** Day or week agenda. Controlled with `onViewChange`. */\n\tview?: AppointmentCalendarView;\n\t/** View for uncontrolled use. Defaults to `day`. */\n\tdefaultView?: AppointmentCalendarView;\n\t/** Fired when the Day/Week switch changes. */\n\tonViewChange?: (view: AppointmentCalendarView) => void;\n\t/** Category filter: a category id, or `all`. Controlled with `onCategoryChange`. */\n\tcategory?: string;\n\t/** Category filter for uncontrolled use. Defaults to `all`. */\n\tdefaultCategory?: string;\n\t/** Fired when a category chip is chosen. */\n\tonCategoryChange?: (category: string) => void;\n\t/** Staff filter: a staff id, or `all`. Controlled with `onStaffChange`. */\n\tstaffId?: string;\n\t/** Staff filter for uncontrolled use. Defaults to `all`. */\n\tdefaultStaffId?: string;\n\t/** Fired when the staff filter changes. */\n\tonStaffChange?: (staffId: string) => void;\n\t/** Fired when an appointment is activated. Without it, rows are not interactive. */\n\tonAppointmentClick?: (appointment: T) => void;\n\t/**\n\t * Commands for one appointment, such as confirm, reschedule or cancel,\n\t * offered in a menu at the end of its row. Return an empty list for none.\n\t */\n\tappointmentActions?: (appointment: T) => readonly ActionMenuAction[];\n\t/**\n\t * Renders one appointment in the agenda instead of the built-in row. The\n\t * context carries its category colour, conflict, time, `open`, its actions\n\t * and a ready actions menu, and `defaultRender` for the built-in row.\n\t */\n\trenderAppointment?: (appointment: T, context: AppointmentRenderContext) => ReactNode;\n\t/**\n\t * Fired with the days on screen, the month grid and the agenda together, once\n\t * on mount and whenever they change. Load appointments for this range.\n\t */\n\tonRangeChange?: (range: AppointmentDateRange) => void;\n\t/** Shows the primary \"New appointment\" command; receives the selected day. */\n\tonCreateAppointment?: (date: Date) => void;\n\t/** Fired when the conflict alert is dismissed, with the conflicts it showed. */\n\tonConflictsDismiss?: (conflicts: AppointmentConflict<T>[]) => void;\n\t/** Shows the loading state in the agenda. */\n\tloading?: boolean;\n\t/**\n\t * Shows the error state in the agenda. A string or Error becomes its\n\t * description; any other element replaces the default state.\n\t */\n\terror?: ReactNode | Error;\n\t/** Adds Retry to the default error state. */\n\tonRetry?: () => void;\n\t/** First column of the month and first day of the week. Defaults to the provider, then Sunday. */\n\tweekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;\n\t/** Overrides this calendar's own copy. */\n\tstrings?: StringsProp<AppointmentCalendarStrings>;\n\t/** Merged onto the root. */\n\tclassName?: string;\n}\n","/**\n * Pure helpers for the appointment calendar: day arithmetic, filtering,\n * conflict detection and time formatting. No React, so they are testable and\n * reusable by an application that pre-computes its own view.\n */\nimport type {\n\tAppointment,\n\tAppointmentCategory,\n\tAppointmentCategoryColor,\n\tAppointmentConflict,\n\tAppointmentPerson,\n} from './appointment-calendar.types';\n\nconst CHART_SERIES: AppointmentCategoryColor[] = ['chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5'];\n\n/** Marker colour classes per chart series. Literal so Tailwind generates them. */\nexport const appointmentCategoryColorClasses: Record<AppointmentCategoryColor, string> = {\n\t'chart-1': 'bg-chart-1',\n\t'chart-2': 'bg-chart-2',\n\t'chart-3': 'bg-chart-3',\n\t'chart-4': 'bg-chart-4',\n\t'chart-5': 'bg-chart-5',\n};\n\n/** A category's colour: its own, or the chart series at its position. */\nexport function categoryColor(categories: AppointmentCategory[], id: string): AppointmentCategoryColor {\n\tconst index = categories.findIndex((category) => category.id === id);\n\tif (index < 0) return 'chart-1';\n\treturn categories[index]?.color ?? CHART_SERIES[index % CHART_SERIES.length] ?? 'chart-1';\n}\n\nexport function startOfDay(date: Date): Date {\n\treturn new Date(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\nexport function addDays(date: Date, days: number): Date {\n\treturn new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);\n}\n\nexport function isSameDay(a: Date, b: Date): boolean {\n\treturn a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\n/** The same day of the month in another month, clamped to that month's length. */\nexport function addMonths(date: Date, months: number): Date {\n\tconst target = new Date(date.getFullYear(), date.getMonth() + months, 1);\n\tconst lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n\treturn new Date(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), lastDay));\n}\n\nexport function startOfWeek(date: Date, weekStartsOn: number): Date {\n\tconst day = startOfDay(date);\n\treturn addDays(day, -((day.getDay() - weekStartsOn + 7) % 7));\n}\n\n/** The seven days of the week that holds `date`. */\nexport function weekDays(date: Date, weekStartsOn: number): Date[] {\n\tconst first = startOfWeek(date, weekStartsOn);\n\treturn Array.from({ length: 7 }, (_, index) => addDays(first, index));\n}\n\n/** Six full weeks covering the month of `date`, so the grid never changes height. */\nexport function monthGrid(date: Date, weekStartsOn: number): Date[][] {\n\tconst first = startOfWeek(new Date(date.getFullYear(), date.getMonth(), 1), weekStartsOn);\n\treturn Array.from({ length: 6 }, (_, week) => Array.from({ length: 7 }, (_, day) => addDays(first, week * 7 + day)));\n}\n\n/** Whether an appointment touches a day (it may run past midnight). */\nexport function occursOn(appointment: Appointment, day: Date): boolean {\n\tconst dayStart = startOfDay(day).getTime();\n\tconst dayEnd = addDays(day, 1).getTime();\n\treturn appointment.start.getTime() < dayEnd && appointment.end.getTime() > dayStart;\n}\n\nexport function appointmentsOn<T extends Appointment>(appointments: T[], day: Date): T[] {\n\treturn appointments\n\t\t.filter((appointment) => occursOn(appointment, day))\n\t\t.sort((a, b) => a.start.getTime() - b.start.getTime() || a.end.getTime() - b.end.getTime());\n}\n\n/** Applies the category and staff filters; `all` keeps everything. */\nexport function filterAppointments<T extends Appointment>(appointments: T[], category: string, staffId: string): T[] {\n\treturn appointments.filter((appointment) =>\n\t\t(category === 'all' || appointment.category === category) &&\n\t\t(staffId === 'all' || appointment.staff?.id === staffId),\n\t);\n}\n\n/**\n * Overlapping appointments per staff member. Two appointments conflict when\n * the same staff member is booked for both and their times overlap; touching\n * ends (10:00 to 10:00) do not overlap, and cancelled appointments never conflict.\n */\nexport function findConflicts<T extends Appointment>(appointments: T[]): AppointmentConflict<T>[] {\n\tconst byStaff = new Map<string, T[]>();\n\tfor (const appointment of appointments) {\n\t\tif (!appointment.staff || appointment.status === 'cancelled') continue;\n\t\tconst list = byStaff.get(appointment.staff.id) ?? [];\n\t\tlist.push(appointment);\n\t\tbyStaff.set(appointment.staff.id, list);\n\t}\n\tconst conflicts: AppointmentConflict<T>[] = [];\n\tfor (const list of byStaff.values()) {\n\t\tconst sorted = [...list].sort((a, b) => a.start.getTime() - b.start.getTime());\n\t\tlet group: T[] = [];\n\t\tlet groupEnd = -Infinity;\n\t\tconst flush = () => {\n\t\t\tconst first = group[0];\n\t\t\tif (group.length > 1 && first?.staff) conflicts.push({ staff: first.staff, appointments: group, start: first.start });\n\t\t};\n\t\tfor (const appointment of sorted) {\n\t\t\tif (appointment.start.getTime() < groupEnd) {\n\t\t\t\tgroup.push(appointment);\n\t\t\t\tgroupEnd = Math.max(groupEnd, appointment.end.getTime());\n\t\t\t} else {\n\t\t\t\tflush();\n\t\t\t\tgroup = [appointment];\n\t\t\t\tgroupEnd = appointment.end.getTime();\n\t\t\t}\n\t\t}\n\t\tflush();\n\t}\n\treturn conflicts.sort((a, b) => a.start.getTime() - b.start.getTime());\n}\n\n/** Ids of every appointment that takes part in a conflict. */\nexport function conflictingIds(conflicts: AppointmentConflict[]): Set<string> {\n\treturn new Set(conflicts.flatMap((conflict) => conflict.appointments.map((appointment) => appointment.id)));\n}\n\n/** Distinct staff found on appointments, in first-seen order. */\nexport function staffFrom(appointments: Appointment[]): AppointmentPerson[] {\n\tconst seen = new Map<string, AppointmentPerson>();\n\tfor (const appointment of appointments) if (appointment.staff && !seen.has(appointment.staff.id)) seen.set(appointment.staff.id, appointment.staff);\n\treturn [...seen.values()];\n}\n\n/**\n * \"9 AM\", or \"9:30 AM\" when the minutes matter. A 24-hour clock always keeps\n * its minutes (\"09:00\"), since a bare \"09\" does not read as a time.\n */\nexport function formatTime(date: Date, locale?: string): string {\n\tconst { hour12 } = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).resolvedOptions();\n\tif (!hour12) return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);\n\tconst options: Intl.DateTimeFormatOptions = date.getMinutes() === 0 ? { hour: 'numeric' } : { hour: 'numeric', minute: '2-digit' };\n\treturn new Intl.DateTimeFormat(locale, options).format(date);\n}\n\nexport function personName(person: AppointmentPerson | string | undefined): string | undefined {\n\treturn typeof person === 'string' ? person : person?.name;\n}\n","/**\n * AppointmentAgenda — the list beside the month: one day's appointments, or\n * the selected week grouped by day. Each row shows its category stripe, the\n * service with its status chip (or the conflict chip when it overlaps another\n * booking for the same staff member), the time range and client, and the\n * staff member's avatar. A row opens only when the app can open it: a\n * transparent button stretched over the row takes the click, and the actions\n * menu sits above it, since a button cannot hold another. Private to the\n * appointment calendar.\n */\nimport { isValidElement, useId, useLayoutEffect, useRef, type ReactNode } from 'react';\n\nimport { ActionMenu, type ActionMenuAction } from '../../../base/action-menu';\nimport { Avatar, AvatarFallback, AvatarImage } from '../../../base/avatar';\nimport { Badge, type BadgeTone } from '../../../base/badge';\nimport { Card } from '../../../base/cards';\nimport { ScrollArea, VisuallyHidden } from '../../../base/display';\nimport { ErrorState } from '../../../base/feedback';\nimport { Item, ItemActions, ItemContent, ItemDescription, ItemTitle } from '../../../base/item';\nimport { Skeleton } from '../../../base/skeleton';\nimport { Stack } from '../../../base/structure';\nimport { formatInitials } from '../../../primitives';\nimport { Heading, Text } from '../../../typography';\nimport { EmptyState } from '../../../blocks/data-display';\nimport { focusRecipes } from '../../../../lib/focus-recipes';\nimport { interactionRecipes } from '../../../../lib/interaction-recipes';\nimport { toneRecipes } from '../../../../lib/tone-recipes';\nimport { cn } from '../../../../lib/utils';\n\nimport type {\n\tAppointment,\n\tAppointmentCalendarStrings,\n\tAppointmentCategory,\n\tAppointmentRenderContext,\n\tAppointmentStatus,\n} from '../appointment-calendar.types';\nimport {\n\tappointmentCategoryColorClasses,\n\tappointmentsOn,\n\tcategoryColor,\n\tformatTime,\n\tpersonName,\n} from '../appointment-calendar.utils';\n\n/** Status chip tones. Completed and cancelled are history, not a state to act on. */\nconst STATUS_TONE: Record<AppointmentStatus, BadgeTone> = {\n\tconfirmed: 'success',\n\tpending: 'warning',\n\tcompleted: 'neutral',\n\tcancelled: 'neutral',\n\tnoShow: 'destructive',\n};\n\nexport interface AppointmentAgendaProps {\n\t/** The days to list: one for the day view, seven for the week view. */\n\tdays: Date[];\n\t/** Appointments after the category and staff filters. */\n\tappointments: Appointment[];\n\tcategories: AppointmentCategory[];\n\t/** Ids of appointments that overlap another booking for the same staff member. */\n\tconflicts: Set<string>;\n\theading: string;\n\tloading: boolean;\n\terror?: ReactNode | Error;\n\tonRetry?: () => void;\n\tlocale?: string;\n\tonAppointmentClick?: (appointment: Appointment) => void;\n\tappointmentActions?: (appointment: Appointment) => readonly ActionMenuAction[];\n\trenderAppointment?: (appointment: Appointment, context: AppointmentRenderContext) => ReactNode;\n\tstrings: AppointmentCalendarStrings;\n}\n\ntype RowContext = Omit<AppointmentRenderContext, 'defaultRender'>;\n\n/** The built-in row, drawn from the same context a custom row receives. */\nfunction AppointmentRow({ appointment, context }: { appointment: Appointment; context: RowContext }) {\n\tconst id = useId();\n\tconst client = personName(appointment.client);\n\tconst staff = appointment.staff;\n\tconst { open, conflict } = context;\n\tconst hasActions = context.actions.length > 0;\n\t// The open button is named by the row's own visible copy and the staff name,\n\t// one part per id so the title and its chip read as separate words.\n\tconst labelledBy = [`${id}-title`, `${id}-status`, `${id}-detail`, staff && `${id}-staff`].filter(Boolean).join(' ');\n\tconst openRef = useRef<HTMLButtonElement>(null);\n\tconst actionsHadFocus = useRef(false);\n\n\t// A command can remove the row's last action, and the menu trigger with it.\n\t// Focus then returns to the row's open button instead of falling to the page.\n\tuseLayoutEffect(() => {\n\t\tif (hasActions || !actionsHadFocus.current) return;\n\t\tactionsHadFocus.current = false;\n\t\tif (!document.activeElement || document.activeElement === document.body) openRef.current?.focus();\n\t}, [hasActions]);\n\n\treturn (\n\t\t<Item\n\t\t\tvariant=\"outline\"\n\t\t\tsize=\"sm\"\n\t\t\tpadding=\"default\"\n\t\t\tdata-status={appointment.status}\n\t\t\tdata-conflict={conflict ? '' : undefined}\n\t\t\tclassName={cn(\n\t\t\t\t'appointment-agenda--row relative w-full flex-nowrap',\n\t\t\t\t!!open && interactionRecipes.rowHover,\n\t\t\t\tconflict && cn(toneRecipes.destructive.wash, toneRecipes.destructive.edge),\n\t\t\t)}\n\t\t>\n\t\t\t{!!open && (\n\t\t\t\t<button\n\t\t\t\t\tref={openRef}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-labelledby={labelledBy}\n\t\t\t\t\tonClick={open}\n\t\t\t\t\tclassName={cn('appointment-agenda--open absolute inset-0 z-0 cursor-pointer rounded-inner focus-visible:outline-none', interactionRecipes.nativeButtonReset, focusRecipes.inset)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{/* The category stripe: a categorical mark, so it draws from the chart palette. */}\n\t\t\t<span aria-hidden=\"true\" className={cn('appointment-agenda--stripe w-1 shrink-0 self-stretch rounded-full', context.categoryColorClass)} />\n\t\t\t<ItemContent className=\"min-w-0\">\n\t\t\t\t<ItemTitle className=\"flex-wrap\">\n\t\t\t\t\t<Text type=\"inherit\" id={`${id}-title`} tag=\"span\" weight=\"medium\" className=\"truncate\">{appointment.title}</Text>\n\t\t\t\t\t<Badge id={`${id}-status`} tone={context.statusTone} size=\"sm\">\n\t\t\t\t\t\t{context.statusLabel}\n\t\t\t\t\t</Badge>\n\t\t\t\t</ItemTitle>\n\t\t\t\t<ItemDescription id={`${id}-detail`} clamp={1}>\n\t\t\t\t\t{client ? `${context.time} · ${client}` : context.time}\n\t\t\t\t</ItemDescription>\n\t\t\t</ItemContent>\n\t\t\t{(!!staff || hasActions) && (\n\t\t\t\t<ItemActions\n\t\t\t\t\t// React focus events bubble from the portaled menu, so this tracks the trigger and its menu together.\n\t\t\t\t\tonFocus={() => { actionsHadFocus.current = true; }}\n\t\t\t\t\tonBlur={(event) => {\n\t\t\t\t\t\tif (event.relatedTarget instanceof Node && !event.currentTarget.contains(event.relatedTarget)) actionsHadFocus.current = false;\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{!!staff && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<VisuallyHidden><span id={`${id}-staff`}>{staff.name}</span></VisuallyHidden>\n\t\t\t\t\t\t\t<Avatar size=\"sm\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t{!!staff.avatarUrl && <AvatarImage src={staff.avatarUrl} alt=\"\" />}\n\t\t\t\t\t\t\t\t<AvatarFallback>{formatInitials(staff.name)}</AvatarFallback>\n\t\t\t\t\t\t\t</Avatar>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t\t{context.actionsMenu}\n\t\t\t\t</ItemActions>\n\t\t\t)}\n\t\t</Item>\n\t);\n}\n\nexport function AppointmentAgenda({ days, appointments, categories, conflicts, heading, loading, error, onRetry, locale, onAppointmentClick, appointmentActions, renderAppointment, strings }: AppointmentAgendaProps) {\n\tconst groups = days.map((day) => ({ day, items: appointmentsOn(appointments, day) }));\n\tconst total = groups.reduce((sum, group) => sum + group.items.length, 0);\n\tconst dayFormat = new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric' });\n\tconst grouped = days.length > 1;\n\n\t// One context per appointment: the built-in row draws from it, and a custom\n\t// row receives the same values, so both stay consistent.\n\tconst contextFor = (appointment: Appointment): AppointmentRenderContext => {\n\t\tconst conflict = conflicts.has(appointment.id);\n\t\tconst actions = (appointmentActions?.(appointment) ?? []).filter((action) => action.visible !== false);\n\t\tconst context: RowContext = {\n\t\t\tcategory: categories.find((category) => category.id === appointment.category),\n\t\t\tcategoryColorClass: appointmentCategoryColorClasses[categoryColor(categories, appointment.category)],\n\t\t\tconflict,\n\t\t\tstatusLabel: conflict ? strings.conflict : strings.status[appointment.status],\n\t\t\tstatusTone: conflict ? 'destructive' : STATUS_TONE[appointment.status],\n\t\t\ttime: strings.formatTimeRange(formatTime(appointment.start, locale), formatTime(appointment.end, locale)),\n\t\t\topen: onAppointmentClick ? () => onAppointmentClick(appointment) : undefined,\n\t\t\tactions,\n\t\t\t// Above a stretched open button, so the menu takes its own clicks.\n\t\t\tactionsMenu: actions.length > 0 ? (\n\t\t\t\t<ActionMenu\n\t\t\t\t\tactions={actions}\n\t\t\t\t\tsrText={strings.formatActionsLabel(appointment.title)}\n\t\t\t\t\tbuttonProps={{ size: 'sm', className: 'appointment-agenda--actions relative z-10' }}\n\t\t\t\t/>\n\t\t\t) : null,\n\t\t};\n\t\treturn { ...context, defaultRender: () => <AppointmentRow appointment={appointment} context={context} /> };\n\t};\n\n\tconst list = (items: Appointment[]) => (\n\t\t<Stack render={<ul />} gap=\"sm\" className=\"appointment-agenda--list m-0 list-none p-0\">\n\t\t\t{items.map((appointment) => {\n\t\t\t\tconst context = contextFor(appointment);\n\t\t\t\treturn (\n\t\t\t\t\t<li key={appointment.id} className=\"min-w-0\">\n\t\t\t\t\t\t{renderAppointment ? renderAppointment(appointment, context) : context.defaultRender()}\n\t\t\t\t\t</li>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Stack>\n\t);\n\n\tlet body;\n\tif (loading) {\n\t\tbody = (\n\t\t\t<Stack gap=\"sm\" aria-busy=\"true\" className=\"appointment-agenda--loading\">\n\t\t\t\t<VisuallyHidden>{strings.loading}</VisuallyHidden>\n\t\t\t\t{Array.from({ length: 4 }, (_, index) => <Skeleton key={index} className=\"h-control-lg w-full rounded-inner\" />)}\n\t\t\t</Stack>\n\t\t);\n\t} else if (error) {\n\t\t// An app's own element replaces the default; a message becomes its description.\n\t\tbody = isValidElement(error) ? error : (\n\t\t\t<ErrorState\n\t\t\t\tvariant=\"inline\"\n\t\t\t\ttitle={strings.errorTitle}\n\t\t\t\tdescription={error instanceof Error ? error.message : typeof error === 'string' || typeof error === 'number' ? String(error) : strings.errorDescription}\n\t\t\t\tonRetry={onRetry}\n\t\t\t\tretryLabel={strings.retry}\n\t\t\t\tclassName=\"appointment-agenda--error\"\n\t\t\t/>\n\t\t);\n\t} else if (total === 0) {\n\t\tbody = <EmptyState padding=\"sm\" title={strings.empty} description={false} ariaLabel={strings.empty} className=\"appointment-agenda--empty\" />;\n\t} else if (grouped) {\n\t\tbody = (\n\t\t\t<Stack gap=\"xl\">\n\t\t\t\t{groups.filter((group) => group.items.length > 0).map((group) => (\n\t\t\t\t\t<Stack key={group.day.toISOString()} render={<section />} gap=\"sm\" aria-label={dayFormat.format(group.day)} className=\"appointment-agenda--day\">\n\t\t\t\t\t\t<Heading className=\"text-inherit\" tag=\"h3\" size=\"sm\">{dayFormat.format(group.day)}</Heading>\n\t\t\t\t\t\t{list(group.items)}\n\t\t\t\t\t</Stack>\n\t\t\t\t))}\n\t\t\t</Stack>\n\t\t);\n\t} else {\n\t\tbody = list(groups[0]?.items ?? []);\n\t}\n\n\treturn (\n\t\t<Card\n\t\t\tsurface=\"card\"\n\t\t\ttitle={heading}\n\t\t\theaderEnd={<Text size=\"xs\" type=\"secondary\" className=\"tabular-nums\">{strings.formatCount(total)}</Text>}\n\t\t\tclassName=\"appointment-agenda--component h-full min-h-0\"\n\t\t\tcontentClassName=\"min-h-0 flex-1\"\n\t\t>\n\t\t\t<ScrollArea className=\"appointment-agenda--scroll h-full min-h-0\">\n\t\t\t\t{body}\n\t\t\t</ScrollArea>\n\t\t</Card>\n\t);\n}\n","/**\n * AppointmentMonth — the compact month beside the agenda: month and year\n * selects with previous/next, and a day grid whose dots show which categories\n * are booked that day. The grid is one tab stop: arrow keys move by a day or a\n * week, Home/End to the week's edges, PageUp/PageDown by a month, and Enter or\n * Space chooses the focused day. Private to the appointment calendar.\n */\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react';\n\nimport { Button } from '../../../base/buttons';\nimport { Select } from '../../../base/choice-inputs';\nimport { Stack } from '../../../base/structure';\nimport { Text } from '../../../typography';\nimport { focusRecipes } from '../../../../lib/focus-recipes';\nimport { interactionRecipes } from '../../../../lib/interaction-recipes';\nimport { dotRecipes } from '../../../../lib/tone-recipes';\nimport { cn } from '../../../../lib/utils';\n\nimport type { Appointment, AppointmentCalendarStrings, AppointmentCategory } from '../appointment-calendar.types';\nimport {\n\taddDays,\n\taddMonths,\n\tappointmentCategoryColorClasses,\n\tappointmentsOn,\n\tcategoryColor,\n\tisSameDay,\n\tmonthGrid,\n\tstartOfWeek,\n} from '../appointment-calendar.utils';\n\nexport interface AppointmentMonthProps {\n\tselected: Date;\n\tonSelect: (date: Date) => void;\n\t/** The first day of the month on screen, which keyboard focus can move away from the selection. */\n\tonVisibleMonthChange?: (month: Date) => void;\n\tappointments: Appointment[];\n\tcategories: AppointmentCategory[];\n\tweekStartsOn: number;\n\tlocale?: string;\n\tstrings: AppointmentCalendarStrings;\n}\n\n/** Days with this many categories or more show only the first three dots. */\nconst MAX_DOTS = 3;\n\nexport function AppointmentMonth({ selected, onSelect, onVisibleMonthChange, appointments, categories, weekStartsOn, locale, strings }: AppointmentMonthProps) {\n\tconst [focused, setFocused] = useState(selected);\n\tconst gridRef = useRef<HTMLDivElement>(null);\n\tconst focusOnRender = useRef(false);\n\tconst today = useMemo(() => new Date(), []);\n\n\t// The roving focus follows the selection when it changes from outside.\n\tuseEffect(() => setFocused(selected), [selected]);\n\tconst visibleMonth = focused.getFullYear() * 12 + focused.getMonth();\n\tuseEffect(() => {\n\t\tonVisibleMonthChange?.(new Date(Math.floor(visibleMonth / 12), visibleMonth % 12, 1));\n\t}, [visibleMonth, onVisibleMonthChange]);\n\tuseEffect(() => {\n\t\tif (!focusOnRender.current) return;\n\t\tfocusOnRender.current = false;\n\t\tgridRef.current?.querySelector<HTMLButtonElement>('[data-focus-target]')?.focus();\n\t}, [focused]);\n\n\tconst weeks = useMemo(() => monthGrid(focused, weekStartsOn), [focused, weekStartsOn]);\n\tconst monthFormat = useMemo(() => new Intl.DateTimeFormat(locale, { month: 'long' }), [locale]);\n\tconst weekdayFormat = useMemo(() => new Intl.DateTimeFormat(locale, { weekday: 'short' }), [locale]);\n\tconst dayFormat = useMemo(() => new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }), [locale]);\n\tconst monthOptions = useMemo(() => Array.from({ length: 12 }, (_, month) => ({ value: String(month), label: monthFormat.format(new Date(2000, month, 1)) })), [monthFormat]);\n\tconst yearOptions = useMemo(() => {\n\t\tconst years = new Set<number>([today.getFullYear(), focused.getFullYear()]);\n\t\tfor (const appointment of appointments) years.add(appointment.start.getFullYear());\n\t\tconst min = Math.min(...years) - 1;\n\t\tconst max = Math.max(...years) + 1;\n\t\treturn Array.from({ length: max - min + 1 }, (_, index) => ({ value: String(min + index), label: String(min + index) }));\n\t}, [appointments, focused, today]);\n\n\tconst moveTo = (date: Date, select = false) => {\n\t\tfocusOnRender.current = true;\n\t\tsetFocused(date);\n\t\tif (select) onSelect(date);\n\t};\n\tconst changeMonth = (months: number) => {\n\t\tconst next = addMonths(selected, months);\n\t\tsetFocused(next);\n\t\tonSelect(next);\n\t};\n\n\tconst onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n\t\tconst moves: Record<string, () => Date> = {\n\t\t\tArrowLeft: () => addDays(focused, -1),\n\t\t\tArrowRight: () => addDays(focused, 1),\n\t\t\tArrowUp: () => addDays(focused, -7),\n\t\t\tArrowDown: () => addDays(focused, 7),\n\t\t\tHome: () => startOfWeek(focused, weekStartsOn),\n\t\t\tEnd: () => addDays(startOfWeek(focused, weekStartsOn), 6),\n\t\t\tPageUp: () => addMonths(focused, -1),\n\t\t\tPageDown: () => addMonths(focused, 1),\n\t\t};\n\t\tconst move = moves[event.key];\n\t\tif (!move) return;\n\t\tevent.preventDefault();\n\t\tmoveTo(move());\n\t};\n\n\treturn (\n\t\t<Stack gap=\"lg\" className=\"appointment-month--component min-w-0\">\n\t\t\t<div className=\"appointment-month--header flex min-w-0 items-center gap-space-xs\">\n\t\t\t\t<Button type=\"button\" tone=\"secondary\" buttonStyle=\"ghost\" size=\"sm\" iconOnly aria-label={strings.previousMonth} onClick={() => changeMonth(-1)}>\n\t\t\t\t\t<ChevronLeft aria-hidden=\"true\" className=\"size-icon\" />\n\t\t\t\t</Button>\n\t\t\t\t<Select\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\taria-label={strings.monthLabel}\n\t\t\t\t\toptions={monthOptions}\n\t\t\t\t\tvalue={String(selected.getMonth())}\n\t\t\t\t\tonValueChange={(value) => value !== undefined && changeMonth(Number(value) - selected.getMonth())}\n\t\t\t\t\tclassName=\"min-w-0 flex-1\"\n\t\t\t\t/>\n\t\t\t\t<Select\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\taria-label={strings.yearLabel}\n\t\t\t\t\toptions={yearOptions}\n\t\t\t\t\tvalue={String(selected.getFullYear())}\n\t\t\t\t\tonValueChange={(value) => value !== undefined && changeMonth((Number(value) - selected.getFullYear()) * 12)}\n\t\t\t\t\tclassName=\"min-w-0 flex-1\"\n\t\t\t\t/>\n\t\t\t\t<Button type=\"button\" tone=\"secondary\" buttonStyle=\"ghost\" size=\"sm\" iconOnly aria-label={strings.nextMonth} onClick={() => changeMonth(1)}>\n\t\t\t\t\t<ChevronRight aria-hidden=\"true\" className=\"size-icon\" />\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tref={gridRef}\n\t\t\t\trole=\"grid\"\n\t\t\t\taria-label={`${monthFormat.format(focused)} ${focused.getFullYear()}`}\n\t\t\t\tonKeyDown={onKeyDown}\n\t\t\t\tclassName=\"appointment-month--grid grid min-w-0 grid-cols-7 gap-space-2xs\"\n\t\t\t>\n\t\t\t\t<div role=\"row\" className=\"contents\">\n\t\t\t\t\t{weeks[0]?.map((day) => (\n\t\t\t\t\t\t<Text key={day.getDay()} tag=\"div\" role=\"columnheader\" size=\"xs\" type=\"secondary\" weight=\"medium\" align=\"center\" className=\"appointment-month--weekday py-space-xs\">\n\t\t\t\t\t\t\t{weekdayFormat.format(day)}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t{weeks.map((week) => (\n\t\t\t\t\t<div key={week[0]?.toISOString()} role=\"row\" className=\"contents\">\n\t\t\t\t\t\t{week.map((day) => {\n\t\t\t\t\t\t\tconst dayAppointments = appointmentsOn(appointments, day);\n\t\t\t\t\t\t\tconst dayCategories = [...new Set(dayAppointments.map((appointment) => appointment.category))];\n\t\t\t\t\t\t\tconst isSelected = isSameDay(day, selected);\n\t\t\t\t\t\t\tconst isFocused = isSameDay(day, focused);\n\t\t\t\t\t\t\tconst outside = day.getMonth() !== focused.getMonth();\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={day.toISOString()} role=\"gridcell\" aria-selected={isSelected} className=\"flex min-w-0 justify-center\">\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\ttabIndex={isFocused ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\tdata-focus-target={isFocused ? '' : undefined}\n\t\t\t\t\t\t\t\t\t\tdata-selected={isSelected ? '' : undefined}\n\t\t\t\t\t\t\t\t\t\tdata-outside={outside ? '' : undefined}\n\t\t\t\t\t\t\t\t\t\taria-current={isSameDay(day, today) ? 'date' : undefined}\n\t\t\t\t\t\t\t\t\t\taria-label={strings.formatDayLabel(dayFormat.format(day), dayAppointments.length)}\n\t\t\t\t\t\t\t\t\t\tonClick={() => moveTo(day, true)}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\tinteractionRecipes.nativeButtonReset,\n\t\t\t\t\t\t\t\t\t\t\t'appointment-month--day relative flex size-action flex-col items-center justify-center rounded-inner text-sm tabular-nums outline-none',\n\t\t\t\t\t\t\t\t\t\t\tfocusRecipes.edge,\n\t\t\t\t\t\t\t\t\t\t\tisSelected\n\t\t\t\t\t\t\t\t\t\t\t\t? 'bg-primary font-semibold text-primary-foreground'\n\t\t\t\t\t\t\t\t\t\t\t\t: cn(interactionRecipes.rowHover, outside ? 'text-muted-foreground' : 'text-foreground'),\n\t\t\t\t\t\t\t\t\t\t\t!isSelected && isSameDay(day, today) && 'font-semibold',\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{day.getDate()}\n\t\t\t\t\t\t\t\t\t\t{dayCategories.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t\t<span aria-hidden=\"true\" className=\"appointment-month--dots absolute inset-x-0 bottom-space-2xs flex justify-center gap-space-2xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{dayCategories.slice(0, MAX_DOTS).map((category) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span key={category} className={cn(dotRecipes.inline, appointmentCategoryColorClasses[categoryColor(categories, category)])} />\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</span>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</Stack>\n\t);\n}\n","/**\n * AppointmentCalendar — a booking calendar laid out side by side: a compact\n * month with category dots and filters beside the agenda for the chosen day\n * or week.\n *\n * The header carries the title with booked and conflict counts, the Day/Week\n * switch, an optional staff filter and the \"New appointment\" command. Two\n * overlapping appointments for one staff member are a conflict: both rows say\n * so, and a dismissible alert names who is double-booked and when. Categories\n * are kinds, so their stripes and dots draw from the chart palette, and status\n * chips keep the status tones. The layout follows its own container: the month\n * sits beside the agenda when there is room and above it otherwise.\n *\n * Data, creation and editing stay with the app: the calendar formats and\n * filters the appointments it is given and reports intent through callbacks.\n */\nimport { Plus, TriangleAlert } from 'lucide-react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Button } from '../../base/buttons';\nimport { Card } from '../../base/cards';\nimport { Select } from '../../base/choice-inputs';\nimport { Alert, AlertAction, AlertDescription, AlertTitle } from '../../base/feedback';\nimport { Tabs, TabsList, TabsTrigger } from '../../base/navigation/tabs';\nimport { Stack } from '../../base/structure';\nimport { Heading, Text } from '../../typography';\nimport { useStrings } from '../../../lib/strings';\nimport { dotRecipes } from '../../../lib/tone-recipes';\nimport { useDatesConfig, useFormattingConfig } from '../../../lib/ui-provider';\nimport { cn } from '../../../lib/utils';\n\nimport {\n\tdefaultAppointmentCalendarStrings,\n\ttype Appointment,\n\ttype AppointmentCalendarProps,\n\ttype AppointmentCalendarView,\n\ttype AppointmentConflict,\n\ttype AppointmentDateRange,\n} from './appointment-calendar.types';\nimport {\n\taddDays,\n\tappointmentCategoryColorClasses,\n\tcategoryColor,\n\tconflictingIds,\n\tfilterAppointments,\n\tfindConflicts,\n\tformatTime,\n\tmonthGrid,\n\toccursOn,\n\tstaffFrom,\n\tstartOfDay,\n\tweekDays,\n} from './appointment-calendar.utils';\nimport { AppointmentAgenda, type AppointmentAgendaProps } from './partials/appointment-agenda';\nimport { AppointmentMonth } from './partials/appointment-month';\n\n/** Controlled when `value` is given, otherwise local state seeded by `fallback`. */\nfunction useControllable<T>(value: T | undefined, fallback: T, onChange?: (next: T) => void): [T, (next: T) => void] {\n\tconst [local, setLocal] = useState(fallback);\n\tconst current = value ?? local;\n\treturn [current, (next: T) => {\n\t\tif (value === undefined) setLocal(next);\n\t\tonChange?.(next);\n\t}];\n}\n\nexport function AppointmentCalendar<T extends Appointment = Appointment>({\n\tappointments,\n\tcategories,\n\tstaff: staffProp,\n\ttitle,\n\tdate: dateProp,\n\tdefaultDate,\n\tonDateChange,\n\tview: viewProp,\n\tdefaultView = 'day',\n\tonViewChange,\n\tcategory: categoryProp,\n\tdefaultCategory = 'all',\n\tonCategoryChange,\n\tstaffId: staffIdProp,\n\tdefaultStaffId = 'all',\n\tonStaffChange,\n\tonAppointmentClick,\n\tappointmentActions,\n\trenderAppointment,\n\tonRangeChange,\n\tonCreateAppointment,\n\tonConflictsDismiss,\n\tloading = false,\n\terror,\n\tonRetry,\n\tweekStartsOn: weekStartsOnProp,\n\tstrings: stringsProp,\n\tclassName,\n}: AppointmentCalendarProps<T>) {\n\tconst strings = useStrings(defaultAppointmentCalendarStrings, stringsProp);\n\tconst { locale } = useFormattingConfig();\n\tconst dates = useDatesConfig();\n\tconst weekStartsOn = weekStartsOnProp ?? dates.weekStartsOn ?? 0;\n\n\tconst [date, setDate] = useControllable(dateProp, defaultDate ?? startOfDay(new Date()), onDateChange);\n\tconst [view, setView] = useControllable<AppointmentCalendarView>(viewProp, defaultView, onViewChange);\n\tconst [category, setCategory] = useControllable(categoryProp, defaultCategory, onCategoryChange);\n\tconst [staffId, setStaffId] = useControllable(staffIdProp, defaultStaffId, onStaffChange);\n\tconst [dismissed, setDismissed] = useState<string>('');\n\tconst [visibleMonth, setVisibleMonth] = useState(() => new Date(date.getFullYear(), date.getMonth(), 1));\n\n\tconst staff = useMemo(() => staffProp ?? staffFrom(appointments), [staffProp, appointments]);\n\tconst days = useMemo(() => (view === 'week' ? weekDays(date, weekStartsOn) : [startOfDay(date)]), [view, date, weekStartsOn]);\n\tconst visible = useMemo(() => filterAppointments(appointments, category, staffId), [appointments, category, staffId]);\n\t// The days on screen: the month grid, widened by the agenda when keyboard\n\t// focus has moved the month away from the selected day or week.\n\tconst range = useMemo<AppointmentDateRange>(() => {\n\t\tconst edges = [...monthGrid(visibleMonth, weekStartsOn).flat(), ...days].map((day) => day.getTime());\n\t\treturn { start: new Date(Math.min(...edges)), end: addDays(new Date(Math.max(...edges)), 1) };\n\t}, [visibleMonth, weekStartsOn, days]);\n\tconst reportedRange = useRef('');\n\tuseEffect(() => {\n\t\tconst key = `${range.start.getTime()}:${range.end.getTime()}`;\n\t\tif (key === reportedRange.current) return;\n\t\treportedRange.current = key;\n\t\tonRangeChange?.(range);\n\t}, [range, onRangeChange]);\n\tconst inRange = useMemo(() => visible.filter((appointment) => days.some((day) => occursOn(appointment, day))), [visible, days]);\n\n\t// A staff member is double-booked whatever the category filter shows, so\n\t// overlaps are found across every category, then narrowed to the range.\n\tconst conflicts = useMemo(() => {\n\t\tconst staffScoped = filterAppointments(appointments, 'all', staffId).filter((appointment) => days.some((day) => occursOn(appointment, day)));\n\t\treturn findConflicts(staffScoped);\n\t}, [appointments, staffId, days]);\n\tconst conflictIds = useMemo(() => conflictingIds(conflicts), [conflicts]);\n\tconst visibleConflicts = inRange.filter((appointment) => conflictIds.has(appointment.id)).length;\n\tconst booked = inRange.filter((appointment) => appointment.status !== 'cancelled').length;\n\tconst conflictKey = [...conflictIds].sort().join('|');\n\tconst showAlert = conflicts.length > 0 && dismissed !== conflictKey;\n\n\tconst headingFormat = new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric' });\n\tconst rangeFormat = new Intl.DateTimeFormat(locale, { month: 'long', day: 'numeric' });\n\tconst heading = view === 'week'\n\t\t? strings.formatWeekRange(rangeFormat.format(days[0] ?? date), rangeFormat.format(days[days.length - 1] ?? date))\n\t\t: headingFormat.format(date);\n\n\tconst dismissConflicts = (shown: AppointmentConflict<T>[]) => {\n\t\tsetDismissed(conflictKey);\n\t\tonConflictsDismiss?.(shown);\n\t};\n\n\treturn (\n\t\t<Stack gap=\"xl\" data-slot=\"appointment-calendar\" data-view={view} className={cn('appointment-calendar--component @container/appointment-calendar min-h-0 min-w-0', className)}>\n\t\t\t<div className=\"appointment-calendar--header flex min-w-0 flex-wrap items-start justify-between gap-space-lg\">\n\t\t\t\t<Stack gap=\"xs\" className=\"min-w-0\">\n\t\t\t\t\t{!!title && <Heading className=\"text-inherit\" tag=\"h2\" size=\"lg\">{title}</Heading>}\n\t\t\t\t\t<Text size=\"xs\" type=\"secondary\" className=\"appointment-calendar--counts tabular-nums\">\n\t\t\t\t\t\t{strings.formatBooked(booked)}\n\t\t\t\t\t\t{visibleConflicts > 0 && ` · ${strings.formatConflicts(visibleConflicts)}`}\n\t\t\t\t\t</Text>\n\t\t\t\t</Stack>\n\t\t\t\t<div className=\"appointment-calendar--actions flex min-w-0 flex-wrap items-center gap-space-sm\">\n\t\t\t\t\t<Tabs value={view} onValueChange={(next) => (next === 'day' || next === 'week') && setView(next)}>\n\t\t\t\t\t\t<TabsList role=\"group\" aria-label={strings.viewLabel} aria-orientation={undefined} activateOnFocus>\n\t\t\t\t\t\t\t{(['day', 'week'] as const).map((option) => (\n\t\t\t\t\t\t\t\t<TabsTrigger key={option} value={option} role=\"button\" aria-selected={undefined} aria-controls={undefined} aria-pressed={view === option}>\n\t\t\t\t\t\t\t\t\t{strings[option]}\n\t\t\t\t\t\t\t\t</TabsTrigger>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</TabsList>\n\t\t\t\t\t</Tabs>\n\t\t\t\t\t{staff.length > 0 && (\n\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\taria-label={strings.staffLabel}\n\t\t\t\t\t\t\toptions={[{ value: 'all', label: strings.allStaff }, ...staff.map((person) => ({ value: person.id, label: person.name }))]}\n\t\t\t\t\t\t\tvalue={staffId}\n\t\t\t\t\t\t\tonValueChange={(next) => setStaffId(next ?? 'all')}\n\t\t\t\t\t\t\tclassName=\"appointment-calendar--staff w-44\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!onCreateAppointment && (\n\t\t\t\t\t\t<Button type=\"button\" tone=\"primary\" onClick={() => onCreateAppointment(date)} className=\"appointment-calendar--create\">\n\t\t\t\t\t\t\t<Plus aria-hidden=\"true\" className=\"size-icon\" />\n\t\t\t\t\t\t\t{strings.newAppointment}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{showAlert && (\n\t\t\t\t<Alert tone=\"destructive\" className=\"appointment-calendar--alert\">\n\t\t\t\t\t<TriangleAlert aria-hidden=\"true\" />\n\t\t\t\t\t<AlertTitle>{strings.conflictTitle}</AlertTitle>\n\t\t\t\t\t<AlertDescription>\n\t\t\t\t\t\t{conflicts.map((conflict) => strings.formatConflict(conflict.staff.name, conflict.appointments.length, formatTime(conflict.start, locale))).join(' ')}\n\t\t\t\t\t</AlertDescription>\n\t\t\t\t\t<AlertAction>\n\t\t\t\t\t\t<Button type=\"button\" size=\"sm\" onClick={() => dismissConflicts(conflicts)}>{strings.dismiss}</Button>\n\t\t\t\t\t</AlertAction>\n\t\t\t\t</Alert>\n\t\t\t)}\n\n\t\t\t<div className=\"appointment-calendar--body grid min-h-0 min-w-0 flex-1 gap-space-xl @3xl/appointment-calendar:grid-cols-[minmax(17rem,20rem)_minmax(0,1fr)]\">\n\t\t\t\t<Card surface=\"card\" className=\"appointment-calendar--aside min-w-0 self-start\">\n\t\t\t\t\t<Stack gap=\"xl\">\n\t\t\t\t\t\t<AppointmentMonth\n\t\t\t\t\t\t\tselected={date}\n\t\t\t\t\t\t\tonSelect={setDate}\n\t\t\t\t\t\t\tonVisibleMonthChange={setVisibleMonth}\n\t\t\t\t\t\t\tappointments={visible}\n\t\t\t\t\t\t\tcategories={categories}\n\t\t\t\t\t\t\tweekStartsOn={weekStartsOn}\n\t\t\t\t\t\t\tlocale={locale}\n\t\t\t\t\t\t\tstrings={strings}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{categories.length > 0 && (\n\t\t\t\t\t\t\t<Tabs value={category} onValueChange={(next) => typeof next === 'string' && setCategory(next)}>\n\t\t\t\t\t\t\t\t<TabsList variant=\"chips\" role=\"group\" aria-label={strings.categoriesLabel} aria-orientation={undefined} activateOnFocus>\n\t\t\t\t\t\t\t\t\t{[{ id: 'all', label: strings.allCategories }, ...categories].map((option) => (\n\t\t\t\t\t\t\t\t\t\t<TabsTrigger key={option.id} value={option.id} role=\"button\" aria-selected={undefined} aria-controls={undefined} aria-pressed={category === option.id} className=\"appointment-calendar--category gap-space-xs\">\n\t\t\t\t\t\t\t\t\t\t\t{option.id !== 'all' && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span aria-hidden=\"true\" className={cn(dotRecipes.inline, appointmentCategoryColorClasses[categoryColor(categories, option.id)])} />\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t\t\t</TabsTrigger>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</TabsList>\n\t\t\t\t\t\t\t</Tabs>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Stack>\n\t\t\t\t</Card>\n\n\t\t\t\t<AppointmentAgenda\n\t\t\t\t\tdays={days}\n\t\t\t\t\tappointments={visible}\n\t\t\t\t\tcategories={categories}\n\t\t\t\t\tconflicts={conflictIds}\n\t\t\t\t\theading={heading}\n\t\t\t\t\tloading={loading}\n\t\t\t\t\terror={error}\n\t\t\t\t\tonRetry={onRetry}\n\t\t\t\t\tlocale={locale}\n\t\t\t\t\t// The agenda only hands back items from `appointments`, so the app's own type holds.\n\t\t\t\t\tonAppointmentClick={onAppointmentClick as ((appointment: Appointment) => void) | undefined}\n\t\t\t\t\tappointmentActions={appointmentActions as AppointmentAgendaProps['appointmentActions']}\n\t\t\t\t\trenderAppointment={renderAppointment as AppointmentAgendaProps['renderAppointment']}\n\t\t\t\t\tstrings={strings}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</Stack>\n\t);\n}\n\nAppointmentCalendar.displayName = 'AppointmentCalendar';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"appointment-calendar.js","names":["_Fragment","useFormattingConfig","useDatesConfig","cn","Button","Text","Heading","headingRoleSizes","focusRecipes","Stack","toneRecipes","dotRecipes","AlertDescription","AlertAction","Alert","Card","AlertTitle","ErrorState","compositionClasses","ActionMenu","Skeleton","interactionRecipes","formatInitials","AvatarFallback","Avatar","AvatarImage","Badge","Select","VisuallyHidden","ScrollArea","ItemDescription","ItemActions","ItemContent","Item","ItemTitle","TabsTrigger","TabsList","Tabs","EmptyState","Fragment$1","defaultAppointmentCalendarStrings","count","staffName","time","start","end","date","title","CHART_SERIES","appointmentCategoryColorClasses","categoryColor","index","categories","category","id","startOfDay","addDays","days","isSameDay","a","b","addMonths","target","months","lastDay","startOfWeek","day","weekStartsOn","weekDays","first","monthGrid","week","occursOn","dayStart","dayEnd","appointment","appointmentsOn","appointments","filterAppointments","staffId","findConflicts","byStaff","list","conflicts","sorted","group","groupEnd","flush","conflictingIds","conflict","staffFrom","seen","formatTime","locale","hour12","options","personName","person","STATUS_TONE","AppointmentRow","useId","client","staff","context","hasActions","labelledBy","openRef","useRef","actionsHadFocus","useLayoutEffect","open","event","AppointmentAgenda","groups","total","sum","dayFormat","grouped","contextFor","actions","appointmentActions","action","strings","onAppointmentClick","items","renderAppointment","body","loading","error","isValidElement","heading","MAX_DOTS","AppointmentMonth","focused","setFocused","useState","selected","gridRef","focusOnRender","today","useMemo","visibleMonth","useEffect","onVisibleMonthChange","weeks","monthFormat","weekdayFormat","monthOptions","month","yearOptions","years","min","max","moveTo","select","onSelect","changeMonth","next","ChevronLeft","value","ChevronRight","move","dayAppointments","dayCategories","isSelected","isFocused","outside","useControllable","local","setLocal","fallback","onChange","AppointmentCalendar","staffProp","dateProp","viewProp","categoryProp","staffIdProp","weekStartsOnProp","stringsProp","useStrings","dates","setDate","defaultDate","onDateChange","view","setView","defaultView","onViewChange","setCategory","defaultCategory","onCategoryChange","setStaffId","defaultStaffId","onStaffChange","dismissed","setDismissed","setVisibleMonth","visible","range","edges","reportedRange","key","onRangeChange","inRange","conflictIds","visibleConflicts","booked","conflictKey","showAlert","headingFormat","rangeFormat","dismissConflicts","onConflictsDismiss","shown","className","option","onCreateAppointment","Plus","TriangleAlert"],"sources":["../../src/components/features/appointment-calendar/appointment-calendar.types.ts","../../src/components/features/appointment-calendar/appointment-calendar.utils.ts","../../src/components/features/appointment-calendar/partials/appointment-agenda.tsx","../../src/components/features/appointment-calendar/partials/appointment-month.tsx","../../src/components/features/appointment-calendar/appointment-calendar.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport type { ActionMenuAction } from '../../base/action-menu';\nimport type { BadgeTone } from '../../base/badge';\nimport type { StringsProp } from '../../../lib/strings';\n\n/** Where an appointment stands. Conflicts are derived, never a status. */\nexport type AppointmentStatus = 'confirmed' | 'pending' | 'completed' | 'cancelled' | 'noShow';\n\n/** The day agenda or the seven-day week agenda beside the month. */\nexport type AppointmentCalendarView = 'day' | 'week';\n\n/**\n * Categorical colour for a service category. Categories are kinds, not\n * statuses, so they draw from the chart series palette and never from the\n * success, warning or destructive tones that status chips own.\n */\nexport type AppointmentCategoryColor = 'chart-1' | 'chart-2' | 'chart-3' | 'chart-4' | 'chart-5';\n\n/** A service category: its label, filter chip and marker colour. */\nexport interface AppointmentCategory {\n\t/** Stable identity, referenced by `Appointment.category`. */\n\tid: string;\n\t/** Chip and legend label. */\n\tlabel: string;\n\t/** Marker colour. Defaults to the chart series by the category's position. */\n\tcolor?: AppointmentCategoryColor;\n}\n\n/** A person on an appointment: the staff member who delivers it, or the client. */\nexport interface AppointmentPerson {\n\t/** Stable identity. Staff overlap is detected by this id. */\n\tid: string;\n\t/** Display name. */\n\tname: string;\n\t/** Portrait. Initials stand in without one, or when it fails to load. */\n\tavatarUrl?: string;\n}\n\n/** One booked slot. The calendar formats it; it never fetches or saves. */\nexport interface Appointment {\n\t/** Stable identity. */\n\tid: string;\n\t/** The service: \"Cut and blow-dry\". */\n\ttitle: string;\n\t/** Start of the slot. */\n\tstart: Date;\n\t/** End of the slot; later than `start`. */\n\tend: Date;\n\t/** Category id, matching an `AppointmentCategory`. */\n\tcategory: string;\n\t/** Booking state. Cancelled appointments are listed but never conflict. */\n\tstatus: AppointmentStatus;\n\t/** Who the appointment is for, shown after the time. */\n\tclient?: AppointmentPerson | string;\n\t/** Who delivers it. Two overlapping appointments for one staff member conflict. */\n\tstaff?: AppointmentPerson;\n}\n\n/** The days on screen: the month grid and the agenda. `end` is exclusive (midnight after the last day). */\nexport interface AppointmentDateRange {\n\tstart: Date;\n\tend: Date;\n}\n\n/** Overlapping appointments for one staff member. */\nexport interface AppointmentConflict<T extends Appointment = Appointment> {\n\t/** The double-booked staff member. */\n\tstaff: AppointmentPerson;\n\t/** The appointments that overlap, earliest first. */\n\tappointments: T[];\n\t/** When the overlap begins. */\n\tstart: Date;\n}\n\nexport interface AppointmentCalendarStrings {\n\t/** Booked count beside the title: \"8 booked\". */\n\tformatBooked: (count: number) => string;\n\t/** Conflict count beside the title: \"2 conflicts\". */\n\tformatConflicts: (count: number) => string;\n\t/** Accessible name of the Day/Week switch. */\n\tviewLabel: string;\n\tday: string;\n\tweek: string;\n\t/** Accessible name of the staff filter. */\n\tstaffLabel: string;\n\t/** The staff filter's \"everyone\" option. */\n\tallStaff: string;\n\t/** Primary command. */\n\tnewAppointment: string;\n\t/** Conflict alert title. */\n\tconflictTitle: string;\n\t/** One overlapping-booking sentence per double-booked staff member. */\n\tformatConflict: (staffName: string, count: number, time: string) => string;\n\t/** Hides the conflict alert. */\n\tdismiss: string;\n\tpreviousMonth: string;\n\tnextMonth: string;\n\t/** Accessible name of the month select. */\n\tmonthLabel: string;\n\t/** Accessible name of the year select. */\n\tyearLabel: string;\n\t/** Accessible name of the category filter. */\n\tcategoriesLabel: string;\n\t/** The category filter's \"every category\" chip. */\n\tallCategories: string;\n\t/** Count beside the agenda heading: \"8 appointments\". */\n\tformatCount: (count: number) => string;\n\t/** A slot: \"9 AM to 10 AM\". Receives already formatted times. */\n\tformatTimeRange: (start: string, end: string) => string;\n\t/** Accessible day label in the month: \"Tuesday, June 9, 3 appointments\". */\n\tformatDayLabel: (date: string, count: number) => string;\n\t/** Agenda heading for the week view: \"June 8 to 14\". */\n\tformatWeekRange: (start: string, end: string) => string;\n\t/** Status chip words. */\n\tstatus: Record<AppointmentStatus, string>;\n\t/** Chip shown instead of the status when an appointment overlaps another. */\n\tconflict: string;\n\t/** Agenda copy when nothing matches the day or week. */\n\tempty: string;\n\t/** Loading copy for assistive technology. */\n\tloading: string;\n\t/** Default error state title. */\n\terrorTitle: string;\n\t/** Default error state description, when `error` carries no message. */\n\terrorDescription: string;\n\t/** Retry command in the default error state. */\n\tretry: string;\n\t/** Accessible name of an appointment's actions menu: \"Actions for Balayage\". */\n\tformatActionsLabel: (title: string) => string;\n}\n\nexport const defaultAppointmentCalendarStrings: AppointmentCalendarStrings = {\n\tformatBooked: (count) => `${count} booked`,\n\tformatConflicts: (count) => (count === 1 ? '1 conflict' : `${count} conflicts`),\n\tviewLabel: 'View',\n\tday: 'Day',\n\tweek: 'Week',\n\tstaffLabel: 'Staff',\n\tallStaff: 'All staff',\n\tnewAppointment: 'New appointment',\n\tconflictTitle: 'Double-booked',\n\tformatConflict: (staffName, count, time) => `${staffName} has ${count} overlapping bookings at ${time}.`,\n\tdismiss: 'Dismiss',\n\tpreviousMonth: 'Previous month',\n\tnextMonth: 'Next month',\n\tmonthLabel: 'Month',\n\tyearLabel: 'Year',\n\tcategoriesLabel: 'Categories',\n\tallCategories: 'All',\n\tformatCount: (count) => (count === 1 ? '1 appointment' : `${count} appointments`),\n\tformatTimeRange: (start, end) => `${start} to ${end}`,\n\tformatDayLabel: (date, count) => (count === 0 ? date : `${date}, ${count === 1 ? '1 appointment' : `${count} appointments`}`),\n\tformatWeekRange: (start, end) => `${start} to ${end}`,\n\tstatus: { confirmed: 'Confirmed', pending: 'Pending', completed: 'Completed', cancelled: 'Cancelled', noShow: 'No-show' },\n\tconflict: 'Conflict',\n\tempty: 'No appointments',\n\tloading: 'Loading appointments',\n\terrorTitle: 'Appointments unavailable',\n\terrorDescription: 'The appointments could not be loaded.',\n\tretry: 'Retry',\n\tformatActionsLabel: (title) => `Actions for ${title}`,\n};\n\n/** What the calendar has worked out for one appointment, handed to `renderAppointment`. */\nexport interface AppointmentRenderContext {\n\t/** The appointment's category, when one matches. */\n\tcategory?: AppointmentCategory;\n\t/** The category's marker class (`bg-chart-N`), for a stripe or dot of your own. */\n\tcategoryColorClass: string;\n\t/** Whether it overlaps another booking for the same staff member. */\n\tconflict: boolean;\n\t/** The status chip's word, or the conflict word when it overlaps. */\n\tstatusLabel: string;\n\t/** The status chip's tone: destructive for a conflict, otherwise the status tone. */\n\tstatusTone: BadgeTone;\n\t/** The formatted slot: \"09:00 to 10:00\". */\n\ttime: string;\n\t/** Opens it through `onAppointmentClick`. Undefined when rows are not interactive. */\n\topen?: () => void;\n\t/** The visible commands `appointmentActions` returned for it. */\n\tactions: readonly ActionMenuAction[];\n\t/** The built-in actions menu for those commands, or null when there are none. */\n\tactionsMenu: ReactNode;\n\t/** The built-in row, to wrap or extend instead of replacing. */\n\tdefaultRender: () => ReactNode;\n}\n\n/**\n * Props for `AppointmentCalendar`. `T` is the app's own appointment type: extra\n * fields such as a price or notes come back, typed, in every callback.\n */\nexport interface AppointmentCalendarProps<T extends Appointment = Appointment> {\n\t/** Appointments to place. The calendar filters and formats; it never fetches. */\n\tappointments: T[];\n\t/** Service categories: filter chips, markers and day dots. */\n\tcategories: AppointmentCategory[];\n\t/** Staff offered by the staff filter. Defaults to the staff found on appointments. */\n\tstaff?: AppointmentPerson[];\n\t/** Heading above the calendar: the location or calendar name. */\n\ttitle?: ReactNode;\n\t/** Selected day. Controlled with `onDateChange`. */\n\tdate?: Date;\n\t/** Selected day for uncontrolled use. Defaults to today. */\n\tdefaultDate?: Date;\n\t/** Fired when a day is chosen or the month moves. */\n\tonDateChange?: (date: Date) => void;\n\t/** Day or week agenda. Controlled with `onViewChange`. */\n\tview?: AppointmentCalendarView;\n\t/** View for uncontrolled use. Defaults to `day`. */\n\tdefaultView?: AppointmentCalendarView;\n\t/** Fired when the Day/Week switch changes. */\n\tonViewChange?: (view: AppointmentCalendarView) => void;\n\t/** Category filter: a category id, or `all`. Controlled with `onCategoryChange`. */\n\tcategory?: string;\n\t/** Category filter for uncontrolled use. Defaults to `all`. */\n\tdefaultCategory?: string;\n\t/** Fired when a category chip is chosen. */\n\tonCategoryChange?: (category: string) => void;\n\t/** Staff filter: a staff id, or `all`. Controlled with `onStaffChange`. */\n\tstaffId?: string;\n\t/** Staff filter for uncontrolled use. Defaults to `all`. */\n\tdefaultStaffId?: string;\n\t/** Fired when the staff filter changes. */\n\tonStaffChange?: (staffId: string) => void;\n\t/** Fired when an appointment is activated. Without it, rows are not interactive. */\n\tonAppointmentClick?: (appointment: T) => void;\n\t/**\n\t * Commands for one appointment, such as confirm, reschedule or cancel,\n\t * offered in a menu at the end of its row. Return an empty list for none.\n\t */\n\tappointmentActions?: (appointment: T) => readonly ActionMenuAction[];\n\t/**\n\t * Renders one appointment in the agenda instead of the built-in row. The\n\t * context carries its category colour, conflict, time, `open`, its actions\n\t * and a ready actions menu, and `defaultRender` for the built-in row.\n\t */\n\trenderAppointment?: (appointment: T, context: AppointmentRenderContext) => ReactNode;\n\t/**\n\t * Fired with the days on screen, the month grid and the agenda together, once\n\t * on mount and whenever they change. Load appointments for this range.\n\t */\n\tonRangeChange?: (range: AppointmentDateRange) => void;\n\t/** Shows the primary \"New appointment\" command; receives the selected day. */\n\tonCreateAppointment?: (date: Date) => void;\n\t/** Fired when the conflict alert is dismissed, with the conflicts it showed. */\n\tonConflictsDismiss?: (conflicts: AppointmentConflict<T>[]) => void;\n\t/** Shows the loading state in the agenda. */\n\tloading?: boolean;\n\t/**\n\t * Shows the error state in the agenda. A string or Error becomes its\n\t * description; any other element replaces the default state.\n\t */\n\terror?: ReactNode | Error;\n\t/** Adds Retry to the default error state. */\n\tonRetry?: () => void;\n\t/** First column of the month and first day of the week. Defaults to the provider, then Sunday. */\n\tweekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;\n\t/** Overrides this calendar's own copy. */\n\tstrings?: StringsProp<AppointmentCalendarStrings>;\n\t/** Merged onto the root. */\n\tclassName?: string;\n}\n","/**\n * Pure helpers for the appointment calendar: day arithmetic, filtering,\n * conflict detection and time formatting. No React, so they are testable and\n * reusable by an application that pre-computes its own view.\n */\nimport type {\n\tAppointment,\n\tAppointmentCategory,\n\tAppointmentCategoryColor,\n\tAppointmentConflict,\n\tAppointmentPerson,\n} from './appointment-calendar.types';\n\nconst CHART_SERIES: AppointmentCategoryColor[] = ['chart-1', 'chart-2', 'chart-3', 'chart-4', 'chart-5'];\n\n/** Marker colour classes per chart series. Literal so Tailwind generates them. */\nexport const appointmentCategoryColorClasses: Record<AppointmentCategoryColor, string> = {\n\t'chart-1': 'bg-chart-1',\n\t'chart-2': 'bg-chart-2',\n\t'chart-3': 'bg-chart-3',\n\t'chart-4': 'bg-chart-4',\n\t'chart-5': 'bg-chart-5',\n};\n\n/** A category's colour: its own, or the chart series at its position. */\nexport function categoryColor(categories: AppointmentCategory[], id: string): AppointmentCategoryColor {\n\tconst index = categories.findIndex((category) => category.id === id);\n\tif (index < 0) return 'chart-1';\n\treturn categories[index]?.color ?? CHART_SERIES[index % CHART_SERIES.length] ?? 'chart-1';\n}\n\nexport function startOfDay(date: Date): Date {\n\treturn new Date(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\nexport function addDays(date: Date, days: number): Date {\n\treturn new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);\n}\n\nexport function isSameDay(a: Date, b: Date): boolean {\n\treturn a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\n\n/** The same day of the month in another month, clamped to that month's length. */\nexport function addMonths(date: Date, months: number): Date {\n\tconst target = new Date(date.getFullYear(), date.getMonth() + months, 1);\n\tconst lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n\treturn new Date(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), lastDay));\n}\n\nexport function startOfWeek(date: Date, weekStartsOn: number): Date {\n\tconst day = startOfDay(date);\n\treturn addDays(day, -((day.getDay() - weekStartsOn + 7) % 7));\n}\n\n/** The seven days of the week that holds `date`. */\nexport function weekDays(date: Date, weekStartsOn: number): Date[] {\n\tconst first = startOfWeek(date, weekStartsOn);\n\treturn Array.from({ length: 7 }, (_, index) => addDays(first, index));\n}\n\n/** Six full weeks covering the month of `date`, so the grid never changes height. */\nexport function monthGrid(date: Date, weekStartsOn: number): Date[][] {\n\tconst first = startOfWeek(new Date(date.getFullYear(), date.getMonth(), 1), weekStartsOn);\n\treturn Array.from({ length: 6 }, (_, week) => Array.from({ length: 7 }, (_, day) => addDays(first, week * 7 + day)));\n}\n\n/** Whether an appointment touches a day (it may run past midnight). */\nexport function occursOn(appointment: Appointment, day: Date): boolean {\n\tconst dayStart = startOfDay(day).getTime();\n\tconst dayEnd = addDays(day, 1).getTime();\n\treturn appointment.start.getTime() < dayEnd && appointment.end.getTime() > dayStart;\n}\n\nexport function appointmentsOn<T extends Appointment>(appointments: T[], day: Date): T[] {\n\treturn appointments\n\t\t.filter((appointment) => occursOn(appointment, day))\n\t\t.sort((a, b) => a.start.getTime() - b.start.getTime() || a.end.getTime() - b.end.getTime());\n}\n\n/** Applies the category and staff filters; `all` keeps everything. */\nexport function filterAppointments<T extends Appointment>(appointments: T[], category: string, staffId: string): T[] {\n\treturn appointments.filter((appointment) =>\n\t\t(category === 'all' || appointment.category === category) &&\n\t\t(staffId === 'all' || appointment.staff?.id === staffId),\n\t);\n}\n\n/**\n * Overlapping appointments per staff member. Two appointments conflict when\n * the same staff member is booked for both and their times overlap; touching\n * ends (10:00 to 10:00) do not overlap, and cancelled appointments never conflict.\n */\nexport function findConflicts<T extends Appointment>(appointments: T[]): AppointmentConflict<T>[] {\n\tconst byStaff = new Map<string, T[]>();\n\tfor (const appointment of appointments) {\n\t\tif (!appointment.staff || appointment.status === 'cancelled') continue;\n\t\tconst list = byStaff.get(appointment.staff.id) ?? [];\n\t\tlist.push(appointment);\n\t\tbyStaff.set(appointment.staff.id, list);\n\t}\n\tconst conflicts: AppointmentConflict<T>[] = [];\n\tfor (const list of byStaff.values()) {\n\t\tconst sorted = [...list].sort((a, b) => a.start.getTime() - b.start.getTime());\n\t\tlet group: T[] = [];\n\t\tlet groupEnd = -Infinity;\n\t\tconst flush = () => {\n\t\t\tconst first = group[0];\n\t\t\tif (group.length > 1 && first?.staff) conflicts.push({ staff: first.staff, appointments: group, start: first.start });\n\t\t};\n\t\tfor (const appointment of sorted) {\n\t\t\tif (appointment.start.getTime() < groupEnd) {\n\t\t\t\tgroup.push(appointment);\n\t\t\t\tgroupEnd = Math.max(groupEnd, appointment.end.getTime());\n\t\t\t} else {\n\t\t\t\tflush();\n\t\t\t\tgroup = [appointment];\n\t\t\t\tgroupEnd = appointment.end.getTime();\n\t\t\t}\n\t\t}\n\t\tflush();\n\t}\n\treturn conflicts.sort((a, b) => a.start.getTime() - b.start.getTime());\n}\n\n/** Ids of every appointment that takes part in a conflict. */\nexport function conflictingIds(conflicts: AppointmentConflict[]): Set<string> {\n\treturn new Set(conflicts.flatMap((conflict) => conflict.appointments.map((appointment) => appointment.id)));\n}\n\n/** Distinct staff found on appointments, in first-seen order. */\nexport function staffFrom(appointments: Appointment[]): AppointmentPerson[] {\n\tconst seen = new Map<string, AppointmentPerson>();\n\tfor (const appointment of appointments) if (appointment.staff && !seen.has(appointment.staff.id)) seen.set(appointment.staff.id, appointment.staff);\n\treturn [...seen.values()];\n}\n\n/**\n * \"9 AM\", or \"9:30 AM\" when the minutes matter. A 24-hour clock always keeps\n * its minutes (\"09:00\"), since a bare \"09\" does not read as a time.\n */\nexport function formatTime(date: Date, locale?: string): string {\n\tconst { hour12 } = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).resolvedOptions();\n\tif (!hour12) return new Intl.DateTimeFormat(locale, { hour: '2-digit', minute: '2-digit' }).format(date);\n\tconst options: Intl.DateTimeFormatOptions = date.getMinutes() === 0 ? { hour: 'numeric' } : { hour: 'numeric', minute: '2-digit' };\n\treturn new Intl.DateTimeFormat(locale, options).format(date);\n}\n\nexport function personName(person: AppointmentPerson | string | undefined): string | undefined {\n\treturn typeof person === 'string' ? person : person?.name;\n}\n","/**\n * AppointmentAgenda — the list beside the month: one day's appointments, or\n * the selected week grouped by day. Each row shows its category stripe, the\n * service with its status chip (or the conflict chip when it overlaps another\n * booking for the same staff member), the time range and client, and the\n * staff member's avatar. A row opens only when the app can open it: a\n * transparent button stretched over the row takes the click, and the actions\n * menu sits above it, since a button cannot hold another. Private to the\n * appointment calendar.\n */\nimport { isValidElement, useId, useLayoutEffect, useRef, type ReactNode } from 'react';\n\nimport { ActionMenu, type ActionMenuAction } from '../../../base/action-menu';\nimport { Avatar, AvatarFallback, AvatarImage } from '../../../base/avatar';\nimport { Badge, type BadgeTone } from '../../../base/badge';\nimport { Card } from '../../../base/cards';\nimport { ScrollArea, VisuallyHidden } from '../../../base/display';\nimport { ErrorState } from '../../../base/feedback';\nimport { Item, ItemActions, ItemContent, ItemDescription, ItemTitle } from '../../../base/item';\nimport { Skeleton } from '../../../base/skeleton';\nimport { Stack } from '../../../base/structure';\nimport { formatInitials } from '../../../primitives';\nimport { Heading, Text } from '../../../typography';\nimport {headingRoleSizes} from '../../../typography/text.styles';\nimport { EmptyState } from '../../../blocks/data-display';\nimport { focusRecipes } from '../../../../lib/focus-recipes';\nimport { interactionRecipes } from '../../../../lib/interaction-recipes';\nimport { toneRecipes } from '../../../../lib/tone-recipes';\nimport { cn } from '../../../../lib/utils';\n\nimport type {\n\tAppointment,\n\tAppointmentCalendarStrings,\n\tAppointmentCategory,\n\tAppointmentRenderContext,\n\tAppointmentStatus,\n} from '../appointment-calendar.types';\nimport {\n\tappointmentCategoryColorClasses,\n\tappointmentsOn,\n\tcategoryColor,\n\tformatTime,\n\tpersonName,\n} from '../appointment-calendar.utils';\n\n/** Status chip tones. Completed and cancelled are history, not a state to act on. */\nconst STATUS_TONE: Record<AppointmentStatus, BadgeTone> = {\n\tconfirmed: 'success',\n\tpending: 'warning',\n\tcompleted: 'neutral',\n\tcancelled: 'neutral',\n\tnoShow: 'destructive',\n};\n\nexport interface AppointmentAgendaProps {\n\t/** The days to list: one for the day view, seven for the week view. */\n\tdays: Date[];\n\t/** Appointments after the category and staff filters. */\n\tappointments: Appointment[];\n\tcategories: AppointmentCategory[];\n\t/** Ids of appointments that overlap another booking for the same staff member. */\n\tconflicts: Set<string>;\n\theading: string;\n\tloading: boolean;\n\terror?: ReactNode | Error;\n\tonRetry?: () => void;\n\tlocale?: string;\n\tonAppointmentClick?: (appointment: Appointment) => void;\n\tappointmentActions?: (appointment: Appointment) => readonly ActionMenuAction[];\n\trenderAppointment?: (appointment: Appointment, context: AppointmentRenderContext) => ReactNode;\n\tstrings: AppointmentCalendarStrings;\n}\n\ntype RowContext = Omit<AppointmentRenderContext, 'defaultRender'>;\n\n/** The built-in row, drawn from the same context a custom row receives. */\nfunction AppointmentRow({ appointment, context }: { appointment: Appointment; context: RowContext }) {\n\tconst id = useId();\n\tconst client = personName(appointment.client);\n\tconst staff = appointment.staff;\n\tconst { open, conflict } = context;\n\tconst hasActions = context.actions.length > 0;\n\t// The open button is named by the row's own visible copy and the staff name,\n\t// one part per id so the title and its chip read as separate words.\n\tconst labelledBy = [`${id}-title`, `${id}-status`, `${id}-detail`, staff && `${id}-staff`].filter(Boolean).join(' ');\n\tconst openRef = useRef<HTMLButtonElement>(null);\n\tconst actionsHadFocus = useRef(false);\n\n\t// A command can remove the row's last action, and the menu trigger with it.\n\t// Focus then returns to the row's open button instead of falling to the page.\n\tuseLayoutEffect(() => {\n\t\tif (hasActions || !actionsHadFocus.current) return;\n\t\tactionsHadFocus.current = false;\n\t\tif (!document.activeElement || document.activeElement === document.body) openRef.current?.focus();\n\t}, [hasActions]);\n\n\treturn (\n\t\t<Item\n\t\t\tvariant=\"outline\"\n\t\t\tsize=\"sm\"\n\t\t\tpadding=\"default\"\n\t\t\tdata-status={appointment.status}\n\t\t\tdata-conflict={conflict ? '' : undefined}\n\t\t\tclassName={cn(\n\t\t\t\t'appointment-agenda--row relative w-full flex-nowrap',\n\t\t\t\t!!open && interactionRecipes.rowHover,\n\t\t\t\tconflict && cn(toneRecipes.destructive.wash, toneRecipes.destructive.edge),\n\t\t\t)}\n\t\t>\n\t\t\t{!!open && (\n\t\t\t\t<button\n\t\t\t\t\tref={openRef}\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-labelledby={labelledBy}\n\t\t\t\t\tonClick={open}\n\t\t\t\t\tclassName={cn('appointment-agenda--open absolute inset-0 z-0 cursor-pointer rounded-radius focus-visible:outline-none', interactionRecipes.nativeButtonReset, focusRecipes.inset)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t\t{/* The category stripe: a categorical mark, so it draws from the chart palette. */}\n\t\t\t<span aria-hidden=\"true\" className={cn('appointment-agenda--stripe w-1 shrink-0 self-stretch rounded-full', context.categoryColorClass)} />\n\t\t\t<ItemContent className=\"min-w-0\">\n\t\t\t\t<ItemTitle className=\"flex-wrap\">\n\t\t\t\t\t<Text type=\"inherit\" id={`${id}-title`} tag=\"span\" weight=\"medium\" className=\"truncate\">{appointment.title}</Text>\n\t\t\t\t\t<Badge id={`${id}-status`} tone={context.statusTone} size=\"sm\">\n\t\t\t\t\t\t{context.statusLabel}\n\t\t\t\t\t</Badge>\n\t\t\t\t</ItemTitle>\n\t\t\t\t<ItemDescription id={`${id}-detail`} clamp={1}>\n\t\t\t\t\t{client ? `${context.time} · ${client}` : context.time}\n\t\t\t\t</ItemDescription>\n\t\t\t</ItemContent>\n\t\t\t{(!!staff || hasActions) && (\n\t\t\t\t<ItemActions\n\t\t\t\t\t// React focus events bubble from the portaled menu, so this tracks the trigger and its menu together.\n\t\t\t\t\tonFocus={() => { actionsHadFocus.current = true; }}\n\t\t\t\t\tonBlur={(event) => {\n\t\t\t\t\t\tif (event.relatedTarget instanceof Node && !event.currentTarget.contains(event.relatedTarget)) actionsHadFocus.current = false;\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t{!!staff && (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<VisuallyHidden><span id={`${id}-staff`}>{staff.name}</span></VisuallyHidden>\n\t\t\t\t\t\t\t<Avatar size=\"sm\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t{!!staff.avatarUrl && <AvatarImage src={staff.avatarUrl} alt=\"\" />}\n\t\t\t\t\t\t\t\t<AvatarFallback>{formatInitials(staff.name)}</AvatarFallback>\n\t\t\t\t\t\t\t</Avatar>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t\t{context.actionsMenu}\n\t\t\t\t</ItemActions>\n\t\t\t)}\n\t\t</Item>\n\t);\n}\n\nexport function AppointmentAgenda({ days, appointments, categories, conflicts, heading, loading, error, onRetry, locale, onAppointmentClick, appointmentActions, renderAppointment, strings }: AppointmentAgendaProps) {\n\tconst groups = days.map((day) => ({ day, items: appointmentsOn(appointments, day) }));\n\tconst total = groups.reduce((sum, group) => sum + group.items.length, 0);\n\tconst dayFormat = new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric' });\n\tconst grouped = days.length > 1;\n\n\t// One context per appointment: the built-in row draws from it, and a custom\n\t// row receives the same values, so both stay consistent.\n\tconst contextFor = (appointment: Appointment): AppointmentRenderContext => {\n\t\tconst conflict = conflicts.has(appointment.id);\n\t\tconst actions = (appointmentActions?.(appointment) ?? []).filter((action) => action.visible !== false);\n\t\tconst context: RowContext = {\n\t\t\tcategory: categories.find((category) => category.id === appointment.category),\n\t\t\tcategoryColorClass: appointmentCategoryColorClasses[categoryColor(categories, appointment.category)],\n\t\t\tconflict,\n\t\t\tstatusLabel: conflict ? strings.conflict : strings.status[appointment.status],\n\t\t\tstatusTone: conflict ? 'destructive' : STATUS_TONE[appointment.status],\n\t\t\ttime: strings.formatTimeRange(formatTime(appointment.start, locale), formatTime(appointment.end, locale)),\n\t\t\topen: onAppointmentClick ? () => onAppointmentClick(appointment) : undefined,\n\t\t\tactions,\n\t\t\t// Above a stretched open button, so the menu takes its own clicks.\n\t\t\tactionsMenu: actions.length > 0 ? (\n\t\t\t\t<ActionMenu\n\t\t\t\t\tactions={actions}\n\t\t\t\t\tsrText={strings.formatActionsLabel(appointment.title)}\n\t\t\t\t\tbuttonProps={{ size: 'sm', className: 'appointment-agenda--actions relative z-10' }}\n\t\t\t\t/>\n\t\t\t) : null,\n\t\t};\n\t\treturn { ...context, defaultRender: () => <AppointmentRow appointment={appointment} context={context} /> };\n\t};\n\n\tconst list = (items: Appointment[]) => (\n\t\t<Stack render={<ul />} gap=\"sm\" className=\"appointment-agenda--list m-0 list-none p-0\">\n\t\t\t{items.map((appointment) => {\n\t\t\t\tconst context = contextFor(appointment);\n\t\t\t\treturn (\n\t\t\t\t\t<li key={appointment.id} className=\"min-w-0\">\n\t\t\t\t\t\t{renderAppointment ? renderAppointment(appointment, context) : context.defaultRender()}\n\t\t\t\t\t</li>\n\t\t\t\t);\n\t\t\t})}\n\t\t</Stack>\n\t);\n\n\tlet body;\n\tif (loading) {\n\t\tbody = (\n\t\t\t<Stack gap=\"sm\" aria-busy=\"true\" className=\"appointment-agenda--loading\">\n\t\t\t\t<VisuallyHidden>{strings.loading}</VisuallyHidden>\n\t\t\t\t{Array.from({ length: 4 }, (_, index) => <Skeleton key={index} className=\"h-control-lg w-full rounded-radius\" />)}\n\t\t\t</Stack>\n\t\t);\n\t} else if (error) {\n\t\t// An app's own element replaces the default; a message becomes its description.\n\t\tbody = isValidElement(error) ? error : (\n\t\t\t<ErrorState\n\t\t\t\tvariant=\"inline\"\n\t\t\t\ttitle={strings.errorTitle}\n\t\t\t\tdescription={error instanceof Error ? error.message : typeof error === 'string' || typeof error === 'number' ? String(error) : strings.errorDescription}\n\t\t\t\tonRetry={onRetry}\n\t\t\t\tretryLabel={strings.retry}\n\t\t\t\tclassName=\"appointment-agenda--error\"\n\t\t\t/>\n\t\t);\n\t} else if (total === 0) {\n\t\tbody = <EmptyState padding=\"sm\" title={strings.empty} description={false} ariaLabel={strings.empty} className=\"appointment-agenda--empty\" />;\n\t} else if (grouped) {\n\t\tbody = (\n\t\t\t<Stack gap=\"xl\">\n\t\t\t\t{groups.filter((group) => group.items.length > 0).map((group) => (\n\t\t\t\t\t<Stack key={group.day.toISOString()} render={<section />} gap=\"sm\" aria-label={dayFormat.format(group.day)} className=\"appointment-agenda--day\">\n\t\t\t\t\t\t<Heading className=\"text-inherit\" tag=\"h3\" size={headingRoleSizes.subsection}>{dayFormat.format(group.day)}</Heading>\n\t\t\t\t\t\t{list(group.items)}\n\t\t\t\t\t</Stack>\n\t\t\t\t))}\n\t\t\t</Stack>\n\t\t);\n\t} else {\n\t\tbody = list(groups[0]?.items ?? []);\n\t}\n\n\treturn (\n\t\t<Card\n\t\t\tsurface=\"card\"\n\t\t\ttitle={heading}\n\t\t\t// The count is unknown while loading or after a failed load, so it is left out rather than read as zero.\n\t\t\theaderEnd={loading || error ? undefined : <Text size=\"xs\" type=\"secondary\" className=\"tabular-nums\">{strings.formatCount(total)}</Text>}\n\t\t\tclassName=\"appointment-agenda--component h-full min-h-0\"\n\t\t\tcontentClassName=\"min-h-0 flex-1\"\n\t\t>\n\t\t\t<ScrollArea className=\"appointment-agenda--scroll h-full min-h-0\">\n\t\t\t\t{body}\n\t\t\t</ScrollArea>\n\t\t</Card>\n\t);\n}\n","/**\n * AppointmentMonth — the compact month beside the agenda: month and year\n * selects with previous/next, and a day grid whose dots show which categories\n * are booked that day. The grid is one tab stop: arrow keys move by a day or a\n * week, Home/End to the week's edges, PageUp/PageDown by a month, and Enter or\n * Space chooses the focused day. Private to the appointment calendar.\n */\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\nimport { useEffect, useMemo, useRef, useState, type KeyboardEvent } from 'react';\n\nimport { Button } from '../../../base/buttons';\nimport { Select } from '../../../base/choice-inputs';\nimport { Stack } from '../../../base/structure';\nimport { Text } from '../../../typography';\nimport { focusRecipes } from '../../../../lib/focus-recipes';\nimport { interactionRecipes } from '../../../../lib/interaction-recipes';\nimport { dotRecipes } from '../../../../lib/tone-recipes';\nimport { cn } from '../../../../lib/utils';\n\nimport type { Appointment, AppointmentCalendarStrings, AppointmentCategory } from '../appointment-calendar.types';\nimport {\n\taddDays,\n\taddMonths,\n\tappointmentCategoryColorClasses,\n\tappointmentsOn,\n\tcategoryColor,\n\tisSameDay,\n\tmonthGrid,\n\tstartOfWeek,\n} from '../appointment-calendar.utils';\n\nexport interface AppointmentMonthProps {\n\tselected: Date;\n\tonSelect: (date: Date) => void;\n\t/** The first day of the month on screen, which keyboard focus can move away from the selection. */\n\tonVisibleMonthChange?: (month: Date) => void;\n\tappointments: Appointment[];\n\tcategories: AppointmentCategory[];\n\tweekStartsOn: number;\n\tlocale?: string;\n\tstrings: AppointmentCalendarStrings;\n}\n\n/** Days with this many categories or more show only the first three dots. */\nconst MAX_DOTS = 3;\n\nexport function AppointmentMonth({ selected, onSelect, onVisibleMonthChange, appointments, categories, weekStartsOn, locale, strings }: AppointmentMonthProps) {\n\tconst [focused, setFocused] = useState(selected);\n\tconst gridRef = useRef<HTMLDivElement>(null);\n\tconst focusOnRender = useRef(false);\n\tconst today = useMemo(() => new Date(), []);\n\n\t// The roving focus follows the selection when it changes from outside.\n\tuseEffect(() => setFocused(selected), [selected]);\n\tconst visibleMonth = focused.getFullYear() * 12 + focused.getMonth();\n\tuseEffect(() => {\n\t\tonVisibleMonthChange?.(new Date(Math.floor(visibleMonth / 12), visibleMonth % 12, 1));\n\t}, [visibleMonth, onVisibleMonthChange]);\n\tuseEffect(() => {\n\t\tif (!focusOnRender.current) return;\n\t\tfocusOnRender.current = false;\n\t\tgridRef.current?.querySelector<HTMLButtonElement>('[data-focus-target]')?.focus();\n\t}, [focused]);\n\n\tconst weeks = useMemo(() => monthGrid(focused, weekStartsOn), [focused, weekStartsOn]);\n\tconst monthFormat = useMemo(() => new Intl.DateTimeFormat(locale, { month: 'long' }), [locale]);\n\tconst weekdayFormat = useMemo(() => new Intl.DateTimeFormat(locale, { weekday: 'short' }), [locale]);\n\tconst dayFormat = useMemo(() => new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }), [locale]);\n\tconst monthOptions = useMemo(() => Array.from({ length: 12 }, (_, month) => ({ value: String(month), label: monthFormat.format(new Date(2000, month, 1)) })), [monthFormat]);\n\tconst yearOptions = useMemo(() => {\n\t\tconst years = new Set<number>([today.getFullYear(), focused.getFullYear()]);\n\t\tfor (const appointment of appointments) years.add(appointment.start.getFullYear());\n\t\tconst min = Math.min(...years) - 1;\n\t\tconst max = Math.max(...years) + 1;\n\t\treturn Array.from({ length: max - min + 1 }, (_, index) => ({ value: String(min + index), label: String(min + index) }));\n\t}, [appointments, focused, today]);\n\n\tconst moveTo = (date: Date, select = false) => {\n\t\tfocusOnRender.current = true;\n\t\tsetFocused(date);\n\t\tif (select) onSelect(date);\n\t};\n\tconst changeMonth = (months: number) => {\n\t\tconst next = addMonths(selected, months);\n\t\tsetFocused(next);\n\t\tonSelect(next);\n\t};\n\n\tconst onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n\t\tconst moves: Record<string, () => Date> = {\n\t\t\tArrowLeft: () => addDays(focused, -1),\n\t\t\tArrowRight: () => addDays(focused, 1),\n\t\t\tArrowUp: () => addDays(focused, -7),\n\t\t\tArrowDown: () => addDays(focused, 7),\n\t\t\tHome: () => startOfWeek(focused, weekStartsOn),\n\t\t\tEnd: () => addDays(startOfWeek(focused, weekStartsOn), 6),\n\t\t\tPageUp: () => addMonths(focused, -1),\n\t\t\tPageDown: () => addMonths(focused, 1),\n\t\t};\n\t\tconst move = moves[event.key];\n\t\tif (!move) return;\n\t\tevent.preventDefault();\n\t\tmoveTo(move());\n\t};\n\n\treturn (\n\t\t<Stack gap=\"lg\" className=\"appointment-month--component min-w-0\">\n\t\t\t<div className=\"appointment-month--header flex min-w-0 items-center gap-space-xs\">\n\t\t\t\t<Button type=\"button\" tone=\"secondary\" buttonStyle=\"ghost\" size=\"sm\" iconOnly aria-label={strings.previousMonth} onClick={() => changeMonth(-1)}>\n\t\t\t\t\t<ChevronLeft aria-hidden=\"true\" className=\"size-icon\" />\n\t\t\t\t</Button>\n\t\t\t\t<Select\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\taria-label={strings.monthLabel}\n\t\t\t\t\toptions={monthOptions}\n\t\t\t\t\tvalue={String(selected.getMonth())}\n\t\t\t\t\tonValueChange={(value) => value !== undefined && changeMonth(Number(value) - selected.getMonth())}\n\t\t\t\t\tclassName=\"min-w-0 flex-1\"\n\t\t\t\t/>\n\t\t\t\t<Select\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\taria-label={strings.yearLabel}\n\t\t\t\t\toptions={yearOptions}\n\t\t\t\t\tvalue={String(selected.getFullYear())}\n\t\t\t\t\tonValueChange={(value) => value !== undefined && changeMonth((Number(value) - selected.getFullYear()) * 12)}\n\t\t\t\t\tclassName=\"min-w-0 flex-1\"\n\t\t\t\t/>\n\t\t\t\t<Button type=\"button\" tone=\"secondary\" buttonStyle=\"ghost\" size=\"sm\" iconOnly aria-label={strings.nextMonth} onClick={() => changeMonth(1)}>\n\t\t\t\t\t<ChevronRight aria-hidden=\"true\" className=\"size-icon\" />\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tref={gridRef}\n\t\t\t\trole=\"grid\"\n\t\t\t\taria-label={`${monthFormat.format(focused)} ${focused.getFullYear()}`}\n\t\t\t\tonKeyDown={onKeyDown}\n\t\t\t\tclassName=\"appointment-month--grid grid min-w-0 grid-cols-7 gap-space-2xs\"\n\t\t\t>\n\t\t\t\t<div role=\"row\" className=\"contents\">\n\t\t\t\t\t{weeks[0]?.map((day) => (\n\t\t\t\t\t\t<Text key={day.getDay()} tag=\"div\" role=\"columnheader\" size=\"xs\" type=\"secondary\" weight=\"medium\" align=\"center\" className=\"appointment-month--weekday py-space-xs\">\n\t\t\t\t\t\t\t{weekdayFormat.format(day)}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t\t{weeks.map((week) => (\n\t\t\t\t\t<div key={week[0]?.toISOString()} role=\"row\" className=\"contents\">\n\t\t\t\t\t\t{week.map((day) => {\n\t\t\t\t\t\t\tconst dayAppointments = appointmentsOn(appointments, day);\n\t\t\t\t\t\t\tconst dayCategories = [...new Set(dayAppointments.map((appointment) => appointment.category))];\n\t\t\t\t\t\t\tconst isSelected = isSameDay(day, selected);\n\t\t\t\t\t\t\tconst isFocused = isSameDay(day, focused);\n\t\t\t\t\t\t\tconst outside = day.getMonth() !== focused.getMonth();\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={day.toISOString()} role=\"gridcell\" aria-selected={isSelected} className=\"flex min-w-0 justify-center\">\n\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\ttabIndex={isFocused ? 0 : -1}\n\t\t\t\t\t\t\t\t\t\tdata-focus-target={isFocused ? '' : undefined}\n\t\t\t\t\t\t\t\t\t\tdata-selected={isSelected ? '' : undefined}\n\t\t\t\t\t\t\t\t\t\tdata-outside={outside ? '' : undefined}\n\t\t\t\t\t\t\t\t\t\taria-current={isSameDay(day, today) ? 'date' : undefined}\n\t\t\t\t\t\t\t\t\t\taria-label={strings.formatDayLabel(dayFormat.format(day), dayAppointments.length)}\n\t\t\t\t\t\t\t\t\t\tonClick={() => moveTo(day, true)}\n\t\t\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\t\tinteractionRecipes.nativeButtonReset,\n\t\t\t\t\t\t\t\t\t\t\t'appointment-month--day relative flex size-action flex-col items-center justify-center rounded-radius text-sm tabular-nums outline-none',\n\t\t\t\t\t\t\t\t\t\t\tfocusRecipes.edge,\n\t\t\t\t\t\t\t\t\t\t\tisSelected\n\t\t\t\t\t\t\t\t\t\t\t\t? 'bg-primary font-semibold text-primary-foreground'\n\t\t\t\t\t\t\t\t\t\t\t\t: cn(interactionRecipes.rowHover, outside ? 'text-muted-foreground' : 'text-foreground'),\n\t\t\t\t\t\t\t\t\t\t\t!isSelected && isSameDay(day, today) && 'font-semibold',\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{day.getDate()}\n\t\t\t\t\t\t\t\t\t\t{dayCategories.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t\t<span aria-hidden=\"true\" className=\"appointment-month--dots absolute inset-x-0 bottom-space-2xs flex justify-center gap-space-2xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{dayCategories.slice(0, MAX_DOTS).map((category) => (\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span key={category} className={cn(dotRecipes.inline, appointmentCategoryColorClasses[categoryColor(categories, category)])} />\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</span>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</div>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</Stack>\n\t);\n}\n","/**\n * AppointmentCalendar — a booking calendar laid out side by side: a compact\n * month with category dots and filters beside the agenda for the chosen day\n * or week.\n *\n * The header carries the title with booked and conflict counts, the Day/Week\n * switch, an optional staff filter and the \"New appointment\" command. Two\n * overlapping appointments for one staff member are a conflict: both rows say\n * so, and a dismissible alert names who is double-booked and when. Categories\n * are kinds, so their stripes and dots draw from the chart palette, and status\n * chips keep the status tones. The layout follows its own container: the month\n * sits beside the agenda when there is room and above it otherwise.\n *\n * Data, creation and editing stay with the app: the calendar formats and\n * filters the appointments it is given and reports intent through callbacks.\n */\nimport {compositionClasses} from '../../base/structure/composition.recipes';\nimport { Plus, TriangleAlert } from 'lucide-react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Button } from '../../base/buttons';\nimport { Card } from '../../base/cards';\nimport { Select } from '../../base/choice-inputs';\nimport { Alert, AlertAction, AlertDescription, AlertTitle } from '../../base/feedback';\nimport { Tabs, TabsList, TabsTrigger } from '../../base/navigation/tabs';\nimport { Stack } from '../../base/structure';\nimport { Heading, Text } from '../../typography';\nimport { useStrings } from '../../../lib/strings';\nimport { dotRecipes } from '../../../lib/tone-recipes';\nimport { useDatesConfig, useFormattingConfig } from '../../../lib/ui-provider';\nimport { cn } from '../../../lib/utils';\n\nimport {\n\tdefaultAppointmentCalendarStrings,\n\ttype Appointment,\n\ttype AppointmentCalendarProps,\n\ttype AppointmentCalendarView,\n\ttype AppointmentConflict,\n\ttype AppointmentDateRange,\n} from './appointment-calendar.types';\nimport {\n\taddDays,\n\tappointmentCategoryColorClasses,\n\tcategoryColor,\n\tconflictingIds,\n\tfilterAppointments,\n\tfindConflicts,\n\tformatTime,\n\tmonthGrid,\n\toccursOn,\n\tstaffFrom,\n\tstartOfDay,\n\tweekDays,\n} from './appointment-calendar.utils';\nimport { AppointmentAgenda, type AppointmentAgendaProps } from './partials/appointment-agenda';\nimport { AppointmentMonth } from './partials/appointment-month';\n\n/** Controlled when `value` is given, otherwise local state seeded by `fallback`. */\nfunction useControllable<T>(value: T | undefined, fallback: T, onChange?: (next: T) => void): [T, (next: T) => void] {\n\tconst [local, setLocal] = useState(fallback);\n\tconst current = value ?? local;\n\treturn [current, (next: T) => {\n\t\tif (value === undefined) setLocal(next);\n\t\tonChange?.(next);\n\t}];\n}\n\nexport function AppointmentCalendar<T extends Appointment = Appointment>({\n\tappointments,\n\tcategories,\n\tstaff: staffProp,\n\ttitle,\n\tdate: dateProp,\n\tdefaultDate,\n\tonDateChange,\n\tview: viewProp,\n\tdefaultView = 'day',\n\tonViewChange,\n\tcategory: categoryProp,\n\tdefaultCategory = 'all',\n\tonCategoryChange,\n\tstaffId: staffIdProp,\n\tdefaultStaffId = 'all',\n\tonStaffChange,\n\tonAppointmentClick,\n\tappointmentActions,\n\trenderAppointment,\n\tonRangeChange,\n\tonCreateAppointment,\n\tonConflictsDismiss,\n\tloading = false,\n\terror,\n\tonRetry,\n\tweekStartsOn: weekStartsOnProp,\n\tstrings: stringsProp,\n\tclassName,\n}: AppointmentCalendarProps<T>) {\n\tconst strings = useStrings(defaultAppointmentCalendarStrings, stringsProp);\n\tconst { locale } = useFormattingConfig();\n\tconst dates = useDatesConfig();\n\tconst weekStartsOn = weekStartsOnProp ?? dates.weekStartsOn ?? 0;\n\n\tconst [date, setDate] = useControllable(dateProp, defaultDate ?? startOfDay(new Date()), onDateChange);\n\tconst [view, setView] = useControllable<AppointmentCalendarView>(viewProp, defaultView, onViewChange);\n\tconst [category, setCategory] = useControllable(categoryProp, defaultCategory, onCategoryChange);\n\tconst [staffId, setStaffId] = useControllable(staffIdProp, defaultStaffId, onStaffChange);\n\tconst [dismissed, setDismissed] = useState<string>('');\n\tconst [visibleMonth, setVisibleMonth] = useState(() => new Date(date.getFullYear(), date.getMonth(), 1));\n\n\tconst staff = useMemo(() => staffProp ?? staffFrom(appointments), [staffProp, appointments]);\n\tconst days = useMemo(() => (view === 'week' ? weekDays(date, weekStartsOn) : [startOfDay(date)]), [view, date, weekStartsOn]);\n\tconst visible = useMemo(() => filterAppointments(appointments, category, staffId), [appointments, category, staffId]);\n\t// The days on screen: the month grid, widened by the agenda when keyboard\n\t// focus has moved the month away from the selected day or week.\n\tconst range = useMemo<AppointmentDateRange>(() => {\n\t\tconst edges = [...monthGrid(visibleMonth, weekStartsOn).flat(), ...days].map((day) => day.getTime());\n\t\treturn { start: new Date(Math.min(...edges)), end: addDays(new Date(Math.max(...edges)), 1) };\n\t}, [visibleMonth, weekStartsOn, days]);\n\tconst reportedRange = useRef('');\n\tuseEffect(() => {\n\t\tconst key = `${range.start.getTime()}:${range.end.getTime()}`;\n\t\tif (key === reportedRange.current) return;\n\t\treportedRange.current = key;\n\t\tonRangeChange?.(range);\n\t}, [range, onRangeChange]);\n\tconst inRange = useMemo(() => visible.filter((appointment) => days.some((day) => occursOn(appointment, day))), [visible, days]);\n\n\t// A staff member is double-booked whatever the category filter shows, so\n\t// overlaps are found across every category, then narrowed to the range.\n\tconst conflicts = useMemo(() => {\n\t\tconst staffScoped = filterAppointments(appointments, 'all', staffId).filter((appointment) => days.some((day) => occursOn(appointment, day)));\n\t\treturn findConflicts(staffScoped);\n\t}, [appointments, staffId, days]);\n\tconst conflictIds = useMemo(() => conflictingIds(conflicts), [conflicts]);\n\tconst visibleConflicts = inRange.filter((appointment) => conflictIds.has(appointment.id)).length;\n\tconst booked = inRange.filter((appointment) => appointment.status !== 'cancelled').length;\n\tconst conflictKey = [...conflictIds].sort().join('|');\n\tconst showAlert = conflicts.length > 0 && dismissed !== conflictKey;\n\n\tconst headingFormat = new Intl.DateTimeFormat(locale, { weekday: 'long', month: 'long', day: 'numeric' });\n\tconst rangeFormat = new Intl.DateTimeFormat(locale, { month: 'long', day: 'numeric' });\n\tconst heading = view === 'week'\n\t\t? strings.formatWeekRange(rangeFormat.format(days[0] ?? date), rangeFormat.format(days[days.length - 1] ?? date))\n\t\t: headingFormat.format(date);\n\n\tconst dismissConflicts = (shown: AppointmentConflict<T>[]) => {\n\t\tsetDismissed(conflictKey);\n\t\tonConflictsDismiss?.(shown);\n\t};\n\n\treturn (\n\t\t<Stack gap=\"xl\" data-slot=\"appointment-calendar\" data-view={view} className={cn('appointment-calendar--component @container/appointment-calendar min-h-0 min-w-0', className)}>\n\t\t\t<div className=\"appointment-calendar--header flex min-w-0 flex-wrap items-start justify-between gap-space-lg\">\n\t\t\t\t<Stack gap=\"xs\" className=\"min-w-0\">\n\t\t\t\t\t{!!title && <Heading className=\"text-inherit\" tag=\"h2\" size=\"lg\">{title}</Heading>}\n\t\t\t\t\t{/* Counts are unknown until the range loads; a zero here would read as a real empty day. */}\n\t\t\t\t\t{!loading && !error && (\n\t\t\t\t\t\t<Text size=\"xs\" type=\"secondary\" className=\"appointment-calendar--counts tabular-nums\">\n\t\t\t\t\t\t\t{strings.formatBooked(booked)}\n\t\t\t\t\t\t\t{visibleConflicts > 0 && ` · ${strings.formatConflicts(visibleConflicts)}`}\n\t\t\t\t\t\t</Text>\n\t\t\t\t\t)}\n\t\t\t\t</Stack>\n\t\t\t\t<div className={cn('appointment-calendar--actions flex min-w-0 flex-wrap items-center', compositionClasses.commands)}>\n\t\t\t\t\t<Tabs value={view} onValueChange={(next) => (next === 'day' || next === 'week') && setView(next)}>\n\t\t\t\t\t\t<TabsList role=\"group\" aria-label={strings.viewLabel} aria-orientation={undefined} activateOnFocus>\n\t\t\t\t\t\t\t{(['day', 'week'] as const).map((option) => (\n\t\t\t\t\t\t\t\t<TabsTrigger key={option} value={option} role=\"button\" aria-selected={undefined} aria-controls={undefined} aria-pressed={view === option}>\n\t\t\t\t\t\t\t\t\t{strings[option]}\n\t\t\t\t\t\t\t\t</TabsTrigger>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</TabsList>\n\t\t\t\t\t</Tabs>\n\t\t\t\t\t{staff.length > 0 && (\n\t\t\t\t\t\t<Select\n\t\t\t\t\t\t\taria-label={strings.staffLabel}\n\t\t\t\t\t\t\toptions={[{ value: 'all', label: strings.allStaff }, ...staff.map((person) => ({ value: person.id, label: person.name }))]}\n\t\t\t\t\t\t\tvalue={staffId}\n\t\t\t\t\t\t\tonValueChange={(next) => setStaffId(next ?? 'all')}\n\t\t\t\t\t\t\tclassName=\"appointment-calendar--staff w-44\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t\t{!!onCreateAppointment && (\n\t\t\t\t\t\t<Button type=\"button\" tone=\"primary\" onClick={() => onCreateAppointment(date)} className=\"appointment-calendar--create\">\n\t\t\t\t\t\t\t<Plus aria-hidden=\"true\" className=\"size-icon\" />\n\t\t\t\t\t\t\t{strings.newAppointment}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{showAlert && (\n\t\t\t\t<Alert tone=\"destructive\" className=\"appointment-calendar--alert\">\n\t\t\t\t\t<TriangleAlert aria-hidden=\"true\" />\n\t\t\t\t\t<AlertTitle>{strings.conflictTitle}</AlertTitle>\n\t\t\t\t\t<AlertDescription>\n\t\t\t\t\t\t{conflicts.map((conflict) => strings.formatConflict(conflict.staff.name, conflict.appointments.length, formatTime(conflict.start, locale))).join(' ')}\n\t\t\t\t\t</AlertDescription>\n\t\t\t\t\t<AlertAction>\n\t\t\t\t\t\t<Button type=\"button\" size=\"sm\" onClick={() => dismissConflicts(conflicts)}>{strings.dismiss}</Button>\n\t\t\t\t\t</AlertAction>\n\t\t\t\t</Alert>\n\t\t\t)}\n\n\t\t\t<div className=\"appointment-calendar--body grid min-h-0 min-w-0 flex-1 gap-space-xl @3xl/appointment-calendar:grid-cols-[minmax(17rem,20rem)_minmax(0,1fr)]\">\n\t\t\t\t<Card surface=\"card\" className=\"appointment-calendar--aside min-w-0 self-start\">\n\t\t\t\t\t<Stack gap=\"xl\">\n\t\t\t\t\t\t<AppointmentMonth\n\t\t\t\t\t\t\tselected={date}\n\t\t\t\t\t\t\tonSelect={setDate}\n\t\t\t\t\t\t\tonVisibleMonthChange={setVisibleMonth}\n\t\t\t\t\t\t\tappointments={visible}\n\t\t\t\t\t\t\tcategories={categories}\n\t\t\t\t\t\t\tweekStartsOn={weekStartsOn}\n\t\t\t\t\t\t\tlocale={locale}\n\t\t\t\t\t\t\tstrings={strings}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{categories.length > 0 && (\n\t\t\t\t\t\t\t<Tabs value={category} onValueChange={(next) => typeof next === 'string' && setCategory(next)}>\n\t\t\t\t\t\t\t\t<TabsList variant=\"chips\" role=\"group\" aria-label={strings.categoriesLabel} aria-orientation={undefined} activateOnFocus>\n\t\t\t\t\t\t\t\t\t{[{ id: 'all', label: strings.allCategories }, ...categories].map((option) => (\n\t\t\t\t\t\t\t\t\t\t<TabsTrigger key={option.id} value={option.id} role=\"button\" aria-selected={undefined} aria-controls={undefined} aria-pressed={category === option.id} className=\"appointment-calendar--category gap-space-xs\">\n\t\t\t\t\t\t\t\t\t\t\t{option.id !== 'all' && (\n\t\t\t\t\t\t\t\t\t\t\t\t<span aria-hidden=\"true\" className={cn(dotRecipes.inline, appointmentCategoryColorClasses[categoryColor(categories, option.id)])} />\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t\t\t\t</TabsTrigger>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</TabsList>\n\t\t\t\t\t\t\t</Tabs>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Stack>\n\t\t\t\t</Card>\n\n\t\t\t\t<AppointmentAgenda\n\t\t\t\t\tdays={days}\n\t\t\t\t\tappointments={visible}\n\t\t\t\t\tcategories={categories}\n\t\t\t\t\tconflicts={conflictIds}\n\t\t\t\t\theading={heading}\n\t\t\t\t\tloading={loading}\n\t\t\t\t\terror={error}\n\t\t\t\t\tonRetry={onRetry}\n\t\t\t\t\tlocale={locale}\n\t\t\t\t\t// The agenda only hands back items from `appointments`, so the app's own type holds.\n\t\t\t\t\tonAppointmentClick={onAppointmentClick as ((appointment: Appointment) => void) | undefined}\n\t\t\t\t\tappointmentActions={appointmentActions as AppointmentAgendaProps['appointmentActions']}\n\t\t\t\t\trenderAppointment={renderAppointment as AppointmentAgendaProps['renderAppointment']}\n\t\t\t\t\tstrings={strings}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</Stack>\n\t);\n}\n\nAppointmentCalendar.displayName = 'AppointmentCalendar';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoIA,IAAawC,KAAgE;CAC5E,eAAe,MAAU,GAAGC,EAAM;CAClC,kBAAkB,MAAWA,MAAU,IAAI,eAAe,GAAGA,EAAM;CACnE,WAAW;CACX,KAAK;CACL,MAAM;CACN,YAAY;CACZ,UAAU;CACV,gBAAgB;CAChB,eAAe;CACf,iBAAiB,GAAW,GAAO,MAAS,GAAGC,EAAU,OAAOD,EAAM,2BAA2BE,EAAK;CACtG,SAAS;CACT,eAAe;CACf,WAAW;CACX,YAAY;CACZ,WAAW;CACX,iBAAiB;CACjB,eAAe;CACf,cAAc,MAAWF,MAAU,IAAI,kBAAkB,GAAGA,EAAM;CAClE,kBAAkB,GAAO,MAAQ,GAAGG,EAAM,MAAMC;CAChD,iBAAiB,GAAM,MAAWJ,MAAU,IAAIK,IAAO,GAAGA,EAAK,IAAIL,MAAU,IAAI,kBAAkB,GAAGA,EAAM;CAC5G,kBAAkB,GAAO,MAAQ,GAAGG,EAAM,MAAMC;CAChD,QAAQ;EAAE,WAAW;EAAa,SAAS;EAAW,WAAW;EAAa,WAAW;EAAa,QAAQ;CAAU;CACxH,UAAU;CACV,OAAO;CACP,SAAS;CACT,YAAY;CACZ,kBAAkB;CAClB,OAAO;CACP,qBAAqB,MAAU,eAAeE;AAC/C,GCrJMC,IAA2C;CAAC;CAAW;CAAW;CAAW;CAAW;AAAS,GAG1FC,IAA4E;CACxF,WAAW;CACX,WAAW;CACX,WAAW;CACX,WAAW;CACX,WAAW;AACZ;AAGA,SAAgBC,GAAc,GAAmC,GAAsC;CACtG,IAAMC,IAAQC,EAAW,WAAW,MAAaC,EAAS,OAAOC,CAAE;CAEnE,OADIH,IAAQ,IAAU,YACfC,EAAWD,EAAM,EAAE,SAASH,EAAaG,IAAQH,EAAa,WAAW;AACjF;AAEA,SAAgBO,EAAW,GAAkB;CAC5C,OAAO,IAAI,KAAKT,EAAK,YAAY,GAAGA,EAAK,SAAS,GAAGA,EAAK,QAAQ,CAAC;AACpE;AAEA,SAAgBU,EAAQ,GAAY,GAAoB;CACvD,OAAO,IAAI,KAAKV,EAAK,YAAY,GAAGA,EAAK,SAAS,GAAGA,EAAK,QAAQ,IAAIW,CAAI;AAC3E;AAEA,SAAgBC,EAAU,GAAS,GAAkB;CACpD,OAAOC,EAAE,YAAY,MAAMC,EAAE,YAAY,KAAKD,EAAE,SAAS,MAAMC,EAAE,SAAS,KAAKD,EAAE,QAAQ,MAAMC,EAAE,QAAQ;AAC1G;AAGA,SAAgBC,EAAU,GAAY,GAAsB;CAC3D,IAAMC,IAAS,IAAI,KAAKhB,EAAK,YAAY,GAAGA,EAAK,SAAS,IAAIiB,GAAQ,CAAC,GACjEC,IAAU,IAAI,KAAKF,EAAO,YAAY,GAAGA,EAAO,SAAS,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ;CACjF,OAAO,IAAI,KAAKA,EAAO,YAAY,GAAGA,EAAO,SAAS,GAAG,KAAK,IAAIhB,EAAK,QAAQ,GAAGkB,CAAO,CAAC;AAC3F;AAEA,SAAgBC,EAAY,GAAY,GAA4B;CACnE,IAAMC,IAAMX,EAAWT,CAAI;CAC3B,OAAOU,EAAQU,GAAK,GAAGA,EAAI,OAAO,IAAIC,IAAe,KAAK,EAAE;AAC7D;AAGA,SAAgBC,GAAS,GAAY,GAA8B;CAClE,IAAMC,IAAQJ,EAAYnB,GAAMqB,CAAY;CAC5C,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAUX,EAAQa,GAAOlB,CAAK,CAAC;AACrE;AAGA,SAAgBmB,GAAU,GAAY,GAAgC;CACrE,IAAMD,IAAQJ,EAAY,IAAI,KAAKnB,EAAK,YAAY,GAAGA,EAAK,SAAS,GAAG,CAAC,GAAGqB,CAAY;CACxF,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAS,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAQX,EAAQa,GAAOE,IAAO,IAAIL,CAAG,CAAC,CAAC;AACpH;AAGA,SAAgBM,GAAS,GAA0B,GAAoB;CACtE,IAAMC,IAAWlB,EAAWW,CAAG,CAAC,CAAC,QAAQ,GACnCQ,IAASlB,EAAQU,GAAK,CAAC,CAAC,CAAC,QAAQ;CACvC,OAAOS,EAAY,MAAM,QAAQ,IAAID,KAAUC,EAAY,IAAI,QAAQ,IAAIF;AAC5E;AAEA,SAAgBG,EAAsC,GAAmB,GAAgB;CACxF,OAAOC,EACL,QAAQ,MAAgBL,GAASG,GAAaT,CAAG,CAAC,CAAC,CACnD,MAAM,GAAG,MAAMP,EAAE,MAAM,QAAQ,IAAIC,EAAE,MAAM,QAAQ,KAAKD,EAAE,IAAI,QAAQ,IAAIC,EAAE,IAAI,QAAQ,CAAC;AAC5F;AAGA,SAAgBkB,GAA0C,GAAmB,GAAkB,GAAsB;CACpH,OAAOD,EAAa,QAAQ,OAC1BxB,MAAa,SAASsB,EAAY,aAAatB,OAC/C0B,MAAY,SAASJ,EAAY,OAAO,OAAOI,EACjD;AACD;AAOA,SAAgBC,GAAqC,GAA6C;CACjG,IAAMC,oBAAU,IAAI,IAAiB;CACrC,KAAK,IAAMN,KAAeE,GAAc;EACvC,IAAI,CAACF,EAAY,SAASA,EAAY,WAAW,aAAa;EAC9D,IAAMO,IAAOD,EAAQ,IAAIN,EAAY,MAAM,EAAE,KAAK,CAAC;EAEnD,AADAO,EAAK,KAAKP,CAAW,GACrBM,EAAQ,IAAIN,EAAY,MAAM,IAAIO,CAAI;CACvC;CACA,IAAMC,IAAsC,CAAC;CAC7C,KAAK,IAAMD,KAAQD,EAAQ,OAAO,GAAG;EACpC,IAAMG,IAAS,CAAC,GAAGF,CAAI,CAAC,CAAC,MAAM,GAAG,MAAMvB,EAAE,MAAM,QAAQ,IAAIC,EAAE,MAAM,QAAQ,CAAC,GACzEyB,IAAa,CAAC,GACdC,IAAW,WACTC,UAAc;GACnB,IAAMlB,IAAQgB,EAAM;GACpB,AAAIA,EAAM,SAAS,KAAKhB,GAAO,SAAOc,EAAU,KAAK;IAAE,OAAOd,EAAM;IAAO,cAAcgB;IAAO,OAAOhB,EAAM;GAAM,CAAC;EACrH;EACA,KAAK,IAAMM,KAAeS,GACzB,AAAIT,EAAY,MAAM,QAAQ,IAAIW,KACjCD,EAAM,KAAKV,CAAW,GACtB,IAAW,KAAK,IAAIW,GAAUX,EAAY,IAAI,QAAQ,CAAC,MAEvDY,EAAM,GACN,IAAQ,CAACZ,CAAW,GACpB,IAAWA,EAAY,IAAI,QAAQ;EAGrC,EAAM;CACP;CACA,OAAOQ,EAAU,MAAM,GAAG,MAAMxB,EAAE,MAAM,QAAQ,IAAIC,EAAE,MAAM,QAAQ,CAAC;AACtE;AAGA,SAAgB4B,GAAe,GAA+C;CAC7E,OAAO,IAAI,IAAIL,EAAU,SAAS,MAAaM,EAAS,aAAa,KAAK,MAAgBd,EAAY,EAAE,CAAC,CAAC;AAC3G;AAGA,SAAgBe,GAAU,GAAkD;CAC3E,IAAMC,oBAAO,IAAI,IAA+B;CAChD,KAAK,IAAMhB,KAAeE,GAAc,AAAIF,EAAY,SAAS,CAACgB,EAAK,IAAIhB,EAAY,MAAM,EAAE,KAAGgB,EAAK,IAAIhB,EAAY,MAAM,IAAIA,EAAY,KAAK;CAClJ,OAAO,CAAC,GAAGgB,EAAK,OAAO,CAAC;AACzB;AAMA,SAAgBC,GAAW,GAAY,GAAyB;CAC/D,IAAM,EAAE,cAAW,IAAI,KAAK,eAAeC,GAAQ,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,gBAAgB;CACxF,IAAI,CAACC,GAAQ,OAAO,IAAI,KAAK,eAAeD,GAAQ;EAAE,MAAM;EAAW,QAAQ;CAAU,CAAC,CAAC,CAAC,OAAO/C,CAAI;CACvG,IAAMiD,IAAsCjD,EAAK,WAAW,MAAM,IAAI,EAAE,MAAM,UAAU,IAAI;EAAE,MAAM;EAAW,QAAQ;CAAU;CACjI,OAAO,IAAI,KAAK,eAAe+C,GAAQE,CAAO,CAAC,CAAC,OAAOjD,CAAI;AAC5D;AAEA,SAAgBkD,EAAW,GAAoE;CAC9F,OAAO,OAAOC,KAAW,WAAWA,IAASA,GAAQ;AACtD;;;ACxGA,IAAMC,IAAoD;CACzD,WAAW;CACX,SAAS;CACT,WAAW;CACX,WAAW;CACX,QAAQ;AACT;AAwBA,SAASC,GAAe,EAAE,gBAAa,cAA8D;CACpG,IAAM7C,IAAK8C,GAAM,GACXC,IAASL,EAAWrB,EAAY,MAAM,GACtC2B,IAAQ3B,EAAY,OACpB,EAAE,SAAM,gBAAa4B,GACrBC,IAAaD,EAAQ,QAAQ,SAAS,GAGtCE,IAAa;EAAC,GAAGnD,EAAG;EAAS,GAAGA,EAAG;EAAU,GAAGA,EAAG;EAAUgD,KAAS,GAAGhD,EAAG;CAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GAC7GoD,IAAUC,EAA0B,IAAI,GACxCC,IAAkBD,EAAO,EAAK;CAUpC,OANAE,SAAsB;EACrB,AAAI,MAAeD,EAAgB,YACnC,EAAgB,UAAU,KACtB,CAAC,SAAS,iBAAiB,SAAS,kBAAkB,SAAS,SAAMF,EAAQ,SAAS,MAAM;CACjG,GAAG,CAACF,CAAU,CAAC,GAGd,kBAACvE,IAAD;EACC,SAAQ;EACR,MAAK;EACL,SAAQ;EACR,eAAa0C,EAAY;EACzB,iBAAec,IAAW,KAAK,KAAA;EAC/B,WAAWtF,EACV,uDACA,CAAC,CAAC2G,KAAQzF,EAAmB,UAC7BoE,KAAYtF,EAAGO,EAAY,YAAY,MAAMA,EAAY,YAAY,IAAI,CAC1E;EAVD,UAAA;GAYE,CAAC,CAACoG,KACF,kBAAC,UAAD;IACC,KAAKJ;IACL,MAAK;IACL,mBAAiBD;IACjB,SAASK;IACT,WAAW3G,EAAG,0GAA0GkB,EAAmB,mBAAmBb,EAAa,KAAK;GAChL,CAAA;GAGF,kBAAC,QAAD;IAAM,eAAY;IAAO,WAAWL,EAAG,qEAAqEoG,EAAQ,kBAAkB;GAAI,CAAA;GAC1I,kBAACvE,IAAD;IAAa,WAAU;IAAvB,UAAA,CACC,kBAACE,IAAD;KAAW,WAAU;KAArB,UAAA,CACC,kBAAC7B,GAAD;MAAM,MAAK;MAAU,IAAI,GAAGiD,EAAG;MAAS,KAAI;MAAO,QAAO;MAAS,WAAU;MAAY,UAAAqB,EAAY;KAAY,CAAA,GACjH,kBAACjD,GAAD;MAAO,IAAI,GAAG4B,EAAG;MAAU,MAAMiD,EAAQ;MAAY,MAAK;MACxD,UAAAA,EAAQ;KACH,CAAA,CACG;IACX,CAAA,GAAA,kBAACzE,IAAD;KAAiB,IAAI,GAAGwB,EAAG;KAAU,OAAO;KAC1C,UAAA+C,IAAS,GAAGE,EAAQ,KAAK,KAAKF,MAAWE,EAAQ;IAClC,CAAA,CACL;;IACX,CAAC,CAACD,KAASE,MACZ,kBAACzE,IAAD;IAEC,eAAe;KAAE,EAAgB,UAAU;IAAM;IACjD,SAAS,MAAU;KAClB,AAAIgF,EAAM,yBAAyB,QAAQ,CAACA,EAAM,cAAc,SAASA,EAAM,aAAa,MAAG,EAAgB,UAAU;IAC1H;IALD,UAAA,CAOE,CAAC,CAACT,KACF,kBAAAtG,IAAA,EAAA,UAAA,CACC,kBAAC4B,GAAD,EAAA,UAAgB,kBAAC,QAAD;KAAM,IAAI,GAAG0B,EAAG;KAAU,UAAAgD,EAAM;IAAW,CAAA,EAAiB,CAAA,GAC5E,kBAAC9E,GAAD;KAAQ,MAAK;KAAK,eAAY;KAA9B,UAAA,CACE,CAAC,CAAC8E,EAAM,aAAa,kBAAC7E,GAAD;MAAa,KAAK6E,EAAM;MAAW,KAAI;KAAI,CAAA,GACjE,kBAAC/E,GAAD,EAAA,UAAiBD,EAAegF,EAAM,IAAI,EAAkB,CAAA,CACrD;IACP,CAAA,CAAA,EAAA,CAAA,GAEFC,EAAQ,WACG;;EAET;;AAER;AAEA,SAAgBS,GAAkB,EAAE,SAAM,iBAAc,eAAY,cAAW,YAAS,YAAS,UAAO,YAAS,WAAQ,uBAAoB,uBAAoB,sBAAmB,cAAmC;CACtN,IAAMC,IAASxD,EAAK,KAAK,OAAS;EAAE;EAAK,OAAOmB,EAAeC,GAAcX,CAAG;CAAE,EAAE,GAC9EgD,IAAQD,EAAO,QAAQ,GAAK,MAAUE,IAAM9B,EAAM,MAAM,QAAQ,CAAC,GACjE+B,IAAY,IAAI,KAAK,eAAevB,GAAQ;EAAE,SAAS;EAAQ,OAAO;EAAQ,KAAK;CAAU,CAAC,GAC9FwB,IAAU5D,EAAK,SAAS,GAIxB6D,KAAc,MAAuD;EAC1E,IAAM7B,IAAWN,EAAU,IAAIR,EAAY,EAAE,GACvC4C,KAAWC,IAAqB7C,CAAW,KAAK,CAAC,EAAA,CAAG,QAAQ,MAAW8C,EAAO,YAAY,EAAK,GAC/FlB,IAAsB;GAC3B,UAAUnD,EAAW,MAAM,MAAaC,EAAS,OAAOsB,EAAY,QAAQ;GAC5E,oBAAoB1B,EAAgCC,GAAcE,GAAYuB,EAAY,QAAQ;GAClG;GACA,aAAac,IAAWiC,EAAQ,WAAWA,EAAQ,OAAO/C,EAAY;GACtE,YAAYc,IAAW,gBAAgBS,EAAYvB,EAAY;GAC/D,MAAM+C,EAAQ,gBAAgB9B,GAAWjB,EAAY,OAAOkB,CAAM,GAAGD,GAAWjB,EAAY,KAAKkB,CAAM,CAAC;GACxG,MAAM8B,UAA2BA,EAAmBhD,CAAW,IAAI,KAAA;GACnE;GAEA,aAAa4C,EAAQ,SAAS,IAC7B,kBAACpG,GAAD;IACU;IACT,QAAQuG,EAAQ,mBAAmB/C,EAAY,KAAK;IACpD,aAAa;KAAE,MAAM;KAAM,WAAW;IAA4C;GAClF,CAAA,IACE;EACL;EACA,OAAO;GAAE,GAAG4B;GAAS,qBAAqB,kBAACJ,IAAD;IAA6B;IAAsB;GAAU,CAAA;EAAE;CAC1G,GAEMjB,KAAQ,MACb,kBAACzE,GAAD;EAAO,QAAQ,kBAAC,MAAD,CAAK,CAAA;EAAG,KAAI;EAAK,WAAU;EACxC,UAAAmH,EAAM,KAAK,MAAgB;GAC3B,IAAMrB,IAAUe,EAAW3C,CAAW;GACtC,OACC,kBAAC,MAAD;IAAyB,WAAU;IACjC,UAAAkD,IAAoBA,EAAkBlD,GAAa4B,CAAO,IAAIA,EAAQ,cAAc;GAClF,GAFK5B,EAAY,EAEjB;EAEN,CAAC;CACK,CAAA,GAGJmD;CAqCJ,OApCA,AAiCCA,IAjCGC,IAEF,kBAACtH,GAAD;EAAO,KAAI;EAAK,aAAU;EAAO,WAAU;EAA3C,UAAA,CACC,kBAACmB,GAAD,EAAA,UAAiB8F,EAAQ,QAAwB,CAAA,GAChD,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,MAAU,kBAACtG,GAAD,EAAsB,WAAU,qCAAsC,GAAvD+B,CAAuD,CAAC,CAC1G;MAEE6E,IAEHC,GAAeD,CAAK,IAAIA,IAC9B,kBAAC/G,GAAD;EACC,SAAQ;EACR,OAAOyG,EAAQ;EACf,aAAaM,aAAiB,QAAQA,EAAM,UAAU,OAAOA,KAAU,YAAY,OAAOA,KAAU,WAAW,OAAOA,CAAK,IAAIN,EAAQ;EAC9H;EACT,YAAYA,EAAQ;EACpB,WAAU;CACV,CAAA,IAEQR,MAAU,IACb,kBAAC5E,IAAD;EAAY,SAAQ;EAAK,OAAOoF,EAAQ;EAAO,aAAa;EAAO,WAAWA,EAAQ;EAAO,WAAU;CAA6B,CAAA,IACjIL,IAET,kBAAC5G,GAAD;EAAO,KAAI;EACT,UAAAwG,EAAO,QAAQ,MAAU5B,EAAM,MAAM,SAAS,CAAC,CAAC,CAAC,KAAK,MACtD,kBAAC5E,GAAD;GAAqC,QAAQ,kBAAC,WAAD,CAAU,CAAA;GAAG,KAAI;GAAK,cAAY2G,EAAU,OAAO/B,EAAM,GAAG;GAAG,WAAU;GAAtH,UAAA,CACC,kBAAC/E,GAAD;IAAS,WAAU;IAAe,KAAI;IAAK,MAAMC,EAAiB;IAAa,UAAA6G,EAAU,OAAO/B,EAAM,GAAG;GAAW,CAAA,GACnHH,EAAKG,EAAM,KAAK,CACX;EAHK,GAAAA,EAAM,IAAI,YAAY,CAG3B,CACP;CACK,CAAA,IAGDH,EAAK+B,EAAO,EAAE,EAAE,SAAS,CAAC,CAAC,GAIlC,kBAAClG,GAAD;EACC,SAAQ;EACR,OAAOmH;EAEP,WAAWH,KAAWC,IAAQ,KAAA,IAAY,kBAAC3H,GAAD;GAAM,MAAK;GAAK,MAAK;GAAY,WAAU;GAAgB,UAAAqH,EAAQ,YAAYR,CAAK;EAAQ,CAAA;EACtI,WAAU;EACV,kBAAiB;EAEjB,UAAA,kBAACrF,GAAD;GAAY,WAAU;GACpB,UAAAiG;EACU,CAAA;CACP,CAAA;AAER;;;AC/MA,IAAMK,IAAW;AAEjB,SAAgBC,GAAiB,EAAE,aAAU,aAAU,yBAAsB,iBAAc,eAAY,iBAAc,WAAQ,cAAkC;CAC9J,IAAM,CAACC,GAASC,KAAcC,EAASC,CAAQ,GACzCC,IAAU9B,EAAuB,IAAI,GACrC+B,IAAgB/B,EAAO,EAAK,GAC5BgC,IAAQC,wBAAc,IAAI,KAAK,GAAG,CAAC,CAAC;CAG1C,QAAgBN,EAAWE,CAAQ,GAAG,CAACA,CAAQ,CAAC;CAChD,IAAMK,IAAeR,EAAQ,YAAY,IAAI,KAAKA,EAAQ,SAAS;CAInE,AAHAS,QAAgB;EACf,IAAuB,IAAI,KAAK,KAAK,MAAMD,IAAe,EAAE,GAAGA,IAAe,IAAI,CAAC,CAAC;CACrF,GAAG,CAACA,GAAcE,CAAoB,CAAC,GACvCD,QAAgB;EACf,AAAKJ,EAAc,YACnB,EAAc,UAAU,IACxBD,EAAQ,SAAS,cAAiC,qBAAqB,CAAC,EAAE,MAAM;CACjF,GAAG,CAACJ,CAAO,CAAC;CAEZ,IAAMW,IAAQJ,QAActE,GAAU+D,GAASlE,CAAY,GAAG,CAACkE,GAASlE,CAAY,CAAC,GAC/E8E,IAAcL,QAAc,IAAI,KAAK,eAAe/C,GAAQ,EAAE,OAAO,OAAO,CAAC,GAAG,CAACA,CAAM,CAAC,GACxFqD,IAAgBN,QAAc,IAAI,KAAK,eAAe/C,GAAQ,EAAE,SAAS,QAAQ,CAAC,GAAG,CAACA,CAAM,CAAC,GAC7FuB,IAAYwB,QAAc,IAAI,KAAK,eAAe/C,GAAQ;EAAE,SAAS;EAAQ,OAAO;EAAQ,KAAK;EAAW,MAAM;CAAU,CAAC,GAAG,CAACA,CAAM,CAAC,GACxIsD,IAAeP,QAAc,MAAM,KAAK,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAW;EAAE,OAAO,OAAOQ,CAAK;EAAG,OAAOH,EAAY,OAAO,IAAI,KAAK,KAAMG,GAAO,CAAC,CAAC;CAAE,EAAE,GAAG,CAACH,CAAW,CAAC,GACrKI,IAAcT,QAAc;EACjC,IAAMU,oBAAQ,IAAI,IAAY,CAACX,EAAM,YAAY,GAAGN,EAAQ,YAAY,CAAC,CAAC;EAC1E,KAAK,IAAM1D,KAAeE,GAAc,EAAM,IAAIF,EAAY,MAAM,YAAY,CAAC;EACjF,IAAM4E,IAAM,KAAK,IAAI,GAAGD,CAAK,IAAI,GAC3BE,IAAM,KAAK,IAAI,GAAGF,CAAK,IAAI;EACjC,OAAO,MAAM,KAAK,EAAE,QAAQE,IAAMD,IAAM,EAAE,IAAI,GAAG,OAAW;GAAE,OAAO,OAAOA,IAAMpG,CAAK;GAAG,OAAO,OAAOoG,IAAMpG,CAAK;EAAE,EAAE;CACxH,GAAG;EAAC0B;EAAcwD;EAASM;CAAK,CAAC,GAE3Bc,KAAU,GAAY,IAAS,OAAU;EAG9C,AAFA,EAAc,UAAU,IACxBnB,EAAWxF,CAAI,GACX4G,KAAQC,EAAS7G,CAAI;CAC1B,GACM8G,KAAe,MAAmB;EACvC,IAAMC,IAAOhG,EAAU2E,GAAUzE,CAAM;EAEvC,AADAuE,EAAWuB,CAAI,GACfF,EAASE,CAAI;CACd;CAmBA,OACC,kBAACpJ,GAAD;EAAO,KAAI;EAAK,WAAU;EAA1B,UAAA,CACC,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACC,kBAACL,GAAD;KAAQ,MAAK;KAAS,MAAK;KAAY,aAAY;KAAQ,MAAK;KAAK,UAAA;KAAS,cAAYsH,EAAQ;KAAe,eAAekC,EAAY,EAAE;KAC7I,UAAA,kBAACE,IAAD;MAAa,eAAY;MAAO,WAAU;KAAa,CAAA;IAChD,CAAA;IACR,kBAACnI,GAAD;KACC,MAAK;KACL,cAAY+F,EAAQ;KACpB,SAASyB;KACT,OAAO,OAAOX,EAAS,SAAS,CAAC;KACjC,gBAAgB,MAAUuB,MAAU,KAAA,KAAaH,EAAY,OAAOG,CAAK,IAAIvB,EAAS,SAAS,CAAC;KAChG,WAAU;IACV,CAAA;IACD,kBAAC7G,GAAD;KACC,MAAK;KACL,cAAY+F,EAAQ;KACpB,SAAS2B;KACT,OAAO,OAAOb,EAAS,YAAY,CAAC;KACpC,gBAAgB,MAAUuB,MAAU,KAAA,KAAaH,GAAa,OAAOG,CAAK,IAAIvB,EAAS,YAAY,KAAK,EAAE;KAC1G,WAAU;IACV,CAAA;IACD,kBAACpI,GAAD;KAAQ,MAAK;KAAS,MAAK;KAAY,aAAY;KAAQ,MAAK;KAAK,UAAA;KAAS,cAAYsH,EAAQ;KAAW,eAAekC,EAAY,CAAC;KACxI,UAAA,kBAACI,IAAD;MAAc,eAAY;MAAO,WAAU;KAAa,CAAA;IACjD,CAAA;GACJ;EAEL,CAAA,GAAA,kBAAC,OAAD;GACC,KAAKvB;GACL,MAAK;GACL,cAAY,GAAGQ,EAAY,OAAOZ,CAAO,EAAE,GAAGA,EAAQ,YAAY;GACvD,YAhDK,MAAyC;IAW3D,IAAM4B,IAAO;KATZ,iBAAiBzG,EAAQ6E,GAAS,EAAE;KACpC,kBAAkB7E,EAAQ6E,GAAS,CAAC;KACpC,eAAe7E,EAAQ6E,GAAS,EAAE;KAClC,iBAAiB7E,EAAQ6E,GAAS,CAAC;KACnC,YAAYpE,EAAYoE,GAASlE,CAAY;KAC7C,WAAWX,EAAQS,EAAYoE,GAASlE,CAAY,GAAG,CAAC;KACxD,cAAcN,EAAUwE,GAAS,EAAE;KACnC,gBAAgBxE,EAAUwE,GAAS,CAAC;IAExB,EAAMtB,EAAM;IACzB,AAAKkD,MACLlD,EAAM,eAAe,GACrB0C,EAAOQ,EAAK,CAAC;GACd;GAkCG,WAAU;GALX,UAAA,CAOC,kBAAC,OAAD;IAAK,MAAK;IAAM,WAAU;IACxB,UAAAjB,EAAM,EAAE,EAAE,KAAK,MACf,kBAAC3I,GAAD;KAAyB,KAAI;KAAM,MAAK;KAAe,MAAK;KAAK,MAAK;KAAY,QAAO;KAAS,OAAM;KAAS,WAAU;KACzH,UAAA6I,EAAc,OAAOhF,CAAG;IACpB,GAFKA,EAAI,OAAO,CAEhB,CACN;GACG,CAAA,GACJ8E,EAAM,KAAK,MACX,kBAAC,OAAD;IAAkC,MAAK;IAAM,WAAU;IACrD,UAAAzE,EAAK,KAAK,MAAQ;KAClB,IAAM2F,IAAkBtF,EAAeC,GAAcX,CAAG,GAClDiG,IAAgB,CAAC,GAAG,IAAI,IAAID,EAAgB,KAAK,MAAgBvF,EAAY,QAAQ,CAAC,CAAC,GACvFyF,IAAa1G,EAAUQ,GAAKsE,CAAQ,GACpC6B,IAAY3G,EAAUQ,GAAKmE,CAAO,GAClCiC,IAAUpG,EAAI,SAAS,MAAMmE,EAAQ,SAAS;KACpD,OACC,kBAAC,OAAD;MAA6B,MAAK;MAAW,iBAAe+B;MAAY,WAAU;MACjF,UAAA,kBAAC,UAAD;OACC,MAAK;OACL,UAAUC,IAAY,IAAI;OAC1B,qBAAmBA,IAAY,KAAK,KAAA;OACpC,iBAAeD,IAAa,KAAK,KAAA;OACjC,gBAAcE,IAAU,KAAK,KAAA;OAC7B,gBAAc5G,EAAUQ,GAAKyE,CAAK,IAAI,SAAS,KAAA;OAC/C,cAAYjB,EAAQ,eAAeN,EAAU,OAAOlD,CAAG,GAAGgG,EAAgB,MAAM;OAChF,eAAeT,EAAOvF,GAAK,EAAI;OAC/B,WAAW/D,EACVkB,EAAmB,mBACnB,0IACAb,EAAa,MACb4J,IACG,qDACAjK,EAAGkB,EAAmB,UAAUiJ,IAAU,0BAA0B,iBAAiB,GACxF,CAACF,KAAc1G,EAAUQ,GAAKyE,CAAK,KAAK,eACzC;OAjBD,UAAA,CAmBEzE,EAAI,QAAQ,GACZiG,EAAc,SAAS,KACvB,kBAAC,QAAD;QAAM,eAAY;QAAO,WAAU;QACjC,UAAAA,EAAc,MAAM,GAAGhC,CAAQ,CAAC,CAAC,KAAK,MACtC,kBAAC,QAAD,EAAqB,WAAWhI,EAAGQ,EAAW,QAAQsC,EAAgCC,GAAcE,GAAYC,CAAQ,EAAE,EAAI,GAAnHA,CAAmH,CAC9H;OACI,CAAA,CAEA;;KACJ,GA7BKa,EAAI,YAAY,CA6BrB;IAEP,CAAC;GACG,GAxCKK,EAAK,EAAE,EAAE,YAAY,CAwC1B,CACL,CACG;EACC,CAAA,CAAA;;AAET;;;ACtIA,SAASgG,EAAmB,GAAsB,GAAa,GAAsD;CACpH,IAAM,CAACC,GAAOC,KAAYlC,EAASmC,CAAQ;CAE3C,OAAO,CADSX,KAASS,IACP,MAAY;EAE7B,AADIT,MAAU,KAAA,KAAWU,EAASZ,CAAI,GACtCc,IAAWd,CAAI;CAChB,CAAC;AACF;AAEA,SAAgBe,GAAyD,EACxE,iBACA,eACA,OAAOC,GACP,UACA,MAAMC,GACN,gBACA,iBACA,MAAMC,GACN,iBAAc,OACd,iBACA,UAAUC,GACV,qBAAkB,OAClB,qBACA,SAASC,GACT,qBAAiB,OACjB,mBACA,wBACA,wBACA,uBACA,mBACA,yBACA,wBACA,cAAU,IACV,WACA,aACA,cAAcC,IACd,SAASC,GACT,gBAC+B;CAC/B,IAAMzD,IAAU0D,EAAW5I,IAAmC2I,CAAW,GACnE,EAAE,cAAWlL,EAAoB,GACjCoL,IAAQnL,EAAe,GACvBiE,IAAe+G,MAAoBG,EAAM,gBAAgB,GAEzD,CAACvI,GAAMwI,MAAWf,EAAgBO,GAAUS,KAAehI,kBAAW,IAAI,KAAK,CAAC,GAAGiI,CAAY,GAC/F,CAACC,GAAMC,MAAWnB,EAAyCQ,GAAUY,GAAaC,CAAY,GAC9F,CAACvI,GAAUwI,MAAetB,EAAgBS,GAAcc,GAAiBC,CAAgB,GACzF,CAAChH,GAASiH,MAAczB,EAAgBU,GAAagB,IAAgBC,EAAa,GAClF,CAACC,IAAWC,MAAgB7D,EAAiB,EAAE,GAC/C,CAACM,IAAcwD,MAAmB9D,QAAe,IAAI,KAAKzF,EAAK,YAAY,GAAGA,EAAK,SAAS,GAAG,CAAC,CAAC,GAEjGwD,KAAQsC,QAAciC,KAAanF,GAAUb,CAAY,GAAG,CAACgG,GAAWhG,CAAY,CAAC,GACrFpB,IAAOmF,QAAe6C,MAAS,SAASrH,GAAStB,GAAMqB,CAAY,IAAI,CAACZ,EAAWT,CAAI,CAAC,GAAI;EAAC2I;EAAM3I;EAAMqB;CAAY,CAAC,GACtHmI,IAAU1D,QAAc9D,GAAmBD,GAAcxB,GAAU0B,CAAO,GAAG;EAACF;EAAcxB;EAAU0B;CAAO,CAAC,GAG9GwH,IAAQ3D,QAAoC;EACjD,IAAM4D,IAAQ,CAAC,GAAGlI,GAAUuE,IAAc1E,CAAY,CAAC,CAAC,KAAK,GAAG,GAAGV,CAAI,CAAC,CAAC,KAAK,MAAQS,EAAI,QAAQ,CAAC;EACnG,OAAO;GAAE,OAAO,IAAI,KAAK,KAAK,IAAI,GAAGsI,CAAK,CAAC;GAAG,KAAKhJ,EAAQ,IAAI,KAAK,KAAK,IAAI,GAAGgJ,CAAK,CAAC,GAAG,CAAC;EAAE;CAC7F,GAAG;EAAC3D;EAAc1E;EAAcV;CAAI,CAAC,GAC/BgJ,KAAgB9F,EAAO,EAAE;CAC/B,QAAgB;EACf,IAAM+F,IAAM,GAAGH,EAAM,MAAM,QAAQ,EAAE,GAAGA,EAAM,IAAI,QAAQ;EAC1D,AAAIG,MAAQD,GAAc,YAC1B,GAAc,UAAUC,GACxBC,KAAgBJ,CAAK;CACtB,GAAG,CAACA,GAAOI,EAAa,CAAC;CACzB,IAAMC,KAAUhE,QAAc0D,EAAQ,QAAQ,MAAgB7I,EAAK,MAAM,MAAQe,GAASG,GAAaT,CAAG,CAAC,CAAC,GAAG,CAACoI,GAAS7I,CAAI,CAAC,GAIxH0B,IAAYyD,QAEV5D,GADaF,GAAmBD,GAAc,OAAOE,CAAO,CAAC,CAAC,QAAQ,MAAgBtB,EAAK,MAAM,MAAQe,GAASG,GAAaT,CAAG,CAAC,CACrH,CAAW,GAC9B;EAACW;EAAcE;EAAStB;CAAI,CAAC,GAC1BoJ,KAAcjE,QAAcpD,GAAeL,CAAS,GAAG,CAACA,CAAS,CAAC,GAClE2H,KAAmBF,GAAQ,QAAQ,MAAgBC,GAAY,IAAIlI,EAAY,EAAE,CAAC,CAAC,CAAC,QACpFoI,KAASH,GAAQ,QAAQ,MAAgBjI,EAAY,WAAW,WAAW,CAAC,CAAC,QAC7EqI,KAAc,CAAC,GAAGH,EAAW,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAC9CI,KAAY9H,EAAU,SAAS,KAAKgH,OAAca,IAElDE,KAAgB,IAAI,KAAK,eAAerH,GAAQ;EAAE,SAAS;EAAQ,OAAO;EAAQ,KAAK;CAAU,CAAC,GAClGsH,KAAc,IAAI,KAAK,eAAetH,GAAQ;EAAE,OAAO;EAAQ,KAAK;CAAU,CAAC,GAC/EqC,KAAUuD,MAAS,SACtB/D,EAAQ,gBAAgByF,GAAY,OAAO1J,EAAK,MAAMX,CAAI,GAAGqK,GAAY,OAAO1J,EAAKA,EAAK,SAAS,MAAMX,CAAI,CAAC,IAC9GoK,GAAc,OAAOpK,CAAI,GAEtBsK,MAAoB,MAAoC;EAE7D,AADAhB,GAAaY,EAAW,GACxBK,KAAqBC,CAAK;CAC3B;CAEA,OACC,kBAAC7M,GAAD;EAAO,KAAI;EAAK,aAAU;EAAuB,aAAWgL;EAAM,WAAWtL,EAAG,mFAAmFoN,CAAS;EAA5K,UAAA;GACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACC,kBAAC9M,GAAD;KAAO,KAAI;KAAK,WAAU;KAA1B,UAAA,CACE,CAAC,CAACsC,KAAS,kBAACzC,GAAD;MAAS,WAAU;MAAe,KAAI;MAAK,MAAK;MAAM,UAAAyC;KAAe,CAAA,GAEhF,CAACgF,MAAW,CAACC,MACb,kBAAC3H,GAAD;MAAM,MAAK;MAAK,MAAK;MAAY,WAAU;MAA3C,UAAA,CACEqH,EAAQ,aAAaqF,EAAM,GAC3BD,KAAmB,KAAK,MAAMpF,EAAQ,gBAAgBoF,EAAgB,GAClE;KAED,CAAA,CAAA;IACP,CAAA,GAAA,kBAAC,OAAD;KAAK,WAAW3M,EAAG,qEAAqEe,EAAmB,QAAQ;KAAnH,UAAA;MACC,kBAACmB,IAAD;OAAM,OAAOoJ;OAAM,gBAAgB,OAAU5B,MAAS,SAASA,MAAS,WAAW6B,GAAQ7B,CAAI;OAC9F,UAAA,kBAACzH,IAAD;QAAU,MAAK;QAAQ,cAAYsF,EAAQ;QAAW,oBAAkB,KAAA;QAAW,iBAAA;QAChF,UAAA,CAAC,OAAO,MAAM,CAAC,CAAW,KAAK,MAChC,kBAACvF,IAAD;SAA0B,OAAOqL;SAAQ,MAAK;SAAS,iBAAe,KAAA;SAAW,iBAAe,KAAA;SAAW,gBAAc/B,MAAS+B;SAChI,UAAA9F,EAAQ8F;QACG,GAFKA,CAEL,CACb;OACQ,CAAA;MACL,CAAA;MACLlH,GAAM,SAAS,KACf,kBAAC3E,GAAD;OACC,cAAY+F,EAAQ;OACpB,SAAS,CAAC;QAAE,OAAO;QAAO,OAAOA,EAAQ;OAAS,GAAG,GAAGpB,GAAM,KAAK,OAAY;QAAE,OAAOL,EAAO;QAAI,OAAOA,EAAO;OAAK,EAAE,CAAC;OACzH,OAAOlB;OACP,gBAAgB,MAASiH,GAAWnC,KAAQ,KAAK;OACjD,WAAU;MACV,CAAA;MAED,CAAC,CAAC4D,MACF,kBAACrN,GAAD;OAAQ,MAAK;OAAS,MAAK;OAAU,eAAeqN,GAAoB3K,CAAI;OAAG,WAAU;OAAzF,UAAA,CACC,kBAAC4K,IAAD;QAAM,eAAY;QAAO,WAAU;OAAa,CAAA,GAC/ChG,EAAQ,cACF;;KAEL;IACD,CAAA,CAAA;;GAEJuF,MACA,kBAACnM,GAAD;IAAO,MAAK;IAAc,WAAU;IAApC,UAAA;KACC,kBAAC6M,IAAD,EAAe,eAAY,OAAQ,CAAA;KACnC,kBAAC3M,GAAD,EAAA,UAAa0G,EAAQ,cAA0B,CAAA;KAC/C,kBAAC9G,GAAD,EAAA,UACEuE,EAAU,KAAK,MAAauC,EAAQ,eAAejC,EAAS,MAAM,MAAMA,EAAS,aAAa,QAAQG,GAAWH,EAAS,OAAOI,CAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,EACnI,CAAA;KAClB,kBAAChF,GAAD,EAAA,UACC,kBAACT,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,eAAegN,GAAiBjI,CAAS;MAAI,UAAAuC,EAAQ;KAAgB,CAAA,EACzF,CAAA;IACP;;GAGR,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACC,kBAAC3G,GAAD;KAAM,SAAQ;KAAO,WAAU;KAC9B,UAAA,kBAACN,GAAD;MAAO,KAAI;MAAX,UAAA,CACC,kBAAC2H,IAAD;OACC,UAAUtF;OACV,UAAUwI;OACV,sBAAsBe;OACtB,cAAcC;OACF;OACE;OACN;OACC;MACT,CAAA,GACAlJ,EAAW,SAAS,KACpB,kBAACf,IAAD;OAAM,OAAOgB;OAAU,gBAAgB,MAAS,OAAOwG,KAAS,YAAYgC,GAAYhC,CAAI;OAC3F,UAAA,kBAACzH,IAAD;QAAU,SAAQ;QAAQ,MAAK;QAAQ,cAAYsF,EAAQ;QAAiB,oBAAkB,KAAA;QAAW,iBAAA;QACvG,UAAA,CAAC;SAAE,IAAI;SAAO,OAAOA,EAAQ;QAAc,GAAG,GAAGtE,CAAU,CAAC,CAAC,KAAK,MAClE,kBAACjB,IAAD;SAA6B,OAAOqL,EAAO;SAAI,MAAK;SAAS,iBAAe,KAAA;SAAW,iBAAe,KAAA;SAAW,gBAAcnK,MAAamK,EAAO;SAAI,WAAU;SAAjK,UAAA,CACEA,EAAO,OAAO,SACd,kBAAC,QAAD;UAAM,eAAY;UAAO,WAAWrN,EAAGQ,EAAW,QAAQsC,EAAgCC,GAAcE,GAAYoK,EAAO,EAAE,EAAE;SAAI,CAAA,GAEnIA,EAAO,KACI;QALK,GAAAA,EAAO,EAKZ,CACb;OACQ,CAAA;MACL,CAAA,CAED;;IACF,CAAA,GAEN,kBAACxG,IAAD;KACO;KACN,cAAcsF;KACF;KACZ,WAAWO;KACF;KACA;KACF;KACE;KACD;KAEY;KACA;KACD;KACV;IACT,CAAA,CACG;;EACC;;AAET;AAEA,GAAoB,cAAc"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useStrings as e } from "../lib/strings.js";
|
|
3
|
-
import { t } from "../utils-
|
|
4
|
-
import { n } from "../buttons-
|
|
5
|
-
import { t as r } from "../structure-
|
|
6
|
-
import { n as i, t as a } from "../feedback-
|
|
7
|
-
import { i as o } from "../popover.recipes-
|
|
8
|
-
import { _ as s, d as c, g as l, p as u } from "../primitives-
|
|
9
|
-
import { t as d } from "../badge-
|
|
10
|
-
import { c as f, o as p, t as m } from "../popover-
|
|
11
|
-
import { s as h } from "../data-display-
|
|
3
|
+
import { t } from "../utils-B6kKb8jB.js";
|
|
4
|
+
import { n } from "../buttons-BedGfygC.js";
|
|
5
|
+
import { t as r } from "../structure-DuxKl954.js";
|
|
6
|
+
import { n as i, t as a } from "../feedback-Dm4izqFn.js";
|
|
7
|
+
import { i as o } from "../popover.recipes-DdiEp0rd.js";
|
|
8
|
+
import { _ as s, d as c, g as l, p as u } from "../primitives-ByWgGUgt.js";
|
|
9
|
+
import { t as d } from "../badge-xIiV_E7f.js";
|
|
10
|
+
import { c as f, o as p, t as m } from "../popover-B85RenIl.js";
|
|
11
|
+
import { s as h } from "../data-display-BdgCAw8T.js";
|
|
12
12
|
import g, { createContext as _, useCallback as v, useContext as y, useEffect as b, useMemo as ee, useRef as x, useState as S } from "react";
|
|
13
13
|
import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
14
14
|
import { ChevronDown as E } from "lucide-react";
|
|
@@ -290,6 +290,7 @@ function I({ className: e, children: n, align: r = "start", sideOffset: i = 8, f
|
|
|
290
290
|
lg: "flush"
|
|
291
291
|
}[u];
|
|
292
292
|
return /* @__PURE__ */ w(m, {
|
|
293
|
+
type: "display",
|
|
293
294
|
align: r,
|
|
294
295
|
sideOffset: i,
|
|
295
296
|
finalFocus: a,
|
|
@@ -467,7 +468,7 @@ var q = g.forwardRef(function({ value: e, name: r, secondary: i, leading: a, tra
|
|
|
467
468
|
"aria-hidden": !0
|
|
468
469
|
})]
|
|
469
470
|
}) : /* @__PURE__ */ w("div", {
|
|
470
|
-
className: t("preview-trigger-cell--component flex h-auto min-h-action-sm max-w-full items-center justify-start rounded-
|
|
471
|
+
className: t("preview-trigger-cell--component flex h-auto min-h-action-sm max-w-full items-center justify-start rounded-radius px-control-sm py-space-xs text-left", p),
|
|
471
472
|
"aria-disabled": d ? !0 : void 0,
|
|
472
473
|
title: typeof d == "string" ? d : void 0,
|
|
473
474
|
children: /* @__PURE__ */ w(K, { ...v })
|