@kouji-ui/core 0.0.3 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +6 -3
- package/CHANGELOG.md +177 -0
- package/ng-package.json +5 -1
- package/package.json +18 -6
- package/src/a11y/aria-describedby.ts +7 -3
- package/src/a11y/aria-labelledby.spec.ts +55 -0
- package/src/a11y/aria-labelledby.ts +38 -0
- package/src/a11y/focus-trap.ts +4 -2
- package/src/a11y/index.ts +1 -0
- package/src/a11y/live-region.ts +4 -2
- package/src/a11y/roving-tabindex.spec.ts +139 -0
- package/src/a11y/roving-tabindex.ts +56 -7
- package/src/a11y/visually-hidden.ts +4 -2
- package/src/accordion/accordion.context.ts +22 -0
- package/src/accordion/accordion.spec.ts +233 -23
- package/src/accordion/accordion.ts +311 -39
- package/src/accordion/index.ts +8 -2
- package/src/alert/alert.context.ts +28 -0
- package/src/alert/alert.spec.ts +217 -0
- package/src/alert/alert.ts +417 -0
- package/src/alert/config.ts +46 -0
- package/src/alert/index.ts +19 -0
- package/src/avatar/avatar-group.context.ts +45 -0
- package/src/avatar/avatar-group.spec.ts +358 -0
- package/src/avatar/avatar-group.ts +259 -0
- package/src/avatar/avatar.ts +17 -4
- package/src/avatar/index.ts +11 -1
- package/src/badge/badge.spec.ts +8 -0
- package/src/badge/badge.ts +24 -3
- package/src/breadcrumb/breadcrumb-current.ts +38 -0
- package/src/breadcrumb/breadcrumb-ellipsis.ts +71 -0
- package/src/breadcrumb/breadcrumb-item.ts +41 -0
- package/src/breadcrumb/breadcrumb-link.ts +44 -0
- package/src/breadcrumb/breadcrumb-list.ts +42 -0
- package/src/breadcrumb/breadcrumb-separator.ts +45 -0
- package/src/breadcrumb/breadcrumb.context.ts +45 -0
- package/src/breadcrumb/breadcrumb.spec.ts +354 -0
- package/src/breadcrumb/breadcrumb.ts +239 -0
- package/src/breadcrumb/config.ts +84 -0
- package/src/breadcrumb/index.ts +18 -0
- package/src/button/_examples/button.example.ts +71 -0
- package/src/button/_examples/button.finance.example.ts +83 -0
- package/src/button/_examples/button.retro.example.ts +91 -0
- package/src/button/_examples/button.sizes.example.ts +60 -0
- package/src/button/_examples/index.ts +6 -0
- package/src/button/button.spec.ts +139 -8
- package/src/button/button.ts +114 -16
- package/src/button/config.spec.ts +33 -0
- package/src/button/config.ts +45 -0
- package/src/button/index.ts +2 -1
- package/src/button-group/button-group.context.ts +28 -0
- package/src/button-group/button-group.spec.ts +99 -0
- package/src/button-group/button-group.ts +99 -0
- package/src/button-group/index.ts +2 -0
- package/src/calendar/calendar-day.ts +102 -0
- package/src/calendar/calendar-grid.ts +90 -0
- package/src/calendar/calendar-header.ts +65 -0
- package/src/calendar/calendar.context.ts +53 -0
- package/src/calendar/calendar.spec.ts +225 -0
- package/src/calendar/calendar.ts +233 -0
- package/src/calendar/date-utils.ts +225 -0
- package/src/calendar/index.ts +28 -0
- package/src/carousel/carousel.context.ts +81 -0
- package/src/carousel/carousel.spec.ts +337 -0
- package/src/carousel/carousel.ts +919 -0
- package/src/carousel/index.ts +22 -0
- package/src/cascade-select/cascade-select-option.ts +205 -0
- package/src/cascade-select/cascade-select-panel.ts +106 -0
- package/src/cascade-select/cascade-select-root.ts +265 -0
- package/src/cascade-select/cascade-select-sub-panel.ts +168 -0
- package/src/cascade-select/cascade-select-trigger.ts +44 -0
- package/src/cascade-select/cascade-select.context.ts +71 -0
- package/src/cascade-select/cascade-select.spec.ts +241 -0
- package/src/cascade-select/cascade-select.ts +5 -0
- package/src/cascade-select/index.ts +11 -0
- package/src/chart/chart.ts +6 -2
- package/src/chat/chat-avatar.ts +31 -0
- package/src/chat/chat-bubble.ts +49 -0
- package/src/chat/chat-footer.ts +67 -0
- package/src/chat/chat-header.ts +41 -0
- package/src/chat/chat-log.ts +43 -0
- package/src/chat/chat.context.ts +64 -0
- package/src/chat/chat.spec.ts +341 -0
- package/src/chat/chat.ts +191 -0
- package/src/chat/config.ts +53 -0
- package/src/chat/index.ts +21 -0
- package/src/checkbox/checkbox.ts +9 -2
- package/src/color-picker/color-picker.context.ts +74 -0
- package/src/color-picker/color-picker.spec.ts +241 -0
- package/src/color-picker/color-picker.ts +698 -0
- package/src/color-picker/color-picker.utils.ts +140 -0
- package/src/color-picker/index.ts +28 -0
- package/src/combobox/combobox-input.ts +143 -0
- package/src/combobox/combobox-listbox.ts +49 -0
- package/src/combobox/combobox-option.ts +43 -0
- package/src/combobox/combobox-root.ts +281 -0
- package/src/combobox/combobox.spec.ts +75 -0
- package/src/combobox/combobox.ts +4 -0
- package/src/combobox/index.ts +4 -0
- package/src/command-palette/command-empty.ts +36 -0
- package/src/command-palette/command-group.ts +21 -0
- package/src/command-palette/command-input.ts +70 -0
- package/src/command-palette/command-item.ts +60 -0
- package/src/command-palette/command-list.ts +25 -0
- package/src/command-palette/command-palette-dialog.ts +74 -0
- package/src/command-palette/command-palette-trigger.ts +64 -0
- package/src/command-palette/command-palette.filters.ts +53 -0
- package/src/command-palette/command-palette.spec.ts +349 -0
- package/src/command-palette/command-palette.ts +204 -0
- package/src/command-palette/command-separator.ts +18 -0
- package/src/command-palette/index.ts +15 -0
- package/src/confirm-popup/confirm-popup-action.ts +39 -0
- package/src/confirm-popup/confirm-popup-cancel.ts +38 -0
- package/src/confirm-popup/confirm-popup-content.ts +113 -0
- package/src/confirm-popup/confirm-popup-message.ts +36 -0
- package/src/confirm-popup/confirm-popup-trigger.ts +31 -0
- package/src/confirm-popup/confirm-popup.context.ts +41 -0
- package/src/confirm-popup/confirm-popup.spec.ts +337 -0
- package/src/confirm-popup/confirm-popup.ts +109 -0
- package/src/confirm-popup/index.ts +12 -0
- package/src/date-picker/date-picker-calendar.ts +65 -0
- package/src/date-picker/date-picker-trigger.ts +215 -0
- package/src/date-picker/date-picker.context.ts +50 -0
- package/src/date-picker/date-picker.spec.ts +117 -0
- package/src/date-picker/date-picker.ts +127 -0
- package/src/date-picker/index.ts +7 -0
- package/src/dialog/_examples/dialog.confirm.example.ts +145 -0
- package/src/dialog/_examples/dialog.example.ts +106 -0
- package/src/dialog/_examples/dialog.finance.example.ts +121 -0
- package/src/dialog/_examples/dialog.retro.example.ts +126 -0
- package/src/dialog/_examples/index.ts +6 -0
- package/src/dialog/dialog.ref.ts +42 -0
- package/src/dialog/dialog.service.ts +57 -167
- package/src/dialog/dialog.spec.ts +35 -120
- package/src/dialog/dialog.ts +17 -192
- package/src/dialog/index.ts +3 -9
- package/src/divider/divider.spec.ts +223 -0
- package/src/divider/divider.ts +137 -0
- package/src/divider/index.ts +5 -0
- package/src/drawer/drawer.ref.ts +63 -0
- package/src/drawer/drawer.service.ts +106 -0
- package/src/drawer/drawer.spec.ts +117 -0
- package/src/drawer/drawer.ts +122 -0
- package/src/drawer/index.ts +10 -0
- package/src/dropdown-menu/dropdown-menu-content.ts +258 -0
- package/src/dropdown-menu/dropdown-menu-group.ts +31 -0
- package/src/dropdown-menu/dropdown-menu-item.ts +51 -0
- package/src/dropdown-menu/dropdown-menu-label.ts +41 -0
- package/src/dropdown-menu/dropdown-menu-separator.ts +27 -0
- package/src/dropdown-menu/dropdown-menu-trigger.ts +140 -0
- package/src/dropdown-menu/dropdown-menu.spec.ts +265 -0
- package/src/dropdown-menu/dropdown-menu.ts +60 -0
- package/src/dropdown-menu/index.ts +15 -0
- package/src/example-components.ts +39 -30
- package/src/field/field-error.ts +49 -0
- package/src/field/field-group.ts +39 -0
- package/src/field/field-help.ts +47 -0
- package/src/field/field-label.ts +30 -0
- package/src/field/field.context.ts +28 -0
- package/src/field/field.spec.ts +179 -0
- package/src/field/field.ts +121 -0
- package/src/field/index.ts +6 -0
- package/src/file-upload/file-upload.context.ts +89 -0
- package/src/file-upload/file-upload.spec.ts +290 -0
- package/src/file-upload/file-upload.ts +639 -0
- package/src/file-upload/file-upload.types.ts +59 -0
- package/src/file-upload/index.ts +23 -0
- package/src/form/form-error-summary.ts +87 -0
- package/src/form/form-field.context.ts +3 -0
- package/src/form/form-field.spec.ts +25 -0
- package/src/form/form-field.ts +52 -0
- package/src/form/form.context.ts +52 -2
- package/src/form/form.spec.ts +155 -18
- package/src/form/form.ts +315 -35
- package/src/form/index.ts +11 -2
- package/src/icon/E2E.md +14 -0
- package/src/icon/icon.css +40 -0
- package/src/icon/icon.directive.spec.ts +198 -0
- package/src/icon/icon.directive.ts +113 -0
- package/src/icon/icon.mode.spec.ts +29 -0
- package/src/icon/icon.mode.ts +23 -0
- package/src/icon/icon.providers.spec.ts +63 -0
- package/src/icon/icon.providers.ts +47 -0
- package/src/icon/icon.resolver.spec.ts +96 -0
- package/src/icon/icon.resolver.ts +49 -0
- package/src/icon/icon.tokens.ts +88 -0
- package/src/icon/icon.types.ts +48 -0
- package/src/icon/index.ts +21 -0
- package/src/input/input.ts +12 -3
- package/src/input-group/index.ts +3 -0
- package/src/input-group/input-group-addon.ts +92 -0
- package/src/input-group/input-group.context.ts +27 -0
- package/src/input-group/input-group.spec.ts +186 -0
- package/src/input-group/input-group.ts +136 -0
- package/src/input-mask/index.ts +11 -0
- package/src/input-mask/input-mask.compile.ts +69 -0
- package/src/input-mask/input-mask.engine.ts +376 -0
- package/src/input-mask/input-mask.presets.ts +24 -0
- package/src/input-mask/input-mask.spec.ts +304 -0
- package/src/input-mask/input-mask.tokens.ts +49 -0
- package/src/input-mask/input-mask.ts +280 -0
- package/src/input-otp/index.ts +2 -0
- package/src/input-otp/input-otp.context.ts +41 -0
- package/src/input-otp/input-otp.spec.ts +308 -0
- package/src/input-otp/input-otp.ts +470 -0
- package/src/kbd/index.ts +1 -0
- package/src/kbd/kbd.spec.ts +127 -0
- package/src/kbd/kbd.ts +132 -0
- package/src/link/config.ts +44 -0
- package/src/link/index.ts +2 -0
- package/src/link/link.spec.ts +246 -0
- package/src/link/link.ts +226 -0
- package/src/list/index.ts +11 -0
- package/src/list/list.spec.ts +237 -0
- package/src/list/list.ts +277 -0
- package/src/menubar/index.ts +7 -0
- package/src/menubar/menubar-item.ts +204 -0
- package/src/menubar/menubar.context.ts +43 -0
- package/src/menubar/menubar.spec.ts +433 -0
- package/src/menubar/menubar.ts +309 -0
- package/src/number-input/index.ts +4 -0
- package/src/number-input/number-input-group.ts +64 -0
- package/src/number-input/number-input.context.ts +31 -0
- package/src/number-input/number-input.format.ts +148 -0
- package/src/number-input/number-input.spec.ts +170 -0
- package/src/number-input/number-input.ts +457 -0
- package/src/number-input/number-stepper.ts +193 -0
- package/src/overlay-badge/index.ts +7 -0
- package/src/overlay-badge/overlay-badge-content.ts +73 -0
- package/src/overlay-badge/overlay-badge.context.ts +37 -0
- package/src/overlay-badge/overlay-badge.spec.ts +220 -0
- package/src/overlay-badge/overlay-badge.ts +128 -0
- package/src/pagination/config.ts +82 -0
- package/src/pagination/index.ts +19 -0
- package/src/pagination/page-tokens.ts +78 -0
- package/src/pagination/pagination-ellipsis.ts +69 -0
- package/src/pagination/pagination-first.ts +84 -0
- package/src/pagination/pagination-info.ts +70 -0
- package/src/pagination/pagination-item.ts +81 -0
- package/src/pagination/pagination-last.ts +85 -0
- package/src/pagination/pagination-next.ts +86 -0
- package/src/pagination/pagination-previous.ts +90 -0
- package/src/pagination/pagination.context.ts +52 -0
- package/src/pagination/pagination.spec.ts +388 -0
- package/src/pagination/pagination.ts +288 -0
- package/src/password-input/index.ts +15 -0
- package/src/password-input/password-input.context.ts +65 -0
- package/src/password-input/password-input.scorer.ts +34 -0
- package/src/password-input/password-input.spec.ts +274 -0
- package/src/password-input/password-input.ts +488 -0
- package/src/popover/_examples/index.ts +5 -0
- package/src/popover/_examples/popover.example.ts +92 -0
- package/src/popover/_examples/popover.finance.example.ts +106 -0
- package/src/popover/_examples/popover.retro.example.ts +103 -0
- package/src/popover/index.ts +5 -12
- package/src/popover/popover-arrow.ts +30 -0
- package/src/popover/popover-close.ts +36 -0
- package/src/popover/popover-content.ts +41 -0
- package/src/popover/popover-title.ts +39 -0
- package/src/popover/popover-trigger.ts +40 -0
- package/src/popover/popover.spec.ts +51 -44
- package/src/popover/popover.ts +5 -124
- package/src/presets/bind-presets.spec.ts +50 -0
- package/src/presets/bind-presets.ts +43 -0
- package/src/presets/index.ts +3 -0
- package/src/presets/size.spec.ts +67 -0
- package/src/presets/size.ts +59 -0
- package/src/presets/variant.spec.ts +72 -0
- package/src/presets/variant.ts +62 -0
- package/src/primitives/directionality/directionality.spec.ts +112 -0
- package/src/primitives/directionality/directionality.ts +89 -0
- package/src/primitives/directionality/index.ts +1 -0
- package/src/primitives/forms/form-control.spec.ts +14 -6
- package/src/primitives/forms/form-control.ts +6 -2
- package/src/primitives/index.ts +3 -0
- package/src/primitives/interaction/disabled.ts +12 -5
- package/src/primitives/interaction/focus-ring.ts +4 -2
- package/src/primitives/list/filterable-list.spec.ts +114 -0
- package/src/primitives/list/filterable-list.ts +126 -0
- package/src/primitives/list/group.spec.ts +99 -0
- package/src/primitives/list/group.ts +139 -0
- package/src/primitives/list/index.ts +8 -0
- package/src/primitives/list/inject-helpers.ts +8 -0
- package/src/primitives/list/item.spec.ts +173 -0
- package/src/primitives/list/item.ts +222 -0
- package/src/primitives/list/navigator.spec.ts +286 -0
- package/src/primitives/list/navigator.ts +238 -0
- package/src/primitives/list/selection.spec.ts +214 -0
- package/src/primitives/list/selection.ts +339 -0
- package/src/primitives/list/tokens.ts +106 -0
- package/src/primitives/list/type-ahead.spec.ts +58 -0
- package/src/primitives/list/type-ahead.ts +46 -0
- package/src/primitives/overlay/backdrop.spec.ts +54 -0
- package/src/primitives/overlay/backdrop.ts +31 -0
- package/src/primitives/overlay/builder.spec.ts +38 -0
- package/src/primitives/overlay/builder.ts +151 -0
- package/src/primitives/overlay/container.ts +42 -0
- package/src/primitives/overlay/context.ts +14 -0
- package/src/primitives/overlay/controller.spec.ts +86 -0
- package/src/primitives/overlay/controller.ts +190 -0
- package/src/primitives/overlay/id.spec.ts +24 -0
- package/src/primitives/overlay/id.ts +17 -0
- package/src/primitives/overlay/index.ts +18 -1
- package/src/primitives/overlay/overlay.css +42 -0
- package/src/primitives/overlay/panel.spec.ts +52 -0
- package/src/primitives/overlay/panel.ts +102 -0
- package/src/primitives/overlay/stack.spec.ts +55 -0
- package/src/primitives/overlay/stack.ts +113 -0
- package/src/primitives/overlay/strategies/backdrop/blurred.spec.ts +11 -0
- package/src/primitives/overlay/strategies/backdrop/blurred.ts +5 -0
- package/src/primitives/overlay/strategies/backdrop/none.spec.ts +10 -0
- package/src/primitives/overlay/strategies/backdrop/none.ts +9 -0
- package/src/primitives/overlay/strategies/backdrop/solid.spec.ts +18 -0
- package/src/primitives/overlay/strategies/backdrop/solid.ts +23 -0
- package/src/primitives/overlay/strategies/focus-trap/inert-based.spec.ts +28 -0
- package/src/primitives/overlay/strategies/focus-trap/inert-based.ts +38 -0
- package/src/primitives/overlay/strategies/focus-trap/no-trap.spec.ts +9 -0
- package/src/primitives/overlay/strategies/focus-trap/no-trap.ts +8 -0
- package/src/primitives/overlay/strategies/focus-trap/tab-cycle.spec.ts +49 -0
- package/src/primitives/overlay/strategies/focus-trap/tab-cycle.ts +85 -0
- package/src/primitives/overlay/strategies/index.ts +34 -0
- package/src/primitives/overlay/strategies/live-announcer/_announce.ts +35 -0
- package/src/primitives/overlay/strategies/live-announcer/assertive.spec.ts +21 -0
- package/src/primitives/overlay/strategies/live-announcer/assertive.ts +11 -0
- package/src/primitives/overlay/strategies/live-announcer/polite.spec.ts +21 -0
- package/src/primitives/overlay/strategies/live-announcer/polite.ts +11 -0
- package/src/primitives/overlay/strategies/live-announcer/silent.spec.ts +12 -0
- package/src/primitives/overlay/strategies/live-announcer/silent.ts +5 -0
- package/src/primitives/overlay/strategies/mount/body-portal.spec.ts +40 -0
- package/src/primitives/overlay/strategies/mount/body-portal.ts +91 -0
- package/src/primitives/overlay/strategies/mount/in-container.spec.ts +43 -0
- package/src/primitives/overlay/strategies/mount/in-container.ts +39 -0
- package/src/primitives/overlay/strategies/mount/in-place.spec.ts +40 -0
- package/src/primitives/overlay/strategies/mount/in-place.ts +20 -0
- package/src/primitives/overlay/strategies/position/anchored-to.spec.ts +56 -0
- package/src/primitives/overlay/strategies/position/anchored-to.ts +248 -0
- package/src/primitives/overlay/strategies/position/corner.spec.ts +36 -0
- package/src/primitives/overlay/strategies/position/corner.ts +33 -0
- package/src/primitives/overlay/strategies/position/edge-sheet.spec.ts +32 -0
- package/src/primitives/overlay/strategies/position/edge-sheet.ts +36 -0
- package/src/primitives/overlay/strategies/position/in-place-sibling.spec.ts +25 -0
- package/src/primitives/overlay/strategies/position/in-place-sibling.ts +13 -0
- package/src/primitives/overlay/strategies/position/point-at.spec.ts +40 -0
- package/src/primitives/overlay/strategies/position/point-at.ts +34 -0
- package/src/primitives/overlay/strategies/position/viewport-centered.spec.ts +31 -0
- package/src/primitives/overlay/strategies/position/viewport-centered.ts +31 -0
- package/src/primitives/overlay/strategies/scroll-lock/css-clip.spec.ts +15 -0
- package/src/primitives/overlay/strategies/scroll-lock/css-clip.ts +39 -0
- package/src/primitives/overlay/strategies/scroll-lock/html-overflow.spec.ts +21 -0
- package/src/primitives/overlay/strategies/scroll-lock/html-overflow.ts +44 -0
- package/src/primitives/overlay/strategies/scroll-lock/none.spec.ts +9 -0
- package/src/primitives/overlay/strategies/scroll-lock/none.ts +5 -0
- package/src/primitives/overlay/strategies/trigger-event/on-click.spec.ts +32 -0
- package/src/primitives/overlay/strategies/trigger-event/on-click.ts +28 -0
- package/src/primitives/overlay/strategies/trigger-event/on-context-menu.spec.ts +45 -0
- package/src/primitives/overlay/strategies/trigger-event/on-context-menu.ts +70 -0
- package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.spec.ts +35 -0
- package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.ts +34 -0
- package/src/primitives/overlay/strategies/trigger-event/on-focus.spec.ts +64 -0
- package/src/primitives/overlay/strategies/trigger-event/on-focus.ts +37 -0
- package/src/primitives/overlay/strategies/trigger-event/on-hotkey.spec.ts +37 -0
- package/src/primitives/overlay/strategies/trigger-event/on-hotkey.ts +59 -0
- package/src/primitives/overlay/strategies/trigger-event/on-hover.spec.ts +34 -0
- package/src/primitives/overlay/strategies/trigger-event/on-hover.ts +86 -0
- package/src/primitives/overlay/strategies/trigger-event/programmatic.spec.ts +16 -0
- package/src/primitives/overlay/strategies/trigger-event/programmatic.ts +12 -0
- package/src/primitives/overlay/tokens.ts +54 -0
- package/src/primitives/overlay/trigger.spec.ts +103 -0
- package/src/primitives/overlay/trigger.ts +75 -0
- package/src/primitives/overlay/types.ts +24 -0
- package/src/primitives/overlay/wrapper.ts +50 -0
- package/src/primitives/signals/deep-signal.ts +109 -0
- package/src/primitives/signals/index.ts +1 -0
- package/src/progress-bar/config.ts +48 -0
- package/src/progress-bar/index.ts +12 -0
- package/src/progress-bar/progress-bar-fill.ts +37 -0
- package/src/progress-bar/progress-bar.context.ts +34 -0
- package/src/progress-bar/progress-bar.spec.ts +423 -0
- package/src/progress-bar/progress-bar.ts +217 -0
- package/src/public-api.ts +58 -9
- package/src/radio/radio.ts +14 -3
- package/src/select/index.ts +4 -2
- package/src/select/select-content.ts +69 -0
- package/src/select/select-option.ts +35 -0
- package/src/select/select-root.ts +129 -0
- package/src/select/select-trigger.ts +93 -0
- package/src/select/select.spec.ts +133 -140
- package/src/select/select.ts +4 -250
- package/src/skeleton/index.ts +5 -0
- package/src/skeleton/skeleton.spec.ts +115 -0
- package/src/skeleton/skeleton.ts +56 -0
- package/src/slider/index.ts +10 -0
- package/src/slider/slider-range.ts +49 -0
- package/src/slider/slider-thumb.ts +335 -0
- package/src/slider/slider-track.ts +70 -0
- package/src/slider/slider.context.ts +79 -0
- package/src/slider/slider.geometry.ts +73 -0
- package/src/slider/slider.spec.ts +216 -0
- package/src/slider/slider.ts +443 -0
- package/src/speed-dial/index.ts +10 -0
- package/src/speed-dial/speed-dial-action.ts +40 -0
- package/src/speed-dial/speed-dial-actions.ts +31 -0
- package/src/speed-dial/speed-dial-trigger.ts +55 -0
- package/src/speed-dial/speed-dial.context.ts +36 -0
- package/src/speed-dial/speed-dial.spec.ts +143 -0
- package/src/speed-dial/speed-dial.ts +127 -0
- package/src/spinner/config.ts +48 -0
- package/src/spinner/index.ts +8 -0
- package/src/spinner/spinner.spec.ts +262 -0
- package/src/spinner/spinner.ts +129 -0
- package/src/stepper/index.ts +15 -0
- package/src/stepper/stepper.context.ts +63 -0
- package/src/stepper/stepper.spec.ts +403 -0
- package/src/stepper/stepper.ts +544 -0
- package/src/styles.css +17 -0
- package/src/table/column-helpers.spec.ts +74 -0
- package/src/table/column-helpers.ts +68 -0
- package/src/table/filter-fns.ts +230 -0
- package/src/table/filter-models.spec.ts +240 -0
- package/src/table/filter-models.ts +124 -0
- package/src/table/filter-params.ts +90 -0
- package/src/table/grid-api-impl.ts +321 -0
- package/src/table/grid-api.spec.ts +178 -0
- package/src/table/grid-api.ts +285 -0
- package/src/table/index.ts +73 -1
- package/src/table/table-cell.spec.ts +43 -0
- package/src/table/table-cell.ts +38 -0
- package/src/table/table-filter-outlet.ts +120 -0
- package/src/table/table-header.spec.ts +54 -0
- package/src/table/table-header.ts +63 -0
- package/src/table/table-keyboard.spec.ts +68 -0
- package/src/table/table-keyboard.ts +107 -0
- package/src/table/table-resource.spec.ts +37 -0
- package/src/table/table-resource.ts +36 -0
- package/src/table/table-row.spec.ts +54 -0
- package/src/table/table-row.ts +31 -0
- package/src/table/table-storage.spec.ts +67 -0
- package/src/table/table-storage.ts +76 -0
- package/src/table/table.spec.ts +102 -43
- package/src/table/table.ts +228 -73
- package/src/table/table.types.ts +83 -0
- package/src/tabs/index.ts +7 -2
- package/src/tabs/tabs.context.ts +27 -4
- package/src/tabs/tabs.spec.ts +336 -24
- package/src/tabs/tabs.ts +313 -79
- package/src/tag/config.ts +53 -0
- package/src/tag/index.ts +7 -0
- package/src/tag/tag-list.ts +76 -0
- package/src/tag/tag-remove.ts +61 -0
- package/src/tag/tag.context.ts +36 -0
- package/src/tag/tag.spec.ts +240 -0
- package/src/tag/tag.ts +203 -0
- package/src/textarea/config.ts +42 -0
- package/src/textarea/index.ts +8 -0
- package/src/textarea/textarea.spec.ts +176 -0
- package/src/textarea/textarea.ts +235 -0
- package/src/time-picker/index.ts +15 -0
- package/src/time-picker/time-picker-meridiem.ts +123 -0
- package/src/time-picker/time-picker-segment.ts +318 -0
- package/src/time-picker/time-picker.context.ts +38 -0
- package/src/time-picker/time-picker.format.ts +181 -0
- package/src/time-picker/time-picker.spec.ts +189 -0
- package/src/time-picker/time-picker.ts +274 -0
- package/src/toast/_examples/index.ts +5 -0
- package/src/toast/_examples/toast.example.ts +282 -0
- package/src/toast/_examples/toast.finance.example.ts +180 -0
- package/src/toast/_examples/toast.retro.example.ts +161 -0
- package/src/toast/index.ts +8 -1
- package/src/toast/toast.ref.ts +26 -0
- package/src/toast/toast.service.ts +227 -41
- package/src/toast/toast.spec.ts +178 -25
- package/src/toast/toast.strategy.ts +10 -0
- package/src/toast/toast.ts +178 -22
- package/src/toggle/toggle.ts +10 -2
- package/src/tooltip/_examples/index.ts +6 -0
- package/src/tooltip/_examples/tooltip.example.ts +82 -0
- package/src/tooltip/_examples/tooltip.finance.example.ts +97 -0
- package/src/tooltip/_examples/tooltip.placements.example.ts +83 -0
- package/src/tooltip/_examples/tooltip.retro.example.ts +107 -0
- package/src/tooltip/index.ts +4 -5
- package/src/tooltip/tooltip-arrow.ts +31 -0
- package/src/tooltip/tooltip-content.ts +38 -0
- package/src/tooltip/tooltip-group.ts +32 -0
- package/src/tooltip/tooltip-trigger.ts +47 -0
- package/src/tooltip/tooltip.spec.ts +38 -102
- package/src/tooltip/tooltip.ts +5 -129
- package/src/tree-select/index.ts +12 -0
- package/src/tree-select/tree-select-content.ts +199 -0
- package/src/tree-select/tree-select-node.ts +132 -0
- package/src/tree-select/tree-select-root.ts +272 -0
- package/src/tree-select/tree-select-trigger.ts +90 -0
- package/src/tree-select/tree-select.context.ts +63 -0
- package/src/tree-select/tree-select.spec.ts +433 -0
- package/src/tree-select/tree-select.ts +2 -0
- package/src/typography/blockquote.ts +57 -0
- package/src/typography/code.ts +53 -0
- package/src/typography/index.ts +22 -0
- package/src/typography/lead.ts +49 -0
- package/src/typography/muted.ts +29 -0
- package/src/typography/prose.css +312 -0
- package/src/typography/truncate.ts +99 -0
- package/src/typography/typography.spec.ts +203 -0
- package/tsconfig.lib.json +9 -1
- package/tsconfig.lib.prod.json +7 -1
- package/tsconfig.spec.json +9 -1
- package/vite.config.ts +8 -0
- package/src/button/button.example.ts +0 -30
- package/src/button/button.finance.example.ts +0 -37
- package/src/button/button.retro.example.ts +0 -47
- package/src/button/button.sizes.example.ts +0 -25
- package/src/dialog/dialog.confirm.example.ts +0 -57
- package/src/dialog/dialog.context.ts +0 -11
- package/src/dialog/dialog.example.ts +0 -40
- package/src/dialog/dialog.finance.example.ts +0 -47
- package/src/dialog/dialog.retro.example.ts +0 -46
- package/src/menu/index.ts +0 -2
- package/src/menu/menu.context.ts +0 -10
- package/src/menu/menu.example.ts +0 -39
- package/src/menu/menu.spec.ts +0 -168
- package/src/menu/menu.ts +0 -176
- package/src/popover/popover.context.ts +0 -18
- package/src/popover/popover.example.ts +0 -50
- package/src/popover/popover.finance.example.ts +0 -52
- package/src/popover/popover.retro.example.ts +0 -53
- package/src/primitives/overlay/overlay.spec.ts +0 -90
- package/src/primitives/overlay/overlay.ts +0 -102
- package/src/select/select.context.ts +0 -3
- package/src/toast/toast.example.ts +0 -134
- package/src/toast/toast.finance.example.ts +0 -68
- package/src/toast/toast.retro.example.ts +0 -69
- package/src/tooltip/tooltip.example.ts +0 -46
- package/src/tooltip/tooltip.finance.example.ts +0 -54
- package/src/tooltip/tooltip.placements.example.ts +0 -56
- package/src/tooltip/tooltip.retro.example.ts +0 -65
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
2
|
Directive,
|
|
3
3
|
ElementRef,
|
|
4
4
|
InjectionToken,
|
|
5
5
|
contentChildren,
|
|
6
6
|
effect,
|
|
7
|
+
forwardRef,
|
|
7
8
|
inject,
|
|
9
|
+
input,
|
|
8
10
|
signal,
|
|
9
11
|
} from '@angular/core';
|
|
10
12
|
|
|
@@ -21,7 +23,9 @@ export const KJ_ROVING_TABINDEX = new InjectionToken<KjRovingTabindex>(
|
|
|
21
23
|
* ```html
|
|
22
24
|
* <button kjRovingTabindexItem>Item</button>
|
|
23
25
|
* ```
|
|
24
|
-
* @category Core/Accessibility
|
|
26
|
+
* @doc-category Core/Accessibility
|
|
27
|
+
* @doc
|
|
28
|
+
* @doc-name a11y
|
|
25
29
|
*/
|
|
26
30
|
@Directive({
|
|
27
31
|
selector: '[kjRovingTabindexItem]',
|
|
@@ -48,21 +52,37 @@ export class KjRovingTabindexItemDirective {
|
|
|
48
52
|
* <button kjRovingTabindexItem>Italic</button>
|
|
49
53
|
* </div>
|
|
50
54
|
* ```
|
|
51
|
-
* @category Core/Accessibility
|
|
55
|
+
* @doc-category Core/Accessibility
|
|
56
|
+
* @doc
|
|
57
|
+
* @doc-name a11y
|
|
52
58
|
*/
|
|
53
59
|
@Directive({
|
|
54
60
|
selector: '[kjRovingTabindex]',
|
|
55
61
|
standalone: true,
|
|
56
|
-
providers: [{ provide: KJ_ROVING_TABINDEX, useExisting: KjRovingTabindex }],
|
|
62
|
+
providers: [{ provide: KJ_ROVING_TABINDEX, useExisting: forwardRef(() => KjRovingTabindex) }],
|
|
57
63
|
host: {
|
|
58
64
|
'(keydown)': 'onKeydown($event)',
|
|
59
65
|
'(focusin)': 'onFocusIn($event)',
|
|
60
66
|
},
|
|
61
67
|
})
|
|
62
68
|
export class KjRovingTabindex {
|
|
63
|
-
private readonly
|
|
69
|
+
private readonly host = inject(ElementRef<HTMLElement>);
|
|
70
|
+
private readonly items = contentChildren(KjRovingTabindexItemDirective, {
|
|
71
|
+
descendants: true,
|
|
72
|
+
});
|
|
64
73
|
private readonly activeIndex = signal(0);
|
|
65
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Restricts arrow-key navigation to a single axis.
|
|
77
|
+
* - `'horizontal'`: only ArrowLeft / ArrowRight move focus.
|
|
78
|
+
* - `'vertical'`: only ArrowUp / ArrowDown move focus.
|
|
79
|
+
* - `'both'`: all four arrow keys move focus (default — preserves prior behaviour).
|
|
80
|
+
*
|
|
81
|
+
* Under `'horizontal'`, ArrowLeft / ArrowRight are swapped when the host
|
|
82
|
+
* element resolves to `dir="rtl"`.
|
|
83
|
+
*/
|
|
84
|
+
readonly kjRovingOrientation = input<'horizontal' | 'vertical' | 'both'>('both');
|
|
85
|
+
|
|
66
86
|
constructor() {
|
|
67
87
|
effect(() => {
|
|
68
88
|
const all = this.items();
|
|
@@ -70,6 +90,20 @@ export class KjRovingTabindex {
|
|
|
70
90
|
});
|
|
71
91
|
}
|
|
72
92
|
|
|
93
|
+
private resolveRtl(): boolean {
|
|
94
|
+
const el = this.host.nativeElement;
|
|
95
|
+
if (typeof getComputedStyle === 'function') {
|
|
96
|
+
const direction = getComputedStyle(el).direction;
|
|
97
|
+
if (direction === 'rtl') return true;
|
|
98
|
+
if (direction === 'ltr') {
|
|
99
|
+
// Some test environments (jsdom) return the default 'ltr' even when an
|
|
100
|
+
// ancestor sets `dir="rtl"`. Fall through to attribute lookup.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const dirHost = el.closest('[dir]') as HTMLElement | null;
|
|
104
|
+
return dirHost?.dir.toLowerCase() === 'rtl';
|
|
105
|
+
}
|
|
106
|
+
|
|
73
107
|
/** @internal — syncs activeIndex when focus moves into an item programmatically */
|
|
74
108
|
onFocusIn(event: FocusEvent): void {
|
|
75
109
|
const all = this.items();
|
|
@@ -85,9 +119,24 @@ export class KjRovingTabindex {
|
|
|
85
119
|
if (!all.length) return;
|
|
86
120
|
let next = this.activeIndex();
|
|
87
121
|
|
|
88
|
-
|
|
122
|
+
const orientation = this.kjRovingOrientation();
|
|
123
|
+
const horizontalActive = orientation === 'horizontal' || orientation === 'both';
|
|
124
|
+
const verticalActive = orientation === 'vertical' || orientation === 'both';
|
|
125
|
+
|
|
126
|
+
// Resolve directionality lazily; only matters when horizontal arrows are active.
|
|
127
|
+
// Prefer computed style; fall back to the nearest `dir` attribute (jsdom does
|
|
128
|
+
// not propagate ancestor `dir` to computed style in all cases).
|
|
129
|
+
const isRtl = horizontalActive && this.resolveRtl();
|
|
130
|
+
const forwardKey = isRtl ? 'ArrowLeft' : 'ArrowRight';
|
|
131
|
+
const backwardKey = isRtl ? 'ArrowRight' : 'ArrowLeft';
|
|
132
|
+
|
|
133
|
+
if (horizontalActive && event.key === forwardKey) {
|
|
134
|
+
next = (next + 1) % all.length;
|
|
135
|
+
} else if (horizontalActive && event.key === backwardKey) {
|
|
136
|
+
next = (next - 1 + all.length) % all.length;
|
|
137
|
+
} else if (verticalActive && event.key === 'ArrowDown') {
|
|
89
138
|
next = (next + 1) % all.length;
|
|
90
|
-
} else if (
|
|
139
|
+
} else if (verticalActive && event.key === 'ArrowUp') {
|
|
91
140
|
next = (next - 1 + all.length) % all.length;
|
|
92
141
|
} else if (event.key === 'Home') {
|
|
93
142
|
next = 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { Directive } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Visually hides an element while keeping it accessible to screen readers.
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* <span kjVisuallyHidden>Close dialog</span>
|
|
12
12
|
* </button>
|
|
13
13
|
* ```
|
|
14
|
-
* @category Core/Accessibility
|
|
14
|
+
* @doc-category Core/Accessibility
|
|
15
|
+
* @doc
|
|
16
|
+
* @doc-name a11y
|
|
15
17
|
*/
|
|
16
18
|
@Directive({
|
|
17
19
|
selector: '[kjVisuallyHidden]',
|
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
import { InjectionToken, Signal } from '@angular/core';
|
|
2
2
|
|
|
3
|
+
/** Accordion mode: `'single'` (one item open at a time) or `'multiple'` (any number open). */
|
|
4
|
+
export type KjAccordionType = 'single' | 'multiple';
|
|
5
|
+
|
|
3
6
|
/** Context interface for the root accordion directive. */
|
|
4
7
|
export interface KjAccordionContext {
|
|
8
|
+
/** Set of currently open item values. */
|
|
5
9
|
readonly openIds: Signal<ReadonlySet<string>>;
|
|
10
|
+
/** Current mode: single or multiple. */
|
|
11
|
+
readonly type: Signal<KjAccordionType>;
|
|
12
|
+
/** Whether opt-in arrow-key roving navigation is enabled. */
|
|
13
|
+
readonly arrowNavigation: Signal<boolean>;
|
|
14
|
+
/** Toggle an item by its string value. In single mode, closes others first. */
|
|
6
15
|
toggle(id: string): void;
|
|
16
|
+
/** Whether the given item value is currently open. */
|
|
7
17
|
isOpen(id: string): boolean;
|
|
8
18
|
}
|
|
9
19
|
|
|
10
20
|
/** Context interface for an individual accordion item directive. */
|
|
11
21
|
export interface KjAccordionItemContext {
|
|
22
|
+
/** Stable string value identifying the item within the parent accordion. */
|
|
23
|
+
readonly value: Signal<string>;
|
|
24
|
+
/** Whether this item is currently expanded. */
|
|
12
25
|
readonly expanded: Signal<boolean>;
|
|
26
|
+
/** Whether this item is disabled (toggle is a no-op, trigger announces aria-disabled). */
|
|
27
|
+
readonly disabled: Signal<boolean>;
|
|
28
|
+
/** Stable id for the trigger element — `aria-labelledby` target on the content region. */
|
|
29
|
+
readonly headerId: Signal<string>;
|
|
30
|
+
/** Stable id for the content region — `aria-controls` target on the trigger. */
|
|
31
|
+
readonly contentId: Signal<string>;
|
|
32
|
+
/** Toggle this item's expanded state. No-op when disabled. */
|
|
13
33
|
toggle(): void;
|
|
34
|
+
/** Open this item. No-op when disabled. */
|
|
14
35
|
open(): void;
|
|
36
|
+
/** Close this item. No-op when disabled. */
|
|
15
37
|
close(): void;
|
|
16
38
|
}
|
|
17
39
|
|
|
@@ -1,32 +1,242 @@
|
|
|
1
|
-
|
|
1
|
+
import { Component, signal } from '@angular/core';
|
|
2
|
+
import { render, fireEvent } from '@testing-library/angular';
|
|
2
3
|
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
KjAccordion,
|
|
6
|
+
KjAccordionItem,
|
|
7
|
+
KjAccordionTrigger,
|
|
8
|
+
KjAccordionContent,
|
|
9
|
+
} from './accordion';
|
|
4
10
|
|
|
5
11
|
expect.extend(toHaveNoViolations);
|
|
12
|
+
|
|
6
13
|
const imports = [KjAccordion, KjAccordionItem, KjAccordionTrigger, KjAccordionContent];
|
|
7
|
-
|
|
14
|
+
|
|
15
|
+
const baseTemplate = `
|
|
16
|
+
<div kjAccordion>
|
|
17
|
+
<div kjAccordionItem kjItemValue="i1">
|
|
18
|
+
<button kjAccordionTrigger>Section 1</button>
|
|
19
|
+
<div kjAccordionContent>Body 1</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div kjAccordionItem kjItemValue="i2">
|
|
22
|
+
<button kjAccordionTrigger>Section 2</button>
|
|
23
|
+
<div kjAccordionContent>Body 2</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
`;
|
|
8
27
|
|
|
9
28
|
describe('KjAccordion', () => {
|
|
10
29
|
it('content hidden by default', async () => {
|
|
11
|
-
const { container } = await render(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
expect(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
fireEvent.click(
|
|
26
|
-
expect(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
expect(
|
|
30
|
+
const { container } = await render(baseTemplate, { imports });
|
|
31
|
+
const content = container.querySelector('[kjAccordionContent]');
|
|
32
|
+
// Visibility is driven by `[data-state]` + CSS animation (the element
|
|
33
|
+
// stays in the DOM so open/close can transition). `aria-hidden` + `inert`
|
|
34
|
+
// keep the closed panel out of the AT tree and tab sequence.
|
|
35
|
+
expect(content).toHaveAttribute('data-state', 'closed');
|
|
36
|
+
expect(content).toHaveAttribute('aria-hidden', 'true');
|
|
37
|
+
expect(content).toHaveAttribute('inert', '');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('click trigger expands and updates aria-expanded', async () => {
|
|
41
|
+
const { container } = await render(baseTemplate, { imports });
|
|
42
|
+
const trigger = container.querySelector('[kjAccordionTrigger]')!;
|
|
43
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
44
|
+
fireEvent.click(trigger);
|
|
45
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
46
|
+
const content = container.querySelector('[kjAccordionContent]');
|
|
47
|
+
expect(content).toHaveAttribute('data-state', 'open');
|
|
48
|
+
expect(content).not.toHaveAttribute('aria-hidden');
|
|
49
|
+
expect(content).not.toHaveAttribute('inert');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('single mode closes other items when one opens', async () => {
|
|
53
|
+
const { container } = await render(baseTemplate, { imports });
|
|
54
|
+
const triggers = container.querySelectorAll('[kjAccordionTrigger]');
|
|
55
|
+
fireEvent.click(triggers[0]);
|
|
56
|
+
fireEvent.click(triggers[1]);
|
|
57
|
+
expect(triggers[0]).toHaveAttribute('aria-expanded', 'false');
|
|
58
|
+
expect(triggers[1]).toHaveAttribute('aria-expanded', 'true');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('multiple mode keeps multiple items open', async () => {
|
|
62
|
+
const { container } = await render(
|
|
63
|
+
`<div kjAccordion kjType="multiple">
|
|
64
|
+
<div kjAccordionItem kjItemValue="a"><button kjAccordionTrigger>A</button><div kjAccordionContent>A</div></div>
|
|
65
|
+
<div kjAccordionItem kjItemValue="b"><button kjAccordionTrigger>B</button><div kjAccordionContent>B</div></div>
|
|
66
|
+
</div>`,
|
|
67
|
+
{ imports },
|
|
68
|
+
);
|
|
69
|
+
const triggers = container.querySelectorAll('[kjAccordionTrigger]');
|
|
70
|
+
fireEvent.click(triggers[0]);
|
|
71
|
+
fireEvent.click(triggers[1]);
|
|
72
|
+
expect(triggers[0]).toHaveAttribute('aria-expanded', 'true');
|
|
73
|
+
expect(triggers[1]).toHaveAttribute('aria-expanded', 'true');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('ARIA wiring', () => {
|
|
77
|
+
it('trigger gets aria-controls pointing at the content id', async () => {
|
|
78
|
+
const { container } = await render(baseTemplate, { imports });
|
|
79
|
+
const trigger = container.querySelector('[kjAccordionTrigger]') as HTMLElement;
|
|
80
|
+
const content = container.querySelector('[kjAccordionContent]') as HTMLElement;
|
|
81
|
+
const controls = trigger.getAttribute('aria-controls');
|
|
82
|
+
expect(controls).toBeTruthy();
|
|
83
|
+
expect(controls).toBe(content.id);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('content has role="region" and aria-labelledby pointing at the trigger id', async () => {
|
|
87
|
+
const { container } = await render(baseTemplate, { imports });
|
|
88
|
+
const trigger = container.querySelector('[kjAccordionTrigger]') as HTMLElement;
|
|
89
|
+
const content = container.querySelector('[kjAccordionContent]') as HTMLElement;
|
|
90
|
+
expect(content).toHaveAttribute('role', 'region');
|
|
91
|
+
const labelledBy = content.getAttribute('aria-labelledby');
|
|
92
|
+
expect(labelledBy).toBeTruthy();
|
|
93
|
+
expect(labelledBy).toBe(trigger.id);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('header / content ids are stable across change detection', async () => {
|
|
97
|
+
const { container, fixture } = await render(baseTemplate, { imports });
|
|
98
|
+
const trigger = container.querySelector('[kjAccordionTrigger]') as HTMLElement;
|
|
99
|
+
const before = trigger.id;
|
|
100
|
+
fireEvent.click(trigger);
|
|
101
|
+
fixture.detectChanges();
|
|
102
|
+
expect(trigger.id).toBe(before);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('passes axe audit (closed)', async () => {
|
|
106
|
+
const { container } = await render(baseTemplate, { imports });
|
|
107
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('passes axe audit (open)', async () => {
|
|
111
|
+
const { container } = await render(baseTemplate, { imports });
|
|
112
|
+
fireEvent.click(container.querySelector('[kjAccordionTrigger]')!);
|
|
113
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('disabled item', () => {
|
|
118
|
+
it('toggle is a no-op and aria-disabled is set on the trigger', async () => {
|
|
119
|
+
const { container } = await render(
|
|
120
|
+
`<div kjAccordion>
|
|
121
|
+
<div kjAccordionItem kjItemValue="locked" kjItemDisabled>
|
|
122
|
+
<button kjAccordionTrigger>Locked</button>
|
|
123
|
+
<div kjAccordionContent>Body</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>`,
|
|
126
|
+
{ imports },
|
|
127
|
+
);
|
|
128
|
+
const trigger = container.querySelector('[kjAccordionTrigger]') as HTMLElement;
|
|
129
|
+
expect(trigger).toHaveAttribute('aria-disabled', 'true');
|
|
130
|
+
fireEvent.click(trigger);
|
|
131
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('two-way value binding', () => {
|
|
136
|
+
@Component({
|
|
137
|
+
standalone: true,
|
|
138
|
+
imports,
|
|
139
|
+
template: `
|
|
140
|
+
<div kjAccordion [(kjValue)]="open">
|
|
141
|
+
<div kjAccordionItem kjItemValue="a"><button kjAccordionTrigger>A</button><div kjAccordionContent>A</div></div>
|
|
142
|
+
<div kjAccordionItem kjItemValue="b"><button kjAccordionTrigger>B</button><div kjAccordionContent>B</div></div>
|
|
143
|
+
</div>
|
|
144
|
+
`,
|
|
145
|
+
})
|
|
146
|
+
class SingleHost {
|
|
147
|
+
readonly open = signal<string>('a');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
it('opens the seeded item from the bound value (single mode)', async () => {
|
|
151
|
+
const { container, fixture } = await render(SingleHost);
|
|
152
|
+
await fixture.whenStable();
|
|
153
|
+
fixture.detectChanges();
|
|
154
|
+
const triggers = container.querySelectorAll('[kjAccordionTrigger]');
|
|
155
|
+
expect(triggers[0]).toHaveAttribute('aria-expanded', 'true');
|
|
156
|
+
expect(triggers[1]).toHaveAttribute('aria-expanded', 'false');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('writes the open value back to the parent signal on click', async () => {
|
|
160
|
+
const { container, fixture } = await render(SingleHost);
|
|
161
|
+
await fixture.whenStable();
|
|
162
|
+
fireEvent.click(container.querySelectorAll('[kjAccordionTrigger]')[1]);
|
|
163
|
+
fixture.detectChanges();
|
|
164
|
+
expect(fixture.componentInstance.open()).toBe('b');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
@Component({
|
|
168
|
+
standalone: true,
|
|
169
|
+
imports,
|
|
170
|
+
template: `
|
|
171
|
+
<div kjAccordion kjType="multiple" [(kjValue)]="open">
|
|
172
|
+
<div kjAccordionItem kjItemValue="a"><button kjAccordionTrigger>A</button><div kjAccordionContent>A</div></div>
|
|
173
|
+
<div kjAccordionItem kjItemValue="b"><button kjAccordionTrigger>B</button><div kjAccordionContent>B</div></div>
|
|
174
|
+
</div>
|
|
175
|
+
`,
|
|
176
|
+
})
|
|
177
|
+
class MultipleHost {
|
|
178
|
+
readonly open = signal<string[]>(['a']);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
it('multiple mode emits array updates', async () => {
|
|
182
|
+
const { container, fixture } = await render(MultipleHost);
|
|
183
|
+
await fixture.whenStable();
|
|
184
|
+
fireEvent.click(container.querySelectorAll('[kjAccordionTrigger]')[1]);
|
|
185
|
+
fixture.detectChanges();
|
|
186
|
+
expect(fixture.componentInstance.open()).toEqual(['a', 'b']);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('arrow-key navigation (opt-in)', () => {
|
|
191
|
+
it('does not move focus when kjArrowNavigation is off (default)', async () => {
|
|
192
|
+
const { container } = await render(baseTemplate, { imports });
|
|
193
|
+
const triggers = container.querySelectorAll<HTMLElement>('[kjAccordionTrigger]');
|
|
194
|
+
triggers[0].focus();
|
|
195
|
+
fireEvent.keyDown(triggers[0], { key: 'ArrowDown' });
|
|
196
|
+
// Without arrow-nav opted in, focus stays on the first trigger.
|
|
197
|
+
expect(document.activeElement).toBe(triggers[0]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('ArrowDown / ArrowUp / Home / End move focus when kjArrowNavigation is on', async () => {
|
|
201
|
+
const { container } = await render(
|
|
202
|
+
`<div kjAccordion kjArrowNavigation kjType="multiple">
|
|
203
|
+
<div kjAccordionItem kjItemValue="a"><button kjAccordionTrigger>A</button><div kjAccordionContent>A</div></div>
|
|
204
|
+
<div kjAccordionItem kjItemValue="b"><button kjAccordionTrigger>B</button><div kjAccordionContent>B</div></div>
|
|
205
|
+
<div kjAccordionItem kjItemValue="c"><button kjAccordionTrigger>C</button><div kjAccordionContent>C</div></div>
|
|
206
|
+
</div>`,
|
|
207
|
+
{ imports },
|
|
208
|
+
);
|
|
209
|
+
const triggers = container.querySelectorAll<HTMLElement>('[kjAccordionTrigger]');
|
|
210
|
+
triggers[0].focus();
|
|
211
|
+
fireEvent.keyDown(triggers[0], { key: 'ArrowDown' });
|
|
212
|
+
expect(document.activeElement).toBe(triggers[1]);
|
|
213
|
+
fireEvent.keyDown(triggers[1], { key: 'ArrowDown' });
|
|
214
|
+
expect(document.activeElement).toBe(triggers[2]);
|
|
215
|
+
fireEvent.keyDown(triggers[2], { key: 'ArrowDown' });
|
|
216
|
+
// Wraps to first.
|
|
217
|
+
expect(document.activeElement).toBe(triggers[0]);
|
|
218
|
+
fireEvent.keyDown(triggers[0], { key: 'ArrowUp' });
|
|
219
|
+
// Wraps backwards to last.
|
|
220
|
+
expect(document.activeElement).toBe(triggers[2]);
|
|
221
|
+
fireEvent.keyDown(triggers[2], { key: 'Home' });
|
|
222
|
+
expect(document.activeElement).toBe(triggers[0]);
|
|
223
|
+
fireEvent.keyDown(triggers[0], { key: 'End' });
|
|
224
|
+
expect(document.activeElement).toBe(triggers[2]);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('skips disabled items during arrow navigation', async () => {
|
|
228
|
+
const { container } = await render(
|
|
229
|
+
`<div kjAccordion kjArrowNavigation>
|
|
230
|
+
<div kjAccordionItem kjItemValue="a"><button kjAccordionTrigger>A</button></div>
|
|
231
|
+
<div kjAccordionItem kjItemValue="b" kjItemDisabled><button kjAccordionTrigger>B</button></div>
|
|
232
|
+
<div kjAccordionItem kjItemValue="c"><button kjAccordionTrigger>C</button></div>
|
|
233
|
+
</div>`,
|
|
234
|
+
{ imports },
|
|
235
|
+
);
|
|
236
|
+
const triggers = container.querySelectorAll<HTMLElement>('[kjAccordionTrigger]');
|
|
237
|
+
triggers[0].focus();
|
|
238
|
+
fireEvent.keyDown(triggers[0], { key: 'ArrowDown' });
|
|
239
|
+
expect(document.activeElement).toBe(triggers[2]);
|
|
240
|
+
});
|
|
31
241
|
});
|
|
32
242
|
});
|