@vadem/ui 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-lucide.txt +43 -0
- package/README.md +19 -2
- package/fesm2022/vadem-ui-accordion.mjs +139 -0
- package/fesm2022/vadem-ui-accordion.mjs.map +1 -0
- package/fesm2022/vadem-ui-active-filters.mjs +355 -0
- package/fesm2022/vadem-ui-active-filters.mjs.map +1 -0
- package/fesm2022/vadem-ui-alert-dialog.mjs +433 -0
- package/fesm2022/vadem-ui-alert-dialog.mjs.map +1 -0
- package/fesm2022/vadem-ui-alert.mjs +266 -0
- package/fesm2022/vadem-ui-alert.mjs.map +1 -0
- package/fesm2022/vadem-ui-autocomplete.mjs +715 -0
- package/fesm2022/vadem-ui-autocomplete.mjs.map +1 -0
- package/fesm2022/vadem-ui-avatar.mjs +219 -0
- package/fesm2022/vadem-ui-avatar.mjs.map +1 -0
- package/fesm2022/vadem-ui-badge.mjs +86 -0
- package/fesm2022/vadem-ui-badge.mjs.map +1 -0
- package/fesm2022/vadem-ui-breadcrumbs.mjs +61 -0
- package/fesm2022/vadem-ui-breadcrumbs.mjs.map +1 -0
- package/fesm2022/vadem-ui-button.mjs +220 -0
- package/fesm2022/vadem-ui-button.mjs.map +1 -0
- package/fesm2022/vadem-ui-calendar.mjs +1314 -0
- package/fesm2022/vadem-ui-calendar.mjs.map +1 -0
- package/fesm2022/vadem-ui-card.mjs +271 -0
- package/fesm2022/vadem-ui-card.mjs.map +1 -0
- package/fesm2022/vadem-ui-character-count.mjs +269 -0
- package/fesm2022/vadem-ui-character-count.mjs.map +1 -0
- package/fesm2022/vadem-ui-chart.mjs +1984 -0
- package/fesm2022/vadem-ui-chart.mjs.map +1 -0
- package/fesm2022/vadem-ui-checkbox.mjs +67 -0
- package/fesm2022/vadem-ui-checkbox.mjs.map +1 -0
- package/fesm2022/vadem-ui-color-picker.mjs +815 -0
- package/fesm2022/vadem-ui-color-picker.mjs.map +1 -0
- package/fesm2022/vadem-ui-command.mjs +735 -0
- package/fesm2022/vadem-ui-command.mjs.map +1 -0
- package/fesm2022/vadem-ui-copy-button.mjs +375 -0
- package/fesm2022/vadem-ui-copy-button.mjs.map +1 -0
- package/fesm2022/vadem-ui-date-range-picker.mjs +1011 -0
- package/fesm2022/vadem-ui-date-range-picker.mjs.map +1 -0
- package/fesm2022/vadem-ui-description-list.mjs +59 -0
- package/fesm2022/vadem-ui-description-list.mjs.map +1 -0
- package/fesm2022/vadem-ui-dialog.mjs +587 -0
- package/fesm2022/vadem-ui-dialog.mjs.map +1 -0
- package/fesm2022/vadem-ui-dropzone.mjs +176 -0
- package/fesm2022/vadem-ui-dropzone.mjs.map +1 -0
- package/fesm2022/vadem-ui-editable-text.mjs +641 -0
- package/fesm2022/vadem-ui-editable-text.mjs.map +1 -0
- package/fesm2022/vadem-ui-empty-state.mjs +175 -0
- package/fesm2022/vadem-ui-empty-state.mjs.map +1 -0
- package/fesm2022/vadem-ui-expandable-text.mjs +244 -0
- package/fesm2022/vadem-ui-expandable-text.mjs.map +1 -0
- package/fesm2022/vadem-ui-field.mjs +583 -0
- package/fesm2022/vadem-ui-field.mjs.map +1 -0
- package/fesm2022/vadem-ui-file-preview.mjs +532 -0
- package/fesm2022/vadem-ui-file-preview.mjs.map +1 -0
- package/fesm2022/vadem-ui-file-size.mjs +83 -0
- package/fesm2022/vadem-ui-file-size.mjs.map +1 -0
- package/fesm2022/vadem-ui-form-error-summary.mjs +201 -0
- package/fesm2022/vadem-ui-form-error-summary.mjs.map +1 -0
- package/fesm2022/vadem-ui-icon.mjs +303 -0
- package/fesm2022/vadem-ui-icon.mjs.map +1 -0
- package/fesm2022/vadem-ui-input.mjs +120 -0
- package/fesm2022/vadem-ui-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-kbd.mjs +286 -0
- package/fesm2022/vadem-ui-kbd.mjs.map +1 -0
- package/fesm2022/vadem-ui-keyboard.mjs +105 -0
- package/fesm2022/vadem-ui-keyboard.mjs.map +1 -0
- package/fesm2022/vadem-ui-locale.mjs +443 -0
- package/fesm2022/vadem-ui-locale.mjs.map +1 -0
- package/fesm2022/vadem-ui-menu.mjs +637 -0
- package/fesm2022/vadem-ui-menu.mjs.map +1 -0
- package/fesm2022/vadem-ui-navigation-list.mjs +130 -0
- package/fesm2022/vadem-ui-navigation-list.mjs.map +1 -0
- package/fesm2022/vadem-ui-number-input.mjs +264 -0
- package/fesm2022/vadem-ui-number-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-otp-input.mjs +86 -0
- package/fesm2022/vadem-ui-otp-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-pagination.mjs +353 -0
- package/fesm2022/vadem-ui-pagination.mjs.map +1 -0
- package/fesm2022/vadem-ui-password-input.mjs +213 -0
- package/fesm2022/vadem-ui-password-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-popover.mjs +178 -0
- package/fesm2022/vadem-ui-popover.mjs.map +1 -0
- package/fesm2022/vadem-ui-progress.mjs +331 -0
- package/fesm2022/vadem-ui-progress.mjs.map +1 -0
- package/fesm2022/vadem-ui-radio.mjs +39 -0
- package/fesm2022/vadem-ui-radio.mjs.map +1 -0
- package/fesm2022/vadem-ui-range-slider.mjs +561 -0
- package/fesm2022/vadem-ui-range-slider.mjs.map +1 -0
- package/fesm2022/vadem-ui-rating.mjs +404 -0
- package/fesm2022/vadem-ui-rating.mjs.map +1 -0
- package/fesm2022/vadem-ui-relative-time.mjs +217 -0
- package/fesm2022/vadem-ui-relative-time.mjs.map +1 -0
- package/fesm2022/vadem-ui-reorder-list.mjs +601 -0
- package/fesm2022/vadem-ui-reorder-list.mjs.map +1 -0
- package/fesm2022/vadem-ui-scroll-area.mjs +65 -0
- package/fesm2022/vadem-ui-scroll-area.mjs.map +1 -0
- package/fesm2022/vadem-ui-search-input.mjs +307 -0
- package/fesm2022/vadem-ui-search-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-segmented.mjs +297 -0
- package/fesm2022/vadem-ui-segmented.mjs.map +1 -0
- package/fesm2022/vadem-ui-select.mjs +1462 -0
- package/fesm2022/vadem-ui-select.mjs.map +1 -0
- package/fesm2022/vadem-ui-sidebar.mjs +493 -0
- package/fesm2022/vadem-ui-sidebar.mjs.map +1 -0
- package/fesm2022/vadem-ui-skeleton.mjs +106 -0
- package/fesm2022/vadem-ui-skeleton.mjs.map +1 -0
- package/fesm2022/vadem-ui-slider.mjs +60 -0
- package/fesm2022/vadem-ui-slider.mjs.map +1 -0
- package/fesm2022/vadem-ui-splitter.mjs +438 -0
- package/fesm2022/vadem-ui-splitter.mjs.map +1 -0
- package/fesm2022/vadem-ui-stat.mjs +369 -0
- package/fesm2022/vadem-ui-stat.mjs.map +1 -0
- package/fesm2022/vadem-ui-stepper.mjs +483 -0
- package/fesm2022/vadem-ui-stepper.mjs.map +1 -0
- package/fesm2022/vadem-ui-switch.mjs +45 -0
- package/fesm2022/vadem-ui-switch.mjs.map +1 -0
- package/fesm2022/vadem-ui-table.mjs +593 -0
- package/fesm2022/vadem-ui-table.mjs.map +1 -0
- package/fesm2022/vadem-ui-tabs.mjs +405 -0
- package/fesm2022/vadem-ui-tabs.mjs.map +1 -0
- package/fesm2022/vadem-ui-tag-input.mjs +685 -0
- package/fesm2022/vadem-ui-tag-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-text-highlight.mjs +126 -0
- package/fesm2022/vadem-ui-text-highlight.mjs.map +1 -0
- package/fesm2022/vadem-ui-time-input.mjs +430 -0
- package/fesm2022/vadem-ui-time-input.mjs.map +1 -0
- package/fesm2022/vadem-ui-timeline.mjs +313 -0
- package/fesm2022/vadem-ui-timeline.mjs.map +1 -0
- package/fesm2022/vadem-ui-toast.mjs +397 -0
- package/fesm2022/vadem-ui-toast.mjs.map +1 -0
- package/fesm2022/vadem-ui-toolbar.mjs +396 -0
- package/fesm2022/vadem-ui-toolbar.mjs.map +1 -0
- package/fesm2022/vadem-ui-tooltip.mjs +218 -0
- package/fesm2022/vadem-ui-tooltip.mjs.map +1 -0
- package/fesm2022/vadem-ui-tree.mjs +551 -0
- package/fesm2022/vadem-ui-tree.mjs.map +1 -0
- package/fesm2022/vadem-ui-upload-list.mjs +408 -0
- package/fesm2022/vadem-ui-upload-list.mjs.map +1 -0
- package/fesm2022/vadem-ui.mjs +4 -0
- package/fesm2022/vadem-ui.mjs.map +1 -0
- package/fonts/jetbrains-mono/OFL.txt +93 -0
- package/fonts/jetbrains-mono/jetbrains-mono-cyrillic.woff2 +0 -0
- package/fonts/jetbrains-mono/jetbrains-mono-latin.woff2 +0 -0
- package/fonts/manrope/OFL.txt +93 -0
- package/fonts/manrope/manrope-cyrillic.woff2 +0 -0
- package/fonts/manrope/manrope-latin.woff2 +0 -0
- package/package.json +306 -3
- package/styles/base.css +160 -0
- package/styles/components/accordion.css +130 -0
- package/styles/components/active-filters.css +42 -0
- package/styles/components/alert-dialog.css +34 -0
- package/styles/components/alert.css +159 -0
- package/styles/components/autocomplete.css +97 -0
- package/styles/components/avatar.css +90 -0
- package/styles/components/badge.css +91 -0
- package/styles/components/breadcrumbs.css +94 -0
- package/styles/components/button.css +174 -0
- package/styles/components/calendar.css +186 -0
- package/styles/components/card.css +206 -0
- package/styles/components/character-count.css +41 -0
- package/styles/components/chart.css +308 -0
- package/styles/components/checkbox.css +115 -0
- package/styles/components/color-picker.css +158 -0
- package/styles/components/command.css +175 -0
- package/styles/components/copy-button.css +58 -0
- package/styles/components/date-range-picker.css +153 -0
- package/styles/components/description-list.css +69 -0
- package/styles/components/dialog.css +334 -0
- package/styles/components/dropzone.css +89 -0
- package/styles/components/editable-text.css +58 -0
- package/styles/components/empty-state.css +72 -0
- package/styles/components/expandable-text.css +24 -0
- package/styles/components/field.css +148 -0
- package/styles/components/file-preview.css +65 -0
- package/styles/components/form-error-summary.css +71 -0
- package/styles/components/icon.css +38 -0
- package/styles/components/index.css +80 -0
- package/styles/components/input.css +171 -0
- package/styles/components/kbd.css +42 -0
- package/styles/components/menu.css +168 -0
- package/styles/components/multi-select.css +156 -0
- package/styles/components/navigation-list.css +147 -0
- package/styles/components/number-input.css +33 -0
- package/styles/components/otp-input.css +26 -0
- package/styles/components/pagination.css +127 -0
- package/styles/components/password-input.css +20 -0
- package/styles/components/popover.css +93 -0
- package/styles/components/progress-ring.css +112 -0
- package/styles/components/progress.css +162 -0
- package/styles/components/radio.css +117 -0
- package/styles/components/range-slider.css +158 -0
- package/styles/components/rating.css +100 -0
- package/styles/components/reorder-list.css +143 -0
- package/styles/components/scroll-area.css +39 -0
- package/styles/components/search-input.css +25 -0
- package/styles/components/segmented.css +136 -0
- package/styles/components/select.css +257 -0
- package/styles/components/sidebar.css +105 -0
- package/styles/components/skeleton.css +83 -0
- package/styles/components/slider.css +132 -0
- package/styles/components/splitter.css +83 -0
- package/styles/components/stat.css +62 -0
- package/styles/components/stepper.css +236 -0
- package/styles/components/switch.css +107 -0
- package/styles/components/table.css +195 -0
- package/styles/components/tabs.css +198 -0
- package/styles/components/tag-input.css +138 -0
- package/styles/components/text-highlight.css +22 -0
- package/styles/components/time-input.css +96 -0
- package/styles/components/timeline.css +182 -0
- package/styles/components/toast.css +146 -0
- package/styles/components/toolbar.css +72 -0
- package/styles/components/tooltip.css +93 -0
- package/styles/components/tree.css +88 -0
- package/styles/components/upload-list.css +113 -0
- package/styles/fonts.css +67 -0
- package/styles/index.css +14 -0
- package/styles/reset.css +57 -0
- package/styles/tokens/primitives.css +364 -0
- package/styles/tokens/semantic.css +233 -0
- package/types/vadem-ui-accordion.d.ts +43 -0
- package/types/vadem-ui-active-filters.d.ts +73 -0
- package/types/vadem-ui-alert-dialog.d.ts +87 -0
- package/types/vadem-ui-alert.d.ts +64 -0
- package/types/vadem-ui-autocomplete.d.ts +156 -0
- package/types/vadem-ui-avatar.d.ts +59 -0
- package/types/vadem-ui-badge.d.ts +25 -0
- package/types/vadem-ui-breadcrumbs.d.ts +22 -0
- package/types/vadem-ui-button.d.ts +52 -0
- package/types/vadem-ui-calendar.d.ts +327 -0
- package/types/vadem-ui-card.d.ts +58 -0
- package/types/vadem-ui-character-count.d.ts +71 -0
- package/types/vadem-ui-chart.d.ts +452 -0
- package/types/vadem-ui-checkbox.d.ts +20 -0
- package/types/vadem-ui-color-picker.d.ts +171 -0
- package/types/vadem-ui-command.d.ts +145 -0
- package/types/vadem-ui-copy-button.d.ts +90 -0
- package/types/vadem-ui-date-range-picker.d.ts +216 -0
- package/types/vadem-ui-description-list.d.ts +15 -0
- package/types/vadem-ui-dialog.d.ts +174 -0
- package/types/vadem-ui-dropzone.d.ts +73 -0
- package/types/vadem-ui-editable-text.d.ts +141 -0
- package/types/vadem-ui-empty-state.d.ts +34 -0
- package/types/vadem-ui-expandable-text.d.ts +52 -0
- package/types/vadem-ui-field.d.ts +180 -0
- package/types/vadem-ui-file-preview.d.ts +108 -0
- package/types/vadem-ui-file-size.d.ts +18 -0
- package/types/vadem-ui-form-error-summary.d.ts +46 -0
- package/types/vadem-ui-icon.d.ts +152 -0
- package/types/vadem-ui-input.d.ts +31 -0
- package/types/vadem-ui-kbd.d.ts +66 -0
- package/types/vadem-ui-keyboard.d.ts +61 -0
- package/types/vadem-ui-locale.d.ts +241 -0
- package/types/vadem-ui-menu.d.ts +132 -0
- package/types/vadem-ui-navigation-list.d.ts +28 -0
- package/types/vadem-ui-number-input.d.ts +39 -0
- package/types/vadem-ui-otp-input.d.ts +15 -0
- package/types/vadem-ui-pagination.d.ts +96 -0
- package/types/vadem-ui-password-input.d.ts +36 -0
- package/types/vadem-ui-popover.d.ts +48 -0
- package/types/vadem-ui-progress.d.ts +95 -0
- package/types/vadem-ui-radio.d.ts +11 -0
- package/types/vadem-ui-range-slider.d.ts +136 -0
- package/types/vadem-ui-rating.d.ts +95 -0
- package/types/vadem-ui-relative-time.d.ts +58 -0
- package/types/vadem-ui-reorder-list.d.ts +120 -0
- package/types/vadem-ui-scroll-area.d.ts +13 -0
- package/types/vadem-ui-search-input.d.ts +58 -0
- package/types/vadem-ui-segmented.d.ts +76 -0
- package/types/vadem-ui-select.d.ts +303 -0
- package/types/vadem-ui-sidebar.d.ts +70 -0
- package/types/vadem-ui-skeleton.d.ts +28 -0
- package/types/vadem-ui-slider.d.ts +17 -0
- package/types/vadem-ui-splitter.d.ts +99 -0
- package/types/vadem-ui-stat.d.ts +101 -0
- package/types/vadem-ui-stepper.d.ts +108 -0
- package/types/vadem-ui-switch.d.ts +10 -0
- package/types/vadem-ui-table.d.ts +172 -0
- package/types/vadem-ui-tabs.d.ts +101 -0
- package/types/vadem-ui-tag-input.d.ts +170 -0
- package/types/vadem-ui-text-highlight.d.ts +27 -0
- package/types/vadem-ui-time-input.d.ts +47 -0
- package/types/vadem-ui-timeline.d.ts +54 -0
- package/types/vadem-ui-toast.d.ts +104 -0
- package/types/vadem-ui-toolbar.d.ts +80 -0
- package/types/vadem-ui-tooltip.d.ts +71 -0
- package/types/vadem-ui-tree.d.ts +123 -0
- package/types/vadem-ui-upload-list.d.ts +70 -0
- package/types/vadem-ui.d.ts +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vadem-ui-input.mjs","names":[],"sources":["../../../projects/ui/input/src/input.ts","../../../projects/ui/input/src/input-group.ts"],"sourcesContent":["import { Directive, input } from '@angular/core';\nimport { VdFieldControlBase } from '@vadem/ui/field';\n\nexport type VdInputSize = 'sm' | 'md' | 'lg';\n\n/**\n * Styles a native `<input>` or `<textarea>`. Value binding stays native (any forms API works);\n * validity is read from Reactive/Template forms (`NgControl`) or Signal Forms (`[formField]`)\n * and shown once the control is touched. Spec: specs/input.md\n */\n@Directive({\n selector: 'input[vdInput], textarea[vdInput]',\n host: {\n class: 'vd-input',\n '[attr.data-size]': 'size()',\n },\n})\nexport class VdInput extends VdFieldControlBase {\n readonly size = input<VdInputSize>('md');\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\n\n/**\n * Draws one control boundary around a `vdInput` plus icons or buttons in\n * `[slot=start]` / `[slot=end]`. Size, focus and invalid states follow the inner input.\n * Clicking the non-interactive parts (padding, icons) focuses the input.\n */\n@Component({\n selector: 'vd-input-group',\n template: `\n <ng-content select=\"[slot=start]\" />\n <ng-content />\n <ng-content select=\"[slot=end]\" />\n `,\n host: {\n class: 'vd-input-group',\n '(click)': 'focusInput($event)',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n})\nexport class VdInputGroup {\n private readonly el: HTMLElement = inject(ElementRef).nativeElement;\n\n protected focusInput(event: MouseEvent): void {\n const interactive = (event.target as Element).closest(\n 'button, a, input, textarea, select, [tabindex]',\n );\n // Only interactive elements *inside* the group handle their own clicks.\n if (interactive && interactive !== this.el && this.el.contains(interactive)) return;\n this.el.querySelector<HTMLElement>(':scope > .vd-input')?.focus();\n }\n}\n"],"mappings":";;;AAiBA,IAAa,UAAb,MAAa,gBAAgB,mBAAkB;CACpC,OAAO,MAAmB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAD7B,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAO,MAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAP,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAO,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,MAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,MAAA;GAAA,YAAA,EAAA,kBAAA,SAAA;GAAA,gBAAA;EAAA;EAAA,iBAAA;EAAA,UAAA;CAAA,CAAA;;AAAP,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAO,YAAA,CAAA;EAPnB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,MAAM;IACJ,OAAO;IACP,oBAAoB;GACrB;EACF,CAAA;;;;;;;;;;;ACWD,IAAa,eAAb,MAAa,aAAY;CACN,KAAkB,OAAO,UAAU,CAAC,CAAC;CAE5C,WAAW,OAAiB;EACpC,MAAM,cAAe,MAAM,OAAmB,QAC5C,gDAAgD;EAGlD,IAAI,eAAe,gBAAgB,KAAK,MAAM,KAAK,GAAG,SAAS,WAAW,GAAG;EAC7E,KAAK,GAAG,cAA2B,oBAAoB,CAAC,EAAE,MAAK;CACjE;CAVW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAY,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAZ,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAY,cAAA;EAAA,UAAA;EAAA,MAAA;GAAA,WAAA,EAAA,SAAA,qBAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UAZb;;;;;EAIT,UAAA;EAAA,iBAAA,GAAA,wBAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AAQU,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EAdxB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,UAAU;;;;;GAKV,MAAM;IACJ,OAAO;IACP,WAAW;GACZ;GACD,iBAAiB,wBAAwB;GACzC,eAAe,kBAAkB;EAClC,CAAA"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, ViewEncapsulation, afterNextRender, computed, inject, input, signal } from "@angular/core";
|
|
3
|
+
import { DOCUMENT } from "@angular/common";
|
|
4
|
+
import { vdTexts } from "@vadem/ui/locale";
|
|
5
|
+
const KEYS = {
|
|
6
|
+
mod: {
|
|
7
|
+
apple: ["⌘", "Command"],
|
|
8
|
+
other: ["Ctrl", "Control"],
|
|
9
|
+
aria: "Mod"
|
|
10
|
+
},
|
|
11
|
+
meta: {
|
|
12
|
+
apple: ["⌘", "Command"],
|
|
13
|
+
other: ["Win", "Windows"],
|
|
14
|
+
aria: "Meta"
|
|
15
|
+
},
|
|
16
|
+
ctrl: {
|
|
17
|
+
apple: ["⌃", "Control"],
|
|
18
|
+
other: ["Ctrl", "Control"],
|
|
19
|
+
aria: "Control"
|
|
20
|
+
},
|
|
21
|
+
alt: {
|
|
22
|
+
apple: ["⌥", "Option"],
|
|
23
|
+
other: ["Alt", "Alt"],
|
|
24
|
+
aria: "Alt"
|
|
25
|
+
},
|
|
26
|
+
shift: {
|
|
27
|
+
apple: ["⇧", "Shift"],
|
|
28
|
+
other: ["Shift", "Shift"],
|
|
29
|
+
aria: "Shift"
|
|
30
|
+
},
|
|
31
|
+
enter: {
|
|
32
|
+
apple: ["↵", "Return"],
|
|
33
|
+
other: ["Enter", "Enter"],
|
|
34
|
+
aria: "Enter"
|
|
35
|
+
},
|
|
36
|
+
esc: {
|
|
37
|
+
apple: ["Esc", "Escape"],
|
|
38
|
+
other: ["Esc", "Escape"],
|
|
39
|
+
aria: "Escape"
|
|
40
|
+
},
|
|
41
|
+
backspace: {
|
|
42
|
+
apple: ["⌫", "Delete"],
|
|
43
|
+
other: ["Backspace", "Backspace"],
|
|
44
|
+
aria: "Backspace"
|
|
45
|
+
},
|
|
46
|
+
delete: {
|
|
47
|
+
apple: ["⌦", "Forward delete"],
|
|
48
|
+
other: ["Del", "Delete"],
|
|
49
|
+
aria: "Delete"
|
|
50
|
+
},
|
|
51
|
+
tab: {
|
|
52
|
+
apple: ["⇥", "Tab"],
|
|
53
|
+
other: ["Tab", "Tab"],
|
|
54
|
+
aria: "Tab"
|
|
55
|
+
},
|
|
56
|
+
space: {
|
|
57
|
+
apple: ["Space", "Space"],
|
|
58
|
+
other: ["Space", "Space"],
|
|
59
|
+
aria: "Space"
|
|
60
|
+
},
|
|
61
|
+
up: {
|
|
62
|
+
apple: ["↑", "Up arrow"],
|
|
63
|
+
other: ["↑", "Up arrow"],
|
|
64
|
+
aria: "ArrowUp"
|
|
65
|
+
},
|
|
66
|
+
down: {
|
|
67
|
+
apple: ["↓", "Down arrow"],
|
|
68
|
+
other: ["↓", "Down arrow"],
|
|
69
|
+
aria: "ArrowDown"
|
|
70
|
+
},
|
|
71
|
+
left: {
|
|
72
|
+
apple: ["←", "Left arrow"],
|
|
73
|
+
other: ["←", "Left arrow"],
|
|
74
|
+
aria: "ArrowLeft"
|
|
75
|
+
},
|
|
76
|
+
right: {
|
|
77
|
+
apple: ["→", "Right arrow"],
|
|
78
|
+
other: ["→", "Right arrow"],
|
|
79
|
+
aria: "ArrowRight"
|
|
80
|
+
},
|
|
81
|
+
plus: {
|
|
82
|
+
apple: ["+", "Plus"],
|
|
83
|
+
other: ["+", "Plus"],
|
|
84
|
+
aria: "Plus"
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const ALIASES = {
|
|
88
|
+
control: "ctrl",
|
|
89
|
+
option: "alt",
|
|
90
|
+
opt: "alt",
|
|
91
|
+
cmd: "meta",
|
|
92
|
+
command: "meta",
|
|
93
|
+
return: "enter",
|
|
94
|
+
escape: "esc",
|
|
95
|
+
del: "delete",
|
|
96
|
+
arrowup: "up",
|
|
97
|
+
arrowdown: "down",
|
|
98
|
+
arrowleft: "left",
|
|
99
|
+
arrowright: "right"
|
|
100
|
+
};
|
|
101
|
+
function resolveKey(token, platform) {
|
|
102
|
+
const id = token.toLowerCase();
|
|
103
|
+
const def = KEYS[ALIASES[id] ?? id];
|
|
104
|
+
if (def) {
|
|
105
|
+
const [label, name] = def[platform];
|
|
106
|
+
return {
|
|
107
|
+
label,
|
|
108
|
+
name,
|
|
109
|
+
ariaName: def.aria === "Mod" ? platform === "apple" ? "Meta" : "Control" : def.aria
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const label = token.length === 1 ? token.toUpperCase() : token;
|
|
113
|
+
return {
|
|
114
|
+
label,
|
|
115
|
+
name: label,
|
|
116
|
+
ariaName: label
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function vdParseShortcut(keys, platform) {
|
|
120
|
+
return keys.trim().split(/\s+/).filter(Boolean).map((step) => step.split("+").filter(Boolean).map((token) => resolveKey(token, platform))).filter((step) => step.length > 0);
|
|
121
|
+
}
|
|
122
|
+
function vdShortcutAria(keys, platform) {
|
|
123
|
+
const steps = vdParseShortcut(keys, platform);
|
|
124
|
+
if (steps.length !== 1) return "";
|
|
125
|
+
return steps[0].map((key) => key.ariaName).join("+");
|
|
126
|
+
}
|
|
127
|
+
function vdDetectPlatform(nav) {
|
|
128
|
+
const source = `${nav?.platform ?? ""} ${nav?.userAgent ?? ""}`;
|
|
129
|
+
return /Mac|iPhone|iPad|iPod/i.test(source) ? "apple" : "other";
|
|
130
|
+
}
|
|
131
|
+
var VdKbd = class VdKbd {
|
|
132
|
+
keys = input.required(...ngDevMode ? [{ debugName: "keys" }] : /* istanbul ignore next */ []);
|
|
133
|
+
thenLabel = input(...ngDevMode ? [void 0, { debugName: "thenLabel" }] : /* istanbul ignore next */ []);
|
|
134
|
+
t = vdTexts("kbd", { thenLabel: this.thenLabel });
|
|
135
|
+
platform = input("auto", ...ngDevMode ? [{ debugName: "platform" }] : /* istanbul ignore next */ []);
|
|
136
|
+
detected = signal("other", ...ngDevMode ? [{ debugName: "detected" }] : /* istanbul ignore next */ []);
|
|
137
|
+
resolvedPlatform = computed(() => {
|
|
138
|
+
const chosen = this.platform();
|
|
139
|
+
return chosen === "auto" ? this.detected() : chosen;
|
|
140
|
+
}, ...ngDevMode ? [{ debugName: "resolvedPlatform" }] : /* istanbul ignore next */ []);
|
|
141
|
+
steps = computed(() => vdParseShortcut(this.keys(), this.resolvedPlatform()), ...ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []);
|
|
142
|
+
constructor() {
|
|
143
|
+
const doc = inject(DOCUMENT);
|
|
144
|
+
afterNextRender(() => this.detected.set(vdDetectPlatform(doc.defaultView?.navigator)));
|
|
145
|
+
}
|
|
146
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
147
|
+
minVersion: "12.0.0",
|
|
148
|
+
version: "22.2.1",
|
|
149
|
+
ngImport: i0,
|
|
150
|
+
type: VdKbd,
|
|
151
|
+
deps: [],
|
|
152
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
153
|
+
});
|
|
154
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
155
|
+
minVersion: "17.0.0",
|
|
156
|
+
version: "22.2.1",
|
|
157
|
+
type: VdKbd,
|
|
158
|
+
isStandalone: true,
|
|
159
|
+
selector: "vd-kbd",
|
|
160
|
+
inputs: {
|
|
161
|
+
keys: {
|
|
162
|
+
classPropertyName: "keys",
|
|
163
|
+
publicName: "keys",
|
|
164
|
+
isSignal: true,
|
|
165
|
+
isRequired: true,
|
|
166
|
+
transformFunction: null
|
|
167
|
+
},
|
|
168
|
+
thenLabel: {
|
|
169
|
+
classPropertyName: "thenLabel",
|
|
170
|
+
publicName: "thenLabel",
|
|
171
|
+
isSignal: true,
|
|
172
|
+
isRequired: false,
|
|
173
|
+
transformFunction: null
|
|
174
|
+
},
|
|
175
|
+
platform: {
|
|
176
|
+
classPropertyName: "platform",
|
|
177
|
+
publicName: "platform",
|
|
178
|
+
isSignal: true,
|
|
179
|
+
isRequired: false,
|
|
180
|
+
transformFunction: null
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
host: { classAttribute: "vd-kbd-host" },
|
|
184
|
+
ngImport: i0,
|
|
185
|
+
template: `
|
|
186
|
+
<kbd class="vd-kbd" [attr.data-platform]="resolvedPlatform()">
|
|
187
|
+
@for (step of steps(); track $index; let lastStep = $last) {
|
|
188
|
+
@for (key of step; track $index; let last = $last) {
|
|
189
|
+
<kbd>
|
|
190
|
+
@if (key.label === key.name) {
|
|
191
|
+
{{ key.label }}
|
|
192
|
+
} @else {
|
|
193
|
+
<span aria-hidden="true">{{ key.label }}</span>
|
|
194
|
+
<span class="vd-visually-hidden">{{ key.name }}</span>
|
|
195
|
+
}
|
|
196
|
+
</kbd>
|
|
197
|
+
@if (!last) {
|
|
198
|
+
<span class="vd-kbd__plus" aria-hidden="true">+</span>
|
|
199
|
+
<span class="vd-visually-hidden">{{ ' ' }}</span>
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
@if (!lastStep) {
|
|
203
|
+
<span class="vd-kbd__then"
|
|
204
|
+
>{{ ' ' }}<span class="vd-visually-hidden">{{ t().thenLabel }}</span
|
|
205
|
+
>{{ ' ' }}</span
|
|
206
|
+
>
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
</kbd>
|
|
210
|
+
`,
|
|
211
|
+
isInline: true,
|
|
212
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
213
|
+
encapsulation: i0.ViewEncapsulation.None
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
217
|
+
minVersion: "12.0.0",
|
|
218
|
+
version: "22.2.1",
|
|
219
|
+
ngImport: i0,
|
|
220
|
+
type: VdKbd,
|
|
221
|
+
decorators: [{
|
|
222
|
+
type: Component,
|
|
223
|
+
args: [{
|
|
224
|
+
selector: "vd-kbd",
|
|
225
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
226
|
+
encapsulation: ViewEncapsulation.None,
|
|
227
|
+
host: { class: "vd-kbd-host" },
|
|
228
|
+
template: `
|
|
229
|
+
<kbd class="vd-kbd" [attr.data-platform]="resolvedPlatform()">
|
|
230
|
+
@for (step of steps(); track $index; let lastStep = $last) {
|
|
231
|
+
@for (key of step; track $index; let last = $last) {
|
|
232
|
+
<kbd>
|
|
233
|
+
@if (key.label === key.name) {
|
|
234
|
+
{{ key.label }}
|
|
235
|
+
} @else {
|
|
236
|
+
<span aria-hidden="true">{{ key.label }}</span>
|
|
237
|
+
<span class="vd-visually-hidden">{{ key.name }}</span>
|
|
238
|
+
}
|
|
239
|
+
</kbd>
|
|
240
|
+
@if (!last) {
|
|
241
|
+
<span class="vd-kbd__plus" aria-hidden="true">+</span>
|
|
242
|
+
<span class="vd-visually-hidden">{{ ' ' }}</span>
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
@if (!lastStep) {
|
|
246
|
+
<span class="vd-kbd__then"
|
|
247
|
+
>{{ ' ' }}<span class="vd-visually-hidden">{{ t().thenLabel }}</span
|
|
248
|
+
>{{ ' ' }}</span
|
|
249
|
+
>
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
</kbd>
|
|
253
|
+
`
|
|
254
|
+
}]
|
|
255
|
+
}],
|
|
256
|
+
ctorParameters: () => [],
|
|
257
|
+
propDecorators: {
|
|
258
|
+
keys: [{
|
|
259
|
+
type: i0.Input,
|
|
260
|
+
args: [{
|
|
261
|
+
isSignal: true,
|
|
262
|
+
alias: "keys",
|
|
263
|
+
required: true
|
|
264
|
+
}]
|
|
265
|
+
}],
|
|
266
|
+
thenLabel: [{
|
|
267
|
+
type: i0.Input,
|
|
268
|
+
args: [{
|
|
269
|
+
isSignal: true,
|
|
270
|
+
alias: "thenLabel",
|
|
271
|
+
required: false
|
|
272
|
+
}]
|
|
273
|
+
}],
|
|
274
|
+
platform: [{
|
|
275
|
+
type: i0.Input,
|
|
276
|
+
args: [{
|
|
277
|
+
isSignal: true,
|
|
278
|
+
alias: "platform",
|
|
279
|
+
required: false
|
|
280
|
+
}]
|
|
281
|
+
}]
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
export { VdKbd, vdDetectPlatform, vdParseShortcut, vdShortcutAria };
|
|
285
|
+
|
|
286
|
+
//# sourceMappingURL=vadem-ui-kbd.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vadem-ui-kbd.mjs","names":[],"sources":["../../../projects/ui/kbd/src/core/shortcut.ts","../../../projects/ui/kbd/src/kbd.ts"],"sourcesContent":["/**\n * Framework-agnostic shortcut parsing: \"Mod+Shift+K\" -> keys with a visible label and a spoken\n * name, per platform. A space separates steps of a sequence (\"G D\").\n */\n\nexport type VdPlatform = 'apple' | 'other';\n\nexport interface VdShortcutKey {\n /** What is shown (may be a symbol). */\n label: string;\n /** Full name read by assistive technology. */\n name: string;\n /** Key name for `aria-keyshortcuts` (UI Events `key` values). */\n ariaName: string;\n}\n\ninterface KeyDef {\n apple: [label: string, name: string];\n other: [label: string, name: string];\n aria: string;\n}\n\nconst KEYS: Record<string, KeyDef> = {\n mod: { apple: ['⌘', 'Command'], other: ['Ctrl', 'Control'], aria: 'Mod' },\n meta: { apple: ['⌘', 'Command'], other: ['Win', 'Windows'], aria: 'Meta' },\n ctrl: { apple: ['⌃', 'Control'], other: ['Ctrl', 'Control'], aria: 'Control' },\n alt: { apple: ['⌥', 'Option'], other: ['Alt', 'Alt'], aria: 'Alt' },\n shift: { apple: ['⇧', 'Shift'], other: ['Shift', 'Shift'], aria: 'Shift' },\n enter: { apple: ['↵', 'Return'], other: ['Enter', 'Enter'], aria: 'Enter' },\n esc: { apple: ['Esc', 'Escape'], other: ['Esc', 'Escape'], aria: 'Escape' },\n backspace: { apple: ['⌫', 'Delete'], other: ['Backspace', 'Backspace'], aria: 'Backspace' },\n delete: { apple: ['⌦', 'Forward delete'], other: ['Del', 'Delete'], aria: 'Delete' },\n tab: { apple: ['⇥', 'Tab'], other: ['Tab', 'Tab'], aria: 'Tab' },\n space: { apple: ['Space', 'Space'], other: ['Space', 'Space'], aria: 'Space' },\n up: { apple: ['↑', 'Up arrow'], other: ['↑', 'Up arrow'], aria: 'ArrowUp' },\n down: { apple: ['↓', 'Down arrow'], other: ['↓', 'Down arrow'], aria: 'ArrowDown' },\n left: { apple: ['←', 'Left arrow'], other: ['←', 'Left arrow'], aria: 'ArrowLeft' },\n right: { apple: ['→', 'Right arrow'], other: ['→', 'Right arrow'], aria: 'ArrowRight' },\n plus: { apple: ['+', 'Plus'], other: ['+', 'Plus'], aria: 'Plus' },\n};\n\nconst ALIASES: Record<string, string> = {\n control: 'ctrl',\n option: 'alt',\n opt: 'alt',\n cmd: 'meta',\n command: 'meta',\n return: 'enter',\n escape: 'esc',\n del: 'delete',\n arrowup: 'up',\n arrowdown: 'down',\n arrowleft: 'left',\n arrowright: 'right',\n};\n\nfunction resolveKey(token: string, platform: VdPlatform): VdShortcutKey {\n const id = token.toLowerCase();\n const def = KEYS[ALIASES[id] ?? id];\n if (def) {\n const [label, name] = def[platform];\n // \"Mod\" has no aria-keyshortcuts value of its own; it maps to the platform modifier.\n const ariaName = def.aria === 'Mod' ? (platform === 'apple' ? 'Meta' : 'Control') : def.aria;\n return { label, name, ariaName };\n }\n const label = token.length === 1 ? token.toUpperCase() : token;\n return { label, name: label, ariaName: label };\n}\n\n/** Steps of a sequence, each a combination of keys. Empty tokens are ignored. */\nexport function vdParseShortcut(keys: string, platform: VdPlatform): VdShortcutKey[][] {\n return keys\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .map((step) =>\n step\n .split('+')\n .filter(Boolean)\n .map((token) => resolveKey(token, platform)),\n )\n .filter((step) => step.length > 0);\n}\n\n/**\n * Value for `aria-keyshortcuts` on the control that owns the shortcut. In that attribute a\n * space separates alternatives, and sequences cannot be expressed, so a multi-step sequence\n * returns an empty string (omit the attribute).\n */\nexport function vdShortcutAria(keys: string, platform: VdPlatform): string {\n const steps = vdParseShortcut(keys, platform);\n if (steps.length !== 1) return '';\n return steps[0].map((key) => key.ariaName).join('+');\n}\n\n/** Apple platforms show symbols; detection reads only a navigator-like object. */\nexport function vdDetectPlatform(\n nav?: { platform?: string; userAgent?: string } | null,\n): VdPlatform {\n const source = `${nav?.platform ?? ''} ${nav?.userAgent ?? ''}`;\n return /Mac|iPhone|iPad|iPod/i.test(source) ? 'apple' : 'other';\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { type VdPlatform, vdDetectPlatform, vdParseShortcut } from './core/shortcut';\nimport { vdTexts } from '@vadem/ui/locale';\n\n/**\n * Keyboard shortcut with platform-aware symbols and spoken key names. Spec: specs/kbd.md\n */\n@Component({\n selector: 'vd-kbd',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n host: { class: 'vd-kbd-host' },\n // Layout spacing comes from CSS gap; spoken separators are explicit interpolated spaces,\n // so template formatting never changes the result.\n template: `\n <kbd class=\"vd-kbd\" [attr.data-platform]=\"resolvedPlatform()\">\n @for (step of steps(); track $index; let lastStep = $last) {\n @for (key of step; track $index; let last = $last) {\n <kbd>\n @if (key.label === key.name) {\n {{ key.label }}\n } @else {\n <span aria-hidden=\"true\">{{ key.label }}</span>\n <span class=\"vd-visually-hidden\">{{ key.name }}</span>\n }\n </kbd>\n @if (!last) {\n <span class=\"vd-kbd__plus\" aria-hidden=\"true\">+</span>\n <span class=\"vd-visually-hidden\">{{ ' ' }}</span>\n }\n }\n @if (!lastStep) {\n <span class=\"vd-kbd__then\"\n >{{ ' ' }}<span class=\"vd-visually-hidden\">{{ t().thenLabel }}</span\n >{{ ' ' }}</span\n >\n }\n }\n </kbd>\n `,\n})\nexport class VdKbd {\n /** Keys joined with \"+\", sequence steps separated by spaces: \"Mod+K\", \"G D\". */\n readonly keys = input.required<string>();\n /** Spoken between steps of a sequence. */\n readonly thenLabel = input<string>();\n /** Text inputs resolved against the active VD_LOCALE. */\n protected readonly t = vdTexts('kbd', { thenLabel: this.thenLabel });\n\n /** \"auto\" detects the viewer's platform; set it to document one platform explicitly. */\n readonly platform = input<VdPlatform | 'auto'>('auto');\n\n /** Server rendering detects \"other\"; the browser corrects it after the first render. */\n private readonly detected = signal<VdPlatform>('other');\n readonly resolvedPlatform = computed(() => {\n const chosen = this.platform();\n return chosen === 'auto' ? this.detected() : chosen;\n });\n protected readonly steps = computed(() => vdParseShortcut(this.keys(), this.resolvedPlatform()));\n\n constructor() {\n const doc = inject(DOCUMENT);\n afterNextRender(() => this.detected.set(vdDetectPlatform(doc.defaultView?.navigator)));\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
function vdListTarget(key, current, disabled, options) {
|
|
2
|
+
const count = disabled.length;
|
|
3
|
+
if (count === 0) return null;
|
|
4
|
+
const first = scan(disabled, 0, 1);
|
|
5
|
+
const last = scan(disabled, count - 1, -1);
|
|
6
|
+
if (first === null || last === null) return null;
|
|
7
|
+
switch (key) {
|
|
8
|
+
case "Home": return first;
|
|
9
|
+
case "End": return last;
|
|
10
|
+
case "ArrowDown":
|
|
11
|
+
if (current < 0) return first;
|
|
12
|
+
return scan(disabled, current + 1, 1) ?? (options.loop ? first : current);
|
|
13
|
+
case "ArrowUp":
|
|
14
|
+
if (current < 0) return last;
|
|
15
|
+
return scan(disabled, current - 1, -1) ?? (options.loop ? last : current);
|
|
16
|
+
case "PageDown": return scan(disabled, Math.min(current + options.pageSize, count - 1), -1, current) ?? last;
|
|
17
|
+
case "PageUp": return scan(disabled, Math.max(current - options.pageSize, 0), 1, current) ?? first;
|
|
18
|
+
default: return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function scan(disabled, from, delta, stop) {
|
|
22
|
+
for (let i = from; i >= 0 && i < disabled.length; i += delta) {
|
|
23
|
+
if (stop !== void 0 && (delta === 1 ? i > stop : i < stop)) break;
|
|
24
|
+
if (!disabled[i]) return i;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function vdRovingTarget(key, current, disabled, options) {
|
|
29
|
+
const count = disabled.length;
|
|
30
|
+
if (count === 0) return null;
|
|
31
|
+
const horizontal = options.orientation === "horizontal";
|
|
32
|
+
const forwardKey = horizontal ? options.dir === "rtl" ? "ArrowLeft" : "ArrowRight" : "ArrowDown";
|
|
33
|
+
const backwardKey = horizontal ? options.dir === "rtl" ? "ArrowRight" : "ArrowLeft" : "ArrowUp";
|
|
34
|
+
switch (key) {
|
|
35
|
+
case "Home": return firstEnabled(disabled, 0, 1);
|
|
36
|
+
case "End": return firstEnabled(disabled, count - 1, -1);
|
|
37
|
+
case forwardKey: return step(disabled, current, 1, options.loop);
|
|
38
|
+
case backwardKey: return step(disabled, current, -1, options.loop);
|
|
39
|
+
default: return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function vdIsActivationKey(key) {
|
|
43
|
+
return key === "Enter" || key === " ";
|
|
44
|
+
}
|
|
45
|
+
function firstEnabled(disabled, from, delta) {
|
|
46
|
+
for (let i = from; i >= 0 && i < disabled.length; i += delta) if (!disabled[i]) return i;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function step(disabled, current, delta, loop) {
|
|
50
|
+
const count = disabled.length;
|
|
51
|
+
let i = current;
|
|
52
|
+
for (let n = 0; n < count; n++) {
|
|
53
|
+
i += delta;
|
|
54
|
+
if (i < 0 || i >= count) {
|
|
55
|
+
if (!loop) return current;
|
|
56
|
+
i = (i + count) % count;
|
|
57
|
+
}
|
|
58
|
+
if (!disabled[i]) return i;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
var VdTypeahead = class {
|
|
63
|
+
timeout;
|
|
64
|
+
now;
|
|
65
|
+
buffer = "";
|
|
66
|
+
last = 0;
|
|
67
|
+
constructor(timeout = 500, now = () => Date.now()) {
|
|
68
|
+
this.timeout = timeout;
|
|
69
|
+
this.now = now;
|
|
70
|
+
}
|
|
71
|
+
static accepts(event) {
|
|
72
|
+
return event.key.length === 1 && event.key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
73
|
+
}
|
|
74
|
+
match(char, labels, disabled, current) {
|
|
75
|
+
const t = this.now();
|
|
76
|
+
if (t - this.last > this.timeout) this.buffer = "";
|
|
77
|
+
this.last = t;
|
|
78
|
+
const c = char.toLocaleLowerCase();
|
|
79
|
+
const repeating = this.buffer.length > 0 && [...this.buffer].every((ch) => ch === c);
|
|
80
|
+
this.buffer += c;
|
|
81
|
+
const query = repeating ? c : this.buffer;
|
|
82
|
+
const start = repeating || this.buffer.length === 1 ? current + 1 : Math.max(current, 0);
|
|
83
|
+
const n = labels.length;
|
|
84
|
+
for (let i = 0; i < n; i++) {
|
|
85
|
+
const idx = ((start + i) % n + n) % n;
|
|
86
|
+
if (!disabled[idx] && vdNormalize(labels[idx]).startsWith(query)) return idx;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
reset() {
|
|
91
|
+
this.buffer = "";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
function vdNormalize(text) {
|
|
95
|
+
return text.normalize("NFD").replace(/\p{M}/gu, "").replace(/[’ʼ`]/g, "'").toLocaleLowerCase().trim();
|
|
96
|
+
}
|
|
97
|
+
function vdMatchesQuery(label, query) {
|
|
98
|
+
const words = vdNormalize(query).split(/\s+/).filter(Boolean);
|
|
99
|
+
if (words.length === 0) return true;
|
|
100
|
+
const haystack = vdNormalize(label);
|
|
101
|
+
return words.every((w) => haystack.includes(w));
|
|
102
|
+
}
|
|
103
|
+
export { VdTypeahead, vdIsActivationKey, vdListTarget, vdMatchesQuery, vdNormalize, vdRovingTarget };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=vadem-ui-keyboard.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vadem-ui-keyboard.mjs","names":[],"sources":["../../../projects/ui/keyboard/src/list-keys.ts","../../../projects/ui/keyboard/src/roving-keys.ts","../../../projects/ui/keyboard/src/typeahead.ts"],"sourcesContent":["/**\n * Framework-agnostic keyboard navigation for vertical lists with an \"active\" item\n * (listbox options, menu items): arrows, Home/End, PageUp/PageDown, disabled items skipped.\n */\n\nexport interface VdListKeyOptions {\n /** Wrap at the ends. APG listbox: false; menu: true. */\n loop: boolean;\n /** Items moved by PageUp/PageDown. */\n pageSize: number;\n}\n\n/**\n * Index to make active for `key`, or `null` when the key isn't handled.\n * `current` may be -1 (nothing active yet): ArrowDown goes to the first, ArrowUp to the last.\n * When no enabled item exists in the direction, returns `current`.\n */\nexport function vdListTarget(\n key: string,\n current: number,\n disabled: readonly boolean[],\n options: VdListKeyOptions,\n): number | null {\n const count = disabled.length;\n if (count === 0) return null;\n const first = scan(disabled, 0, 1);\n const last = scan(disabled, count - 1, -1);\n if (first === null || last === null) return null;\n\n switch (key) {\n case 'Home':\n return first;\n case 'End':\n return last;\n case 'ArrowDown':\n if (current < 0) return first;\n return scan(disabled, current + 1, 1) ?? (options.loop ? first : current);\n case 'ArrowUp':\n if (current < 0) return last;\n return scan(disabled, current - 1, -1) ?? (options.loop ? last : current);\n case 'PageDown':\n return scan(disabled, Math.min(current + options.pageSize, count - 1), -1, current) ?? last;\n case 'PageUp':\n return scan(disabled, Math.max(current - options.pageSize, 0), 1, current) ?? first;\n default:\n return null;\n }\n}\n\n/** First enabled index from `from` stepping by `delta`, optionally not passing `stop`. */\nfunction scan(\n disabled: readonly boolean[],\n from: number,\n delta: 1 | -1,\n stop?: number,\n): number | null {\n for (let i = from; i >= 0 && i < disabled.length; i += delta) {\n if (stop !== undefined && (delta === 1 ? i > stop : i < stop)) break;\n if (!disabled[i]) return i;\n }\n return null;\n}\n","/**\n * Framework-agnostic keyboard navigation for a one-dimensional set of items (tabs, toolbars,\n * segmented controls) following the WAI-ARIA APG. No DOM access: callers pass state in and\n * get the index to focus back.\n */\n\nexport type VdOrientation = 'horizontal' | 'vertical';\nexport type VdDirection = 'ltr' | 'rtl';\n\nexport interface VdRovingOptions {\n orientation: VdOrientation;\n dir: VdDirection;\n /** Wrap from last to first and back. APG tabs: true. */\n loop: boolean;\n}\n\n/**\n * Returns the index to move focus to for `key`, or `null` when the key isn't a navigation key\n * for this orientation (let the browser handle it). Disabled items are skipped; if every item is\n * disabled, returns `null`.\n */\nexport function vdRovingTarget(\n key: string,\n current: number,\n disabled: readonly boolean[],\n options: VdRovingOptions,\n): number | null {\n const count = disabled.length;\n if (count === 0) return null;\n\n const horizontal = options.orientation === 'horizontal';\n const forwardKey = horizontal\n ? options.dir === 'rtl'\n ? 'ArrowLeft'\n : 'ArrowRight'\n : 'ArrowDown';\n const backwardKey = horizontal ? (options.dir === 'rtl' ? 'ArrowRight' : 'ArrowLeft') : 'ArrowUp';\n\n switch (key) {\n case 'Home':\n return firstEnabled(disabled, 0, 1);\n case 'End':\n return firstEnabled(disabled, count - 1, -1);\n case forwardKey:\n return step(disabled, current, 1, options.loop);\n case backwardKey:\n return step(disabled, current, -1, options.loop);\n default:\n return null;\n }\n}\n\n/** Keys that activate the focused item when activation is manual. */\nexport function vdIsActivationKey(key: string): boolean {\n return key === 'Enter' || key === ' ';\n}\n\nfunction firstEnabled(disabled: readonly boolean[], from: number, delta: 1 | -1): number | null {\n for (let i = from; i >= 0 && i < disabled.length; i += delta) {\n if (!disabled[i]) return i;\n }\n return null;\n}\n\nfunction step(\n disabled: readonly boolean[],\n current: number,\n delta: 1 | -1,\n loop: boolean,\n): number | null {\n const count = disabled.length;\n let i = current;\n for (let n = 0; n < count; n++) {\n i += delta;\n if (i < 0 || i >= count) {\n if (!loop) return current;\n i = (i + count) % count;\n }\n if (!disabled[i]) return i;\n }\n return null;\n}\n","/**\n * Framework-agnostic typeahead: type letters to jump to the next item whose label starts with\n * them. Repeating one letter cycles through matches; the buffer resets after a pause.\n */\n\nexport class VdTypeahead {\n private buffer = '';\n private last = 0;\n\n constructor(\n private readonly timeout = 500,\n private readonly now: () => number = () => Date.now(),\n ) {}\n\n /** True for keys that should feed the typeahead (single printable characters, no modifiers). */\n static accepts(event: Pick<KeyboardEvent, 'key' | 'ctrlKey' | 'metaKey' | 'altKey'>): boolean {\n return (\n event.key.length === 1 &&\n event.key !== ' ' &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.altKey\n );\n }\n\n /** Index of the match, or `null`. Search starts after `current` and wraps. */\n match(\n char: string,\n labels: readonly string[],\n disabled: readonly boolean[],\n current: number,\n ): number | null {\n const t = this.now();\n if (t - this.last > this.timeout) this.buffer = '';\n this.last = t;\n\n const c = char.toLocaleLowerCase();\n const repeating = this.buffer.length > 0 && [...this.buffer].every((ch) => ch === c);\n this.buffer += c;\n const query = repeating ? c : this.buffer;\n // A fresh or cycling search looks past the current item; a longer word may still match it.\n const start = repeating || this.buffer.length === 1 ? current + 1 : Math.max(current, 0);\n\n const n = labels.length;\n for (let i = 0; i < n; i++) {\n const idx = (((start + i) % n) + n) % n;\n if (!disabled[idx] && vdNormalize(labels[idx]).startsWith(query)) return idx;\n }\n return null;\n }\n\n reset(): void {\n this.buffer = '';\n }\n}\n\n/**\n * Case- and accent-insensitive form for matching user input against labels. Diacritics are\n * dropped (so \"ї\" also matches \"і\", \"é\" matches \"e\"); the apostrophe variants are unified.\n */\nexport function vdNormalize(text: string): string {\n return text\n .normalize('NFD')\n .replace(/\\p{M}/gu, '')\n .replace(/[’ʼ`]/g, \"'\")\n .toLocaleLowerCase()\n .trim();\n}\n\n/** Filtering predicate for comboboxes: every word of the query occurs in the label. */\nexport function vdMatchesQuery(label: string, query: string): boolean {\n const words = vdNormalize(query).split(/\\s+/).filter(Boolean);\n if (words.length === 0) return true;\n const haystack = vdNormalize(label);\n return words.every((w) => haystack.includes(w));\n}\n"],"mappings":"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"}
|