@kouji-ui/core 0.1.1 → 0.1.2
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 +5 -6
- 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
package/src/form/form.ts
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Directive,
|
|
3
|
-
ElementRef,
|
|
4
|
-
Injector,
|
|
5
|
-
afterNextRender,
|
|
6
|
-
booleanAttribute,
|
|
7
|
-
computed,
|
|
8
|
-
inject,
|
|
9
|
-
input,
|
|
10
|
-
model,
|
|
11
|
-
output,
|
|
12
|
-
signal,
|
|
13
|
-
} from '@angular/core';
|
|
14
|
-
import { AbstractControl, FormArray, FormGroup, FormGroupDirective, NgForm } from '@angular/forms';
|
|
15
|
-
import { Observable } from 'rxjs';
|
|
16
|
-
import {
|
|
17
|
-
InvalidControlInfo,
|
|
18
|
-
KJ_FORM,
|
|
19
|
-
KjFormContext,
|
|
20
|
-
KjFormControlRegistration,
|
|
21
|
-
} from './form.context';
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Async submit handler signature accepted by `[kjAsyncSubmit]`. The directive
|
|
25
|
-
* awaits the returned promise/observable and toggles `submitting` for its
|
|
26
|
-
* lifetime.
|
|
27
|
-
*/
|
|
28
|
-
export type KjAsyncSubmitHandler<T = unknown> = (
|
|
29
|
-
value: T,
|
|
30
|
-
) => void | Promise<unknown> | Observable<unknown>;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Coordinator directive applied to a `<form>` element. Owns the submit
|
|
34
|
-
* pipeline (intercept, validity check, focus-on-first-error, scroll-into-view,
|
|
35
|
-
* async submitting state, mark-all-as-touched, optional error summary). Defers
|
|
36
|
-
* to Angular Forms (`FormGroup` / `NgForm`) for validation; this directive is
|
|
37
|
-
* a coordinator, not a state holder.
|
|
38
|
-
*
|
|
39
|
-
* - Emits `(kjSubmit)` only when the form is valid (replaces hand-rolled
|
|
40
|
-
* `(ngSubmit)` + `if (form.invalid) return` patterns).
|
|
41
|
-
* - Emits `(kjInvalidSubmit)` when the user submitted but validity failed,
|
|
42
|
-
* useful for analytics.
|
|
43
|
-
* - When `[kjAsyncSubmit]` is set, awaits its returned `Promise`/`Observable`
|
|
44
|
-
* and reflects `aria-busy="true"` / `data-submitting=""` for the lifetime.
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```html
|
|
48
|
-
* <form kjForm [formGroup]="form" (kjSubmit)="onSubmit($event)">
|
|
49
|
-
* <input formControlName="email" kjInput />
|
|
50
|
-
* <button type="submit">Sign in</button>
|
|
51
|
-
* </form>
|
|
52
|
-
* ```
|
|
53
|
-
* @doc-category Core/Inputs
|
|
54
|
-
* @doc
|
|
55
|
-
* @doc-name form
|
|
56
|
-
* @doc-description Coordinates form submit with validation, first-error focus, and async submitting state.
|
|
57
|
-
* @doc-is-main
|
|
58
|
-
*/
|
|
59
|
-
@Directive({
|
|
60
|
-
selector: 'form[kjForm]',
|
|
61
|
-
standalone: true,
|
|
62
|
-
exportAs: 'kjForm',
|
|
63
|
-
providers: [{ provide: KJ_FORM, useExisting: KjForm }],
|
|
64
|
-
host: {
|
|
65
|
-
'[attr.aria-busy]': 'submitting() ? "true" : null',
|
|
66
|
-
'[attr.aria-describedby]': 'errorSummaryId() ?? null',
|
|
67
|
-
'[attr.data-submitting]': 'submitting() ? "" : null',
|
|
68
|
-
'[attr.data-invalid]': 'invalid() ? "" : null',
|
|
69
|
-
'(submit)': 'onNativeSubmit($event)',
|
|
70
|
-
},
|
|
71
|
-
})
|
|
72
|
-
export class KjForm implements KjFormContext {
|
|
73
|
-
private readonly el = inject<ElementRef<HTMLFormElement>>(ElementRef);
|
|
74
|
-
private readonly injector = inject(Injector);
|
|
75
|
-
private readonly ngForm = inject(NgForm, { optional: true, self: true });
|
|
76
|
-
private readonly formGroupDir = inject(FormGroupDirective, { optional: true, self: true });
|
|
77
|
-
|
|
78
|
-
// ── Inputs ───────────────────────────────────────────────────────────
|
|
79
|
-
/** When `false`, skips moving focus to the first invalid control on invalid submit. */
|
|
80
|
-
readonly kjFocusOnError = input(true, { transform: booleanAttribute });
|
|
81
|
-
/** When `false`, does not call `scrollIntoView` on the focused control. */
|
|
82
|
-
readonly kjScrollOnError = input(true, { transform: booleanAttribute });
|
|
83
|
-
/** Forwarded to `scrollIntoView({ behavior })`. Auto-downgrades to `'auto'` under `prefers-reduced-motion`. */
|
|
84
|
-
readonly kjScrollBehavior = input<ScrollBehavior>('smooth');
|
|
85
|
-
/** Forwarded to `scrollIntoView({ block })`. */
|
|
86
|
-
readonly kjScrollBlock = input<ScrollLogicalPosition>('center');
|
|
87
|
-
/** When `true` (default), calls `markAllAsTouched()` before validity check so all errors show together. */
|
|
88
|
-
readonly kjMarkAllAsTouchedOnSubmit = input(true, { transform: booleanAttribute });
|
|
89
|
-
/** When `true`, calls `form.reset()` after a successful async submit resolves. */
|
|
90
|
-
readonly kjResetOnSuccess = input(false, { transform: booleanAttribute });
|
|
91
|
-
/** Optional async submit handler. When set, the directive awaits its result and toggles `submitting`. */
|
|
92
|
-
readonly kjAsyncSubmit = input<KjAsyncSubmitHandler | undefined>(undefined);
|
|
93
|
-
|
|
94
|
-
// ── Outputs ──────────────────────────────────────────────────────────
|
|
95
|
-
/** Emits the form value when the user submits and the form is valid. */
|
|
96
|
-
readonly kjSubmit = output<unknown>();
|
|
97
|
-
/** Emits the FormGroup when the user submits but validity fails. */
|
|
98
|
-
readonly kjInvalidSubmit = output<FormGroup>();
|
|
99
|
-
|
|
100
|
-
// ── Models / state ───────────────────────────────────────────────────
|
|
101
|
-
/** Two-way bindable submitting flag. When unbound, the directive owns it internally. */
|
|
102
|
-
readonly kjSubmitting = model(false);
|
|
103
|
-
|
|
104
|
-
private readonly _submitted = signal(false);
|
|
105
|
-
private readonly _invalid = signal(false);
|
|
106
|
-
private readonly _invalidControls = signal<readonly InvalidControlInfo[]>([]);
|
|
107
|
-
private readonly _errorSummaryId = signal<string | null>(null);
|
|
108
|
-
private readonly registry = new Map<string, KjFormControlRegistration>();
|
|
109
|
-
private prefersReducedMotion = false;
|
|
110
|
-
|
|
111
|
-
// ── Public surface (KjFormContext) ───────────────────────────────────
|
|
112
|
-
readonly form = computed<FormGroup | null>(() => {
|
|
113
|
-
if (this.formGroupDir) return this.formGroupDir.form;
|
|
114
|
-
if (this.ngForm) return this.ngForm.form;
|
|
115
|
-
return null;
|
|
116
|
-
});
|
|
117
|
-
readonly submitting = computed(() => this.kjSubmitting());
|
|
118
|
-
readonly submitted = this._submitted.asReadonly();
|
|
119
|
-
readonly invalid = this._invalid.asReadonly();
|
|
120
|
-
readonly invalidControls = this._invalidControls.asReadonly();
|
|
121
|
-
readonly errorSummaryId = this._errorSummaryId.asReadonly();
|
|
122
|
-
|
|
123
|
-
constructor() {
|
|
124
|
-
afterNextRender(() => {
|
|
125
|
-
try {
|
|
126
|
-
this.prefersReducedMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
127
|
-
} catch {
|
|
128
|
-
this.prefersReducedMotion = false;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
registerControl(reg: KjFormControlRegistration): () => void {
|
|
134
|
-
this.registry.set(reg.path, reg);
|
|
135
|
-
return () => {
|
|
136
|
-
const cur = this.registry.get(reg.path);
|
|
137
|
-
if (cur === reg) this.registry.delete(reg.path);
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/** Internal: called by `KjFormErrorSummary` to advertise its `id` to the form. */
|
|
142
|
-
setErrorSummaryId(id: string | null): void {
|
|
143
|
-
this._errorSummaryId.set(id);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Imperative submit — equivalent to dispatching a `submit` event on the host. */
|
|
147
|
-
submit(): void {
|
|
148
|
-
this.el.nativeElement.requestSubmit();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** @internal — host listener target. */
|
|
152
|
-
onNativeSubmit(event: Event): void {
|
|
153
|
-
event.preventDefault();
|
|
154
|
-
// Drop submit attempts while a previous submission is still in flight.
|
|
155
|
-
if (this.submitting()) return;
|
|
156
|
-
|
|
157
|
-
const form = this.form();
|
|
158
|
-
this._submitted.set(true);
|
|
159
|
-
|
|
160
|
-
if (!form) {
|
|
161
|
-
// No Angular forms binding — log a dev-mode warning and bail out.
|
|
162
|
-
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
163
|
-
console.warn(
|
|
164
|
-
'[KjForm] <form kjForm> has no `[formGroup]` or `ngForm` binding. The directive is a coordinator over Angular Forms and needs one to function.',
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (this.kjMarkAllAsTouchedOnSubmit()) {
|
|
171
|
-
form.markAllAsTouched();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (form.invalid) {
|
|
175
|
-
this._invalid.set(true);
|
|
176
|
-
const invalidControls = collectInvalidControls(form);
|
|
177
|
-
this._invalidControls.set(this.attachLabels(invalidControls));
|
|
178
|
-
this.kjInvalidSubmit.emit(form);
|
|
179
|
-
this.handleInvalidSubmit(invalidControls);
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
this._invalid.set(false);
|
|
184
|
-
this._invalidControls.set([]);
|
|
185
|
-
|
|
186
|
-
const handler = this.kjAsyncSubmit();
|
|
187
|
-
if (handler) {
|
|
188
|
-
this.runAsyncSubmit(handler, form);
|
|
189
|
-
} else {
|
|
190
|
-
this.kjSubmit.emit(form.value);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// ── Internals ────────────────────────────────────────────────────────
|
|
195
|
-
|
|
196
|
-
private attachLabels(invalid: ReadonlyArray<{ path: string; control: AbstractControl }>): InvalidControlInfo[] {
|
|
197
|
-
return invalid.map((entry) => {
|
|
198
|
-
const reg = this.registry.get(entry.path);
|
|
199
|
-
return { ...entry, label: reg?.label ?? humanizePath(entry.path) };
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
private handleInvalidSubmit(invalid: ReadonlyArray<{ path: string }>): void {
|
|
204
|
-
if (!this.kjFocusOnError() || invalid.length === 0) return;
|
|
205
|
-
const first = invalid[0];
|
|
206
|
-
const reg = this.registry.get(first.path);
|
|
207
|
-
const target = reg?.element ?? this.fallbackQuery(first.path);
|
|
208
|
-
if (!target) return;
|
|
209
|
-
try {
|
|
210
|
-
target.focus({ preventScroll: !this.kjScrollOnError() });
|
|
211
|
-
} catch {
|
|
212
|
-
// Some hosts (SSR/jsdom) may not implement focus options — ignore.
|
|
213
|
-
target.focus?.();
|
|
214
|
-
}
|
|
215
|
-
if (this.kjScrollOnError()) {
|
|
216
|
-
const behavior = this.prefersReducedMotion ? 'auto' : this.kjScrollBehavior();
|
|
217
|
-
target.scrollIntoView?.({ block: this.kjScrollBlock(), behavior });
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
private fallbackQuery(path: string): HTMLElement | null {
|
|
222
|
-
const root = this.el.nativeElement;
|
|
223
|
-
const escaped = cssEscape(path);
|
|
224
|
-
return (
|
|
225
|
-
root.querySelector<HTMLElement>(`[formcontrolname="${escaped}"]`) ??
|
|
226
|
-
root.querySelector<HTMLElement>(`[ng-reflect-name="${escaped}"]`) ??
|
|
227
|
-
null
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
private runAsyncSubmit(handler: KjAsyncSubmitHandler, form: FormGroup): void {
|
|
232
|
-
let result: ReturnType<KjAsyncSubmitHandler>;
|
|
233
|
-
this.kjSubmitting.set(true);
|
|
234
|
-
try {
|
|
235
|
-
result = handler(form.value);
|
|
236
|
-
} catch (err) {
|
|
237
|
-
this.kjSubmitting.set(false);
|
|
238
|
-
throw err;
|
|
239
|
-
}
|
|
240
|
-
if (result instanceof Promise) {
|
|
241
|
-
result.then(
|
|
242
|
-
() => this.afterAsync(form, true),
|
|
243
|
-
() => this.afterAsync(form, false),
|
|
244
|
-
);
|
|
245
|
-
// Also emit the synchronous (kjSubmit) for consumers that use both shapes.
|
|
246
|
-
this.kjSubmit.emit(form.value);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
if (isObservable(result)) {
|
|
250
|
-
const sub = result.subscribe({
|
|
251
|
-
complete: () => this.afterAsync(form, true),
|
|
252
|
-
error: () => this.afterAsync(form, false),
|
|
253
|
-
});
|
|
254
|
-
// Defensive: if the observable completes synchronously, the subscribe
|
|
255
|
-
// call already cleaned us up. Otherwise this no-op preserves cleanup
|
|
256
|
-
// behaviour (we don't track for unsubscription beyond completion).
|
|
257
|
-
void sub;
|
|
258
|
-
this.kjSubmit.emit(form.value);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
// Sync handler — release the flag immediately and emit.
|
|
262
|
-
this.kjSubmitting.set(false);
|
|
263
|
-
this.kjSubmit.emit(form.value);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
private afterAsync(form: FormGroup, success: boolean): void {
|
|
267
|
-
this.kjSubmitting.set(false);
|
|
268
|
-
if (success && this.kjResetOnSuccess()) {
|
|
269
|
-
form.reset();
|
|
270
|
-
this._submitted.set(false);
|
|
271
|
-
this._invalid.set(false);
|
|
272
|
-
this._invalidControls.set([]);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ─── Helpers ──────────────────────────────────────────────────────────
|
|
278
|
-
|
|
279
|
-
/** Walks a `FormGroup` / `FormArray` tree depth-first, returning invalid leaves. */
|
|
280
|
-
function collectInvalidControls(
|
|
281
|
-
root: AbstractControl,
|
|
282
|
-
): ReadonlyArray<{ path: string; control: AbstractControl }> {
|
|
283
|
-
const out: { path: string; control: AbstractControl }[] = [];
|
|
284
|
-
const walk = (ctrl: AbstractControl, path: string): void => {
|
|
285
|
-
if (ctrl instanceof FormGroup) {
|
|
286
|
-
for (const [name, child] of Object.entries(ctrl.controls)) {
|
|
287
|
-
walk(child, path ? `${path}.${name}` : name);
|
|
288
|
-
}
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (ctrl instanceof FormArray) {
|
|
292
|
-
ctrl.controls.forEach((child, i) => walk(child, `${path}.${i}`));
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
if (ctrl.invalid) {
|
|
296
|
-
out.push({ path, control: ctrl });
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
walk(root, '');
|
|
300
|
-
return out;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/** Converts `'address.street'` → `'Address street'` for fallback labels. */
|
|
304
|
-
function humanizePath(path: string): string {
|
|
305
|
-
if (!path) return '';
|
|
306
|
-
const last = path.split('.').pop() ?? path;
|
|
307
|
-
const words = last.replace(/([A-Z])/g, ' $1').replace(/[_-]+/g, ' ').trim();
|
|
308
|
-
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/** Type guard for RxJS observable. Avoids a hard dep on `isObservable` in tests. */
|
|
312
|
-
function isObservable(value: unknown): value is Observable<unknown> {
|
|
313
|
-
return (
|
|
314
|
-
!!value &&
|
|
315
|
-
typeof value === 'object' &&
|
|
316
|
-
typeof (value as { subscribe?: unknown }).subscribe === 'function'
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/** Minimal CSS.escape polyfill for `formcontrolname` attribute selectors. */
|
|
321
|
-
function cssEscape(value: string): string {
|
|
322
|
-
if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
|
|
323
|
-
return CSS.escape(value);
|
|
324
|
-
}
|
|
325
|
-
return value.replace(/[^a-zA-Z0-9_-]/g, (ch) => `\\${ch}`);
|
|
326
|
-
}
|
package/src/form/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { KjFormField, KjFormLabel, KjFormError } from './form-field';
|
|
2
|
-
export { KJ_FORM_FIELD, type KjFormFieldContext } from './form-field.context';
|
|
3
|
-
|
|
4
|
-
export { KjForm, type KjAsyncSubmitHandler } from './form';
|
|
5
|
-
export { KjFormErrorSummary } from './form-error-summary';
|
|
6
|
-
export {
|
|
7
|
-
KJ_FORM,
|
|
8
|
-
type KjFormContext,
|
|
9
|
-
type KjFormControlRegistration,
|
|
10
|
-
type InvalidControlInfo,
|
|
11
|
-
} from './form.context';
|
package/src/icon/E2E.md
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Icon — E2E coverage notes
|
|
2
|
-
|
|
3
|
-
The core icon layer has no consumer-visible UI in this session (no Lucide
|
|
4
|
-
adapter, no example refactor). The directive-level integration tests in
|
|
5
|
-
`icon.directive.spec.ts` cover the end-to-end path through DI:
|
|
6
|
-
|
|
7
|
-
- Eager registration via `provideIcons` → directive renders the registered value.
|
|
8
|
-
- Async loader path → directive renders nothing while pending, then re-renders on success.
|
|
9
|
-
- Decorative vs meaningful a11y modes → axe-clean.
|
|
10
|
-
- Mode switching (svg vs font) → correct CSS variable wrapping and `data-kj-icon-mode`.
|
|
11
|
-
- Selector restriction → directive only attaches to `span` and `i` hosts; ignores other tags.
|
|
12
|
-
|
|
13
|
-
Browser-level E2E lands with the Lucide adapter follow-up, when there's a
|
|
14
|
-
visible component to drive.
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import { render } from '@testing-library/angular';
|
|
2
|
-
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
import { KjIconDirective } from './icon.directive';
|
|
5
|
-
import { provideIcons, provideIconLoader } from './icon.providers';
|
|
6
|
-
|
|
7
|
-
expect.extend(toHaveNoViolations);
|
|
8
|
-
|
|
9
|
-
describe('KjIconDirective — selector', () => {
|
|
10
|
-
it('attaches to <i> hosts', async () => {
|
|
11
|
-
const { container } = await render(`<i [kjIcon]="'settings'"></i>`, {
|
|
12
|
-
imports: [KjIconDirective],
|
|
13
|
-
providers: [provideIcons({ settings: 'url("a")' })],
|
|
14
|
-
});
|
|
15
|
-
const host = container.querySelector('i')!;
|
|
16
|
-
expect(host.classList.contains('kj-icon')).toBe(true);
|
|
17
|
-
expect(host.getAttribute('data-kj-icon-mode')).toBe('svg');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('does NOT attach to disallowed hosts (e.g. <div>)', async () => {
|
|
21
|
-
// Static `kjIcon` attribute (no binding) — Angular only matches the
|
|
22
|
-
// directive against the host element's tag, not the attribute binding.
|
|
23
|
-
const { container } = await render(`<div kjIcon="settings"></div>`, {
|
|
24
|
-
imports: [KjIconDirective],
|
|
25
|
-
providers: [provideIcons({ settings: 'url("a")' })],
|
|
26
|
-
});
|
|
27
|
-
const host = container.querySelector('div')!;
|
|
28
|
-
expect(host.classList.contains('kj-icon')).toBe(false);
|
|
29
|
-
expect(host.hasAttribute('data-kj-icon-mode')).toBe(false);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('KjIconDirective — svg mode (decorative default)', () => {
|
|
34
|
-
it('writes --kj-icon and data-kj-icon-mode="svg"', async () => {
|
|
35
|
-
const { container } = await render(`<span [kjIcon]="'settings'"></span>`, {
|
|
36
|
-
imports: [KjIconDirective],
|
|
37
|
-
providers: [provideIcons({ settings: 'url("a")' })],
|
|
38
|
-
});
|
|
39
|
-
const host = container.querySelector('span')!;
|
|
40
|
-
expect(host.getAttribute('data-kj-icon-mode')).toBe('svg');
|
|
41
|
-
expect(host.style.getPropertyValue('--kj-icon')).toBe('url("a")');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('applies the .kj-icon class', async () => {
|
|
45
|
-
const { container } = await render(`<span [kjIcon]="'settings'"></span>`, {
|
|
46
|
-
imports: [KjIconDirective],
|
|
47
|
-
providers: [provideIcons({ settings: 'url("a")' })],
|
|
48
|
-
});
|
|
49
|
-
expect(container.querySelector('span')!.classList.contains('kj-icon')).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('default = decorative: aria-hidden="true", no role, no aria-label', async () => {
|
|
53
|
-
const { container } = await render(`<span [kjIcon]="'settings'"></span>`, {
|
|
54
|
-
imports: [KjIconDirective],
|
|
55
|
-
providers: [provideIcons({ settings: 'url("a")' })],
|
|
56
|
-
});
|
|
57
|
-
const host = container.querySelector('span')!;
|
|
58
|
-
expect(host.getAttribute('aria-hidden')).toBe('true');
|
|
59
|
-
expect(host.hasAttribute('role')).toBe(false);
|
|
60
|
-
expect(host.hasAttribute('aria-label')).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('KjIconDirective — meaningful mode (kjIconLabel)', () => {
|
|
65
|
-
it('removes aria-hidden, sets role="img" and aria-label', async () => {
|
|
66
|
-
const { container } = await render(
|
|
67
|
-
`<span [kjIcon]="'alert'" [kjIconLabel]="'Warning'"></span>`,
|
|
68
|
-
{
|
|
69
|
-
imports: [KjIconDirective],
|
|
70
|
-
providers: [provideIcons({ alert: 'url("a")' })],
|
|
71
|
-
},
|
|
72
|
-
);
|
|
73
|
-
const host = container.querySelector('span')!;
|
|
74
|
-
expect(host.hasAttribute('aria-hidden')).toBe(false);
|
|
75
|
-
expect(host.getAttribute('role')).toBe('img');
|
|
76
|
-
expect(host.getAttribute('aria-label')).toBe('Warning');
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe('KjIconDirective — color tokens', () => {
|
|
81
|
-
it('inherits color by default (no inline color style)', async () => {
|
|
82
|
-
const { container } = await render(`<span [kjIcon]="'x'"></span>`, {
|
|
83
|
-
imports: [KjIconDirective],
|
|
84
|
-
providers: [provideIcons({ x: 'url("a")' })],
|
|
85
|
-
});
|
|
86
|
-
expect(container.querySelector('span')!.getAttribute('style') ?? '').not.toContain('color:');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('writes color: var(--kj-color-icon-{token}) for non-inherit', async () => {
|
|
90
|
-
const { container } = await render(
|
|
91
|
-
`<span [kjIcon]="'x'" [kjIconColor]="'danger'"></span>`,
|
|
92
|
-
{
|
|
93
|
-
imports: [KjIconDirective],
|
|
94
|
-
providers: [provideIcons({ x: 'url("a")' })],
|
|
95
|
-
},
|
|
96
|
-
);
|
|
97
|
-
const styleAttr = container.querySelector('span')!.getAttribute('style') ?? '';
|
|
98
|
-
expect(styleAttr).toContain('color: var(--kj-color-icon-danger)');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('"inherit" color writes no inline color', async () => {
|
|
102
|
-
const { container } = await render(
|
|
103
|
-
`<span [kjIcon]="'x'" [kjIconColor]="'inherit'"></span>`,
|
|
104
|
-
{
|
|
105
|
-
imports: [KjIconDirective],
|
|
106
|
-
providers: [provideIcons({ x: 'url("a")' })],
|
|
107
|
-
},
|
|
108
|
-
);
|
|
109
|
-
expect(container.querySelector('span')!.getAttribute('style') ?? '').not.toContain('color:');
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
describe('KjIconDirective — size tokens', () => {
|
|
114
|
-
it('writes font-size: var(--kj-icon-size-{token})', async () => {
|
|
115
|
-
const { container } = await render(
|
|
116
|
-
`<span [kjIcon]="'x'" [kjIconSize]="'lg'"></span>`,
|
|
117
|
-
{
|
|
118
|
-
imports: [KjIconDirective],
|
|
119
|
-
providers: [provideIcons({ x: 'url("a")' })],
|
|
120
|
-
},
|
|
121
|
-
);
|
|
122
|
-
const styleAttr = container.querySelector('span')!.getAttribute('style') ?? '';
|
|
123
|
-
expect(styleAttr).toContain('font-size: var(--kj-icon-size-lg)');
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe('KjIconDirective — font mode', () => {
|
|
128
|
-
it('reflects data-kj-icon-mode="font" for @font.* names', async () => {
|
|
129
|
-
const { container } = await render(
|
|
130
|
-
`<span [kjIcon]="'@font.fa-cog'"></span>`,
|
|
131
|
-
{
|
|
132
|
-
imports: [KjIconDirective],
|
|
133
|
-
providers: [provideIcons({ '@font.fa-cog': '"\\f013"' })],
|
|
134
|
-
},
|
|
135
|
-
);
|
|
136
|
-
const host = container.querySelector('span')!;
|
|
137
|
-
expect(host.getAttribute('data-kj-icon-mode')).toBe('font');
|
|
138
|
-
expect(host.style.getPropertyValue('--kj-icon')).toBe('"\\f013"');
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('KjIconDirective — loader pending', () => {
|
|
143
|
-
it('renders no --kj-icon value while async load is pending', async () => {
|
|
144
|
-
const neverResolves = () =>
|
|
145
|
-
new Promise<string>(() => {/* hangs forever */});
|
|
146
|
-
const { container } = await render(`<span [kjIcon]="'missing'"></span>`, {
|
|
147
|
-
imports: [KjIconDirective],
|
|
148
|
-
providers: [provideIconLoader(neverResolves)],
|
|
149
|
-
});
|
|
150
|
-
const host = container.querySelector('span')!;
|
|
151
|
-
expect(host.style.getPropertyValue('--kj-icon')).toBe('');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('updates --kj-icon once loader resolves', async () => {
|
|
155
|
-
let resolveLoad!: (v: string) => void;
|
|
156
|
-
const loader = (_n: string) =>
|
|
157
|
-
new Promise<string>((res) => {
|
|
158
|
-
resolveLoad = res;
|
|
159
|
-
});
|
|
160
|
-
const { container, fixture } = await render(
|
|
161
|
-
`<span [kjIcon]="'settings'"></span>`,
|
|
162
|
-
{
|
|
163
|
-
imports: [KjIconDirective],
|
|
164
|
-
providers: [provideIconLoader(loader)],
|
|
165
|
-
},
|
|
166
|
-
);
|
|
167
|
-
const host = container.querySelector('span')!;
|
|
168
|
-
expect(host.style.getPropertyValue('--kj-icon')).toBe('');
|
|
169
|
-
|
|
170
|
-
resolveLoad('url("loaded")');
|
|
171
|
-
await Promise.resolve();
|
|
172
|
-
await Promise.resolve();
|
|
173
|
-
fixture.detectChanges();
|
|
174
|
-
|
|
175
|
-
expect(host.style.getPropertyValue('--kj-icon')).toBe('url("loaded")');
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('KjIconDirective — a11y audits', () => {
|
|
180
|
-
it('decorative icon passes axe', async () => {
|
|
181
|
-
const { container } = await render(`<span [kjIcon]="'settings'"></span>`, {
|
|
182
|
-
imports: [KjIconDirective],
|
|
183
|
-
providers: [provideIcons({ settings: 'url("a")' })],
|
|
184
|
-
});
|
|
185
|
-
expect(await axe(container)).toHaveNoViolations();
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('meaningful icon passes axe', async () => {
|
|
189
|
-
const { container } = await render(
|
|
190
|
-
`<span [kjIcon]="'alert'" [kjIconLabel]="'Warning'"></span>`,
|
|
191
|
-
{
|
|
192
|
-
imports: [KjIconDirective],
|
|
193
|
-
providers: [provideIcons({ alert: 'url("a")' })],
|
|
194
|
-
},
|
|
195
|
-
);
|
|
196
|
-
expect(await axe(container)).toHaveNoViolations();
|
|
197
|
-
});
|
|
198
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { Directive, computed, input } from '@angular/core';
|
|
2
|
-
import { getIconMode } from './icon.mode';
|
|
3
|
-
import { injectKjIconResolver } from './icon.resolver';
|
|
4
|
-
import type { KjIconColor, KjIconSize } from './icon.types';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Renders an icon on its host element via CSS custom properties. Owns icon
|
|
8
|
-
* accessibility (decorative by default; meaningful when `kjIconLabel` is set).
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```html
|
|
12
|
-
* <span [kjIcon]="'settings'"></span>
|
|
13
|
-
* <span [kjIcon]="'alert-triangle'" [kjIconLabel]="'Warning'"></span>
|
|
14
|
-
* <span [kjIcon]="'check'" [kjIconColor]="'success'" [kjIconSize]="'lg'"></span>
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* @doc-example Gallery
|
|
18
|
-
* Browseable Lucide icon grid with a substring filter. Click any tile to
|
|
19
|
-
* copy its `<i kjIcon="…">` snippet.
|
|
20
|
-
* @doc-file ../../../components/src/icon/icon.gallery.example.ts
|
|
21
|
-
* @doc-example Usage
|
|
22
|
-
* Common icon shapes — decorative inline, meaningful with a label, sized
|
|
23
|
-
* variants, and semantic color tokens.
|
|
24
|
-
* @doc-file ../../../components/src/icon/icon.usage.example.ts
|
|
25
|
-
*
|
|
26
|
-
* @doc-keyboard
|
|
27
|
-
* None — the icon directive is non-interactive. Place inside a focusable parent (button/link) for activation semantics.
|
|
28
|
-
*
|
|
29
|
-
* @doc-aria
|
|
30
|
-
* aria-hidden — Set to "true" by default (decorative). Removed when [kjIconLabel] is provided
|
|
31
|
-
* role="img" — Set when [kjIconLabel] is provided (meaningful icon)
|
|
32
|
-
* aria-label — Bound to [kjIconLabel] when provided
|
|
33
|
-
* data-kj-icon-mode — Mirrors the resolved mode ("svg" | "font") for theme CSS
|
|
34
|
-
*
|
|
35
|
-
* @doc-css-var
|
|
36
|
-
* --kj-icon — CSS-ready resolved icon value (a url() for svg mode or a quoted glyph for font mode). Set by the directive.
|
|
37
|
-
* --kj-icon-font — Font family used in font mode. Consumers set this on a parent when shipping icon fonts.
|
|
38
|
-
* --kj-color-icon-* — Foreground color tokens for [kjIconColor] (muted/primary/success/warning/danger/info).
|
|
39
|
-
* --kj-icon-size-* — Em-relative size tokens for [kjIconSize] (xs/sm/md/lg/xl).
|
|
40
|
-
*
|
|
41
|
-
* @doc-touch
|
|
42
|
-
* The icon is layout-only and does not require a 44×44 target on its own.
|
|
43
|
-
* When the icon is the sole label of an interactive control, the parent
|
|
44
|
-
* (`kj-button kjSize="icon"`, `<a>`, etc.) must meet WCAG 2.5.5.
|
|
45
|
-
*
|
|
46
|
-
* @doc-a11y
|
|
47
|
-
* Decorative by default — `aria-hidden="true"` keeps the icon silent for
|
|
48
|
-
* AT. Pass `[kjIconLabel]` only when the icon conveys meaning that is not
|
|
49
|
-
* duplicated in adjacent text; this swaps in `role="img"` and the label.
|
|
50
|
-
* Color tokens map to `--kj-color-icon-{token}` so theme palettes can
|
|
51
|
-
* retarget per-mode without API churn.
|
|
52
|
-
*
|
|
53
|
-
* @doc-related button,link,badge
|
|
54
|
-
*
|
|
55
|
-
* @doc-category Core/Icon
|
|
56
|
-
* @doc
|
|
57
|
-
* @doc-name icon
|
|
58
|
-
* @doc-description Renders an accessible icon on its host element by name with color and size tokens.
|
|
59
|
-
* @doc-is-main
|
|
60
|
-
*/
|
|
61
|
-
@Directive({
|
|
62
|
-
selector: 'span[kjIcon], i[kjIcon]',
|
|
63
|
-
standalone: true,
|
|
64
|
-
host: {
|
|
65
|
-
class: 'kj-icon',
|
|
66
|
-
'[style.--kj-icon]': 'iconValue()',
|
|
67
|
-
'[style.color]': 'colorVar()',
|
|
68
|
-
'[style.font-size]': 'sizeVar()',
|
|
69
|
-
'[attr.data-kj-icon-mode]': 'mode()',
|
|
70
|
-
'[attr.aria-hidden]': 'ariaHidden()',
|
|
71
|
-
'[attr.role]': 'roleAttr()',
|
|
72
|
-
'[attr.aria-label]': 'ariaLabelAttr()',
|
|
73
|
-
},
|
|
74
|
-
})
|
|
75
|
-
export class KjIconDirective {
|
|
76
|
-
private readonly resolve = injectKjIconResolver();
|
|
77
|
-
|
|
78
|
-
/** Icon name. Names starting with `@font.` use font mode. */
|
|
79
|
-
readonly kjIcon = input.required<string>();
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Accessible name. When set, the icon is treated as meaningful:
|
|
83
|
-
* `role="img"`, `aria-label` set, `aria-hidden` removed. When unset
|
|
84
|
-
* (the default), the icon is decorative and `aria-hidden="true"`.
|
|
85
|
-
*/
|
|
86
|
-
readonly kjIconLabel = input<string | null>(null);
|
|
87
|
-
|
|
88
|
-
/** Semantic color token. Default `null` means inherit (CSS `currentColor`). */
|
|
89
|
-
readonly kjIconColor = input<KjIconColor | null>(null);
|
|
90
|
-
|
|
91
|
-
/** Size token. Default `null` means inherit from surrounding text. */
|
|
92
|
-
readonly kjIconSize = input<KjIconSize | null>(null);
|
|
93
|
-
|
|
94
|
-
protected readonly mode = computed(() => getIconMode(this.kjIcon()));
|
|
95
|
-
protected readonly iconValue = computed(() => this.resolve(this.kjIcon()));
|
|
96
|
-
|
|
97
|
-
protected readonly ariaHidden = computed(() =>
|
|
98
|
-
this.kjIconLabel() ? null : 'true',
|
|
99
|
-
);
|
|
100
|
-
protected readonly roleAttr = computed(() =>
|
|
101
|
-
this.kjIconLabel() ? 'img' : null,
|
|
102
|
-
);
|
|
103
|
-
protected readonly ariaLabelAttr = computed(() => this.kjIconLabel());
|
|
104
|
-
|
|
105
|
-
protected readonly colorVar = computed(() => {
|
|
106
|
-
const c = this.kjIconColor();
|
|
107
|
-
return c && c !== 'inherit' ? `var(--kj-color-icon-${c})` : null;
|
|
108
|
-
});
|
|
109
|
-
protected readonly sizeVar = computed(() => {
|
|
110
|
-
const s = this.kjIconSize();
|
|
111
|
-
return s ? `var(--kj-icon-size-${s})` : null;
|
|
112
|
-
});
|
|
113
|
-
}
|