@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
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Directive,
|
|
3
|
+
ElementRef,
|
|
4
|
+
Signal,
|
|
5
|
+
computed,
|
|
6
|
+
effect,
|
|
7
|
+
inject,
|
|
8
|
+
input,
|
|
9
|
+
model,
|
|
10
|
+
signal,
|
|
11
|
+
} from '@angular/core';
|
|
12
|
+
import {
|
|
13
|
+
KjRovingTabindex,
|
|
14
|
+
KjRovingTabindexItemDirective,
|
|
15
|
+
} from '../a11y/roving-tabindex';
|
|
16
|
+
import {
|
|
17
|
+
KJ_STEP,
|
|
18
|
+
KJ_STEPPER,
|
|
19
|
+
KjStepContext,
|
|
20
|
+
KjStepperContext,
|
|
21
|
+
} from './stepper.context';
|
|
22
|
+
|
|
23
|
+
// TODO(progress-bar): when the Progress Bar primitive lands at
|
|
24
|
+
// `packages/core/src/feedback/progress-bar/`, expose `progressFraction()`
|
|
25
|
+
// and `progressLabel()` computed signals on `KjStepperComponent`-shaped
|
|
26
|
+
// wrappers. The directive layer here intentionally stays out of the
|
|
27
|
+
// progress-bar composition — that's a wrapper concern.
|
|
28
|
+
|
|
29
|
+
let _stepperUid = 0;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Root of the Stepper directive family. Owns the active-step state machine,
|
|
33
|
+
* registers child `KjStep` directives, and provides {@link KJ_STEPPER}.
|
|
34
|
+
*
|
|
35
|
+
* Applied to an `<ol>`. Uses APG wizard semantics — `aria-current="step"`
|
|
36
|
+
* on the active step, *not* `role="tablist"` / `aria-selected`.
|
|
37
|
+
*
|
|
38
|
+
* Roving tabindex is composed via {@link KjRovingTabindex} with the
|
|
39
|
+
* orientation fed from `kjOrientation`. When `kjArrowNavigation=false`
|
|
40
|
+
* the roving directive is still applied but receives no items, so it
|
|
41
|
+
* is a no-op.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```html
|
|
45
|
+
* <ol kjStepper [(kjActiveStep)]="step">
|
|
46
|
+
* <li kjStep>
|
|
47
|
+
* <button kjStepLabel>Account</button>
|
|
48
|
+
* <section kjStepContent>...</section>
|
|
49
|
+
* </li>
|
|
50
|
+
* <li kjStep>
|
|
51
|
+
* <button kjStepLabel>Profile</button>
|
|
52
|
+
* <section kjStepContent>...</section>
|
|
53
|
+
* </li>
|
|
54
|
+
* <button kjStepperPrevious>Back</button>
|
|
55
|
+
* <button kjStepperNext>Continue</button>
|
|
56
|
+
* </ol>
|
|
57
|
+
* ```
|
|
58
|
+
* @doc-category Core/Navigation
|
|
59
|
+
* @doc
|
|
60
|
+
* @doc-name stepper
|
|
61
|
+
* @doc-description Unstyled multi-step wizard root with active-step state, linear-mode gating, and keyboard navigation.
|
|
62
|
+
* @doc-is-main
|
|
63
|
+
*/
|
|
64
|
+
@Directive({
|
|
65
|
+
selector: '[kjStepper]',
|
|
66
|
+
standalone: true,
|
|
67
|
+
exportAs: 'kjStepper',
|
|
68
|
+
hostDirectives: [
|
|
69
|
+
{
|
|
70
|
+
directive: KjRovingTabindex,
|
|
71
|
+
inputs: ['kjRovingOrientation: kjOrientation'],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
providers: [{ provide: KJ_STEPPER, useExisting: KjStepper }],
|
|
75
|
+
host: {
|
|
76
|
+
// No `role` override — `<ol>` carries `list` semantics natively. We do
|
|
77
|
+
// not bind `aria-orientation` because `aria-allowed-attr` rejects it on
|
|
78
|
+
// the implicit `list` role; the keyboard axis is enforced via
|
|
79
|
+
// `KjRovingTabindex`'s `kjRovingOrientation` and themes read
|
|
80
|
+
// `data-orientation` for visual layout.
|
|
81
|
+
'[attr.data-orientation]': 'orientation()',
|
|
82
|
+
'[attr.data-linear]': 'linear() ? "true" : null',
|
|
83
|
+
'[attr.data-active-step]': 'activeStep()',
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
export class KjStepper implements KjStepperContext {
|
|
87
|
+
/** Two-way bound active-step pointer (0-based). */
|
|
88
|
+
readonly kjActiveStep = model<number>(0);
|
|
89
|
+
|
|
90
|
+
/** Linear-mode flag. Linear gates forward jumps on prior-step completion. */
|
|
91
|
+
readonly kjLinear = input<boolean>(false);
|
|
92
|
+
|
|
93
|
+
/** Stepper orientation. Drives `aria-orientation` and the arrow-key axis. */
|
|
94
|
+
readonly kjOrientation = input<'horizontal' | 'vertical'>('horizontal');
|
|
95
|
+
|
|
96
|
+
/** When true, `next()` from the last step wraps to 0; `previous()` from 0 wraps to last. */
|
|
97
|
+
readonly kjLoop = input<boolean>(false);
|
|
98
|
+
|
|
99
|
+
/** Whether `reset()` should also emit `(kjReset)` so consumers can clear per-step signals. */
|
|
100
|
+
readonly kjResetStepStates = input<boolean>(false);
|
|
101
|
+
|
|
102
|
+
/** Whether to enable arrow-key roving across step headers. */
|
|
103
|
+
readonly kjArrowNavigation = input<boolean>(true);
|
|
104
|
+
|
|
105
|
+
/** Stable id for this stepper instance, used to namespace step ids. */
|
|
106
|
+
readonly stepperId = `kj-stepper-${++_stepperUid}`;
|
|
107
|
+
|
|
108
|
+
private readonly _steps = signal<readonly KjStepContext[]>([]);
|
|
109
|
+
private readonly _navigationSource = signal<'click' | 'command' | 'programmatic'>(
|
|
110
|
+
'programmatic',
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
/** @internal — read-only view of registered steps in registration order. */
|
|
114
|
+
readonly steps = this._steps.asReadonly();
|
|
115
|
+
|
|
116
|
+
/** @internal — read by `KjStepLabel` to decide focus behaviour. */
|
|
117
|
+
readonly navigationSource = this._navigationSource.asReadonly();
|
|
118
|
+
|
|
119
|
+
/** Active-step index (0-based). */
|
|
120
|
+
readonly activeStep: Signal<number> = computed(() => this.kjActiveStep());
|
|
121
|
+
|
|
122
|
+
/** Total registered step count. */
|
|
123
|
+
readonly totalSteps: Signal<number> = computed(() => this._steps().length);
|
|
124
|
+
|
|
125
|
+
/** Linear-mode flag (signal mirror). */
|
|
126
|
+
readonly linear: Signal<boolean> = computed(() => this.kjLinear());
|
|
127
|
+
|
|
128
|
+
/** Orientation (signal mirror). */
|
|
129
|
+
readonly orientation: Signal<'horizontal' | 'vertical'> = computed(() =>
|
|
130
|
+
this.kjOrientation(),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
/** True when `next()` will succeed under the current mode and state. */
|
|
134
|
+
readonly canAdvance: Signal<boolean> = computed(() => {
|
|
135
|
+
const steps = this._steps();
|
|
136
|
+
const total = steps.length;
|
|
137
|
+
if (total === 0) return false;
|
|
138
|
+
const idx = this.kjActiveStep();
|
|
139
|
+
const atEnd = idx >= total - 1;
|
|
140
|
+
if (atEnd && !this.kjLoop()) return false;
|
|
141
|
+
if (!this.kjLinear()) return true;
|
|
142
|
+
const current = steps[idx];
|
|
143
|
+
if (!current) return false;
|
|
144
|
+
return current.completed() || current.optional();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
/** True when `previous()` will succeed. */
|
|
148
|
+
readonly canRetreat: Signal<boolean> = computed(() => {
|
|
149
|
+
const total = this.totalSteps();
|
|
150
|
+
if (total === 0) return false;
|
|
151
|
+
if (this.activeStep() > 0) return true;
|
|
152
|
+
return this.kjLoop();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
constructor() {
|
|
156
|
+
// Two-way binding sync: clamp out-of-range writes silently. The clamped
|
|
157
|
+
// value is in-range, so the effect re-runs once and stabilises.
|
|
158
|
+
effect(() => {
|
|
159
|
+
const v = this.kjActiveStep();
|
|
160
|
+
const total = this.totalSteps();
|
|
161
|
+
if (total === 0) return;
|
|
162
|
+
if (v < 0) {
|
|
163
|
+
this.kjActiveStep.set(0);
|
|
164
|
+
} else if (v >= total) {
|
|
165
|
+
this.kjActiveStep.set(total - 1);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** @internal */
|
|
171
|
+
register(step: KjStepContext): void {
|
|
172
|
+
this._steps.update((steps) => [...steps, step]);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @internal */
|
|
176
|
+
unregister(step: KjStepContext): void {
|
|
177
|
+
this._steps.update((steps) => steps.filter((s) => s !== step));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @internal — reachability under linear gating. */
|
|
181
|
+
isReachable(index: number): boolean {
|
|
182
|
+
if (!this.kjLinear()) return true;
|
|
183
|
+
const active = this.kjActiveStep();
|
|
184
|
+
if (index <= active) return true;
|
|
185
|
+
const steps = this._steps();
|
|
186
|
+
// For any forward jump, every step strictly before `index` must be
|
|
187
|
+
// completed or optional. This subsumes the "+1" case (only the active
|
|
188
|
+
// step matters then, since steps before it are necessarily completed
|
|
189
|
+
// in a well-formed linear flow — and if they aren't, the user can't
|
|
190
|
+
// be there in the first place).
|
|
191
|
+
for (let i = 0; i < index; i++) {
|
|
192
|
+
const s = steps[i];
|
|
193
|
+
if (!s) return false;
|
|
194
|
+
if (!s.completed() && !s.optional()) return false;
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Advance one step. No-op when `canAdvance()` is false. */
|
|
200
|
+
next(): void {
|
|
201
|
+
if (!this.canAdvance()) return;
|
|
202
|
+
this._navigationSource.set('command');
|
|
203
|
+
const total = this.totalSteps();
|
|
204
|
+
const idx = this.activeStep();
|
|
205
|
+
const nextIdx = idx >= total - 1 ? (this.kjLoop() ? 0 : idx) : idx + 1;
|
|
206
|
+
this.kjActiveStep.set(nextIdx);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Retreat one step. No-op when `canRetreat()` is false. */
|
|
210
|
+
previous(): void {
|
|
211
|
+
if (!this.canRetreat()) return;
|
|
212
|
+
this._navigationSource.set('command');
|
|
213
|
+
const idx = this.activeStep();
|
|
214
|
+
const total = this.totalSteps();
|
|
215
|
+
const prevIdx = idx === 0 ? (this.kjLoop() ? total - 1 : 0) : idx - 1;
|
|
216
|
+
this.kjActiveStep.set(prevIdx);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Jump to a specific index. Subject to linear-mode gating. */
|
|
220
|
+
goTo(index: number): void {
|
|
221
|
+
const total = this.totalSteps();
|
|
222
|
+
if (total === 0) return;
|
|
223
|
+
if (index < 0 || index >= total) return;
|
|
224
|
+
if (!this.isReachable(index)) return;
|
|
225
|
+
this._navigationSource.set('click');
|
|
226
|
+
this.kjActiveStep.set(index);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Jump to the step whose `kjStepKey` matches. First match wins. */
|
|
230
|
+
goToKey(key: string): void {
|
|
231
|
+
const steps = this._steps();
|
|
232
|
+
const idx = steps.findIndex((s) => s.key() === key);
|
|
233
|
+
if (idx === -1) return;
|
|
234
|
+
this.goTo(idx);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Reset to step 0. Consumer is responsible for clearing per-step state when `kjResetStepStates=true`. */
|
|
238
|
+
reset(): void {
|
|
239
|
+
this._navigationSource.set('command');
|
|
240
|
+
this.kjActiveStep.set(0);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let _stepUid = 0;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Individual step within a {@link KjStepper}. Registers with the parent on
|
|
248
|
+
* construction, exposes per-step state (`completed`, `error`, `optional`,
|
|
249
|
+
* `disabled`, `reachable`, `active`) via {@link KJ_STEP}, and host-binds
|
|
250
|
+
* `aria-current="step"` when active.
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```html
|
|
254
|
+
* <li kjStep [kjStepCompleted]="form.valid()" [kjStepError]="form.invalid() && form.touched()">
|
|
255
|
+
* <button kjStepLabel>Profile</button>
|
|
256
|
+
* <section kjStepContent>...</section>
|
|
257
|
+
* </li>
|
|
258
|
+
* ```
|
|
259
|
+
* @doc-category Core/Navigation
|
|
260
|
+
* @doc
|
|
261
|
+
* @doc-name stepper
|
|
262
|
+
*/
|
|
263
|
+
@Directive({
|
|
264
|
+
selector: '[kjStep]',
|
|
265
|
+
standalone: true,
|
|
266
|
+
exportAs: 'kjStep',
|
|
267
|
+
providers: [{ provide: KJ_STEP, useExisting: KjStep }],
|
|
268
|
+
host: {
|
|
269
|
+
// No `role` override — applied to an `<li>`, the native `listitem`
|
|
270
|
+
// semantics already apply, and forcing the role would orphan the item
|
|
271
|
+
// when the step lives inside a non-`<ol>` parent (rare but possible).
|
|
272
|
+
'[attr.aria-current]': 'active() ? "step" : null',
|
|
273
|
+
'[attr.data-active]': 'active() ? "true" : null',
|
|
274
|
+
'[attr.data-completed]': 'completed() ? "true" : null',
|
|
275
|
+
'[attr.data-error]': 'error() ? "true" : null',
|
|
276
|
+
'[attr.data-optional]': 'optional() ? "true" : null',
|
|
277
|
+
'[attr.data-disabled]': 'disabled() ? "true" : null',
|
|
278
|
+
'[attr.data-reachable]': 'reachable() ? "true" : null',
|
|
279
|
+
'[attr.data-step-index]': 'index()',
|
|
280
|
+
},
|
|
281
|
+
})
|
|
282
|
+
export class KjStep implements KjStepContext {
|
|
283
|
+
private readonly stepper = inject(KJ_STEPPER) as KjStepper;
|
|
284
|
+
|
|
285
|
+
/** Marks the step as completed. Drives `data-completed` and gates linear advancement. */
|
|
286
|
+
readonly kjStepCompleted = input<boolean>(false);
|
|
287
|
+
|
|
288
|
+
/** Marks the step as in error. Drives `data-error`. Does *not* block advancement on its own. */
|
|
289
|
+
readonly kjStepError = input<boolean>(false);
|
|
290
|
+
|
|
291
|
+
/** Marks the step as optional — permits linear advancement without `completed`. */
|
|
292
|
+
readonly kjStepOptional = input<boolean>(false);
|
|
293
|
+
|
|
294
|
+
/** Explicit per-step disable, independent of linear-mode reachability. */
|
|
295
|
+
readonly kjStepDisabled = input<boolean>(false);
|
|
296
|
+
|
|
297
|
+
/** Optional human-meaningful key for `goToKey()` / analytics. */
|
|
298
|
+
readonly kjStepKey = input<string | undefined>(undefined);
|
|
299
|
+
|
|
300
|
+
private readonly _uid = ++_stepUid;
|
|
301
|
+
|
|
302
|
+
/** 0-based index in the parent stepper's step list. */
|
|
303
|
+
readonly index: Signal<number> = computed(() => this.stepper.steps().indexOf(this));
|
|
304
|
+
|
|
305
|
+
/** True when this is the active step. */
|
|
306
|
+
readonly active: Signal<boolean> = computed(
|
|
307
|
+
() => this.stepper.activeStep() === this.index(),
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
/** Mirror of the `kjStepCompleted` input as a signal. */
|
|
311
|
+
readonly completed: Signal<boolean> = computed(() => this.kjStepCompleted());
|
|
312
|
+
|
|
313
|
+
/** Mirror of the `kjStepError` input as a signal. */
|
|
314
|
+
readonly error: Signal<boolean> = computed(() => this.kjStepError());
|
|
315
|
+
|
|
316
|
+
/** Mirror of the `kjStepOptional` input as a signal. */
|
|
317
|
+
readonly optional: Signal<boolean> = computed(() => this.kjStepOptional());
|
|
318
|
+
|
|
319
|
+
/** Mirror of the `kjStepDisabled` input as a signal. */
|
|
320
|
+
readonly disabled: Signal<boolean> = computed(() => this.kjStepDisabled());
|
|
321
|
+
|
|
322
|
+
/** Mirror of the `kjStepKey` input as a signal. */
|
|
323
|
+
readonly key: Signal<string | undefined> = computed(() => this.kjStepKey());
|
|
324
|
+
|
|
325
|
+
/** True when this step is reachable under the current mode (always true non-linear). */
|
|
326
|
+
readonly reachable: Signal<boolean> = computed(() => {
|
|
327
|
+
if (this.disabled()) return false;
|
|
328
|
+
return this.stepper.isReachable(this.index());
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
/** Stable id for `aria-labelledby` wiring. */
|
|
332
|
+
readonly labelId: Signal<string> = computed(
|
|
333
|
+
() => `${this.stepper.stepperId}-step-${this._uid}-label`,
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
/** Stable id for the content region. */
|
|
337
|
+
readonly contentId: Signal<string> = computed(
|
|
338
|
+
() => `${this.stepper.stepperId}-step-${this._uid}-content`,
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
constructor() {
|
|
342
|
+
this.stepper.register(this);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Activate this step. Subject to linear-mode gating. */
|
|
346
|
+
activate(): void {
|
|
347
|
+
if (this.disabled()) return;
|
|
348
|
+
this.stepper.goTo(this.index());
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Marks an element as the *header* of its parent {@link KjStep}. Wires the
|
|
354
|
+
* accessible id, `aria-controls`, `aria-disabled`, and the click handler.
|
|
355
|
+
* Also acts as a roving-tabindex item, joining the parent stepper's
|
|
356
|
+
* single-tab-stop header strip.
|
|
357
|
+
*
|
|
358
|
+
* Apply to `<button>` (the recommended host) or any focusable element.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```html
|
|
362
|
+
* <button kjStepLabel>Profile</button>
|
|
363
|
+
* ```
|
|
364
|
+
* @doc-category Core/Navigation
|
|
365
|
+
* @doc
|
|
366
|
+
* @doc-name stepper
|
|
367
|
+
*/
|
|
368
|
+
@Directive({
|
|
369
|
+
selector: '[kjStepLabel]',
|
|
370
|
+
standalone: true,
|
|
371
|
+
hostDirectives: [KjRovingTabindexItemDirective],
|
|
372
|
+
host: {
|
|
373
|
+
'[attr.id]': 'step.labelId()',
|
|
374
|
+
'[attr.aria-controls]': 'step.contentId()',
|
|
375
|
+
'[attr.aria-disabled]': 'isAriaDisabled()',
|
|
376
|
+
'[attr.disabled]': 'isNativeDisabled()',
|
|
377
|
+
'[attr.data-active]': 'step.active() ? "true" : null',
|
|
378
|
+
'(click)': 'onClick()',
|
|
379
|
+
'(keydown.enter)': 'onActivationKey($event)',
|
|
380
|
+
'(keydown.space)': 'onActivationKey($event)',
|
|
381
|
+
},
|
|
382
|
+
})
|
|
383
|
+
export class KjStepLabel {
|
|
384
|
+
/** Parent step context. */
|
|
385
|
+
readonly step = inject(KJ_STEP);
|
|
386
|
+
private readonly host = inject(ElementRef<HTMLElement>);
|
|
387
|
+
|
|
388
|
+
/** True when host element is a native `<button>`. */
|
|
389
|
+
private readonly isButton = computed(
|
|
390
|
+
() => this.host.nativeElement.tagName === 'BUTTON',
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
/** Resolves the `aria-disabled` attribute string ('true' or null). */
|
|
394
|
+
readonly isAriaDisabled = computed(() => {
|
|
395
|
+
const blocked = this.step.disabled() || !this.step.reachable();
|
|
396
|
+
return blocked ? 'true' : null;
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
/** Resolves the native `disabled` attribute, only when host is a button. */
|
|
400
|
+
readonly isNativeDisabled = computed(() => {
|
|
401
|
+
if (!this.isButton()) return null;
|
|
402
|
+
const blocked = this.step.disabled() || !this.step.reachable();
|
|
403
|
+
return blocked ? '' : null;
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
/** @internal */
|
|
407
|
+
onClick(): void {
|
|
408
|
+
if (this.step.disabled() || !this.step.reachable()) return;
|
|
409
|
+
this.step.activate();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/** @internal */
|
|
413
|
+
onActivationKey(event: Event): void {
|
|
414
|
+
// Native <button> handles Enter/Space natively — only intercept when host is not a button.
|
|
415
|
+
if (this.isButton()) return;
|
|
416
|
+
event.preventDefault();
|
|
417
|
+
if (this.step.disabled() || !this.step.reachable()) return;
|
|
418
|
+
this.step.activate();
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Marks an element as the *content panel* of its parent {@link KjStep}.
|
|
424
|
+
* Host-binds `role="region"`, `aria-labelledby` to the step's label id,
|
|
425
|
+
* and toggles `[hidden]` / `[inert]` based on the step's active state.
|
|
426
|
+
*
|
|
427
|
+
* The wrapper layer renders the content via `@if (step.active())` so only
|
|
428
|
+
* the active panel is in the DOM. This directive's host bindings remain
|
|
429
|
+
* correct even when the wrapper opts to keep all panels mounted (e.g.
|
|
430
|
+
* for a crossfade).
|
|
431
|
+
*
|
|
432
|
+
* @example
|
|
433
|
+
* ```html
|
|
434
|
+
* <section kjStepContent>...</section>
|
|
435
|
+
* ```
|
|
436
|
+
* @doc-category Core/Navigation
|
|
437
|
+
* @doc
|
|
438
|
+
* @doc-name stepper
|
|
439
|
+
*/
|
|
440
|
+
@Directive({
|
|
441
|
+
selector: '[kjStepContent]',
|
|
442
|
+
standalone: true,
|
|
443
|
+
host: {
|
|
444
|
+
role: 'region',
|
|
445
|
+
'[attr.id]': 'step.contentId()',
|
|
446
|
+
'[attr.aria-labelledby]': 'step.labelId()',
|
|
447
|
+
'[attr.hidden]': '!step.active() ? "" : null',
|
|
448
|
+
'[attr.inert]': '!step.active() ? "" : null',
|
|
449
|
+
'[attr.data-state]': 'step.active() ? "active" : "inactive"',
|
|
450
|
+
'[attr.tabindex]': 'step.active() ? "-1" : null',
|
|
451
|
+
},
|
|
452
|
+
})
|
|
453
|
+
export class KjStepContent {
|
|
454
|
+
/** Parent step context. */
|
|
455
|
+
readonly step = inject(KJ_STEP);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Stepper-level *Next* command. Apply to a `<button>`. Host-binds
|
|
460
|
+
* `[disabled]` from the parent's `canAdvance()`, and dispatches `next()` on click.
|
|
461
|
+
*
|
|
462
|
+
* @example `<button kjStepperNext>Continue</button>`
|
|
463
|
+
* @doc-category Core/Navigation
|
|
464
|
+
* @doc
|
|
465
|
+
* @doc-name stepper
|
|
466
|
+
*/
|
|
467
|
+
@Directive({
|
|
468
|
+
selector: '[kjStepperNext]',
|
|
469
|
+
standalone: true,
|
|
470
|
+
host: {
|
|
471
|
+
'[attr.disabled]': 'isDisabled()',
|
|
472
|
+
'[attr.aria-disabled]': 'isDisabled() !== null ? "true" : null',
|
|
473
|
+
'[attr.data-stepper-action]': '"next"',
|
|
474
|
+
'(click)': 'onClick()',
|
|
475
|
+
},
|
|
476
|
+
})
|
|
477
|
+
export class KjStepperNext {
|
|
478
|
+
private readonly stepper = inject(KJ_STEPPER);
|
|
479
|
+
|
|
480
|
+
/** @internal */
|
|
481
|
+
readonly isDisabled = computed(() => (this.stepper.canAdvance() ? null : ''));
|
|
482
|
+
|
|
483
|
+
/** @internal */
|
|
484
|
+
onClick(): void {
|
|
485
|
+
this.stepper.next();
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Stepper-level *Previous* command. Apply to a `<button>`. Host-binds
|
|
491
|
+
* `[disabled]` from the parent's `canRetreat()`, and dispatches `previous()` on click.
|
|
492
|
+
*
|
|
493
|
+
* @example `<button kjStepperPrevious>Back</button>`
|
|
494
|
+
* @doc-category Core/Navigation
|
|
495
|
+
* @doc
|
|
496
|
+
* @doc-name stepper
|
|
497
|
+
*/
|
|
498
|
+
@Directive({
|
|
499
|
+
selector: '[kjStepperPrevious]',
|
|
500
|
+
standalone: true,
|
|
501
|
+
host: {
|
|
502
|
+
'[attr.disabled]': 'isDisabled()',
|
|
503
|
+
'[attr.aria-disabled]': 'isDisabled() !== null ? "true" : null',
|
|
504
|
+
'[attr.data-stepper-action]': '"previous"',
|
|
505
|
+
'(click)': 'onClick()',
|
|
506
|
+
},
|
|
507
|
+
})
|
|
508
|
+
export class KjStepperPrevious {
|
|
509
|
+
private readonly stepper = inject(KJ_STEPPER);
|
|
510
|
+
|
|
511
|
+
/** @internal */
|
|
512
|
+
readonly isDisabled = computed(() => (this.stepper.canRetreat() ? null : ''));
|
|
513
|
+
|
|
514
|
+
/** @internal */
|
|
515
|
+
onClick(): void {
|
|
516
|
+
this.stepper.previous();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Stepper-level *Reset* command. Apply to a `<button>`. Dispatches
|
|
522
|
+
* `reset()` on click; never gated.
|
|
523
|
+
*
|
|
524
|
+
* @example `<button kjStepperReset>Start over</button>`
|
|
525
|
+
* @doc-category Core/Navigation
|
|
526
|
+
* @doc
|
|
527
|
+
* @doc-name stepper
|
|
528
|
+
*/
|
|
529
|
+
@Directive({
|
|
530
|
+
selector: '[kjStepperReset]',
|
|
531
|
+
standalone: true,
|
|
532
|
+
host: {
|
|
533
|
+
'[attr.data-stepper-action]': '"reset"',
|
|
534
|
+
'(click)': 'onClick()',
|
|
535
|
+
},
|
|
536
|
+
})
|
|
537
|
+
export class KjStepperReset {
|
|
538
|
+
private readonly stepper = inject(KJ_STEPPER);
|
|
539
|
+
|
|
540
|
+
/** @internal */
|
|
541
|
+
onClick(): void {
|
|
542
|
+
this.stepper.reset();
|
|
543
|
+
}
|
|
544
|
+
}
|
package/src/styles.css
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────────────────────
|
|
2
|
+
@kouji-ui/core — aggregated global stylesheet
|
|
3
|
+
--------------------------------------------------------------
|
|
4
|
+
Single entry-point for the core-only global CSS pieces that
|
|
5
|
+
ship without a corresponding Angular component (prose + icon
|
|
6
|
+
attribute styles).
|
|
7
|
+
|
|
8
|
+
Overlay container chrome ships separately through
|
|
9
|
+
`packages/components/src/overlay/overlay.css`, which re-exports
|
|
10
|
+
the core overlay primitive plus every themed overlay-family
|
|
11
|
+
component (popover, tooltip, dropdown-menu, dialog, drawer,
|
|
12
|
+
toast, confirm-popup). Register that one file alongside this
|
|
13
|
+
one in your build.
|
|
14
|
+
──────────────────────────────────────────────────────────── */
|
|
15
|
+
|
|
16
|
+
@import "./typography/prose.css";
|
|
17
|
+
@import "./icon/icon.css";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { kjColumn, kjColumnGroup } from './column-helpers';
|
|
3
|
+
|
|
4
|
+
interface User { id: string; name: string; email: string; age: number; }
|
|
5
|
+
type AnyRec = Record<string, unknown>;
|
|
6
|
+
|
|
7
|
+
describe('kjColumn', () => {
|
|
8
|
+
it('returns a ColumnDef compatible with TanStack', () => {
|
|
9
|
+
const col = kjColumn<User>({ accessorKey: 'name', header: 'Name' });
|
|
10
|
+
expect(col.accessorKey).toBe('name');
|
|
11
|
+
expect(col.header).toBe('Name');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('hoists kj* knobs into meta.kj', () => {
|
|
15
|
+
const col = kjColumn<User>({
|
|
16
|
+
accessorKey: 'name',
|
|
17
|
+
kjType: 'text',
|
|
18
|
+
kjEditable: true,
|
|
19
|
+
kjPin: 'left',
|
|
20
|
+
});
|
|
21
|
+
expect((col.meta as AnyRec)?.kj).toEqual({
|
|
22
|
+
type: 'text',
|
|
23
|
+
editable: true,
|
|
24
|
+
pin: 'left',
|
|
25
|
+
});
|
|
26
|
+
// top-level kj* fields are stripped — TanStack sees only its native fields.
|
|
27
|
+
expect((col as AnyRec).kjType).toBeUndefined();
|
|
28
|
+
expect((col as AnyRec).kjEditable).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('preserves existing meta', () => {
|
|
32
|
+
const col = kjColumn<User>({
|
|
33
|
+
accessorKey: 'name',
|
|
34
|
+
meta: { foo: 'bar' } as AnyRec,
|
|
35
|
+
kjEditable: true,
|
|
36
|
+
});
|
|
37
|
+
expect((col.meta as AnyRec).foo).toBe('bar');
|
|
38
|
+
expect(((col.meta as AnyRec).kj as AnyRec).editable).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('omits meta.kj when no kj* knobs are passed', () => {
|
|
42
|
+
const col = kjColumn<User>({ accessorKey: 'name' });
|
|
43
|
+
expect((col.meta as AnyRec)?.kj).toBeUndefined();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('auto-wires filterFn from kjType so the built-in filter UIs round-trip', () => {
|
|
47
|
+
const text = kjColumn<User>({ accessorKey: 'name', kjType: 'text' });
|
|
48
|
+
const number = kjColumn<User>({ accessorKey: 'age', kjType: 'number' });
|
|
49
|
+
const sel = kjColumn<User>({ accessorKey: 'email', kjType: 'select' });
|
|
50
|
+
expect(typeof (text as AnyRec).filterFn).toBe('function');
|
|
51
|
+
expect(typeof (number as AnyRec).filterFn).toBe('function');
|
|
52
|
+
expect(typeof (sel as AnyRec).filterFn).toBe('function');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('respects a user-supplied filterFn over the auto-wired default', () => {
|
|
56
|
+
const custom = () => true;
|
|
57
|
+
const col = kjColumn<User>({ accessorKey: 'age', kjType: 'number', filterFn: custom });
|
|
58
|
+
expect((col as AnyRec).filterFn).toBe(custom);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('kjColumnGroup', () => {
|
|
63
|
+
it('returns a group column def with nested columns', () => {
|
|
64
|
+
const grp = kjColumnGroup<User>({
|
|
65
|
+
header: 'Identity',
|
|
66
|
+
columns: [
|
|
67
|
+
kjColumn<User>({ accessorKey: 'name' }),
|
|
68
|
+
kjColumn<User>({ accessorKey: 'email' }),
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
expect(grp.header).toBe('Identity');
|
|
72
|
+
expect((grp as AnyRec).columns).toHaveLength(2);
|
|
73
|
+
});
|
|
74
|
+
});
|