@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
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { InjectionToken, Signal } from '@angular/core';
|
|
2
|
-
|
|
3
|
-
/** Logical text direction surfaced by the group to its CSS / wrapper. */
|
|
4
|
-
export type KjAvatarGroupDirection = 'ltr' | 'rtl';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Shape forwarded from the group to its child avatars as a default.
|
|
8
|
-
* Per-child overrides win.
|
|
9
|
-
*/
|
|
10
|
-
export type KjAvatarShape = 'circle' | 'rounded';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Shared state surfaced by `KjAvatarGroup` for child avatars (in the wrapper
|
|
14
|
-
* package) and the wrapper template to read.
|
|
15
|
-
*
|
|
16
|
-
* - `size` / `shape` are *defaults* — children may override per-instance.
|
|
17
|
-
* - `direction` mirrors the group's resolved logical direction.
|
|
18
|
-
* - `visibleCount`, `overflowCount`, `total` drive the count-aware
|
|
19
|
-
* `aria-label` and the wrapper's overflow chip.
|
|
20
|
-
*/
|
|
21
|
-
export interface KjAvatarGroupContext {
|
|
22
|
-
/** Size token forwarded from the group as a default for children. */
|
|
23
|
-
readonly size: Signal<string | undefined>;
|
|
24
|
-
/** Shape forwarded from the group as a default for children. */
|
|
25
|
-
readonly shape: Signal<KjAvatarShape | undefined>;
|
|
26
|
-
/** Logical text direction observed by the group. */
|
|
27
|
-
readonly direction: Signal<KjAvatarGroupDirection>;
|
|
28
|
-
/**
|
|
29
|
-
* Number of avatars rendered visibly, including the overflow chip when
|
|
30
|
-
* present.
|
|
31
|
-
*/
|
|
32
|
-
readonly visibleCount: Signal<number>;
|
|
33
|
-
/** Number of avatars hidden behind the chip. `0` when no overflow. */
|
|
34
|
-
readonly overflowCount: Signal<number>;
|
|
35
|
-
/**
|
|
36
|
-
* Effective total: `kjTotal` if provided (and not less than the projected
|
|
37
|
-
* count), otherwise the projected child count.
|
|
38
|
-
*/
|
|
39
|
-
readonly total: Signal<number>;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** Injection token for `KjAvatarGroupContext`. */
|
|
43
|
-
export const KJ_AVATAR_GROUP = new InjectionToken<KjAvatarGroupContext>(
|
|
44
|
-
'KjAvatarGroup',
|
|
45
|
-
);
|
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import { Component, PLATFORM_ID, inject } from '@angular/core';
|
|
2
|
-
import { render } from '@testing-library/angular';
|
|
3
|
-
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
4
|
-
|
|
5
|
-
import { KjAvatar, KjAvatarFallback } from './avatar';
|
|
6
|
-
import { KjAvatarGroup } from './avatar-group';
|
|
7
|
-
import { KJ_AVATAR_GROUP } from './avatar-group.context';
|
|
8
|
-
|
|
9
|
-
expect.extend(toHaveNoViolations);
|
|
10
|
-
|
|
11
|
-
const imports = [KjAvatar, KjAvatarFallback, KjAvatarGroup];
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Allow Angular's signal-driven `effect()` to run after a query update —
|
|
15
|
-
* tests need a microtask + a macrotask for content-children + writes to
|
|
16
|
-
* settle before asserting on host attributes.
|
|
17
|
-
*/
|
|
18
|
-
async function flush(): Promise<void> {
|
|
19
|
-
await new Promise<void>((resolve) => setTimeout(resolve, 0));
|
|
20
|
-
await Promise.resolve();
|
|
21
|
-
await Promise.resolve();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function setHtmlDir(value: 'ltr' | 'rtl' | null): void {
|
|
25
|
-
if (value === null) {
|
|
26
|
-
document.documentElement.removeAttribute('dir');
|
|
27
|
-
} else {
|
|
28
|
-
document.documentElement.setAttribute('dir', value);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
describe('KjAvatarGroup', () => {
|
|
33
|
-
afterEach(() => setHtmlDir(null));
|
|
34
|
-
|
|
35
|
-
it('enumerates projected children', async () => {
|
|
36
|
-
const { container } = await render(
|
|
37
|
-
`<span kjAvatarGroup>
|
|
38
|
-
<span kjAvatar>A</span>
|
|
39
|
-
<span kjAvatar>B</span>
|
|
40
|
-
<span kjAvatar>C</span>
|
|
41
|
-
</span>`,
|
|
42
|
-
{ imports },
|
|
43
|
-
);
|
|
44
|
-
await flush();
|
|
45
|
-
|
|
46
|
-
expect(container.querySelectorAll('[kjAvatar]')).toHaveLength(3);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('hides children past kjMax via [hidden] and data-overflow', async () => {
|
|
50
|
-
const { container } = await render(
|
|
51
|
-
`<span kjAvatarGroup [kjMax]="2">
|
|
52
|
-
<span kjAvatar id="a">A</span>
|
|
53
|
-
<span kjAvatar id="b">B</span>
|
|
54
|
-
<span kjAvatar id="c">C</span>
|
|
55
|
-
<span kjAvatar id="d">D</span>
|
|
56
|
-
</span>`,
|
|
57
|
-
{ imports },
|
|
58
|
-
);
|
|
59
|
-
await flush();
|
|
60
|
-
|
|
61
|
-
const a = container.querySelector('#a') as HTMLElement;
|
|
62
|
-
const b = container.querySelector('#b') as HTMLElement;
|
|
63
|
-
const c = container.querySelector('#c') as HTMLElement;
|
|
64
|
-
const d = container.querySelector('#d') as HTMLElement;
|
|
65
|
-
|
|
66
|
-
expect(a.hasAttribute('hidden')).toBe(false);
|
|
67
|
-
expect(b.hasAttribute('hidden')).toBe(false);
|
|
68
|
-
expect(c.hasAttribute('hidden')).toBe(true);
|
|
69
|
-
expect(c.getAttribute('data-overflow')).toBe('true');
|
|
70
|
-
expect(d.hasAttribute('hidden')).toBe(true);
|
|
71
|
-
expect(d.getAttribute('data-overflow')).toBe('true');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('exposes visible / overflow / total signals correctly', async () => {
|
|
75
|
-
@Component({
|
|
76
|
-
standalone: true,
|
|
77
|
-
imports,
|
|
78
|
-
template: `
|
|
79
|
-
<span kjAvatarGroup [kjMax]="2">
|
|
80
|
-
@for (i of items; track i) {
|
|
81
|
-
<span kjAvatar></span>
|
|
82
|
-
}
|
|
83
|
-
</span>`,
|
|
84
|
-
})
|
|
85
|
-
class Host {
|
|
86
|
-
items = [1, 2, 3, 4, 5];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const { fixture } = await render(Host);
|
|
90
|
-
await flush();
|
|
91
|
-
|
|
92
|
-
const el = fixture.nativeElement.querySelector(
|
|
93
|
-
'[kjAvatarGroup]',
|
|
94
|
-
) as HTMLElement;
|
|
95
|
-
expect(el).toBeTruthy();
|
|
96
|
-
|
|
97
|
-
// Visible count = min(5, 2) = 2; overflow = 5 - 2 = 3; total = 5.
|
|
98
|
-
// Verify via the count-aware aria-label and CSS variable as public surfaces.
|
|
99
|
-
expect(el.getAttribute('aria-label')).toBe('2 of 5 avatars');
|
|
100
|
-
expect(el.getAttribute('role')).toBe('group');
|
|
101
|
-
expect(el.style.getPropertyValue('--kj-avatar-group-count')).toBe('2');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('default count-aware aria-label uses "avatars"', async () => {
|
|
105
|
-
const { container } = await render(
|
|
106
|
-
`<span kjAvatarGroup [kjMax]="3">
|
|
107
|
-
<span kjAvatar></span>
|
|
108
|
-
<span kjAvatar></span>
|
|
109
|
-
<span kjAvatar></span>
|
|
110
|
-
<span kjAvatar></span>
|
|
111
|
-
<span kjAvatar></span>
|
|
112
|
-
</span>`,
|
|
113
|
-
{ imports },
|
|
114
|
-
);
|
|
115
|
-
await flush();
|
|
116
|
-
|
|
117
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
118
|
-
expect(el.getAttribute('aria-label')).toBe('3 of 5 avatars');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('aria-label uses kjAriaLabel noun and kjTotal override', async () => {
|
|
122
|
-
const { container } = await render(
|
|
123
|
-
`<span kjAvatarGroup [kjMax]="3" kjAriaLabel="collaborators" [kjTotal]="42">
|
|
124
|
-
<span kjAvatar></span>
|
|
125
|
-
<span kjAvatar></span>
|
|
126
|
-
<span kjAvatar></span>
|
|
127
|
-
</span>`,
|
|
128
|
-
{ imports },
|
|
129
|
-
);
|
|
130
|
-
await flush();
|
|
131
|
-
|
|
132
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
133
|
-
expect(el.getAttribute('aria-label')).toBe('3 of 42 collaborators');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('clamps kjTotal upward when smaller than projected child count', async () => {
|
|
137
|
-
const { container } = await render(
|
|
138
|
-
`<span kjAvatarGroup [kjMax]="2" [kjTotal]="1">
|
|
139
|
-
<span kjAvatar></span>
|
|
140
|
-
<span kjAvatar></span>
|
|
141
|
-
<span kjAvatar></span>
|
|
142
|
-
</span>`,
|
|
143
|
-
{ imports },
|
|
144
|
-
);
|
|
145
|
-
await flush();
|
|
146
|
-
|
|
147
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
148
|
-
// Clamped to 3 (the projected count); never reads "2 of 1".
|
|
149
|
-
expect(el.getAttribute('aria-label')).toBe('2 of 3 avatars');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('omits aria-label entirely when total === 0', async () => {
|
|
153
|
-
const { container } = await render(
|
|
154
|
-
`<span kjAvatarGroup [kjMax]="3"></span>`,
|
|
155
|
-
{ imports },
|
|
156
|
-
);
|
|
157
|
-
await flush();
|
|
158
|
-
|
|
159
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
160
|
-
expect(el.hasAttribute('aria-label')).toBe(false);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('aria-label override (kjAriaLabelOverride) wins over count-aware default', async () => {
|
|
164
|
-
const { container } = await render(
|
|
165
|
-
`<span kjAvatarGroup [kjMax]="2" kjAriaLabelOverride="Project team">
|
|
166
|
-
<span kjAvatar></span>
|
|
167
|
-
<span kjAvatar></span>
|
|
168
|
-
<span kjAvatar></span>
|
|
169
|
-
</span>`,
|
|
170
|
-
{ imports },
|
|
171
|
-
);
|
|
172
|
-
await flush();
|
|
173
|
-
|
|
174
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
175
|
-
expect(el.getAttribute('aria-label')).toBe('Project team');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('honours custom kjAriaLabelFormat for i18n', async () => {
|
|
179
|
-
@Component({
|
|
180
|
-
standalone: true,
|
|
181
|
-
imports,
|
|
182
|
-
template: `
|
|
183
|
-
<span kjAvatarGroup [kjMax]="2" [kjAriaLabelFormat]="format">
|
|
184
|
-
<span kjAvatar></span>
|
|
185
|
-
<span kjAvatar></span>
|
|
186
|
-
<span kjAvatar></span>
|
|
187
|
-
<span kjAvatar></span>
|
|
188
|
-
</span>`,
|
|
189
|
-
})
|
|
190
|
-
class Host {
|
|
191
|
-
format = (v: number, t: number, l: string) =>
|
|
192
|
-
`${v}/${t} ${l} (FR)`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const { fixture } = await render(Host);
|
|
196
|
-
await flush();
|
|
197
|
-
|
|
198
|
-
const el = fixture.nativeElement.querySelector(
|
|
199
|
-
'[kjAvatarGroup]',
|
|
200
|
-
) as HTMLElement;
|
|
201
|
-
expect(el.getAttribute('aria-label')).toBe('2/4 avatars (FR)');
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('size and shape propagate via KJ_AVATAR_GROUP context', async () => {
|
|
205
|
-
@Component({
|
|
206
|
-
selector: 'kj-test-child',
|
|
207
|
-
standalone: true,
|
|
208
|
-
template: `<span data-test-child [attr.data-size]="ctx?.size()" [attr.data-shape]="ctx?.shape()"></span>`,
|
|
209
|
-
})
|
|
210
|
-
class Child {
|
|
211
|
-
readonly ctx = inject(KJ_AVATAR_GROUP, { optional: true });
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
@Component({
|
|
215
|
-
standalone: true,
|
|
216
|
-
imports: [...imports, Child],
|
|
217
|
-
template: `
|
|
218
|
-
<span kjAvatarGroup kjSize="lg" kjShape="rounded">
|
|
219
|
-
<span kjAvatar><kj-test-child /></span>
|
|
220
|
-
<span kjAvatar><kj-test-child /></span>
|
|
221
|
-
</span>`,
|
|
222
|
-
})
|
|
223
|
-
class Host {}
|
|
224
|
-
|
|
225
|
-
const { container } = await render(Host);
|
|
226
|
-
await flush();
|
|
227
|
-
|
|
228
|
-
const probes = container.querySelectorAll('[data-test-child]');
|
|
229
|
-
expect(probes.length).toBe(2);
|
|
230
|
-
probes.forEach((p) => {
|
|
231
|
-
expect(p.getAttribute('data-size')).toBe('lg');
|
|
232
|
-
expect(p.getAttribute('data-shape')).toBe('rounded');
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('kjRole controls host role (group / list)', async () => {
|
|
237
|
-
const { container } = await render(
|
|
238
|
-
`<span kjAvatarGroup kjRole="list">
|
|
239
|
-
<span kjAvatar></span>
|
|
240
|
-
<span kjAvatar></span>
|
|
241
|
-
</span>`,
|
|
242
|
-
{ imports },
|
|
243
|
-
);
|
|
244
|
-
await flush();
|
|
245
|
-
|
|
246
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
247
|
-
expect(el.getAttribute('role')).toBe('list');
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('kjRole=null opts out of the host role attribute', async () => {
|
|
251
|
-
@Component({
|
|
252
|
-
standalone: true,
|
|
253
|
-
imports,
|
|
254
|
-
template: `
|
|
255
|
-
<span kjAvatarGroup [kjRole]="null">
|
|
256
|
-
<span kjAvatar></span>
|
|
257
|
-
</span>`,
|
|
258
|
-
})
|
|
259
|
-
class Host {}
|
|
260
|
-
|
|
261
|
-
const { container } = await render(Host);
|
|
262
|
-
await flush();
|
|
263
|
-
|
|
264
|
-
const el = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
265
|
-
expect(el.hasAttribute('role')).toBe(false);
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('LTR stacking writes per-child --kj-avatar-group-stack-order with first child on top', async () => {
|
|
269
|
-
setHtmlDir('ltr');
|
|
270
|
-
|
|
271
|
-
const { container } = await render(
|
|
272
|
-
`<span kjAvatarGroup [kjMax]="0">
|
|
273
|
-
<span kjAvatar id="a"></span>
|
|
274
|
-
<span kjAvatar id="b"></span>
|
|
275
|
-
<span kjAvatar id="c"></span>
|
|
276
|
-
</span>`,
|
|
277
|
-
{ imports },
|
|
278
|
-
);
|
|
279
|
-
await flush();
|
|
280
|
-
|
|
281
|
-
const a = container.querySelector('#a') as HTMLElement;
|
|
282
|
-
const b = container.querySelector('#b') as HTMLElement;
|
|
283
|
-
const c = container.querySelector('#c') as HTMLElement;
|
|
284
|
-
|
|
285
|
-
// First child highest stack-order in LTR.
|
|
286
|
-
expect(a.style.getPropertyValue('--kj-avatar-group-stack-order')).toBe('2');
|
|
287
|
-
expect(b.style.getPropertyValue('--kj-avatar-group-stack-order')).toBe('1');
|
|
288
|
-
expect(c.style.getPropertyValue('--kj-avatar-group-stack-order')).toBe('0');
|
|
289
|
-
|
|
290
|
-
const groupEl = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
291
|
-
expect(groupEl.getAttribute('data-direction')).toBe('ltr');
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it('RTL stacking flips so the last DOM child paints on top', async () => {
|
|
295
|
-
setHtmlDir('rtl');
|
|
296
|
-
|
|
297
|
-
const { container } = await render(
|
|
298
|
-
`<span kjAvatarGroup [kjMax]="0">
|
|
299
|
-
<span kjAvatar id="a"></span>
|
|
300
|
-
<span kjAvatar id="b"></span>
|
|
301
|
-
<span kjAvatar id="c"></span>
|
|
302
|
-
</span>`,
|
|
303
|
-
{ imports },
|
|
304
|
-
);
|
|
305
|
-
await flush();
|
|
306
|
-
// Direction signal updates after afterNextRender; allow another tick.
|
|
307
|
-
await flush();
|
|
308
|
-
|
|
309
|
-
const a = container.querySelector('#a') as HTMLElement;
|
|
310
|
-
const c = container.querySelector('#c') as HTMLElement;
|
|
311
|
-
|
|
312
|
-
const groupEl = container.querySelector('[kjAvatarGroup]') as HTMLElement;
|
|
313
|
-
expect(groupEl.getAttribute('data-direction')).toBe('rtl');
|
|
314
|
-
|
|
315
|
-
// In RTL the visually-leading face (last DOM child) should paint on
|
|
316
|
-
// top — so its stack-order is the highest, while the first DOM child
|
|
317
|
-
// is now visually trailing and paints behind.
|
|
318
|
-
expect(c.style.getPropertyValue('--kj-avatar-group-stack-order')).toBe('2');
|
|
319
|
-
expect(a.style.getPropertyValue('--kj-avatar-group-stack-order')).toBe('0');
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it('SSR safe — no DOM mutations when PLATFORM_ID is "server"', async () => {
|
|
323
|
-
const { container } = await render(
|
|
324
|
-
`<span kjAvatarGroup [kjMax]="1">
|
|
325
|
-
<span kjAvatar id="a"></span>
|
|
326
|
-
<span kjAvatar id="b"></span>
|
|
327
|
-
<span kjAvatar id="c"></span>
|
|
328
|
-
</span>`,
|
|
329
|
-
{
|
|
330
|
-
imports,
|
|
331
|
-
providers: [{ provide: PLATFORM_ID, useValue: 'server' }],
|
|
332
|
-
},
|
|
333
|
-
);
|
|
334
|
-
await flush();
|
|
335
|
-
|
|
336
|
-
// On the server we must not write [hidden] or stack-order CSS variables;
|
|
337
|
-
// those belong to the hydration step.
|
|
338
|
-
const b = container.querySelector('#b') as HTMLElement;
|
|
339
|
-
const c = container.querySelector('#c') as HTMLElement;
|
|
340
|
-
expect(b.hasAttribute('hidden')).toBe(false);
|
|
341
|
-
expect(c.hasAttribute('hidden')).toBe(false);
|
|
342
|
-
expect(b.style.getPropertyValue('--kj-avatar-group-stack-order')).toBe('');
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
it('passes axe accessibility audit (default group)', async () => {
|
|
346
|
-
const { container } = await render(
|
|
347
|
-
`<span kjAvatarGroup kjAriaLabel="collaborators" [kjMax]="2">
|
|
348
|
-
<span kjAvatar><span kjAvatarFallback aria-hidden="true">JD</span></span>
|
|
349
|
-
<span kjAvatar><span kjAvatarFallback aria-hidden="true">AB</span></span>
|
|
350
|
-
<span kjAvatar><span kjAvatarFallback aria-hidden="true">CD</span></span>
|
|
351
|
-
</span>`,
|
|
352
|
-
{ imports },
|
|
353
|
-
);
|
|
354
|
-
await flush();
|
|
355
|
-
|
|
356
|
-
expect(await axe(container)).toHaveNoViolations();
|
|
357
|
-
});
|
|
358
|
-
});
|
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Directive,
|
|
3
|
-
ElementRef,
|
|
4
|
-
PLATFORM_ID,
|
|
5
|
-
Signal,
|
|
6
|
-
computed,
|
|
7
|
-
contentChildren,
|
|
8
|
-
effect,
|
|
9
|
-
inject,
|
|
10
|
-
input,
|
|
11
|
-
} from '@angular/core';
|
|
12
|
-
import { isPlatformBrowser } from '@angular/common';
|
|
13
|
-
|
|
14
|
-
import { KjDirectionality } from '../primitives/directionality/directionality';
|
|
15
|
-
import { KjAvatar } from './avatar';
|
|
16
|
-
import {
|
|
17
|
-
KJ_AVATAR_GROUP,
|
|
18
|
-
KjAvatarGroupContext,
|
|
19
|
-
KjAvatarGroupDirection,
|
|
20
|
-
KjAvatarShape,
|
|
21
|
-
} from './avatar-group.context';
|
|
22
|
-
|
|
23
|
-
/** Format used to compose the count-aware `aria-label`. */
|
|
24
|
-
export type KjAvatarGroupAriaLabelFormat = (
|
|
25
|
-
visible: number,
|
|
26
|
-
total: number,
|
|
27
|
-
label: string,
|
|
28
|
-
) => string;
|
|
29
|
-
|
|
30
|
-
const DEFAULT_ARIA_LABEL_FORMAT: KjAvatarGroupAriaLabelFormat = (v, t, l) =>
|
|
31
|
-
`${v} of ${t} ${l}`;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Coordinates a horizontally stacked cluster of `KjAvatar` children.
|
|
35
|
-
*
|
|
36
|
-
* Owns:
|
|
37
|
-
* - **Counting** — enumerates the projected `KjAvatar` directives via
|
|
38
|
-
* `contentChildren` and exposes `visibleCount`, `overflowCount`, and `total`
|
|
39
|
-
* signals for the wrapper template.
|
|
40
|
-
* - **Overflow hiding (Plan C)** — writes `[hidden]` (and a
|
|
41
|
-
* `data-overflow="true"` data attribute) on each child past `kjMax`.
|
|
42
|
-
* Cleared automatically when the child re-enters the visible range.
|
|
43
|
-
* - **ARIA** — applies `role="group"` (or `"list"` / none) and a count-aware
|
|
44
|
-
* `aria-label` such as `"3 of 8 collaborators"`. Consumers may override the
|
|
45
|
-
* noun (`kjAriaLabel`) and the entire format function (`kjAriaLabelFormat`),
|
|
46
|
-
* or pass a static label via the standard `aria-label` attribute on the
|
|
47
|
-
* host (the host binding only writes when the consumer hasn't).
|
|
48
|
-
* - **RTL-aware stacking** — composes `KjDirectionality` and writes a
|
|
49
|
-
* per-child `--kj-avatar-group-stack-order` CSS custom property (and the
|
|
50
|
-
* group-wide `--kj-avatar-group-count` and `--kj-avatar-group-direction`)
|
|
51
|
-
* so theme CSS can paint first-on-top in either direction without walking
|
|
52
|
-
* ancestors.
|
|
53
|
-
*
|
|
54
|
-
* The directive renders nothing of its own (no template, no DOM mutations
|
|
55
|
-
* beyond child host attributes / inline custom properties). The wrapper
|
|
56
|
-
* component owns the chip element and the layout CSS.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```html
|
|
60
|
-
* <span kjAvatarGroup [kjMax]="3" kjAriaLabel="collaborators">
|
|
61
|
-
* <span kjAvatar>...</span>
|
|
62
|
-
* <span kjAvatar>...</span>
|
|
63
|
-
* <span kjAvatar>...</span>
|
|
64
|
-
* <span kjAvatar>...</span>
|
|
65
|
-
* <span kjAvatar>...</span>
|
|
66
|
-
* </span>
|
|
67
|
-
* ```
|
|
68
|
-
* @doc-category Core/Data display
|
|
69
|
-
* @doc
|
|
70
|
-
* @doc-name avatar
|
|
71
|
-
*/
|
|
72
|
-
@Directive({
|
|
73
|
-
selector: '[kjAvatarGroup]',
|
|
74
|
-
standalone: true,
|
|
75
|
-
exportAs: 'kjAvatarGroup',
|
|
76
|
-
providers: [{ provide: KJ_AVATAR_GROUP, useExisting: KjAvatarGroup }],
|
|
77
|
-
host: {
|
|
78
|
-
'[attr.role]': 'kjRole()',
|
|
79
|
-
'[attr.aria-label]': 'resolvedAriaLabel()',
|
|
80
|
-
'[attr.data-direction]': 'direction()',
|
|
81
|
-
'[style.--kj-avatar-group-count]': 'visibleCount()',
|
|
82
|
-
'[style.--kj-avatar-group-direction]': 'direction()',
|
|
83
|
-
},
|
|
84
|
-
})
|
|
85
|
-
export class KjAvatarGroup implements KjAvatarGroupContext {
|
|
86
|
-
private readonly platformId = inject(PLATFORM_ID);
|
|
87
|
-
private readonly directionality = inject(KjDirectionality);
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Maximum number of avatars to show before the overflow chip. Children past
|
|
91
|
-
* this index are hidden via `[hidden]` and counted toward
|
|
92
|
-
* `overflowCount`. `0` disables the cap (always show all, no chip).
|
|
93
|
-
* @default 4
|
|
94
|
-
*/
|
|
95
|
-
readonly kjMax = input<number>(4);
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Override of the effective total. When provided (and not less than the
|
|
99
|
-
* projected child count) drives the count-aware `aria-label` and the
|
|
100
|
-
* overflow count, so consumers can show a *page* of a larger collection
|
|
101
|
-
* (e.g. server-side pagination).
|
|
102
|
-
*
|
|
103
|
-
* If the consumer passes a value smaller than the projected count, the
|
|
104
|
-
* directive clamps to the projected count to avoid nonsense like `"5 of 3"`.
|
|
105
|
-
*/
|
|
106
|
-
readonly kjTotal = input<number | undefined>(undefined);
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Default size token forwarded to children via `KJ_AVATAR_GROUP`. Per-child
|
|
110
|
-
* overrides win.
|
|
111
|
-
*/
|
|
112
|
-
readonly kjSize = input<string | undefined>(undefined);
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Default shape forwarded to children via `KJ_AVATAR_GROUP`. Per-child
|
|
116
|
-
* overrides win.
|
|
117
|
-
* @default 'circle'
|
|
118
|
-
*/
|
|
119
|
-
readonly kjShape = input<KjAvatarShape | undefined>('circle');
|
|
120
|
-
|
|
121
|
-
/** Noun used in the count-aware `aria-label`. */
|
|
122
|
-
readonly kjAriaLabel = input<string>('avatars');
|
|
123
|
-
|
|
124
|
-
/** Formatter for the count-aware `aria-label`. */
|
|
125
|
-
readonly kjAriaLabelFormat = input<KjAvatarGroupAriaLabelFormat>(
|
|
126
|
-
DEFAULT_ARIA_LABEL_FORMAT,
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Host role. `'group'` for a decorative cluster, `'list'` when each child
|
|
131
|
-
* is wrapped in a `listitem` (e.g. interactive avatars as links), `null`
|
|
132
|
-
* to opt out entirely.
|
|
133
|
-
* @default 'group'
|
|
134
|
-
*/
|
|
135
|
-
readonly kjRole = input<'group' | 'list' | null>('group');
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Per-consumer override for the host `aria-label`. When set, takes
|
|
139
|
-
* precedence over the count-aware label. `null` opts out of `aria-label`.
|
|
140
|
-
*/
|
|
141
|
-
readonly kjAriaLabelOverride = input<string | null | undefined>(undefined);
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* All `KjAvatar` directives projected into the group, including those
|
|
145
|
-
* composed via `hostDirectives` on a wrapper component.
|
|
146
|
-
*
|
|
147
|
-
* `descendants: true` so wrapping a `<kj-avatar>` in `<a>` (the "stack of
|
|
148
|
-
* links" use case) still finds the child.
|
|
149
|
-
*/
|
|
150
|
-
private readonly avatars = contentChildren(KjAvatar, { descendants: true });
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Host elements for each projected `KjAvatar`, queried in parallel with
|
|
154
|
-
* the directive query so we can write `[hidden]` and CSS variables onto
|
|
155
|
-
* the right host node without having to expose `ElementRef` on `KjAvatar`.
|
|
156
|
-
*/
|
|
157
|
-
private readonly avatarHosts = contentChildren(KjAvatar, {
|
|
158
|
-
descendants: true,
|
|
159
|
-
read: ElementRef,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
/** Effective total: `kjTotal` (clamped) or the projected child count. */
|
|
163
|
-
readonly total: Signal<number> = computed(() => {
|
|
164
|
-
const childCount = this.avatars().length;
|
|
165
|
-
const override = this.kjTotal();
|
|
166
|
-
if (override === undefined) return childCount;
|
|
167
|
-
return Math.max(override, childCount);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
/** Number of children rendered visibly (the rest are `[hidden]`). */
|
|
171
|
-
readonly visibleCount: Signal<number> = computed(() => {
|
|
172
|
-
const max = this.kjMax();
|
|
173
|
-
const childCount = this.avatars().length;
|
|
174
|
-
if (max <= 0) return childCount;
|
|
175
|
-
return Math.min(childCount, max);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
/** Number of avatars hidden by the cap. `0` when nothing overflows. */
|
|
179
|
-
readonly overflowCount: Signal<number> = computed(() => {
|
|
180
|
-
const max = this.kjMax();
|
|
181
|
-
if (max <= 0) return 0;
|
|
182
|
-
return Math.max(0, this.total() - max);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
/** Logical text direction observed at the document level. */
|
|
186
|
-
readonly direction: Signal<KjAvatarGroupDirection> = computed(
|
|
187
|
-
() => this.directionality.current() as KjAvatarGroupDirection,
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
/** Default `aria-label`, omitted when the group is empty. */
|
|
191
|
-
private readonly countAwareAriaLabel = computed<string | null>(() => {
|
|
192
|
-
const total = this.total();
|
|
193
|
-
if (total === 0) return null;
|
|
194
|
-
return this.kjAriaLabelFormat()(this.visibleCount(), total, this.kjAriaLabel());
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* `aria-label` actually written to the host. Consumer override wins; `null`
|
|
199
|
-
* opts out of the attribute entirely.
|
|
200
|
-
*/
|
|
201
|
-
protected readonly resolvedAriaLabel = computed<string | null>(() => {
|
|
202
|
-
const override = this.kjAriaLabelOverride();
|
|
203
|
-
if (override !== undefined) return override ?? null;
|
|
204
|
-
return this.countAwareAriaLabel();
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
/** Read-only signal — exposed for the wrapper / spec ergonomics. */
|
|
208
|
-
get size(): Signal<string | undefined> {
|
|
209
|
-
return this.kjSize;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/** Read-only signal — exposed for the wrapper / spec ergonomics. */
|
|
213
|
-
get shape(): Signal<KjAvatarShape | undefined> {
|
|
214
|
-
return this.kjShape;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
constructor() {
|
|
218
|
-
// Plan C from `avatar-group.md`: write `[hidden]` and a per-child stack
|
|
219
|
-
// order onto each projected avatar's host element. Crosses the directive
|
|
220
|
-
// boundary by design — the group owns visibility of its overflow items.
|
|
221
|
-
effect(() => {
|
|
222
|
-
const hosts = this.avatarHosts();
|
|
223
|
-
const max = this.kjMax();
|
|
224
|
-
const dir = this.direction();
|
|
225
|
-
const visibleCount = this.visibleCount();
|
|
226
|
-
const isBrowser = isPlatformBrowser(this.platformId);
|
|
227
|
-
if (!isBrowser) return;
|
|
228
|
-
|
|
229
|
-
const total = hosts.length;
|
|
230
|
-
const cap = max <= 0 ? total : Math.min(max, total);
|
|
231
|
-
|
|
232
|
-
hosts.forEach((ref, index) => {
|
|
233
|
-
const el = ref.nativeElement as HTMLElement | null;
|
|
234
|
-
if (!el) return;
|
|
235
|
-
|
|
236
|
-
const overflow = max > 0 && index >= cap;
|
|
237
|
-
if (overflow) {
|
|
238
|
-
el.setAttribute('hidden', '');
|
|
239
|
-
el.setAttribute('data-overflow', 'true');
|
|
240
|
-
} else {
|
|
241
|
-
el.removeAttribute('hidden');
|
|
242
|
-
el.removeAttribute('data-overflow');
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// First-on-top in LTR (highest z-index goes to index 0); flipped in
|
|
246
|
-
// RTL so the visually-leading face — which is now on the right —
|
|
247
|
-
// still paints on top.
|
|
248
|
-
const visualIndex =
|
|
249
|
-
dir === 'rtl' ? Math.max(0, visibleCount - 1 - index) : index;
|
|
250
|
-
const stackOrder = Math.max(0, visibleCount - 1 - visualIndex);
|
|
251
|
-
el.style.setProperty(
|
|
252
|
-
'--kj-avatar-group-stack-order',
|
|
253
|
-
String(stackOrder),
|
|
254
|
-
);
|
|
255
|
-
el.style.setProperty('--kj-avatar-group-index', String(index));
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { render } from '@testing-library/angular';
|
|
2
|
-
import { axe, toHaveNoViolations } from 'jest-axe';
|
|
3
|
-
import { KjAvatar, KjAvatarImage, KjAvatarFallback } from './avatar';
|
|
4
|
-
|
|
5
|
-
expect.extend(toHaveNoViolations);
|
|
6
|
-
|
|
7
|
-
const imports = [KjAvatar, KjAvatarImage, KjAvatarFallback];
|
|
8
|
-
|
|
9
|
-
describe('KjAvatar', () => {
|
|
10
|
-
it('renders container', async () => {
|
|
11
|
-
const { container } = await render(`<span kjAvatar><img kjAvatarImage src="" alt="JD" /><span kjAvatarFallback>JD</span></span>`, { imports });
|
|
12
|
-
expect(container.querySelector('[kjAvatar]')).toBeInTheDocument();
|
|
13
|
-
});
|
|
14
|
-
it('passes axe audit', async () => {
|
|
15
|
-
const { container } = await render(`<span kjAvatar><img kjAvatarImage src="/p.jpg" alt="Jane Doe" /><span kjAvatarFallback aria-hidden="true">JD</span></span>`, { imports });
|
|
16
|
-
expect(await axe(container)).toHaveNoViolations();
|
|
17
|
-
});
|
|
18
|
-
});
|