@tribepad/themis 1.0.0 → 1.0.2
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/dist/elements/Accordion/index.js +2 -77
- package/dist/elements/Accordion/index.js.map +1 -1
- package/dist/elements/Accordion/index.mjs +2 -4
- package/dist/elements/Accordion/index.mjs.map +1 -1
- package/dist/elements/AlertDialog/AlertDialog.d.ts +43 -0
- package/dist/elements/AlertDialog/AlertDialog.d.ts.map +1 -0
- package/dist/elements/AlertDialog/AlertDialog.styles.d.ts +15 -0
- package/dist/elements/AlertDialog/AlertDialog.styles.d.ts.map +1 -0
- package/dist/elements/AlertDialog/AlertDialog.types.d.ts +72 -0
- package/dist/elements/AlertDialog/AlertDialog.types.d.ts.map +1 -0
- package/dist/elements/AlertDialog/index.d.ts +25 -0
- package/dist/elements/AlertDialog/index.d.ts.map +1 -0
- package/dist/elements/AlertDialog/index.js +3 -0
- package/dist/elements/AlertDialog/index.js.map +1 -0
- package/dist/elements/AlertDialog/index.mjs +3 -0
- package/dist/elements/AlertDialog/index.mjs.map +1 -0
- package/dist/elements/Avatar/index.js +2 -53
- package/dist/elements/Avatar/index.js.map +1 -1
- package/dist/elements/Avatar/index.mjs +2 -4
- package/dist/elements/Avatar/index.mjs.map +1 -1
- package/dist/elements/Badge/index.js +2 -42
- package/dist/elements/Badge/index.js.map +1 -1
- package/dist/elements/Badge/index.mjs +2 -5
- package/dist/elements/Badge/index.mjs.map +1 -1
- package/dist/elements/Breadcrumbs/index.js +2 -53
- package/dist/elements/Breadcrumbs/index.js.map +1 -1
- package/dist/elements/Breadcrumbs/index.mjs +2 -8
- package/dist/elements/Breadcrumbs/index.mjs.map +1 -1
- package/dist/elements/Button/Button.d.ts +26 -81
- package/dist/elements/Button/Button.d.ts.map +1 -1
- package/dist/elements/Button/Button.styles.d.ts +35 -0
- package/dist/elements/Button/Button.styles.d.ts.map +1 -0
- package/dist/elements/Button/Button.types.d.ts +20 -8
- package/dist/elements/Button/Button.types.d.ts.map +1 -1
- package/dist/elements/Button/index.js +2 -26
- package/dist/elements/Button/index.js.map +1 -1
- package/dist/elements/Button/index.mjs +2 -5
- package/dist/elements/Button/index.mjs.map +1 -1
- package/dist/elements/ButtonGroup/index.js +2 -65
- package/dist/elements/ButtonGroup/index.js.map +1 -1
- package/dist/elements/ButtonGroup/index.mjs +2 -4
- package/dist/elements/ButtonGroup/index.mjs.map +1 -1
- package/dist/elements/Card/Card.d.ts.map +1 -1
- package/dist/elements/Card/index.js +2 -84
- package/dist/elements/Card/index.js.map +1 -1
- package/dist/elements/Card/index.mjs +2 -7
- package/dist/elements/Card/index.mjs.map +1 -1
- package/dist/elements/Carousel/Carousel.d.ts +1 -11
- package/dist/elements/Carousel/Carousel.d.ts.map +1 -1
- package/dist/elements/Carousel/LazyCarousel.d.ts +1 -1
- package/dist/elements/Carousel/LazyCarousel.d.ts.map +1 -1
- package/dist/elements/Carousel/index.js +2 -22
- package/dist/elements/Carousel/index.js.map +1 -1
- package/dist/elements/Carousel/index.mjs +2 -9
- package/dist/elements/Carousel/index.mjs.map +1 -1
- package/dist/elements/Chart/ChartContext.d.ts.map +1 -1
- package/dist/elements/Chart/index.js +2 -46
- package/dist/elements/Chart/index.js.map +1 -1
- package/dist/elements/Chart/index.mjs +2 -5
- package/dist/elements/Chart/index.mjs.map +1 -1
- package/dist/elements/Checkbox/index.js +2 -46
- package/dist/elements/Checkbox/index.js.map +1 -1
- package/dist/elements/Checkbox/index.mjs +2 -5
- package/dist/elements/Checkbox/index.mjs.map +1 -1
- package/dist/elements/CheckboxGroup/index.js +2 -70
- package/dist/elements/CheckboxGroup/index.js.map +1 -1
- package/dist/elements/CheckboxGroup/index.mjs +2 -5
- package/dist/elements/CheckboxGroup/index.mjs.map +1 -1
- package/dist/elements/Combobox/Combobox.d.ts +56 -0
- package/dist/elements/Combobox/Combobox.d.ts.map +1 -0
- package/dist/elements/Combobox/Combobox.styles.d.ts +29 -0
- package/dist/elements/Combobox/Combobox.styles.d.ts.map +1 -0
- package/dist/elements/Combobox/Combobox.types.d.ts +67 -0
- package/dist/elements/Combobox/Combobox.types.d.ts.map +1 -0
- package/dist/elements/Combobox/index.d.ts +20 -0
- package/dist/elements/Combobox/index.d.ts.map +1 -0
- package/dist/elements/Combobox/index.js +3 -0
- package/dist/elements/Combobox/index.js.map +1 -0
- package/dist/elements/Combobox/index.mjs +3 -0
- package/dist/elements/Combobox/index.mjs.map +1 -0
- package/dist/elements/DatePicker/DatePicker.d.ts +1 -1
- package/dist/elements/DatePicker/DatePicker.d.ts.map +1 -1
- package/dist/elements/DatePicker/index.js +2 -122
- package/dist/elements/DatePicker/index.js.map +1 -1
- package/dist/elements/DatePicker/index.mjs +2 -5
- package/dist/elements/DatePicker/index.mjs.map +1 -1
- package/dist/elements/Dropdown/Dropdown.d.ts +7 -15
- package/dist/elements/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/elements/Dropdown/Dropdown.styles.d.ts +22 -0
- package/dist/elements/Dropdown/Dropdown.styles.d.ts.map +1 -0
- package/dist/elements/Dropdown/index.d.ts +1 -0
- package/dist/elements/Dropdown/index.d.ts.map +1 -1
- package/dist/elements/Dropdown/index.js +2 -40
- package/dist/elements/Dropdown/index.js.map +1 -1
- package/dist/elements/Dropdown/index.mjs +2 -3
- package/dist/elements/Dropdown/index.mjs.map +1 -1
- package/dist/elements/FileField/index.js +2 -137
- package/dist/elements/FileField/index.js.map +1 -1
- package/dist/elements/FileField/index.mjs +2 -8
- package/dist/elements/FileField/index.mjs.map +1 -1
- package/dist/elements/FormLayout/index.js +2 -16
- package/dist/elements/FormLayout/index.js.map +1 -1
- package/dist/elements/FormLayout/index.mjs +2 -3
- package/dist/elements/FormLayout/index.mjs.map +1 -1
- package/dist/elements/Modal/Modal.d.ts +9 -14
- package/dist/elements/Modal/Modal.d.ts.map +1 -1
- package/dist/elements/Modal/Modal.styles.d.ts +29 -0
- package/dist/elements/Modal/Modal.styles.d.ts.map +1 -0
- package/dist/elements/Modal/index.d.ts +1 -0
- package/dist/elements/Modal/index.d.ts.map +1 -1
- package/dist/elements/Modal/index.js +2 -51
- package/dist/elements/Modal/index.js.map +1 -1
- package/dist/elements/Modal/index.mjs +2 -2
- package/dist/elements/Modal/index.mjs.map +1 -1
- package/dist/elements/NumberField/index.js +2 -56
- package/dist/elements/NumberField/index.js.map +1 -1
- package/dist/elements/NumberField/index.mjs +2 -7
- package/dist/elements/NumberField/index.mjs.map +1 -1
- package/dist/elements/OTPInput/OTPInput.d.ts.map +1 -1
- package/dist/elements/OTPInput/index.js +2 -12
- package/dist/elements/OTPInput/index.js.map +1 -1
- package/dist/elements/OTPInput/index.mjs +2 -3
- package/dist/elements/OTPInput/index.mjs.map +1 -1
- package/dist/elements/Pagination/Pagination.d.ts +45 -0
- package/dist/elements/Pagination/Pagination.d.ts.map +1 -0
- package/dist/elements/Pagination/Pagination.styles.d.ts +10 -0
- package/dist/elements/Pagination/Pagination.styles.d.ts.map +1 -0
- package/dist/elements/Pagination/Pagination.types.d.ts +55 -0
- package/dist/elements/Pagination/Pagination.types.d.ts.map +1 -0
- package/dist/elements/Pagination/index.d.ts +21 -0
- package/dist/elements/Pagination/index.d.ts.map +1 -0
- package/dist/elements/Pagination/index.js +3 -0
- package/dist/elements/Pagination/index.js.map +1 -0
- package/dist/elements/Pagination/index.mjs +3 -0
- package/dist/elements/Pagination/index.mjs.map +1 -0
- package/dist/elements/Panel/index.js +2 -32
- package/dist/elements/Panel/index.js.map +1 -1
- package/dist/elements/Panel/index.mjs +2 -3
- package/dist/elements/Panel/index.mjs.map +1 -1
- package/dist/elements/PasswordField/PasswordField.d.ts +27 -0
- package/dist/elements/PasswordField/PasswordField.d.ts.map +1 -0
- package/dist/elements/PasswordField/PasswordField.styles.d.ts +32 -0
- package/dist/elements/PasswordField/PasswordField.styles.d.ts.map +1 -0
- package/dist/elements/PasswordField/PasswordField.types.d.ts +100 -0
- package/dist/elements/PasswordField/PasswordField.types.d.ts.map +1 -0
- package/dist/elements/PasswordField/index.css +2 -0
- package/dist/elements/PasswordField/index.css.map +1 -0
- package/dist/elements/PasswordField/index.d.ts +20 -0
- package/dist/elements/PasswordField/index.d.ts.map +1 -0
- package/dist/elements/PasswordField/index.js +3 -0
- package/dist/elements/PasswordField/index.js.map +1 -0
- package/dist/elements/PasswordField/index.mjs +3 -0
- package/dist/elements/PasswordField/index.mjs.map +1 -0
- package/dist/elements/Progress/index.js +2 -29
- package/dist/elements/Progress/index.js.map +1 -1
- package/dist/elements/Progress/index.mjs +2 -4
- package/dist/elements/Progress/index.mjs.map +1 -1
- package/dist/elements/RadioGroup/index.js +2 -46
- package/dist/elements/RadioGroup/index.js.map +1 -1
- package/dist/elements/RadioGroup/index.mjs +2 -5
- package/dist/elements/RadioGroup/index.mjs.map +1 -1
- package/dist/elements/Resizable/components/ResizableHandle.d.ts +0 -8
- package/dist/elements/Resizable/components/ResizableHandle.d.ts.map +1 -1
- package/dist/elements/Resizable/components/ResizablePanel.d.ts +0 -8
- package/dist/elements/Resizable/components/ResizablePanel.d.ts.map +1 -1
- package/dist/elements/Resizable/components/ResizablePanelGroup.d.ts +0 -8
- package/dist/elements/Resizable/components/ResizablePanelGroup.d.ts.map +1 -1
- package/dist/elements/Resizable/components/ResizablePopover.d.ts +0 -8
- package/dist/elements/Resizable/components/ResizablePopover.d.ts.map +1 -1
- package/dist/elements/Resizable/index.js +2 -64
- package/dist/elements/Resizable/index.js.map +1 -1
- package/dist/elements/Resizable/index.mjs +2 -7
- package/dist/elements/Resizable/index.mjs.map +1 -1
- package/dist/elements/SearchField/SearchField.d.ts +27 -0
- package/dist/elements/SearchField/SearchField.d.ts.map +1 -0
- package/dist/elements/SearchField/SearchField.styles.d.ts +32 -0
- package/dist/elements/SearchField/SearchField.styles.d.ts.map +1 -0
- package/dist/elements/SearchField/SearchField.types.d.ts +45 -0
- package/dist/elements/SearchField/SearchField.types.d.ts.map +1 -0
- package/dist/elements/SearchField/index.css +2 -0
- package/dist/elements/SearchField/index.css.map +1 -0
- package/dist/elements/SearchField/index.d.ts +21 -0
- package/dist/elements/SearchField/index.d.ts.map +1 -0
- package/dist/elements/SearchField/index.js +3 -0
- package/dist/elements/SearchField/index.js.map +1 -0
- package/dist/elements/SearchField/index.mjs +3 -0
- package/dist/elements/SearchField/index.mjs.map +1 -0
- package/dist/elements/Select/Select.d.ts +19 -48
- package/dist/elements/Select/Select.d.ts.map +1 -1
- package/dist/elements/Select/Select.styles.d.ts +55 -0
- package/dist/elements/Select/Select.styles.d.ts.map +1 -0
- package/dist/elements/Select/index.js +2 -32
- package/dist/elements/Select/index.js.map +1 -1
- package/dist/elements/Select/index.mjs +2 -3
- package/dist/elements/Select/index.mjs.map +1 -1
- package/dist/elements/Skeleton/index.js +2 -21
- package/dist/elements/Skeleton/index.js.map +1 -1
- package/dist/elements/Skeleton/index.mjs +2 -4
- package/dist/elements/Skeleton/index.mjs.map +1 -1
- package/dist/elements/Switch/index.js +2 -48
- package/dist/elements/Switch/index.js.map +1 -1
- package/dist/elements/Switch/index.mjs +2 -30
- package/dist/elements/Switch/index.mjs.map +1 -1
- package/dist/elements/Table/Table.d.ts +3 -24
- package/dist/elements/Table/Table.d.ts.map +1 -1
- package/dist/elements/Table/Table.styles.d.ts +24 -0
- package/dist/elements/Table/Table.styles.d.ts.map +1 -0
- package/dist/elements/Table/index.js +2 -75
- package/dist/elements/Table/index.js.map +1 -1
- package/dist/elements/Table/index.mjs +2 -6
- package/dist/elements/Table/index.mjs.map +1 -1
- package/dist/elements/Tabs/index.js +2 -73
- package/dist/elements/Tabs/index.js.map +1 -1
- package/dist/elements/Tabs/index.mjs +2 -4
- package/dist/elements/Tabs/index.mjs.map +1 -1
- package/dist/elements/TextField/TextField.d.ts +6 -42
- package/dist/elements/TextField/TextField.d.ts.map +1 -1
- package/dist/elements/TextField/TextField.hooks.d.ts +63 -0
- package/dist/elements/TextField/TextField.hooks.d.ts.map +1 -0
- package/dist/elements/TextField/TextField.icons.d.ts +19 -0
- package/dist/elements/TextField/TextField.icons.d.ts.map +1 -0
- package/dist/elements/TextField/TextField.styles.d.ts +37 -0
- package/dist/elements/TextField/TextField.styles.d.ts.map +1 -0
- package/dist/elements/TextField/TextField.types.d.ts +3 -0
- package/dist/elements/TextField/TextField.types.d.ts.map +1 -1
- package/dist/elements/TextField/index.css +1 -22
- package/dist/elements/TextField/index.css.map +1 -1
- package/dist/elements/TextField/index.js +2 -259
- package/dist/elements/TextField/index.js.map +1 -1
- package/dist/elements/TextField/index.mjs +2 -206
- package/dist/elements/TextField/index.mjs.map +1 -1
- package/dist/elements/TimeField/index.js +2 -44
- package/dist/elements/TimeField/index.js.map +1 -1
- package/dist/elements/TimeField/index.mjs +2 -3
- package/dist/elements/TimeField/index.mjs.map +1 -1
- package/dist/elements/Toast/Toast.d.ts +0 -22
- package/dist/elements/Toast/Toast.d.ts.map +1 -1
- package/dist/elements/Toast/index.js +2 -59
- package/dist/elements/Toast/index.js.map +1 -1
- package/dist/elements/Toast/index.mjs +2 -6
- package/dist/elements/Toast/index.mjs.map +1 -1
- package/dist/elements/Tooltip/index.js +2 -58
- package/dist/elements/Tooltip/index.js.map +1 -1
- package/dist/elements/Tooltip/index.mjs +2 -5
- package/dist/elements/Tooltip/index.mjs.map +1 -1
- package/dist/elements/index.css +1 -22
- package/dist/elements/index.css.map +1 -1
- package/dist/elements/index.d.ts +13 -1
- package/dist/elements/index.d.ts.map +1 -1
- package/dist/elements/index.js +2 -838
- package/dist/elements/index.js.map +1 -1
- package/dist/elements/index.mjs +2 -41
- package/dist/elements/index.mjs.map +1 -1
- package/dist/index.css +1 -22
- package/dist/index.css.map +1 -1
- package/dist/index.js +3 -864
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -43
- package/dist/index.mjs.map +1 -1
- package/dist/schemas/index.js +2 -28
- package/dist/schemas/index.js.map +1 -1
- package/dist/schemas/index.mjs +2 -3
- package/dist/schemas/index.mjs.map +1 -1
- package/dist/styles/defaults.css +151 -0
- package/dist/styles/index.js +1 -152
- package/dist/styles/index.js.map +1 -1
- package/dist/styles/index.mjs +1 -3
- package/dist/styles/index.mjs.map +1 -1
- package/dist/utils/index.js +1 -12
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +1 -3
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +9 -7
- package/src/elements/Accordion/Accordion.stories.tsx +1 -1
- package/src/elements/AlertDialog/AlertDialog.stories.tsx +124 -0
- package/src/elements/Avatar/Avatar.stories.tsx +1 -1
- package/src/elements/Badge/Badge.stories.tsx +1 -1
- package/src/elements/Breadcrumbs/Breadcrumbs.stories.tsx +1 -1
- package/src/elements/Button/Button.stories.tsx +1 -1
- package/src/elements/ButtonGroup/ButtonGroup.stories.tsx +1 -1
- package/src/elements/Card/Card.stories.tsx +1 -1
- package/src/elements/Carousel/Carousel.stories.tsx +1 -1
- package/src/elements/Chart/Chart.stories.tsx +1 -1
- package/src/elements/Checkbox/Checkbox.stories.tsx +1 -1
- package/src/elements/CheckboxGroup/CheckboxGroup.stories.tsx +1 -1
- package/src/elements/Combobox/Combobox.stories.tsx +133 -0
- package/src/elements/DatePicker/DatePicker.stories.tsx +1 -1
- package/src/elements/Dropdown/Dropdown.stories.tsx +1 -1
- package/src/elements/FileField/FileField.stories.tsx +1 -1
- package/src/elements/FileField/FileProgress.stories.tsx +1 -1
- package/src/elements/FormLayout/FormLayout.stories.tsx +1 -1
- package/src/elements/Modal/Modal.stories.tsx +1 -1
- package/src/elements/NumberField/NumberField.stories.tsx +1 -1
- package/src/elements/OTPInput/OTPInput.stories.tsx +1 -1
- package/src/elements/Pagination/Pagination.stories.tsx +203 -0
- package/src/elements/Panel/Panel.stories.tsx +1 -1
- package/src/elements/PasswordField/PasswordField.stories.tsx +167 -0
- package/src/elements/Progress/Progress.stories.tsx +1 -1
- package/src/elements/RadioGroup/RadioGroup.stories.tsx +1 -1
- package/src/elements/Resizable/Resizable.stories.tsx +1 -1
- package/src/elements/SearchField/SearchField.stories.tsx +146 -0
- package/src/elements/Select/Select.stories.tsx +1 -1
- package/src/elements/Skeleton/Skeleton.stories.tsx +1 -1
- package/src/elements/Switch/Switch.stories.tsx +1 -1
- package/src/elements/Table/Table.stories.tsx +1 -1
- package/src/elements/Tabs/Tabs.stories.tsx +1 -1
- package/src/elements/TextField/TextField.stories.tsx +1 -1
- package/src/elements/TimeField/TimeField.stories.tsx +1 -1
- package/src/elements/Toast/Toast.stories.tsx +1 -1
- package/src/elements/Tooltip/Tooltip.stories.tsx +1 -1
- package/dist/Carousel-NTZX5TOW.js +0 -16
- package/dist/Carousel-NTZX5TOW.js.map +0 -1
- package/dist/Carousel-YH3DOQJU.mjs +0 -7
- package/dist/Carousel-YH3DOQJU.mjs.map +0 -1
- package/dist/chunk-2HIUTHMU.mjs +0 -234
- package/dist/chunk-2HIUTHMU.mjs.map +0 -1
- package/dist/chunk-34GTFTDO.js +0 -431
- package/dist/chunk-34GTFTDO.js.map +0 -1
- package/dist/chunk-3H7ASYR7.js +0 -250
- package/dist/chunk-3H7ASYR7.js.map +0 -1
- package/dist/chunk-3IEN7JOP.js +0 -316
- package/dist/chunk-3IEN7JOP.js.map +0 -1
- package/dist/chunk-3JHN4GAL.js +0 -326
- package/dist/chunk-3JHN4GAL.js.map +0 -1
- package/dist/chunk-3MJPASQU.js +0 -232
- package/dist/chunk-3MJPASQU.js.map +0 -1
- package/dist/chunk-3XD2JUL3.js +0 -572
- package/dist/chunk-3XD2JUL3.js.map +0 -1
- package/dist/chunk-3YOY2VJ6.js +0 -189
- package/dist/chunk-3YOY2VJ6.js.map +0 -1
- package/dist/chunk-4DU5JSXB.js +0 -408
- package/dist/chunk-4DU5JSXB.js.map +0 -1
- package/dist/chunk-4E4E2GSS.js +0 -352
- package/dist/chunk-4E4E2GSS.js.map +0 -1
- package/dist/chunk-4NHAP4AN.mjs +0 -3
- package/dist/chunk-4NHAP4AN.mjs.map +0 -1
- package/dist/chunk-4S33J5NY.mjs +0 -415
- package/dist/chunk-4S33J5NY.mjs.map +0 -1
- package/dist/chunk-5SMGRT3G.mjs +0 -354
- package/dist/chunk-5SMGRT3G.mjs.map +0 -1
- package/dist/chunk-5SVLJN2C.mjs +0 -22
- package/dist/chunk-5SVLJN2C.mjs.map +0 -1
- package/dist/chunk-66WTU4EB.mjs +0 -299
- package/dist/chunk-66WTU4EB.mjs.map +0 -1
- package/dist/chunk-6S25NMOT.mjs +0 -335
- package/dist/chunk-6S25NMOT.mjs.map +0 -1
- package/dist/chunk-6SP7UB3D.js +0 -4
- package/dist/chunk-6SP7UB3D.js.map +0 -1
- package/dist/chunk-6TYWWQHM.mjs +0 -565
- package/dist/chunk-6TYWWQHM.mjs.map +0 -1
- package/dist/chunk-A3YUJA6W.mjs +0 -384
- package/dist/chunk-A3YUJA6W.mjs.map +0 -1
- package/dist/chunk-A6KEDVUR.js +0 -61
- package/dist/chunk-A6KEDVUR.js.map +0 -1
- package/dist/chunk-A77RUEWL.js +0 -730
- package/dist/chunk-A77RUEWL.js.map +0 -1
- package/dist/chunk-AA4IKMPE.mjs +0 -3
- package/dist/chunk-AA4IKMPE.mjs.map +0 -1
- package/dist/chunk-AKIA6GW6.mjs +0 -163
- package/dist/chunk-AKIA6GW6.mjs.map +0 -1
- package/dist/chunk-AL6P275L.mjs +0 -435
- package/dist/chunk-AL6P275L.mjs.map +0 -1
- package/dist/chunk-AZ3RJYTB.js +0 -37
- package/dist/chunk-AZ3RJYTB.js.map +0 -1
- package/dist/chunk-B5Q4UPL6.js +0 -32
- package/dist/chunk-B5Q4UPL6.js.map +0 -1
- package/dist/chunk-B6DHPMDP.mjs +0 -335
- package/dist/chunk-B6DHPMDP.mjs.map +0 -1
- package/dist/chunk-BDXKKMBZ.mjs +0 -184
- package/dist/chunk-BDXKKMBZ.mjs.map +0 -1
- package/dist/chunk-BL6E2DLZ.mjs +0 -52
- package/dist/chunk-BL6E2DLZ.mjs.map +0 -1
- package/dist/chunk-CGFDS4XS.mjs +0 -121
- package/dist/chunk-CGFDS4XS.mjs.map +0 -1
- package/dist/chunk-CJIW5TKI.js +0 -139
- package/dist/chunk-CJIW5TKI.js.map +0 -1
- package/dist/chunk-CKNISJOQ.js +0 -314
- package/dist/chunk-CKNISJOQ.js.map +0 -1
- package/dist/chunk-D6CBOECS.mjs +0 -1757
- package/dist/chunk-D6CBOECS.mjs.map +0 -1
- package/dist/chunk-DDWEVC2S.js +0 -166
- package/dist/chunk-DDWEVC2S.js.map +0 -1
- package/dist/chunk-DZ556D2F.mjs +0 -176
- package/dist/chunk-DZ556D2F.mjs.map +0 -1
- package/dist/chunk-E2KQFV3O.mjs +0 -10
- package/dist/chunk-E2KQFV3O.mjs.map +0 -1
- package/dist/chunk-EMMLADSC.js +0 -126
- package/dist/chunk-EMMLADSC.js.map +0 -1
- package/dist/chunk-EP4WOI5D.mjs +0 -926
- package/dist/chunk-EP4WOI5D.mjs.map +0 -1
- package/dist/chunk-FJRXLJC2.mjs +0 -160
- package/dist/chunk-FJRXLJC2.mjs.map +0 -1
- package/dist/chunk-FKQI434R.js +0 -345
- package/dist/chunk-FKQI434R.js.map +0 -1
- package/dist/chunk-FPKEAJRZ.mjs +0 -100
- package/dist/chunk-FPKEAJRZ.mjs.map +0 -1
- package/dist/chunk-FWQYB22U.js +0 -183
- package/dist/chunk-FWQYB22U.js.map +0 -1
- package/dist/chunk-GD5GHTMA.js +0 -189
- package/dist/chunk-GD5GHTMA.js.map +0 -1
- package/dist/chunk-GE5XTSDZ.js +0 -447
- package/dist/chunk-GE5XTSDZ.js.map +0 -1
- package/dist/chunk-GVE47ZAX.mjs +0 -32
- package/dist/chunk-GVE47ZAX.mjs.map +0 -1
- package/dist/chunk-HK46BT5U.mjs +0 -18
- package/dist/chunk-HK46BT5U.mjs.map +0 -1
- package/dist/chunk-HQVRMR6N.js +0 -365
- package/dist/chunk-HQVRMR6N.js.map +0 -1
- package/dist/chunk-HSGBJPJO.mjs +0 -398
- package/dist/chunk-HSGBJPJO.mjs.map +0 -1
- package/dist/chunk-I3AUTOMZ.mjs +0 -125
- package/dist/chunk-I3AUTOMZ.mjs.map +0 -1
- package/dist/chunk-IEI5LD5C.mjs +0 -1161
- package/dist/chunk-IEI5LD5C.mjs.map +0 -1
- package/dist/chunk-IIPTC2X7.mjs +0 -118
- package/dist/chunk-IIPTC2X7.mjs.map +0 -1
- package/dist/chunk-J7TLHF2Q.js +0 -4
- package/dist/chunk-J7TLHF2Q.js.map +0 -1
- package/dist/chunk-JJOWXFXQ.mjs +0 -765
- package/dist/chunk-JJOWXFXQ.mjs.map +0 -1
- package/dist/chunk-JPTSS2OA.mjs +0 -3
- package/dist/chunk-JPTSS2OA.mjs.map +0 -1
- package/dist/chunk-KFXXRLTP.js +0 -396
- package/dist/chunk-KFXXRLTP.js.map +0 -1
- package/dist/chunk-KPRRBSG6.mjs +0 -272
- package/dist/chunk-KPRRBSG6.mjs.map +0 -1
- package/dist/chunk-NFSBGRDB.mjs +0 -57
- package/dist/chunk-NFSBGRDB.mjs.map +0 -1
- package/dist/chunk-NGJVCFTM.js +0 -219
- package/dist/chunk-NGJVCFTM.js.map +0 -1
- package/dist/chunk-NSQ6MZJ6.mjs +0 -728
- package/dist/chunk-NSQ6MZJ6.mjs.map +0 -1
- package/dist/chunk-NYQYHT76.mjs +0 -296
- package/dist/chunk-NYQYHT76.mjs.map +0 -1
- package/dist/chunk-OLJJGI5B.js +0 -1193
- package/dist/chunk-OLJJGI5B.js.map +0 -1
- package/dist/chunk-Q3572X2J.js +0 -292
- package/dist/chunk-Q3572X2J.js.map +0 -1
- package/dist/chunk-QH7N7D4I.mjs +0 -210
- package/dist/chunk-QH7N7D4I.mjs.map +0 -1
- package/dist/chunk-R7XUIV25.js +0 -466
- package/dist/chunk-R7XUIV25.js.map +0 -1
- package/dist/chunk-RFFO4KPM.js +0 -135
- package/dist/chunk-RFFO4KPM.js.map +0 -1
- package/dist/chunk-RFX7QKA7.mjs +0 -180
- package/dist/chunk-RFX7QKA7.mjs.map +0 -1
- package/dist/chunk-SN5LFAP3.js +0 -940
- package/dist/chunk-SN5LFAP3.js.map +0 -1
- package/dist/chunk-T4COXKQ3.js +0 -24
- package/dist/chunk-T4COXKQ3.js.map +0 -1
- package/dist/chunk-TS54QM27.js +0 -125
- package/dist/chunk-TS54QM27.js.map +0 -1
- package/dist/chunk-UE2S4PCX.mjs +0 -220
- package/dist/chunk-UE2S4PCX.mjs.map +0 -1
- package/dist/chunk-UTW3QX2A.mjs +0 -282
- package/dist/chunk-UTW3QX2A.mjs.map +0 -1
- package/dist/chunk-V74LGMAE.js +0 -1767
- package/dist/chunk-V74LGMAE.js.map +0 -1
- package/dist/chunk-VIREG536.js +0 -12
- package/dist/chunk-VIREG536.js.map +0 -1
- package/dist/chunk-VY7M7346.js +0 -4
- package/dist/chunk-VY7M7346.js.map +0 -1
- package/dist/chunk-W3TJOO7H.mjs +0 -319
- package/dist/chunk-W3TJOO7H.mjs.map +0 -1
- package/dist/chunk-WIUOB36M.js +0 -54
- package/dist/chunk-WIUOB36M.js.map +0 -1
- package/dist/chunk-WJGLM4CY.js +0 -291
- package/dist/chunk-WJGLM4CY.js.map +0 -1
- package/dist/chunk-WNURH5OO.mjs +0 -453
- package/dist/chunk-WNURH5OO.mjs.map +0 -1
- package/dist/chunk-X25TNRSD.mjs +0 -364
- package/dist/chunk-X25TNRSD.mjs.map +0 -1
- package/dist/chunk-Y3GT7ETK.js +0 -108
- package/dist/chunk-Y3GT7ETK.js.map +0 -1
- package/dist/chunk-Z4FRNOF6.mjs +0 -115
- package/dist/chunk-Z4FRNOF6.mjs.map +0 -1
- package/dist/chunk-ZMYLD3BN.js +0 -166
- package/dist/chunk-ZMYLD3BN.js.map +0 -1
- package/dist/chunk-ZP2KV6EX.js +0 -815
- package/dist/chunk-ZP2KV6EX.js.map +0 -1
- package/dist/chunk-ZVKXFELU.js +0 -366
- package/dist/chunk-ZVKXFELU.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Modal/Modal.styles.ts","../../../src/elements/Modal/Modal.tsx"],"names":["cn","inputs","twMerge","clsx","modalContentVariants","cva","modalOverlayVariants","ModalContext","createContext","ModalRoot","children","defaultOpen","isOpen","onOpenChange","role","childArray","Children","hasTrigger","child","isValidElement","ModalTrigger","hasContent","ModalContent","triggerChild","contentChild","triggerElement","unwrappedTrigger","unwrappedContent","jsx","jsxs","AriaDialogTrigger","size","animation","animationDuration","isDismissable","isKeyboardDismissDisabled","showClose","className","useContext","overlayClasses","modalClasses","mergedModalClasses","AriaModalOverlay","AriaModal","AriaDialog","close","Fragment","AriaButton","X","ModalOverlay","_props","ModalHeader","ModalTitle","as","Heading","ModalDescription","ModalFooter","ModalClose","state","OverlayTriggerStateContext","childElement","handlePress","existingOnPress","cloneElement","Modal"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n/**\n * CVA Variants for Modal.Content\n *\n * Size and animation variant definitions for the modal content container.\n * Uses CSS custom properties for all colours to support theming.\n *\n * @see Modal.types.ts (ModalSize, ModalAnimation)\n */\nexport const modalContentVariants = cva(\n [\n // Base styles\n 'relative',\n 'bg-[var(--content-background)]',\n 'text-[var(--content-foreground)]',\n 'rounded-lg',\n 'shadow-lg',\n 'p-6',\n 'w-full',\n 'outline-none',\n // Responsive: full-width on mobile with padding, constrained on desktop\n 'mx-4',\n 'sm:mx-0',\n ],\n {\n variants: {\n size: {\n sm: 'max-w-sm', // 300px\n md: 'max-w-md', // 425px\n lg: 'max-w-lg', // 600px\n xl: 'max-w-2xl', // 800px\n full: 'max-w-full min-h-screen rounded-none', // Full screen\n },\n animation: {\n 'fade-zoom': 'animate-fadeIn', // Fade in with scale\n fade: 'animate-fadeIn', // Fade in only\n slide: 'animate-slideUp', // Slide up\n none: '', // No animation\n },\n },\n defaultVariants: {\n size: 'md',\n animation: 'fade-zoom',\n },\n }\n);\n\n/**\n * CVA Variants for Modal Overlay\n *\n * Animation variant definitions for the modal backdrop overlay.\n * Uses CSS custom properties for all colours to support theming.\n */\nexport const modalOverlayVariants = cva(\n [\n // Base overlay styles\n 'fixed',\n 'inset-0',\n 'z-50',\n 'flex',\n 'items-center',\n 'justify-center',\n 'bg-black/50',\n 'backdrop-blur-sm',\n ],\n {\n variants: {\n animation: {\n 'fade-zoom': 'animate-fadeIn',\n fade: 'animate-fadeIn',\n slide: 'animate-fadeIn',\n none: '',\n },\n },\n defaultVariants: {\n animation: 'fade-zoom',\n },\n }\n);\n\n/**\n * Type exports for variant props\n * Allows TypeScript inference of variant combinations\n */\nexport type ModalContentVariantProps = VariantProps<typeof modalContentVariants>;\nexport type ModalOverlayVariantProps = VariantProps<typeof modalOverlayVariants>;\n","'use client';\n\n/**\n * Modal Component - Implementation\n *\n * Accessible modal dialog component combining React Aria primitives with ShadCN styling.\n * Follows Themis library patterns with compound component structure.\n *\n * @see PRD.md (Full requirements)\n * @see Modal.types.ts (Zod schemas)\n * @see RESEARCH.md (React Aria patterns)\n */\n\nimport {\n Children,\n isValidElement,\n cloneElement,\n useContext,\n createContext,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n DialogTrigger as AriaDialogTrigger,\n Modal as AriaModal,\n ModalOverlay as AriaModalOverlay,\n Dialog as AriaDialog,\n Heading,\n Button as AriaButton,\n OverlayTriggerStateContext,\n} from 'react-aria-components';\nimport { X } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { modalContentVariants, modalOverlayVariants } from './Modal.styles';\nimport type {\n ModalProps,\n ModalTriggerProps,\n ModalContentProps,\n ModalOverlayProps,\n ModalHeaderProps,\n ModalTitleProps,\n ModalDescriptionProps,\n ModalFooterProps,\n ModalCloseProps,\n} from './Modal.types';\n\n/**\n * Modal Context\n * Passes role prop from Modal root to Modal.Content\n */\ninterface ModalContextValue {\n role?: 'dialog' | 'alertdialog';\n}\n\nconst ModalContext = createContext<ModalContextValue | undefined>(undefined);\n\n/**\n * Modal Root Component\n *\n * Manages modal open/close state and validates required children structure.\n * Must contain exactly one Modal.Trigger and one Modal.Content.\n *\n * Unwraps compound component children and passes them to React Aria's DialogTrigger.\n *\n * @see PRD.md FR-001 (Modal Root Requirements)\n * @see PRD.md FR-012 (Controlled Mode)\n * @see PRD.md FR-013 (Uncontrolled Mode)\n */\nfunction ModalRoot({ children, defaultOpen, isOpen, onOpenChange, role = 'dialog' }: ModalProps): ReactElement {\n const childArray = Children.toArray(children);\n\n // Validate children structure in development only\n if (process.env.NODE_ENV !== 'production') {\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalTrigger ||\n (child.type as { displayName?: string }).displayName === 'ModalTrigger')\n );\n\n const hasContent = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalContent ||\n (child.type as { displayName?: string }).displayName === 'ModalContent')\n );\n\n if (!hasTrigger || !hasContent) {\n throw new Error(\n 'Modal requires exactly one Modal.Trigger and one Modal.Content as children'\n );\n }\n }\n\n // Find trigger and content children\n const triggerChild = childArray.find(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalTrigger ||\n (child.type as { displayName?: string }).displayName === 'ModalTrigger')\n );\n\n const contentChild = childArray.find(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalContent ||\n (child.type as { displayName?: string }).displayName === 'ModalContent')\n );\n\n // Extract the actual children from Modal.Trigger and Modal.Content\n // React Aria's DialogTrigger expects direct Button and Modal children\n const triggerElement = triggerChild as ReactElement;\n const unwrappedTrigger = isValidElement(triggerElement)\n ? ((triggerElement.props as unknown as { children?: ReactNode }).children as ReactNode)\n : null;\n const unwrappedContent = contentChild as ReactElement;\n\n return (\n <ModalContext.Provider value={{ role }}>\n <AriaDialogTrigger\n defaultOpen={defaultOpen}\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n >\n {unwrappedTrigger}\n {unwrappedContent}\n </AriaDialogTrigger>\n </ModalContext.Provider>\n );\n}\n\nModalRoot.displayName = 'Modal';\n\n/**\n * Modal.Trigger Component\n *\n * Wraps a single child element (typically Button) with modal trigger behavior.\n * Handles click events to open modal and manages ARIA attributes.\n *\n * React Aria's DialogTrigger (used in Modal root) automatically applies:\n * - aria-haspopup=\"dialog\"\n * - aria-expanded (true/false based on state)\n * - onClick handler to toggle modal\n *\n * @see PRD.md FR-002 (Trigger Requirements)\n * @see RESEARCH.md Section 2 (React Aria Integration)\n */\nfunction ModalTrigger({ children }: ModalTriggerProps): ReactElement {\n // React Aria's DialogTrigger (in Modal root) automatically adds ARIA attributes\n // to the first child component. We pass through the child element directly.\n return children as ReactElement;\n}\n\nModalTrigger.displayName = 'ModalTrigger';\n\n/**\n * Modal.Content Component\n *\n * Renders the modal content with overlay backdrop.\n * Uses React Aria's Modal and ModalOverlay for accessibility.\n * Applies CVA variants for size and animation.\n *\n * @see PRD.md FR-003 (Content Requirements)\n * @see PRD.md TR-001 (CVA Variant Styling)\n * @see RESEARCH.md Section 2 (React Aria Integration)\n */\nfunction ModalContent({\n children,\n size = 'md',\n animation = 'fade-zoom',\n animationDuration = 200,\n isDismissable = true,\n isKeyboardDismissDisabled = false,\n showClose = true,\n className,\n}: ModalContentProps): ReactElement {\n // Get role from context\n const context = useContext(ModalContext);\n const role = context?.role ?? 'dialog';\n\n // Generate overlay classes with animation variant\n const overlayClasses = modalOverlayVariants({ animation });\n\n // Generate modal classes with size and animation variants, merged with custom className\n const modalClasses = modalContentVariants({ size, animation });\n const mergedModalClasses = cn(modalClasses, className);\n\n return (\n <AriaModalOverlay\n isDismissable={isDismissable}\n isKeyboardDismissDisabled={isKeyboardDismissDisabled}\n className={overlayClasses}\n >\n <AriaModal\n className={mergedModalClasses}\n style={{\n transitionDuration: `${animationDuration}ms`,\n }}\n >\n <AriaDialog role={role} className=\"outline-none\">\n {({ close }) => (\n <>\n {showClose && (\n <AriaButton\n onPress={close}\n className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-[var(--content-background)] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[var(--ring)] focus:ring-offset-2 disabled:pointer-events-none min-h-[44px] min-w-[44px]\"\n aria-label=\"Close modal\"\n >\n <X className=\"h-4 w-4\" aria-hidden=\"true\" />\n </AriaButton>\n )}\n {children}\n </>\n )}\n </AriaDialog>\n </AriaModal>\n </AriaModalOverlay>\n );\n}\n\nModalContent.displayName = 'ModalContent';\n\n/**\n * Modal.Overlay Component (Placeholder - not exposed in public API)\n * Overlay is managed internally by Modal.Content via AriaModalOverlay\n */\nfunction ModalOverlay(_props: ModalOverlayProps): null {\n return null;\n}\n\nModalOverlay.displayName = 'ModalOverlay';\n\n/**\n * Modal.Header Component\n *\n * Container for modal header content (typically Title and Description).\n * Applies consistent spacing and layout.\n *\n * @see PRD.md FR-005 (Header Requirements)\n */\nfunction ModalHeader({ children, className }: ModalHeaderProps): ReactElement {\n return <div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)}>{children}</div>;\n}\n\nModalHeader.displayName = 'ModalHeader';\n\n/**\n * Modal.Title Component\n *\n * Renders modal title using React Aria's Heading component.\n * Automatically links to modal via aria-labelledby.\n *\n * @see PRD.md FR-006 (Title Requirements)\n * @see PRD.md AR-002 (ARIA Attributes - auto-labelledby)\n */\nfunction ModalTitle({ children, as = 'h2', className }: ModalTitleProps): ReactElement {\n return (\n <Heading slot=\"title\" level={parseInt(as[1] ?? '2')} className={cn('text-lg font-semibold leading-none tracking-tight', className)}>\n {children}\n </Heading>\n );\n}\n\nModalTitle.displayName = 'ModalTitle';\n\n/**\n * Modal.Description Component\n *\n * Renders description text that automatically links to modal via aria-describedby.\n * Uses muted text color for visual hierarchy.\n *\n * @see PRD.md FR-007 (Description Requirements)\n * @see PRD.md AR-002 (ARIA Attributes - auto-describedby)\n */\nfunction ModalDescription({ children, className }: ModalDescriptionProps): ReactElement {\n return (\n <p slot=\"description\" className={cn('text-sm text-[var(--menu-muted)]', className)}>\n {children}\n </p>\n );\n}\n\nModalDescription.displayName = 'ModalDescription';\n\n/**\n * Modal.Footer Component\n *\n * Container for modal action buttons (Cancel, Confirm, etc.).\n * Aligns buttons to the right with consistent spacing.\n * Responsive: stacks vertically on mobile, horizontal on desktop.\n *\n * @see PRD.md FR-008 (Footer Requirements)\n * @see PRD.md DS-003 (Spacing - footer button gap)\n */\nfunction ModalFooter({ children, className }: ModalFooterProps): ReactElement {\n return <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end gap-2', className)}>{children}</div>;\n}\n\nModalFooter.displayName = 'ModalFooter';\n\n/**\n * Modal.Close Component\n *\n * Wraps a child element (typically Button) with modal close behavior.\n * Uses OverlayTriggerStateContext from React Aria to access close function.\n *\n * @see PRD.md FR-009 (Close Requirements)\n */\nfunction ModalClose({ children }: ModalCloseProps): ReactElement {\n // Access the overlay trigger state from React Aria context\n const state = useContext(OverlayTriggerStateContext);\n\n if (!state) {\n throw new Error('Modal.Close must be used inside Modal.Content');\n }\n\n // Clone the child element and add/merge the onPress handler to close the modal\n if (!isValidElement(children)) {\n throw new Error('Modal.Close requires a valid React element as a child');\n }\n\n // Cast to ReactElement after validation\n const childElement = children as ReactElement;\n\n const handlePress = (): void => {\n state.close();\n };\n\n // Merge with existing onPress if present\n const existingOnPress = (childElement.props as unknown as { onPress?: () => void })?.onPress;\n const mergedOnPress = existingOnPress\n ? (): void => {\n existingOnPress();\n handlePress();\n }\n : handlePress;\n\n // cloneElement with onPress override - use unknown for flexible typing\n return cloneElement(childElement, { onPress: mergedOnPress } as unknown as Partial<typeof childElement.props>);\n}\n\nModalClose.displayName = 'ModalClose';\n\n/**\n * Re-export CVA variants from Modal.styles.ts for backwards compatibility.\n * Consumers importing { modalContentVariants, modalOverlayVariants } from './Modal'\n * will continue to work.\n */\nexport { modalContentVariants, modalOverlayVariants } from './Modal.styles';\n\n/**\n * Compound Component Export\n *\n * Follows Themis library pattern using Object.assign() for compound components.\n * Enables usage like Modal.Trigger, Modal.Content, etc.\n *\n * @deprecated The Object.assign compound pattern will be removed in v2.\n * Use the direct named exports (ModalTrigger, ModalContent, etc.) instead.\n * This pattern is kept for backwards compatibility only.\n *\n * @see RESEARCH.md Section 1 (Compound Component Pattern)\n */\nexport const Modal = Object.assign(ModalRoot, {\n Trigger: ModalTrigger,\n Content: ModalContent,\n Overlay: ModalOverlay,\n Header: ModalHeader,\n Title: ModalTitle,\n Description: ModalDescription,\n Footer: ModalFooter,\n Close: ModalClose,\n});\n\n// Named exports for individual components\nexport {\n ModalRoot,\n ModalTrigger,\n ModalContent,\n ModalOverlay,\n ModalHeader,\n ModalTitle,\n ModalDescription,\n ModalFooter,\n ModalClose,\n};\n"]}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import {createContext,Children,isValidElement,useContext,cloneElement}from'react';import {DialogTrigger,OverlayTriggerStateContext,Heading,ModalOverlay,Modal,Dialog,Button}from'react-aria-components';import {X as X$1}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {cva}from'class-variance-authority';import {jsx,jsxs,Fragment}from'react/jsx-runtime';function d(...e){return twMerge(clsx(e))}var M=cva(["relative","bg-[var(--content-background)]","text-[var(--content-foreground)]","rounded-lg","shadow-lg","p-6","w-full","outline-none","mx-4","sm:mx-0"],{variants:{size:{sm:"max-w-sm",md:"max-w-md",lg:"max-w-lg",xl:"max-w-2xl",full:"max-w-full min-h-screen rounded-none"},animation:{"fade-zoom":"animate-fadeIn",fade:"animate-fadeIn",slide:"animate-slideUp",none:""}},defaultVariants:{size:"md",animation:"fade-zoom"}}),g=cva(["fixed","inset-0","z-50","flex","items-center","justify-center","bg-black/50","backdrop-blur-sm"],{variants:{animation:{"fade-zoom":"animate-fadeIn",fade:"animate-fadeIn",slide:"animate-fadeIn",none:""}},defaultVariants:{animation:"fade-zoom"}});var R=createContext(void 0);function h({children:e,defaultOpen:a,isOpen:r,onOpenChange:s,role:i="dialog"}){let l=Children.toArray(e);if(process.env.NODE_ENV!=="production"){let o=l.some(n=>isValidElement(n)&&(n.type===m||n.type.displayName==="ModalTrigger")),P=l.some(n=>isValidElement(n)&&(n.type===c||n.type.displayName==="ModalContent"));if(!o||!P)throw new Error("Modal requires exactly one Modal.Trigger and one Modal.Content as children")}let f=l.find(o=>isValidElement(o)&&(o.type===m||o.type.displayName==="ModalTrigger")),u=l.find(o=>isValidElement(o)&&(o.type===c||o.type.displayName==="ModalContent")),y=f,x=isValidElement(y)?y.props.children:null,C=u;return jsx(R.Provider,{value:{role:i},children:jsxs(DialogTrigger,{defaultOpen:a,isOpen:r,onOpenChange:s,children:[x,C]})})}h.displayName="Modal";function m({children:e}){return e}m.displayName="ModalTrigger";function c({children:e,size:a="md",animation:r="fade-zoom",animationDuration:s=200,isDismissable:i=true,isKeyboardDismissDisabled:l=false,showClose:f=true,className:u}){let x=useContext(R)?.role??"dialog",C=g({animation:r}),o=M({size:a,animation:r}),P=d(o,u);return jsx(ModalOverlay,{isDismissable:i,isKeyboardDismissDisabled:l,className:C,children:jsx(Modal,{className:P,style:{transitionDuration:`${s}ms`},children:jsx(Dialog,{role:x,className:"outline-none",children:({close:n})=>jsxs(Fragment,{children:[f&&jsx(Button,{onPress:n,className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-[var(--content-background)] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[var(--ring)] focus:ring-offset-2 disabled:pointer-events-none min-h-[44px] min-w-[44px]","aria-label":"Close modal",children:jsx(X$1,{className:"h-4 w-4","aria-hidden":"true"})}),e]})})})})}c.displayName="ModalContent";function v(e){return null}v.displayName="ModalOverlay";function N({children:e,className:a}){return jsx("div",{className:d("flex flex-col space-y-1.5 text-center sm:text-left",a),children:e})}N.displayName="ModalHeader";function O({children:e,as:a="h2",className:r}){return jsx(Heading,{slot:"title",level:parseInt(a[1]??"2"),className:d("text-lg font-semibold leading-none tracking-tight",r),children:e})}O.displayName="ModalTitle";function V({children:e,className:a}){return jsx("p",{slot:"description",className:d("text-sm text-[var(--menu-muted)]",a),children:e})}V.displayName="ModalDescription";function E({children:e,className:a}){return jsx("div",{className:d("flex flex-col-reverse sm:flex-row sm:justify-end gap-2",a),children:e})}E.displayName="ModalFooter";function T({children:e}){let a=useContext(OverlayTriggerStateContext);if(!a)throw new Error("Modal.Close must be used inside Modal.Content");if(!isValidElement(e))throw new Error("Modal.Close requires a valid React element as a child");let r=e,s=()=>{a.close();},i=r.props?.onPress;return cloneElement(r,{onPress:i?()=>{i(),s();}:s})}T.displayName="ModalClose";var X=Object.assign(h,{Trigger:m,Content:c,Overlay:v,Header:N,Title:O,Description:V,Footer:E,Close:T});export{X as Modal,T as ModalClose,c as ModalContent,V as ModalDescription,E as ModalFooter,N as ModalHeader,v as ModalOverlay,O as ModalTitle,m as ModalTrigger,M as modalContentVariants,g as modalOverlayVariants};//# sourceMappingURL=index.mjs.map
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Modal/Modal.styles.ts","../../../src/elements/Modal/Modal.tsx"],"names":["cn","inputs","twMerge","clsx","modalContentVariants","cva","modalOverlayVariants","ModalContext","createContext","ModalRoot","children","defaultOpen","isOpen","onOpenChange","role","childArray","Children","hasTrigger","child","isValidElement","ModalTrigger","hasContent","ModalContent","triggerChild","contentChild","triggerElement","unwrappedTrigger","unwrappedContent","jsx","jsxs","AriaDialogTrigger","size","animation","animationDuration","isDismissable","isKeyboardDismissDisabled","showClose","className","useContext","overlayClasses","modalClasses","mergedModalClasses","AriaModalOverlay","AriaModal","AriaDialog","close","Fragment","AriaButton","X","ModalOverlay","_props","ModalHeader","ModalTitle","as","Heading","ModalDescription","ModalFooter","ModalClose","state","OverlayTriggerStateContext","childElement","handlePress","existingOnPress","cloneElement","Modal"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva, type VariantProps } from 'class-variance-authority';\n\n/**\n * CVA Variants for Modal.Content\n *\n * Size and animation variant definitions for the modal content container.\n * Uses CSS custom properties for all colours to support theming.\n *\n * @see Modal.types.ts (ModalSize, ModalAnimation)\n */\nexport const modalContentVariants = cva(\n [\n // Base styles\n 'relative',\n 'bg-[var(--content-background)]',\n 'text-[var(--content-foreground)]',\n 'rounded-lg',\n 'shadow-lg',\n 'p-6',\n 'w-full',\n 'outline-none',\n // Responsive: full-width on mobile with padding, constrained on desktop\n 'mx-4',\n 'sm:mx-0',\n ],\n {\n variants: {\n size: {\n sm: 'max-w-sm', // 300px\n md: 'max-w-md', // 425px\n lg: 'max-w-lg', // 600px\n xl: 'max-w-2xl', // 800px\n full: 'max-w-full min-h-screen rounded-none', // Full screen\n },\n animation: {\n 'fade-zoom': 'animate-fadeIn', // Fade in with scale\n fade: 'animate-fadeIn', // Fade in only\n slide: 'animate-slideUp', // Slide up\n none: '', // No animation\n },\n },\n defaultVariants: {\n size: 'md',\n animation: 'fade-zoom',\n },\n }\n);\n\n/**\n * CVA Variants for Modal Overlay\n *\n * Animation variant definitions for the modal backdrop overlay.\n * Uses CSS custom properties for all colours to support theming.\n */\nexport const modalOverlayVariants = cva(\n [\n // Base overlay styles\n 'fixed',\n 'inset-0',\n 'z-50',\n 'flex',\n 'items-center',\n 'justify-center',\n 'bg-black/50',\n 'backdrop-blur-sm',\n ],\n {\n variants: {\n animation: {\n 'fade-zoom': 'animate-fadeIn',\n fade: 'animate-fadeIn',\n slide: 'animate-fadeIn',\n none: '',\n },\n },\n defaultVariants: {\n animation: 'fade-zoom',\n },\n }\n);\n\n/**\n * Type exports for variant props\n * Allows TypeScript inference of variant combinations\n */\nexport type ModalContentVariantProps = VariantProps<typeof modalContentVariants>;\nexport type ModalOverlayVariantProps = VariantProps<typeof modalOverlayVariants>;\n","'use client';\n\n/**\n * Modal Component - Implementation\n *\n * Accessible modal dialog component combining React Aria primitives with ShadCN styling.\n * Follows Themis library patterns with compound component structure.\n *\n * @see PRD.md (Full requirements)\n * @see Modal.types.ts (Zod schemas)\n * @see RESEARCH.md (React Aria patterns)\n */\n\nimport {\n Children,\n isValidElement,\n cloneElement,\n useContext,\n createContext,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport {\n DialogTrigger as AriaDialogTrigger,\n Modal as AriaModal,\n ModalOverlay as AriaModalOverlay,\n Dialog as AriaDialog,\n Heading,\n Button as AriaButton,\n OverlayTriggerStateContext,\n} from 'react-aria-components';\nimport { X } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport { modalContentVariants, modalOverlayVariants } from './Modal.styles';\nimport type {\n ModalProps,\n ModalTriggerProps,\n ModalContentProps,\n ModalOverlayProps,\n ModalHeaderProps,\n ModalTitleProps,\n ModalDescriptionProps,\n ModalFooterProps,\n ModalCloseProps,\n} from './Modal.types';\n\n/**\n * Modal Context\n * Passes role prop from Modal root to Modal.Content\n */\ninterface ModalContextValue {\n role?: 'dialog' | 'alertdialog';\n}\n\nconst ModalContext = createContext<ModalContextValue | undefined>(undefined);\n\n/**\n * Modal Root Component\n *\n * Manages modal open/close state and validates required children structure.\n * Must contain exactly one Modal.Trigger and one Modal.Content.\n *\n * Unwraps compound component children and passes them to React Aria's DialogTrigger.\n *\n * @see PRD.md FR-001 (Modal Root Requirements)\n * @see PRD.md FR-012 (Controlled Mode)\n * @see PRD.md FR-013 (Uncontrolled Mode)\n */\nfunction ModalRoot({ children, defaultOpen, isOpen, onOpenChange, role = 'dialog' }: ModalProps): ReactElement {\n const childArray = Children.toArray(children);\n\n // Validate children structure in development only\n if (process.env.NODE_ENV !== 'production') {\n const hasTrigger = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalTrigger ||\n (child.type as { displayName?: string }).displayName === 'ModalTrigger')\n );\n\n const hasContent = childArray.some(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalContent ||\n (child.type as { displayName?: string }).displayName === 'ModalContent')\n );\n\n if (!hasTrigger || !hasContent) {\n throw new Error(\n 'Modal requires exactly one Modal.Trigger and one Modal.Content as children'\n );\n }\n }\n\n // Find trigger and content children\n const triggerChild = childArray.find(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalTrigger ||\n (child.type as { displayName?: string }).displayName === 'ModalTrigger')\n );\n\n const contentChild = childArray.find(\n (child) =>\n isValidElement(child) &&\n (child.type === ModalContent ||\n (child.type as { displayName?: string }).displayName === 'ModalContent')\n );\n\n // Extract the actual children from Modal.Trigger and Modal.Content\n // React Aria's DialogTrigger expects direct Button and Modal children\n const triggerElement = triggerChild as ReactElement;\n const unwrappedTrigger = isValidElement(triggerElement)\n ? ((triggerElement.props as unknown as { children?: ReactNode }).children as ReactNode)\n : null;\n const unwrappedContent = contentChild as ReactElement;\n\n return (\n <ModalContext.Provider value={{ role }}>\n <AriaDialogTrigger\n defaultOpen={defaultOpen}\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n >\n {unwrappedTrigger}\n {unwrappedContent}\n </AriaDialogTrigger>\n </ModalContext.Provider>\n );\n}\n\nModalRoot.displayName = 'Modal';\n\n/**\n * Modal.Trigger Component\n *\n * Wraps a single child element (typically Button) with modal trigger behavior.\n * Handles click events to open modal and manages ARIA attributes.\n *\n * React Aria's DialogTrigger (used in Modal root) automatically applies:\n * - aria-haspopup=\"dialog\"\n * - aria-expanded (true/false based on state)\n * - onClick handler to toggle modal\n *\n * @see PRD.md FR-002 (Trigger Requirements)\n * @see RESEARCH.md Section 2 (React Aria Integration)\n */\nfunction ModalTrigger({ children }: ModalTriggerProps): ReactElement {\n // React Aria's DialogTrigger (in Modal root) automatically adds ARIA attributes\n // to the first child component. We pass through the child element directly.\n return children as ReactElement;\n}\n\nModalTrigger.displayName = 'ModalTrigger';\n\n/**\n * Modal.Content Component\n *\n * Renders the modal content with overlay backdrop.\n * Uses React Aria's Modal and ModalOverlay for accessibility.\n * Applies CVA variants for size and animation.\n *\n * @see PRD.md FR-003 (Content Requirements)\n * @see PRD.md TR-001 (CVA Variant Styling)\n * @see RESEARCH.md Section 2 (React Aria Integration)\n */\nfunction ModalContent({\n children,\n size = 'md',\n animation = 'fade-zoom',\n animationDuration = 200,\n isDismissable = true,\n isKeyboardDismissDisabled = false,\n showClose = true,\n className,\n}: ModalContentProps): ReactElement {\n // Get role from context\n const context = useContext(ModalContext);\n const role = context?.role ?? 'dialog';\n\n // Generate overlay classes with animation variant\n const overlayClasses = modalOverlayVariants({ animation });\n\n // Generate modal classes with size and animation variants, merged with custom className\n const modalClasses = modalContentVariants({ size, animation });\n const mergedModalClasses = cn(modalClasses, className);\n\n return (\n <AriaModalOverlay\n isDismissable={isDismissable}\n isKeyboardDismissDisabled={isKeyboardDismissDisabled}\n className={overlayClasses}\n >\n <AriaModal\n className={mergedModalClasses}\n style={{\n transitionDuration: `${animationDuration}ms`,\n }}\n >\n <AriaDialog role={role} className=\"outline-none\">\n {({ close }) => (\n <>\n {showClose && (\n <AriaButton\n onPress={close}\n className=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-[var(--content-background)] transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-[var(--ring)] focus:ring-offset-2 disabled:pointer-events-none min-h-[44px] min-w-[44px]\"\n aria-label=\"Close modal\"\n >\n <X className=\"h-4 w-4\" aria-hidden=\"true\" />\n </AriaButton>\n )}\n {children}\n </>\n )}\n </AriaDialog>\n </AriaModal>\n </AriaModalOverlay>\n );\n}\n\nModalContent.displayName = 'ModalContent';\n\n/**\n * Modal.Overlay Component (Placeholder - not exposed in public API)\n * Overlay is managed internally by Modal.Content via AriaModalOverlay\n */\nfunction ModalOverlay(_props: ModalOverlayProps): null {\n return null;\n}\n\nModalOverlay.displayName = 'ModalOverlay';\n\n/**\n * Modal.Header Component\n *\n * Container for modal header content (typically Title and Description).\n * Applies consistent spacing and layout.\n *\n * @see PRD.md FR-005 (Header Requirements)\n */\nfunction ModalHeader({ children, className }: ModalHeaderProps): ReactElement {\n return <div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)}>{children}</div>;\n}\n\nModalHeader.displayName = 'ModalHeader';\n\n/**\n * Modal.Title Component\n *\n * Renders modal title using React Aria's Heading component.\n * Automatically links to modal via aria-labelledby.\n *\n * @see PRD.md FR-006 (Title Requirements)\n * @see PRD.md AR-002 (ARIA Attributes - auto-labelledby)\n */\nfunction ModalTitle({ children, as = 'h2', className }: ModalTitleProps): ReactElement {\n return (\n <Heading slot=\"title\" level={parseInt(as[1] ?? '2')} className={cn('text-lg font-semibold leading-none tracking-tight', className)}>\n {children}\n </Heading>\n );\n}\n\nModalTitle.displayName = 'ModalTitle';\n\n/**\n * Modal.Description Component\n *\n * Renders description text that automatically links to modal via aria-describedby.\n * Uses muted text color for visual hierarchy.\n *\n * @see PRD.md FR-007 (Description Requirements)\n * @see PRD.md AR-002 (ARIA Attributes - auto-describedby)\n */\nfunction ModalDescription({ children, className }: ModalDescriptionProps): ReactElement {\n return (\n <p slot=\"description\" className={cn('text-sm text-[var(--menu-muted)]', className)}>\n {children}\n </p>\n );\n}\n\nModalDescription.displayName = 'ModalDescription';\n\n/**\n * Modal.Footer Component\n *\n * Container for modal action buttons (Cancel, Confirm, etc.).\n * Aligns buttons to the right with consistent spacing.\n * Responsive: stacks vertically on mobile, horizontal on desktop.\n *\n * @see PRD.md FR-008 (Footer Requirements)\n * @see PRD.md DS-003 (Spacing - footer button gap)\n */\nfunction ModalFooter({ children, className }: ModalFooterProps): ReactElement {\n return <div className={cn('flex flex-col-reverse sm:flex-row sm:justify-end gap-2', className)}>{children}</div>;\n}\n\nModalFooter.displayName = 'ModalFooter';\n\n/**\n * Modal.Close Component\n *\n * Wraps a child element (typically Button) with modal close behavior.\n * Uses OverlayTriggerStateContext from React Aria to access close function.\n *\n * @see PRD.md FR-009 (Close Requirements)\n */\nfunction ModalClose({ children }: ModalCloseProps): ReactElement {\n // Access the overlay trigger state from React Aria context\n const state = useContext(OverlayTriggerStateContext);\n\n if (!state) {\n throw new Error('Modal.Close must be used inside Modal.Content');\n }\n\n // Clone the child element and add/merge the onPress handler to close the modal\n if (!isValidElement(children)) {\n throw new Error('Modal.Close requires a valid React element as a child');\n }\n\n // Cast to ReactElement after validation\n const childElement = children as ReactElement;\n\n const handlePress = (): void => {\n state.close();\n };\n\n // Merge with existing onPress if present\n const existingOnPress = (childElement.props as unknown as { onPress?: () => void })?.onPress;\n const mergedOnPress = existingOnPress\n ? (): void => {\n existingOnPress();\n handlePress();\n }\n : handlePress;\n\n // cloneElement with onPress override - use unknown for flexible typing\n return cloneElement(childElement, { onPress: mergedOnPress } as unknown as Partial<typeof childElement.props>);\n}\n\nModalClose.displayName = 'ModalClose';\n\n/**\n * Re-export CVA variants from Modal.styles.ts for backwards compatibility.\n * Consumers importing { modalContentVariants, modalOverlayVariants } from './Modal'\n * will continue to work.\n */\nexport { modalContentVariants, modalOverlayVariants } from './Modal.styles';\n\n/**\n * Compound Component Export\n *\n * Follows Themis library pattern using Object.assign() for compound components.\n * Enables usage like Modal.Trigger, Modal.Content, etc.\n *\n * @deprecated The Object.assign compound pattern will be removed in v2.\n * Use the direct named exports (ModalTrigger, ModalContent, etc.) instead.\n * This pattern is kept for backwards compatibility only.\n *\n * @see RESEARCH.md Section 1 (Compound Component Pattern)\n */\nexport const Modal = Object.assign(ModalRoot, {\n Trigger: ModalTrigger,\n Content: ModalContent,\n Overlay: ModalOverlay,\n Header: ModalHeader,\n Title: ModalTitle,\n Description: ModalDescription,\n Footer: ModalFooter,\n Close: ModalClose,\n});\n\n// Named exports for individual components\nexport {\n ModalRoot,\n ModalTrigger,\n ModalContent,\n ModalOverlay,\n ModalHeader,\n ModalTitle,\n ModalDescription,\n ModalFooter,\n ModalClose,\n};\n"]}
|
|
@@ -1,57 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require('../../chunk-6SP7UB3D.js');
|
|
4
|
-
var chunkKFXXRLTP_js = require('../../chunk-KFXXRLTP.js');
|
|
5
|
-
require('../../chunk-3YOY2VJ6.js');
|
|
6
|
-
require('../../chunk-Y3GT7ETK.js');
|
|
7
|
-
require('../../chunk-B5Q4UPL6.js');
|
|
8
|
-
require('../../chunk-VIREG536.js');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Object.defineProperty(exports, "DEFAULT_MAX_VALUE", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () { return chunkKFXXRLTP_js.DEFAULT_MAX_VALUE; }
|
|
15
|
-
});
|
|
16
|
-
Object.defineProperty(exports, "DEFAULT_MIN_VALUE", {
|
|
17
|
-
enumerable: true,
|
|
18
|
-
get: function () { return chunkKFXXRLTP_js.DEFAULT_MIN_VALUE; }
|
|
19
|
-
});
|
|
20
|
-
Object.defineProperty(exports, "NEGATIVE_MIN_VALUE", {
|
|
21
|
-
enumerable: true,
|
|
22
|
-
get: function () { return chunkKFXXRLTP_js.NEGATIVE_MIN_VALUE; }
|
|
23
|
-
});
|
|
24
|
-
Object.defineProperty(exports, "NumberField", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () { return chunkKFXXRLTP_js.NumberField; }
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(exports, "NumberFieldPropsSchema", {
|
|
29
|
-
enumerable: true,
|
|
30
|
-
get: function () { return chunkKFXXRLTP_js.NumberFieldPropsSchema; }
|
|
31
|
-
});
|
|
32
|
-
Object.defineProperty(exports, "numberFieldDescriptionVariants", {
|
|
33
|
-
enumerable: true,
|
|
34
|
-
get: function () { return chunkKFXXRLTP_js.numberFieldDescriptionVariants; }
|
|
35
|
-
});
|
|
36
|
-
Object.defineProperty(exports, "numberFieldErrorVariants", {
|
|
37
|
-
enumerable: true,
|
|
38
|
-
get: function () { return chunkKFXXRLTP_js.numberFieldErrorVariants; }
|
|
39
|
-
});
|
|
40
|
-
Object.defineProperty(exports, "numberFieldInputVariants", {
|
|
41
|
-
enumerable: true,
|
|
42
|
-
get: function () { return chunkKFXXRLTP_js.numberFieldInputVariants; }
|
|
43
|
-
});
|
|
44
|
-
Object.defineProperty(exports, "numberFieldLabelVariants", {
|
|
45
|
-
enumerable: true,
|
|
46
|
-
get: function () { return chunkKFXXRLTP_js.numberFieldLabelVariants; }
|
|
47
|
-
});
|
|
48
|
-
Object.defineProperty(exports, "numberFieldStepperVariants", {
|
|
49
|
-
enumerable: true,
|
|
50
|
-
get: function () { return chunkKFXXRLTP_js.numberFieldStepperVariants; }
|
|
51
|
-
});
|
|
52
|
-
Object.defineProperty(exports, "numberFieldVariants", {
|
|
53
|
-
enumerable: true,
|
|
54
|
-
get: function () { return chunkKFXXRLTP_js.numberFieldVariants; }
|
|
55
|
-
});
|
|
56
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var react=require('react'),reactAriaComponents=require('react-aria-components'),lucideReact=require('lucide-react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),classVarianceAuthority=require('class-variance-authority'),jsxRuntime=require('react/jsx-runtime'),zod=require('zod');function t(...c){return tailwindMerge.twMerge(clsx.clsx(c))}var C=classVarianceAuthority.cva("inline-flex justify-center min-h-[44px] min-w-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50",{variants:{fullWidth:{true:"w-full",false:""},inVerticalGroup:{true:"items-stretch",false:"items-center"}},defaultVariants:{fullWidth:false,inVerticalGroup:false}}),L=classVarianceAuthority.cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative cursor-pointer",{variants:{variant:{default:"bg-[var(--primary-action)] text-[var(--primary-action-foreground)] shadow-md hover:bg-[var(--primary-action-hover)] data-[pressed]:bg-[var(--primary-action)]/80",destructive:"bg-[var(--destructive-background)] text-[var(--destructive-foreground)] shadow-md hover:bg-[var(--destructive-background)]/90 data-[pressed]:bg-[var(--destructive-background)]/80",outline:"border border-[var(--input-border)] bg-[var(--page-background)] hover:bg-[var(--input-border)] data-[pressed]:bg-[var(--input-border)]",secondary:"bg-[var(--secondary)] text-[var(--secondary-foreground)] shadow-md hover:bg-[var(--secondary)]/80 data-[pressed]:bg-[var(--secondary)]/70",ghost:"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)] data-[pressed]:bg-[var(--accent)]",link:"text-[var(--text-link)] underline-offset-4 hover:underline data-[pressed]:text-[var(--text-link-hover)]"},fullWidth:{true:"w-full",false:""},visualSize:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3 text-xs",lg:"h-11 rounded-md px-8",icon:"h-10 w-10",dot:"h-5 w-5 rounded-full p-0 min-h-0 min-w-0"},paywall:{true:"!bg-[var(--paywall)] !text-[var(--paywall-foreground)] !shadow-md hover:!bg-[var(--paywall)]/90 !cursor-not-allowed !border-transparent",false:""}},defaultVariants:{variant:"default",visualSize:"default",paywall:false}});var P="data-[pressed]:scale-[0.97]";var G="data-[hovered]:shadow-md";var S="hc:data-[hovered]:outline hc:data-[hovered]:outline-2 hc:data-[hovered]:outline-foreground",y="hc:data-[pressed]:outline hc:data-[pressed]:outline-2 hc:data-[pressed]:outline-offset-1 hc:data-[pressed]:outline-foreground";var ee=react.createContext(null);ee.displayName="ButtonGroupContext";function te(){return react.useContext(ee)}var re=react.createContext(null);re.displayName="ButtonGroupItemContext";function ae(){return react.useContext(re)}classVarianceAuthority.cva("inline-flex items-center gap-0",{variants:{orientation:{horizontal:"flex-row",vertical:"flex-col w-full"}},defaultVariants:{orientation:"horizontal"}});var oe=classVarianceAuthority.cva("",{variants:{orientation:{horizontal:"min-w-[44px]",vertical:"flex min-h-[44px]"},position:{first:"",middle:"",last:"",only:""}},compoundVariants:[{orientation:"horizontal",position:"first",className:"rounded-r-none border-r-0"},{orientation:"horizontal",position:"middle",className:"rounded-none border-r-0"},{orientation:"horizontal",position:"last",className:"rounded-l-none"},{orientation:"vertical",position:"first",className:"rounded-b-none border-b-0"},{orientation:"vertical",position:"middle",className:"rounded-none border-b-0"},{orientation:"vertical",position:"last",className:"rounded-t-none"}],defaultVariants:{orientation:"horizontal",position:"only"}});classVarianceAuthority.cva("bg-[var(--border)]",{variants:{orientation:{horizontal:"w-px h-6 mx-1",vertical:"h-px w-full my-1"}},defaultVariants:{orientation:"horizontal"}});var i=react.memo(react.forwardRef(({className:c,buttonVisualClassName:v,variant:A,size:a,visualSize:x,fullWidth:I,loading:s=false,loadingText:h="Loading...",shortcut:g,children:V,isDisabled:w,paywall:o=false,paywallRedirect:f,paywallDescription:_,onPress:N,...F},T)=>{let E=react.useId(),n=te(),l=ae(),u=A??n?.variant??"default",le=a??n?.size,ue=w??n?.isDisabled??false,X=n?.orientation==="vertical",j=I||X,de=l?oe({orientation:n?.orientation??"horizontal",position:l.position}):"",B=x??le??"default";return process.env.NODE_ENV!=="production"&&(B==="dot"||B==="icon")&&!F["aria-label"]&&!V&&console.warn('[Button] visualSize="dot" or "icon" requires aria-label when no visible text is provided (WCAG 1.1.1)'),jsxRuntime.jsx(reactAriaComponents.Button,{ref:T,isDisabled:ue||s||void 0,"aria-disabled":o?true:void 0,"aria-describedby":o?E:void 0,onPress:b=>{if(o){f&&window.open(f,"_blank","noopener,noreferrer");return}N?.(b);},className:t(C({fullWidth:j,inVerticalGroup:X}),c),...F,children:b=>jsxRuntime.jsxs("span",{className:t(L({variant:u,visualSize:B,paywall:o,fullWidth:j}),de,v,P,G,S,y),"data-pressed":b.isPressed||void 0,children:[s&&jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx(lucideReact.Loader2,{className:"motion-safe:animate-spin","aria-hidden":"true"}),jsxRuntime.jsx("span",{className:"sr-only","aria-live":"polite",children:h})]}),!s&&V,o&&jsxRuntime.jsx(lucideReact.Zap,{"data-testid":"zap-icon","aria-hidden":"true",className:"ml-1"}),o&&jsxRuntime.jsxs("span",{id:E,className:"sr-only",children:["Premium feature: ",_||"Upgrade required to access this feature"]}),b.isFocusVisible&&g&&jsxRuntime.jsx("kbd",{className:"ml-auto hidden text-xs opacity-60 lg:inline",children:g}),b.isPressed&&jsxRuntime.jsx("span",{className:"absolute inset-0 rounded-[inherit] bg-current opacity-10 motion-safe:animate-in motion-safe:zoom-in-95","aria-hidden":"true"})]})})}));i.displayName="Button";var O=4294967295,k=0,U=-2147483647,Ne=zod.z.object({value:zod.z.number().nullable().optional(),defaultValue:zod.z.number().optional(),minValue:zod.z.number().optional(),maxValue:zod.z.number().optional(),allowNegative:zod.z.boolean().optional(),step:zod.z.number().positive().optional(),formatOptions:zod.z.custom().optional(),isDisabled:zod.z.boolean().optional(),isReadOnly:zod.z.boolean().optional(),isRequired:zod.z.boolean().optional(),isInvalid:zod.z.boolean().optional(),isWheelDisabled:zod.z.boolean().optional(),validate:zod.z.function().optional(),validationBehavior:zod.z.enum(["native","aria"]).default("native"),label:zod.z.string(),description:zod.z.string().optional(),errorMessage:zod.z.union([zod.z.string(),zod.z.function()]).optional(),stepperLayout:zod.z.enum(["sides","stacked","hidden"]).default("sides"),incrementAriaLabel:zod.z.string().optional(),decrementAriaLabel:zod.z.string().optional(),name:zod.z.string().optional(),size:zod.z.enum(["sm","default","lg"]).default("default"),onChange:zod.z.function().optional(),onFocus:zod.z.function().optional(),onBlur:zod.z.function().optional(),onFocusChange:zod.z.function().optional(),className:zod.z.string().optional(),autoFocus:zod.z.boolean().optional()});var H=classVarianceAuthority.cva(["inline-flex items-center rounded-md border","bg-[var(--content-background)] text-[var(--content-foreground)]","transition-colors duration-200","focus-within:ring-2 focus-within:ring-[var(--ring)] focus-within:ring-offset-2","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50"],{variants:{size:{sm:"h-9 text-sm",default:"h-10 text-base",lg:"h-12 text-lg"},isInvalid:{true:"border-[var(--destructive)] focus-within:ring-[var(--destructive)]",false:"border-[var(--input)] hover:border-[var(--input)]/80"}},defaultVariants:{size:"default",isInvalid:false}}),M=classVarianceAuthority.cva(["flex-1 bg-transparent text-center tabular-nums","min-w-0","focus:outline-none","[appearance:textfield]","[&::-webkit-outer-spin-button]:appearance-none","[&::-webkit-inner-spin-button]:appearance-none"],{variants:{size:{sm:"px-2 text-sm",default:"px-3 text-base",lg:"px-4 text-lg"}},defaultVariants:{size:"default"}}),m=classVarianceAuthority.cva(["flex items-center justify-center","transition-colors duration-150","select-none","hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]","focus-visible:ring-inset","active:bg-[var(--accent)]/80","disabled:pointer-events-none disabled:opacity-50"],{variants:{size:{sm:"min-w-8 min-h-8 text-sm",default:"min-w-10 min-h-10 text-base",lg:"min-w-12 min-h-12 text-lg"},position:{left:"rounded-l-md border-r border-[var(--input)]",right:"rounded-r-md border-l border-[var(--input)]",top:"rounded-tr-md border-b border-l border-[var(--input)] h-1/2",bottom:"rounded-br-md border-l border-[var(--input)] h-1/2"}},defaultVariants:{size:"default"}}),$=classVarianceAuthority.cva(["block font-medium text-[var(--content-foreground)]","mb-1.5",'data-[required]:after:content-["*"] data-[required]:after:ml-0.5',"data-[required]:after:text-[var(--destructive)]"],{variants:{size:{sm:"text-sm",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),W=classVarianceAuthority.cva(["text-[var(--menu-muted)]","mt-1"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),Y=classVarianceAuthority.cva(["flex items-center gap-1","text-[var(--destructive)]","mt-1"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}});var se=react.forwardRef(({label:c,description:v,errorMessage:A,size:a="default",stepperLayout:x="sides",allowNegative:I=false,incrementAriaLabel:s,decrementAriaLabel:h,minValue:g,maxValue:V,className:w,isInvalid:o,isRequired:f,isDisabled:_,isReadOnly:N,...F},T)=>{let E=g??(I?U:k),n=V??O,l=x!=="hidden"&&!N,u=x==="stacked";return jsxRuntime.jsxs(reactAriaComponents.NumberField,{ref:T,className:t("group flex flex-col",w),minValue:E,maxValue:n,isInvalid:o,isRequired:f,isDisabled:_,isReadOnly:N,...F,children:[jsxRuntime.jsx(reactAriaComponents.Label,{className:t($({size:a})),"data-required":f||void 0,children:c}),jsxRuntime.jsxs(reactAriaComponents.Group,{className:t(H({size:a,isInvalid:o??false}),u&&"pr-0"),children:[l&&!u&&jsxRuntime.jsx(i,{slot:"decrement",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"left"})),"aria-label":h??"Decrease value",children:jsxRuntime.jsx(lucideReact.Minus,{className:"h-4 w-4","aria-hidden":"true"})}),jsxRuntime.jsx(reactAriaComponents.Input,{className:t(M({size:a}))}),l&&u&&jsxRuntime.jsxs("div",{className:"flex flex-col h-full",children:[jsxRuntime.jsx(i,{slot:"increment",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"top"})),"aria-label":s??"Increase value",children:jsxRuntime.jsx(lucideReact.Plus,{className:"h-3 w-3","aria-hidden":"true"})}),jsxRuntime.jsx(i,{slot:"decrement",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"bottom"})),"aria-label":h??"Decrease value",children:jsxRuntime.jsx(lucideReact.Minus,{className:"h-3 w-3","aria-hidden":"true"})})]}),l&&!u&&jsxRuntime.jsx(i,{slot:"increment",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"right"})),"aria-label":s??"Increase value",children:jsxRuntime.jsx(lucideReact.Plus,{className:"h-4 w-4","aria-hidden":"true"})})]}),v&&jsxRuntime.jsx(reactAriaComponents.Text,{slot:"description",className:t(W({size:a})),children:v}),jsxRuntime.jsx(reactAriaComponents.FieldError,{className:t(Y({size:a})),children:A})]})});se.displayName="NumberField";exports.DEFAULT_MAX_VALUE=O;exports.DEFAULT_MIN_VALUE=k;exports.NEGATIVE_MIN_VALUE=U;exports.NumberField=se;exports.NumberFieldPropsSchema=Ne;exports.numberFieldDescriptionVariants=W;exports.numberFieldErrorVariants=Y;exports.numberFieldInputVariants=M;exports.numberFieldLabelVariants=$;exports.numberFieldStepperVariants=m;exports.numberFieldVariants=H;//# sourceMappingURL=index.js.map
|
|
57
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Button/Button.styles.ts","../../../src/styles/interaction-states.ts","../../../src/elements/ButtonGroup/ButtonGroupContext.tsx","../../../src/elements/ButtonGroup/ButtonGroup.variants.ts","../../../src/elements/Button/Button.tsx","../../../src/elements/NumberField/NumberField.types.ts","../../../src/elements/NumberField/NumberField.variants.ts","../../../src/elements/NumberField/NumberField.tsx"],"names":["cn","inputs","twMerge","clsx","buttonOuterVariants","cva","buttonVisualVariants","PRESSED_STYLES","HOVER_STYLES","HIGH_CONTRAST_HOVER","HIGH_CONTRAST_PRESSED","ButtonGroupContext","createContext","useButtonGroupContext","useContext","ButtonGroupItemContext","useButtonGroupItemContext","buttonGroupItemVariants","Button","memo","forwardRef","className","buttonVisualClassName","variant","size","visualSize","fullWidth","loading","loadingText","shortcut","children","isDisabled","paywall","paywallRedirect","paywallDescription","onPress","props","ref","paywallDescriptionId","useId","groupContext","itemContext","effectiveVariant","effectiveSize","effectiveIsDisabled","isInVerticalGroup","effectiveFullWidth","positionClassName","effectiveVisualSize","jsx","AriaButton","e","renderProps","jsxs","Fragment","Loader2","Zap","DEFAULT_MAX_VALUE","DEFAULT_MIN_VALUE","NEGATIVE_MIN_VALUE","NumberFieldPropsSchema","z","numberFieldVariants","numberFieldInputVariants","numberFieldStepperVariants","numberFieldLabelVariants","numberFieldDescriptionVariants","numberFieldErrorVariants","NumberField","label","description","errorMessage","stepperLayout","allowNegative","incrementAriaLabel","decrementAriaLabel","minValue","maxValue","isInvalid","isRequired","isReadOnly","effectiveMinValue","effectiveMaxValue","showSteppers","isStackedLayout","AriaNumberField","AriaLabel","AriaGroup","Minus","AriaInput","Plus","AriaText","AriaFieldError"],"mappings":"oTAcO,SAASA,CAAAA,CAAAA,GAAMC,CAAAA,CAA8B,CAClD,OAAOC,qBAAAA,CAAQC,SAAAA,CAAKF,CAAM,CAAC,CAC7B,CCLO,IAAMG,CAAAA,CAAsBC,0BAAAA,CACjC,0PACA,CACE,QAAA,CAAU,CACR,SAAA,CAAW,CACT,IAAA,CAAM,QAAA,CACN,MAAO,EACT,CAAA,CACA,gBAAiB,CACf,IAAA,CAAM,gBACN,KAAA,CAAO,cACT,CACF,CAAA,CACA,gBAAiB,CACf,SAAA,CAAW,KAAA,CACX,eAAA,CAAiB,KACnB,CACF,CACF,CAAA,CAQaC,CAAAA,CAAuBD,2BAClC,6NAAA,CACA,CACE,SAAU,CACR,OAAA,CAAS,CACP,OAAA,CACE,kKAAA,CACF,WAAA,CACE,oLAAA,CACF,QACE,wIAAA,CACF,SAAA,CACE,4IACF,KAAA,CACE,kGAAA,CACF,KAAM,yGACR,CAAA,CACA,SAAA,CAAW,CACT,KAAM,QAAA,CACN,KAAA,CAAO,EACT,CAAA,CACA,UAAA,CAAY,CACV,OAAA,CAAS,gBAAA,CACT,EAAA,CAAI,6BAAA,CACJ,GAAI,sBAAA,CACJ,IAAA,CAAM,WAAA,CACN,GAAA,CAAK,0CACP,CAAA,CACA,OAAA,CAAS,CACP,IAAA,CAAM,0IACN,KAAA,CAAO,EACT,CACF,CAAA,CACA,eAAA,CAAiB,CACf,OAAA,CAAS,SAAA,CACT,UAAA,CAAY,SAAA,CACZ,QAAS,KACX,CACF,CACF,CAAA,CCxDO,IAUME,CAAAA,CAAiB,8BAevB,IAAMC,EAAe,0BAAA,CAarB,IAMMC,CAAAA,CAAsB,6FAMtBC,CAAAA,CAAwB,+HAAA,CClCrC,IAAMC,EAAAA,CAAqBC,oBAA8C,IAAI,CAAA,CAE7ED,GAAmB,WAAA,CAAc,oBAAA,CAM1B,SAASE,EAAAA,EAAwD,CACtE,OAAOC,gBAAAA,CAAWH,EAAkB,CACtC,CAUA,IAAMI,EAAAA,CACJH,mBAAAA,CAAkD,IAAI,EAExDG,EAAAA,CAAuB,WAAA,CAAc,yBAM9B,SAASC,EAAAA,EAAgE,CAC9E,OAAOF,gBAAAA,CAAWC,EAAsB,CAC1C,CC5CmCV,0BAAAA,CAAI,gCAAA,CAAkC,CACvE,QAAA,CAAU,CACR,WAAA,CAAa,CACX,WAAY,UAAA,CACZ,QAAA,CAAU,iBACZ,CACF,CAAA,CACA,eAAA,CAAiB,CACf,YAAa,YACf,CACF,CAAC,CAAA,KAcYY,GAA0BZ,0BAAAA,CAAI,EAAA,CAAI,CAC7C,QAAA,CAAU,CACR,WAAA,CAAa,CAEX,WAAY,cAAA,CAGZ,QAAA,CAAU,mBACZ,CAAA,CACA,QAAA,CAAU,CACR,KAAA,CAAO,GACP,MAAA,CAAQ,EAAA,CACR,KAAM,EAAA,CACN,IAAA,CAAM,EACR,CACF,CAAA,CACA,gBAAA,CAAkB,CAIhB,CACE,WAAA,CAAa,YAAA,CACb,SAAU,OAAA,CACV,SAAA,CAAW,2BACb,CAAA,CACA,CACE,WAAA,CAAa,YAAA,CACb,SAAU,QAAA,CACV,SAAA,CAAW,yBACb,CAAA,CACA,CACE,YAAa,YAAA,CACb,QAAA,CAAU,MAAA,CACV,SAAA,CAAW,gBACb,CAAA,CAKA,CACE,YAAa,UAAA,CACb,QAAA,CAAU,QACV,SAAA,CAAW,2BACb,CAAA,CACA,CACE,YAAa,UAAA,CACb,QAAA,CAAU,SACV,SAAA,CAAW,yBACb,EACA,CACE,WAAA,CAAa,UAAA,CACb,QAAA,CAAU,OACV,SAAA,CAAW,gBACb,CACF,CAAA,CACA,eAAA,CAAiB,CACf,WAAA,CAAa,YAAA,CACb,QAAA,CAAU,MACZ,CACF,CAAC,CAAA,CAU2CA,0BAAAA,CAAI,qBAAsB,CACpE,QAAA,CAAU,CACR,WAAA,CAAa,CACX,UAAA,CAAY,eAAA,CACZ,SAAU,kBACZ,CACF,EACA,eAAA,CAAiB,CACf,WAAA,CAAa,YACf,CACF,CAAC,ECpFD,IAAMa,EAASC,UAAAA,CAAKC,gBAAAA,CAClB,CACE,CACE,SAAA,CAAAC,EACA,qBAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,CAAAA,CACA,KAAAC,CAAAA,CACA,UAAA,CAAAC,CAAAA,CACA,SAAA,CAAAC,EACA,OAAA,CAAAC,CAAAA,CAAU,KAAA,CACV,WAAA,CAAAC,EAAc,YAAA,CACd,QAAA,CAAAC,EACA,QAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CACA,OAAA,CAAAC,CAAAA,CAAU,KAAA,CACV,gBAAAC,CAAAA,CACA,kBAAA,CAAAC,EACA,OAAA,CAAAC,CAAAA,CACA,GAAGC,CACL,CAAA,CACAC,CAAAA,GACG,CACH,IAAMC,CAAAA,CAAuBC,WAAAA,GAOvBC,CAAAA,CAAe3B,EAAAA,GAGf4B,CAAAA,CAAczB,EAAAA,EAA0B,CAGxC0B,CAAAA,CAAmBnB,GAAWiB,CAAAA,EAAc,OAAA,EAAW,SAAA,CACvDG,EAAAA,CAAgBnB,GAAQgB,CAAAA,EAAc,IAAA,CACtCI,EAAAA,CAAsBb,CAAAA,EAAcS,GAAc,UAAA,EAAc,KAAA,CAGhEK,EAAoBL,CAAAA,EAAc,WAAA,GAAgB,WAClDM,CAAAA,CAAqBpB,CAAAA,EAAamB,CAAAA,CAGlCE,EAAAA,CAAoBN,EACtBxB,EAAAA,CAAwB,CACtB,YAAauB,CAAAA,EAAc,WAAA,EAAe,aAC1C,QAAA,CAAUC,CAAAA,CAAY,QACxB,CAAC,EACD,EAAA,CAGEO,CAAAA,CAAsBvB,GAAckB,EAAAA,EAAiB,SAAA,CAG3D,OAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,GAAa,YAAA,GAExBK,IAAwB,KAAA,EAASA,CAAAA,GAAwB,MAAA,CAAA,EAC1D,CAACZ,EAAM,YAAY,CAAA,EACnB,CAACN,CAAAA,EAED,QAAQ,IAAA,CACN,uGACF,EAyBFmB,cAAAA,CAACC,0BAAAA,CAAA,CACC,GAAA,CAAKb,CAAAA,CACL,UAAA,CALuBO,EAAAA,EAAuBjB,GAAW,MAAA,CAMzD,eAAA,CAAeK,EAAU,IAAA,CAAO,MAAA,CAChC,mBAAkBA,CAAAA,CAAUM,CAAAA,CAAuB,MAAA,CACnD,OAAA,CArBiBa,GAAoE,CACvF,GAAInB,EAAS,CACPC,CAAAA,EACF,OAAO,IAAA,CAAKA,CAAAA,CAAiB,QAAA,CAAU,qBAAqB,EAG9D,MACF,CACAE,CAAAA,GAAUgB,CAAC,EACb,CAAA,CAaI,SAAA,CAAWnD,CAAAA,CAAGI,CAAAA,CAAoB,CAAE,SAAA,CAAW0C,CAAAA,CAAoB,gBAAiBD,CAAkB,CAAC,EAAGxB,CAAS,CAAA,CAClH,GAAGe,CAAAA,CAEH,SAACgB,CAAAA,EAEAC,eAAAA,CAAC,QACC,SAAA,CAAWrD,CAAAA,CACTM,EAAqB,CACnB,OAAA,CAASoC,CAAAA,CACT,UAAA,CAAYM,EACZ,OAAA,CAAAhB,CAAAA,CACA,UAAWc,CACb,CAAC,EAEDC,EAAAA,CACAzB,CAAAA,CAEAf,CAAAA,CACAC,CAAAA,CACAC,EACAC,CACF,CAAA,CACA,cAAA,CAAc0C,CAAAA,CAAY,WAAa,MAAA,CAMtC,QAAA,CAAA,CAAAzB,CAAAA,EACC0B,eAAAA,CAAAC,oBAAA,CACE,QAAA,CAAA,CAAAL,eAACM,mBAAAA,CAAA,CAAQ,UAAU,0BAAA,CAA2B,aAAA,CAAY,MAAA,CAAO,CAAA,CACjEN,eAAC,MAAA,CAAA,CAAK,SAAA,CAAU,UAAU,WAAA,CAAU,QAAA,CACjC,SAAArB,CAAAA,CACH,CAAA,CAAA,CACF,CAAA,CAID,CAACD,GAAWG,CAAAA,CAGZE,CAAAA,EACCiB,eAACO,eAAAA,CAAA,CACC,cAAY,UAAA,CACZ,aAAA,CAAY,MAAA,CACZ,SAAA,CAAU,OACZ,CAAA,CAIDxB,CAAAA,EACCqB,eAAAA,CAAC,MAAA,CAAA,CAAK,GAAIf,CAAAA,CAAsB,SAAA,CAAU,SAAA,CAAU,QAAA,CAAA,CAAA,mBAAA,CAChCJ,GAAsB,yCAAA,CAAA,CAC1C,CAAA,CAIDkB,EAAY,cAAA,EAAkBvB,CAAAA,EAC7BoB,eAAC,KAAA,CAAA,CAAI,SAAA,CAAU,6CAAA,CACZ,QAAA,CAAApB,EACH,CAAA,CAKDuB,CAAAA,CAAY,WACXH,cAAAA,CAAC,MAAA,CAAA,CACC,UAAU,wGAAA,CACV,aAAA,CAAY,MAAA,CACd,CAAA,CAAA,CAEJ,EAEJ,CAEJ,CACF,CAAC,CAAA,CAED/B,CAAAA,CAAO,YAAc,QAAA,CC5Ld,IAAMuC,CAAAA,CAAoB,WAKpBC,CAAAA,CAAoB,CAAA,CAKpBC,EAAqB,WAAA,CAkCrBC,EAAAA,CAAyBC,KAAAA,CAAE,MAAA,CAAO,CAG7C,KAAA,CAAOA,KAAAA,CAAE,QAAO,CAAE,QAAA,GAAW,QAAA,EAAS,CAEtC,YAAA,CAAcA,KAAAA,CAAE,QAAO,CAAE,QAAA,GAIzB,QAAA,CAAUA,KAAAA,CAAE,QAAO,CAAE,QAAA,EAAS,CAE9B,QAAA,CAAUA,MAAE,MAAA,EAAO,CAAE,UAAS,CAE9B,aAAA,CAAeA,MAAE,OAAA,EAAQ,CAAE,QAAA,EAAS,CAEpC,KAAMA,KAAAA,CAAE,MAAA,EAAO,CAAE,QAAA,GAAW,QAAA,EAAS,CAIrC,aAAA,CAAeA,KAAAA,CAAE,QAAiC,CAAE,QAAA,GAIpD,UAAA,CAAYA,KAAAA,CAAE,SAAQ,CAAE,QAAA,EAAS,CAEjC,UAAA,CAAYA,MAAE,OAAA,EAAQ,CAAE,UAAS,CAEjC,UAAA,CAAYA,MAAE,OAAA,EAAQ,CAAE,QAAA,EAAS,CAEjC,UAAWA,KAAAA,CAAE,OAAA,GAAU,QAAA,EAAS,CAEhC,gBAAiBA,KAAAA,CAAE,OAAA,EAAQ,CAAE,QAAA,GAI7B,QAAA,CAAUA,KAAAA,CAAE,QAAA,EAAS,CAAE,UAAS,CAEhC,kBAAA,CAAoBA,KAAAA,CAAE,IAAA,CAAK,CAAC,QAAA,CAAU,MAAM,CAAC,CAAA,CAAE,OAAA,CAAQ,QAAQ,CAAA,CAI/D,KAAA,CAAOA,KAAAA,CAAE,MAAA,GAET,WAAA,CAAaA,KAAAA,CAAE,QAAO,CAAE,QAAA,GAExB,YAAA,CAAcA,KAAAA,CAAE,KAAA,CAAM,CAACA,MAAE,MAAA,EAAO,CAAGA,MAAE,QAAA,EAAU,CAAC,CAAA,CAAE,QAAA,EAAS,CAI3D,aAAA,CAAeA,MAAE,IAAA,CAAK,CAAC,OAAA,CAAS,SAAA,CAAW,QAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,OAAO,EAErE,kBAAA,CAAoBA,KAAAA,CAAE,QAAO,CAAE,QAAA,GAE/B,kBAAA,CAAoBA,KAAAA,CAAE,MAAA,EAAO,CAAE,UAAS,CAIxC,IAAA,CAAMA,MAAE,MAAA,EAAO,CAAE,UAAS,CAI1B,IAAA,CAAMA,KAAAA,CAAE,IAAA,CAAK,CAAC,IAAA,CAAM,SAAA,CAAW,IAAI,CAAC,CAAA,CAAE,QAAQ,SAAS,CAAA,CAIvD,QAAA,CAAUA,KAAAA,CAAE,UAAS,CAAE,QAAA,EAAS,CAEhC,OAAA,CAASA,MAAE,QAAA,EAAS,CAAE,QAAA,EAAS,CAE/B,OAAQA,KAAAA,CAAE,QAAA,GAAW,QAAA,EAAS,CAE9B,cAAeA,KAAAA,CAAE,QAAA,EAAS,CAAE,QAAA,GAI5B,SAAA,CAAWA,KAAAA,CAAE,QAAO,CAAE,QAAA,GAEtB,SAAA,CAAWA,KAAAA,CAAE,OAAA,EAAQ,CAAE,UACzB,CAAC,EClHM,IAAMC,CAAAA,CAAsBzD,0BAAAA,CACjC,CAEE,4CAAA,CACA,iEAAA,CACA,gCAAA,CAEA,gFAAA,CAEA,+DACF,CAAA,CACA,CACE,QAAA,CAAU,CACR,KAAM,CACJ,EAAA,CAAI,cACJ,OAAA,CAAS,gBAAA,CACT,GAAI,cACN,CAAA,CACA,SAAA,CAAW,CACT,KAAM,oEAAA,CACN,KAAA,CAAO,sDACT,CACF,CAAA,CACA,gBAAiB,CACf,IAAA,CAAM,SAAA,CACN,SAAA,CAAW,KACb,CACF,CACF,EAUa0D,CAAAA,CAA2B1D,0BAAAA,CACtC,CAEE,gDAAA,CACA,SAAA,CAEA,oBAAA,CAEA,wBAAA,CACA,iDACA,gDACF,CAAA,CACA,CACE,QAAA,CAAU,CACR,IAAA,CAAM,CACJ,EAAA,CAAI,cAAA,CACJ,QAAS,gBAAA,CACT,EAAA,CAAI,cACN,CACF,CAAA,CACA,gBAAiB,CACf,IAAA,CAAM,SACR,CACF,CACF,CAAA,CAca2D,CAAAA,CAA6B3D,2BACxC,CAEE,kCAAA,CACA,iCACA,aAAA,CAEA,gEAAA,CAEA,kFAAA,CACA,0BAAA,CAEA,+BAEA,kDACF,CAAA,CACA,CACE,QAAA,CAAU,CACR,KAAM,CACJ,EAAA,CAAI,yBAAA,CACJ,OAAA,CAAS,8BACT,EAAA,CAAI,2BACN,CAAA,CACA,QAAA,CAAU,CACR,IAAA,CAAM,6CAAA,CACN,KAAA,CAAO,6CAAA,CACP,IAAK,6DAAA,CACL,MAAA,CAAQ,oDACV,CACF,CAAA,CACA,gBAAiB,CACf,IAAA,CAAM,SACR,CACF,CACF,CAAA,CASa4D,CAAAA,CAA2B5D,2BACtC,CACE,oDAAA,CACA,SAEA,kEAAA,CACA,iDACF,CAAA,CACA,CACE,SAAU,CACR,IAAA,CAAM,CACJ,EAAA,CAAI,SAAA,CACJ,QAAS,SAAA,CACT,EAAA,CAAI,WACN,CACF,EACA,eAAA,CAAiB,CACf,KAAM,SACR,CACF,CACF,CAAA,CASa6D,CAAAA,CAAiC7D,0BAAAA,CAC5C,CACE,2BACA,MACF,CAAA,CACA,CACE,QAAA,CAAU,CACR,KAAM,CACJ,EAAA,CAAI,SAAA,CACJ,OAAA,CAAS,UACT,EAAA,CAAI,WACN,CACF,CAAA,CACA,eAAA,CAAiB,CACf,IAAA,CAAM,SACR,CACF,CACF,EASa8D,CAAAA,CAA2B9D,0BAAAA,CACtC,CACE,yBAAA,CACA,2BAAA,CACA,MACF,CAAA,CACA,CACE,QAAA,CAAU,CACR,KAAM,CACJ,EAAA,CAAI,SAAA,CACJ,OAAA,CAAS,UACT,EAAA,CAAI,WACN,CACF,CAAA,CACA,gBAAiB,CACf,IAAA,CAAM,SACR,CACF,CACF,ECpIO,IAAM+D,EAAAA,CAAchD,iBACzB,CACE,CAEE,MAAAiD,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,YAAA,CAAAC,EAEA,IAAA,CAAA/C,CAAAA,CAAO,UACP,aAAA,CAAAgD,CAAAA,CAAgB,QAEhB,aAAA,CAAAC,CAAAA,CAAgB,KAAA,CAChB,kBAAA,CAAAC,EACA,kBAAA,CAAAC,CAAAA,CAEA,QAAA,CAAAC,CAAAA,CACA,SAAAC,CAAAA,CAEA,SAAA,CAAAxD,CAAAA,CACA,SAAA,CAAAyD,EACA,UAAA,CAAAC,CAAAA,CACA,WAAAhD,CAAAA,CACA,UAAA,CAAAiD,EAEA,GAAG5C,CACL,CAAA,CACAC,CAAAA,GACiB,CAEjB,IAAM4C,CAAAA,CACJL,IAAaH,CAAAA,CAAgBd,CAAAA,CAAqBD,GAC9CwB,CAAAA,CAAoBL,CAAAA,EAAYpB,CAAAA,CAGhC0B,CAAAA,CAAeX,IAAkB,QAAA,EAAY,CAACQ,EAC9CI,CAAAA,CAAkBZ,CAAAA,GAAkB,UAE1C,OACEnB,eAAAA,CAACgC,+BAAAA,CAAA,CACC,IAAKhD,CAAAA,CACL,SAAA,CAAWrC,CAAAA,CAAG,qBAAA,CAAuBqB,CAAS,CAAA,CAC9C,QAAA,CAAU4D,CAAAA,CACV,QAAA,CAAUC,EACV,SAAA,CAAWJ,CAAAA,CACX,WAAYC,CAAAA,CACZ,UAAA,CAAYhD,EACZ,UAAA,CAAYiD,CAAAA,CACX,GAAG5C,CAAAA,CAGJ,UAAAa,cAAAA,CAACqC,yBAAAA,CAAA,CACC,SAAA,CAAWtF,CAAAA,CAAGiE,EAAyB,CAAE,IAAA,CAAAzC,CAAK,CAAC,CAAC,CAAA,CAChD,eAAA,CAAeuD,GAAc,MAAA,CAE5B,QAAA,CAAAV,EACH,CAAA,CAGAhB,eAAAA,CAACkC,yBAAAA,CAAA,CACC,UAAWvF,CAAAA,CACT8D,CAAAA,CAAoB,CAClB,IAAA,CAAAtC,EACA,SAAA,CAAWsD,CAAAA,EAAa,KAC1B,CAAC,EACDM,CAAAA,EAAmB,MACrB,EAGC,QAAA,CAAA,CAAAD,CAAAA,EAAgB,CAACC,CAAAA,EAChBnC,cAAAA,CAAC/B,CAAAA,CAAA,CACC,KAAK,WAAA,CACL,OAAA,CAAQ,QACR,SAAA,CAAU,mBAAA,CACV,sBAAuBlB,CAAAA,CACrBgE,CAAAA,CAA2B,CACzB,IAAA,CAAAxC,EACA,QAAA,CAAU,MACZ,CAAC,CACH,CAAA,CACA,aAAYmD,CAAAA,EAAsB,gBAAA,CAElC,QAAA,CAAA1B,cAAAA,CAACuC,kBAAA,CAAM,SAAA,CAAU,SAAA,CAAU,aAAA,CAAY,OAAO,CAAA,CAChD,CAAA,CAIFvC,cAAAA,CAACwC,yBAAAA,CAAA,CACC,SAAA,CAAWzF,CAAAA,CAAG+D,EAAyB,CAAE,IAAA,CAAAvC,CAAK,CAAC,CAAC,CAAA,CAClD,CAAA,CAGC2D,GAAgBC,CAAAA,EACf/B,eAAAA,CAAC,OAAI,SAAA,CAAU,sBAAA,CACb,UAAAJ,cAAAA,CAAC/B,CAAAA,CAAA,CACC,IAAA,CAAK,YACL,OAAA,CAAQ,OAAA,CACR,UAAU,mBAAA,CACV,qBAAA,CAAuBlB,EACrBgE,CAAAA,CAA2B,CACzB,IAAA,CAAAxC,CAAAA,CACA,SAAU,KACZ,CAAC,CACH,CAAA,CACA,aAAYkD,CAAAA,EAAsB,gBAAA,CAElC,QAAA,CAAAzB,cAAAA,CAACyC,iBAAA,CAAK,SAAA,CAAU,UAAU,aAAA,CAAY,MAAA,CAAO,EAC/C,CAAA,CACAzC,cAAAA,CAAC/B,CAAAA,CAAA,CACC,KAAK,WAAA,CACL,OAAA,CAAQ,QACR,SAAA,CAAU,mBAAA,CACV,sBAAuBlB,CAAAA,CACrBgE,CAAAA,CAA2B,CACzB,IAAA,CAAAxC,EACA,QAAA,CAAU,QACZ,CAAC,CACH,CAAA,CACA,aAAYmD,CAAAA,EAAsB,gBAAA,CAElC,QAAA,CAAA1B,cAAAA,CAACuC,kBAAA,CAAM,SAAA,CAAU,SAAA,CAAU,aAAA,CAAY,OAAO,CAAA,CAChD,CAAA,CAAA,CACF,CAAA,CAIDL,CAAAA,EAAgB,CAACC,CAAAA,EAChBnC,cAAAA,CAAC/B,EAAA,CACC,IAAA,CAAK,YACL,OAAA,CAAQ,OAAA,CACR,SAAA,CAAU,mBAAA,CACV,sBAAuBlB,CAAAA,CACrBgE,CAAAA,CAA2B,CACzB,IAAA,CAAAxC,CAAAA,CACA,SAAU,OACZ,CAAC,CACH,CAAA,CACA,aAAYkD,CAAAA,EAAsB,gBAAA,CAElC,SAAAzB,cAAAA,CAACyC,gBAAAA,CAAA,CAAK,SAAA,CAAU,SAAA,CAAU,aAAA,CAAY,MAAA,CAAO,EAC/C,CAAA,CAAA,CAEJ,CAAA,CAGCpB,GACCrB,cAAAA,CAAC0C,wBAAAA,CAAA,CACC,IAAA,CAAK,aAAA,CACL,SAAA,CAAW3F,CAAAA,CAAGkE,EAA+B,CAAE,IAAA,CAAA1C,CAAK,CAAC,CAAC,EAErD,QAAA,CAAA8C,CAAAA,CACH,CAAA,CAIFrB,cAAAA,CAAC2C,+BAAA,CAAe,SAAA,CAAW5F,EAAGmE,CAAAA,CAAyB,CAAE,KAAA3C,CAAK,CAAC,CAAC,CAAA,CAC7D,SAAA+C,CAAAA,CACH,CAAA,CAAA,CACF,CAEJ,CACF,EAEAH,GAAY,WAAA,CAAc,aAAA","file":"index.js","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva } from 'class-variance-authority';\n\n/**\n * Layer 1: Transparent outer touch target (44x44px minimum)\n * Handles WCAG 2.2 AAA touch target requirement\n * Always transparent, centers the visual button inside\n * IMPORTANT: Focus ring stays on Layer 1 for AAA compliance (2.4.13)\n *\n * In vertical ButtonGroups, uses items-stretch so the visual layer (Layer 2)\n * can fill the full touch target height, eliminating gaps between buttons.\n */\nexport const buttonOuterVariants = cva(\n \"inline-flex justify-center min-h-[44px] min-w-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n fullWidth: {\n true: \"w-full\",\n false: \"\",\n },\n inVerticalGroup: {\n true: \"items-stretch\",\n false: \"items-center\",\n },\n },\n defaultVariants: {\n fullWidth: false,\n inVerticalGroup: false,\n },\n }\n);\n\n/**\n * Layer 2: Visual button appearance (adjustable size)\n * Provides the visual appearance with configurable size\n * Can be smaller than touch target for use cases like carousel dots\n * NOTE: NO focus-visible styles here - focus ring is on Layer 1\n */\nexport const buttonVisualVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative cursor-pointer\",\n {\n variants: {\n variant: {\n default:\n \"bg-[var(--primary-action)] text-[var(--primary-action-foreground)] shadow-md hover:bg-[var(--primary-action-hover)] data-[pressed]:bg-[var(--primary-action)]/80\",\n destructive:\n \"bg-[var(--destructive-background)] text-[var(--destructive-foreground)] shadow-md hover:bg-[var(--destructive-background)]/90 data-[pressed]:bg-[var(--destructive-background)]/80\",\n outline:\n \"border border-[var(--input-border)] bg-[var(--page-background)] hover:bg-[var(--input-border)] data-[pressed]:bg-[var(--input-border)]\",\n secondary:\n \"bg-[var(--secondary)] text-[var(--secondary-foreground)] shadow-md hover:bg-[var(--secondary)]/80 data-[pressed]:bg-[var(--secondary)]/70\",\n ghost:\n \"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)] data-[pressed]:bg-[var(--accent)]\",\n link: \"text-[var(--text-link)] underline-offset-4 hover:underline data-[pressed]:text-[var(--text-link-hover)]\",\n },\n fullWidth: {\n true: \"w-full\",\n false: \"\",\n },\n visualSize: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3 text-xs\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n dot: \"h-5 w-5 rounded-full p-0 min-h-0 min-w-0\",\n },\n paywall: {\n true: \"!bg-[var(--paywall)] !text-[var(--paywall-foreground)] !shadow-md hover:!bg-[var(--paywall)]/90 !cursor-not-allowed !border-transparent\",\n false: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n visualSize: \"default\",\n paywall: false,\n },\n }\n);\n\n/**\n * @deprecated Use buttonVisualVariants instead. This alias is kept for backward compatibility.\n */\nexport const buttonVariants = buttonVisualVariants;\n","/**\n * Global Interaction State Styles\n *\n * Consistent interaction patterns across all Themis components.\n * These styles ensure WCAG 2.2 AAA compliance and predictable UX.\n *\n * @see spec.md FR-010 (Visible focus ring for keyboard navigation)\n * @see spec.md FR-031 (Pressed state feedback)\n * @see spec.md FR-012 (High contrast mode support)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\n/**\n * Focus state styles (FR-010)\n * Visible focus ring for keyboard navigation - WCAG 2.2 Level AAA\n *\n * Components can override by extending these styles:\n * @example\n * cn(FOCUS_STYLES, \"ring-4\") // Increases ring width to 4px\n */\nexport const FOCUS_STYLES = \"data-[focus-visible]:ring-2 data-[focus-visible]:ring-[var(--themis-ring)] data-[focus-visible]:ring-offset-2\";\n\n/**\n * Pressed/Active state styles (FR-031)\n * Visual feedback for press interactions\n *\n * Components can override the scale amount:\n * @example\n * cn(PRESSED_STYLES_BASE, \"data-[pressed]:scale-[0.95]\") // More pronounced scale\n */\nexport const PRESSED_STYLES = \"data-[pressed]:scale-[0.97]\";\n\n/**\n * Base pressed styles without scale (for components that need different feedback)\n */\nexport const PRESSED_STYLES_BASE = \"data-[pressed]:transition-transform data-[pressed]:duration-100\";\n\n/**\n * Hover state styles\n * Elevation change on hover for better affordance\n *\n * Components can override shadow depth:\n * @example\n * cn(HOVER_STYLES_BASE, \"data-[hovered]:shadow-lg\") // Larger shadow\n */\nexport const HOVER_STYLES = \"data-[hovered]:shadow-md\";\n\n/**\n * Base hover styles without shadow (for components that use different hover effects)\n */\nexport const HOVER_STYLES_BASE = \"data-[hovered]:transition-shadow data-[hovered]:duration-200\";\n\n/**\n * High contrast mode focus (FR-012)\n * Enhanced outlines for users requiring high contrast\n *\n * Uses 'hc:' prefix for prefers-contrast: more media query\n */\nexport const HIGH_CONTRAST_FOCUS = \"hc:data-[focus-visible]:outline hc:data-[focus-visible]:outline-4 hc:data-[focus-visible]:outline-offset-2 hc:data-[focus-visible]:outline-foreground\";\n\n/**\n * High contrast mode hover (FR-012)\n * Enhanced outlines for hover in high contrast mode\n */\nexport const HIGH_CONTRAST_HOVER = \"hc:data-[hovered]:outline hc:data-[hovered]:outline-2 hc:data-[hovered]:outline-foreground\";\n\n/**\n * High contrast mode pressed state\n * Enhanced outlines for pressed state in high contrast mode\n */\nexport const HIGH_CONTRAST_PRESSED = \"hc:data-[pressed]:outline hc:data-[pressed]:outline-2 hc:data-[pressed]:outline-offset-1 hc:data-[pressed]:outline-foreground\";\n\n/**\n * Combined high contrast styles\n * Use this for components that need all high contrast interaction states\n */\nexport const HIGH_CONTRAST_INTERACTIONS = `${HIGH_CONTRAST_FOCUS} ${HIGH_CONTRAST_HOVER} ${HIGH_CONTRAST_PRESSED}`;\n\n/**\n * Disabled state styles\n * Consistent disabled appearance across all components\n */\nexport const DISABLED_STYLES = \"disabled:pointer-events-none disabled:opacity-50\";\n\n/**\n * Default interaction bundle\n * Most common combination for interactive components\n *\n * Includes: focus ring, pressed scale, hover shadow, high contrast enhancements\n *\n * @example\n * <button className={cn(DEFAULT_INTERACTIONS, \"bg-primary\")}>Click</button>\n */\nexport const DEFAULT_INTERACTIONS = `${FOCUS_STYLES} ${PRESSED_STYLES} ${HOVER_STYLES} ${HIGH_CONTRAST_FOCUS} ${HIGH_CONTRAST_HOVER} ${HIGH_CONTRAST_PRESSED}`;\n\n/**\n * Subtle interaction bundle\n * For components that need less pronounced feedback\n *\n * Includes: focus ring and high contrast, but no hover shadow or pressed scale\n */\nexport const SUBTLE_INTERACTIONS = `${FOCUS_STYLES} ${HIGH_CONTRAST_FOCUS}`;\n\n/**\n * Non-interactive element styles\n * For elements that should indicate they are not interactive\n */\nexport const NON_INTERACTIVE = \"cursor-default select-none\";\n","\"use client\";\n\nimport { createContext, useContext } from 'react';\nimport type {\n ButtonGroupContextValue,\n ButtonGroupItemContextValue,\n} from './ButtonGroup.types';\n\n/**\n * ButtonGroup Context System (Two-Level)\n *\n * Provides a two-level context pattern for ButtonGroup:\n *\n * 1. ButtonGroupContext (group-level):\n * - Provides: orientation, variant, size, isDisabled\n * - Consumed by: Button (for prop inheritance), Separator (for orientation)\n *\n * 2. ButtonGroupItemContext (item-level):\n * - Provides: position ('first' | 'middle' | 'last' | 'only')\n * - Consumed by: Button (for border-radius styling)\n *\n * Both contexts return null when not in a provider, allowing Button\n * to work standalone without any group context.\n *\n * @see plan.md for architecture details\n * @see ButtonGroup.tsx for Provider implementation\n */\n\n// =============================================================================\n// Group-Level Context\n// =============================================================================\n\n/**\n * Context for group-level props (orientation, variant, size, isDisabled)\n * Default value is null to indicate \"not in a group\"\n */\nconst ButtonGroupContext = createContext<ButtonGroupContextValue | null>(null);\n\nButtonGroupContext.displayName = 'ButtonGroupContext';\n\n/**\n * Hook to access group-level context\n * @returns ButtonGroupContextValue if inside a ButtonGroup, null otherwise\n */\nexport function useButtonGroupContext(): ButtonGroupContextValue | null {\n return useContext(ButtonGroupContext);\n}\n\n// =============================================================================\n// Item-Level Context\n// =============================================================================\n\n/**\n * Context for per-button position information\n * Default value is null to indicate \"not wrapped with position context\"\n */\nconst ButtonGroupItemContext =\n createContext<ButtonGroupItemContextValue | null>(null);\n\nButtonGroupItemContext.displayName = 'ButtonGroupItemContext';\n\n/**\n * Hook to access item-level context (position)\n * @returns ButtonGroupItemContextValue if wrapped with position context, null otherwise\n */\nexport function useButtonGroupItemContext(): ButtonGroupItemContextValue | null {\n return useContext(ButtonGroupItemContext);\n}\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ButtonGroupContext, ButtonGroupItemContext };\n","import { cva } from 'class-variance-authority';\n\n/**\n * ButtonGroup CVA Variants\n *\n * Defines Class Variance Authority (CVA) variants for:\n * - ButtonGroup container (orientation-based layout)\n * - ButtonGroupItem (position-based border-radius)\n * - ButtonGroupSeparator (orientation-based styling)\n *\n * @see plan.md Phase 1: Design & Contracts - CVA Variants\n * @see constitution.md Principle V (Component Quality Standards)\n */\n\n// =============================================================================\n// Container Variants\n// =============================================================================\n\n/**\n * ButtonGroup container variants\n * Controls the layout direction based on orientation\n * Uses gap-0 to ensure buttons are connected (share borders)\n */\nexport const buttonGroupVariants = cva('inline-flex items-center gap-0', {\n variants: {\n orientation: {\n horizontal: 'flex-row',\n vertical: 'flex-col w-full',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n },\n});\n\n// =============================================================================\n// Item Position Variants\n// =============================================================================\n\n/**\n * ButtonGroupItem position variants\n * Applied to Button's visual layer (Layer 2) for position-aware border-radius\n *\n * Compound variants handle both orientation and position combinations:\n * - Horizontal: left/right borders and radii\n * - Vertical: top/bottom borders and radii\n */\nexport const buttonGroupItemVariants = cva('', {\n variants: {\n orientation: {\n // min-w-[44px] ensures visual layer fills touch target width (for icon buttons)\n horizontal: 'min-w-[44px]',\n // flex (overrides inline-flex) + min-h-[44px] makes visual layer fill touch target,\n // eliminating gaps between stacked buttons in vertical orientation\n vertical: 'flex min-h-[44px]',\n },\n position: {\n first: '',\n middle: '',\n last: '',\n only: '', // Single button - no modifications needed\n },\n },\n compoundVariants: [\n // ==========================================================================\n // Horizontal Orientation\n // ==========================================================================\n {\n orientation: 'horizontal',\n position: 'first',\n className: 'rounded-r-none border-r-0',\n },\n {\n orientation: 'horizontal',\n position: 'middle',\n className: 'rounded-none border-r-0',\n },\n {\n orientation: 'horizontal',\n position: 'last',\n className: 'rounded-l-none',\n },\n // ==========================================================================\n // Vertical Orientation\n // Note: w-full is handled by Button's effectiveFullWidth for both layers\n // ==========================================================================\n {\n orientation: 'vertical',\n position: 'first',\n className: 'rounded-b-none border-b-0',\n },\n {\n orientation: 'vertical',\n position: 'middle',\n className: 'rounded-none border-b-0',\n },\n {\n orientation: 'vertical',\n position: 'last',\n className: 'rounded-t-none',\n },\n ],\n defaultVariants: {\n orientation: 'horizontal',\n position: 'only',\n },\n});\n\n// =============================================================================\n// Separator Variants\n// =============================================================================\n\n/**\n * ButtonGroupSeparator variants\n * Orientation-aware visual divider between button groups\n */\nexport const buttonGroupSeparatorVariants = cva('bg-[var(--border)]', {\n variants: {\n orientation: {\n horizontal: 'w-px h-6 mx-1',\n vertical: 'h-px w-full my-1',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n },\n});\n","\"use client\";\n\n/**\n * Button Component - 3-Layer Architecture\n * Accessible button with React Aria primitives and CVA styling\n *\n * Architecture:\n * - Layer 1: Touch Target (44x44px WCAG AAA compliant, transparent)\n * - Layer 2: Visual Button (configurable size, colors, borders)\n * - Layer 3: Content & Effects (text, icons, ripple, loading spinner)\n *\n * @see 3layer-plan.md for architecture details\n * @see spec.md FR-029 to FR-037 (Button Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, useId } from 'react';\nimport {\n Button as AriaButton,\n type ButtonProps as AriaButtonProps,\n} from 'react-aria-components';\nimport { Loader2, Zap } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type { ButtonProps } from './Button.types';\nimport { buttonOuterVariants, buttonVisualVariants, buttonVariants } from './Button.styles';\nimport { PRESSED_STYLES, HOVER_STYLES, HIGH_CONTRAST_HOVER, HIGH_CONTRAST_PRESSED } from '../../styles/interaction-states';\nimport {\n useButtonGroupContext,\n useButtonGroupItemContext,\n} from '../ButtonGroup/ButtonGroupContext';\nimport { buttonGroupItemVariants } from '../ButtonGroup/ButtonGroup.variants';\n\n/**\n * Button Component - 3-Layer Architecture\n * Fully accessible button with React Aria and themed styling\n *\n * Layer 1: Touch Target (AriaButton) - 44x44px WCAG AAA compliant\n * Layer 2: Visual Button (span) - configurable appearance\n * Layer 3: Content (children) - text, icons, effects\n */\nconst Button = memo(forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n buttonVisualClassName,\n variant,\n size,\n visualSize,\n fullWidth,\n loading = false,\n loadingText = \"Loading...\",\n shortcut,\n children,\n isDisabled,\n paywall = false,\n paywallRedirect,\n paywallDescription,\n onPress,\n ...props\n },\n ref\n ) => {\n const paywallDescriptionId = useId();\n\n // ==========================================================================\n // ButtonGroup Context Integration\n // ==========================================================================\n\n // Consume group-level context (variant, size, isDisabled, orientation)\n const groupContext = useButtonGroupContext();\n\n // Consume item-level context (position for border-radius styling)\n const itemContext = useButtonGroupItemContext();\n\n // Merge context values with props (props take precedence)\n const effectiveVariant = variant ?? groupContext?.variant ?? 'default';\n const effectiveSize = size ?? groupContext?.size;\n const effectiveIsDisabled = isDisabled ?? groupContext?.isDisabled ?? false;\n\n // In vertical groups, buttons should be full width automatically\n const isInVerticalGroup = groupContext?.orientation === 'vertical';\n const effectiveFullWidth = fullWidth || isInVerticalGroup;\n\n // Position styling for ButtonGroup (only applied when in a group)\n const positionClassName = itemContext\n ? buttonGroupItemVariants({\n orientation: groupContext?.orientation ?? 'horizontal',\n position: itemContext.position,\n })\n : '';\n\n // Default visualSize to size for backward compatibility\n const effectiveVisualSize = visualSize ?? effectiveSize ?? 'default';\n\n // AAA Accessibility: Warn in dev/test if icon/dot variant lacks accessible name\n if (process.env.NODE_ENV !== 'production') {\n if (\n (effectiveVisualSize === 'dot' || effectiveVisualSize === 'icon') &&\n !props['aria-label'] &&\n !children\n ) {\n console.warn(\n '[Button] visualSize=\"dot\" or \"icon\" requires aria-label when no visible text is provided (WCAG 1.1.1)'\n );\n }\n }\n\n /**\n * Handle button press - intercepts action when paywalled\n * If paywalled with redirect URL, opens in new tab\n * Otherwise, calls the normal onPress handler\n */\n const handlePress = (e: Parameters<NonNullable<AriaButtonProps['onPress']>>[0]): void => {\n if (paywall) {\n if (paywallRedirect) {\n window.open(paywallRedirect, '_blank', 'noopener,noreferrer');\n }\n // Don't call onPress when paywalled\n return;\n }\n onPress?.(e);\n };\n\n // Only set isDisabled when we have a reason to disable\n // Otherwise, let slot system control disabled state (e.g., in NumberField)\n const computedIsDisabled = effectiveIsDisabled || loading || undefined;\n\n return (\n <AriaButton\n ref={ref}\n isDisabled={computedIsDisabled}\n aria-disabled={paywall ? true : undefined}\n aria-describedby={paywall ? paywallDescriptionId : undefined}\n onPress={handlePress}\n className={cn(buttonOuterVariants({ fullWidth: effectiveFullWidth, inVerticalGroup: isInVerticalGroup }), className)}\n {...props}\n >\n {(renderProps) => (\n /* Layer 2: Visual Button */\n <span\n className={cn(\n buttonVisualVariants({\n variant: effectiveVariant,\n visualSize: effectiveVisualSize,\n paywall,\n fullWidth: effectiveFullWidth,\n }),\n // Position styling from ButtonGroup context (border-radius adjustments)\n positionClassName,\n buttonVisualClassName,\n // Layer 2 interaction styles (no focus - focus ring is on Layer 1)\n PRESSED_STYLES,\n HOVER_STYLES,\n HIGH_CONTRAST_HOVER,\n HIGH_CONTRAST_PRESSED\n )}\n data-pressed={renderProps.isPressed || undefined}\n >\n {/* Layer 3: Content & Effects */}\n\n {/* FR-033: Loading spinner with screen reader announcement */}\n {/* Uses motion-safe: for WCAG 2.3.3 AAA (Animation from Interactions) */}\n {loading && (\n <>\n <Loader2 className=\"motion-safe:animate-spin\" aria-hidden=\"true\" />\n <span className=\"sr-only\" aria-live=\"polite\">\n {loadingText}\n </span>\n </>\n )}\n\n {/* Hide children during loading */}\n {!loading && children}\n\n {/* Paywall: Lightning bolt icon */}\n {paywall && (\n <Zap\n data-testid=\"zap-icon\"\n aria-hidden=\"true\"\n className=\"ml-1\"\n />\n )}\n\n {/* Paywall: Screen reader description */}\n {paywall && (\n <span id={paywallDescriptionId} className=\"sr-only\">\n Premium feature: {paywallDescription || \"Upgrade required to access this feature\"}\n </span>\n )}\n\n {/* FR-034: Keyboard shortcut display on focus */}\n {renderProps.isFocusVisible && shortcut && (\n <kbd className=\"ml-auto hidden text-xs opacity-60 lg:inline\">\n {shortcut}\n </kbd>\n )}\n\n {/* Touch/press ripple effect - FR-031: Pressed state feedback */}\n {/* Uses motion-safe: for WCAG 2.3.3 AAA (Animation from Interactions) */}\n {renderProps.isPressed && (\n <span\n className=\"absolute inset-0 rounded-[inherit] bg-current opacity-10 motion-safe:animate-in motion-safe:zoom-in-95\"\n aria-hidden=\"true\"\n />\n )}\n </span>\n )}\n </AriaButton>\n );\n }\n));\n\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants, buttonOuterVariants, buttonVisualVariants };\nexport type { ButtonProps } from './Button.types';\n","/**\n * NumberField Component Types\n *\n * Zod schemas and TypeScript types for the NumberField component.\n * CVA variants are in a separate file (NumberField.variants.ts) to separate\n * styling concerns from type definitions.\n *\n * Note: Zod schemas are used for contract tests and developer guardrails,\n * not runtime validation. This follows the established Themis pattern.\n *\n * @see {@link ../../docs/prd/numberfield-prd.md} for full requirements\n */\n\nimport { z } from 'zod';\nimport type {\n NumberFieldProps as AriaNumberFieldProps,\n ValidationResult,\n} from 'react-aria-components';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Default maximum value (UINT32_MAX) to prevent overflow/Infinity.\n */\nexport const DEFAULT_MAX_VALUE = 4294967295;\n\n/**\n * Default minimum value for non-negative numbers.\n */\nexport const DEFAULT_MIN_VALUE = 0;\n\n/**\n * Minimum value when allowNegative is enabled (INT32_MIN + 1).\n */\nexport const NEGATIVE_MIN_VALUE = -2147483647;\n\n// ============================================================================\n// Size Variant Type\n// ============================================================================\n\n/**\n * Size variants for NumberField component.\n * - 'sm': Compact size (36px height) - touch targets via padding\n * - 'default': Standard size (40px height) - AAA compliant\n * - 'lg': Large size (48px height) - AAA compliant\n */\nexport type NumberFieldSize = 'sm' | 'default' | 'lg';\n\n// ============================================================================\n// Stepper Layout Type\n// ============================================================================\n\n/**\n * Layout options for stepper buttons.\n * - 'sides': Buttons on left (-) and right (+) of input (default)\n * - 'stacked': Buttons stacked vertically on right side\n * - 'hidden': No stepper buttons (keyboard/typing only)\n */\nexport type StepperLayout = 'sides' | 'stacked' | 'hidden';\n\n// ============================================================================\n// Zod Schemas\n// ============================================================================\n\n/**\n * Zod schema for NumberField props validation.\n * Used for contract tests and developer guardrails, not runtime validation.\n */\nexport const NumberFieldPropsSchema = z.object({\n // Value props\n /** Current value (controlled mode) */\n value: z.number().nullable().optional(),\n /** Default value (uncontrolled mode) */\n defaultValue: z.number().optional(),\n\n // Constraint props\n /** Minimum allowed value (default: 0) */\n minValue: z.number().optional(),\n /** Maximum allowed value (default: 4294967295 / UINT32_MAX) */\n maxValue: z.number().optional(),\n /** Allow negative numbers (sets minValue to -2147483647 if not explicitly set) */\n allowNegative: z.boolean().optional(),\n /** Step increment for stepper buttons and arrow keys (default: 1) */\n step: z.number().positive().optional(),\n\n // Formatting props\n /** Intl.NumberFormat options for locale-aware formatting */\n formatOptions: z.custom<Intl.NumberFormatOptions>().optional(),\n\n // State props\n /** Whether the field is disabled */\n isDisabled: z.boolean().optional(),\n /** Whether the field is read-only */\n isReadOnly: z.boolean().optional(),\n /** Whether the field is required */\n isRequired: z.boolean().optional(),\n /** Whether the field is in an invalid state */\n isInvalid: z.boolean().optional(),\n /** Whether scroll wheel adjustment is disabled */\n isWheelDisabled: z.boolean().optional(),\n\n // Validation props\n /** Custom validation function that returns an error message or null */\n validate: z.function().optional(),\n /** Validation behavior: 'native' for HTML5 validation, 'aria' for ARIA-only */\n validationBehavior: z.enum(['native', 'aria']).default('native'),\n\n // Display props\n /** Field label (required for accessibility) */\n label: z.string(),\n /** Description text below the field */\n description: z.string().optional(),\n /** Error message string or render function */\n errorMessage: z.union([z.string(), z.function()]).optional(),\n\n // Stepper props\n /** Layout for stepper buttons */\n stepperLayout: z.enum(['sides', 'stacked', 'hidden']).default('sides'),\n /** Custom aria-label for increment button */\n incrementAriaLabel: z.string().optional(),\n /** Custom aria-label for decrement button */\n decrementAriaLabel: z.string().optional(),\n\n // Form props\n /** Name attribute for form submission */\n name: z.string().optional(),\n\n // Variant props\n /** Size variant */\n size: z.enum(['sm', 'default', 'lg']).default('default'),\n\n // Event props\n /** Called when the numeric value changes */\n onChange: z.function().optional(),\n /** Called when the field gains focus */\n onFocus: z.function().optional(),\n /** Called when the field loses focus */\n onBlur: z.function().optional(),\n /** Called when focus state changes */\n onFocusChange: z.function().optional(),\n\n // Standard props\n /** Additional CSS classes */\n className: z.string().optional(),\n /** Whether to auto-focus on mount */\n autoFocus: z.boolean().optional(),\n});\n\n// ============================================================================\n// TypeScript Types\n// ============================================================================\n\n/**\n * Custom props added to NumberField (not from React Aria).\n */\nexport interface ThemisNumberFieldCustomProps {\n /** Size variant: 'sm', 'default', or 'lg' */\n size?: NumberFieldSize;\n /** Field label (required for accessibility) */\n label: string;\n /** Description text below the field */\n description?: string;\n /** Error message when field is invalid */\n errorMessage?: string | ((validation: ValidationResult) => string);\n /** Layout for stepper buttons */\n stepperLayout?: StepperLayout;\n /** Custom aria-label for increment button */\n incrementAriaLabel?: string;\n /** Custom aria-label for decrement button */\n decrementAriaLabel?: string;\n /** Allow negative numbers (sets minValue to -2147483647 if not explicitly set) */\n allowNegative?: boolean;\n}\n\n/**\n * Props for the NumberField component.\n * Combines React Aria's NumberFieldProps with Themis-specific props.\n */\nexport type NumberFieldProps = Omit<AriaNumberFieldProps, 'children'> &\n ThemisNumberFieldCustomProps;\n","/**\n * NumberField Component CVA Variants\n *\n * Class Variance Authority (CVA) variant definitions for the NumberField component.\n * Separated from types to maintain clean separation of concerns.\n *\n * Styling uses semantic CSS tokens that map to ThemeProvider variables:\n * - --background: Input background color\n * - --foreground: Text color\n * - --input: Input border color (default state)\n * - --ring: Focus ring color\n * - --accent: Stepper button hover background\n * - --accent-foreground: Stepper button hover text\n * - --destructive: Error state border and text\n * - --muted-foreground: Placeholder/disabled text\n *\n * @see {@link ../../docs/prd/numberfield-prd.md} for full requirements\n */\n\nimport { cva, type VariantProps } from 'class-variance-authority';\n\n// ============================================================================\n// Container Variants\n// ============================================================================\n\n/**\n * Variants for the NumberField container (Group element).\n * Contains the input and stepper buttons.\n *\n * Size notes:\n * - sm (36px): Compact, touch targets achieved via padding\n * - default (40px): Standard size, AAA compliant touch targets\n * - lg (48px): Large size, enhanced touch targets\n */\nexport const numberFieldVariants = cva(\n [\n // Base styles\n 'inline-flex items-center rounded-md border',\n 'bg-[var(--content-background)] text-[var(--content-foreground)]',\n 'transition-colors duration-200',\n // Focus within\n 'focus-within:ring-2 focus-within:ring-[var(--ring)] focus-within:ring-offset-2',\n // Disabled\n 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',\n ],\n {\n variants: {\n size: {\n sm: 'h-9 text-sm',\n default: 'h-10 text-base',\n lg: 'h-12 text-lg',\n },\n isInvalid: {\n true: 'border-[var(--destructive)] focus-within:ring-[var(--destructive)]',\n false: 'border-[var(--input)] hover:border-[var(--input)]/80',\n },\n },\n defaultVariants: {\n size: 'default',\n isInvalid: false,\n },\n }\n);\n\n// ============================================================================\n// Input Variants\n// ============================================================================\n\n/**\n * Variants for the numeric input element.\n * Hides native spinners and centers text.\n */\nexport const numberFieldInputVariants = cva(\n [\n // Base styles\n 'flex-1 bg-transparent text-center tabular-nums',\n 'min-w-0', // Allow shrinking\n // Focus\n 'focus:outline-none',\n // Hide native spinners\n '[appearance:textfield]',\n '[&::-webkit-outer-spin-button]:appearance-none',\n '[&::-webkit-inner-spin-button]:appearance-none',\n ],\n {\n variants: {\n size: {\n sm: 'px-2 text-sm',\n default: 'px-3 text-base',\n lg: 'px-4 text-lg',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Stepper Button Variants\n// ============================================================================\n\n/**\n * Variants for the stepper buttons (increment/decrement).\n * Supports different positions for sides and stacked layouts.\n *\n * Touch target strategy:\n * - Visual button size varies with component size\n * - 44x44px minimum touch target achieved via padding/hit area\n */\nexport const numberFieldStepperVariants = cva(\n [\n // Base styles\n 'flex items-center justify-center',\n 'transition-colors duration-150',\n 'select-none',\n // Hover\n 'hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]',\n // Focus\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',\n 'focus-visible:ring-inset',\n // Active (pressed)\n 'active:bg-[var(--accent)]/80',\n // Disabled\n 'disabled:pointer-events-none disabled:opacity-50',\n ],\n {\n variants: {\n size: {\n sm: 'min-w-8 min-h-8 text-sm',\n default: 'min-w-10 min-h-10 text-base',\n lg: 'min-w-12 min-h-12 text-lg',\n },\n position: {\n left: 'rounded-l-md border-r border-[var(--input)]',\n right: 'rounded-r-md border-l border-[var(--input)]',\n top: 'rounded-tr-md border-b border-l border-[var(--input)] h-1/2',\n bottom: 'rounded-br-md border-l border-[var(--input)] h-1/2',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Label Variants\n// ============================================================================\n\n/**\n * Variants for the NumberField label.\n */\nexport const numberFieldLabelVariants = cva(\n [\n 'block font-medium text-[var(--content-foreground)]',\n 'mb-1.5',\n // Required indicator\n 'data-[required]:after:content-[\"*\"] data-[required]:after:ml-0.5',\n 'data-[required]:after:text-[var(--destructive)]',\n ],\n {\n variants: {\n size: {\n sm: 'text-sm',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Description Variants\n// ============================================================================\n\n/**\n * Variants for the description text below the field.\n */\nexport const numberFieldDescriptionVariants = cva(\n [\n 'text-[var(--menu-muted)]',\n 'mt-1',\n ],\n {\n variants: {\n size: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Error Variants\n// ============================================================================\n\n/**\n * Variants for the error message display.\n */\nexport const numberFieldErrorVariants = cva(\n [\n 'flex items-center gap-1',\n 'text-[var(--destructive)]',\n 'mt-1',\n ],\n {\n variants: {\n size: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Variant Types (from CVA)\n// ============================================================================\n\n/**\n * Variant props for numberFieldVariants CVA function.\n */\nexport type NumberFieldVariantProps = VariantProps<typeof numberFieldVariants>;\n\n/**\n * Variant props for numberFieldInputVariants CVA function.\n */\nexport type NumberFieldInputVariantProps = VariantProps<typeof numberFieldInputVariants>;\n\n/**\n * Variant props for numberFieldStepperVariants CVA function.\n */\nexport type NumberFieldStepperVariantProps = VariantProps<typeof numberFieldStepperVariants>;\n","'use client';\n\n/**\n * NumberField Component\n *\n * A fully accessible numeric input component built on React Aria's NumberField primitive.\n * Provides keyboard-editable input with optional increment/decrement stepper buttons.\n *\n * Features:\n * - WCAG 2.2 AAA compliant (44x44px touch targets, 7:1 contrast)\n * - Spinbutton ARIA semantics\n * - Locale-aware number formatting via Intl.NumberFormat\n * - Configurable min/max/step constraints\n * - Optional stepper buttons (sides, stacked, or hidden layouts)\n * - Scroll wheel support\n * - Form integration with hidden input\n * - Full keyboard navigation (Arrow, Page Up/Down, Home/End)\n * - Screen reader accessible\n *\n * @see {@link ../../docs/prd/numberfield-prd.md} for full requirements\n */\n\nimport { forwardRef, type ReactElement } from 'react';\nimport {\n NumberField as AriaNumberField,\n Group as AriaGroup,\n Input as AriaInput,\n Label as AriaLabel,\n Text as AriaText,\n FieldError as AriaFieldError,\n} from 'react-aria-components';\nimport { Minus, Plus } from 'lucide-react';\nimport { Button } from '../Button';\nimport { cn } from '../../utils/cn';\nimport type { NumberFieldProps } from './NumberField.types';\nimport {\n DEFAULT_MAX_VALUE,\n DEFAULT_MIN_VALUE,\n NEGATIVE_MIN_VALUE,\n} from './NumberField.types';\nimport {\n numberFieldVariants,\n numberFieldInputVariants,\n numberFieldStepperVariants,\n numberFieldLabelVariants,\n numberFieldDescriptionVariants,\n numberFieldErrorVariants,\n} from './NumberField.variants';\n\n// =============================================================================\n// NumberField Component\n// =============================================================================\n\n/**\n * NumberField component for numeric input with optional stepper buttons.\n *\n * @example\n * ```tsx\n * import { NumberField } from '@tribepad/themis/elements/NumberField';\n *\n * // Basic usage\n * <NumberField label=\"Quantity\" />\n *\n * // With constraints\n * <NumberField\n * label=\"Quantity\"\n * minValue={1}\n * maxValue={100}\n * step={1}\n * defaultValue={5}\n * />\n *\n * // Currency formatting\n * <NumberField\n * label=\"Price\"\n * formatOptions={{ style: 'currency', currency: 'USD' }}\n * step={0.01}\n * defaultValue={9.99}\n * />\n *\n * // Allow negative numbers\n * <NumberField\n * label=\"Temperature\"\n * allowNegative\n * formatOptions={{ style: 'unit', unit: 'celsius' }}\n * />\n *\n * // Hidden steppers\n * <NumberField\n * label=\"Account Number\"\n * stepperLayout=\"hidden\"\n * />\n * ```\n */\nexport const NumberField = forwardRef<HTMLDivElement, NumberFieldProps>(\n (\n {\n // Display props\n label,\n description,\n errorMessage,\n // Variant props\n size = 'default',\n stepperLayout = 'sides',\n // Custom props\n allowNegative = false,\n incrementAriaLabel,\n decrementAriaLabel,\n // Constraint props (apply defaults)\n minValue,\n maxValue,\n // Standard props\n className,\n isInvalid,\n isRequired,\n isDisabled,\n isReadOnly,\n // All other props go to AriaNumberField\n ...props\n },\n ref\n ): ReactElement => {\n // Calculate effective min/max values\n const effectiveMinValue =\n minValue ?? (allowNegative ? NEGATIVE_MIN_VALUE : DEFAULT_MIN_VALUE);\n const effectiveMaxValue = maxValue ?? DEFAULT_MAX_VALUE;\n\n // Determine if steppers should be shown\n const showSteppers = stepperLayout !== 'hidden' && !isReadOnly;\n const isStackedLayout = stepperLayout === 'stacked';\n\n return (\n <AriaNumberField\n ref={ref}\n className={cn('group flex flex-col', className)}\n minValue={effectiveMinValue}\n maxValue={effectiveMaxValue}\n isInvalid={isInvalid}\n isRequired={isRequired}\n isDisabled={isDisabled}\n isReadOnly={isReadOnly}\n {...props}\n >\n {/* Label */}\n <AriaLabel\n className={cn(numberFieldLabelVariants({ size }))}\n data-required={isRequired || undefined}\n >\n {label}\n </AriaLabel>\n\n {/* Input Group */}\n <AriaGroup\n className={cn(\n numberFieldVariants({\n size,\n isInvalid: isInvalid ?? false,\n }),\n isStackedLayout && 'pr-0'\n )}\n >\n {/* Decrement Button (left side for sides layout) */}\n {showSteppers && !isStackedLayout && (\n <Button\n slot=\"decrement\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'left',\n })\n )}\n aria-label={decrementAriaLabel ?? 'Decrease value'}\n >\n <Minus className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n )}\n\n {/* Input */}\n <AriaInput\n className={cn(numberFieldInputVariants({ size }))}\n />\n\n {/* Stacked Layout Buttons */}\n {showSteppers && isStackedLayout && (\n <div className=\"flex flex-col h-full\">\n <Button\n slot=\"increment\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'top',\n })\n )}\n aria-label={incrementAriaLabel ?? 'Increase value'}\n >\n <Plus className=\"h-3 w-3\" aria-hidden=\"true\" />\n </Button>\n <Button\n slot=\"decrement\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'bottom',\n })\n )}\n aria-label={decrementAriaLabel ?? 'Decrease value'}\n >\n <Minus className=\"h-3 w-3\" aria-hidden=\"true\" />\n </Button>\n </div>\n )}\n\n {/* Increment Button (right side for sides layout) */}\n {showSteppers && !isStackedLayout && (\n <Button\n slot=\"increment\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'right',\n })\n )}\n aria-label={incrementAriaLabel ?? 'Increase value'}\n >\n <Plus className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n )}\n </AriaGroup>\n\n {/* Description */}\n {description && (\n <AriaText\n slot=\"description\"\n className={cn(numberFieldDescriptionVariants({ size }))}\n >\n {description}\n </AriaText>\n )}\n\n {/* Error Message */}\n <AriaFieldError className={cn(numberFieldErrorVariants({ size }))}>\n {errorMessage}\n </AriaFieldError>\n </AriaNumberField>\n );\n }\n);\n\nNumberField.displayName = 'NumberField';\n"]}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export { DEFAULT_MAX_VALUE, DEFAULT_MIN_VALUE, NEGATIVE_MIN_VALUE, NumberField, NumberFieldPropsSchema, numberFieldDescriptionVariants, numberFieldErrorVariants, numberFieldInputVariants, numberFieldLabelVariants, numberFieldStepperVariants, numberFieldVariants } from '../../chunk-A3YUJA6W.mjs';
|
|
3
|
-
import '../../chunk-BDXKKMBZ.mjs';
|
|
4
|
-
import '../../chunk-FPKEAJRZ.mjs';
|
|
5
|
-
import '../../chunk-HK46BT5U.mjs';
|
|
6
|
-
import '../../chunk-E2KQFV3O.mjs';
|
|
7
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
"use client";
|
|
2
|
+
import {createContext,memo,forwardRef,useId,useContext}from'react';import {Button,NumberField,Label,Group,Input,Text,FieldError}from'react-aria-components';import {Loader2,Zap,Minus,Plus}from'lucide-react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {cva}from'class-variance-authority';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {z}from'zod';function t(...c){return twMerge(clsx(c))}var C=cva("inline-flex justify-center min-h-[44px] min-w-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50",{variants:{fullWidth:{true:"w-full",false:""},inVerticalGroup:{true:"items-stretch",false:"items-center"}},defaultVariants:{fullWidth:false,inVerticalGroup:false}}),L=cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative cursor-pointer",{variants:{variant:{default:"bg-[var(--primary-action)] text-[var(--primary-action-foreground)] shadow-md hover:bg-[var(--primary-action-hover)] data-[pressed]:bg-[var(--primary-action)]/80",destructive:"bg-[var(--destructive-background)] text-[var(--destructive-foreground)] shadow-md hover:bg-[var(--destructive-background)]/90 data-[pressed]:bg-[var(--destructive-background)]/80",outline:"border border-[var(--input-border)] bg-[var(--page-background)] hover:bg-[var(--input-border)] data-[pressed]:bg-[var(--input-border)]",secondary:"bg-[var(--secondary)] text-[var(--secondary-foreground)] shadow-md hover:bg-[var(--secondary)]/80 data-[pressed]:bg-[var(--secondary)]/70",ghost:"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)] data-[pressed]:bg-[var(--accent)]",link:"text-[var(--text-link)] underline-offset-4 hover:underline data-[pressed]:text-[var(--text-link-hover)]"},fullWidth:{true:"w-full",false:""},visualSize:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3 text-xs",lg:"h-11 rounded-md px-8",icon:"h-10 w-10",dot:"h-5 w-5 rounded-full p-0 min-h-0 min-w-0"},paywall:{true:"!bg-[var(--paywall)] !text-[var(--paywall-foreground)] !shadow-md hover:!bg-[var(--paywall)]/90 !cursor-not-allowed !border-transparent",false:""}},defaultVariants:{variant:"default",visualSize:"default",paywall:false}});var P="data-[pressed]:scale-[0.97]";var G="data-[hovered]:shadow-md";var S="hc:data-[hovered]:outline hc:data-[hovered]:outline-2 hc:data-[hovered]:outline-foreground",y="hc:data-[pressed]:outline hc:data-[pressed]:outline-2 hc:data-[pressed]:outline-offset-1 hc:data-[pressed]:outline-foreground";var ee=createContext(null);ee.displayName="ButtonGroupContext";function te(){return useContext(ee)}var re=createContext(null);re.displayName="ButtonGroupItemContext";function ae(){return useContext(re)}cva("inline-flex items-center gap-0",{variants:{orientation:{horizontal:"flex-row",vertical:"flex-col w-full"}},defaultVariants:{orientation:"horizontal"}});var oe=cva("",{variants:{orientation:{horizontal:"min-w-[44px]",vertical:"flex min-h-[44px]"},position:{first:"",middle:"",last:"",only:""}},compoundVariants:[{orientation:"horizontal",position:"first",className:"rounded-r-none border-r-0"},{orientation:"horizontal",position:"middle",className:"rounded-none border-r-0"},{orientation:"horizontal",position:"last",className:"rounded-l-none"},{orientation:"vertical",position:"first",className:"rounded-b-none border-b-0"},{orientation:"vertical",position:"middle",className:"rounded-none border-b-0"},{orientation:"vertical",position:"last",className:"rounded-t-none"}],defaultVariants:{orientation:"horizontal",position:"only"}});cva("bg-[var(--border)]",{variants:{orientation:{horizontal:"w-px h-6 mx-1",vertical:"h-px w-full my-1"}},defaultVariants:{orientation:"horizontal"}});var i=memo(forwardRef(({className:c,buttonVisualClassName:v,variant:A,size:a,visualSize:x,fullWidth:I,loading:s=false,loadingText:h="Loading...",shortcut:g,children:V,isDisabled:w,paywall:o=false,paywallRedirect:f,paywallDescription:_,onPress:N,...F},T)=>{let E=useId(),n=te(),l=ae(),u=A??n?.variant??"default",le=a??n?.size,ue=w??n?.isDisabled??false,X=n?.orientation==="vertical",j=I||X,de=l?oe({orientation:n?.orientation??"horizontal",position:l.position}):"",B=x??le??"default";return process.env.NODE_ENV!=="production"&&(B==="dot"||B==="icon")&&!F["aria-label"]&&!V&&console.warn('[Button] visualSize="dot" or "icon" requires aria-label when no visible text is provided (WCAG 1.1.1)'),jsx(Button,{ref:T,isDisabled:ue||s||void 0,"aria-disabled":o?true:void 0,"aria-describedby":o?E:void 0,onPress:b=>{if(o){f&&window.open(f,"_blank","noopener,noreferrer");return}N?.(b);},className:t(C({fullWidth:j,inVerticalGroup:X}),c),...F,children:b=>jsxs("span",{className:t(L({variant:u,visualSize:B,paywall:o,fullWidth:j}),de,v,P,G,S,y),"data-pressed":b.isPressed||void 0,children:[s&&jsxs(Fragment,{children:[jsx(Loader2,{className:"motion-safe:animate-spin","aria-hidden":"true"}),jsx("span",{className:"sr-only","aria-live":"polite",children:h})]}),!s&&V,o&&jsx(Zap,{"data-testid":"zap-icon","aria-hidden":"true",className:"ml-1"}),o&&jsxs("span",{id:E,className:"sr-only",children:["Premium feature: ",_||"Upgrade required to access this feature"]}),b.isFocusVisible&&g&&jsx("kbd",{className:"ml-auto hidden text-xs opacity-60 lg:inline",children:g}),b.isPressed&&jsx("span",{className:"absolute inset-0 rounded-[inherit] bg-current opacity-10 motion-safe:animate-in motion-safe:zoom-in-95","aria-hidden":"true"})]})})}));i.displayName="Button";var O=4294967295,k=0,U=-2147483647,Ne=z.object({value:z.number().nullable().optional(),defaultValue:z.number().optional(),minValue:z.number().optional(),maxValue:z.number().optional(),allowNegative:z.boolean().optional(),step:z.number().positive().optional(),formatOptions:z.custom().optional(),isDisabled:z.boolean().optional(),isReadOnly:z.boolean().optional(),isRequired:z.boolean().optional(),isInvalid:z.boolean().optional(),isWheelDisabled:z.boolean().optional(),validate:z.function().optional(),validationBehavior:z.enum(["native","aria"]).default("native"),label:z.string(),description:z.string().optional(),errorMessage:z.union([z.string(),z.function()]).optional(),stepperLayout:z.enum(["sides","stacked","hidden"]).default("sides"),incrementAriaLabel:z.string().optional(),decrementAriaLabel:z.string().optional(),name:z.string().optional(),size:z.enum(["sm","default","lg"]).default("default"),onChange:z.function().optional(),onFocus:z.function().optional(),onBlur:z.function().optional(),onFocusChange:z.function().optional(),className:z.string().optional(),autoFocus:z.boolean().optional()});var H=cva(["inline-flex items-center rounded-md border","bg-[var(--content-background)] text-[var(--content-foreground)]","transition-colors duration-200","focus-within:ring-2 focus-within:ring-[var(--ring)] focus-within:ring-offset-2","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50"],{variants:{size:{sm:"h-9 text-sm",default:"h-10 text-base",lg:"h-12 text-lg"},isInvalid:{true:"border-[var(--destructive)] focus-within:ring-[var(--destructive)]",false:"border-[var(--input)] hover:border-[var(--input)]/80"}},defaultVariants:{size:"default",isInvalid:false}}),M=cva(["flex-1 bg-transparent text-center tabular-nums","min-w-0","focus:outline-none","[appearance:textfield]","[&::-webkit-outer-spin-button]:appearance-none","[&::-webkit-inner-spin-button]:appearance-none"],{variants:{size:{sm:"px-2 text-sm",default:"px-3 text-base",lg:"px-4 text-lg"}},defaultVariants:{size:"default"}}),m=cva(["flex items-center justify-center","transition-colors duration-150","select-none","hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]","focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]","focus-visible:ring-inset","active:bg-[var(--accent)]/80","disabled:pointer-events-none disabled:opacity-50"],{variants:{size:{sm:"min-w-8 min-h-8 text-sm",default:"min-w-10 min-h-10 text-base",lg:"min-w-12 min-h-12 text-lg"},position:{left:"rounded-l-md border-r border-[var(--input)]",right:"rounded-r-md border-l border-[var(--input)]",top:"rounded-tr-md border-b border-l border-[var(--input)] h-1/2",bottom:"rounded-br-md border-l border-[var(--input)] h-1/2"}},defaultVariants:{size:"default"}}),$=cva(["block font-medium text-[var(--content-foreground)]","mb-1.5",'data-[required]:after:content-["*"] data-[required]:after:ml-0.5',"data-[required]:after:text-[var(--destructive)]"],{variants:{size:{sm:"text-sm",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),W=cva(["text-[var(--menu-muted)]","mt-1"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}}),Y=cva(["flex items-center gap-1","text-[var(--destructive)]","mt-1"],{variants:{size:{sm:"text-xs",default:"text-sm",lg:"text-base"}},defaultVariants:{size:"default"}});var se=forwardRef(({label:c,description:v,errorMessage:A,size:a="default",stepperLayout:x="sides",allowNegative:I=false,incrementAriaLabel:s,decrementAriaLabel:h,minValue:g,maxValue:V,className:w,isInvalid:o,isRequired:f,isDisabled:_,isReadOnly:N,...F},T)=>{let E=g??(I?U:k),n=V??O,l=x!=="hidden"&&!N,u=x==="stacked";return jsxs(NumberField,{ref:T,className:t("group flex flex-col",w),minValue:E,maxValue:n,isInvalid:o,isRequired:f,isDisabled:_,isReadOnly:N,...F,children:[jsx(Label,{className:t($({size:a})),"data-required":f||void 0,children:c}),jsxs(Group,{className:t(H({size:a,isInvalid:o??false}),u&&"pr-0"),children:[l&&!u&&jsx(i,{slot:"decrement",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"left"})),"aria-label":h??"Decrease value",children:jsx(Minus,{className:"h-4 w-4","aria-hidden":"true"})}),jsx(Input,{className:t(M({size:a}))}),l&&u&&jsxs("div",{className:"flex flex-col h-full",children:[jsx(i,{slot:"increment",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"top"})),"aria-label":s??"Increase value",children:jsx(Plus,{className:"h-3 w-3","aria-hidden":"true"})}),jsx(i,{slot:"decrement",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"bottom"})),"aria-label":h??"Decrease value",children:jsx(Minus,{className:"h-3 w-3","aria-hidden":"true"})})]}),l&&!u&&jsx(i,{slot:"increment",variant:"ghost",className:"!min-h-0 !min-w-0",buttonVisualClassName:t(m({size:a,position:"right"})),"aria-label":s??"Increase value",children:jsx(Plus,{className:"h-4 w-4","aria-hidden":"true"})})]}),v&&jsx(Text,{slot:"description",className:t(W({size:a})),children:v}),jsx(FieldError,{className:t(Y({size:a})),children:A})]})});se.displayName="NumberField";export{O as DEFAULT_MAX_VALUE,k as DEFAULT_MIN_VALUE,U as NEGATIVE_MIN_VALUE,se as NumberField,Ne as NumberFieldPropsSchema,W as numberFieldDescriptionVariants,Y as numberFieldErrorVariants,M as numberFieldInputVariants,$ as numberFieldLabelVariants,m as numberFieldStepperVariants,H as numberFieldVariants};//# sourceMappingURL=index.mjs.map
|
|
8
3
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.mjs"}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/cn.ts","../../../src/elements/Button/Button.styles.ts","../../../src/styles/interaction-states.ts","../../../src/elements/ButtonGroup/ButtonGroupContext.tsx","../../../src/elements/ButtonGroup/ButtonGroup.variants.ts","../../../src/elements/Button/Button.tsx","../../../src/elements/NumberField/NumberField.types.ts","../../../src/elements/NumberField/NumberField.variants.ts","../../../src/elements/NumberField/NumberField.tsx"],"names":["cn","inputs","twMerge","clsx","buttonOuterVariants","cva","buttonVisualVariants","PRESSED_STYLES","HOVER_STYLES","HIGH_CONTRAST_HOVER","HIGH_CONTRAST_PRESSED","ButtonGroupContext","createContext","useButtonGroupContext","useContext","ButtonGroupItemContext","useButtonGroupItemContext","buttonGroupItemVariants","Button","memo","forwardRef","className","buttonVisualClassName","variant","size","visualSize","fullWidth","loading","loadingText","shortcut","children","isDisabled","paywall","paywallRedirect","paywallDescription","onPress","props","ref","paywallDescriptionId","useId","groupContext","itemContext","effectiveVariant","effectiveSize","effectiveIsDisabled","isInVerticalGroup","effectiveFullWidth","positionClassName","effectiveVisualSize","jsx","AriaButton","e","renderProps","jsxs","Fragment","Loader2","Zap","DEFAULT_MAX_VALUE","DEFAULT_MIN_VALUE","NEGATIVE_MIN_VALUE","NumberFieldPropsSchema","z","numberFieldVariants","numberFieldInputVariants","numberFieldStepperVariants","numberFieldLabelVariants","numberFieldDescriptionVariants","numberFieldErrorVariants","NumberField","label","description","errorMessage","stepperLayout","allowNegative","incrementAriaLabel","decrementAriaLabel","minValue","maxValue","isInvalid","isRequired","isReadOnly","effectiveMinValue","effectiveMaxValue","showSteppers","isStackedLayout","AriaNumberField","AriaLabel","AriaGroup","Minus","AriaInput","Plus","AriaText","AriaFieldError"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Class Name Utility\n * Merges Tailwind CSS classes with conflict resolution\n *\n * Combines clsx for conditional classes and tailwind-merge for deduplication\n *\n * @example\n * cn('px-2 py-1', 'px-4') // => 'py-1 px-4' (px-4 overrides px-2)\n * cn('text-red-500', condition && 'text-blue-500') // => conditional application\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { cva } from 'class-variance-authority';\n\n/**\n * Layer 1: Transparent outer touch target (44x44px minimum)\n * Handles WCAG 2.2 AAA touch target requirement\n * Always transparent, centers the visual button inside\n * IMPORTANT: Focus ring stays on Layer 1 for AAA compliance (2.4.13)\n *\n * In vertical ButtonGroups, uses items-stretch so the visual layer (Layer 2)\n * can fill the full touch target height, eliminating gaps between buttons.\n */\nexport const buttonOuterVariants = cva(\n \"inline-flex justify-center min-h-[44px] min-w-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n fullWidth: {\n true: \"w-full\",\n false: \"\",\n },\n inVerticalGroup: {\n true: \"items-stretch\",\n false: \"items-center\",\n },\n },\n defaultVariants: {\n fullWidth: false,\n inVerticalGroup: false,\n },\n }\n);\n\n/**\n * Layer 2: Visual button appearance (adjustable size)\n * Provides the visual appearance with configurable size\n * Can be smaller than touch target for use cases like carousel dots\n * NOTE: NO focus-visible styles here - focus ring is on Layer 1\n */\nexport const buttonVisualVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative cursor-pointer\",\n {\n variants: {\n variant: {\n default:\n \"bg-[var(--primary-action)] text-[var(--primary-action-foreground)] shadow-md hover:bg-[var(--primary-action-hover)] data-[pressed]:bg-[var(--primary-action)]/80\",\n destructive:\n \"bg-[var(--destructive-background)] text-[var(--destructive-foreground)] shadow-md hover:bg-[var(--destructive-background)]/90 data-[pressed]:bg-[var(--destructive-background)]/80\",\n outline:\n \"border border-[var(--input-border)] bg-[var(--page-background)] hover:bg-[var(--input-border)] data-[pressed]:bg-[var(--input-border)]\",\n secondary:\n \"bg-[var(--secondary)] text-[var(--secondary-foreground)] shadow-md hover:bg-[var(--secondary)]/80 data-[pressed]:bg-[var(--secondary)]/70\",\n ghost:\n \"hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)] data-[pressed]:bg-[var(--accent)]\",\n link: \"text-[var(--text-link)] underline-offset-4 hover:underline data-[pressed]:text-[var(--text-link-hover)]\",\n },\n fullWidth: {\n true: \"w-full\",\n false: \"\",\n },\n visualSize: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3 text-xs\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n dot: \"h-5 w-5 rounded-full p-0 min-h-0 min-w-0\",\n },\n paywall: {\n true: \"!bg-[var(--paywall)] !text-[var(--paywall-foreground)] !shadow-md hover:!bg-[var(--paywall)]/90 !cursor-not-allowed !border-transparent\",\n false: \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n visualSize: \"default\",\n paywall: false,\n },\n }\n);\n\n/**\n * @deprecated Use buttonVisualVariants instead. This alias is kept for backward compatibility.\n */\nexport const buttonVariants = buttonVisualVariants;\n","/**\n * Global Interaction State Styles\n *\n * Consistent interaction patterns across all Themis components.\n * These styles ensure WCAG 2.2 AAA compliance and predictable UX.\n *\n * @see spec.md FR-010 (Visible focus ring for keyboard navigation)\n * @see spec.md FR-031 (Pressed state feedback)\n * @see spec.md FR-012 (High contrast mode support)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\n/**\n * Focus state styles (FR-010)\n * Visible focus ring for keyboard navigation - WCAG 2.2 Level AAA\n *\n * Components can override by extending these styles:\n * @example\n * cn(FOCUS_STYLES, \"ring-4\") // Increases ring width to 4px\n */\nexport const FOCUS_STYLES = \"data-[focus-visible]:ring-2 data-[focus-visible]:ring-[var(--themis-ring)] data-[focus-visible]:ring-offset-2\";\n\n/**\n * Pressed/Active state styles (FR-031)\n * Visual feedback for press interactions\n *\n * Components can override the scale amount:\n * @example\n * cn(PRESSED_STYLES_BASE, \"data-[pressed]:scale-[0.95]\") // More pronounced scale\n */\nexport const PRESSED_STYLES = \"data-[pressed]:scale-[0.97]\";\n\n/**\n * Base pressed styles without scale (for components that need different feedback)\n */\nexport const PRESSED_STYLES_BASE = \"data-[pressed]:transition-transform data-[pressed]:duration-100\";\n\n/**\n * Hover state styles\n * Elevation change on hover for better affordance\n *\n * Components can override shadow depth:\n * @example\n * cn(HOVER_STYLES_BASE, \"data-[hovered]:shadow-lg\") // Larger shadow\n */\nexport const HOVER_STYLES = \"data-[hovered]:shadow-md\";\n\n/**\n * Base hover styles without shadow (for components that use different hover effects)\n */\nexport const HOVER_STYLES_BASE = \"data-[hovered]:transition-shadow data-[hovered]:duration-200\";\n\n/**\n * High contrast mode focus (FR-012)\n * Enhanced outlines for users requiring high contrast\n *\n * Uses 'hc:' prefix for prefers-contrast: more media query\n */\nexport const HIGH_CONTRAST_FOCUS = \"hc:data-[focus-visible]:outline hc:data-[focus-visible]:outline-4 hc:data-[focus-visible]:outline-offset-2 hc:data-[focus-visible]:outline-foreground\";\n\n/**\n * High contrast mode hover (FR-012)\n * Enhanced outlines for hover in high contrast mode\n */\nexport const HIGH_CONTRAST_HOVER = \"hc:data-[hovered]:outline hc:data-[hovered]:outline-2 hc:data-[hovered]:outline-foreground\";\n\n/**\n * High contrast mode pressed state\n * Enhanced outlines for pressed state in high contrast mode\n */\nexport const HIGH_CONTRAST_PRESSED = \"hc:data-[pressed]:outline hc:data-[pressed]:outline-2 hc:data-[pressed]:outline-offset-1 hc:data-[pressed]:outline-foreground\";\n\n/**\n * Combined high contrast styles\n * Use this for components that need all high contrast interaction states\n */\nexport const HIGH_CONTRAST_INTERACTIONS = `${HIGH_CONTRAST_FOCUS} ${HIGH_CONTRAST_HOVER} ${HIGH_CONTRAST_PRESSED}`;\n\n/**\n * Disabled state styles\n * Consistent disabled appearance across all components\n */\nexport const DISABLED_STYLES = \"disabled:pointer-events-none disabled:opacity-50\";\n\n/**\n * Default interaction bundle\n * Most common combination for interactive components\n *\n * Includes: focus ring, pressed scale, hover shadow, high contrast enhancements\n *\n * @example\n * <button className={cn(DEFAULT_INTERACTIONS, \"bg-primary\")}>Click</button>\n */\nexport const DEFAULT_INTERACTIONS = `${FOCUS_STYLES} ${PRESSED_STYLES} ${HOVER_STYLES} ${HIGH_CONTRAST_FOCUS} ${HIGH_CONTRAST_HOVER} ${HIGH_CONTRAST_PRESSED}`;\n\n/**\n * Subtle interaction bundle\n * For components that need less pronounced feedback\n *\n * Includes: focus ring and high contrast, but no hover shadow or pressed scale\n */\nexport const SUBTLE_INTERACTIONS = `${FOCUS_STYLES} ${HIGH_CONTRAST_FOCUS}`;\n\n/**\n * Non-interactive element styles\n * For elements that should indicate they are not interactive\n */\nexport const NON_INTERACTIVE = \"cursor-default select-none\";\n","\"use client\";\n\nimport { createContext, useContext } from 'react';\nimport type {\n ButtonGroupContextValue,\n ButtonGroupItemContextValue,\n} from './ButtonGroup.types';\n\n/**\n * ButtonGroup Context System (Two-Level)\n *\n * Provides a two-level context pattern for ButtonGroup:\n *\n * 1. ButtonGroupContext (group-level):\n * - Provides: orientation, variant, size, isDisabled\n * - Consumed by: Button (for prop inheritance), Separator (for orientation)\n *\n * 2. ButtonGroupItemContext (item-level):\n * - Provides: position ('first' | 'middle' | 'last' | 'only')\n * - Consumed by: Button (for border-radius styling)\n *\n * Both contexts return null when not in a provider, allowing Button\n * to work standalone without any group context.\n *\n * @see plan.md for architecture details\n * @see ButtonGroup.tsx for Provider implementation\n */\n\n// =============================================================================\n// Group-Level Context\n// =============================================================================\n\n/**\n * Context for group-level props (orientation, variant, size, isDisabled)\n * Default value is null to indicate \"not in a group\"\n */\nconst ButtonGroupContext = createContext<ButtonGroupContextValue | null>(null);\n\nButtonGroupContext.displayName = 'ButtonGroupContext';\n\n/**\n * Hook to access group-level context\n * @returns ButtonGroupContextValue if inside a ButtonGroup, null otherwise\n */\nexport function useButtonGroupContext(): ButtonGroupContextValue | null {\n return useContext(ButtonGroupContext);\n}\n\n// =============================================================================\n// Item-Level Context\n// =============================================================================\n\n/**\n * Context for per-button position information\n * Default value is null to indicate \"not wrapped with position context\"\n */\nconst ButtonGroupItemContext =\n createContext<ButtonGroupItemContextValue | null>(null);\n\nButtonGroupItemContext.displayName = 'ButtonGroupItemContext';\n\n/**\n * Hook to access item-level context (position)\n * @returns ButtonGroupItemContextValue if wrapped with position context, null otherwise\n */\nexport function useButtonGroupItemContext(): ButtonGroupItemContextValue | null {\n return useContext(ButtonGroupItemContext);\n}\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ButtonGroupContext, ButtonGroupItemContext };\n","import { cva } from 'class-variance-authority';\n\n/**\n * ButtonGroup CVA Variants\n *\n * Defines Class Variance Authority (CVA) variants for:\n * - ButtonGroup container (orientation-based layout)\n * - ButtonGroupItem (position-based border-radius)\n * - ButtonGroupSeparator (orientation-based styling)\n *\n * @see plan.md Phase 1: Design & Contracts - CVA Variants\n * @see constitution.md Principle V (Component Quality Standards)\n */\n\n// =============================================================================\n// Container Variants\n// =============================================================================\n\n/**\n * ButtonGroup container variants\n * Controls the layout direction based on orientation\n * Uses gap-0 to ensure buttons are connected (share borders)\n */\nexport const buttonGroupVariants = cva('inline-flex items-center gap-0', {\n variants: {\n orientation: {\n horizontal: 'flex-row',\n vertical: 'flex-col w-full',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n },\n});\n\n// =============================================================================\n// Item Position Variants\n// =============================================================================\n\n/**\n * ButtonGroupItem position variants\n * Applied to Button's visual layer (Layer 2) for position-aware border-radius\n *\n * Compound variants handle both orientation and position combinations:\n * - Horizontal: left/right borders and radii\n * - Vertical: top/bottom borders and radii\n */\nexport const buttonGroupItemVariants = cva('', {\n variants: {\n orientation: {\n // min-w-[44px] ensures visual layer fills touch target width (for icon buttons)\n horizontal: 'min-w-[44px]',\n // flex (overrides inline-flex) + min-h-[44px] makes visual layer fill touch target,\n // eliminating gaps between stacked buttons in vertical orientation\n vertical: 'flex min-h-[44px]',\n },\n position: {\n first: '',\n middle: '',\n last: '',\n only: '', // Single button - no modifications needed\n },\n },\n compoundVariants: [\n // ==========================================================================\n // Horizontal Orientation\n // ==========================================================================\n {\n orientation: 'horizontal',\n position: 'first',\n className: 'rounded-r-none border-r-0',\n },\n {\n orientation: 'horizontal',\n position: 'middle',\n className: 'rounded-none border-r-0',\n },\n {\n orientation: 'horizontal',\n position: 'last',\n className: 'rounded-l-none',\n },\n // ==========================================================================\n // Vertical Orientation\n // Note: w-full is handled by Button's effectiveFullWidth for both layers\n // ==========================================================================\n {\n orientation: 'vertical',\n position: 'first',\n className: 'rounded-b-none border-b-0',\n },\n {\n orientation: 'vertical',\n position: 'middle',\n className: 'rounded-none border-b-0',\n },\n {\n orientation: 'vertical',\n position: 'last',\n className: 'rounded-t-none',\n },\n ],\n defaultVariants: {\n orientation: 'horizontal',\n position: 'only',\n },\n});\n\n// =============================================================================\n// Separator Variants\n// =============================================================================\n\n/**\n * ButtonGroupSeparator variants\n * Orientation-aware visual divider between button groups\n */\nexport const buttonGroupSeparatorVariants = cva('bg-[var(--border)]', {\n variants: {\n orientation: {\n horizontal: 'w-px h-6 mx-1',\n vertical: 'h-px w-full my-1',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n },\n});\n","\"use client\";\n\n/**\n * Button Component - 3-Layer Architecture\n * Accessible button with React Aria primitives and CVA styling\n *\n * Architecture:\n * - Layer 1: Touch Target (44x44px WCAG AAA compliant, transparent)\n * - Layer 2: Visual Button (configurable size, colors, borders)\n * - Layer 3: Content & Effects (text, icons, ripple, loading spinner)\n *\n * @see 3layer-plan.md for architecture details\n * @see spec.md FR-029 to FR-037 (Button Component Requirements)\n * @see spec.md FR-009 (WCAG 2.2 AAA - 7:1 contrast ratio)\n * @see spec.md FR-014 (44x44px minimum touch targets)\n * @see constitution.md Principle IV (Accessibility First)\n */\n\nimport { forwardRef, memo, useId } from 'react';\nimport {\n Button as AriaButton,\n type ButtonProps as AriaButtonProps,\n} from 'react-aria-components';\nimport { Loader2, Zap } from 'lucide-react';\nimport { cn } from '../../utils/cn';\nimport type { ButtonProps } from './Button.types';\nimport { buttonOuterVariants, buttonVisualVariants, buttonVariants } from './Button.styles';\nimport { PRESSED_STYLES, HOVER_STYLES, HIGH_CONTRAST_HOVER, HIGH_CONTRAST_PRESSED } from '../../styles/interaction-states';\nimport {\n useButtonGroupContext,\n useButtonGroupItemContext,\n} from '../ButtonGroup/ButtonGroupContext';\nimport { buttonGroupItemVariants } from '../ButtonGroup/ButtonGroup.variants';\n\n/**\n * Button Component - 3-Layer Architecture\n * Fully accessible button with React Aria and themed styling\n *\n * Layer 1: Touch Target (AriaButton) - 44x44px WCAG AAA compliant\n * Layer 2: Visual Button (span) - configurable appearance\n * Layer 3: Content (children) - text, icons, effects\n */\nconst Button = memo(forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n buttonVisualClassName,\n variant,\n size,\n visualSize,\n fullWidth,\n loading = false,\n loadingText = \"Loading...\",\n shortcut,\n children,\n isDisabled,\n paywall = false,\n paywallRedirect,\n paywallDescription,\n onPress,\n ...props\n },\n ref\n ) => {\n const paywallDescriptionId = useId();\n\n // ==========================================================================\n // ButtonGroup Context Integration\n // ==========================================================================\n\n // Consume group-level context (variant, size, isDisabled, orientation)\n const groupContext = useButtonGroupContext();\n\n // Consume item-level context (position for border-radius styling)\n const itemContext = useButtonGroupItemContext();\n\n // Merge context values with props (props take precedence)\n const effectiveVariant = variant ?? groupContext?.variant ?? 'default';\n const effectiveSize = size ?? groupContext?.size;\n const effectiveIsDisabled = isDisabled ?? groupContext?.isDisabled ?? false;\n\n // In vertical groups, buttons should be full width automatically\n const isInVerticalGroup = groupContext?.orientation === 'vertical';\n const effectiveFullWidth = fullWidth || isInVerticalGroup;\n\n // Position styling for ButtonGroup (only applied when in a group)\n const positionClassName = itemContext\n ? buttonGroupItemVariants({\n orientation: groupContext?.orientation ?? 'horizontal',\n position: itemContext.position,\n })\n : '';\n\n // Default visualSize to size for backward compatibility\n const effectiveVisualSize = visualSize ?? effectiveSize ?? 'default';\n\n // AAA Accessibility: Warn in dev/test if icon/dot variant lacks accessible name\n if (process.env.NODE_ENV !== 'production') {\n if (\n (effectiveVisualSize === 'dot' || effectiveVisualSize === 'icon') &&\n !props['aria-label'] &&\n !children\n ) {\n console.warn(\n '[Button] visualSize=\"dot\" or \"icon\" requires aria-label when no visible text is provided (WCAG 1.1.1)'\n );\n }\n }\n\n /**\n * Handle button press - intercepts action when paywalled\n * If paywalled with redirect URL, opens in new tab\n * Otherwise, calls the normal onPress handler\n */\n const handlePress = (e: Parameters<NonNullable<AriaButtonProps['onPress']>>[0]): void => {\n if (paywall) {\n if (paywallRedirect) {\n window.open(paywallRedirect, '_blank', 'noopener,noreferrer');\n }\n // Don't call onPress when paywalled\n return;\n }\n onPress?.(e);\n };\n\n // Only set isDisabled when we have a reason to disable\n // Otherwise, let slot system control disabled state (e.g., in NumberField)\n const computedIsDisabled = effectiveIsDisabled || loading || undefined;\n\n return (\n <AriaButton\n ref={ref}\n isDisabled={computedIsDisabled}\n aria-disabled={paywall ? true : undefined}\n aria-describedby={paywall ? paywallDescriptionId : undefined}\n onPress={handlePress}\n className={cn(buttonOuterVariants({ fullWidth: effectiveFullWidth, inVerticalGroup: isInVerticalGroup }), className)}\n {...props}\n >\n {(renderProps) => (\n /* Layer 2: Visual Button */\n <span\n className={cn(\n buttonVisualVariants({\n variant: effectiveVariant,\n visualSize: effectiveVisualSize,\n paywall,\n fullWidth: effectiveFullWidth,\n }),\n // Position styling from ButtonGroup context (border-radius adjustments)\n positionClassName,\n buttonVisualClassName,\n // Layer 2 interaction styles (no focus - focus ring is on Layer 1)\n PRESSED_STYLES,\n HOVER_STYLES,\n HIGH_CONTRAST_HOVER,\n HIGH_CONTRAST_PRESSED\n )}\n data-pressed={renderProps.isPressed || undefined}\n >\n {/* Layer 3: Content & Effects */}\n\n {/* FR-033: Loading spinner with screen reader announcement */}\n {/* Uses motion-safe: for WCAG 2.3.3 AAA (Animation from Interactions) */}\n {loading && (\n <>\n <Loader2 className=\"motion-safe:animate-spin\" aria-hidden=\"true\" />\n <span className=\"sr-only\" aria-live=\"polite\">\n {loadingText}\n </span>\n </>\n )}\n\n {/* Hide children during loading */}\n {!loading && children}\n\n {/* Paywall: Lightning bolt icon */}\n {paywall && (\n <Zap\n data-testid=\"zap-icon\"\n aria-hidden=\"true\"\n className=\"ml-1\"\n />\n )}\n\n {/* Paywall: Screen reader description */}\n {paywall && (\n <span id={paywallDescriptionId} className=\"sr-only\">\n Premium feature: {paywallDescription || \"Upgrade required to access this feature\"}\n </span>\n )}\n\n {/* FR-034: Keyboard shortcut display on focus */}\n {renderProps.isFocusVisible && shortcut && (\n <kbd className=\"ml-auto hidden text-xs opacity-60 lg:inline\">\n {shortcut}\n </kbd>\n )}\n\n {/* Touch/press ripple effect - FR-031: Pressed state feedback */}\n {/* Uses motion-safe: for WCAG 2.3.3 AAA (Animation from Interactions) */}\n {renderProps.isPressed && (\n <span\n className=\"absolute inset-0 rounded-[inherit] bg-current opacity-10 motion-safe:animate-in motion-safe:zoom-in-95\"\n aria-hidden=\"true\"\n />\n )}\n </span>\n )}\n </AriaButton>\n );\n }\n));\n\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants, buttonOuterVariants, buttonVisualVariants };\nexport type { ButtonProps } from './Button.types';\n","/**\n * NumberField Component Types\n *\n * Zod schemas and TypeScript types for the NumberField component.\n * CVA variants are in a separate file (NumberField.variants.ts) to separate\n * styling concerns from type definitions.\n *\n * Note: Zod schemas are used for contract tests and developer guardrails,\n * not runtime validation. This follows the established Themis pattern.\n *\n * @see {@link ../../docs/prd/numberfield-prd.md} for full requirements\n */\n\nimport { z } from 'zod';\nimport type {\n NumberFieldProps as AriaNumberFieldProps,\n ValidationResult,\n} from 'react-aria-components';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * Default maximum value (UINT32_MAX) to prevent overflow/Infinity.\n */\nexport const DEFAULT_MAX_VALUE = 4294967295;\n\n/**\n * Default minimum value for non-negative numbers.\n */\nexport const DEFAULT_MIN_VALUE = 0;\n\n/**\n * Minimum value when allowNegative is enabled (INT32_MIN + 1).\n */\nexport const NEGATIVE_MIN_VALUE = -2147483647;\n\n// ============================================================================\n// Size Variant Type\n// ============================================================================\n\n/**\n * Size variants for NumberField component.\n * - 'sm': Compact size (36px height) - touch targets via padding\n * - 'default': Standard size (40px height) - AAA compliant\n * - 'lg': Large size (48px height) - AAA compliant\n */\nexport type NumberFieldSize = 'sm' | 'default' | 'lg';\n\n// ============================================================================\n// Stepper Layout Type\n// ============================================================================\n\n/**\n * Layout options for stepper buttons.\n * - 'sides': Buttons on left (-) and right (+) of input (default)\n * - 'stacked': Buttons stacked vertically on right side\n * - 'hidden': No stepper buttons (keyboard/typing only)\n */\nexport type StepperLayout = 'sides' | 'stacked' | 'hidden';\n\n// ============================================================================\n// Zod Schemas\n// ============================================================================\n\n/**\n * Zod schema for NumberField props validation.\n * Used for contract tests and developer guardrails, not runtime validation.\n */\nexport const NumberFieldPropsSchema = z.object({\n // Value props\n /** Current value (controlled mode) */\n value: z.number().nullable().optional(),\n /** Default value (uncontrolled mode) */\n defaultValue: z.number().optional(),\n\n // Constraint props\n /** Minimum allowed value (default: 0) */\n minValue: z.number().optional(),\n /** Maximum allowed value (default: 4294967295 / UINT32_MAX) */\n maxValue: z.number().optional(),\n /** Allow negative numbers (sets minValue to -2147483647 if not explicitly set) */\n allowNegative: z.boolean().optional(),\n /** Step increment for stepper buttons and arrow keys (default: 1) */\n step: z.number().positive().optional(),\n\n // Formatting props\n /** Intl.NumberFormat options for locale-aware formatting */\n formatOptions: z.custom<Intl.NumberFormatOptions>().optional(),\n\n // State props\n /** Whether the field is disabled */\n isDisabled: z.boolean().optional(),\n /** Whether the field is read-only */\n isReadOnly: z.boolean().optional(),\n /** Whether the field is required */\n isRequired: z.boolean().optional(),\n /** Whether the field is in an invalid state */\n isInvalid: z.boolean().optional(),\n /** Whether scroll wheel adjustment is disabled */\n isWheelDisabled: z.boolean().optional(),\n\n // Validation props\n /** Custom validation function that returns an error message or null */\n validate: z.function().optional(),\n /** Validation behavior: 'native' for HTML5 validation, 'aria' for ARIA-only */\n validationBehavior: z.enum(['native', 'aria']).default('native'),\n\n // Display props\n /** Field label (required for accessibility) */\n label: z.string(),\n /** Description text below the field */\n description: z.string().optional(),\n /** Error message string or render function */\n errorMessage: z.union([z.string(), z.function()]).optional(),\n\n // Stepper props\n /** Layout for stepper buttons */\n stepperLayout: z.enum(['sides', 'stacked', 'hidden']).default('sides'),\n /** Custom aria-label for increment button */\n incrementAriaLabel: z.string().optional(),\n /** Custom aria-label for decrement button */\n decrementAriaLabel: z.string().optional(),\n\n // Form props\n /** Name attribute for form submission */\n name: z.string().optional(),\n\n // Variant props\n /** Size variant */\n size: z.enum(['sm', 'default', 'lg']).default('default'),\n\n // Event props\n /** Called when the numeric value changes */\n onChange: z.function().optional(),\n /** Called when the field gains focus */\n onFocus: z.function().optional(),\n /** Called when the field loses focus */\n onBlur: z.function().optional(),\n /** Called when focus state changes */\n onFocusChange: z.function().optional(),\n\n // Standard props\n /** Additional CSS classes */\n className: z.string().optional(),\n /** Whether to auto-focus on mount */\n autoFocus: z.boolean().optional(),\n});\n\n// ============================================================================\n// TypeScript Types\n// ============================================================================\n\n/**\n * Custom props added to NumberField (not from React Aria).\n */\nexport interface ThemisNumberFieldCustomProps {\n /** Size variant: 'sm', 'default', or 'lg' */\n size?: NumberFieldSize;\n /** Field label (required for accessibility) */\n label: string;\n /** Description text below the field */\n description?: string;\n /** Error message when field is invalid */\n errorMessage?: string | ((validation: ValidationResult) => string);\n /** Layout for stepper buttons */\n stepperLayout?: StepperLayout;\n /** Custom aria-label for increment button */\n incrementAriaLabel?: string;\n /** Custom aria-label for decrement button */\n decrementAriaLabel?: string;\n /** Allow negative numbers (sets minValue to -2147483647 if not explicitly set) */\n allowNegative?: boolean;\n}\n\n/**\n * Props for the NumberField component.\n * Combines React Aria's NumberFieldProps with Themis-specific props.\n */\nexport type NumberFieldProps = Omit<AriaNumberFieldProps, 'children'> &\n ThemisNumberFieldCustomProps;\n","/**\n * NumberField Component CVA Variants\n *\n * Class Variance Authority (CVA) variant definitions for the NumberField component.\n * Separated from types to maintain clean separation of concerns.\n *\n * Styling uses semantic CSS tokens that map to ThemeProvider variables:\n * - --background: Input background color\n * - --foreground: Text color\n * - --input: Input border color (default state)\n * - --ring: Focus ring color\n * - --accent: Stepper button hover background\n * - --accent-foreground: Stepper button hover text\n * - --destructive: Error state border and text\n * - --muted-foreground: Placeholder/disabled text\n *\n * @see {@link ../../docs/prd/numberfield-prd.md} for full requirements\n */\n\nimport { cva, type VariantProps } from 'class-variance-authority';\n\n// ============================================================================\n// Container Variants\n// ============================================================================\n\n/**\n * Variants for the NumberField container (Group element).\n * Contains the input and stepper buttons.\n *\n * Size notes:\n * - sm (36px): Compact, touch targets achieved via padding\n * - default (40px): Standard size, AAA compliant touch targets\n * - lg (48px): Large size, enhanced touch targets\n */\nexport const numberFieldVariants = cva(\n [\n // Base styles\n 'inline-flex items-center rounded-md border',\n 'bg-[var(--content-background)] text-[var(--content-foreground)]',\n 'transition-colors duration-200',\n // Focus within\n 'focus-within:ring-2 focus-within:ring-[var(--ring)] focus-within:ring-offset-2',\n // Disabled\n 'data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50',\n ],\n {\n variants: {\n size: {\n sm: 'h-9 text-sm',\n default: 'h-10 text-base',\n lg: 'h-12 text-lg',\n },\n isInvalid: {\n true: 'border-[var(--destructive)] focus-within:ring-[var(--destructive)]',\n false: 'border-[var(--input)] hover:border-[var(--input)]/80',\n },\n },\n defaultVariants: {\n size: 'default',\n isInvalid: false,\n },\n }\n);\n\n// ============================================================================\n// Input Variants\n// ============================================================================\n\n/**\n * Variants for the numeric input element.\n * Hides native spinners and centers text.\n */\nexport const numberFieldInputVariants = cva(\n [\n // Base styles\n 'flex-1 bg-transparent text-center tabular-nums',\n 'min-w-0', // Allow shrinking\n // Focus\n 'focus:outline-none',\n // Hide native spinners\n '[appearance:textfield]',\n '[&::-webkit-outer-spin-button]:appearance-none',\n '[&::-webkit-inner-spin-button]:appearance-none',\n ],\n {\n variants: {\n size: {\n sm: 'px-2 text-sm',\n default: 'px-3 text-base',\n lg: 'px-4 text-lg',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Stepper Button Variants\n// ============================================================================\n\n/**\n * Variants for the stepper buttons (increment/decrement).\n * Supports different positions for sides and stacked layouts.\n *\n * Touch target strategy:\n * - Visual button size varies with component size\n * - 44x44px minimum touch target achieved via padding/hit area\n */\nexport const numberFieldStepperVariants = cva(\n [\n // Base styles\n 'flex items-center justify-center',\n 'transition-colors duration-150',\n 'select-none',\n // Hover\n 'hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)]',\n // Focus\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',\n 'focus-visible:ring-inset',\n // Active (pressed)\n 'active:bg-[var(--accent)]/80',\n // Disabled\n 'disabled:pointer-events-none disabled:opacity-50',\n ],\n {\n variants: {\n size: {\n sm: 'min-w-8 min-h-8 text-sm',\n default: 'min-w-10 min-h-10 text-base',\n lg: 'min-w-12 min-h-12 text-lg',\n },\n position: {\n left: 'rounded-l-md border-r border-[var(--input)]',\n right: 'rounded-r-md border-l border-[var(--input)]',\n top: 'rounded-tr-md border-b border-l border-[var(--input)] h-1/2',\n bottom: 'rounded-br-md border-l border-[var(--input)] h-1/2',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Label Variants\n// ============================================================================\n\n/**\n * Variants for the NumberField label.\n */\nexport const numberFieldLabelVariants = cva(\n [\n 'block font-medium text-[var(--content-foreground)]',\n 'mb-1.5',\n // Required indicator\n 'data-[required]:after:content-[\"*\"] data-[required]:after:ml-0.5',\n 'data-[required]:after:text-[var(--destructive)]',\n ],\n {\n variants: {\n size: {\n sm: 'text-sm',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Description Variants\n// ============================================================================\n\n/**\n * Variants for the description text below the field.\n */\nexport const numberFieldDescriptionVariants = cva(\n [\n 'text-[var(--menu-muted)]',\n 'mt-1',\n ],\n {\n variants: {\n size: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Error Variants\n// ============================================================================\n\n/**\n * Variants for the error message display.\n */\nexport const numberFieldErrorVariants = cva(\n [\n 'flex items-center gap-1',\n 'text-[var(--destructive)]',\n 'mt-1',\n ],\n {\n variants: {\n size: {\n sm: 'text-xs',\n default: 'text-sm',\n lg: 'text-base',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n);\n\n// ============================================================================\n// Variant Types (from CVA)\n// ============================================================================\n\n/**\n * Variant props for numberFieldVariants CVA function.\n */\nexport type NumberFieldVariantProps = VariantProps<typeof numberFieldVariants>;\n\n/**\n * Variant props for numberFieldInputVariants CVA function.\n */\nexport type NumberFieldInputVariantProps = VariantProps<typeof numberFieldInputVariants>;\n\n/**\n * Variant props for numberFieldStepperVariants CVA function.\n */\nexport type NumberFieldStepperVariantProps = VariantProps<typeof numberFieldStepperVariants>;\n","'use client';\n\n/**\n * NumberField Component\n *\n * A fully accessible numeric input component built on React Aria's NumberField primitive.\n * Provides keyboard-editable input with optional increment/decrement stepper buttons.\n *\n * Features:\n * - WCAG 2.2 AAA compliant (44x44px touch targets, 7:1 contrast)\n * - Spinbutton ARIA semantics\n * - Locale-aware number formatting via Intl.NumberFormat\n * - Configurable min/max/step constraints\n * - Optional stepper buttons (sides, stacked, or hidden layouts)\n * - Scroll wheel support\n * - Form integration with hidden input\n * - Full keyboard navigation (Arrow, Page Up/Down, Home/End)\n * - Screen reader accessible\n *\n * @see {@link ../../docs/prd/numberfield-prd.md} for full requirements\n */\n\nimport { forwardRef, type ReactElement } from 'react';\nimport {\n NumberField as AriaNumberField,\n Group as AriaGroup,\n Input as AriaInput,\n Label as AriaLabel,\n Text as AriaText,\n FieldError as AriaFieldError,\n} from 'react-aria-components';\nimport { Minus, Plus } from 'lucide-react';\nimport { Button } from '../Button';\nimport { cn } from '../../utils/cn';\nimport type { NumberFieldProps } from './NumberField.types';\nimport {\n DEFAULT_MAX_VALUE,\n DEFAULT_MIN_VALUE,\n NEGATIVE_MIN_VALUE,\n} from './NumberField.types';\nimport {\n numberFieldVariants,\n numberFieldInputVariants,\n numberFieldStepperVariants,\n numberFieldLabelVariants,\n numberFieldDescriptionVariants,\n numberFieldErrorVariants,\n} from './NumberField.variants';\n\n// =============================================================================\n// NumberField Component\n// =============================================================================\n\n/**\n * NumberField component for numeric input with optional stepper buttons.\n *\n * @example\n * ```tsx\n * import { NumberField } from '@tribepad/themis/elements/NumberField';\n *\n * // Basic usage\n * <NumberField label=\"Quantity\" />\n *\n * // With constraints\n * <NumberField\n * label=\"Quantity\"\n * minValue={1}\n * maxValue={100}\n * step={1}\n * defaultValue={5}\n * />\n *\n * // Currency formatting\n * <NumberField\n * label=\"Price\"\n * formatOptions={{ style: 'currency', currency: 'USD' }}\n * step={0.01}\n * defaultValue={9.99}\n * />\n *\n * // Allow negative numbers\n * <NumberField\n * label=\"Temperature\"\n * allowNegative\n * formatOptions={{ style: 'unit', unit: 'celsius' }}\n * />\n *\n * // Hidden steppers\n * <NumberField\n * label=\"Account Number\"\n * stepperLayout=\"hidden\"\n * />\n * ```\n */\nexport const NumberField = forwardRef<HTMLDivElement, NumberFieldProps>(\n (\n {\n // Display props\n label,\n description,\n errorMessage,\n // Variant props\n size = 'default',\n stepperLayout = 'sides',\n // Custom props\n allowNegative = false,\n incrementAriaLabel,\n decrementAriaLabel,\n // Constraint props (apply defaults)\n minValue,\n maxValue,\n // Standard props\n className,\n isInvalid,\n isRequired,\n isDisabled,\n isReadOnly,\n // All other props go to AriaNumberField\n ...props\n },\n ref\n ): ReactElement => {\n // Calculate effective min/max values\n const effectiveMinValue =\n minValue ?? (allowNegative ? NEGATIVE_MIN_VALUE : DEFAULT_MIN_VALUE);\n const effectiveMaxValue = maxValue ?? DEFAULT_MAX_VALUE;\n\n // Determine if steppers should be shown\n const showSteppers = stepperLayout !== 'hidden' && !isReadOnly;\n const isStackedLayout = stepperLayout === 'stacked';\n\n return (\n <AriaNumberField\n ref={ref}\n className={cn('group flex flex-col', className)}\n minValue={effectiveMinValue}\n maxValue={effectiveMaxValue}\n isInvalid={isInvalid}\n isRequired={isRequired}\n isDisabled={isDisabled}\n isReadOnly={isReadOnly}\n {...props}\n >\n {/* Label */}\n <AriaLabel\n className={cn(numberFieldLabelVariants({ size }))}\n data-required={isRequired || undefined}\n >\n {label}\n </AriaLabel>\n\n {/* Input Group */}\n <AriaGroup\n className={cn(\n numberFieldVariants({\n size,\n isInvalid: isInvalid ?? false,\n }),\n isStackedLayout && 'pr-0'\n )}\n >\n {/* Decrement Button (left side for sides layout) */}\n {showSteppers && !isStackedLayout && (\n <Button\n slot=\"decrement\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'left',\n })\n )}\n aria-label={decrementAriaLabel ?? 'Decrease value'}\n >\n <Minus className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n )}\n\n {/* Input */}\n <AriaInput\n className={cn(numberFieldInputVariants({ size }))}\n />\n\n {/* Stacked Layout Buttons */}\n {showSteppers && isStackedLayout && (\n <div className=\"flex flex-col h-full\">\n <Button\n slot=\"increment\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'top',\n })\n )}\n aria-label={incrementAriaLabel ?? 'Increase value'}\n >\n <Plus className=\"h-3 w-3\" aria-hidden=\"true\" />\n </Button>\n <Button\n slot=\"decrement\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'bottom',\n })\n )}\n aria-label={decrementAriaLabel ?? 'Decrease value'}\n >\n <Minus className=\"h-3 w-3\" aria-hidden=\"true\" />\n </Button>\n </div>\n )}\n\n {/* Increment Button (right side for sides layout) */}\n {showSteppers && !isStackedLayout && (\n <Button\n slot=\"increment\"\n variant=\"ghost\"\n className=\"!min-h-0 !min-w-0\"\n buttonVisualClassName={cn(\n numberFieldStepperVariants({\n size,\n position: 'right',\n })\n )}\n aria-label={incrementAriaLabel ?? 'Increase value'}\n >\n <Plus className=\"h-4 w-4\" aria-hidden=\"true\" />\n </Button>\n )}\n </AriaGroup>\n\n {/* Description */}\n {description && (\n <AriaText\n slot=\"description\"\n className={cn(numberFieldDescriptionVariants({ size }))}\n >\n {description}\n </AriaText>\n )}\n\n {/* Error Message */}\n <AriaFieldError className={cn(numberFieldErrorVariants({ size }))}>\n {errorMessage}\n </AriaFieldError>\n </AriaNumberField>\n );\n }\n);\n\nNumberField.displayName = 'NumberField';\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OTPInput.d.ts","sourceRoot":"","sources":["../../../src/elements/OTPInput/OTPInput.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"OTPInput.d.ts","sourceRoot":"","sources":["../../../src/elements/OTPInput/OTPInput.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAkD,KAAK,UAAU,EAAsB,MAAM,OAAO,CAAC;AAE5G,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAUxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CAiLnB,CAAC"}
|