@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,470 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Directive,
|
|
3
|
-
ElementRef,
|
|
4
|
-
OnDestroy,
|
|
5
|
-
OnInit,
|
|
6
|
-
Signal,
|
|
7
|
-
booleanAttribute,
|
|
8
|
-
computed,
|
|
9
|
-
effect,
|
|
10
|
-
forwardRef,
|
|
11
|
-
inject,
|
|
12
|
-
input,
|
|
13
|
-
output,
|
|
14
|
-
signal,
|
|
15
|
-
} from '@angular/core';
|
|
16
|
-
import { KjDisabled } from '../primitives/interaction/disabled';
|
|
17
|
-
import { KjFormControl } from '../primitives/forms/form-control';
|
|
18
|
-
import { KjLiveRegion } from '../a11y/live-region';
|
|
19
|
-
import { KjFocusRing } from '../primitives/interaction/focus-ring';
|
|
20
|
-
import { KJ_INPUT_OTP, KjInputOtpContext } from './input-otp.context';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Root headless directive for the OTP input widget.
|
|
24
|
-
*
|
|
25
|
-
* Owns the concatenated value, cell count, character-set filtering, paste
|
|
26
|
-
* distribution, auto-advance, completion announcement, and the
|
|
27
|
-
* `KJ_INPUT_OTP` context that every `KjInputOtpCell` reads from.
|
|
28
|
-
*
|
|
29
|
-
* Composes `KjFormControl` via `hostDirectives` so the **whole widget** is a
|
|
30
|
-
* single Angular form control — `[(ngModel)]` and `[formControl]` bind to the
|
|
31
|
-
* concatenated string.
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* ```html
|
|
35
|
-
* <div kjInputOtp [kjLength]="6" [(ngModel)]="code">
|
|
36
|
-
* @for (i of cells; track i) {
|
|
37
|
-
* <input kjInputOtpCell [kjIndex]="i" />
|
|
38
|
-
* }
|
|
39
|
-
* </div>
|
|
40
|
-
* ```
|
|
41
|
-
*
|
|
42
|
-
* @doc-category Core/Data input
|
|
43
|
-
* @doc
|
|
44
|
-
* @doc-name input-otp
|
|
45
|
-
* @doc-description Unstyled multi-cell one-time-password root that exposes the whole widget as a single form control.
|
|
46
|
-
* @doc-is-main
|
|
47
|
-
*/
|
|
48
|
-
@Directive({
|
|
49
|
-
selector: '[kjInputOtp]',
|
|
50
|
-
standalone: true,
|
|
51
|
-
exportAs: 'kjInputOtp',
|
|
52
|
-
hostDirectives: [
|
|
53
|
-
{ directive: KjDisabled, inputs: ['kjDisabled'] },
|
|
54
|
-
KjFormControl,
|
|
55
|
-
KjLiveRegion,
|
|
56
|
-
],
|
|
57
|
-
providers: [
|
|
58
|
-
{ provide: KJ_INPUT_OTP, useExisting: forwardRef(() => KjInputOtp) },
|
|
59
|
-
],
|
|
60
|
-
host: {
|
|
61
|
-
'role': 'group',
|
|
62
|
-
'[attr.aria-label]': 'kjAriaLabel() ?? null',
|
|
63
|
-
'[attr.aria-invalid]': 'formCtrl.touched() && kjInvalid() ? "true" : null',
|
|
64
|
-
'[attr.data-invalid]': 'formCtrl.touched() && kjInvalid() ? "" : null',
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
export class KjInputOtp implements KjInputOtpContext, OnInit, OnDestroy {
|
|
68
|
-
readonly formCtrl = inject(KjFormControl);
|
|
69
|
-
private readonly disabled$ = inject(KjDisabled);
|
|
70
|
-
private readonly liveRegion = inject(KjLiveRegion);
|
|
71
|
-
|
|
72
|
-
// ── Inputs ──────────────────────────────────────────────────────────────────
|
|
73
|
-
|
|
74
|
-
/** Number of OTP cells. Common values: 4, 6, 8. */
|
|
75
|
-
readonly kjLength = input<number>(6);
|
|
76
|
-
|
|
77
|
-
/** Character-set restriction. Drives `inputmode`, `pattern`, and input/paste filtering. */
|
|
78
|
-
readonly kjCharSet = input<'digits' | 'alphanumeric' | RegExp>('digits');
|
|
79
|
-
|
|
80
|
-
/** When `true`, cells render with `type="password"`. */
|
|
81
|
-
readonly kjMask = input(false, { transform: booleanAttribute });
|
|
82
|
-
|
|
83
|
-
/** When `true`, emits `kjComplete` once the value reaches `kjLength`. */
|
|
84
|
-
readonly kjAutoSubmit = input(false, { transform: booleanAttribute });
|
|
85
|
-
|
|
86
|
-
/** Reflects an invalid state via `aria-invalid` (touched-gated). */
|
|
87
|
-
readonly kjInvalid = input(false, { transform: booleanAttribute });
|
|
88
|
-
|
|
89
|
-
/** Sets all cells to `readonly`. */
|
|
90
|
-
readonly kjReadonly = input(false, { transform: booleanAttribute });
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Accessible label for the widget when there is no parent `KjFormField`
|
|
94
|
-
* supplying an `aria-labelledby`.
|
|
95
|
-
*/
|
|
96
|
-
readonly kjAriaLabel = input<string | undefined>(undefined);
|
|
97
|
-
|
|
98
|
-
// ── Outputs ─────────────────────────────────────────────────────────────────
|
|
99
|
-
|
|
100
|
-
/** Emitted when the full code is entered (value.length === kjLength). */
|
|
101
|
-
readonly kjComplete = output<string>();
|
|
102
|
-
|
|
103
|
-
/** Emitted after a paste distributes characters across cells. */
|
|
104
|
-
readonly kjPasted = output<string>();
|
|
105
|
-
|
|
106
|
-
// ── Internal state ───────────────────────────────────────────────────────────
|
|
107
|
-
|
|
108
|
-
/** Per-cell character array; resized lazily by setCellValue. */
|
|
109
|
-
private readonly _chars = signal<string[]>([]);
|
|
110
|
-
|
|
111
|
-
/** Cell element registry for programmatic focus management. */
|
|
112
|
-
readonly _cells = new Map<number, HTMLInputElement>();
|
|
113
|
-
|
|
114
|
-
/** Focused cell index, or -1. */
|
|
115
|
-
private readonly _focusedIndex = signal<number>(-1);
|
|
116
|
-
|
|
117
|
-
/** Whether the code was already complete on the previous notification cycle. */
|
|
118
|
-
private _wasComplete = false;
|
|
119
|
-
|
|
120
|
-
// ── Context signals (KjInputOtpContext) ──────────────────────────────────────
|
|
121
|
-
|
|
122
|
-
/** Full concatenated OTP value (public, read-only signal). */
|
|
123
|
-
readonly value: Signal<string> = computed(() =>
|
|
124
|
-
this._chars().slice(0, this.kjLength()).join(''),
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
readonly length: Signal<number> = computed(() => this.kjLength());
|
|
128
|
-
|
|
129
|
-
readonly disabled: Signal<boolean> = computed(
|
|
130
|
-
() => this.disabled$.disabled() || this.formCtrl.disabled(),
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
readonly readonly: Signal<boolean> = computed(() => this.kjReadonly());
|
|
134
|
-
|
|
135
|
-
readonly masked: Signal<boolean> = computed(() => this.kjMask());
|
|
136
|
-
|
|
137
|
-
readonly charSet: Signal<'digits' | 'alphanumeric' | RegExp> = computed(
|
|
138
|
-
() => this.kjCharSet(),
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
readonly focusedIndex: Signal<number> = this._focusedIndex.asReadonly();
|
|
142
|
-
|
|
143
|
-
// ── Lifecycle ────────────────────────────────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
constructor() {
|
|
146
|
-
// Reflect CVA value writes to internal char array (e.g. programmatic setValue).
|
|
147
|
-
effect(() => {
|
|
148
|
-
const incoming = this.formCtrl.value();
|
|
149
|
-
if (incoming == null) return;
|
|
150
|
-
const str = String(incoming);
|
|
151
|
-
const chars = str.split('').slice(0, this.kjLength());
|
|
152
|
-
this._chars.set(chars);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Notify forms layer whenever the value signal changes.
|
|
156
|
-
effect(() => {
|
|
157
|
-
const val = this.value();
|
|
158
|
-
this.formCtrl.notifyChange(val);
|
|
159
|
-
this._checkCompletion(val);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
ngOnInit(): void {
|
|
164
|
-
// Initialise the char array to the correct length on first render.
|
|
165
|
-
if (this._chars().length === 0) {
|
|
166
|
-
this._chars.set(Array(this.kjLength()).fill(''));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
ngOnDestroy(): void {
|
|
171
|
-
this._cells.clear();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ── KjInputOtpContext methods ────────────────────────────────────────────────
|
|
175
|
-
|
|
176
|
-
/** Update a single cell's character and notify forms. */
|
|
177
|
-
setCellValue(index: number, char: string): void {
|
|
178
|
-
const current = [...this._chars()];
|
|
179
|
-
// Ensure the array is long enough.
|
|
180
|
-
while (current.length <= index) current.push('');
|
|
181
|
-
current[index] = char;
|
|
182
|
-
this._chars.set(current);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** Move focus by delta (+1 / -1), clamped to valid range. */
|
|
186
|
-
moveFocus(delta: number): void {
|
|
187
|
-
const current = this._focusedIndex();
|
|
188
|
-
const next = Math.max(0, Math.min(this.kjLength() - 1, current + delta));
|
|
189
|
-
this._cells.get(next)?.focus();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** Focus a specific cell index (clamped to valid range). */
|
|
193
|
-
focusIndex(index: number): void {
|
|
194
|
-
const clamped = Math.max(0, Math.min(this.kjLength() - 1, index));
|
|
195
|
-
this._focusedIndex.set(clamped);
|
|
196
|
-
this._cells.get(clamped)?.focus();
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Distribute pasted text across cells starting from `fromIndex`.
|
|
201
|
-
* Filters the pasted text through the current charSet before distributing.
|
|
202
|
-
*/
|
|
203
|
-
handlePaste(event: ClipboardEvent, fromIndex: number): void {
|
|
204
|
-
event.preventDefault();
|
|
205
|
-
const raw = event.clipboardData?.getData('text') ?? '';
|
|
206
|
-
this.distributeText(raw, fromIndex);
|
|
207
|
-
const filtered = this._filterChars(raw);
|
|
208
|
-
if (filtered) {
|
|
209
|
-
this.kjPasted.emit(filtered);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** Intercept copy and write the full OTP value to the clipboard. */
|
|
214
|
-
handleCopy(event: ClipboardEvent): void {
|
|
215
|
-
event.preventDefault();
|
|
216
|
-
event.clipboardData?.setData('text/plain', this.value());
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/** Register a cell's native input element for programmatic focus. */
|
|
220
|
-
registerCell(index: number, el: HTMLInputElement): void {
|
|
221
|
-
this._cells.set(index, el);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/** Deregister a cell element on destroy. */
|
|
225
|
-
unregisterCell(index: number): void {
|
|
226
|
-
this._cells.delete(index);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Distribute raw text across cells starting from `fromIndex`, filtering
|
|
231
|
-
* through the current charSet. Called by `KjInputOtpCell` for both
|
|
232
|
-
* iOS-autofill over-length writes and as the internal paste helper.
|
|
233
|
-
* @internal
|
|
234
|
-
*/
|
|
235
|
-
distributeText(text: string, fromIndex: number): void {
|
|
236
|
-
const filtered = this._filterChars(text);
|
|
237
|
-
if (!filtered) return;
|
|
238
|
-
|
|
239
|
-
const current = [...this._chars()];
|
|
240
|
-
while (current.length < this.kjLength()) current.push('');
|
|
241
|
-
|
|
242
|
-
let cellIndex = fromIndex;
|
|
243
|
-
for (const ch of filtered) {
|
|
244
|
-
if (cellIndex >= this.kjLength()) break;
|
|
245
|
-
current[cellIndex] = ch;
|
|
246
|
-
cellIndex++;
|
|
247
|
-
}
|
|
248
|
-
this._chars.set(current);
|
|
249
|
-
|
|
250
|
-
// Focus the first empty cell after distribution, or the last cell.
|
|
251
|
-
const firstEmpty = current.findIndex((c, i) => i >= fromIndex && !c);
|
|
252
|
-
const focusTarget = firstEmpty !== -1 ? firstEmpty : this.kjLength() - 1;
|
|
253
|
-
this._cells.get(focusTarget)?.focus();
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// ── Private helpers ──────────────────────────────────────────────────────────
|
|
257
|
-
|
|
258
|
-
private _checkCompletion(val: string): void {
|
|
259
|
-
const complete = val.length >= this.kjLength() && !val.includes('');
|
|
260
|
-
if (complete && !this._wasComplete) {
|
|
261
|
-
this._wasComplete = true;
|
|
262
|
-
this.liveRegion.announce('Code complete');
|
|
263
|
-
// Always emit kjComplete so consumers can react regardless of
|
|
264
|
-
// kjAutoSubmit. kjAutoSubmit is a UX hint for consumers, not a gate.
|
|
265
|
-
this.kjComplete.emit(val);
|
|
266
|
-
} else if (!complete) {
|
|
267
|
-
this._wasComplete = false;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/** Filter a string to only characters allowed by the current charSet. */
|
|
272
|
-
private _filterChars(input: string): string {
|
|
273
|
-
const cs = this.kjCharSet();
|
|
274
|
-
if (cs === 'digits') return input.replace(/[^0-9]/g, '');
|
|
275
|
-
if (cs === 'alphanumeric') return input.replace(/[^A-Za-z0-9]/g, '');
|
|
276
|
-
// Custom RegExp — apply per character.
|
|
277
|
-
return input.split('').filter(ch => (cs as RegExp).test(ch)).join('');
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// ────────────────────────────────────────────────────────────────────────────
|
|
282
|
-
// KjInputOtpCell
|
|
283
|
-
// ────────────────────────────────────────────────────────────────────────────
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Leaf directive applied to each `<input>` inside a `[kjInputOtp]` group.
|
|
287
|
-
*
|
|
288
|
-
* Reads its character from the parent context signal keyed by `kjIndex`.
|
|
289
|
-
* Owns per-cell keyboard handling (Backspace, ArrowLeft/Right, Home/End)
|
|
290
|
-
* and delegates paste/copy and focus tracking back to the root directive.
|
|
291
|
-
*
|
|
292
|
-
* @example
|
|
293
|
-
* ```html
|
|
294
|
-
* <input kjInputOtpCell [kjIndex]="i" />
|
|
295
|
-
* ```
|
|
296
|
-
*
|
|
297
|
-
* @doc-category Core/Data input
|
|
298
|
-
* @doc
|
|
299
|
-
* @doc-name input-otp
|
|
300
|
-
*/
|
|
301
|
-
@Directive({
|
|
302
|
-
selector: 'input[kjInputOtpCell]',
|
|
303
|
-
standalone: true,
|
|
304
|
-
hostDirectives: [KjFocusRing],
|
|
305
|
-
host: {
|
|
306
|
-
'type': 'text',
|
|
307
|
-
'maxlength': '1',
|
|
308
|
-
'autocapitalize': 'off',
|
|
309
|
-
'autocorrect': 'off',
|
|
310
|
-
'spellcheck': 'false',
|
|
311
|
-
'[attr.inputmode]': 'inputmode()',
|
|
312
|
-
'[attr.pattern]': 'pattern()',
|
|
313
|
-
'[attr.autocomplete]': 'kjIndex() === 0 ? "one-time-code" : "off"',
|
|
314
|
-
'[attr.aria-label]': 'ariaLabel()',
|
|
315
|
-
'[attr.tabindex]': 'isTabStop() ? "0" : "-1"',
|
|
316
|
-
'[attr.disabled]': 'ctx.disabled() ? "" : null',
|
|
317
|
-
'[attr.readonly]': 'ctx.readonly() ? "" : null',
|
|
318
|
-
'[attr.type]': 'ctx.masked() ? "password" : "text"',
|
|
319
|
-
'[value]': 'ctx.value()[kjIndex()] ?? ""',
|
|
320
|
-
'(input)': 'onInput($event)',
|
|
321
|
-
'(keydown)': 'onKeydown($event)',
|
|
322
|
-
'(paste)': 'ctx.handlePaste($event, kjIndex())',
|
|
323
|
-
'(copy)': 'ctx.handleCopy($event)',
|
|
324
|
-
'(focus)': 'ctx.focusIndex(kjIndex())',
|
|
325
|
-
'(blur)': 'onBlur()',
|
|
326
|
-
},
|
|
327
|
-
})
|
|
328
|
-
export class KjInputOtpCell implements OnInit, OnDestroy {
|
|
329
|
-
/** The context provided by the parent `KjInputOtp`. */
|
|
330
|
-
readonly ctx = inject(KJ_INPUT_OTP);
|
|
331
|
-
|
|
332
|
-
/** Zero-based index of this cell within the OTP group. Required. */
|
|
333
|
-
readonly kjIndex = input.required<number>();
|
|
334
|
-
|
|
335
|
-
/** Whether this cell is the roving tab stop. */
|
|
336
|
-
protected readonly isTabStop = computed(() => {
|
|
337
|
-
const chars = this.ctx.value();
|
|
338
|
-
const len = this.ctx.length();
|
|
339
|
-
// Tab stop is the first empty cell, or cell 0 when all are filled.
|
|
340
|
-
const firstEmpty = Array.from({ length: len }, (_, i) => chars[i] ?? '').findIndex(c => !c);
|
|
341
|
-
const tabStopIndex = firstEmpty === -1 ? 0 : firstEmpty;
|
|
342
|
-
return this.kjIndex() === tabStopIndex;
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
protected readonly inputmode = computed(() =>
|
|
346
|
-
this.ctx.charSet() === 'digits' ? 'numeric' : 'text',
|
|
347
|
-
);
|
|
348
|
-
|
|
349
|
-
protected readonly pattern = computed(() =>
|
|
350
|
-
this.ctx.charSet() === 'digits' ? '[0-9]*' : null,
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
protected readonly ariaLabel = computed(
|
|
354
|
-
() => `Code digit ${this.kjIndex() + 1} of ${this.ctx.length()}`,
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
// ── Lifecycle ────────────────────────────────────────────────────────────────
|
|
358
|
-
|
|
359
|
-
private readonly _elRef = inject<ElementRef<HTMLInputElement>>(ElementRef);
|
|
360
|
-
|
|
361
|
-
ngOnInit(): void {
|
|
362
|
-
this.ctx.registerCell(this.kjIndex(), this._elRef.nativeElement);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
ngOnDestroy(): void {
|
|
366
|
-
this.ctx.unregisterCell(this.kjIndex());
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// ── Event handlers ───────────────────────────────────────────────────────────
|
|
370
|
-
|
|
371
|
-
/** Handle character input from the user (or iOS autofill writing a full code). */
|
|
372
|
-
protected onInput(event: Event): void {
|
|
373
|
-
const target = event.target as HTMLInputElement;
|
|
374
|
-
const raw = target.value;
|
|
375
|
-
|
|
376
|
-
if (raw.length > 1) {
|
|
377
|
-
// iOS autofill or paste-via-input: treat as a paste from this index.
|
|
378
|
-
// We call distributeText directly on the root to avoid constructing
|
|
379
|
-
// ClipboardEvent/DataTransfer which are unavailable in some environments.
|
|
380
|
-
(this.ctx as KjInputOtp).distributeText(raw, this.kjIndex());
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const cs = this.ctx.charSet();
|
|
385
|
-
const filtered = this._filterChar(raw, cs);
|
|
386
|
-
|
|
387
|
-
if (filtered === '' && raw !== '') {
|
|
388
|
-
// Character rejected — restore original value.
|
|
389
|
-
target.value = this.ctx.value()[this.kjIndex()] ?? '';
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
this.ctx.setCellValue(this.kjIndex(), filtered);
|
|
394
|
-
|
|
395
|
-
if (filtered !== '') {
|
|
396
|
-
// Advance focus only if a valid character was entered.
|
|
397
|
-
this.ctx.moveFocus(1);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/** Handle keyboard navigation within the OTP group. */
|
|
402
|
-
protected onKeydown(event: KeyboardEvent): void {
|
|
403
|
-
const { key } = event;
|
|
404
|
-
|
|
405
|
-
if (key === 'Backspace') {
|
|
406
|
-
event.preventDefault();
|
|
407
|
-
const currentChar = this.ctx.value()[this.kjIndex()] ?? '';
|
|
408
|
-
if (currentChar !== '') {
|
|
409
|
-
// Filled cell: clear it and move focus back.
|
|
410
|
-
this.ctx.setCellValue(this.kjIndex(), '');
|
|
411
|
-
this.ctx.moveFocus(-1);
|
|
412
|
-
} else {
|
|
413
|
-
// Empty cell: move to previous and clear that cell.
|
|
414
|
-
const prevIndex = this.kjIndex() - 1;
|
|
415
|
-
if (prevIndex >= 0) {
|
|
416
|
-
this.ctx.setCellValue(prevIndex, '');
|
|
417
|
-
this.ctx.moveFocus(-1);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (key === 'Delete') {
|
|
424
|
-
event.preventDefault();
|
|
425
|
-
this.ctx.setCellValue(this.kjIndex(), '');
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (key === 'ArrowLeft') {
|
|
430
|
-
event.preventDefault();
|
|
431
|
-
this.ctx.moveFocus(-1);
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
if (key === 'ArrowRight') {
|
|
436
|
-
event.preventDefault();
|
|
437
|
-
this.ctx.moveFocus(1);
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
if (key === 'Home') {
|
|
442
|
-
event.preventDefault();
|
|
443
|
-
this.ctx.focusIndex(0);
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (key === 'End') {
|
|
448
|
-
event.preventDefault();
|
|
449
|
-
this.ctx.focusIndex(this.ctx.length() - 1);
|
|
450
|
-
return;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
protected onBlur(): void {
|
|
455
|
-
// Notify the form control as touched when any cell blurs
|
|
456
|
-
// (the form control is on the root, cells delegate).
|
|
457
|
-
// We reach the root's formCtrl through the context cast.
|
|
458
|
-
const root = this.ctx as KjInputOtp;
|
|
459
|
-
root.formCtrl?.notifyTouched?.();
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// ── Private helpers ──────────────────────────────────────────────────────────
|
|
463
|
-
|
|
464
|
-
private _filterChar(ch: string, cs: 'digits' | 'alphanumeric' | RegExp): string {
|
|
465
|
-
if (!ch) return '';
|
|
466
|
-
if (cs === 'digits') return /^[0-9]$/.test(ch) ? ch : '';
|
|
467
|
-
if (cs === 'alphanumeric') return /^[A-Za-z0-9]$/.test(ch) ? ch : '';
|
|
468
|
-
return (cs as RegExp).test(ch) ? ch : '';
|
|
469
|
-
}
|
|
470
|
-
}
|
package/src/kbd/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { KjKbd, KJ_KBD_SIZE_PRESET } from './kbd';
|
package/src/kbd/kbd.spec.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
|
2
|
-
import { TestBed } from '@angular/core/testing';
|
|
3
|
-
import { render } from '@testing-library/angular';
|
|
4
|
-
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import { KJ_SIZE_PRESET } from '../presets';
|
|
6
|
-
import { KJ_KBD_SIZE_PRESET, KjKbd } from './kbd';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Flush microtasks + the rAF that backs `afterNextRender` so the directive's
|
|
10
|
-
* dev-mode host inspection has a chance to run.
|
|
11
|
-
*/
|
|
12
|
-
async function flushAfterNextRender(): Promise<void> {
|
|
13
|
-
await new Promise<void>((resolve) => setTimeout(resolve, 0));
|
|
14
|
-
await Promise.resolve();
|
|
15
|
-
await Promise.resolve();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
@Component({
|
|
19
|
-
standalone: true,
|
|
20
|
-
imports: [KjKbd],
|
|
21
|
-
changeDetection: ChangeDetectionStrategy.Eager,
|
|
22
|
-
template: `<kbd kjKbd [kjSize]="size">{{ label }}</kbd>`,
|
|
23
|
-
})
|
|
24
|
-
class HostComponent {
|
|
25
|
-
size: string | undefined = undefined;
|
|
26
|
-
label = 'Enter';
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
describe('KjKbd', () => {
|
|
30
|
-
afterEach(() => vi.restoreAllMocks());
|
|
31
|
-
|
|
32
|
-
describe('size composition (KjSize via hostDirectives)', () => {
|
|
33
|
-
it('reflects default kjSize as data-size="md" on the host', async () => {
|
|
34
|
-
const { container } = await render(`<kbd kjKbd>Enter</kbd>`, { imports: [KjKbd] });
|
|
35
|
-
await flushAfterNextRender();
|
|
36
|
-
// Built-in KJ_SIZE_PRESET factory default is 'md'.
|
|
37
|
-
expect(container.querySelector('kbd')).toHaveAttribute('data-size', 'md');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('reflects kjSize input as data-size on the host', async () => {
|
|
41
|
-
const { container } = await render(`<kbd kjKbd [kjSize]="'lg'">Enter</kbd>`, {
|
|
42
|
-
imports: [KjKbd],
|
|
43
|
-
providers: [
|
|
44
|
-
{
|
|
45
|
-
provide: KJ_SIZE_PRESET,
|
|
46
|
-
useValue: { values: ['xs', 'sm', 'md', 'lg'], default: 'md' },
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
});
|
|
50
|
-
await flushAfterNextRender();
|
|
51
|
-
expect(container.querySelector('kbd')).toHaveAttribute('data-size', 'lg');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('honours the KJ_KBD_SIZE_PRESET re-export (xs / sm / md / lg, default md)', async () => {
|
|
55
|
-
TestBed.configureTestingModule({
|
|
56
|
-
providers: [{ provide: KJ_SIZE_PRESET, useValue: KJ_KBD_SIZE_PRESET }],
|
|
57
|
-
});
|
|
58
|
-
const fixture = TestBed.createComponent(HostComponent);
|
|
59
|
-
fixture.componentInstance.size = 'xs';
|
|
60
|
-
fixture.detectChanges();
|
|
61
|
-
const host = fixture.nativeElement.querySelector('kbd');
|
|
62
|
-
expect(host.getAttribute('data-size')).toBe('xs');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('warns in dev mode when kjSize is outside the preset (size validation flows through)', async () => {
|
|
66
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
67
|
-
TestBed.configureTestingModule({
|
|
68
|
-
providers: [{ provide: KJ_SIZE_PRESET, useValue: KJ_KBD_SIZE_PRESET }],
|
|
69
|
-
});
|
|
70
|
-
const fixture = TestBed.createComponent(HostComponent);
|
|
71
|
-
fixture.componentInstance.size = 'huge';
|
|
72
|
-
fixture.detectChanges();
|
|
73
|
-
// `KjSize` warns synchronously via `effect`; element-tag warning is
|
|
74
|
-
// deferred to `afterNextRender`. Either way both have already fired by
|
|
75
|
-
// here; we just need *some* call matching the size message.
|
|
76
|
-
const matched = warn.mock.calls.some((c) => /unknown size/i.test(String(c[0])));
|
|
77
|
-
expect(matched).toBe(true);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe('host element discipline (dev-mode warning)', () => {
|
|
82
|
-
it('does not warn when host is <kbd>', async () => {
|
|
83
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
84
|
-
await render(`<kbd kjKbd>Enter</kbd>`, { imports: [KjKbd] });
|
|
85
|
-
await flushAfterNextRender();
|
|
86
|
-
const matched = warn.mock.calls.some((c) => /applied to <\w+>/i.test(String(c[0])));
|
|
87
|
-
expect(matched).toBe(false);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('warns when host is not <kbd> (e.g. <span>)', async () => {
|
|
91
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
92
|
-
await render(`<span kjKbd>Enter</span>`, { imports: [KjKbd] });
|
|
93
|
-
await flushAfterNextRender();
|
|
94
|
-
const matched = warn.mock.calls.some((c) => {
|
|
95
|
-
const msg = String(c[0]);
|
|
96
|
-
return /kjKbd applied to <span>/i.test(msg) && /<kbd>/i.test(msg);
|
|
97
|
-
});
|
|
98
|
-
expect(matched).toBe(true);
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
describe('focusable-descendant discipline (dev-mode warning)', () => {
|
|
103
|
-
it('warns when a focusable descendant exists', async () => {
|
|
104
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
105
|
-
await render(`<kbd kjKbd><button>?</button></kbd>`, { imports: [KjKbd] });
|
|
106
|
-
await flushAfterNextRender();
|
|
107
|
-
const matched = warn.mock.calls.some((c) => /focusable descendant/i.test(String(c[0])));
|
|
108
|
-
expect(matched).toBe(true);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('does not warn for plain text content', async () => {
|
|
112
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
113
|
-
await render(`<kbd kjKbd>Enter</kbd>`, { imports: [KjKbd] });
|
|
114
|
-
await flushAfterNextRender();
|
|
115
|
-
const matched = warn.mock.calls.some((c) => /focusable descendant/i.test(String(c[0])));
|
|
116
|
-
expect(matched).toBe(false);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('does not warn for non-focusable element children', async () => {
|
|
120
|
-
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
121
|
-
await render(`<kbd kjKbd><span>Enter</span></kbd>`, { imports: [KjKbd] });
|
|
122
|
-
await flushAfterNextRender();
|
|
123
|
-
const matched = warn.mock.calls.some((c) => /focusable descendant/i.test(String(c[0])));
|
|
124
|
-
expect(matched).toBe(false);
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
});
|