@fpkit/acss 0.5.12 → 0.6.0
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/README.md +89 -0
- package/libs/chunk-2NRIP6RB.cjs +17 -0
- package/libs/chunk-2NRIP6RB.cjs.map +1 -0
- package/libs/chunk-33PNJ4LO.cjs +15 -0
- package/libs/chunk-33PNJ4LO.cjs.map +1 -0
- package/libs/chunk-4BZKFPEC.cjs +17 -0
- package/libs/chunk-4BZKFPEC.cjs.map +1 -0
- package/libs/{chunk-O6QZBB6G.js → chunk-5QD3DWFI.js} +5 -5
- package/libs/chunk-5QD3DWFI.js.map +1 -0
- package/libs/chunk-6SAHIYCZ.js +7 -0
- package/libs/chunk-6SAHIYCZ.js.map +1 -0
- package/libs/{chunk-KKLTUJFB.cjs → chunk-6WTC4JXH.cjs} +5 -5
- package/libs/chunk-6WTC4JXH.cjs.map +1 -0
- package/libs/chunk-75QHTLFO.js +7 -0
- package/libs/chunk-75QHTLFO.js.map +1 -0
- package/libs/{chunk-YWOYVRFT.js → chunk-7XPFW7CB.js} +3 -3
- package/libs/chunk-BFK62VX5.js +5 -0
- package/libs/chunk-BFK62VX5.js.map +1 -0
- package/libs/{chunk-ICCKQ2GC.cjs → chunk-DKTHCQ5P.cjs} +4 -4
- package/libs/{chunk-6TE5QEVE.cjs → chunk-E2AJURUW.cjs} +3 -3
- package/libs/chunk-E2AJURUW.cjs.map +1 -0
- package/libs/chunk-ENTCUJ3A.cjs +13 -0
- package/libs/chunk-ENTCUJ3A.cjs.map +1 -0
- package/libs/chunk-F5EYMVQM.js +10 -0
- package/libs/chunk-F5EYMVQM.js.map +1 -0
- package/libs/chunk-FVROL3V5.js +9 -0
- package/libs/chunk-FVROL3V5.js.map +1 -0
- package/libs/chunk-GT77BX4L.cjs +17 -0
- package/libs/chunk-GT77BX4L.cjs.map +1 -0
- package/libs/chunk-GUJSMQ3V.cjs +16 -0
- package/libs/chunk-GUJSMQ3V.cjs.map +1 -0
- package/libs/chunk-HHLNOC5T.js +7 -0
- package/libs/chunk-HHLNOC5T.js.map +1 -0
- package/libs/chunk-HRRHPLER.js +8 -0
- package/libs/chunk-HRRHPLER.js.map +1 -0
- package/libs/chunk-IEB64SWY.js +8 -0
- package/libs/chunk-IEB64SWY.js.map +1 -0
- package/libs/{chunk-LIQJ7ZZR.js → chunk-IQ76HGVP.js} +2 -2
- package/libs/chunk-IRLFZ3OL.js +9 -0
- package/libs/chunk-IRLFZ3OL.js.map +1 -0
- package/libs/chunk-KK47SYZI.js +8 -0
- package/libs/chunk-KK47SYZI.js.map +1 -0
- package/libs/chunk-O3JIHC5M.cjs +15 -0
- package/libs/chunk-O3JIHC5M.cjs.map +1 -0
- package/libs/chunk-O5XAJ7BY.cjs +18 -0
- package/libs/chunk-O5XAJ7BY.cjs.map +1 -0
- package/libs/chunk-OVWLQYMK.js +10 -0
- package/libs/chunk-OVWLQYMK.js.map +1 -0
- package/libs/chunk-PNWIRCG3.cjs +7 -0
- package/libs/chunk-PNWIRCG3.cjs.map +1 -0
- package/libs/chunk-QVW6W76L.cjs +18 -0
- package/libs/chunk-QVW6W76L.cjs.map +1 -0
- package/libs/chunk-T4T6GWYQ.cjs +17 -0
- package/libs/chunk-T4T6GWYQ.cjs.map +1 -0
- package/libs/chunk-TON2YGMD.cjs +9 -0
- package/libs/chunk-TON2YGMD.cjs.map +1 -0
- package/libs/chunk-UEPAWMDF.js +8 -0
- package/libs/chunk-UEPAWMDF.js.map +1 -0
- package/libs/{chunk-LT5KZ2QW.cjs → chunk-US2I5GI7.cjs} +3 -3
- package/libs/{chunk-E3XP6BEX.cjs → chunk-W2UIN7EV.cjs} +3 -3
- package/libs/chunk-W5TKWBFC.cjs +18 -0
- package/libs/chunk-W5TKWBFC.cjs.map +1 -0
- package/libs/chunk-WXBFBWYF.cjs +16 -0
- package/libs/chunk-WXBFBWYF.cjs.map +1 -0
- package/libs/chunk-X3JCTEPD.js +11 -0
- package/libs/chunk-X3JCTEPD.js.map +1 -0
- package/libs/chunk-X5LGFCWG.js +9 -0
- package/libs/chunk-X5LGFCWG.js.map +1 -0
- package/libs/{chunk-5M57K4SW.js → chunk-Y2PFDELK.js} +2 -2
- package/libs/chunk-ZFJ4U45S.js +10 -0
- package/libs/chunk-ZFJ4U45S.js.map +1 -0
- package/libs/{component-props-a8a2f97e.d.ts → component-props-67d978a2.d.ts} +4 -4
- package/libs/components/alert/alert.css +1 -1
- package/libs/components/alert/alert.css.map +1 -1
- package/libs/components/alert/alert.min.css +2 -2
- package/libs/components/badge/badge.css +1 -1
- package/libs/components/badge/badge.css.map +1 -1
- package/libs/components/badge/badge.min.css +2 -2
- package/libs/components/breadcrumbs/breadcrumb.cjs +9 -5
- package/libs/components/breadcrumbs/breadcrumb.d.cts +275 -36
- package/libs/components/breadcrumbs/breadcrumb.d.ts +275 -36
- package/libs/components/breadcrumbs/breadcrumb.js +3 -3
- package/libs/components/button.cjs +6 -4
- package/libs/components/button.d.cts +97 -4
- package/libs/components/button.d.ts +97 -4
- package/libs/components/button.js +4 -2
- package/libs/components/buttons/button.css +1 -1
- package/libs/components/buttons/button.css.map +1 -1
- package/libs/components/buttons/button.min.css +2 -2
- package/libs/components/card.cjs +7 -7
- package/libs/components/card.d.cts +278 -34
- package/libs/components/card.d.ts +278 -34
- package/libs/components/card.js +2 -2
- package/libs/components/cards/card.css +1 -1
- package/libs/components/cards/card.css.map +1 -1
- package/libs/components/cards/card.min.css +2 -2
- package/libs/components/details/details.css +1 -1
- package/libs/components/details/details.css.map +1 -1
- package/libs/components/details/details.min.css +2 -2
- package/libs/components/dialog/dialog.cjs +9 -7
- package/libs/components/dialog/dialog.css +1 -1
- package/libs/components/dialog/dialog.css.map +1 -1
- package/libs/components/dialog/dialog.d.cts +88 -34
- package/libs/components/dialog/dialog.d.ts +88 -34
- package/libs/components/dialog/dialog.js +7 -5
- package/libs/components/dialog/dialog.min.css +2 -2
- package/libs/components/form/fields.cjs +4 -4
- package/libs/components/form/fields.d.cts +16 -7
- package/libs/components/form/fields.d.ts +16 -7
- package/libs/components/form/fields.js +2 -2
- package/libs/components/form/inputs.cjs +6 -4
- package/libs/components/form/inputs.d.cts +50 -2
- package/libs/components/form/inputs.d.ts +50 -2
- package/libs/components/form/inputs.js +4 -2
- package/libs/components/form/textarea.cjs +5 -4
- package/libs/components/form/textarea.d.cts +32 -23
- package/libs/components/form/textarea.d.ts +32 -23
- package/libs/components/form/textarea.js +3 -2
- package/libs/components/heading/heading.cjs +3 -3
- package/libs/components/heading/heading.d.cts +3 -14
- package/libs/components/heading/heading.d.ts +3 -14
- package/libs/components/heading/heading.js +2 -2
- package/libs/components/icons/icon.cjs +4 -4
- package/libs/components/icons/icon.d.cts +183 -39
- package/libs/components/icons/icon.d.ts +183 -39
- package/libs/components/icons/icon.js +2 -2
- package/libs/components/images/img.css +1 -1
- package/libs/components/images/img.css.map +1 -1
- package/libs/components/images/img.min.css +2 -2
- package/libs/components/link/link.cjs +4 -4
- package/libs/components/link/link.css +1 -1
- package/libs/components/link/link.css.map +1 -1
- package/libs/components/link/link.d.cts +3 -19
- package/libs/components/link/link.d.ts +3 -19
- package/libs/components/link/link.js +2 -2
- package/libs/components/link/link.min.css +2 -2
- package/libs/components/list/list.cjs +5 -5
- package/libs/components/list/list.css +1 -0
- package/libs/components/list/list.css.map +1 -0
- package/libs/components/list/list.d.cts +120 -33
- package/libs/components/list/list.d.ts +120 -33
- package/libs/components/list/list.js +2 -2
- package/libs/components/list/list.min.css +3 -0
- package/libs/components/modal.cjs +6 -4
- package/libs/components/modal.d.cts +8 -8
- package/libs/components/modal.d.ts +8 -8
- package/libs/components/modal.js +5 -3
- package/libs/components/nav/nav.cjs +7 -7
- package/libs/components/nav/nav.css +1 -1
- package/libs/components/nav/nav.css.map +1 -1
- package/libs/components/nav/nav.d.cts +550 -34
- package/libs/components/nav/nav.d.ts +550 -34
- package/libs/components/nav/nav.js +3 -3
- package/libs/components/nav/nav.min.css +2 -2
- package/libs/components/popover/popover.d.cts +5 -5
- package/libs/components/popover/popover.d.ts +5 -5
- package/libs/components/tables/table.cjs +5 -5
- package/libs/components/tables/table.d.cts +8 -8
- package/libs/components/tables/table.d.ts +8 -8
- package/libs/components/tables/table.js +2 -2
- package/libs/components/tag/tag.css +1 -1
- package/libs/components/tag/tag.css.map +1 -1
- package/libs/components/tag/tag.min.css +2 -2
- package/libs/components/text/text.cjs +5 -5
- package/libs/components/text/text.d.cts +5 -5
- package/libs/components/text/text.d.ts +5 -5
- package/libs/components/text/text.js +2 -2
- package/libs/form.types-d25ebfac.d.ts +233 -0
- package/libs/heading-7446cb46.d.ts +250 -0
- package/libs/hooks.cjs +12 -0
- package/libs/hooks.d.cts +140 -1
- package/libs/hooks.d.ts +140 -1
- package/libs/hooks.js +4 -0
- package/libs/icons.cjs +3 -3
- package/libs/icons.d.cts +2 -2
- package/libs/icons.d.ts +2 -2
- package/libs/icons.js +2 -2
- package/libs/index.cjs +117 -94
- package/libs/index.cjs.map +1 -1
- package/libs/index.css +1 -1
- package/libs/index.css.map +1 -1
- package/libs/index.d.cts +834 -61
- package/libs/index.d.ts +834 -61
- package/libs/index.js +36 -22
- package/libs/index.js.map +1 -1
- package/libs/link-5192f411.d.ts +323 -0
- package/libs/list.types-d26de310.d.ts +245 -0
- package/libs/ui-d01b50d4.d.ts +289 -0
- package/package.json +4 -87
- package/src/components/README-UI.mdx +416 -0
- package/src/components/alert/ACCESSIBILITY.md +319 -0
- package/src/components/alert/README.mdx +475 -19
- package/src/components/alert/alert.scss +110 -6
- package/src/components/alert/alert.stories.tsx +372 -0
- package/src/components/alert/alert.test.tsx +762 -0
- package/src/components/alert/alert.tsx +331 -66
- package/src/components/alert/views/alert-actions.tsx +13 -0
- package/src/components/alert/views/alert-content.tsx +17 -0
- package/src/components/alert/views/alert-icon.tsx +53 -0
- package/src/components/alert/views/alert-screen-reader-text.tsx +30 -0
- package/src/components/alert/views/alert-title.tsx +23 -0
- package/src/components/alert/views/alert-view.tsx +158 -0
- package/src/components/alert/views/index.ts +12 -0
- package/src/components/badge/badge.mdx +186 -49
- package/src/components/badge/badge.scss +20 -2
- package/src/components/badge/badge.stories.tsx +160 -14
- package/src/components/badge/badge.test.tsx +179 -0
- package/src/components/badge/badge.tsx +97 -4
- package/src/components/breadcrumbs/README.mdx +364 -45
- package/src/components/breadcrumbs/__snapshots__/breadcrumb.test.tsx.snap +152 -0
- package/src/components/breadcrumbs/breadcrumb.stories.tsx +7 -3
- package/src/components/breadcrumbs/breadcrumb.test.tsx +490 -0
- package/src/components/breadcrumbs/breadcrumb.tsx +430 -170
- package/src/components/buttons/README.mdx +102 -1
- package/src/components/buttons/button.scss +34 -31
- package/src/components/buttons/button.stories.tsx +141 -0
- package/src/components/buttons/button.tsx +82 -52
- package/src/components/cards/README.mdx +657 -0
- package/src/components/cards/card.scss +22 -0
- package/src/components/cards/card.stories.tsx +167 -5
- package/src/components/cards/card.test.tsx +360 -20
- package/src/components/cards/card.tsx +200 -79
- package/src/components/cards/card.types.ts +135 -0
- package/src/components/cards/card.utils.ts +79 -0
- package/src/components/details/ACCESSIBILITY-REVIEW-LIVE.md +1050 -0
- package/src/components/details/ACCESSIBILITY-REVIEW.md +502 -0
- package/src/components/details/README.mdx +437 -69
- package/src/components/details/details.scss +16 -7
- package/src/components/details/details.test.tsx +385 -0
- package/src/components/details/details.tsx +101 -69
- package/src/components/details/details.types.ts +76 -0
- package/src/components/dialog/README.mdx +513 -110
- package/src/components/dialog/dialog-a11y-review.md +653 -0
- package/src/components/dialog/dialog-modal.tsx +79 -56
- package/src/components/dialog/dialog.scss +53 -3
- package/src/components/dialog/dialog.stories.tsx +10 -7
- package/src/components/dialog/dialog.test.tsx +450 -0
- package/src/components/dialog/dialog.tsx +69 -59
- package/src/components/dialog/dialog.types.ts +133 -0
- package/src/components/dialog/views/dialog-footer.tsx +54 -11
- package/src/components/dialog/views/dialog-header.tsx +20 -15
- package/src/components/form/README.mdx +725 -43
- package/src/components/form/WCAG-REVIEW.md +654 -0
- package/src/components/form/fields.tsx +10 -1
- package/src/components/form/form.stories.tsx +604 -23
- package/src/components/form/form.tsx +204 -63
- package/src/components/form/form.types.ts +378 -0
- package/src/components/form/input.stories.tsx +71 -3
- package/src/components/form/inputs.tsx +159 -67
- package/src/components/form/select.tsx +122 -66
- package/src/components/form/textarea.tsx +120 -73
- package/src/components/fp.tsx +86 -11
- package/src/components/heading/heading.stories.tsx +44 -4
- package/src/components/heading/heading.tsx +89 -23
- package/src/components/icons/README.mdx +332 -0
- package/src/components/icons/icon.stories.tsx +74 -1
- package/src/components/icons/icon.tsx +89 -1
- package/src/components/icons/types.ts +47 -0
- package/src/components/images/README.mdx +340 -24
- package/src/components/images/img.scss +19 -3
- package/src/components/images/img.stories.tsx +424 -15
- package/src/components/images/img.test.tsx +354 -25
- package/src/components/images/img.tsx +186 -63
- package/src/components/images/img.types.ts +211 -0
- package/src/components/link/README.mdx +923 -0
- package/src/components/link/link.scss +79 -26
- package/src/components/link/link.stories.tsx +383 -30
- package/src/components/link/link.test.tsx +677 -0
- package/src/components/link/link.tsx +163 -57
- package/src/components/link/link.types.ts +261 -0
- package/src/components/list/README.mdx +764 -0
- package/src/components/list/list.scss +285 -0
- package/src/components/list/list.stories.tsx +514 -27
- package/src/components/list/list.test.tsx +554 -0
- package/src/components/list/list.tsx +153 -51
- package/src/components/list/list.types.ts +255 -0
- package/src/components/nav/ACCESSIBILITY.md +649 -0
- package/src/components/nav/README.mdx +782 -0
- package/src/components/nav/nav.scss +32 -1
- package/src/components/nav/nav.stories.tsx +44 -6
- package/src/components/nav/nav.tsx +302 -51
- package/src/components/nav/nav.types.ts +308 -0
- package/src/components/tag/README.mdx +426 -0
- package/src/components/tag/tag.scss +101 -27
- package/src/components/tag/tag.stories.tsx +384 -10
- package/src/components/tag/tag.test.tsx +210 -0
- package/src/components/tag/tag.tsx +106 -9
- package/src/components/tag/tag.types.ts +107 -0
- package/src/components/title/MIGRATION.md +199 -0
- package/src/components/title/README.md +326 -0
- package/src/components/title/README.mdx +452 -0
- package/src/components/title/title.stories.tsx +393 -0
- package/src/components/title/title.test.tsx +251 -0
- package/src/components/title/title.tsx +219 -0
- package/src/components/ui.stories.tsx +894 -0
- package/src/components/ui.test.tsx +559 -0
- package/src/components/ui.tsx +274 -18
- package/src/components/word-count/README.md +240 -0
- package/src/hooks/use-disabled-state.test.tsx +536 -0
- package/src/hooks/use-disabled-state.ts +246 -0
- package/src/hooks/useDisabledState.md +393 -0
- package/src/hooks.ts +7 -0
- package/src/index.scss +2 -0
- package/src/index.ts +12 -3
- package/src/sass/_globals.scss +2 -7
- package/src/sass/_properties.scss +1 -0
- package/src/styles/alert/alert.css +92 -4
- package/src/styles/alert/alert.css.map +1 -1
- package/src/styles/badge/badge.css +20 -2
- package/src/styles/badge/badge.css.map +1 -1
- package/src/styles/buttons/button.css +31 -31
- package/src/styles/buttons/button.css.map +1 -1
- package/src/styles/cards/card.css +16 -0
- package/src/styles/cards/card.css.map +1 -1
- package/src/styles/details/details.css +19 -8
- package/src/styles/details/details.css.map +1 -1
- package/src/styles/dialog/dialog.css +43 -2
- package/src/styles/dialog/dialog.css.map +1 -1
- package/src/styles/images/img.css +15 -3
- package/src/styles/images/img.css.map +1 -1
- package/src/styles/index.css +691 -128
- package/src/styles/index.css.map +1 -1
- package/src/styles/link/link.css +45 -28
- package/src/styles/link/link.css.map +1 -1
- package/src/styles/list/list.css +214 -0
- package/src/styles/list/list.css.map +1 -0
- package/src/styles/nav/nav.css +21 -1
- package/src/styles/nav/nav.css.map +1 -1
- package/src/styles/tag/tag.css +113 -35
- package/src/styles/tag/tag.css.map +1 -1
- package/src/styles/utilities/_disabled.scss +58 -0
- package/src/test/setup.d.ts +9 -0
- package/src/test/setup.ts +53 -1
- package/src/types/shared.ts +43 -6
- package/src/utils/accessibility.ts +109 -0
- package/libs/chunk-5ZM4XL44.js +0 -8
- package/libs/chunk-5ZM4XL44.js.map +0 -1
- package/libs/chunk-6BVXFW7U.cjs +0 -15
- package/libs/chunk-6BVXFW7U.cjs.map +0 -1
- package/libs/chunk-6TE5QEVE.cjs.map +0 -1
- package/libs/chunk-7K76RW2A.cjs +0 -18
- package/libs/chunk-7K76RW2A.cjs.map +0 -1
- package/libs/chunk-BHRQBJRY.js +0 -8
- package/libs/chunk-BHRQBJRY.js.map +0 -1
- package/libs/chunk-BIP2NY53.js +0 -8
- package/libs/chunk-BIP2NY53.js.map +0 -1
- package/libs/chunk-BSPKFLO4.js +0 -8
- package/libs/chunk-BSPKFLO4.js.map +0 -1
- package/libs/chunk-BV5CLH44.cjs +0 -18
- package/libs/chunk-BV5CLH44.cjs.map +0 -1
- package/libs/chunk-DKGJHKGW.js +0 -9
- package/libs/chunk-DKGJHKGW.js.map +0 -1
- package/libs/chunk-DV56L5YX.cjs +0 -18
- package/libs/chunk-DV56L5YX.cjs.map +0 -1
- package/libs/chunk-ECLD37WN.cjs +0 -16
- package/libs/chunk-ECLD37WN.cjs.map +0 -1
- package/libs/chunk-EQ67LF46.js +0 -9
- package/libs/chunk-EQ67LF46.js.map +0 -1
- package/libs/chunk-HYBZBN4G.js +0 -8
- package/libs/chunk-HYBZBN4G.js.map +0 -1
- package/libs/chunk-IYUN2EW3.cjs +0 -15
- package/libs/chunk-IYUN2EW3.cjs.map +0 -1
- package/libs/chunk-KKLTUJFB.cjs.map +0 -1
- package/libs/chunk-LHVJKDMA.cjs +0 -15
- package/libs/chunk-LHVJKDMA.cjs.map +0 -1
- package/libs/chunk-LL7HTLMS.cjs +0 -15
- package/libs/chunk-LL7HTLMS.cjs.map +0 -1
- package/libs/chunk-M5QL5TAE.cjs +0 -14
- package/libs/chunk-M5QL5TAE.cjs.map +0 -1
- package/libs/chunk-NE6YXTMC.js +0 -7
- package/libs/chunk-NE6YXTMC.js.map +0 -1
- package/libs/chunk-NHYXGV3L.js +0 -8
- package/libs/chunk-NHYXGV3L.js.map +0 -1
- package/libs/chunk-O6QZBB6G.js.map +0 -1
- package/libs/chunk-P7TTEYCD.js +0 -7
- package/libs/chunk-P7TTEYCD.js.map +0 -1
- package/libs/chunk-PPOOBUOS.js +0 -8
- package/libs/chunk-PPOOBUOS.js.map +0 -1
- package/libs/chunk-QCMV4VQZ.js +0 -8
- package/libs/chunk-QCMV4VQZ.js.map +0 -1
- package/libs/chunk-QVV34QEH.cjs +0 -32
- package/libs/chunk-QVV34QEH.cjs.map +0 -1
- package/libs/chunk-S7BABR7Z.cjs +0 -13
- package/libs/chunk-S7BABR7Z.cjs.map +0 -1
- package/libs/chunk-SXVZSWX6.js +0 -11
- package/libs/chunk-SXVZSWX6.js.map +0 -1
- package/libs/chunk-X3EVB7VS.cjs +0 -15
- package/libs/chunk-X3EVB7VS.cjs.map +0 -1
- package/libs/inputs-f3a216db.d.ts +0 -45
- package/libs/ui-9a6f9f8d.d.ts +0 -24
- package/src/components/cards/README.md +0 -80
- package/src/components/dialog/hooks/useClickOutside.ts +0 -33
- /package/libs/{chunk-YWOYVRFT.js.map → chunk-7XPFW7CB.js.map} +0 -0
- /package/libs/{chunk-ICCKQ2GC.cjs.map → chunk-DKTHCQ5P.cjs.map} +0 -0
- /package/libs/{chunk-LIQJ7ZZR.js.map → chunk-IQ76HGVP.js.map} +0 -0
- /package/libs/{chunk-LT5KZ2QW.cjs.map → chunk-US2I5GI7.cjs.map} +0 -0
- /package/libs/{chunk-E3XP6BEX.cjs.map → chunk-W2UIN7EV.cjs.map} +0 -0
- /package/libs/{chunk-5M57K4SW.js.map → chunk-Y2PFDELK.js.map} +0 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import Details from "./details";
|
|
5
|
+
import React from "react";
|
|
6
|
+
|
|
7
|
+
describe("Details Component", () => {
|
|
8
|
+
describe("Rendering", () => {
|
|
9
|
+
it("should render with summary and children", () => {
|
|
10
|
+
render(
|
|
11
|
+
<Details summary="Test Summary">
|
|
12
|
+
<p>Test Content</p>
|
|
13
|
+
</Details>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
expect(screen.getByText("Test Summary")).toBeInTheDocument();
|
|
17
|
+
expect(screen.getByText("Test Content")).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("should render with icon", () => {
|
|
21
|
+
const TestIcon = () => <svg data-testid="test-icon" />;
|
|
22
|
+
render(
|
|
23
|
+
<Details summary="Test Summary" icon={<TestIcon />}>
|
|
24
|
+
<p>Content</p>
|
|
25
|
+
</Details>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
expect(screen.getByTestId("test-icon")).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should apply custom classes", () => {
|
|
32
|
+
render(
|
|
33
|
+
<Details summary="Test" classes="custom-class">
|
|
34
|
+
<p>Content</p>
|
|
35
|
+
</Details>
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
39
|
+
expect(detailsElement).toHaveClass("custom-class");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should apply custom styles", () => {
|
|
43
|
+
render(
|
|
44
|
+
<Details summary="Test" styles={{ backgroundColor: "red" }}>
|
|
45
|
+
<p>Content</p>
|
|
46
|
+
</Details>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
50
|
+
// Check that style attribute contains the property
|
|
51
|
+
const styleAttr = detailsElement?.getAttribute("style") || "";
|
|
52
|
+
expect(styleAttr).toContain("background-color");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should render with aria-label when provided", () => {
|
|
56
|
+
render(
|
|
57
|
+
<Details summary="Test" ariaLabel="Custom label">
|
|
58
|
+
<p>Content</p>
|
|
59
|
+
</Details>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
63
|
+
expect(detailsElement).toHaveAttribute("aria-label", "Custom label");
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("Open/Close State", () => {
|
|
68
|
+
it("should be closed by default", () => {
|
|
69
|
+
render(
|
|
70
|
+
<Details summary="Test">
|
|
71
|
+
<p>Content</p>
|
|
72
|
+
</Details>
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
76
|
+
expect(detailsElement).not.toHaveAttribute("open");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should be open when open prop is true", () => {
|
|
80
|
+
render(
|
|
81
|
+
<Details summary="Test" open>
|
|
82
|
+
<p>Content</p>
|
|
83
|
+
</Details>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
87
|
+
expect(detailsElement).toHaveAttribute("open");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should toggle open state on summary click", async () => {
|
|
91
|
+
const user = userEvent.setup();
|
|
92
|
+
render(
|
|
93
|
+
<Details summary="Test">
|
|
94
|
+
<p>Content</p>
|
|
95
|
+
</Details>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const summaryElement = screen.getByText("Test");
|
|
99
|
+
const detailsElement = summaryElement.closest("details")!;
|
|
100
|
+
|
|
101
|
+
// Initially closed
|
|
102
|
+
expect(detailsElement).not.toHaveAttribute("open");
|
|
103
|
+
|
|
104
|
+
// Click to open
|
|
105
|
+
await user.click(summaryElement);
|
|
106
|
+
expect(detailsElement).toHaveAttribute("open");
|
|
107
|
+
|
|
108
|
+
// Click to close
|
|
109
|
+
await user.click(summaryElement);
|
|
110
|
+
expect(detailsElement).not.toHaveAttribute("open");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe("Keyboard Interaction", () => {
|
|
115
|
+
it("should be keyboard accessible with focusable summary", () => {
|
|
116
|
+
render(
|
|
117
|
+
<Details summary="Test">
|
|
118
|
+
<p>Content</p>
|
|
119
|
+
</Details>
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const summaryElement = screen.getByText("Test");
|
|
123
|
+
summaryElement.focus();
|
|
124
|
+
|
|
125
|
+
// Summary element should be focusable for keyboard navigation
|
|
126
|
+
expect(summaryElement).toHaveFocus();
|
|
127
|
+
expect(summaryElement.tagName).toBe("SUMMARY");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("should support keyboard interaction through native browser behavior", () => {
|
|
131
|
+
// Note: Keyboard interaction (Space, Enter) on <summary> is handled
|
|
132
|
+
// natively by the browser and is part of the HTML5 spec.
|
|
133
|
+
// These interactions are tested in Storybook interaction tests
|
|
134
|
+
// where the browser's native behavior is fully available.
|
|
135
|
+
render(
|
|
136
|
+
<Details summary="Test">
|
|
137
|
+
<p>Content</p>
|
|
138
|
+
</Details>
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const summaryElement = screen.getByText("Test");
|
|
142
|
+
const detailsElement = summaryElement.closest("details");
|
|
143
|
+
|
|
144
|
+
// Verify semantic HTML structure that enables keyboard support
|
|
145
|
+
expect(summaryElement.tagName).toBe("SUMMARY");
|
|
146
|
+
expect(detailsElement?.tagName).toBe("DETAILS");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should call onToggle callback when interaction occurs", async () => {
|
|
150
|
+
const user = userEvent.setup();
|
|
151
|
+
const handleToggle = vi.fn();
|
|
152
|
+
|
|
153
|
+
render(
|
|
154
|
+
<Details summary="Test" onToggle={handleToggle}>
|
|
155
|
+
<p>Content</p>
|
|
156
|
+
</Details>
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const summaryElement = screen.getByText("Test");
|
|
160
|
+
|
|
161
|
+
// Click interaction
|
|
162
|
+
await user.click(summaryElement);
|
|
163
|
+
|
|
164
|
+
// Callback should be invoked
|
|
165
|
+
expect(handleToggle).toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("Event Handlers", () => {
|
|
170
|
+
it("should call onToggle when toggled", async () => {
|
|
171
|
+
const user = userEvent.setup();
|
|
172
|
+
const handleToggle = vi.fn();
|
|
173
|
+
|
|
174
|
+
render(
|
|
175
|
+
<Details summary="Test" onToggle={handleToggle}>
|
|
176
|
+
<p>Content</p>
|
|
177
|
+
</Details>
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const summaryElement = screen.getByText("Test");
|
|
181
|
+
await user.click(summaryElement);
|
|
182
|
+
|
|
183
|
+
expect(handleToggle).toHaveBeenCalledTimes(1);
|
|
184
|
+
expect(handleToggle).toHaveBeenCalledWith(
|
|
185
|
+
expect.objectContaining({
|
|
186
|
+
type: "toggle",
|
|
187
|
+
})
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should call onPointerDown on summary pointer down", async () => {
|
|
192
|
+
const user = userEvent.setup();
|
|
193
|
+
const handlePointerDown = vi.fn();
|
|
194
|
+
|
|
195
|
+
render(
|
|
196
|
+
<Details summary="Test" onPointerDown={handlePointerDown}>
|
|
197
|
+
<p>Content</p>
|
|
198
|
+
</Details>
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const summaryElement = screen.getByText("Test");
|
|
202
|
+
await user.pointer({ target: summaryElement, keys: "[MouseLeft>]" });
|
|
203
|
+
|
|
204
|
+
expect(handlePointerDown).toHaveBeenCalled();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should not call onToggle multiple times incorrectly", async () => {
|
|
208
|
+
const user = userEvent.setup();
|
|
209
|
+
const handleToggle = vi.fn();
|
|
210
|
+
|
|
211
|
+
render(
|
|
212
|
+
<Details summary="Test" onToggle={handleToggle}>
|
|
213
|
+
<p>Content</p>
|
|
214
|
+
</Details>
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const summaryElement = screen.getByText("Test");
|
|
218
|
+
await user.click(summaryElement);
|
|
219
|
+
|
|
220
|
+
// Should only be called once per toggle
|
|
221
|
+
expect(handleToggle).toHaveBeenCalledTimes(1);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe("Accordion Behavior", () => {
|
|
226
|
+
it("should support name attribute for accordion groups", () => {
|
|
227
|
+
render(
|
|
228
|
+
<>
|
|
229
|
+
<Details summary="First" name="accordion-group">
|
|
230
|
+
<p>Content 1</p>
|
|
231
|
+
</Details>
|
|
232
|
+
<Details summary="Second" name="accordion-group">
|
|
233
|
+
<p>Content 2</p>
|
|
234
|
+
</Details>
|
|
235
|
+
</>
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const firstDetails = screen.getByText("First").closest("details");
|
|
239
|
+
const secondDetails = screen.getByText("Second").closest("details");
|
|
240
|
+
|
|
241
|
+
expect(firstDetails).toHaveAttribute("name", "accordion-group");
|
|
242
|
+
expect(secondDetails).toHaveAttribute("name", "accordion-group");
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should configure accordion group with name attribute", () => {
|
|
246
|
+
// Note: The exclusive open/close behavior of accordion groups
|
|
247
|
+
// is handled natively by browsers and tested in Storybook.
|
|
248
|
+
// Here we verify the name attribute is correctly applied.
|
|
249
|
+
render(
|
|
250
|
+
<>
|
|
251
|
+
<Details summary="First" name="test-accordion">
|
|
252
|
+
<p>Content 1</p>
|
|
253
|
+
</Details>
|
|
254
|
+
<Details summary="Second" name="test-accordion">
|
|
255
|
+
<p>Content 2</p>
|
|
256
|
+
</Details>
|
|
257
|
+
</>
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const firstDetails = screen.getByText("First").closest("details");
|
|
261
|
+
const secondDetails = screen.getByText("Second").closest("details");
|
|
262
|
+
|
|
263
|
+
// Both should have the same name for accordion grouping
|
|
264
|
+
expect(firstDetails).toHaveAttribute("name", "test-accordion");
|
|
265
|
+
expect(secondDetails).toHaveAttribute("name", "test-accordion");
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("Accessibility", () => {
|
|
270
|
+
it("should use semantic details element", () => {
|
|
271
|
+
render(
|
|
272
|
+
<Details summary="Test">
|
|
273
|
+
<p>Content</p>
|
|
274
|
+
</Details>
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
278
|
+
expect(detailsElement?.tagName).toBe("DETAILS");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("should use semantic summary element", () => {
|
|
282
|
+
render(
|
|
283
|
+
<Details summary="Test">
|
|
284
|
+
<p>Content</p>
|
|
285
|
+
</Details>
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
const summaryElement = screen.getByText("Test");
|
|
289
|
+
expect(summaryElement.tagName).toBe("SUMMARY");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("should wrap content in section element", () => {
|
|
293
|
+
render(
|
|
294
|
+
<Details summary="Test">
|
|
295
|
+
<p data-testid="content">Content</p>
|
|
296
|
+
</Details>
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const contentElement = screen.getByTestId("content");
|
|
300
|
+
const sectionElement = contentElement.closest("section");
|
|
301
|
+
expect(sectionElement).toBeInTheDocument();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it("should support ref forwarding", () => {
|
|
305
|
+
const ref = React.createRef<HTMLDetailsElement>();
|
|
306
|
+
render(
|
|
307
|
+
<Details summary="Test" ref={ref}>
|
|
308
|
+
<p>Content</p>
|
|
309
|
+
</Details>
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
expect(ref.current).toBeInstanceOf(HTMLDetailsElement);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe("Complex Content", () => {
|
|
317
|
+
it("should render React nodes as summary", () => {
|
|
318
|
+
render(
|
|
319
|
+
<Details
|
|
320
|
+
summary={
|
|
321
|
+
<>
|
|
322
|
+
<span>Icon</span>
|
|
323
|
+
<span>Text</span>
|
|
324
|
+
</>
|
|
325
|
+
}
|
|
326
|
+
>
|
|
327
|
+
<p>Content</p>
|
|
328
|
+
</Details>
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
expect(screen.getByText("Icon")).toBeInTheDocument();
|
|
332
|
+
expect(screen.getByText("Text")).toBeInTheDocument();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("should render complex children", () => {
|
|
336
|
+
render(
|
|
337
|
+
<Details summary="Test">
|
|
338
|
+
<div>
|
|
339
|
+
<h3>Heading</h3>
|
|
340
|
+
<p>Paragraph</p>
|
|
341
|
+
<ul>
|
|
342
|
+
<li>Item 1</li>
|
|
343
|
+
<li>Item 2</li>
|
|
344
|
+
</ul>
|
|
345
|
+
</div>
|
|
346
|
+
</Details>
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
expect(screen.getByText("Heading")).toBeInTheDocument();
|
|
350
|
+
expect(screen.getByText("Paragraph")).toBeInTheDocument();
|
|
351
|
+
expect(screen.getByText("Item 1")).toBeInTheDocument();
|
|
352
|
+
expect(screen.getByText("Item 2")).toBeInTheDocument();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe("Edge Cases", () => {
|
|
357
|
+
it("should handle undefined optional props", () => {
|
|
358
|
+
render(
|
|
359
|
+
<Details summary="Test">
|
|
360
|
+
<p>Content</p>
|
|
361
|
+
</Details>
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
const detailsElement = screen.getByText("Test").closest("details");
|
|
365
|
+
expect(detailsElement).toBeInTheDocument();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("should handle empty children", () => {
|
|
369
|
+
render(<Details summary="Test">{null}</Details>);
|
|
370
|
+
|
|
371
|
+
expect(screen.getByText("Test")).toBeInTheDocument();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("should pass through additional HTML attributes", () => {
|
|
375
|
+
render(
|
|
376
|
+
<Details summary="Test" data-testid="custom-details" id="details-id">
|
|
377
|
+
<p>Content</p>
|
|
378
|
+
</Details>
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
const detailsElement = screen.getByTestId("custom-details");
|
|
382
|
+
expect(detailsElement).toHaveAttribute("id", "details-id");
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
});
|
|
@@ -1,78 +1,110 @@
|
|
|
1
1
|
import UI from "#components/ui";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useCallback } from "react";
|
|
3
|
+
import type { DetailsProps } from "./details.types";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*
|
|
5
|
+
/**
|
|
6
|
+
* Details - A progressive disclosure component using native HTML `<details>` element.
|
|
7
|
+
*
|
|
8
|
+
* This component wraps the native `<details>` and `<summary>` elements to provide
|
|
9
|
+
* an accessible, semantic way to show and hide content. It supports accordion behavior
|
|
10
|
+
* through the `name` attribute and includes proper keyboard navigation out of the box.
|
|
11
|
+
*
|
|
12
|
+
* ## Key Features:
|
|
13
|
+
* - **Semantic HTML**: Uses native `<details>` for built-in accessibility
|
|
14
|
+
* - **Keyboard Support**: Space/Enter to toggle, fully accessible by default
|
|
15
|
+
* - **Accordion Mode**: Group multiple details with `name` for exclusive expansion
|
|
16
|
+
* - **Customizable**: Supports icons, custom styles, and event handlers
|
|
17
|
+
*
|
|
18
|
+
* ## Accessibility:
|
|
19
|
+
* - ✅ WCAG 2.1 AA compliant using semantic HTML
|
|
20
|
+
* - ✅ Native keyboard support (Space, Enter)
|
|
21
|
+
* - ✅ Screen reader compatible (announced as "disclosure" or "expandable")
|
|
22
|
+
* - ✅ Focus indicators automatically applied via CSS
|
|
23
|
+
* - ✅ `aria-expanded` managed automatically by browser
|
|
20
24
|
*
|
|
21
|
-
* @
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* @
|
|
25
|
+
* @example
|
|
26
|
+
* ```tsx
|
|
27
|
+
* // Basic usage
|
|
28
|
+
* <Details summary="Click to expand">
|
|
29
|
+
* <p>Hidden content here</p>
|
|
30
|
+
* </Details>
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* // With icon and custom styling
|
|
36
|
+
* <Details
|
|
37
|
+
* summary="Shipping Information"
|
|
38
|
+
* icon={<ChevronDownIcon />}
|
|
39
|
+
* classes="custom-details"
|
|
40
|
+
* onToggle={(e) => console.log('Open:', e.currentTarget.open)}
|
|
41
|
+
* >
|
|
42
|
+
* <p>Ships within 2-3 business days</p>
|
|
43
|
+
* </Details>
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* // Accordion mode - only one open at a time
|
|
49
|
+
* <Details name="faq" summary="Question 1">Answer 1</Details>
|
|
50
|
+
* <Details name="faq" summary="Question 2">Answer 2</Details>
|
|
51
|
+
* <Details name="faq" summary="Question 3">Answer 3</Details>
|
|
52
|
+
* ```
|
|
30
53
|
*/
|
|
31
|
-
export const Details = (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
export const Details = React.forwardRef<HTMLDetailsElement, DetailsProps>(
|
|
55
|
+
(
|
|
56
|
+
{
|
|
57
|
+
summary,
|
|
58
|
+
icon,
|
|
59
|
+
styles,
|
|
60
|
+
classes,
|
|
61
|
+
ariaLabel,
|
|
62
|
+
name,
|
|
63
|
+
open,
|
|
64
|
+
onPointerDown,
|
|
65
|
+
onToggle,
|
|
66
|
+
children,
|
|
67
|
+
...props
|
|
68
|
+
},
|
|
69
|
+
ref
|
|
70
|
+
) => {
|
|
71
|
+
// Memoize callbacks to prevent unnecessary re-renders of child components
|
|
72
|
+
const handlePointerDown = useCallback(
|
|
73
|
+
(e: React.PointerEvent<HTMLElement>) => {
|
|
74
|
+
onPointerDown?.(e as React.PointerEvent<HTMLDetailsElement>);
|
|
75
|
+
},
|
|
76
|
+
[onPointerDown]
|
|
77
|
+
);
|
|
46
78
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
79
|
+
const handleToggle = useCallback(
|
|
80
|
+
(e: React.SyntheticEvent<HTMLDetailsElement>) => {
|
|
81
|
+
onToggle?.(e);
|
|
82
|
+
},
|
|
83
|
+
[onToggle]
|
|
84
|
+
);
|
|
51
85
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{icon}
|
|
70
|
-
{summary}
|
|
86
|
+
return (
|
|
87
|
+
<UI
|
|
88
|
+
as="details"
|
|
89
|
+
styles={styles}
|
|
90
|
+
classes={classes}
|
|
91
|
+
onToggle={handleToggle}
|
|
92
|
+
ref={ref}
|
|
93
|
+
open={open}
|
|
94
|
+
aria-label={ariaLabel}
|
|
95
|
+
name={name}
|
|
96
|
+
{...props}
|
|
97
|
+
>
|
|
98
|
+
<UI as="summary" onPointerDown={handlePointerDown}>
|
|
99
|
+
{icon}
|
|
100
|
+
{summary}
|
|
101
|
+
</UI>
|
|
102
|
+
<UI as="section">{children}</UI>
|
|
71
103
|
</UI>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
);
|
|
76
107
|
|
|
77
|
-
export default Details;
|
|
78
108
|
Details.displayName = "Details";
|
|
109
|
+
|
|
110
|
+
export default Details;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import UI from "#components/ui";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props for the Details component.
|
|
6
|
+
*
|
|
7
|
+
* Combines native HTML details element props with custom styling and interaction handlers.
|
|
8
|
+
* The Details component uses the native `<details>` element for progressive disclosure,
|
|
9
|
+
* providing built-in keyboard support and semantic HTML.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Details
|
|
14
|
+
* summary="Click to expand"
|
|
15
|
+
* icon={<ChevronIcon />}
|
|
16
|
+
* onToggle={(e) => console.log('Toggled:', e.currentTarget.open)}
|
|
17
|
+
* >
|
|
18
|
+
* <p>Hidden content revealed when opened</p>
|
|
19
|
+
* </Details>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export type DetailsProps = {
|
|
23
|
+
/**
|
|
24
|
+
* The summary text or element shown in the clickable header.
|
|
25
|
+
* This is always visible and acts as the toggle control.
|
|
26
|
+
*
|
|
27
|
+
* @required
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* summary="Shipping Information"
|
|
31
|
+
* // or
|
|
32
|
+
* summary={<><Icon /> Shipping Information</>}
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
summary: React.ReactNode;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Optional icon displayed before the summary text.
|
|
39
|
+
* Commonly used for chevron/arrow indicators.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* icon={<ChevronDownIcon />}
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
icon?: React.ReactNode;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Accessible label for screen readers.
|
|
50
|
+
* If not provided, the native `<details>` semantic will be used.
|
|
51
|
+
*
|
|
52
|
+
* Note: Native `<details>` elements are already semantic and announced properly
|
|
53
|
+
* by screen readers. Only provide this if you need to override the default behavior.
|
|
54
|
+
*
|
|
55
|
+
* @optional
|
|
56
|
+
* @example
|
|
57
|
+
* ```tsx
|
|
58
|
+
* ariaLabel="Product details section"
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
ariaLabel?: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Groups multiple details elements into an accordion where only one can be open.
|
|
65
|
+
* Multiple details elements with the same `name` will behave as a mutually exclusive group.
|
|
66
|
+
*
|
|
67
|
+
* @optional
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* <Details name="faq-accordion" summary="Question 1">...</Details>
|
|
71
|
+
* <Details name="faq-accordion" summary="Question 2">...</Details>
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
name?: string;
|
|
75
|
+
} & React.ComponentProps<"details"> &
|
|
76
|
+
Partial<React.ComponentProps<typeof UI>>;
|