@kouji-ui/core 0.1.1 → 0.1.3
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/fesm2022/kouji-ui-core.mjs +26789 -0
- package/fesm2022/kouji-ui-core.mjs.map +1 -0
- package/package.json +15 -7
- package/types/kouji-ui-core.d.ts +13545 -0
- package/.turbo/turbo-build.log +0 -30
- package/CHANGELOG.md +0 -190
- package/ng-package.json +0 -11
- package/src/a11y/.gitkeep +0 -0
- package/src/a11y/aria-describedby.spec.ts +0 -55
- package/src/a11y/aria-describedby.ts +0 -37
- package/src/a11y/aria-labelledby.spec.ts +0 -55
- package/src/a11y/aria-labelledby.ts +0 -38
- package/src/a11y/focus-trap.spec.ts +0 -86
- package/src/a11y/focus-trap.ts +0 -72
- package/src/a11y/index.ts +0 -10
- package/src/a11y/live-region.spec.ts +0 -58
- package/src/a11y/live-region.ts +0 -50
- package/src/a11y/roving-tabindex.spec.ts +0 -201
- package/src/a11y/roving-tabindex.ts +0 -153
- package/src/a11y/visually-hidden.spec.ts +0 -34
- package/src/a11y/visually-hidden.ts +0 -26
- package/src/accordion/accordion.context.ts +0 -44
- package/src/accordion/accordion.spec.ts +0 -242
- package/src/accordion/accordion.ts +0 -401
- package/src/accordion/index.ts +0 -8
- package/src/alert/alert.context.ts +0 -28
- package/src/alert/alert.spec.ts +0 -217
- package/src/alert/alert.ts +0 -417
- package/src/alert/config.ts +0 -46
- package/src/alert/index.ts +0 -19
- package/src/avatar/avatar-group.context.ts +0 -45
- package/src/avatar/avatar-group.spec.ts +0 -358
- package/src/avatar/avatar-group.ts +0 -259
- package/src/avatar/avatar.spec.ts +0 -18
- package/src/avatar/avatar.ts +0 -39
- package/src/avatar/index.ts +0 -11
- package/src/badge/badge.spec.ts +0 -28
- package/src/badge/badge.ts +0 -35
- package/src/badge/index.ts +0 -1
- package/src/breadcrumb/breadcrumb-current.ts +0 -38
- package/src/breadcrumb/breadcrumb-ellipsis.ts +0 -71
- package/src/breadcrumb/breadcrumb-item.ts +0 -41
- package/src/breadcrumb/breadcrumb-link.ts +0 -44
- package/src/breadcrumb/breadcrumb-list.ts +0 -42
- package/src/breadcrumb/breadcrumb-separator.ts +0 -45
- package/src/breadcrumb/breadcrumb.context.ts +0 -45
- package/src/breadcrumb/breadcrumb.spec.ts +0 -354
- package/src/breadcrumb/breadcrumb.ts +0 -239
- package/src/breadcrumb/config.ts +0 -84
- package/src/breadcrumb/index.ts +0 -18
- package/src/button/_examples/button.example.ts +0 -71
- package/src/button/_examples/button.finance.example.ts +0 -83
- package/src/button/_examples/button.retro.example.ts +0 -91
- package/src/button/_examples/button.sizes.example.ts +0 -60
- package/src/button/_examples/index.ts +0 -6
- package/src/button/button.spec.ts +0 -163
- package/src/button/button.ts +0 -142
- package/src/button/config.spec.ts +0 -33
- package/src/button/config.ts +0 -45
- package/src/button/index.ts +0 -2
- package/src/button-group/button-group.context.ts +0 -28
- package/src/button-group/button-group.spec.ts +0 -99
- package/src/button-group/button-group.ts +0 -99
- package/src/button-group/index.ts +0 -2
- package/src/calendar/calendar-day.ts +0 -102
- package/src/calendar/calendar-grid.ts +0 -90
- package/src/calendar/calendar-header.ts +0 -65
- package/src/calendar/calendar.context.ts +0 -53
- package/src/calendar/calendar.spec.ts +0 -225
- package/src/calendar/calendar.ts +0 -233
- package/src/calendar/date-utils.ts +0 -225
- package/src/calendar/index.ts +0 -28
- package/src/carousel/carousel.context.ts +0 -81
- package/src/carousel/carousel.spec.ts +0 -337
- package/src/carousel/carousel.ts +0 -919
- package/src/carousel/index.ts +0 -22
- package/src/cascade-select/cascade-select-option.ts +0 -205
- package/src/cascade-select/cascade-select-panel.ts +0 -106
- package/src/cascade-select/cascade-select-root.ts +0 -265
- package/src/cascade-select/cascade-select-sub-panel.ts +0 -168
- package/src/cascade-select/cascade-select-trigger.ts +0 -44
- package/src/cascade-select/cascade-select.context.ts +0 -71
- package/src/cascade-select/cascade-select.spec.ts +0 -241
- package/src/cascade-select/cascade-select.ts +0 -5
- package/src/cascade-select/index.ts +0 -11
- package/src/chart/chart.spec.ts +0 -27
- package/src/chart/chart.ts +0 -52
- package/src/chart/index.ts +0 -1
- package/src/chat/chat-avatar.ts +0 -31
- package/src/chat/chat-bubble.ts +0 -49
- package/src/chat/chat-footer.ts +0 -67
- package/src/chat/chat-header.ts +0 -41
- package/src/chat/chat-log.ts +0 -43
- package/src/chat/chat.context.ts +0 -64
- package/src/chat/chat.spec.ts +0 -341
- package/src/chat/chat.ts +0 -191
- package/src/chat/config.ts +0 -53
- package/src/chat/index.ts +0 -21
- package/src/checkbox/checkbox.spec.ts +0 -35
- package/src/checkbox/checkbox.ts +0 -89
- package/src/checkbox/index.ts +0 -1
- package/src/color-picker/color-picker.context.ts +0 -74
- package/src/color-picker/color-picker.spec.ts +0 -241
- package/src/color-picker/color-picker.ts +0 -698
- package/src/color-picker/color-picker.utils.ts +0 -140
- package/src/color-picker/index.ts +0 -28
- package/src/combobox/combobox-input.ts +0 -143
- package/src/combobox/combobox-listbox.ts +0 -49
- package/src/combobox/combobox-option.ts +0 -43
- package/src/combobox/combobox-root.ts +0 -281
- package/src/combobox/combobox.spec.ts +0 -75
- package/src/combobox/combobox.ts +0 -4
- package/src/combobox/index.ts +0 -4
- package/src/command-palette/command-empty.ts +0 -36
- package/src/command-palette/command-group.ts +0 -21
- package/src/command-palette/command-input.ts +0 -70
- package/src/command-palette/command-item.ts +0 -60
- package/src/command-palette/command-list.ts +0 -25
- package/src/command-palette/command-palette-dialog.ts +0 -74
- package/src/command-palette/command-palette-trigger.ts +0 -64
- package/src/command-palette/command-palette.filters.ts +0 -53
- package/src/command-palette/command-palette.spec.ts +0 -349
- package/src/command-palette/command-palette.ts +0 -204
- package/src/command-palette/command-separator.ts +0 -18
- package/src/command-palette/index.ts +0 -15
- package/src/confirm-popup/confirm-popup-action.ts +0 -39
- package/src/confirm-popup/confirm-popup-cancel.ts +0 -38
- package/src/confirm-popup/confirm-popup-content.ts +0 -113
- package/src/confirm-popup/confirm-popup-message.ts +0 -36
- package/src/confirm-popup/confirm-popup-trigger.ts +0 -31
- package/src/confirm-popup/confirm-popup.context.ts +0 -41
- package/src/confirm-popup/confirm-popup.spec.ts +0 -337
- package/src/confirm-popup/confirm-popup.ts +0 -109
- package/src/confirm-popup/index.ts +0 -12
- package/src/date-picker/date-picker-calendar.ts +0 -65
- package/src/date-picker/date-picker-trigger.ts +0 -215
- package/src/date-picker/date-picker.context.ts +0 -50
- package/src/date-picker/date-picker.spec.ts +0 -117
- package/src/date-picker/date-picker.ts +0 -127
- package/src/date-picker/index.ts +0 -7
- package/src/dialog/_examples/dialog.confirm.example.ts +0 -145
- package/src/dialog/_examples/dialog.example.ts +0 -106
- package/src/dialog/_examples/dialog.finance.example.ts +0 -121
- package/src/dialog/_examples/dialog.retro.example.ts +0 -126
- package/src/dialog/_examples/index.ts +0 -6
- package/src/dialog/dialog.ref.ts +0 -42
- package/src/dialog/dialog.service.ts +0 -66
- package/src/dialog/dialog.spec.ts +0 -37
- package/src/dialog/dialog.ts +0 -26
- package/src/dialog/index.ts +0 -3
- package/src/divider/divider.spec.ts +0 -223
- package/src/divider/divider.ts +0 -137
- package/src/divider/index.ts +0 -5
- package/src/drawer/drawer.ref.ts +0 -63
- package/src/drawer/drawer.service.ts +0 -106
- package/src/drawer/drawer.spec.ts +0 -117
- package/src/drawer/drawer.ts +0 -122
- package/src/drawer/index.ts +0 -10
- package/src/dropdown-menu/dropdown-menu-content.ts +0 -258
- package/src/dropdown-menu/dropdown-menu-group.ts +0 -31
- package/src/dropdown-menu/dropdown-menu-item.ts +0 -51
- package/src/dropdown-menu/dropdown-menu-label.ts +0 -41
- package/src/dropdown-menu/dropdown-menu-separator.ts +0 -27
- package/src/dropdown-menu/dropdown-menu-trigger.ts +0 -140
- package/src/dropdown-menu/dropdown-menu.spec.ts +0 -265
- package/src/dropdown-menu/dropdown-menu.ts +0 -60
- package/src/dropdown-menu/index.ts +0 -15
- package/src/example-components.ts +0 -42
- package/src/field/field-error.ts +0 -49
- package/src/field/field-group.ts +0 -39
- package/src/field/field-help.ts +0 -47
- package/src/field/field-label.ts +0 -30
- package/src/field/field.context.ts +0 -28
- package/src/field/field.spec.ts +0 -179
- package/src/field/field.ts +0 -121
- package/src/field/index.ts +0 -6
- package/src/file-upload/file-upload.context.ts +0 -89
- package/src/file-upload/file-upload.spec.ts +0 -290
- package/src/file-upload/file-upload.ts +0 -639
- package/src/file-upload/file-upload.types.ts +0 -59
- package/src/file-upload/index.ts +0 -23
- package/src/form/form-error-summary.ts +0 -87
- package/src/form/form-field.context.ts +0 -3
- package/src/form/form-field.spec.ts +0 -25
- package/src/form/form-field.ts +0 -52
- package/src/form/form.context.ts +0 -53
- package/src/form/form.spec.ts +0 -162
- package/src/form/form.ts +0 -326
- package/src/form/index.ts +0 -11
- package/src/icon/E2E.md +0 -14
- package/src/icon/icon.directive.spec.ts +0 -198
- package/src/icon/icon.directive.ts +0 -113
- package/src/icon/icon.mode.spec.ts +0 -29
- package/src/icon/icon.mode.ts +0 -23
- package/src/icon/icon.providers.spec.ts +0 -63
- package/src/icon/icon.providers.ts +0 -47
- package/src/icon/icon.resolver.spec.ts +0 -96
- package/src/icon/icon.resolver.ts +0 -49
- package/src/icon/icon.tokens.ts +0 -88
- package/src/icon/icon.types.ts +0 -48
- package/src/icon/index.ts +0 -21
- package/src/input/index.ts +0 -1
- package/src/input/input.spec.ts +0 -43
- package/src/input/input.ts +0 -89
- package/src/input-group/index.ts +0 -3
- package/src/input-group/input-group-addon.ts +0 -92
- package/src/input-group/input-group.context.ts +0 -27
- package/src/input-group/input-group.spec.ts +0 -186
- package/src/input-group/input-group.ts +0 -136
- package/src/input-mask/index.ts +0 -11
- package/src/input-mask/input-mask.compile.ts +0 -69
- package/src/input-mask/input-mask.engine.ts +0 -376
- package/src/input-mask/input-mask.presets.ts +0 -24
- package/src/input-mask/input-mask.spec.ts +0 -304
- package/src/input-mask/input-mask.tokens.ts +0 -49
- package/src/input-mask/input-mask.ts +0 -280
- package/src/input-otp/index.ts +0 -2
- package/src/input-otp/input-otp.context.ts +0 -41
- package/src/input-otp/input-otp.spec.ts +0 -308
- package/src/input-otp/input-otp.ts +0 -470
- package/src/kbd/index.ts +0 -1
- package/src/kbd/kbd.spec.ts +0 -127
- package/src/kbd/kbd.ts +0 -132
- package/src/link/config.ts +0 -44
- package/src/link/index.ts +0 -2
- package/src/link/link.spec.ts +0 -246
- package/src/link/link.ts +0 -226
- package/src/list/index.ts +0 -11
- package/src/list/list.spec.ts +0 -237
- package/src/list/list.ts +0 -277
- package/src/menubar/index.ts +0 -7
- package/src/menubar/menubar-item.ts +0 -204
- package/src/menubar/menubar.context.ts +0 -43
- package/src/menubar/menubar.spec.ts +0 -433
- package/src/menubar/menubar.ts +0 -309
- package/src/number-input/index.ts +0 -4
- package/src/number-input/number-input-group.ts +0 -64
- package/src/number-input/number-input.context.ts +0 -31
- package/src/number-input/number-input.format.ts +0 -148
- package/src/number-input/number-input.spec.ts +0 -170
- package/src/number-input/number-input.ts +0 -457
- package/src/number-input/number-stepper.ts +0 -193
- package/src/overlay-badge/index.ts +0 -7
- package/src/overlay-badge/overlay-badge-content.ts +0 -73
- package/src/overlay-badge/overlay-badge.context.ts +0 -37
- package/src/overlay-badge/overlay-badge.spec.ts +0 -220
- package/src/overlay-badge/overlay-badge.ts +0 -128
- package/src/pagination/config.ts +0 -82
- package/src/pagination/index.ts +0 -19
- package/src/pagination/page-tokens.ts +0 -78
- package/src/pagination/pagination-ellipsis.ts +0 -69
- package/src/pagination/pagination-first.ts +0 -84
- package/src/pagination/pagination-info.ts +0 -70
- package/src/pagination/pagination-item.ts +0 -81
- package/src/pagination/pagination-last.ts +0 -85
- package/src/pagination/pagination-next.ts +0 -86
- package/src/pagination/pagination-previous.ts +0 -90
- package/src/pagination/pagination.context.ts +0 -52
- package/src/pagination/pagination.spec.ts +0 -388
- package/src/pagination/pagination.ts +0 -288
- package/src/password-input/index.ts +0 -15
- package/src/password-input/password-input.context.ts +0 -65
- package/src/password-input/password-input.scorer.ts +0 -34
- package/src/password-input/password-input.spec.ts +0 -274
- package/src/password-input/password-input.ts +0 -488
- package/src/popover/_examples/index.ts +0 -5
- package/src/popover/_examples/popover.example.ts +0 -92
- package/src/popover/_examples/popover.finance.example.ts +0 -106
- package/src/popover/_examples/popover.retro.example.ts +0 -103
- package/src/popover/index.ts +0 -5
- package/src/popover/popover-arrow.ts +0 -30
- package/src/popover/popover-close.ts +0 -36
- package/src/popover/popover-content.ts +0 -41
- package/src/popover/popover-title.ts +0 -39
- package/src/popover/popover-trigger.ts +0 -40
- package/src/popover/popover.spec.ts +0 -59
- package/src/popover/popover.ts +0 -5
- package/src/presets/bind-presets.spec.ts +0 -50
- package/src/presets/bind-presets.ts +0 -43
- package/src/presets/index.ts +0 -3
- package/src/presets/size.spec.ts +0 -67
- package/src/presets/size.ts +0 -59
- package/src/presets/variant.spec.ts +0 -72
- package/src/presets/variant.ts +0 -62
- package/src/primitives/.gitkeep +0 -0
- package/src/primitives/directionality/directionality.spec.ts +0 -112
- package/src/primitives/directionality/directionality.ts +0 -89
- package/src/primitives/directionality/index.ts +0 -1
- package/src/primitives/forms/form-control.spec.ts +0 -67
- package/src/primitives/forms/form-control.ts +0 -94
- package/src/primitives/forms/index.ts +0 -1
- package/src/primitives/index.ts +0 -6
- package/src/primitives/interaction/disabled.spec.ts +0 -47
- package/src/primitives/interaction/disabled.ts +0 -31
- package/src/primitives/interaction/focus-ring.spec.ts +0 -62
- package/src/primitives/interaction/focus-ring.ts +0 -59
- package/src/primitives/interaction/index.ts +0 -2
- package/src/primitives/list/filterable-list.spec.ts +0 -114
- package/src/primitives/list/filterable-list.ts +0 -126
- package/src/primitives/list/group.spec.ts +0 -99
- package/src/primitives/list/group.ts +0 -139
- package/src/primitives/list/index.ts +0 -8
- package/src/primitives/list/inject-helpers.ts +0 -8
- package/src/primitives/list/item.spec.ts +0 -173
- package/src/primitives/list/item.ts +0 -222
- package/src/primitives/list/navigator.spec.ts +0 -286
- package/src/primitives/list/navigator.ts +0 -238
- package/src/primitives/list/selection.spec.ts +0 -214
- package/src/primitives/list/selection.ts +0 -339
- package/src/primitives/list/tokens.ts +0 -106
- package/src/primitives/list/type-ahead.spec.ts +0 -58
- package/src/primitives/list/type-ahead.ts +0 -46
- package/src/primitives/overlay/backdrop.spec.ts +0 -54
- package/src/primitives/overlay/backdrop.ts +0 -31
- package/src/primitives/overlay/builder.spec.ts +0 -38
- package/src/primitives/overlay/builder.ts +0 -151
- package/src/primitives/overlay/container.ts +0 -42
- package/src/primitives/overlay/context.ts +0 -14
- package/src/primitives/overlay/controller.spec.ts +0 -86
- package/src/primitives/overlay/controller.ts +0 -190
- package/src/primitives/overlay/id.spec.ts +0 -24
- package/src/primitives/overlay/id.ts +0 -17
- package/src/primitives/overlay/index.ts +0 -18
- package/src/primitives/overlay/overlay.css +0 -42
- package/src/primitives/overlay/panel.spec.ts +0 -52
- package/src/primitives/overlay/panel.ts +0 -102
- package/src/primitives/overlay/stack.spec.ts +0 -55
- package/src/primitives/overlay/stack.ts +0 -113
- package/src/primitives/overlay/strategies/backdrop/blurred.spec.ts +0 -11
- package/src/primitives/overlay/strategies/backdrop/blurred.ts +0 -5
- package/src/primitives/overlay/strategies/backdrop/none.spec.ts +0 -10
- package/src/primitives/overlay/strategies/backdrop/none.ts +0 -9
- package/src/primitives/overlay/strategies/backdrop/solid.spec.ts +0 -18
- package/src/primitives/overlay/strategies/backdrop/solid.ts +0 -23
- package/src/primitives/overlay/strategies/focus-trap/inert-based.spec.ts +0 -28
- package/src/primitives/overlay/strategies/focus-trap/inert-based.ts +0 -38
- package/src/primitives/overlay/strategies/focus-trap/no-trap.spec.ts +0 -9
- package/src/primitives/overlay/strategies/focus-trap/no-trap.ts +0 -8
- package/src/primitives/overlay/strategies/focus-trap/tab-cycle.spec.ts +0 -49
- package/src/primitives/overlay/strategies/focus-trap/tab-cycle.ts +0 -85
- package/src/primitives/overlay/strategies/index.ts +0 -34
- package/src/primitives/overlay/strategies/live-announcer/_announce.ts +0 -35
- package/src/primitives/overlay/strategies/live-announcer/assertive.spec.ts +0 -21
- package/src/primitives/overlay/strategies/live-announcer/assertive.ts +0 -11
- package/src/primitives/overlay/strategies/live-announcer/polite.spec.ts +0 -21
- package/src/primitives/overlay/strategies/live-announcer/polite.ts +0 -11
- package/src/primitives/overlay/strategies/live-announcer/silent.spec.ts +0 -12
- package/src/primitives/overlay/strategies/live-announcer/silent.ts +0 -5
- package/src/primitives/overlay/strategies/mount/body-portal.spec.ts +0 -40
- package/src/primitives/overlay/strategies/mount/body-portal.ts +0 -91
- package/src/primitives/overlay/strategies/mount/in-container.spec.ts +0 -43
- package/src/primitives/overlay/strategies/mount/in-container.ts +0 -39
- package/src/primitives/overlay/strategies/mount/in-place.spec.ts +0 -40
- package/src/primitives/overlay/strategies/mount/in-place.ts +0 -20
- package/src/primitives/overlay/strategies/position/anchored-to.spec.ts +0 -56
- package/src/primitives/overlay/strategies/position/anchored-to.ts +0 -248
- package/src/primitives/overlay/strategies/position/corner.spec.ts +0 -36
- package/src/primitives/overlay/strategies/position/corner.ts +0 -33
- package/src/primitives/overlay/strategies/position/edge-sheet.spec.ts +0 -32
- package/src/primitives/overlay/strategies/position/edge-sheet.ts +0 -36
- package/src/primitives/overlay/strategies/position/in-place-sibling.spec.ts +0 -25
- package/src/primitives/overlay/strategies/position/in-place-sibling.ts +0 -13
- package/src/primitives/overlay/strategies/position/point-at.spec.ts +0 -40
- package/src/primitives/overlay/strategies/position/point-at.ts +0 -34
- package/src/primitives/overlay/strategies/position/viewport-centered.spec.ts +0 -31
- package/src/primitives/overlay/strategies/position/viewport-centered.ts +0 -31
- package/src/primitives/overlay/strategies/scroll-lock/css-clip.spec.ts +0 -15
- package/src/primitives/overlay/strategies/scroll-lock/css-clip.ts +0 -39
- package/src/primitives/overlay/strategies/scroll-lock/html-overflow.spec.ts +0 -21
- package/src/primitives/overlay/strategies/scroll-lock/html-overflow.ts +0 -44
- package/src/primitives/overlay/strategies/scroll-lock/none.spec.ts +0 -9
- package/src/primitives/overlay/strategies/scroll-lock/none.ts +0 -5
- package/src/primitives/overlay/strategies/trigger-event/on-click.spec.ts +0 -32
- package/src/primitives/overlay/strategies/trigger-event/on-click.ts +0 -28
- package/src/primitives/overlay/strategies/trigger-event/on-context-menu.spec.ts +0 -45
- package/src/primitives/overlay/strategies/trigger-event/on-context-menu.ts +0 -70
- package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.spec.ts +0 -35
- package/src/primitives/overlay/strategies/trigger-event/on-focus-or-input.ts +0 -34
- package/src/primitives/overlay/strategies/trigger-event/on-focus.spec.ts +0 -64
- package/src/primitives/overlay/strategies/trigger-event/on-focus.ts +0 -37
- package/src/primitives/overlay/strategies/trigger-event/on-hotkey.spec.ts +0 -37
- package/src/primitives/overlay/strategies/trigger-event/on-hotkey.ts +0 -59
- package/src/primitives/overlay/strategies/trigger-event/on-hover.spec.ts +0 -34
- package/src/primitives/overlay/strategies/trigger-event/on-hover.ts +0 -86
- package/src/primitives/overlay/strategies/trigger-event/programmatic.spec.ts +0 -16
- package/src/primitives/overlay/strategies/trigger-event/programmatic.ts +0 -12
- package/src/primitives/overlay/tokens.ts +0 -54
- package/src/primitives/overlay/trigger.spec.ts +0 -103
- package/src/primitives/overlay/trigger.ts +0 -75
- package/src/primitives/overlay/types.ts +0 -24
- package/src/primitives/overlay/wrapper.ts +0 -50
- package/src/primitives/signals/deep-signal.ts +0 -109
- package/src/primitives/signals/index.ts +0 -1
- package/src/progress-bar/config.ts +0 -48
- package/src/progress-bar/index.ts +0 -12
- package/src/progress-bar/progress-bar-fill.ts +0 -37
- package/src/progress-bar/progress-bar.context.ts +0 -34
- package/src/progress-bar/progress-bar.spec.ts +0 -423
- package/src/progress-bar/progress-bar.ts +0 -217
- package/src/public-api.ts +0 -84
- package/src/radio/index.ts +0 -2
- package/src/radio/radio.context.ts +0 -3
- package/src/radio/radio.spec.ts +0 -36
- package/src/radio/radio.ts +0 -66
- package/src/select/index.ts +0 -4
- package/src/select/select-content.ts +0 -69
- package/src/select/select-option.ts +0 -35
- package/src/select/select-root.ts +0 -129
- package/src/select/select-trigger.ts +0 -93
- package/src/select/select.spec.ts +0 -138
- package/src/select/select.ts +0 -4
- package/src/skeleton/index.ts +0 -5
- package/src/skeleton/skeleton.spec.ts +0 -115
- package/src/skeleton/skeleton.ts +0 -56
- package/src/slider/index.ts +0 -10
- package/src/slider/slider-range.ts +0 -49
- package/src/slider/slider-thumb.ts +0 -335
- package/src/slider/slider-track.ts +0 -70
- package/src/slider/slider.context.ts +0 -79
- package/src/slider/slider.geometry.ts +0 -73
- package/src/slider/slider.spec.ts +0 -216
- package/src/slider/slider.ts +0 -443
- package/src/speed-dial/index.ts +0 -10
- package/src/speed-dial/speed-dial-action.ts +0 -40
- package/src/speed-dial/speed-dial-actions.ts +0 -31
- package/src/speed-dial/speed-dial-trigger.ts +0 -55
- package/src/speed-dial/speed-dial.context.ts +0 -36
- package/src/speed-dial/speed-dial.spec.ts +0 -143
- package/src/speed-dial/speed-dial.ts +0 -127
- package/src/spinner/config.ts +0 -48
- package/src/spinner/index.ts +0 -8
- package/src/spinner/spinner.spec.ts +0 -262
- package/src/spinner/spinner.ts +0 -129
- package/src/stepper/index.ts +0 -15
- package/src/stepper/stepper.context.ts +0 -63
- package/src/stepper/stepper.spec.ts +0 -403
- package/src/stepper/stepper.ts +0 -544
- package/src/styles/docs-themes.css +0 -82
- package/src/styles.css +0 -17
- package/src/table/column-helpers.spec.ts +0 -74
- package/src/table/column-helpers.ts +0 -68
- package/src/table/filter-fns.ts +0 -230
- package/src/table/filter-models.spec.ts +0 -240
- package/src/table/filter-models.ts +0 -124
- package/src/table/filter-params.ts +0 -90
- package/src/table/grid-api-impl.ts +0 -321
- package/src/table/grid-api.spec.ts +0 -178
- package/src/table/grid-api.ts +0 -285
- package/src/table/index.ts +0 -73
- package/src/table/table-cell.spec.ts +0 -43
- package/src/table/table-cell.ts +0 -38
- package/src/table/table-filter-outlet.ts +0 -120
- package/src/table/table-header.spec.ts +0 -54
- package/src/table/table-header.ts +0 -63
- package/src/table/table-keyboard.spec.ts +0 -68
- package/src/table/table-keyboard.ts +0 -107
- package/src/table/table-resource.spec.ts +0 -37
- package/src/table/table-resource.ts +0 -36
- package/src/table/table-row.spec.ts +0 -54
- package/src/table/table-row.ts +0 -31
- package/src/table/table-storage.spec.ts +0 -67
- package/src/table/table-storage.ts +0 -76
- package/src/table/table.spec.ts +0 -172
- package/src/table/table.ts +0 -281
- package/src/table/table.types.ts +0 -83
- package/src/tabs/index.ts +0 -7
- package/src/tabs/tabs.context.ts +0 -32
- package/src/tabs/tabs.spec.ts +0 -352
- package/src/tabs/tabs.ts +0 -364
- package/src/tag/config.ts +0 -53
- package/src/tag/index.ts +0 -7
- package/src/tag/tag-list.ts +0 -76
- package/src/tag/tag-remove.ts +0 -61
- package/src/tag/tag.context.ts +0 -36
- package/src/tag/tag.spec.ts +0 -240
- package/src/tag/tag.ts +0 -203
- package/src/test-setup.ts +0 -5
- package/src/textarea/config.ts +0 -42
- package/src/textarea/index.ts +0 -8
- package/src/textarea/textarea.spec.ts +0 -176
- package/src/textarea/textarea.ts +0 -235
- package/src/time-picker/index.ts +0 -15
- package/src/time-picker/time-picker-meridiem.ts +0 -123
- package/src/time-picker/time-picker-segment.ts +0 -318
- package/src/time-picker/time-picker.context.ts +0 -38
- package/src/time-picker/time-picker.format.ts +0 -181
- package/src/time-picker/time-picker.spec.ts +0 -189
- package/src/time-picker/time-picker.ts +0 -274
- package/src/toast/_examples/index.ts +0 -5
- package/src/toast/_examples/toast.example.ts +0 -282
- package/src/toast/_examples/toast.finance.example.ts +0 -180
- package/src/toast/_examples/toast.retro.example.ts +0 -161
- package/src/toast/index.ts +0 -28
- package/src/toast/toast.ref.ts +0 -26
- package/src/toast/toast.service.ts +0 -339
- package/src/toast/toast.spec.ts +0 -247
- package/src/toast/toast.strategy.ts +0 -112
- package/src/toast/toast.ts +0 -463
- package/src/toast/toast.types.ts +0 -5
- package/src/toggle/index.ts +0 -1
- package/src/toggle/toggle.spec.ts +0 -24
- package/src/toggle/toggle.ts +0 -48
- package/src/tooltip/_examples/index.ts +0 -6
- package/src/tooltip/_examples/tooltip.example.ts +0 -82
- package/src/tooltip/_examples/tooltip.finance.example.ts +0 -97
- package/src/tooltip/_examples/tooltip.placements.example.ts +0 -83
- package/src/tooltip/_examples/tooltip.retro.example.ts +0 -107
- package/src/tooltip/index.ts +0 -4
- package/src/tooltip/tooltip-arrow.ts +0 -31
- package/src/tooltip/tooltip-content.ts +0 -38
- package/src/tooltip/tooltip-group.ts +0 -32
- package/src/tooltip/tooltip-trigger.ts +0 -47
- package/src/tooltip/tooltip.spec.ts +0 -40
- package/src/tooltip/tooltip.ts +0 -5
- package/src/tree-select/index.ts +0 -12
- package/src/tree-select/tree-select-content.ts +0 -199
- package/src/tree-select/tree-select-node.ts +0 -132
- package/src/tree-select/tree-select-root.ts +0 -272
- package/src/tree-select/tree-select-trigger.ts +0 -90
- package/src/tree-select/tree-select.context.ts +0 -63
- package/src/tree-select/tree-select.spec.ts +0 -433
- package/src/tree-select/tree-select.ts +0 -2
- package/src/typography/blockquote.ts +0 -57
- package/src/typography/code.ts +0 -53
- package/src/typography/index.ts +0 -22
- package/src/typography/lead.ts +0 -49
- package/src/typography/muted.ts +0 -29
- package/src/typography/truncate.ts +0 -99
- package/src/typography/typography.spec.ts +0 -203
- package/tsconfig.lib.json +0 -21
- package/tsconfig.lib.prod.json +0 -17
- package/tsconfig.spec.json +0 -18
- package/vite.config.ts +0 -27
- /package/{src/icon → icon}/icon.css +0 -0
- /package/{src/typography → typography}/prose.css +0 -0
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { Component, signal } from '@angular/core';
|
|
2
|
-
import { render, fireEvent } from '@testing-library/angular';
|
|
3
|
-
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
4
|
-
import {
|
|
5
|
-
KjAccordion,
|
|
6
|
-
KjAccordionItem,
|
|
7
|
-
KjAccordionTrigger,
|
|
8
|
-
KjAccordionContent,
|
|
9
|
-
} from './accordion';
|
|
10
|
-
|
|
11
|
-
expect.extend(toHaveNoViolations);
|
|
12
|
-
|
|
13
|
-
const imports = [KjAccordion, KjAccordionItem, KjAccordionTrigger, KjAccordionContent];
|
|
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
|
-
`;
|
|
27
|
-
|
|
28
|
-
describe('KjAccordion', () => {
|
|
29
|
-
it('content hidden by default', async () => {
|
|
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
|
-
});
|
|
241
|
-
});
|
|
242
|
-
});
|
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Directive,
|
|
3
|
-
ElementRef,
|
|
4
|
-
OnDestroy,
|
|
5
|
-
OnInit,
|
|
6
|
-
Signal,
|
|
7
|
-
booleanAttribute,
|
|
8
|
-
computed,
|
|
9
|
-
effect,
|
|
10
|
-
inject,
|
|
11
|
-
input,
|
|
12
|
-
model,
|
|
13
|
-
signal,
|
|
14
|
-
untracked,
|
|
15
|
-
} from '@angular/core';
|
|
16
|
-
import {
|
|
17
|
-
KJ_ACCORDION,
|
|
18
|
-
KJ_ACCORDION_ITEM,
|
|
19
|
-
KjAccordionContext,
|
|
20
|
-
KjAccordionItemContext,
|
|
21
|
-
KjAccordionType,
|
|
22
|
-
} from './accordion.context';
|
|
23
|
-
|
|
24
|
-
let kjAccordionSeedCounter = 0;
|
|
25
|
-
function nextSeed(): string {
|
|
26
|
-
// Try crypto.randomUUID where available (browser, jsdom 22+, node 19+).
|
|
27
|
-
// Fall back to a counter so SSR / older environments still produce a stable string.
|
|
28
|
-
const cryptoLike = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;
|
|
29
|
-
if (cryptoLike?.randomUUID) return cryptoLike.randomUUID().slice(0, 8);
|
|
30
|
-
return `kj${(++kjAccordionSeedCounter).toString(36)}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Root accordion container. Manages open/close state for accordion items.
|
|
35
|
-
* Supports `'single'` (only one item open) or `'multiple'` (any number open).
|
|
36
|
-
*
|
|
37
|
-
* Two-way bound `kjValue` mirrors the open set as a string (single mode) or
|
|
38
|
-
* `string[]` (multiple mode). Internally the directive keeps a single
|
|
39
|
-
* `ReadonlySet<string>` so single ↔ multiple flips don't lose state.
|
|
40
|
-
*
|
|
41
|
-
* Arrow-key roving navigation is opt-in via `kjArrowNavigation`; when enabled
|
|
42
|
-
* the root listens for ArrowUp/ArrowDown/Home/End on registered triggers and
|
|
43
|
-
* moves focus between them. When disabled (the default) each trigger is a
|
|
44
|
-
* plain button in the page tab sequence — the WAI-ARIA APG-recommended
|
|
45
|
-
* arrangement for FAQ-style content.
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```html
|
|
49
|
-
* <div kjAccordion [(kjValue)]="open" kjType="multiple">
|
|
50
|
-
* <div kjAccordionItem kjItemValue="billing">
|
|
51
|
-
* <button kjAccordionTrigger>Billing</button>
|
|
52
|
-
* <div kjAccordionContent>...</div>
|
|
53
|
-
* </div>
|
|
54
|
-
* </div>
|
|
55
|
-
* ```
|
|
56
|
-
* @doc-category Core/Data display
|
|
57
|
-
* @doc
|
|
58
|
-
* @doc-name accordion
|
|
59
|
-
* @doc-description Unstyled accordion root that manages expand/collapse state across child accordion items.
|
|
60
|
-
* @doc-is-main
|
|
61
|
-
*/
|
|
62
|
-
@Directive({
|
|
63
|
-
selector: '[kjAccordion]',
|
|
64
|
-
standalone: true,
|
|
65
|
-
providers: [{ provide: KJ_ACCORDION, useExisting: KjAccordion }],
|
|
66
|
-
host: {
|
|
67
|
-
'[attr.data-orientation]': '"vertical"',
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
export class KjAccordion implements KjAccordionContext {
|
|
71
|
-
/** Mode: `'single'` (one open at a time) or `'multiple'` (any number open). */
|
|
72
|
-
readonly kjType = input<KjAccordionType>('single');
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Two-way bound open value. In `'single'` mode it is a string (the open
|
|
76
|
-
* item's value, or `''` when nothing is open); in `'multiple'` mode it is a
|
|
77
|
-
* `string[]` (open item values, in insertion order).
|
|
78
|
-
*/
|
|
79
|
-
readonly kjValue = model<string | string[]>('');
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Opt-in roving tabindex on triggers. When `true`, ArrowUp/ArrowDown/Home/End
|
|
83
|
-
* move focus between triggers and the group becomes a single tab stop.
|
|
84
|
-
* When `false` (default), each trigger is a plain button in the page tab
|
|
85
|
-
* sequence — the simpler arrangement for FAQ-style content where Tab also
|
|
86
|
-
* needs to reach links and form fields inside an open panel.
|
|
87
|
-
*/
|
|
88
|
-
readonly kjArrowNavigation = input(false, { transform: booleanAttribute });
|
|
89
|
-
|
|
90
|
-
private readonly _openIds = signal<ReadonlySet<string>>(new Set());
|
|
91
|
-
/** Set of currently open item values. */
|
|
92
|
-
readonly openIds = this._openIds.asReadonly();
|
|
93
|
-
|
|
94
|
-
/** Read-only view of `kjType` for context consumers. */
|
|
95
|
-
readonly type: Signal<KjAccordionType> = this.kjType;
|
|
96
|
-
|
|
97
|
-
/** Read-only view of `kjArrowNavigation` for context consumers. */
|
|
98
|
-
readonly arrowNavigation: Signal<boolean> = this.kjArrowNavigation;
|
|
99
|
-
|
|
100
|
-
/** @internal Registered triggers in document order — for arrow-key roving. */
|
|
101
|
-
private readonly _triggers = signal<readonly KjAccordionTrigger[]>([]);
|
|
102
|
-
|
|
103
|
-
/** Public read-only registration list, in document order. */
|
|
104
|
-
readonly triggers = this._triggers.asReadonly();
|
|
105
|
-
|
|
106
|
-
constructor() {
|
|
107
|
-
// Reconcile incoming kjValue → internal _openIds (controlled binding).
|
|
108
|
-
effect(() => {
|
|
109
|
-
const v = this.kjValue();
|
|
110
|
-
const next = new Set<string>();
|
|
111
|
-
if (typeof v === 'string') {
|
|
112
|
-
if (v) next.add(v);
|
|
113
|
-
} else if (Array.isArray(v)) {
|
|
114
|
-
for (const id of v) if (id) next.add(id);
|
|
115
|
-
}
|
|
116
|
-
// In single mode, only first wins.
|
|
117
|
-
if (this.kjType() === 'single' && next.size > 1) {
|
|
118
|
-
const [first] = next;
|
|
119
|
-
next.clear();
|
|
120
|
-
next.add(first);
|
|
121
|
-
}
|
|
122
|
-
// Avoid set-equal write loops with the toggle path.
|
|
123
|
-
const current = untracked(this._openIds);
|
|
124
|
-
if (!setsEqual(current, next)) this._openIds.set(next);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Toggles an item open or closed. In single mode, closes all others first. */
|
|
129
|
-
toggle(id: string): void {
|
|
130
|
-
const next = new Set(this._openIds());
|
|
131
|
-
if (next.has(id)) {
|
|
132
|
-
next.delete(id);
|
|
133
|
-
} else {
|
|
134
|
-
if (this.kjType() === 'single') next.clear();
|
|
135
|
-
next.add(id);
|
|
136
|
-
}
|
|
137
|
-
this._openIds.set(next);
|
|
138
|
-
this.syncModelFromSet(next);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** Returns whether the given item value is currently open. */
|
|
142
|
-
isOpen(id: string): boolean {
|
|
143
|
-
return this._openIds().has(id);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** @internal Trigger registration — called from `KjAccordionTrigger.ngOnInit`. */
|
|
147
|
-
registerTrigger(t: KjAccordionTrigger): void {
|
|
148
|
-
this._triggers.update((list) => (list.includes(t) ? list : [...list, t]));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** @internal Trigger un-registration — called from `KjAccordionTrigger.ngOnDestroy`. */
|
|
152
|
-
unregisterTrigger(t: KjAccordionTrigger): void {
|
|
153
|
-
this._triggers.update((list) => list.filter((x) => x !== t));
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** @internal Move focus by delta among non-disabled triggers. */
|
|
157
|
-
focusTrigger(delta: number, fromIndex: number): void {
|
|
158
|
-
const list = this._triggers();
|
|
159
|
-
if (!list.length) return;
|
|
160
|
-
const len = list.length;
|
|
161
|
-
let i = fromIndex;
|
|
162
|
-
for (let step = 0; step < len; step++) {
|
|
163
|
-
i = (i + delta + len) % len;
|
|
164
|
-
const t = list[i];
|
|
165
|
-
if (!t.item.disabled()) {
|
|
166
|
-
t.el.nativeElement.focus();
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** @internal Focus first / last non-disabled trigger. */
|
|
173
|
-
focusEdge(edge: 'first' | 'last'): void {
|
|
174
|
-
const list = this._triggers();
|
|
175
|
-
if (!list.length) return;
|
|
176
|
-
const range = edge === 'first' ? list : [...list].reverse();
|
|
177
|
-
for (const t of range) {
|
|
178
|
-
if (!t.item.disabled()) {
|
|
179
|
-
t.el.nativeElement.focus();
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
private syncModelFromSet(set: ReadonlySet<string>): void {
|
|
186
|
-
if (this.kjType() === 'single') {
|
|
187
|
-
const first = set.values().next().value ?? '';
|
|
188
|
-
const current = this.kjValue();
|
|
189
|
-
if (typeof current === 'string') {
|
|
190
|
-
if (current !== first) this.kjValue.set(first);
|
|
191
|
-
} else {
|
|
192
|
-
this.kjValue.set(first);
|
|
193
|
-
}
|
|
194
|
-
} else {
|
|
195
|
-
const arr = Array.from(set);
|
|
196
|
-
const current = this.kjValue();
|
|
197
|
-
if (Array.isArray(current) && arraysEqual(current, arr)) return;
|
|
198
|
-
this.kjValue.set(arr);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function setsEqual(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean {
|
|
204
|
-
if (a.size !== b.size) return false;
|
|
205
|
-
for (const v of a) if (!b.has(v)) return false;
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function arraysEqual(a: readonly string[], b: readonly string[]): boolean {
|
|
210
|
-
if (a.length !== b.length) return false;
|
|
211
|
-
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Individual accordion item. Owns the per-item `value`, `expanded` state, and
|
|
217
|
-
* the stable `headerId` / `contentId` pair the trigger and content use to wire
|
|
218
|
-
* `aria-controls` / `aria-labelledby`.
|
|
219
|
-
*
|
|
220
|
-
* @example
|
|
221
|
-
* ```html
|
|
222
|
-
* <div kjAccordionItem kjItemValue="section-1">
|
|
223
|
-
* <button kjAccordionTrigger>Section 1</button>
|
|
224
|
-
* <div kjAccordionContent>Content</div>
|
|
225
|
-
* </div>
|
|
226
|
-
* ```
|
|
227
|
-
* @doc-category Core/Data display
|
|
228
|
-
* @doc
|
|
229
|
-
* @doc-name accordion
|
|
230
|
-
*/
|
|
231
|
-
@Directive({
|
|
232
|
-
selector: '[kjAccordionItem]',
|
|
233
|
-
standalone: true,
|
|
234
|
-
providers: [{ provide: KJ_ACCORDION_ITEM, useExisting: KjAccordionItem }],
|
|
235
|
-
host: {
|
|
236
|
-
'[attr.data-state]': 'expanded() ? "open" : "closed"',
|
|
237
|
-
'[attr.data-disabled]': 'kjItemDisabled() ? "" : null',
|
|
238
|
-
},
|
|
239
|
-
})
|
|
240
|
-
export class KjAccordionItem implements KjAccordionItemContext {
|
|
241
|
-
private readonly accordion = inject(KJ_ACCORDION) as KjAccordion;
|
|
242
|
-
|
|
243
|
-
/** The unique value identifying this item within the accordion. */
|
|
244
|
-
readonly kjItemValue = input.required<string>();
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Whether this item is disabled. Gates `toggle`/`open`/`close`, drives
|
|
248
|
-
* `aria-disabled` on the trigger and `data-disabled` on the item host.
|
|
249
|
-
*/
|
|
250
|
-
readonly kjItemDisabled = input(false, { transform: booleanAttribute });
|
|
251
|
-
|
|
252
|
-
private readonly idSeed = nextSeed();
|
|
253
|
-
|
|
254
|
-
/** Stable id for the trigger element. */
|
|
255
|
-
readonly headerId = computed(() => `kj-accordion-trigger-${this.kjItemValue()}-${this.idSeed}`);
|
|
256
|
-
|
|
257
|
-
/** Stable id for the content region element. */
|
|
258
|
-
readonly contentId = computed(() => `kj-accordion-content-${this.kjItemValue()}-${this.idSeed}`);
|
|
259
|
-
|
|
260
|
-
/** Read-only mirror of the item value for context consumers. */
|
|
261
|
-
readonly value: Signal<string> = this.kjItemValue;
|
|
262
|
-
|
|
263
|
-
/** Read-only mirror of the disabled flag for context consumers. */
|
|
264
|
-
readonly disabled: Signal<boolean> = this.kjItemDisabled;
|
|
265
|
-
|
|
266
|
-
/** Whether this item is currently expanded. */
|
|
267
|
-
readonly expanded = computed(() => this.accordion.isOpen(this.kjItemValue()));
|
|
268
|
-
|
|
269
|
-
/** Toggles this item's expanded state. No-op when disabled. */
|
|
270
|
-
toggle(): void {
|
|
271
|
-
if (this.kjItemDisabled()) return;
|
|
272
|
-
this.accordion.toggle(this.kjItemValue());
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/** Opens this item. No-op when disabled. */
|
|
276
|
-
open(): void {
|
|
277
|
-
if (this.kjItemDisabled()) return;
|
|
278
|
-
if (!this.expanded()) this.accordion.toggle(this.kjItemValue());
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/** Closes this item. No-op when disabled. */
|
|
282
|
-
close(): void {
|
|
283
|
-
if (this.kjItemDisabled()) return;
|
|
284
|
-
if (this.expanded()) this.accordion.toggle(this.kjItemValue());
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Trigger button for an accordion item. Wires `aria-expanded`, `aria-controls`,
|
|
290
|
-
* `aria-disabled`, and the click toggle. Also provides Enter / Space / arrow
|
|
291
|
-
* key handling — arrow keys are gated on the root's `kjArrowNavigation` flag.
|
|
292
|
-
*
|
|
293
|
-
* The host element should be a `<button>` per WAI-ARIA APG so Enter / Space
|
|
294
|
-
* activation, focus, and disabled semantics work without extra wiring.
|
|
295
|
-
*
|
|
296
|
-
* @example
|
|
297
|
-
* ```html
|
|
298
|
-
* <button kjAccordionTrigger>Section title</button>
|
|
299
|
-
* ```
|
|
300
|
-
* @doc-category Core/Data display
|
|
301
|
-
* @doc
|
|
302
|
-
* @doc-name accordion
|
|
303
|
-
*/
|
|
304
|
-
@Directive({
|
|
305
|
-
selector: '[kjAccordionTrigger]',
|
|
306
|
-
standalone: true,
|
|
307
|
-
host: {
|
|
308
|
-
'[attr.id]': 'item.headerId()',
|
|
309
|
-
'[attr.aria-expanded]': 'item.expanded() ? "true" : "false"',
|
|
310
|
-
'[attr.aria-controls]': 'item.contentId()',
|
|
311
|
-
'[attr.aria-disabled]': 'item.disabled() ? "true" : null',
|
|
312
|
-
'[attr.data-state]': 'item.expanded() ? "open" : "closed"',
|
|
313
|
-
'[attr.data-open]': 'item.expanded() ? "" : null',
|
|
314
|
-
'[attr.data-disabled]': 'item.disabled() ? "" : null',
|
|
315
|
-
'(click)': 'onClick()',
|
|
316
|
-
'(keydown)': 'onKeydown($event)',
|
|
317
|
-
},
|
|
318
|
-
})
|
|
319
|
-
export class KjAccordionTrigger implements OnInit, OnDestroy {
|
|
320
|
-
/** The parent accordion item context. */
|
|
321
|
-
readonly item = inject(KJ_ACCORDION_ITEM) as KjAccordionItem;
|
|
322
|
-
private readonly accordion = inject(KJ_ACCORDION) as KjAccordion;
|
|
323
|
-
/** @internal Native host element. */
|
|
324
|
-
readonly el = inject<ElementRef<HTMLElement>>(ElementRef);
|
|
325
|
-
|
|
326
|
-
ngOnInit(): void {
|
|
327
|
-
this.accordion.registerTrigger(this);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
ngOnDestroy(): void {
|
|
331
|
-
this.accordion.unregisterTrigger(this);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** @internal Click handler. */
|
|
335
|
-
onClick(): void {
|
|
336
|
-
if (this.item.disabled()) return;
|
|
337
|
-
this.item.toggle();
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/** @internal Keydown handler — arrow-nav opt-in via `kjArrowNavigation` on the root. */
|
|
341
|
-
onKeydown(event: KeyboardEvent): void {
|
|
342
|
-
if (!this.accordion.arrowNavigation()) return;
|
|
343
|
-
const list = this.accordion.triggers();
|
|
344
|
-
const idx = list.indexOf(this);
|
|
345
|
-
if (idx === -1) return;
|
|
346
|
-
switch (event.key) {
|
|
347
|
-
case 'ArrowDown':
|
|
348
|
-
event.preventDefault();
|
|
349
|
-
this.accordion.focusTrigger(1, idx);
|
|
350
|
-
return;
|
|
351
|
-
case 'ArrowUp':
|
|
352
|
-
event.preventDefault();
|
|
353
|
-
this.accordion.focusTrigger(-1, idx);
|
|
354
|
-
return;
|
|
355
|
-
case 'Home':
|
|
356
|
-
event.preventDefault();
|
|
357
|
-
this.accordion.focusEdge('first');
|
|
358
|
-
return;
|
|
359
|
-
case 'End':
|
|
360
|
-
event.preventDefault();
|
|
361
|
-
this.accordion.focusEdge('last');
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Accordion content panel. Hosts `role="region"` + `aria-labelledby` to the
|
|
369
|
-
* trigger's id. Visibility is signalled via `[data-state]` (`"open"` /
|
|
370
|
-
* `"closed"`) so consumers can CSS-animate the open/close transition. While
|
|
371
|
-
* closed, `aria-hidden="true"` and `inert` keep the panel out of the AT tree
|
|
372
|
-
* and tab sequence — the element stays in the DOM rather than being removed
|
|
373
|
-
* with `hidden`, which would interrupt the animation.
|
|
374
|
-
*
|
|
375
|
-
* @example
|
|
376
|
-
* ```html
|
|
377
|
-
* <div kjAccordionContent>Panel content</div>
|
|
378
|
-
* ```
|
|
379
|
-
* @doc-category Core/Data display
|
|
380
|
-
* @doc
|
|
381
|
-
* @doc-name accordion
|
|
382
|
-
*/
|
|
383
|
-
@Directive({
|
|
384
|
-
selector: '[kjAccordionContent]',
|
|
385
|
-
standalone: true,
|
|
386
|
-
host: {
|
|
387
|
-
'[attr.role]': '"region"',
|
|
388
|
-
'[attr.id]': 'item.contentId()',
|
|
389
|
-
'[attr.aria-labelledby]': 'item.headerId()',
|
|
390
|
-
'[attr.data-state]': 'item.expanded() ? "open" : "closed"',
|
|
391
|
-
// `aria-hidden` keeps the closed panel out of the AT tree while leaving
|
|
392
|
-
// the element in the DOM so CSS can animate its open/close transition
|
|
393
|
-
// (driven by [data-state]). The visual hide is owned by the component CSS.
|
|
394
|
-
'[attr.aria-hidden]': '!item.expanded() ? "true" : null',
|
|
395
|
-
'[attr.inert]': '!item.expanded() ? "" : null',
|
|
396
|
-
},
|
|
397
|
-
})
|
|
398
|
-
export class KjAccordionContent {
|
|
399
|
-
/** The parent accordion item context. */
|
|
400
|
-
readonly item = inject(KJ_ACCORDION_ITEM);
|
|
401
|
-
}
|
package/src/accordion/index.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { InjectionToken, Signal } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Resolved alert mode after applying the matrix. See `alert.md` for the
|
|
5
|
-
* full role/aria-live mapping.
|
|
6
|
-
*/
|
|
7
|
-
export type KjAlertMode = 'assertive' | 'polite' | 'static' | 'off';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Context exposed by `KjAlert` to its descendant directives via the
|
|
11
|
-
* `KJ_ALERT` injection token. Title/description register their generated
|
|
12
|
-
* ids so the root can reflect `aria-labelledby` / `aria-describedby`.
|
|
13
|
-
*/
|
|
14
|
-
export interface KjAlertContext {
|
|
15
|
-
readonly alertId: Signal<string>;
|
|
16
|
-
readonly variant: Signal<string>;
|
|
17
|
-
readonly mode: Signal<KjAlertMode>;
|
|
18
|
-
readonly titleId: Signal<string | null>;
|
|
19
|
-
readonly descriptionId: Signal<string | null>;
|
|
20
|
-
registerTitle(id: string): void;
|
|
21
|
-
unregisterTitle(id: string): void;
|
|
22
|
-
registerDescription(id: string): void;
|
|
23
|
-
unregisterDescription(id: string): void;
|
|
24
|
-
dismiss(): void;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** DI token for the alert context — provided by `KjAlert`. */
|
|
28
|
-
export const KJ_ALERT = new InjectionToken<KjAlertContext>('KjAlert');
|