sveltacular 0.0.76 → 1.0.0
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/README.md +142 -15
- package/dist/forms/base-input-wrapper.svelte +99 -0
- package/dist/forms/base-input-wrapper.svelte.d.ts +15 -0
- package/dist/forms/bool-box/bool-box.svelte +30 -17
- package/dist/forms/bool-box/bool-box.svelte.d.ts +9 -21
- package/dist/forms/button/button.svelte +153 -89
- package/dist/forms/button/button.svelte.d.ts +25 -29
- package/dist/forms/check-box/check-box-group.svelte +63 -29
- package/dist/forms/check-box/check-box-group.svelte.d.ts +11 -27
- package/dist/forms/check-box/check-box.svelte +57 -33
- package/dist/forms/check-box/check-box.svelte.d.ts +15 -25
- package/dist/forms/check-box/index.d.ts +2 -0
- package/dist/forms/check-box/index.js +2 -0
- package/dist/forms/combo/new-or-existing-combo.svelte +37 -18
- package/dist/forms/combo/new-or-existing-combo.svelte.d.ts +15 -25
- package/dist/forms/combo-box/combo-box.svelte +655 -0
- package/dist/forms/combo-box/combo-box.svelte.d.ts +62 -0
- package/dist/forms/combo-box/index.d.ts +1 -0
- package/dist/forms/combo-box/index.js +1 -0
- package/dist/forms/date-box/date-box.svelte +80 -54
- package/dist/forms/date-box/date-box.svelte.d.ts +21 -32
- package/dist/forms/file-area/file-area.svelte +109 -68
- package/dist/forms/file-area/file-area.svelte.d.ts +12 -22
- package/dist/forms/file-box/file-box.svelte +40 -21
- package/dist/forms/file-box/file-box.svelte.d.ts +14 -25
- package/dist/forms/form-field.svelte +18 -15
- package/dist/forms/form-field.svelte.d.ts +8 -18
- package/dist/forms/form-footer.svelte +6 -3
- package/dist/forms/form-footer.svelte.d.ts +6 -26
- package/dist/forms/form-header.svelte +15 -4
- package/dist/forms/form-header.svelte.d.ts +8 -18
- package/dist/forms/form-label.svelte +15 -6
- package/dist/forms/form-label.svelte.d.ts +8 -19
- package/dist/forms/form-section.svelte +15 -4
- package/dist/forms/form-section.svelte.d.ts +8 -18
- package/dist/forms/form.svelte +30 -13
- package/dist/forms/form.svelte.d.ts +11 -22
- package/dist/forms/index.d.ts +26 -0
- package/dist/forms/index.js +31 -0
- package/dist/forms/info-box/info-box.svelte +19 -8
- package/dist/forms/info-box/info-box.svelte.d.ts +8 -19
- package/dist/forms/list-box/index.d.ts +2 -0
- package/dist/forms/list-box/index.js +1 -0
- package/dist/forms/list-box/list-box.svelte +190 -118
- package/dist/forms/list-box/list-box.svelte.d.ts +16 -26
- package/dist/forms/money-box/money-box.svelte +223 -190
- package/dist/forms/money-box/money-box.svelte.d.ts +16 -28
- package/dist/forms/number-box/number-box.svelte +84 -67
- package/dist/forms/number-box/number-box.svelte.d.ts +17 -28
- package/dist/forms/phone-box/index.d.ts +1 -0
- package/dist/forms/phone-box/index.js +1 -0
- package/dist/forms/phone-box/phone-box.svelte +152 -122
- package/dist/forms/phone-box/phone-box.svelte.d.ts +8 -20
- package/dist/forms/radio-group/index.d.ts +2 -0
- package/dist/forms/radio-group/index.js +2 -0
- package/dist/forms/radio-group/radio-box.svelte +23 -8
- package/dist/forms/radio-group/radio-box.svelte.d.ts +10 -19
- package/dist/forms/radio-group/radio-group.svelte +27 -13
- package/dist/forms/radio-group/radio-group.svelte.d.ts +10 -21
- package/dist/forms/slider/slider.svelte +210 -0
- package/dist/forms/slider/slider.svelte.d.ts +17 -0
- package/dist/forms/switch-box/switch-box.svelte +35 -21
- package/dist/forms/switch-box/switch-box.svelte.d.ts +9 -20
- package/dist/forms/text-area/text-area.svelte +89 -15
- package/dist/forms/text-area/text-area.svelte.d.ts +15 -23
- package/dist/forms/text-box/text-box.svelte +253 -75
- package/dist/forms/text-box/text-box.svelte.d.ts +28 -36
- package/dist/forms/time-box/time-box.svelte +67 -0
- package/dist/forms/time-box/time-box.svelte.d.ts +12 -0
- package/dist/forms/url-box/url-box.svelte +32 -18
- package/dist/forms/url-box/url-box.svelte.d.ts +9 -20
- package/dist/forms/validation.d.ts +60 -0
- package/dist/forms/validation.js +123 -0
- package/dist/generic/address/address.svelte +22 -13
- package/dist/generic/address/address.svelte.d.ts +9 -19
- package/dist/generic/avatar/avatar.svelte +86 -0
- package/dist/generic/avatar/avatar.svelte.d.ts +10 -0
- package/dist/generic/badge/badge.svelte +82 -0
- package/dist/generic/badge/badge.svelte.d.ts +11 -0
- package/dist/generic/card/card-container.svelte +41 -13
- package/dist/generic/card/card-container.svelte.d.ts +8 -18
- package/dist/generic/card/card.svelte +47 -29
- package/dist/generic/card/card.svelte.d.ts +9 -19
- package/dist/generic/card/index.d.ts +3 -0
- package/dist/generic/card/index.js +2 -0
- package/dist/generic/chip/chip.svelte +90 -0
- package/dist/generic/chip/chip.svelte.d.ts +11 -0
- package/dist/generic/date/date-time.svelte +86 -64
- package/dist/generic/date/date-time.svelte.d.ts +10 -20
- package/dist/generic/divider/divider.svelte.d.ts +22 -19
- package/dist/generic/dot/dot.svelte +13 -4
- package/dist/generic/dot/dot.svelte.d.ts +7 -17
- package/dist/generic/dropdown-item/dropdown-item.svelte +24 -12
- package/dist/generic/dropdown-item/dropdown-item.svelte.d.ts +10 -21
- package/dist/generic/email/email.svelte +6 -4
- package/dist/generic/email/email.svelte.d.ts +5 -15
- package/dist/generic/empty/empty.svelte +57 -26
- package/dist/generic/empty/empty.svelte.d.ts +11 -21
- package/dist/generic/header/header.svelte +26 -10
- package/dist/generic/header/header.svelte.d.ts +10 -20
- package/dist/generic/index.d.ts +28 -0
- package/dist/generic/index.js +31 -0
- package/dist/generic/link/link.svelte +20 -7
- package/dist/generic/link/link.svelte.d.ts +11 -21
- package/dist/generic/list/index.d.ts +4 -0
- package/dist/generic/list/index.js +3 -0
- package/dist/generic/list/list-item.svelte +17 -13
- package/dist/generic/list/list-item.svelte.d.ts +6 -15
- package/dist/generic/list/list.d.ts +2 -2
- package/dist/generic/list/list.svelte +28 -15
- package/dist/generic/list/list.svelte.d.ts +9 -19
- package/dist/generic/menu/menu.svelte +163 -57
- package/dist/generic/menu/menu.svelte.d.ts +16 -24
- package/dist/generic/notice/notice.svelte +119 -81
- package/dist/generic/notice/notice.svelte.d.ts +17 -26
- package/dist/generic/overlay.svelte +40 -14
- package/dist/generic/overlay.svelte.d.ts +9 -19
- package/dist/generic/panel/panel.svelte +16 -6
- package/dist/generic/panel/panel.svelte.d.ts +8 -18
- package/dist/generic/phone/phone.svelte +30 -24
- package/dist/generic/phone/phone.svelte.d.ts +6 -16
- package/dist/generic/pill/pill.svelte +47 -33
- package/dist/generic/pill/pill.svelte.d.ts +10 -21
- package/dist/generic/popover/popover.svelte +226 -0
- package/dist/generic/popover/popover.svelte.d.ts +15 -0
- package/dist/generic/rating/rating.svelte +85 -0
- package/dist/generic/rating/rating.svelte.d.ts +11 -0
- package/dist/generic/scorecard/scorecard.svelte +34 -21
- package/dist/generic/scorecard/scorecard.svelte.d.ts +9 -19
- package/dist/generic/section/section.svelte +28 -9
- package/dist/generic/section/section.svelte.d.ts +11 -21
- package/dist/generic/spinner/spinner.svelte +64 -0
- package/dist/generic/spinner/spinner.svelte.d.ts +8 -0
- package/dist/generic/theme-provider/index.d.ts +1 -0
- package/dist/generic/theme-provider/index.js +1 -0
- package/dist/generic/theme-provider/theme-provider-demo.svelte +182 -0
- package/dist/generic/theme-provider/theme-provider-demo.svelte.d.ts +3 -0
- package/dist/generic/theme-provider/theme-provider.svelte +83 -0
- package/dist/generic/theme-provider/theme-provider.svelte.d.ts +44 -0
- package/dist/generic/toaster/toaster.svelte +31 -6
- package/dist/generic/toaster/toaster.svelte.d.ts +7 -15
- package/dist/generic/tooltip/tooltip.svelte +389 -0
- package/dist/generic/tooltip/tooltip.svelte.d.ts +21 -0
- package/dist/helpers/ago.d.ts +7 -1
- package/dist/helpers/ago.js +6 -0
- package/dist/helpers/animation-actions.d.ts +124 -0
- package/dist/helpers/animation-actions.js +299 -0
- package/dist/helpers/animations.d.ts +198 -0
- package/dist/helpers/animations.js +280 -0
- package/dist/helpers/announcer.d.ts +118 -0
- package/dist/helpers/announcer.js +250 -0
- package/dist/helpers/copy-to-clipboard.svelte.d.ts +5 -0
- package/dist/helpers/copy-to-clipboard.svelte.js +28 -0
- package/dist/helpers/debounce.d.ts +7 -0
- package/dist/helpers/debounce.js +7 -0
- package/dist/helpers/focus.d.ts +123 -0
- package/dist/helpers/focus.js +335 -0
- package/dist/helpers/fuzzy-search.d.ts +41 -0
- package/dist/helpers/fuzzy-search.js +114 -0
- package/dist/helpers/index.d.ts +24 -0
- package/dist/helpers/index.js +24 -0
- package/dist/helpers/navigate-to.d.ts +4 -0
- package/dist/helpers/navigate-to.js +4 -0
- package/dist/helpers/positioning.d.ts +97 -0
- package/dist/helpers/positioning.js +230 -0
- package/dist/helpers/round-to-decimals.d.ts +7 -5
- package/dist/helpers/round-to-decimals.js +7 -5
- package/dist/helpers/spring.svelte.d.ts +97 -0
- package/dist/helpers/spring.svelte.js +216 -0
- package/dist/helpers/subscribable.d.ts +1 -2
- package/dist/helpers/theme.svelte.d.ts +63 -0
- package/dist/helpers/theme.svelte.js +123 -0
- package/dist/helpers/unique-id.d.ts +4 -0
- package/dist/helpers/unique-id.js +4 -0
- package/dist/helpers/use-position.svelte.d.ts +96 -0
- package/dist/helpers/use-position.svelte.js +189 -0
- package/dist/helpers/use-virtual-list.svelte.d.ts +121 -0
- package/dist/helpers/use-virtual-list.svelte.js +239 -0
- package/dist/icons/angle-right-icon.svelte +2 -1
- package/dist/icons/angle-right-icon.svelte.d.ts +16 -12
- package/dist/icons/angle-up-icon.svelte.d.ts +22 -19
- package/dist/icons/check-icon.svelte.d.ts +22 -19
- package/dist/icons/copy-icon.svelte +46 -0
- package/dist/icons/copy-icon.svelte.d.ts +6 -0
- package/dist/icons/envelope-icon.svelte.d.ts +22 -19
- package/dist/icons/folder-open-icon.svelte.d.ts +22 -19
- package/dist/icons/hamburger-icon.svelte.d.ts +22 -19
- package/dist/icons/home-icon.svelte +2 -1
- package/dist/icons/home-icon.svelte.d.ts +16 -12
- package/dist/icons/index.d.ts +13 -0
- package/dist/icons/index.js +13 -0
- package/dist/icons/link-icon.svelte.d.ts +22 -19
- package/dist/icons/mobile-phone-icon.svelte.d.ts +22 -19
- package/dist/icons/phone-icon.svelte.d.ts +22 -19
- package/dist/icons/svg-icon.svelte +46 -12
- package/dist/icons/svg-icon.svelte.d.ts +13 -23
- package/dist/icons/upload-icon.svelte.d.ts +22 -19
- package/dist/images/icon.svelte +9 -3
- package/dist/images/icon.svelte.d.ts +6 -16
- package/dist/images/image.svelte +28 -10
- package/dist/images/image.svelte.d.ts +14 -26
- package/dist/images/index.d.ts +2 -0
- package/dist/images/index.js +2 -0
- package/dist/index.d.ts +13 -122
- package/dist/index.js +27 -135
- package/dist/layout/flex-col.svelte +65 -22
- package/dist/layout/flex-col.svelte.d.ts +12 -22
- package/dist/layout/flex-item.svelte +13 -3
- package/dist/layout/flex-item.svelte.d.ts +8 -18
- package/dist/layout/flex-row.svelte +70 -21
- package/dist/layout/flex-row.svelte.d.ts +14 -24
- package/dist/layout/grid.svelte +7 -1
- package/dist/layout/grid.svelte.d.ts +6 -26
- package/dist/layout/index.d.ts +4 -0
- package/dist/layout/index.js +4 -0
- package/dist/modals/alert.svelte +42 -28
- package/dist/modals/alert.svelte.d.ts +13 -24
- package/dist/modals/confirm.svelte +54 -37
- package/dist/modals/confirm.svelte.d.ts +16 -27
- package/dist/modals/dialog-body.svelte +10 -4
- package/dist/modals/dialog-body.svelte.d.ts +6 -26
- package/dist/modals/dialog-close-button.svelte +15 -9
- package/dist/modals/dialog-close-button.svelte.d.ts +6 -17
- package/dist/modals/dialog-footer.svelte +6 -3
- package/dist/modals/dialog-footer.svelte.d.ts +6 -26
- package/dist/modals/dialog-header.svelte +13 -1
- package/dist/modals/dialog-header.svelte.d.ts +7 -26
- package/dist/modals/dialog-window.svelte +42 -14
- package/dist/modals/dialog-window.svelte.d.ts +9 -17
- package/dist/modals/index.d.ts +9 -0
- package/dist/modals/index.js +9 -0
- package/dist/modals/modal.svelte +88 -25
- package/dist/modals/modal.svelte.d.ts +14 -22
- package/dist/modals/prompt.svelte +71 -50
- package/dist/modals/prompt.svelte.d.ts +19 -30
- package/dist/navigation/accordion/accordion.svelte +104 -0
- package/dist/navigation/accordion/accordion.svelte.d.ts +9 -0
- package/dist/navigation/app-bar/app-bar.svelte +26 -20
- package/dist/navigation/app-bar/app-bar.svelte.d.ts +10 -20
- package/dist/navigation/app-bar/app-branding.svelte +10 -5
- package/dist/navigation/app-bar/app-branding.svelte.d.ts +6 -15
- package/dist/navigation/app-bar/app-logo.svelte +20 -5
- package/dist/navigation/app-bar/app-logo.svelte.d.ts +9 -19
- package/dist/navigation/app-bar/app-nav-item.svelte +26 -14
- package/dist/navigation/app-bar/app-nav-item.svelte.d.ts +9 -20
- package/dist/navigation/app-bar/app-nav.svelte +39 -12
- package/dist/navigation/app-bar/app-nav.svelte.d.ts +8 -18
- package/dist/navigation/app-bar/index.d.ts +5 -0
- package/dist/navigation/app-bar/index.js +5 -0
- package/dist/navigation/breadcrumbs/breadcrumbs.svelte +54 -28
- package/dist/navigation/breadcrumbs/breadcrumbs.svelte.d.ts +12 -21
- package/dist/navigation/command-palette/command-palette.svelte +758 -0
- package/dist/navigation/command-palette/command-palette.svelte.d.ts +65 -0
- package/dist/navigation/command-palette/index.d.ts +2 -0
- package/dist/navigation/command-palette/index.js +1 -0
- package/dist/navigation/context-menu/README.md +146 -0
- package/dist/navigation/context-menu/context-menu-divider.svelte +21 -0
- package/dist/navigation/context-menu/context-menu-divider.svelte.d.ts +18 -0
- package/dist/navigation/context-menu/context-menu-item.svelte +268 -0
- package/dist/navigation/context-menu/context-menu-item.svelte.d.ts +19 -0
- package/dist/navigation/context-menu/context-menu.svelte +226 -0
- package/dist/navigation/context-menu/context-menu.svelte.d.ts +38 -0
- package/dist/navigation/context-menu/index.d.ts +3 -0
- package/dist/navigation/context-menu/index.js +3 -0
- package/dist/navigation/drawer/drawer.svelte +137 -0
- package/dist/navigation/drawer/drawer.svelte.d.ts +11 -0
- package/dist/navigation/dropdown-button/dropdown-button.svelte +58 -20
- package/dist/navigation/dropdown-button/dropdown-button.svelte.d.ts +10 -20
- package/dist/navigation/index.d.ts +11 -0
- package/dist/navigation/index.js +14 -0
- package/dist/navigation/pagination/pagination.svelte +55 -42
- package/dist/navigation/pagination/pagination.svelte.d.ts +10 -21
- package/dist/navigation/side-bar/side-bar.svelte +18 -9
- package/dist/navigation/side-bar/side-bar.svelte.d.ts +7 -17
- package/dist/navigation/tabs/index.d.ts +4 -0
- package/dist/navigation/tabs/index.js +3 -0
- package/dist/navigation/tabs/tab-context.d.ts +12 -6
- package/dist/navigation/tabs/tab-group.svelte +268 -55
- package/dist/navigation/tabs/tab-group.svelte.d.ts +9 -20
- package/dist/navigation/tabs/tab.svelte +64 -34
- package/dist/navigation/tabs/tab.svelte.d.ts +11 -22
- package/dist/navigation/wizard/index.d.ts +3 -0
- package/dist/navigation/wizard/index.js +2 -0
- package/dist/navigation/wizard/wizard-context.d.ts +13 -8
- package/dist/navigation/wizard/wizard-step.svelte +38 -15
- package/dist/navigation/wizard/wizard-step.svelte.d.ts +8 -18
- package/dist/navigation/wizard/wizard.svelte +123 -89
- package/dist/navigation/wizard/wizard.svelte.d.ts +15 -26
- package/dist/placeholders/index.d.ts +6 -0
- package/dist/placeholders/index.js +6 -0
- package/dist/placeholders/loading.svelte +39 -23
- package/dist/placeholders/loading.svelte.d.ts +10 -17
- package/dist/placeholders/progress.svelte +7 -6
- package/dist/placeholders/progress.svelte.d.ts +5 -15
- package/dist/placeholders/skeleton-input.svelte +66 -38
- package/dist/placeholders/skeleton-input.svelte.d.ts +5 -15
- package/dist/placeholders/skeleton-paragraph.svelte +25 -0
- package/dist/placeholders/skeleton-paragraph.svelte.d.ts +8 -0
- package/dist/placeholders/skeleton-table.svelte +75 -0
- package/dist/placeholders/skeleton-table.svelte.d.ts +8 -0
- package/dist/placeholders/skeleton-text.svelte +46 -16
- package/dist/placeholders/skeleton-text.svelte.d.ts +7 -17
- package/dist/tables/cell-renderers.d.ts +24 -0
- package/dist/tables/cell-renderers.js +228 -0
- package/dist/tables/data-grid.svelte +332 -135
- package/dist/tables/data-grid.svelte.d.ts +34 -33
- package/dist/tables/index.d.ts +10 -0
- package/dist/tables/index.js +12 -0
- package/dist/tables/table-caption.svelte +13 -4
- package/dist/tables/table-caption.svelte.d.ts +8 -18
- package/dist/tables/table-cell.svelte +45 -15
- package/dist/tables/table-cell.svelte.d.ts +10 -19
- package/dist/tables/table-context.svelte.d.ts +32 -0
- package/dist/tables/table-context.svelte.js +160 -0
- package/dist/tables/table-header-cell.svelte +158 -19
- package/dist/tables/table-header-cell.svelte.d.ts +15 -19
- package/dist/tables/table-header.svelte +31 -6
- package/dist/tables/table-header.svelte.d.ts +7 -26
- package/dist/tables/table-row.svelte +87 -7
- package/dist/tables/table-row.svelte.d.ts +10 -26
- package/dist/tables/table.svelte +61 -2
- package/dist/tables/table.svelte.d.ts +13 -26
- package/dist/test-utils/accessibility-helpers.d.ts +80 -0
- package/dist/test-utils/accessibility-helpers.js +220 -0
- package/dist/test-utils/index.d.ts +8 -0
- package/dist/test-utils/index.js +8 -0
- package/dist/test-utils/mock-helpers.d.ts +68 -0
- package/dist/test-utils/mock-helpers.js +165 -0
- package/dist/test-utils/render-helpers.d.ts +55 -0
- package/dist/test-utils/render-helpers.js +114 -0
- package/dist/test-utils/setup.d.ts +5 -0
- package/dist/test-utils/setup.js +91 -0
- package/dist/test-utils/test-data.d.ts +102 -0
- package/dist/test-utils/test-data.js +99 -0
- package/dist/timeline/index.d.ts +2 -0
- package/dist/timeline/index.js +2 -0
- package/dist/timeline/timeline-item.svelte +26 -9
- package/dist/timeline/timeline-item.svelte.d.ts +13 -23
- package/dist/timeline/timeline.svelte +12 -6
- package/dist/timeline/timeline.svelte.d.ts +6 -26
- package/dist/types/data.d.ts +61 -0
- package/dist/types/date.d.ts +1 -1
- package/dist/types/form.d.ts +20 -2
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +5 -0
- package/dist/types/size.d.ts +22 -0
- package/dist/types/size.js +22 -0
- package/dist/typography/code-block.svelte +89 -10
- package/dist/typography/code-block.svelte.d.ts +7 -17
- package/dist/typography/code.svelte +89 -0
- package/dist/typography/code.svelte.d.ts +7 -0
- package/dist/typography/headline.svelte +29 -9
- package/dist/typography/headline.svelte.d.ts +8 -18
- package/dist/typography/index.d.ts +6 -0
- package/dist/typography/index.js +6 -0
- package/dist/typography/paragraph.svelte +18 -10
- package/dist/typography/paragraph.svelte.d.ts +6 -26
- package/dist/typography/subtitle.svelte +18 -4
- package/dist/typography/subtitle.svelte.d.ts +8 -18
- package/dist/typography/text.svelte +20 -5
- package/dist/typography/text.svelte.d.ts +9 -19
- package/package.json +46 -36
- package/dist/navigation/accordian/accordian.svelte +0 -62
- package/dist/navigation/accordian/accordian.svelte.d.ts +0 -19
- package/dist/tables/table-body.svelte +0 -3
- package/dist/tables/table-body.svelte.d.ts +0 -27
- package/dist/tables/table-footer-cell.svelte +0 -22
- package/dist/tables/table-footer-cell.svelte.d.ts +0 -18
- package/dist/tables/table-footer-row.svelte +0 -3
- package/dist/tables/table-footer-row.svelte.d.ts +0 -27
- package/dist/tables/table-footer.svelte +0 -13
- package/dist/tables/table-footer.svelte.d.ts +0 -27
- package/dist/tables/table-header-row.svelte +0 -4
- package/dist/tables/table-header-row.svelte.d.ts +0 -27
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focus Management Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for managing focus in accessible components including:
|
|
5
|
+
* - Roving tabindex for keyboard navigation
|
|
6
|
+
* - Focus trapping for modals/dialogs
|
|
7
|
+
* - Focus restoration
|
|
8
|
+
* - Focusable element detection
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Query selector for all focusable elements
|
|
12
|
+
*/
|
|
13
|
+
export declare const FOCUSABLE_SELECTOR: string;
|
|
14
|
+
/**
|
|
15
|
+
* Get all focusable elements within a container
|
|
16
|
+
*/
|
|
17
|
+
export declare function getFocusableElements(container: HTMLElement): HTMLElement[];
|
|
18
|
+
/**
|
|
19
|
+
* Get the first focusable element within a container
|
|
20
|
+
*/
|
|
21
|
+
export declare function getFirstFocusable(container: HTMLElement): HTMLElement | null;
|
|
22
|
+
/**
|
|
23
|
+
* Get the last focusable element within a container
|
|
24
|
+
*/
|
|
25
|
+
export declare function getLastFocusable(container: HTMLElement): HTMLElement | null;
|
|
26
|
+
/**
|
|
27
|
+
* Focus Trap - traps focus within a container (for modals, dialogs)
|
|
28
|
+
* Returns a cleanup function to remove the trap
|
|
29
|
+
*/
|
|
30
|
+
export declare function createFocusTrap(container: HTMLElement | null): () => void;
|
|
31
|
+
/**
|
|
32
|
+
* Roving Tabindex Manager
|
|
33
|
+
* Manages keyboard navigation in a list of items (for menus, lists, tabs, etc.)
|
|
34
|
+
*/
|
|
35
|
+
export declare class RovingTabindexManager {
|
|
36
|
+
private items;
|
|
37
|
+
private currentIndex;
|
|
38
|
+
private orientation;
|
|
39
|
+
private loop;
|
|
40
|
+
constructor(items: HTMLElement[], options?: {
|
|
41
|
+
orientation?: 'horizontal' | 'vertical' | 'both';
|
|
42
|
+
loop?: boolean;
|
|
43
|
+
initialIndex?: number;
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Update tabindex attributes based on current index
|
|
47
|
+
*/
|
|
48
|
+
private updateTabindices;
|
|
49
|
+
/**
|
|
50
|
+
* Move focus to a specific index
|
|
51
|
+
*/
|
|
52
|
+
focusItem(index: number): void;
|
|
53
|
+
/**
|
|
54
|
+
* Move focus to the next item
|
|
55
|
+
*/
|
|
56
|
+
focusNext(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Move focus to the previous item
|
|
59
|
+
*/
|
|
60
|
+
focusPrevious(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Move focus to the first item
|
|
63
|
+
*/
|
|
64
|
+
focusFirst(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Move focus to the last item
|
|
67
|
+
*/
|
|
68
|
+
focusLast(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Handle keyboard events for roving tabindex
|
|
71
|
+
*/
|
|
72
|
+
handleKeyDown(event: KeyboardEvent): void;
|
|
73
|
+
/**
|
|
74
|
+
* Update the items list (when items change dynamically)
|
|
75
|
+
*/
|
|
76
|
+
updateItems(items: HTMLElement[]): void;
|
|
77
|
+
/**
|
|
78
|
+
* Get the currently focused item index
|
|
79
|
+
*/
|
|
80
|
+
getCurrentIndex(): number;
|
|
81
|
+
/**
|
|
82
|
+
* Get the currently focused item
|
|
83
|
+
*/
|
|
84
|
+
getCurrentItem(): HTMLElement | null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Svelte action for roving tabindex
|
|
88
|
+
* Usage: <div use:rovingTabindex={{ items, orientation: 'vertical' }}>
|
|
89
|
+
*/
|
|
90
|
+
export declare function rovingTabindex(node: HTMLElement, options: {
|
|
91
|
+
itemSelector: string;
|
|
92
|
+
orientation?: 'horizontal' | 'vertical' | 'both';
|
|
93
|
+
loop?: boolean;
|
|
94
|
+
}): {
|
|
95
|
+
update(newOptions: typeof options): void;
|
|
96
|
+
destroy(): void;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Store the currently focused element
|
|
100
|
+
* Returns the element that had focus when this was called
|
|
101
|
+
*/
|
|
102
|
+
export declare function storeFocus(): HTMLElement | null;
|
|
103
|
+
/**
|
|
104
|
+
* Restore focus to a previously stored element
|
|
105
|
+
*/
|
|
106
|
+
export declare function restoreFocus(element: HTMLElement | null): void;
|
|
107
|
+
/**
|
|
108
|
+
* Trap focus within a container (simplified alias for createFocusTrap)
|
|
109
|
+
* Returns cleanup function
|
|
110
|
+
*/
|
|
111
|
+
export declare function trapFocus(container: HTMLElement | null): () => void;
|
|
112
|
+
/**
|
|
113
|
+
* Focus-visible polyfill check
|
|
114
|
+
* Returns true if the browser supports :focus-visible
|
|
115
|
+
*/
|
|
116
|
+
export declare function supportsFocusVisible(): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Add focus-visible class management for older browsers
|
|
119
|
+
* Usage: use:focusVisible on any focusable element
|
|
120
|
+
*/
|
|
121
|
+
export declare function focusVisible(node: HTMLElement): {
|
|
122
|
+
destroy(): void;
|
|
123
|
+
};
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focus Management Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for managing focus in accessible components including:
|
|
5
|
+
* - Roving tabindex for keyboard navigation
|
|
6
|
+
* - Focus trapping for modals/dialogs
|
|
7
|
+
* - Focus restoration
|
|
8
|
+
* - Focusable element detection
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Query selector for all focusable elements
|
|
12
|
+
*/
|
|
13
|
+
export const FOCUSABLE_SELECTOR = [
|
|
14
|
+
'a[href]',
|
|
15
|
+
'area[href]',
|
|
16
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
17
|
+
'select:not([disabled])',
|
|
18
|
+
'textarea:not([disabled])',
|
|
19
|
+
'button:not([disabled])',
|
|
20
|
+
'iframe',
|
|
21
|
+
'object',
|
|
22
|
+
'embed',
|
|
23
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
24
|
+
'[contenteditable]',
|
|
25
|
+
'audio[controls]',
|
|
26
|
+
'video[controls]'
|
|
27
|
+
].join(',');
|
|
28
|
+
/**
|
|
29
|
+
* Get all focusable elements within a container
|
|
30
|
+
*/
|
|
31
|
+
export function getFocusableElements(container) {
|
|
32
|
+
return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((el) => {
|
|
33
|
+
// Filter out elements that are not visible
|
|
34
|
+
return (el.offsetWidth > 0 &&
|
|
35
|
+
el.offsetHeight > 0 &&
|
|
36
|
+
window.getComputedStyle(el).visibility !== 'hidden');
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the first focusable element within a container
|
|
41
|
+
*/
|
|
42
|
+
export function getFirstFocusable(container) {
|
|
43
|
+
const elements = getFocusableElements(container);
|
|
44
|
+
return elements[0] || null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the last focusable element within a container
|
|
48
|
+
*/
|
|
49
|
+
export function getLastFocusable(container) {
|
|
50
|
+
const elements = getFocusableElements(container);
|
|
51
|
+
return elements[elements.length - 1] || null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Focus Trap - traps focus within a container (for modals, dialogs)
|
|
55
|
+
* Returns a cleanup function to remove the trap
|
|
56
|
+
*/
|
|
57
|
+
export function createFocusTrap(container) {
|
|
58
|
+
// Guard against invalid container
|
|
59
|
+
if (!container || !(container instanceof HTMLElement) || !container.querySelectorAll) {
|
|
60
|
+
console.warn('createFocusTrap: Invalid container provided', container);
|
|
61
|
+
return () => { }; // Return no-op cleanup
|
|
62
|
+
}
|
|
63
|
+
const firstFocusable = getFirstFocusable(container);
|
|
64
|
+
const lastFocusable = getLastFocusable(container);
|
|
65
|
+
// Store the previously focused element to restore later
|
|
66
|
+
const previouslyFocused = document.activeElement;
|
|
67
|
+
// Focus the first focusable element
|
|
68
|
+
firstFocusable?.focus();
|
|
69
|
+
const handleKeyDown = (event) => {
|
|
70
|
+
if (event.key !== 'Tab')
|
|
71
|
+
return;
|
|
72
|
+
const focusableElements = getFocusableElements(container);
|
|
73
|
+
const firstElement = focusableElements[0];
|
|
74
|
+
const lastElement = focusableElements[focusableElements.length - 1];
|
|
75
|
+
// Shift + Tab: wrap to last element
|
|
76
|
+
if (event.shiftKey && document.activeElement === firstElement) {
|
|
77
|
+
event.preventDefault();
|
|
78
|
+
lastElement?.focus();
|
|
79
|
+
}
|
|
80
|
+
// Tab: wrap to first element
|
|
81
|
+
else if (!event.shiftKey && document.activeElement === lastElement) {
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
firstElement?.focus();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
container.addEventListener('keydown', handleKeyDown);
|
|
87
|
+
// Return cleanup function
|
|
88
|
+
return () => {
|
|
89
|
+
container.removeEventListener('keydown', handleKeyDown);
|
|
90
|
+
// Restore focus to previously focused element
|
|
91
|
+
previouslyFocused?.focus();
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Roving Tabindex Manager
|
|
96
|
+
* Manages keyboard navigation in a list of items (for menus, lists, tabs, etc.)
|
|
97
|
+
*/
|
|
98
|
+
export class RovingTabindexManager {
|
|
99
|
+
items = [];
|
|
100
|
+
currentIndex = 0;
|
|
101
|
+
orientation = 'vertical';
|
|
102
|
+
loop = true;
|
|
103
|
+
constructor(items, options = {}) {
|
|
104
|
+
this.items = items;
|
|
105
|
+
this.orientation = options.orientation || 'vertical';
|
|
106
|
+
this.loop = options.loop !== undefined ? options.loop : true;
|
|
107
|
+
this.currentIndex = options.initialIndex || 0;
|
|
108
|
+
// Set initial tabindex values
|
|
109
|
+
this.updateTabindices();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Update tabindex attributes based on current index
|
|
113
|
+
*/
|
|
114
|
+
updateTabindices() {
|
|
115
|
+
this.items.forEach((item, index) => {
|
|
116
|
+
if (index === this.currentIndex) {
|
|
117
|
+
item.setAttribute('tabindex', '0');
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
item.setAttribute('tabindex', '-1');
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Move focus to a specific index
|
|
126
|
+
*/
|
|
127
|
+
focusItem(index) {
|
|
128
|
+
if (index < 0 || index >= this.items.length)
|
|
129
|
+
return;
|
|
130
|
+
this.currentIndex = index;
|
|
131
|
+
this.updateTabindices();
|
|
132
|
+
this.items[index]?.focus();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Move focus to the next item
|
|
136
|
+
*/
|
|
137
|
+
focusNext() {
|
|
138
|
+
let nextIndex = this.currentIndex + 1;
|
|
139
|
+
if (nextIndex >= this.items.length) {
|
|
140
|
+
nextIndex = this.loop ? 0 : this.items.length - 1;
|
|
141
|
+
}
|
|
142
|
+
this.focusItem(nextIndex);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Move focus to the previous item
|
|
146
|
+
*/
|
|
147
|
+
focusPrevious() {
|
|
148
|
+
let prevIndex = this.currentIndex - 1;
|
|
149
|
+
if (prevIndex < 0) {
|
|
150
|
+
prevIndex = this.loop ? this.items.length - 1 : 0;
|
|
151
|
+
}
|
|
152
|
+
this.focusItem(prevIndex);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Move focus to the first item
|
|
156
|
+
*/
|
|
157
|
+
focusFirst() {
|
|
158
|
+
this.focusItem(0);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Move focus to the last item
|
|
162
|
+
*/
|
|
163
|
+
focusLast() {
|
|
164
|
+
this.focusItem(this.items.length - 1);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Handle keyboard events for roving tabindex
|
|
168
|
+
*/
|
|
169
|
+
handleKeyDown(event) {
|
|
170
|
+
const { key } = event;
|
|
171
|
+
// Vertical navigation
|
|
172
|
+
if (this.orientation === 'vertical' || this.orientation === 'both') {
|
|
173
|
+
if (key === 'ArrowDown') {
|
|
174
|
+
event.preventDefault();
|
|
175
|
+
this.focusNext();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (key === 'ArrowUp') {
|
|
179
|
+
event.preventDefault();
|
|
180
|
+
this.focusPrevious();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Horizontal navigation
|
|
185
|
+
if (this.orientation === 'horizontal' || this.orientation === 'both') {
|
|
186
|
+
if (key === 'ArrowRight') {
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
this.focusNext();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (key === 'ArrowLeft') {
|
|
192
|
+
event.preventDefault();
|
|
193
|
+
this.focusPrevious();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Home/End
|
|
198
|
+
if (key === 'Home') {
|
|
199
|
+
event.preventDefault();
|
|
200
|
+
this.focusFirst();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (key === 'End') {
|
|
204
|
+
event.preventDefault();
|
|
205
|
+
this.focusLast();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Update the items list (when items change dynamically)
|
|
211
|
+
*/
|
|
212
|
+
updateItems(items) {
|
|
213
|
+
this.items = items;
|
|
214
|
+
this.currentIndex = Math.min(this.currentIndex, items.length - 1);
|
|
215
|
+
this.updateTabindices();
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get the currently focused item index
|
|
219
|
+
*/
|
|
220
|
+
getCurrentIndex() {
|
|
221
|
+
return this.currentIndex;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get the currently focused item
|
|
225
|
+
*/
|
|
226
|
+
getCurrentItem() {
|
|
227
|
+
return this.items[this.currentIndex] || null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Svelte action for roving tabindex
|
|
232
|
+
* Usage: <div use:rovingTabindex={{ items, orientation: 'vertical' }}>
|
|
233
|
+
*/
|
|
234
|
+
export function rovingTabindex(node, options) {
|
|
235
|
+
let manager;
|
|
236
|
+
function updateManager() {
|
|
237
|
+
const items = Array.from(node.querySelectorAll(options.itemSelector));
|
|
238
|
+
if (manager) {
|
|
239
|
+
manager.updateItems(items);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
manager = new RovingTabindexManager(items, {
|
|
243
|
+
orientation: options.orientation,
|
|
244
|
+
loop: options.loop
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function handleKeyDown(event) {
|
|
249
|
+
manager?.handleKeyDown(event);
|
|
250
|
+
}
|
|
251
|
+
// Initialize
|
|
252
|
+
updateManager();
|
|
253
|
+
node.addEventListener('keydown', handleKeyDown);
|
|
254
|
+
// Set up MutationObserver to watch for DOM changes
|
|
255
|
+
const observer = new MutationObserver(updateManager);
|
|
256
|
+
observer.observe(node, { childList: true, subtree: true });
|
|
257
|
+
return {
|
|
258
|
+
update(newOptions) {
|
|
259
|
+
options = newOptions;
|
|
260
|
+
updateManager();
|
|
261
|
+
},
|
|
262
|
+
destroy() {
|
|
263
|
+
node.removeEventListener('keydown', handleKeyDown);
|
|
264
|
+
observer.disconnect();
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Store the currently focused element
|
|
270
|
+
* Returns the element that had focus when this was called
|
|
271
|
+
*/
|
|
272
|
+
export function storeFocus() {
|
|
273
|
+
return document.activeElement;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Restore focus to a previously stored element
|
|
277
|
+
*/
|
|
278
|
+
export function restoreFocus(element) {
|
|
279
|
+
if (element && typeof element.focus === 'function') {
|
|
280
|
+
element.focus();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Trap focus within a container (simplified alias for createFocusTrap)
|
|
285
|
+
* Returns cleanup function
|
|
286
|
+
*/
|
|
287
|
+
export function trapFocus(container) {
|
|
288
|
+
return createFocusTrap(container);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Focus-visible polyfill check
|
|
292
|
+
* Returns true if the browser supports :focus-visible
|
|
293
|
+
*/
|
|
294
|
+
export function supportsFocusVisible() {
|
|
295
|
+
try {
|
|
296
|
+
document.querySelector(':focus-visible');
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Add focus-visible class management for older browsers
|
|
305
|
+
* Usage: use:focusVisible on any focusable element
|
|
306
|
+
*/
|
|
307
|
+
export function focusVisible(node) {
|
|
308
|
+
let hadKeyboardEvent = false;
|
|
309
|
+
function onKeyDown() {
|
|
310
|
+
hadKeyboardEvent = true;
|
|
311
|
+
}
|
|
312
|
+
function onPointerDown() {
|
|
313
|
+
hadKeyboardEvent = false;
|
|
314
|
+
}
|
|
315
|
+
function onFocus() {
|
|
316
|
+
if (hadKeyboardEvent) {
|
|
317
|
+
node.classList.add('focus-visible');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function onBlur() {
|
|
321
|
+
node.classList.remove('focus-visible');
|
|
322
|
+
}
|
|
323
|
+
document.addEventListener('keydown', onKeyDown);
|
|
324
|
+
document.addEventListener('pointerdown', onPointerDown);
|
|
325
|
+
node.addEventListener('focus', onFocus);
|
|
326
|
+
node.addEventListener('blur', onBlur);
|
|
327
|
+
return {
|
|
328
|
+
destroy() {
|
|
329
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
330
|
+
document.removeEventListener('pointerdown', onPointerDown);
|
|
331
|
+
node.removeEventListener('focus', onFocus);
|
|
332
|
+
node.removeEventListener('blur', onBlur);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fuzzy search utility for command palette and other search features
|
|
3
|
+
* Zero dependencies, custom implementation
|
|
4
|
+
*/
|
|
5
|
+
export interface FuzzyMatch {
|
|
6
|
+
/** The item that matched */
|
|
7
|
+
item: any;
|
|
8
|
+
/** The score of the match (higher is better) */
|
|
9
|
+
score: number;
|
|
10
|
+
/** The indices of matched characters in the string */
|
|
11
|
+
matches: number[];
|
|
12
|
+
/** The key that was matched (if searching object properties) */
|
|
13
|
+
matchedKey?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface FuzzySearchOptions {
|
|
16
|
+
/** Keys to search in if items are objects */
|
|
17
|
+
keys?: string[];
|
|
18
|
+
/** Minimum score threshold (0-1) */
|
|
19
|
+
threshold?: number;
|
|
20
|
+
/** Maximum results to return */
|
|
21
|
+
limit?: number;
|
|
22
|
+
/** Case sensitive search */
|
|
23
|
+
caseSensitive?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Calculate fuzzy match score for a query against a string
|
|
27
|
+
* Returns { score, matches } where matches are character indices
|
|
28
|
+
*/
|
|
29
|
+
export declare function fuzzyMatch(query: string, str: string, caseSensitive?: boolean): {
|
|
30
|
+
score: number;
|
|
31
|
+
matches: number[];
|
|
32
|
+
} | null;
|
|
33
|
+
/**
|
|
34
|
+
* Search an array of items with fuzzy matching
|
|
35
|
+
*/
|
|
36
|
+
export declare function fuzzySearch<T = any>(query: string, items: T[], options?: FuzzySearchOptions): FuzzyMatch[];
|
|
37
|
+
/**
|
|
38
|
+
* Highlight matched characters in a string
|
|
39
|
+
* Returns HTML string with <mark> tags around matches
|
|
40
|
+
*/
|
|
41
|
+
export declare function highlightMatches(str: string, matches: number[]): string;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fuzzy search utility for command palette and other search features
|
|
3
|
+
* Zero dependencies, custom implementation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Calculate fuzzy match score for a query against a string
|
|
7
|
+
* Returns { score, matches } where matches are character indices
|
|
8
|
+
*/
|
|
9
|
+
export function fuzzyMatch(query, str, caseSensitive = false) {
|
|
10
|
+
if (!query)
|
|
11
|
+
return { score: 1, matches: [] };
|
|
12
|
+
if (!str)
|
|
13
|
+
return null;
|
|
14
|
+
const queryStr = caseSensitive ? query : query.toLowerCase();
|
|
15
|
+
const searchStr = caseSensitive ? str : str.toLowerCase();
|
|
16
|
+
let score = 0;
|
|
17
|
+
let queryIndex = 0;
|
|
18
|
+
const matches = [];
|
|
19
|
+
let previousMatchIndex = -1;
|
|
20
|
+
let consecutiveMatchCount = 0;
|
|
21
|
+
// Try to match each character in the query
|
|
22
|
+
for (let i = 0; i < searchStr.length && queryIndex < queryStr.length; i++) {
|
|
23
|
+
if (searchStr[i] === queryStr[queryIndex]) {
|
|
24
|
+
matches.push(i);
|
|
25
|
+
// Base score for match
|
|
26
|
+
score += 1;
|
|
27
|
+
// Bonus for consecutive matches
|
|
28
|
+
if (previousMatchIndex === i - 1) {
|
|
29
|
+
consecutiveMatchCount++;
|
|
30
|
+
score += consecutiveMatchCount * 5; // Exponential bonus
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
consecutiveMatchCount = 0;
|
|
34
|
+
}
|
|
35
|
+
// Bonus for matching at word boundaries
|
|
36
|
+
if (i === 0 || searchStr[i - 1] === ' ' || searchStr[i - 1] === '-') {
|
|
37
|
+
score += 10;
|
|
38
|
+
}
|
|
39
|
+
// Bonus for matching uppercase in camelCase
|
|
40
|
+
if (str[i] === str[i].toUpperCase() && str[i] !== str[i].toLowerCase()) {
|
|
41
|
+
score += 5;
|
|
42
|
+
}
|
|
43
|
+
previousMatchIndex = i;
|
|
44
|
+
queryIndex++;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Must match all characters in query
|
|
48
|
+
if (queryIndex !== queryStr.length) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
// Normalize score based on string length
|
|
52
|
+
score = score / str.length;
|
|
53
|
+
return { score, matches };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Search an array of items with fuzzy matching
|
|
57
|
+
*/
|
|
58
|
+
export function fuzzySearch(query, items, options = {}) {
|
|
59
|
+
const { keys = [], threshold = 0, limit = Infinity, caseSensitive = false } = options;
|
|
60
|
+
const results = [];
|
|
61
|
+
for (const item of items) {
|
|
62
|
+
let bestMatch = null;
|
|
63
|
+
// If item is a string, search directly
|
|
64
|
+
if (typeof item === 'string') {
|
|
65
|
+
const match = fuzzyMatch(query, item, caseSensitive);
|
|
66
|
+
if (match && match.score >= threshold) {
|
|
67
|
+
bestMatch = match;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// If item is an object, search specified keys
|
|
71
|
+
else if (typeof item === 'object' && item !== null) {
|
|
72
|
+
for (const key of keys) {
|
|
73
|
+
const value = item[key];
|
|
74
|
+
if (typeof value === 'string') {
|
|
75
|
+
const match = fuzzyMatch(query, value, caseSensitive);
|
|
76
|
+
if (match && match.score >= threshold) {
|
|
77
|
+
if (!bestMatch || match.score > bestMatch.score) {
|
|
78
|
+
bestMatch = { ...match, matchedKey: key };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (bestMatch) {
|
|
85
|
+
results.push({
|
|
86
|
+
item,
|
|
87
|
+
score: bestMatch.score,
|
|
88
|
+
matches: bestMatch.matches,
|
|
89
|
+
matchedKey: bestMatch.matchedKey
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Sort by score (descending)
|
|
94
|
+
results.sort((a, b) => b.score - a.score);
|
|
95
|
+
// Apply limit
|
|
96
|
+
return results.slice(0, limit);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Highlight matched characters in a string
|
|
100
|
+
* Returns HTML string with <mark> tags around matches
|
|
101
|
+
*/
|
|
102
|
+
export function highlightMatches(str, matches) {
|
|
103
|
+
if (!matches.length)
|
|
104
|
+
return str;
|
|
105
|
+
let result = '';
|
|
106
|
+
let lastIndex = 0;
|
|
107
|
+
for (const index of matches) {
|
|
108
|
+
result += str.slice(lastIndex, index);
|
|
109
|
+
result += `<mark>${str[index]}</mark>`;
|
|
110
|
+
lastIndex = index + 1;
|
|
111
|
+
}
|
|
112
|
+
result += str.slice(lastIndex);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from './ago.js';
|
|
2
|
+
export * from './anchor.js';
|
|
3
|
+
export * from './animation-actions.js';
|
|
4
|
+
export * from './animations.js';
|
|
5
|
+
export * from './announcer.js';
|
|
6
|
+
export * from './capitalize.js';
|
|
7
|
+
export * from './copy-to-clipboard.svelte.js';
|
|
8
|
+
export * from './date.js';
|
|
9
|
+
export * from './debounce.js';
|
|
10
|
+
export * from './focus.js';
|
|
11
|
+
export * from './fuzzy-search.js';
|
|
12
|
+
export * from './navigate-to.js';
|
|
13
|
+
export * from './nobr.js';
|
|
14
|
+
export * from './random.js';
|
|
15
|
+
export * from './remove-properties.js';
|
|
16
|
+
export * from './round-to-decimals.js';
|
|
17
|
+
export * from './split-new-lines.js';
|
|
18
|
+
export * from './spring.svelte.js';
|
|
19
|
+
export * from './subscribable.js';
|
|
20
|
+
export * from './theme.svelte.js';
|
|
21
|
+
export * from './transform.js';
|
|
22
|
+
export * from './ucfirst.js';
|
|
23
|
+
export * from './unique-id.js';
|
|
24
|
+
export * from './use-virtual-list.svelte.js';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from './ago.js';
|
|
2
|
+
export * from './anchor.js';
|
|
3
|
+
export * from './animation-actions.js';
|
|
4
|
+
export * from './animations.js';
|
|
5
|
+
export * from './announcer.js';
|
|
6
|
+
export * from './capitalize.js';
|
|
7
|
+
export * from './copy-to-clipboard.svelte.js';
|
|
8
|
+
export * from './date.js';
|
|
9
|
+
export * from './debounce.js';
|
|
10
|
+
export * from './focus.js';
|
|
11
|
+
export * from './fuzzy-search.js';
|
|
12
|
+
export * from './navigate-to.js';
|
|
13
|
+
export * from './nobr.js';
|
|
14
|
+
export * from './random.js';
|
|
15
|
+
export * from './remove-properties.js';
|
|
16
|
+
export * from './round-to-decimals.js';
|
|
17
|
+
export * from './split-new-lines.js';
|
|
18
|
+
export * from './spring.svelte.js';
|
|
19
|
+
export * from './subscribable.js';
|
|
20
|
+
export * from './theme.svelte.js';
|
|
21
|
+
export * from './transform.js';
|
|
22
|
+
export * from './ucfirst.js';
|
|
23
|
+
export * from './unique-id.js';
|
|
24
|
+
export * from './use-virtual-list.svelte.js';
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { browser } from '$app/environment';
|
|
2
2
|
import { goto } from '$app/navigation';
|
|
3
3
|
import { redirect } from '@sveltejs/kit';
|
|
4
|
+
/**
|
|
5
|
+
* Navigate to a URL using SvelteKit's navigation, with fallback to window.location
|
|
6
|
+
* @param url - The URL to navigate to
|
|
7
|
+
*/
|
|
4
8
|
export const navigateTo = (url) => {
|
|
5
9
|
if (browser) {
|
|
6
10
|
setTimeout(() => {
|