@aceshooting/lyra-ui 16.0.0 → 18.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/CHANGELOG.md +758 -0
- package/README.md +2 -2
- package/custom-elements.json +1 -1
- package/dist/cli/migration-contract.json +1 -1
- package/dist/components/agent-tools/browser-frame/browser-frame.class.d.ts +3 -3
- package/dist/components/agent-tools/browser-frame/browser-frame.class.js +2 -2
- package/dist/components/agent-tools/compare-panel/compare-panel.class.d.ts +2 -2
- package/dist/components/agent-tools/compare-panel/compare-panel.class.js +3 -3
- package/dist/components/agent-tools/confirm-bar/confirm-bar.class.d.ts +37 -13
- package/dist/components/agent-tools/confirm-bar/confirm-bar.class.js +2 -2
- package/dist/components/agent-tools/task-list/task-list.class.js +2 -2
- package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.d.ts +4 -0
- package/dist/components/agent-tools/tool-call-chip/tool-call-chip.class.js +2 -2
- package/dist/components/agent-tools/tool-param-form/tool-param-form.class.d.ts +3 -3
- package/dist/components/agent-tools/tool-param-form/tool-param-form.class.js +1 -1
- package/dist/components/charts/chart/chart.class.d.ts +117 -17
- package/dist/components/charts/chart/chart.class.js +3 -3
- package/dist/components/charts/chart/histogram-bin.d.ts +5 -1
- package/dist/components/charts/chart/histogram-bin.js +1 -1
- package/dist/components/charts/chart/lite-chart.class.d.ts +9 -0
- package/dist/components/conversation/code-block/code-block.styles.js +1 -1
- package/dist/components/conversation/message-actions/message-actions.styles.js +1 -1
- package/dist/components/conversation/model-select/model-select.class.d.ts +13 -4
- package/dist/components/conversation/model-select/model-select.class.js +2 -1
- package/dist/components/conversation/model-select/model-select.styles.js +1 -1
- package/dist/components/conversation/streaming-text/streaming-text-base.class.d.ts +40 -2
- package/dist/components/conversation/streaming-text/streaming-text-base.class.js +2 -2
- package/dist/components/conversation/streaming-text/streaming-text-core.class.d.ts +27 -3
- package/dist/components/conversation/streaming-text/streaming-text-core.class.js +11 -0
- package/dist/components/conversation/streaming-text/streaming-text.class.d.ts +31 -3
- package/dist/components/conversation/streaming-text/streaming-text.class.js +11 -0
- package/dist/components/conversation/suggestion-chips/suggestion-chips.class.d.ts +30 -2
- package/dist/components/conversation/suggestion-chips/suggestion-chips.class.js +4 -3
- package/dist/components/conversation/suggestion-chips/suggestion-chips.styles.js +1 -1
- package/dist/components/conversation/thread-list/thread-list.class.js +1 -1
- package/dist/components/conversation/transcript-feed/transcript-feed.class.js +1 -1
- package/dist/components/conversation/usage-badge/usage-badge-overlay-runtime.js +1 -1
- package/dist/components/conversation/usage-badge/usage-badge.class.d.ts +4 -0
- package/dist/components/conversation/voice-picker/voice-picker.class.d.ts +16 -4
- package/dist/components/conversation/voice-picker/voice-picker.class.js +2 -1
- package/dist/components/conversation/voice-picker/voice-picker.styles.js +1 -1
- package/dist/components/data/context-meter/context-meter.class.d.ts +23 -4
- package/dist/components/data/context-meter/context-meter.class.js +10 -7
- package/dist/components/data/context-meter/context-meter.styles.js +1 -1
- package/dist/components/data/data-grid/data-grid.class.d.ts +5 -2
- package/dist/components/data/data-grid/data-grid.class.js +1 -1
- package/dist/components/data/flow-canvas/flow-canvas.class.d.ts +32 -5
- package/dist/components/data/flow-canvas/flow-canvas.class.js +3 -1
- package/dist/components/data/flow-canvas/flow-canvas.styles.js +1 -1
- package/dist/components/data/flow-canvas/flow-model.js +1 -1
- package/dist/components/data/flow-canvas/flow-types.d.ts +10 -1
- package/dist/components/data/gauge/gauge.class.d.ts +15 -2
- package/dist/components/data/gauge/gauge.class.js +20 -20
- package/dist/components/data/gauge/gauge.styles.js +1 -1
- package/dist/components/data/graph-query-builder/graph-query-builder.class.d.ts +14 -5
- package/dist/components/data/graph-query-builder/graph-query-builder.class.js +2 -2
- package/dist/components/data/sequence-strip/sequence-strip.class.d.ts +28 -2
- package/dist/components/data/sequence-strip/sequence-strip.class.js +3 -2
- package/dist/components/data/sequence-strip/sequence-strip.styles.js +1 -1
- package/dist/components/data/table/table.class.d.ts +155 -30
- package/dist/components/data/table/table.class.js +6 -4
- package/dist/components/data/table/table.styles.js +1 -1
- package/dist/components/data/timeline/timeline-item.class.d.ts +9 -1
- package/dist/components/data/timeline/timeline-item.class.js +2 -2
- package/dist/components/data/word-cloud/word-cloud.class.js +1 -1
- package/dist/components/data/word-cloud/word-cloud.styles.js +1 -1
- package/dist/components/forms/button/button.class.d.ts +30 -1
- package/dist/components/forms/button/button.class.js +2 -2
- package/dist/components/forms/checkbox/checkbox.class.d.ts +8 -6
- package/dist/components/forms/checkbox/checkbox.class.js +2 -2
- package/dist/components/forms/checkbox-group/checkbox-group.class.d.ts +7 -5
- package/dist/components/forms/checkbox-group/checkbox-group.class.js +1 -1
- package/dist/components/forms/color-picker/color-picker.class.d.ts +16 -2
- package/dist/components/forms/color-picker/color-picker.class.js +2 -2
- package/dist/components/forms/color-picker/color-picker.styles.js +1 -1
- package/dist/components/forms/combobox/combobox.class.d.ts +52 -7
- package/dist/components/forms/combobox/combobox.class.js +2 -2
- package/dist/components/forms/combobox/combobox.styles.js +1 -1
- package/dist/components/forms/date-picker/date-input.class.d.ts +4 -0
- package/dist/components/forms/date-picker/date-input.class.js +1 -1
- package/dist/components/forms/icon-button/icon-button.class.d.ts +20 -3
- package/dist/components/forms/icon-button/icon-button.class.js +1 -1
- package/dist/components/forms/icon-button/icon-button.styles.js +1 -1
- package/dist/components/forms/input/input.class.d.ts +5 -2
- package/dist/components/forms/input/input.class.js +1 -1
- package/dist/components/forms/input/time-input.class.d.ts +4 -0
- package/dist/components/forms/input/time-input.class.js +1 -1
- package/dist/components/forms/locale-picker/locale-picker.class.d.ts +11 -5
- package/dist/components/forms/locale-picker/locale-picker.class.js +1 -1
- package/dist/components/forms/otp-input/otp-input.class.d.ts +7 -2
- package/dist/components/forms/otp-input/otp-input.class.js +2 -2
- package/dist/components/forms/radio/radio-button.class.d.ts +2 -1
- package/dist/components/forms/radio/radio-group.class.d.ts +9 -4
- package/dist/components/forms/radio/radio-group.class.js +1 -1
- package/dist/components/forms/radio/radio.class.d.ts +13 -7
- package/dist/components/forms/radio/radio.class.js +1 -1
- package/dist/components/forms/rubric-form/rubric-form.class.d.ts +16 -6
- package/dist/components/forms/rubric-form/rubric-form.class.js +2 -2
- package/dist/components/forms/select/select.class.d.ts +50 -13
- package/dist/components/forms/select/select.class.js +2 -2
- package/dist/components/forms/slider/slider.class.d.ts +4 -2
- package/dist/components/forms/slider/slider.class.js +1 -1
- package/dist/components/forms/switch/switch.class.d.ts +8 -6
- package/dist/components/forms/switch/switch.class.js +1 -1
- package/dist/components/forms/textarea/textarea.class.d.ts +5 -3
- package/dist/components/forms/textarea/textarea.class.js +1 -1
- package/dist/components/forms/time-range/time-range.class.d.ts +12 -7
- package/dist/components/forms/time-range/time-range.class.js +1 -1
- package/dist/components/forms/time-range/time-range.styles.js +1 -1
- package/dist/components/forms/token-input/token-input.class.d.ts +6 -4
- package/dist/components/forms/token-input/token-input.class.js +1 -1
- package/dist/components/layout/app-rail/app-rail-item.class.d.ts +109 -4
- package/dist/components/layout/app-rail/app-rail-item.class.js +34 -29
- package/dist/components/layout/app-rail/app-rail-item.styles.js +1 -1
- package/dist/components/layout/app-rail/app-rail.class.d.ts +25 -3
- package/dist/components/layout/app-rail/app-rail.styles.js +1 -1
- package/dist/components/layout/app-rail-group/app-rail-group.class.d.ts +2 -2
- package/dist/components/layout/app-rail-group/app-rail-group.class.js +2 -2
- package/dist/components/layout/carousel/carousel.class.d.ts +1 -1
- package/dist/components/layout/carousel/carousel.class.js +1 -1
- package/dist/components/layout/details/accordion.class.d.ts +2 -2
- package/dist/components/layout/details/accordion.class.js +2 -2
- package/dist/components/layout/filter-bar/filter-bar-register.d.ts +1 -0
- package/dist/components/layout/filter-bar/filter-bar-register.js +1 -0
- package/dist/components/layout/filter-bar/filter-bar.class.d.ts +153 -16
- package/dist/components/layout/filter-bar/filter-bar.class.js +8 -5
- package/dist/components/layout/menu/menu-item.class.d.ts +3 -3
- package/dist/components/layout/menu/menu-item.class.js +3 -3
- package/dist/components/layout/menu/menu.class.d.ts +5 -1
- package/dist/components/layout/menu/menu.class.js +2 -2
- package/dist/components/layout/reorder-list/reorder-item.styles.js +1 -1
- package/dist/components/layout/reorder-list/reorder-list.class.js +1 -1
- package/dist/components/layout/virtual-list/virtual-list.class.d.ts +107 -2
- package/dist/components/layout/virtual-list/virtual-list.class.js +12 -7
- package/dist/components/media/attachment-trigger/attachment-trigger.styles.js +1 -1
- package/dist/components/media/avatar-group/avatar-group.class.d.ts +12 -1
- package/dist/components/media/avatar-group/avatar-group.class.js +2 -2
- package/dist/components/media/drop-zone/drop-zone.class.d.ts +32 -11
- package/dist/components/media/drop-zone/drop-zone.class.js +2 -2
- package/dist/components/media/file-input/file-input.class.d.ts +40 -19
- package/dist/components/media/file-input/file-input.class.js +2 -2
- package/dist/components/media/map/map.class.d.ts +138 -12
- package/dist/components/media/map/map.class.js +25 -20
- package/dist/components/media/map/map.styles.js +1 -1
- package/dist/components/overlays/callout/callout.styles.js +1 -1
- package/dist/components/overlays/dialog/dialog.styles.js +1 -1
- package/dist/components/overlays/overlay/dropdown.class.d.ts +13 -3
- package/dist/components/overlays/overlay/dropdown.class.js +2 -2
- package/dist/components/overlays/overlay/popover.class.d.ts +12 -3
- package/dist/components/overlays/overlay/popover.class.js +2 -2
- package/dist/components/overlays/rating/rating.class.d.ts +9 -7
- package/dist/components/overlays/rating/rating.class.js +1 -1
- package/dist/components/retrieval/citation-badge/citation-badge.class.d.ts +5 -1
- package/dist/components/retrieval/citation-badge/citation-badge.class.js +1 -1
- package/dist/components/retrieval/embedding-explorer/embedding-explorer.styles.js +1 -1
- package/dist/components/retrieval/entity-chip/entity-chip.class.d.ts +5 -1
- package/dist/components/retrieval/entity-chip/entity-chip.class.js +1 -1
- package/dist/components/retrieval/graph-legend/graph-legend.styles.js +1 -1
- package/dist/components/retrieval/retrieval-value-format.js +1 -1
- package/dist/components/retrieval/source-list/source-list.styles.js +1 -1
- package/dist/components/utility/copy-button/copy-button.class.d.ts +23 -11
- package/dist/components/utility/copy-button/copy-button.class.js +2 -2
- package/dist/components/utility/copy-button/copy-button.styles.js +1 -1
- package/dist/components/utility/diff-view/diff-view.styles.js +1 -1
- package/dist/components/utility/export-button/export-button.class.d.ts +4 -0
- package/dist/components/utility/export-button/export-button.class.js +1 -1
- package/dist/components/utility/json-viewer/json-viewer.styles.js +1 -1
- package/dist/components/utility/known-date/known-date.class.js +1 -1
- package/dist/components/utility/mention-popover/mention-popover.class.d.ts +38 -3
- package/dist/components/utility/mention-popover/mention-popover.class.js +2 -1
- package/dist/components/utility/mention-popover/mention-popover.styles.js +1 -1
- package/dist/components/utility/poll-status/poll-status.styles.js +1 -1
- package/dist/components/utility/tour/tour.class.d.ts +4 -0
- package/dist/components/utility/tour/tour.class.js +1 -1
- package/dist/components/utility/tour/tour.styles.js +1 -1
- package/dist/components/viewers/document-preview/document-preview.class.js +2 -2
- package/dist/components/viewers/docx-viewer/docx-viewer.class.js +2 -2
- package/dist/components/viewers/ebook-viewer/ebook-viewer.class.js +2 -2
- package/dist/components/viewers/highlight-layer/highlight-layer.class.js +2 -2
- package/dist/components/viewers/notebook-viewer/notebook-viewer.class.js +2 -2
- package/dist/components/viewers/pdf-viewer/pdf-viewer.class.js +2 -2
- package/dist/components/viewers/pptx-viewer/pptx-viewer.class.js +2 -2
- package/dist/components/viewers/xml-viewer/xml-viewer.class.js +2 -2
- package/dist/custom-elements-jsx.d.ts +2 -2
- package/dist/events.d.ts +20 -13
- package/dist/internal/aggregate-file-limits.d.ts +33 -0
- package/dist/internal/aggregate-file-limits.js +1 -0
- package/dist/internal/catalog-picker.d.ts +15 -2
- package/dist/internal/catalog-picker.js +1 -1
- package/dist/internal/debounce-controller.d.ts +14 -0
- package/dist/internal/debounce-controller.js +1 -1
- package/dist/internal/default-strings.generated.d.ts +1 -1
- package/dist/internal/default-strings.generated.js +2 -2
- package/dist/internal/focus-navigation.d.ts +45 -0
- package/dist/internal/focus-navigation.js +1 -1
- package/dist/internal/form-associated.js +1 -1
- package/dist/internal/initial-slot-collection.d.ts +30 -0
- package/dist/internal/initial-slot-collection.js +1 -0
- package/dist/internal/intl-cache.js +1 -1
- package/dist/internal/invalid-event-alias.d.ts +46 -0
- package/dist/internal/invalid-event-alias.js +1 -1
- package/dist/internal/localization-runtime.d.ts +24 -0
- package/dist/internal/localization-runtime.js +1 -1
- package/dist/internal/localization-types.d.ts +1 -1
- package/dist/internal/localization.js +1 -1
- package/dist/internal/package-metadata.d.ts +1 -1
- package/dist/internal/package-metadata.js +1 -1
- package/dist/internal/positioning-strategy.d.ts +3 -1
- package/dist/internal/state-part.d.ts +49 -0
- package/dist/internal/state-part.js +1 -0
- package/dist/internal/variants.styles.js +1 -1
- package/dist/lyra.d.ts +1 -1
- package/dist/lyra.js +1 -1
- package/dist/svelte.d.ts +2 -2
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +1 -1
- package/dist/testing/lyra-tag-event-map.d.ts +2 -2
- package/dist/testing/lyra-tag-event-map.js +1 -1
- package/dist/testing/wait-for-mount.d.ts +46 -0
- package/dist/testing/wait-for-mount.js +1 -0
- package/dist/theme/theme-bootstrap.js +1 -1
- package/dist/theme/theme.d.ts +11 -2
- package/dist/theme/theme.js +1 -1
- package/dist/translations/ar/layout.js +1 -1
- package/dist/translations/ar/retrieval.js +1 -1
- package/dist/translations/ar/shared.js +1 -1
- package/dist/translations/de/layout.js +1 -1
- package/dist/translations/de/retrieval.js +1 -1
- package/dist/translations/de/shared.js +1 -1
- package/dist/translations/es/layout.js +1 -1
- package/dist/translations/es/retrieval.js +1 -1
- package/dist/translations/es/shared.js +1 -1
- package/dist/translations/fa/layout.js +1 -1
- package/dist/translations/fa/retrieval.js +1 -1
- package/dist/translations/fa/shared.js +1 -1
- package/dist/translations/fr/layout.js +1 -1
- package/dist/translations/fr/retrieval.js +1 -1
- package/dist/translations/fr/shared.js +1 -1
- package/dist/translations/he/layout.js +1 -1
- package/dist/translations/he/retrieval.js +1 -1
- package/dist/translations/he/shared.js +1 -1
- package/dist/translations/it/layout.js +1 -1
- package/dist/translations/it/retrieval.js +1 -1
- package/dist/translations/it/shared.js +1 -1
- package/dist/translations/ja/layout.js +1 -1
- package/dist/translations/ja/retrieval.js +1 -1
- package/dist/translations/ja/shared.js +1 -1
- package/dist/translations/pt-BR/layout.js +1 -1
- package/dist/translations/pt-BR/retrieval.js +1 -1
- package/dist/translations/pt-BR/shared.js +1 -1
- package/dist/translations/ro/agent-tools.d.ts +1 -0
- package/dist/translations/ro/agent-tools.js +1 -0
- package/dist/translations/ro/charts.d.ts +1 -0
- package/dist/translations/ro/charts.js +1 -0
- package/dist/translations/ro/conversation.d.ts +1 -0
- package/dist/translations/ro/conversation.js +1 -0
- package/dist/translations/ro/data.d.ts +1 -0
- package/dist/translations/ro/data.js +1 -0
- package/dist/translations/ro/forms.d.ts +1 -0
- package/dist/translations/ro/forms.js +1 -0
- package/dist/translations/ro/layout.d.ts +1 -0
- package/dist/translations/ro/layout.js +1 -0
- package/dist/translations/ro/media.d.ts +1 -0
- package/dist/translations/ro/media.js +1 -0
- package/dist/translations/ro/overlays.d.ts +1 -0
- package/dist/translations/ro/overlays.js +1 -0
- package/dist/translations/ro/retrieval.d.ts +1 -0
- package/dist/translations/ro/retrieval.js +1 -0
- package/dist/translations/ro/shared.d.ts +1 -0
- package/dist/translations/ro/shared.js +1 -0
- package/dist/translations/ro/utility.d.ts +1 -0
- package/dist/translations/ro/utility.js +1 -0
- package/dist/translations/ro/viewers.d.ts +1 -0
- package/dist/translations/ro/viewers.js +5 -0
- package/dist/translations/ro.d.ts +1 -0
- package/dist/translations/ro.js +1 -0
- package/dist/translations/ru/layout.js +1 -1
- package/dist/translations/ru/retrieval.js +1 -1
- package/dist/translations/ru/shared.js +1 -1
- package/dist/translations/zh-CN/layout.js +1 -1
- package/dist/translations/zh-CN/retrieval.js +1 -1
- package/dist/translations/zh-CN/shared.js +1 -1
- package/dist/utilities/format.d.ts +17 -0
- package/dist/utilities/format.js +1 -1
- package/dist/vue.d.ts +2 -2
- package/llms/components/lr-app-rail-group.md +87 -10
- package/llms/components/lr-app-rail-item.md +88 -11
- package/llms/components/lr-app-rail.md +88 -11
- package/llms/components/lr-attachment-trigger.md +21 -0
- package/llms/components/lr-bar-chart.md +3 -2
- package/llms/components/lr-bubble-chart.md +3 -2
- package/llms/components/lr-button.md +5 -4
- package/llms/components/lr-callout.md +10 -0
- package/llms/components/lr-card.md +2 -1
- package/llms/components/lr-chart.md +43 -12
- package/llms/components/lr-citation-badge.md +7 -1
- package/llms/components/lr-code-block.md +21 -0
- package/llms/components/lr-color-picker.md +12 -7
- package/llms/components/lr-combobox.md +20 -1
- package/llms/components/lr-confirm-bar.md +36 -7
- package/llms/components/lr-context-meter.md +17 -4
- package/llms/components/lr-date-input.md +7 -1
- package/llms/components/lr-date-picker.md +6 -0
- package/llms/components/lr-dialog.md +21 -0
- package/llms/components/lr-doughnut-chart.md +3 -2
- package/llms/components/lr-drawer.md +10 -0
- package/llms/components/lr-drop-zone.md +16 -7
- package/llms/components/lr-dropdown-item.md +7 -0
- package/llms/components/lr-entity-chip.md +7 -1
- package/llms/components/lr-export-button.md +7 -1
- package/llms/components/lr-file-input.md +21 -10
- package/llms/components/lr-filter-bar.md +177 -18
- package/llms/components/lr-flow-canvas.md +16 -9
- package/llms/components/lr-gauge.md +22 -2
- package/llms/components/lr-histogram.md +7 -2
- package/llms/components/lr-icon-button.md +17 -8
- package/llms/components/lr-input.md +3 -1
- package/llms/components/lr-line-chart.md +3 -2
- package/llms/components/lr-lite-chart.md +13 -0
- package/llms/components/lr-locale-picker.md +7 -1
- package/llms/components/lr-map.md +63 -6
- package/llms/components/lr-mention-popover.md +16 -3
- package/llms/components/lr-menu-item.md +7 -0
- package/llms/components/lr-menu.md +8 -1
- package/llms/components/lr-message-actions.md +10 -0
- package/llms/components/lr-model-select.md +8 -3
- package/llms/components/lr-native-time-input.md +8 -1
- package/llms/components/lr-number-input.md +8 -1
- package/llms/components/lr-option.md +19 -0
- package/llms/components/lr-otp-input.md +6 -0
- package/llms/components/lr-pie-chart.md +3 -2
- package/llms/components/lr-polar-area-chart.md +3 -2
- package/llms/components/lr-prompt-input.md +2 -2
- package/llms/components/lr-radar-chart.md +3 -2
- package/llms/components/lr-reorder-item.md +12 -0
- package/llms/components/lr-reorder-list.md +12 -0
- package/llms/components/lr-scatter-chart.md +3 -2
- package/llms/components/lr-select.md +19 -2
- package/llms/components/lr-sequence-strip.md +10 -4
- package/llms/components/lr-streaming-text-core.md +28 -11
- package/llms/components/lr-streaming-text.md +41 -6
- package/llms/components/lr-suggestion-chips.md +8 -4
- package/llms/components/lr-table.md +47 -10
- package/llms/components/lr-textarea.md +1 -1
- package/llms/components/lr-time-input.md +7 -1
- package/llms/components/lr-tool-call-chip.md +7 -1
- package/llms/components/lr-tour.md +7 -1
- package/llms/components/lr-usage-badge.md +7 -1
- package/llms/components/lr-virtual-list.md +53 -0
- package/llms/components/lr-voice-picker.md +7 -3
- package/llms/shared.md +175 -19
- package/llms/tokens.md +17 -1
- package/llms-full.txt +1214 -169
- package/package.json +43 -3
- package/registrations.json +1 -1
- package/vscode-css-data.json +1 -1
- package/vscode-html-data.json +1 -1
- package/web-types.json +1 -1
|
@@ -102,6 +102,51 @@ export declare function focusFirstAvailable(targets:ComposedFocusRepairTargetSou
|
|
|
102
102
|
*/
|
|
103
103
|
export declare function repairComposedFocus(owner:Element,fallbackTargets:ComposedFocusRepairTargetSource):boolean;
|
|
104
104
|
/**
|
|
105
|
+
* Resolves once a reactive host has had a realistic chance to commit an update it scheduled
|
|
106
|
+
* during the task that just ran -- the exact window `deferComposedFocusRepair()` waits out before
|
|
107
|
+
* re-resolving a return-focus thunk. One microtask, then one animation frame:
|
|
108
|
+
*
|
|
109
|
+
* - A microtask covers Lit (this library's own components included), Vue's `nextTick`, and
|
|
110
|
+
* Svelte's `tick()` -- all three schedule their reactive flush as a microtask off the change
|
|
111
|
+
* that just happened, so by the time a microtask callback of our own runs, one already queued
|
|
112
|
+
* ahead of it (because the host's property write happened first, in the same synchronous turn
|
|
113
|
+
* that led here) has already committed its DOM mutation.
|
|
114
|
+
* - A following animation frame covers React's default automatic batching, which commits a
|
|
115
|
+
* click-driven state update synchronously before the browser's next paint rather than
|
|
116
|
+
* guaranteed inside a single microtask tick. `requestAnimationFrame` runs after the browser has
|
|
117
|
+
* finished any pending style/layout/paint work for the current frame, so a commit that landed
|
|
118
|
+
* "before paint" has necessarily already happened by the time this callback fires.
|
|
119
|
+
*
|
|
120
|
+
* One evaluation, not a poll loop: a return-focus thunk is "ask again once you have had a
|
|
121
|
+
* chance", not "keep asking until you succeed" -- see `deferComposedFocusRepair()`'s own doc
|
|
122
|
+
* comment for the give-up contract that depends on this being a single, bounded wait.
|
|
123
|
+
*/
|
|
124
|
+
export declare function nextHostUpdateOpportunity():Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Captures a repair on `bridge` right now (the synchronous parking spot a terminal focus handoff
|
|
127
|
+
* already moved focus to, so there is no focus gap), then -- after `nextHostUpdateOpportunity()`
|
|
128
|
+
* -- calls `resolveTarget()` again and moves focus to whatever it names if that has since become
|
|
129
|
+
* connected and focusable, without overriding a newer, genuinely different focus move.
|
|
130
|
+
*
|
|
131
|
+
* This exists for exactly one shape: a return-focus thunk whose whole documented reason to exist
|
|
132
|
+
* is naming a control the host is expected to *re-create* on the way back (an async re-render), so
|
|
133
|
+
* calling it once, synchronously, at handoff time necessarily finds nothing yet. Call this only
|
|
134
|
+
* after that first synchronous resolution has already failed and landed focus on `bridge` --
|
|
135
|
+
* an immediately-resolving thunk or a plain element value never reaches this function, so
|
|
136
|
+
* behavior for those already-working cases is unchanged.
|
|
137
|
+
*
|
|
138
|
+
* Declines exactly as `applyComposedFocusRepair()` already does: focus that moved to some other
|
|
139
|
+
* real element outside `owner` in the meantime is left alone. Focus that was lost along with
|
|
140
|
+
* `owner`'s own branch (the host removed the bridge's entire component, dropping focus to
|
|
141
|
+
* `<body>`) is NOT treated as "moved on" -- that disappearance is precisely the case a deferred
|
|
142
|
+
* thunk exists to recover from.
|
|
143
|
+
*
|
|
144
|
+
* Bounded and quiet: exactly one deferred re-resolution; a target that still does not exist, is
|
|
145
|
+
* not connected, or refuses focus (`inert`, removed, hidden) simply leaves focus wherever the
|
|
146
|
+
* synchronous parking step already put it.
|
|
147
|
+
*/
|
|
148
|
+
export declare function deferComposedFocusRepair(owner:Element,bridge:HTMLElement,resolveTarget:()=>HTMLElement|null):void;
|
|
149
|
+
/**
|
|
105
150
|
* Iteratively collects composed focus targets with a shared depth/node budget. Programmatic mode
|
|
106
151
|
* retains native and ARIA-managed actions after a roving owner assigns `tabindex=-1`; tabbable mode
|
|
107
152
|
* models sequential browser order, including one stop per native radio group.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{composedParentElement,deepActiveElementIn}from"./active-element.js";import{isAriaTrue}from"./accessibility-visibility.js";import{asciiWhitespaceTokens}from"./ascii-whitespace.js";import{imageMapImageFor,isHtmlElement,isSvgElement}from"./dom-guards.js";const DEFAULT_FOCUS_MAX_DEPTH=256,DEFAULT_FOCUS_MAX_NODES=1e4,MAX_CONFIGURED_FOCUS_LIMIT=1e5,ARIA_WIDGET_ROLES=new Set(["button","checkbox","combobox","grid","gridcell","link","listbox","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","option","radio","radiogroup","scrollbar","searchbox","separator","slider","spinbutton","switch","tab","tablist","textbox","tree","treegrid","treeitem"]),ARIA_NON_WIDGET_ROLES=new Set(["alert","alertdialog","application","article","banner","blockquote","caption","cell","code","columnheader","comment","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","group","heading","img","image","insertion","list","listitem","log","main","marquee","mark","math","meter","navigation","none","note","paragraph","presentation","progressbar","region","row","rowgroup","rowheader","search","sectionfooter","sectionheader","status","strong","subscript","suggestion","superscript","table","tabpanel","term","time","timer","toolbar","tooltip"]);function finiteFocusLimit(value,fallback){return Number.isFinite(value)?Math.min(MAX_CONFIGURED_FOCUS_LIMIT,Math.max(0,Math.floor(value))):fallback}function createFocusTraversalContext(options){return{elementStates:new Map,imageMapImages:new Map,maxDepth:finiteFocusLimit(options.maxDepth,DEFAULT_FOCUS_MAX_DEPTH),maxNodes:finiteFocusLimit(options.maxNodes,DEFAULT_FOCUS_MAX_NODES),reasons:new Set,workUnits:0}}function renderedElementState(element,imageMapImage){let style;try{style=element.ownerDocument.defaultView?.getComputedStyle(element)}catch{}return{display:style?.display,subtreeUnavailable:element.hasAttribute("hidden")||element.hasAttribute("inert")||isAriaTrue(element.getAttribute("aria-hidden"))||isAriaTrue(element.getAttribute("aria-disabled"))||!imageMapImage&&(style?.display==="none"||style?.contentVisibility==="hidden"),visibility:style?.visibility}}function consumeFocusWork(context){return context.workUnits>=context.maxNodes?(context.reasons.add("nodes"),!1):(context.workUnits+=1,!0)}function cachedRenderedElementState(context,element){let state=context.elementStates.get(element);return state||(state=renderedElementState(element,cachedImageMapImage(context,element)),context.elementStates.set(element,state)),state}function cachedImageMapImage(context,element){if(context.imageMapImages.has(element))return context.imageMapImages.get(element);const image=imageMapImageFor(element,{consume:()=>consumeFocusWork(context)});return context.imageMapImages.set(element,image),image}function isClosedDetailsBranch(details,branch,context){if(details.localName!=="details"||details.hasAttribute("open")||branch===null)return!1;for(const child of details.children){if(!consumeFocusWork(context))return!0;if(child.localName==="summary")return child!==branch}return!0}function composedAncestorsAvailable(element,context){let branch=element,ancestor=composedParentElement(element),depth=0;for(;ancestor;){if(!consumeFocusWork(context)||cachedRenderedElementState(context,ancestor).subtreeUnavailable||isClosedDetailsBranch(ancestor,branch,context))return!1;if(depth+=1,depth>context.maxDepth)return context.reasons.add("depth"),!1;branch=ancestor,ancestor=composedParentElement(ancestor)}return!0}function isRenderedFocusCandidate(context,element,state){const imageMapImage=cachedImageMapImage(context,element);if(isHtmlElement(element)&&element.localName==="area"&&!imageMapImage)return!1;if(imageMapImage){const imageState=cachedRenderedElementState(context,imageMapImage);return composedAncestorsAvailable(imageMapImage,context)&&!imageState.subtreeUnavailable&&isRenderedFocusCandidate(context,imageMapImage,imageState)}if(!element.isConnected||state.visibility==="hidden"||state.visibility==="collapse")return!1;const candidate=element;if(typeof candidate.checkVisibility=="function")try{return candidate.checkVisibility({contentVisibilityAuto:!0})}catch{return!1}return element.getClientRects().length>0}function hasAriaWidgetRole(element){for(const token of asciiWhitespaceTokens(element.getAttribute("role"))){const role=token.toLowerCase();if(ARIA_WIDGET_ROLES.has(role))return!0;if(ARIA_NON_WIDGET_ROLES.has(role))return!1}return!1}function isNativeAction(element){if(isSvgElement(element))return element.localName==="a"&&(element.hasAttribute("href")||element.hasAttributeNS("http://www.w3.org/1999/xlink","href"));switch(element.localName){case"a":return element.hasAttribute("href");case"area":{if(!element.hasAttribute("href"))return!1;let ancestor=element.parentElement;for(let depth=0;ancestor&&depth<=DEFAULT_FOCUS_MAX_DEPTH;depth+=1){if(ancestor.localName==="map")return!0;ancestor=ancestor.parentElement}return!1}case"audio":case"video":return element.hasAttribute("controls");case"button":case"embed":case"iframe":case"select":case"textarea":return!0;case"object":{const data=element.getAttribute("data");return data!==null&&data.trim()!==""}case"input":return element.type!=="hidden";case"summary":return element.matches("details > summary:first-of-type");default:return element.hasAttribute("contenteditable")&&element.isContentEditable&&!element.parentElement?.isContentEditable}}function isBrowserFocusElement(element){return isHtmlElement(element)||isSvgElement(element)}function isShadowRoot(root){return root.nodeType===11&&"host"in root}function isSemanticActionElement(element){return isBrowserFocusElement(element)&&(isNativeAction(element)||hasAriaWidgetRole(element))}function isActionableElement(element){return isSemanticActionElement(element)||isBrowserFocusElement(element)&&element.hasAttribute("tabindex")&&element.tabIndex>=0}function isComposedFocusAvailable(element,options={}){if(!isBrowserFocusElement(element))return!1;const context=createFocusTraversalContext(options);if(!consumeFocusWork(context)||!composedAncestorsAvailable(element,context))return!1;const state=cachedRenderedElementState(context,element);return state.subtreeUnavailable||element.matches(":disabled")?!1:isRenderedFocusCandidate(context,element,state)}function composedContains(container,candidate,maxDepth=DEFAULT_FOCUS_MAX_DEPTH){let current=candidate,depth=0;for(;current;){if(current===container)return!0;if(depth>=maxDepth)return!1;current=composedParentElement(current),depth+=1}return!1}function isComposedFocusRepairTargetList(value){return Array.isArray(value)}function resolveComposedFocusRepairTargets(source){const resolved=typeof source=="function"?source():source;if(!resolved)return[];if(!isComposedFocusRepairTargetList(resolved))return[resolved];const targets=[];for(const target of resolved)target&&targets.push(target);return targets}function captureComposedFocusRepair(owner,candidate){if(!candidate||candidate.ownerDocument!==owner.ownerDocument)return null;const activeElement=deepActiveElementIn(owner.ownerDocument);return!activeElement||!composedContains(owner,activeElement)?null:{activeElement,candidate,document:owner.ownerDocument,owner}}function applyComposedFocusRepair(snapshot,candidateOverride){const{document:ownerDocument,owner}=snapshot,targetSource=arguments.length<2?snapshot.candidate:candidateOverride,candidates=resolveComposedFocusRepairTargets(targetSource);if(candidates.length===0)return!1;const current=deepActiveElementIn(ownerDocument),lostWithBranch=current===null||current===ownerDocument.body||current===ownerDocument.documentElement;return current!==snapshot.activeElement&&!composedContains(owner,current)&&!lostWithBranch?!1:focusFirstAvailable(candidates.filter(candidate=>candidate.ownerDocument===ownerDocument))}function focusFirstAvailable(targets){for(const candidate of resolveComposedFocusRepairTargets(targets)){if(!isComposedFocusAvailable(candidate))continue;candidate.focus();const focused=deepActiveElementIn(candidate.ownerDocument);if(focused===candidate||composedContains(candidate,focused))return!0}return!1}function repairComposedFocus(owner,fallbackTargets){const activeElement=deepActiveElementIn(owner.ownerDocument);if(!activeElement||!composedContains(owner,activeElement))return!1;const candidates=resolveComposedFocusRepairTargets(fallbackTargets),[candidate]=candidates;return candidate?applyComposedFocusRepair({activeElement,candidate,document:owner.ownerDocument,owner},candidates):!1}function traverseComposedElements(root,options,include){const context=createFocusTraversalContext(options),{maxDepth,maxNodes}=context,elements=[],stack=[],visited=new Set,navigationScope={entries:[],nextOrder:0};if(maxNodes===0)return context.reasons.add("nodes"),{elements,navigationScope,reasons:context.reasons,visitedElements:0};const schedule=(element,depth,ancestorsAvailable,scope,workCharged=!1)=>{if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,depth,element,kind:"element",scope,workCharged})},scheduleChildren=(children,depth,ancestorsAvailable,scope)=>{if(children.length!==0){if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,children,depth,index:0,kind:"children",scope})}},scheduleSlotChildren=(slot,depth,ancestorsAvailable,scope)=>{if(depth>maxDepth){context.reasons.add("depth");return}const slotRoot=slot.getRootNode(),candidates=slotRoot.nodeType===11&&"host"in slotRoot?slotRoot.host.childNodes:[];stack.push({ancestorsAvailable,candidates,depth,fallback:slot.children,foundAssigned:!1,index:0,kind:"slot",scope,slot})},scheduleComposedChildren=(element,depth,ancestorsAvailable,scope)=>{if(element.localName==="slot"&&isHtmlElement(element)){scheduleSlotChildren(element,depth,ancestorsAvailable,scope);return}if(element.localName==="details"&&!element.hasAttribute("open")){for(const child of element.children){if(!consumeFocusWork(context))return;if(child.localName==="summary"){schedule(child,depth,ancestorsAvailable,scope,!0);return}}return}scheduleChildren(element.shadowRoot?.children??element.children,depth,ancestorsAvailable,scope)};if(isShadowRoot(root)){const shadowRoot=root,ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(shadowRoot.host,context),hostStateAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,shadowRoot.host).subtreeUnavailable;scheduleChildren(shadowRoot.children,0,ancestorsAvailable&&hostStateAvailable,navigationScope)}else if(options.includeRoot===!1){const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context),ownAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,root).subtreeUnavailable;scheduleComposedChildren(root,0,ancestorsAvailable&&ownAvailable,navigationScope)}else{const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context);schedule(root,0,ancestorsAvailable,navigationScope)}for(;stack.length>0;){const work=stack.pop();if(work.kind==="slot"){if(work.index>=work.candidates.length){work.foundAssigned||scheduleChildren(work.fallback,work.depth,work.ancestorsAvailable,work.scope);continue}if(!consumeFocusWork(context)){stack.length=0;break}const node=work.candidates[work.index],assigned=!!(node&&node.assignedSlot===work.slot);stack.push({...work,foundAssigned:work.foundAssigned||assigned,index:work.index+1}),node?.nodeType===1&&assigned&&schedule(node,work.depth,work.ancestorsAvailable,work.scope,!0);continue}if(work.kind==="children"){if(work.index>=work.children.length)continue;const element=work.children[work.index];stack.push({...work,index:work.index+1}),element&&schedule(element,work.depth,work.ancestorsAvailable,work.scope);continue}if(visited.has(work.element))continue;if(!work.workCharged&&!consumeFocusWork(context)){stack.length=0;break}visited.add(work.element);const state=cachedRenderedElementState(context,work.element),available=work.ancestorsAvailable&&!state.subtreeUnavailable,included=include(work.element,available,state,context);if(included&&elements.push(work.element),!available)continue;if(work.element.shadowRoot||work.element.localName==="slot"&&isHtmlElement(work.element)){const childScope={entries:[],nextOrder:0};work.scope.entries.push({childScope,delegatesFocus:!!work.element.shadowRoot?.delegatesFocus,order:work.scope.nextOrder++,suppressSequentialDescendants:work.element.hasAttribute("tabindex")&&work.element.tabIndex<0,target:included&&isBrowserFocusElement(work.element)?work.element:void 0}),scheduleComposedChildren(work.element,work.depth+1,!0,childScope);continue}included&&isBrowserFocusElement(work.element)&&work.scope.entries.push({order:work.scope.nextOrder++,target:work.element}),scheduleComposedChildren(work.element,work.depth+1,!0,work.scope)}return{elements,navigationScope,reasons:context.reasons,visitedElements:visited.size}}function isOverflowingTabStop(element){const view=element.ownerDocument.defaultView;if(!view)return!1;const{overflowX,overflowY}=view.getComputedStyle(element);return overflowX==="scroll"||overflowY==="scroll"||overflowY==="auto"&&element.scrollHeight>element.clientHeight?!0:overflowX==="auto"&&element.scrollWidth>element.clientWidth}function isTabbableCandidate(element){return element.hasAttribute("tabindex")?element.tabIndex>=0?!0:isHtmlElement(element)&&!isNativeAction(element)&&isOverflowingTabStop(element):isHtmlElement(element)&&element.hasAttribute("contenteditable")&&element.isContentEditable?!element.parentElement?.isContentEditable:isNativeAction(element)}function collapseRadioGroups(elements){const byRoot=new Map;for(const element of elements){if(!isHtmlElement(element)||element.localName!=="input")continue;const input=element;if(input.type!=="radio"||input.name==="")continue;const root=input.getRootNode();let byForm=byRoot.get(root);byForm||(byForm=new Map,byRoot.set(root,byForm));let byName=byForm.get(input.form);byName||(byName=new Map,byForm.set(input.form,byName));const group=byName.get(input.name);group?input.checked&&!group.checked&&(group.checked=input):byName.set(input.name,{checked:input.checked?input:void 0,first:input})}const tabStops=new Set;for(const byForm of byRoot.values())for(const byName of byForm.values())for(const group of byName.values())tabStops.add(group.checked??group.first);return elements.filter(element=>{if(!isHtmlElement(element)||element.localName!=="input")return!0;const input=element;return input.type!=="radio"||input.name===""||tabStops.has(input)})}function navigationEntryTabIndex(entry){return entry.target&&entry.target.tabIndex>0?entry.target.tabIndex:0}function flattenNavigationScope(scope,mode,retainedTargets){const orderedEntries=candidate=>mode==="tabbable"?[...candidate.entries].sort((first,second)=>{const firstTabIndex=navigationEntryTabIndex(first),secondTabIndex=navigationEntryTabIndex(second);return firstTabIndex>0!=secondTabIndex>0?firstTabIndex>0?-1:1:firstTabIndex>0&&firstTabIndex!==secondTabIndex?firstTabIndex-secondTabIndex:first.order-second.order}):candidate.entries,flattened=[],work=[{kind:"scope",scope}];for(;work.length>0;){const current=work.pop();if(current.kind==="target"){flattened.push(current.target);continue}const entries=orderedEntries(current.scope);for(let index=entries.length-1;index>=0;index-=1){const entry=entries[index];entry.childScope&&(mode!=="tabbable"||!entry.suppressSequentialDescendants)&&work.push({kind:"scope",scope:entry.childScope}),entry.target&&retainedTargets.has(entry.target)&&!entry.delegatesFocus&&work.push({kind:"target",target:entry.target})}}return flattened}function collectComposedFocusTargets(root,options={}){const mode=options.mode??"tabbable",traversed=traverseComposedElements(root,options,(candidate,available,state,context)=>!available||!isBrowserFocusElement(candidate)||candidate.matches(":disabled")||!isRenderedFocusCandidate(context,candidate,state)?!1:mode==="programmatic"?candidate.hasAttribute("tabindex")||isActionableElement(candidate):(candidate.hasAttribute("tabindex")||isActionableElement(candidate))&&isTabbableCandidate(candidate)),included=traversed.elements.filter(isBrowserFocusElement),retained=new Set(included),orderedElements=flattenNavigationScope(traversed.navigationScope,mode,retained);return{elements:mode==="tabbable"?collapseRadioGroups(orderedElements):orderedElements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}function collectComposedAutofocusElements(root,options={}){const traversed=traverseComposedElements(root,options,(element,available)=>available&&isHtmlElement(element)&&element.hasAttribute("autofocus"));return{elements:traversed.elements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}export{applyComposedFocusRepair,captureComposedFocusRepair,collectComposedAutofocusElements,collectComposedFocusTargets,focusFirstAvailable,isActionableElement,isComposedFocusAvailable,isSemanticActionElement,repairComposedFocus};
|
|
1
|
+
import{composedParentElement,deepActiveElementIn}from"./active-element.js";import{isAriaTrue}from"./accessibility-visibility.js";import{asciiWhitespaceTokens}from"./ascii-whitespace.js";import{imageMapImageFor,isHtmlElement,isSvgElement}from"./dom-guards.js";const DEFAULT_FOCUS_MAX_DEPTH=256,DEFAULT_FOCUS_MAX_NODES=1e4,MAX_CONFIGURED_FOCUS_LIMIT=1e5,ARIA_WIDGET_ROLES=new Set(["button","checkbox","combobox","grid","gridcell","link","listbox","menu","menubar","menuitem","menuitemcheckbox","menuitemradio","option","radio","radiogroup","scrollbar","searchbox","separator","slider","spinbutton","switch","tab","tablist","textbox","tree","treegrid","treeitem"]),ARIA_NON_WIDGET_ROLES=new Set(["alert","alertdialog","application","article","banner","blockquote","caption","cell","code","columnheader","comment","complementary","contentinfo","definition","deletion","dialog","directory","document","emphasis","feed","figure","form","generic","group","heading","img","image","insertion","list","listitem","log","main","marquee","mark","math","meter","navigation","none","note","paragraph","presentation","progressbar","region","row","rowgroup","rowheader","search","sectionfooter","sectionheader","status","strong","subscript","suggestion","superscript","table","tabpanel","term","time","timer","toolbar","tooltip"]);function finiteFocusLimit(value,fallback){return Number.isFinite(value)?Math.min(MAX_CONFIGURED_FOCUS_LIMIT,Math.max(0,Math.floor(value))):fallback}function createFocusTraversalContext(options){return{elementStates:new Map,imageMapImages:new Map,maxDepth:finiteFocusLimit(options.maxDepth,DEFAULT_FOCUS_MAX_DEPTH),maxNodes:finiteFocusLimit(options.maxNodes,DEFAULT_FOCUS_MAX_NODES),reasons:new Set,workUnits:0}}function renderedElementState(element,imageMapImage){let style;try{style=element.ownerDocument.defaultView?.getComputedStyle(element)}catch{}return{display:style?.display,subtreeUnavailable:element.hasAttribute("hidden")||element.hasAttribute("inert")||isAriaTrue(element.getAttribute("aria-hidden"))||isAriaTrue(element.getAttribute("aria-disabled"))||!imageMapImage&&(style?.display==="none"||style?.contentVisibility==="hidden"),visibility:style?.visibility}}function consumeFocusWork(context){return context.workUnits>=context.maxNodes?(context.reasons.add("nodes"),!1):(context.workUnits+=1,!0)}function cachedRenderedElementState(context,element){let state=context.elementStates.get(element);return state||(state=renderedElementState(element,cachedImageMapImage(context,element)),context.elementStates.set(element,state)),state}function cachedImageMapImage(context,element){if(context.imageMapImages.has(element))return context.imageMapImages.get(element);const image=imageMapImageFor(element,{consume:()=>consumeFocusWork(context)});return context.imageMapImages.set(element,image),image}function isClosedDetailsBranch(details,branch,context){if(details.localName!=="details"||details.hasAttribute("open")||branch===null)return!1;for(const child of details.children){if(!consumeFocusWork(context))return!0;if(child.localName==="summary")return child!==branch}return!0}function composedAncestorsAvailable(element,context){let branch=element,ancestor=composedParentElement(element),depth=0;for(;ancestor;){if(!consumeFocusWork(context)||cachedRenderedElementState(context,ancestor).subtreeUnavailable||isClosedDetailsBranch(ancestor,branch,context))return!1;if(depth+=1,depth>context.maxDepth)return context.reasons.add("depth"),!1;branch=ancestor,ancestor=composedParentElement(ancestor)}return!0}function isRenderedFocusCandidate(context,element,state){const imageMapImage=cachedImageMapImage(context,element);if(isHtmlElement(element)&&element.localName==="area"&&!imageMapImage)return!1;if(imageMapImage){const imageState=cachedRenderedElementState(context,imageMapImage);return composedAncestorsAvailable(imageMapImage,context)&&!imageState.subtreeUnavailable&&isRenderedFocusCandidate(context,imageMapImage,imageState)}if(!element.isConnected||state.visibility==="hidden"||state.visibility==="collapse")return!1;const candidate=element;if(typeof candidate.checkVisibility=="function")try{return candidate.checkVisibility({contentVisibilityAuto:!0})}catch{return!1}return element.getClientRects().length>0}function hasAriaWidgetRole(element){for(const token of asciiWhitespaceTokens(element.getAttribute("role"))){const role=token.toLowerCase();if(ARIA_WIDGET_ROLES.has(role))return!0;if(ARIA_NON_WIDGET_ROLES.has(role))return!1}return!1}function isNativeAction(element){if(isSvgElement(element))return element.localName==="a"&&(element.hasAttribute("href")||element.hasAttributeNS("http://www.w3.org/1999/xlink","href"));switch(element.localName){case"a":return element.hasAttribute("href");case"area":{if(!element.hasAttribute("href"))return!1;let ancestor=element.parentElement;for(let depth=0;ancestor&&depth<=DEFAULT_FOCUS_MAX_DEPTH;depth+=1){if(ancestor.localName==="map")return!0;ancestor=ancestor.parentElement}return!1}case"audio":case"video":return element.hasAttribute("controls");case"button":case"embed":case"iframe":case"select":case"textarea":return!0;case"object":{const data=element.getAttribute("data");return data!==null&&data.trim()!==""}case"input":return element.type!=="hidden";case"summary":return element.matches("details > summary:first-of-type");default:return element.hasAttribute("contenteditable")&&element.isContentEditable&&!element.parentElement?.isContentEditable}}function isBrowserFocusElement(element){return isHtmlElement(element)||isSvgElement(element)}function isShadowRoot(root){return root.nodeType===11&&"host"in root}function isSemanticActionElement(element){return isBrowserFocusElement(element)&&(isNativeAction(element)||hasAriaWidgetRole(element))}function isActionableElement(element){return isSemanticActionElement(element)||isBrowserFocusElement(element)&&element.hasAttribute("tabindex")&&element.tabIndex>=0}function isComposedFocusAvailable(element,options={}){if(!isBrowserFocusElement(element))return!1;const context=createFocusTraversalContext(options);if(!consumeFocusWork(context)||!composedAncestorsAvailable(element,context))return!1;const state=cachedRenderedElementState(context,element);return state.subtreeUnavailable||element.matches(":disabled")?!1:isRenderedFocusCandidate(context,element,state)}function composedContains(container,candidate,maxDepth=DEFAULT_FOCUS_MAX_DEPTH){let current=candidate,depth=0;for(;current;){if(current===container)return!0;if(depth>=maxDepth)return!1;current=composedParentElement(current),depth+=1}return!1}function isComposedFocusRepairTargetList(value){return Array.isArray(value)}function resolveComposedFocusRepairTargets(source){const resolved=typeof source=="function"?source():source;if(!resolved)return[];if(!isComposedFocusRepairTargetList(resolved))return[resolved];const targets=[];for(const target of resolved)target&&targets.push(target);return targets}function captureComposedFocusRepair(owner,candidate){if(!candidate||candidate.ownerDocument!==owner.ownerDocument)return null;const activeElement=deepActiveElementIn(owner.ownerDocument);return!activeElement||!composedContains(owner,activeElement)?null:{activeElement,candidate,document:owner.ownerDocument,owner}}function applyComposedFocusRepair(snapshot,candidateOverride){const{document:ownerDocument,owner}=snapshot,targetSource=arguments.length<2?snapshot.candidate:candidateOverride,candidates=resolveComposedFocusRepairTargets(targetSource);if(candidates.length===0)return!1;const current=deepActiveElementIn(ownerDocument),lostWithBranch=current===null||current===ownerDocument.body||current===ownerDocument.documentElement;return current!==snapshot.activeElement&&!composedContains(owner,current)&&!lostWithBranch?!1:focusFirstAvailable(candidates.filter(candidate=>candidate.ownerDocument===ownerDocument))}function focusFirstAvailable(targets){for(const candidate of resolveComposedFocusRepairTargets(targets)){if(!isComposedFocusAvailable(candidate))continue;candidate.focus();const focused=deepActiveElementIn(candidate.ownerDocument);if(focused===candidate||composedContains(candidate,focused))return!0}return!1}function repairComposedFocus(owner,fallbackTargets){const activeElement=deepActiveElementIn(owner.ownerDocument);if(!activeElement||!composedContains(owner,activeElement))return!1;const candidates=resolveComposedFocusRepairTargets(fallbackTargets),[candidate]=candidates;return candidate?applyComposedFocusRepair({activeElement,candidate,document:owner.ownerDocument,owner},candidates):!1}function nextHostUpdateOpportunity(){return new Promise(resolve=>{queueMicrotask(()=>{requestAnimationFrame(()=>resolve())})})}function deferComposedFocusRepair(owner,bridge,resolveTarget){const snapshot=captureComposedFocusRepair(owner,bridge);snapshot&&nextHostUpdateOpportunity().then(()=>{let target;try{target=resolveTarget()}catch{target=null}applyComposedFocusRepair(snapshot,target?[target]:[])})}function traverseComposedElements(root,options,include){const context=createFocusTraversalContext(options),{maxDepth,maxNodes}=context,elements=[],stack=[],visited=new Set,navigationScope={entries:[],nextOrder:0};if(maxNodes===0)return context.reasons.add("nodes"),{elements,navigationScope,reasons:context.reasons,visitedElements:0};const schedule=(element,depth,ancestorsAvailable,scope,workCharged=!1)=>{if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,depth,element,kind:"element",scope,workCharged})},scheduleChildren=(children,depth,ancestorsAvailable,scope)=>{if(children.length!==0){if(depth>maxDepth){context.reasons.add("depth");return}stack.push({ancestorsAvailable,children,depth,index:0,kind:"children",scope})}},scheduleSlotChildren=(slot,depth,ancestorsAvailable,scope)=>{if(depth>maxDepth){context.reasons.add("depth");return}const slotRoot=slot.getRootNode(),candidates=slotRoot.nodeType===11&&"host"in slotRoot?slotRoot.host.childNodes:[];stack.push({ancestorsAvailable,candidates,depth,fallback:slot.children,foundAssigned:!1,index:0,kind:"slot",scope,slot})},scheduleComposedChildren=(element,depth,ancestorsAvailable,scope)=>{if(element.localName==="slot"&&isHtmlElement(element)){scheduleSlotChildren(element,depth,ancestorsAvailable,scope);return}if(element.localName==="details"&&!element.hasAttribute("open")){for(const child of element.children){if(!consumeFocusWork(context))return;if(child.localName==="summary"){schedule(child,depth,ancestorsAvailable,scope,!0);return}}return}scheduleChildren(element.shadowRoot?.children??element.children,depth,ancestorsAvailable,scope)};if(isShadowRoot(root)){const shadowRoot=root,ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(shadowRoot.host,context),hostStateAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,shadowRoot.host).subtreeUnavailable;scheduleChildren(shadowRoot.children,0,ancestorsAvailable&&hostStateAvailable,navigationScope)}else if(options.includeRoot===!1){const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context),ownAvailable=consumeFocusWork(context)&&!cachedRenderedElementState(context,root).subtreeUnavailable;scheduleComposedChildren(root,0,ancestorsAvailable&&ownAvailable,navigationScope)}else{const ancestorsAvailable=options.skipRootAncestorValidation||composedAncestorsAvailable(root,context);schedule(root,0,ancestorsAvailable,navigationScope)}for(;stack.length>0;){const work=stack.pop();if(work.kind==="slot"){if(work.index>=work.candidates.length){work.foundAssigned||scheduleChildren(work.fallback,work.depth,work.ancestorsAvailable,work.scope);continue}if(!consumeFocusWork(context)){stack.length=0;break}const node=work.candidates[work.index],assigned=!!(node&&node.assignedSlot===work.slot);stack.push({...work,foundAssigned:work.foundAssigned||assigned,index:work.index+1}),node?.nodeType===1&&assigned&&schedule(node,work.depth,work.ancestorsAvailable,work.scope,!0);continue}if(work.kind==="children"){if(work.index>=work.children.length)continue;const element=work.children[work.index];stack.push({...work,index:work.index+1}),element&&schedule(element,work.depth,work.ancestorsAvailable,work.scope);continue}if(visited.has(work.element))continue;if(!work.workCharged&&!consumeFocusWork(context)){stack.length=0;break}visited.add(work.element);const state=cachedRenderedElementState(context,work.element),available=work.ancestorsAvailable&&!state.subtreeUnavailable,included=include(work.element,available,state,context);if(included&&elements.push(work.element),!available)continue;if(work.element.shadowRoot||work.element.localName==="slot"&&isHtmlElement(work.element)){const childScope={entries:[],nextOrder:0};work.scope.entries.push({childScope,delegatesFocus:!!work.element.shadowRoot?.delegatesFocus,order:work.scope.nextOrder++,suppressSequentialDescendants:work.element.hasAttribute("tabindex")&&work.element.tabIndex<0,target:included&&isBrowserFocusElement(work.element)?work.element:void 0}),scheduleComposedChildren(work.element,work.depth+1,!0,childScope);continue}included&&isBrowserFocusElement(work.element)&&work.scope.entries.push({order:work.scope.nextOrder++,target:work.element}),scheduleComposedChildren(work.element,work.depth+1,!0,work.scope)}return{elements,navigationScope,reasons:context.reasons,visitedElements:visited.size}}function isOverflowingTabStop(element){const view=element.ownerDocument.defaultView;if(!view)return!1;const{overflowX,overflowY}=view.getComputedStyle(element);return overflowX==="scroll"||overflowY==="scroll"||overflowY==="auto"&&element.scrollHeight>element.clientHeight?!0:overflowX==="auto"&&element.scrollWidth>element.clientWidth}function isTabbableCandidate(element){return element.hasAttribute("tabindex")?element.tabIndex>=0?!0:isHtmlElement(element)&&!isNativeAction(element)&&isOverflowingTabStop(element):isHtmlElement(element)&&element.hasAttribute("contenteditable")&&element.isContentEditable?!element.parentElement?.isContentEditable:isNativeAction(element)}function collapseRadioGroups(elements){const byRoot=new Map;for(const element of elements){if(!isHtmlElement(element)||element.localName!=="input")continue;const input=element;if(input.type!=="radio"||input.name==="")continue;const root=input.getRootNode();let byForm=byRoot.get(root);byForm||(byForm=new Map,byRoot.set(root,byForm));let byName=byForm.get(input.form);byName||(byName=new Map,byForm.set(input.form,byName));const group=byName.get(input.name);group?input.checked&&!group.checked&&(group.checked=input):byName.set(input.name,{checked:input.checked?input:void 0,first:input})}const tabStops=new Set;for(const byForm of byRoot.values())for(const byName of byForm.values())for(const group of byName.values())tabStops.add(group.checked??group.first);return elements.filter(element=>{if(!isHtmlElement(element)||element.localName!=="input")return!0;const input=element;return input.type!=="radio"||input.name===""||tabStops.has(input)})}function navigationEntryTabIndex(entry){return entry.target&&entry.target.tabIndex>0?entry.target.tabIndex:0}function flattenNavigationScope(scope,mode,retainedTargets){const orderedEntries=candidate=>mode==="tabbable"?[...candidate.entries].sort((first,second)=>{const firstTabIndex=navigationEntryTabIndex(first),secondTabIndex=navigationEntryTabIndex(second);return firstTabIndex>0!=secondTabIndex>0?firstTabIndex>0?-1:1:firstTabIndex>0&&firstTabIndex!==secondTabIndex?firstTabIndex-secondTabIndex:first.order-second.order}):candidate.entries,flattened=[],work=[{kind:"scope",scope}];for(;work.length>0;){const current=work.pop();if(current.kind==="target"){flattened.push(current.target);continue}const entries=orderedEntries(current.scope);for(let index=entries.length-1;index>=0;index-=1){const entry=entries[index];entry.childScope&&(mode!=="tabbable"||!entry.suppressSequentialDescendants)&&work.push({kind:"scope",scope:entry.childScope}),entry.target&&retainedTargets.has(entry.target)&&!entry.delegatesFocus&&work.push({kind:"target",target:entry.target})}}return flattened}function collectComposedFocusTargets(root,options={}){const mode=options.mode??"tabbable",traversed=traverseComposedElements(root,options,(candidate,available,state,context)=>!available||!isBrowserFocusElement(candidate)||candidate.matches(":disabled")||!isRenderedFocusCandidate(context,candidate,state)?!1:mode==="programmatic"?candidate.hasAttribute("tabindex")||isActionableElement(candidate):(candidate.hasAttribute("tabindex")||isActionableElement(candidate))&&isTabbableCandidate(candidate)),included=traversed.elements.filter(isBrowserFocusElement),retained=new Set(included),orderedElements=flattenNavigationScope(traversed.navigationScope,mode,retained);return{elements:mode==="tabbable"?collapseRadioGroups(orderedElements):orderedElements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}function collectComposedAutofocusElements(root,options={}){const traversed=traverseComposedElements(root,options,(element,available)=>available&&isHtmlElement(element)&&element.hasAttribute("autofocus"));return{elements:traversed.elements,truncated:traversed.reasons.size>0,truncationReasons:[...traversed.reasons],visitedElements:traversed.visitedElements}}export{applyComposedFocusRepair,captureComposedFocusRepair,collectComposedAutofocusElements,collectComposedFocusTargets,deferComposedFocusRepair,focusFirstAvailable,isActionableElement,isComposedFocusAvailable,isSemanticActionElement,nextHostUpdateOpportunity,repairComposedFocus};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LYRA_DEFAULT_fieldRequired}from"./default-strings.generated.js";import{resolveLyraString}from"./localization-runtime.js";import{AnchoredValidityController,SET_ANCHORED_VALIDITY,VALIDITY_ANCHOR}from"./anchored-validity.js";import{syncValidityStates}from"./custom-states.js";import{installInvalidEventAlias}from"./invalid-event-alias.js";import{omittedEmptyStringConverter}from"./converters.js";import{attachInternalsSafely,createFallbackInternals}from"./element-internals.js";import{installFormControlLabelSupport}from"./form-control-labels.js";import{getFormOwner,installCustomErrorProperty,setFormOwner}from"./direct-form-associated.js";installFormControlLabelSupport();const FORM_ASSOCIATED_DEFAULT_STRINGS=Object.freeze({fieldRequired:LYRA_DEFAULT_fieldRequired});function createStringArrayFormDataState(name,values){const state=new FormData,key=name||"value";for(const value of values)state.append(key,value);return state}function readStringArrayFormDataState(state){if(typeof FormData!="function")return[];let entries;try{entries=[...FormData.prototype.values.call(state)]}catch{return[]}return entries.some(entry=>typeof entry!="string")?[]:entries}function isEmptyFormValue(value){if(value==null)return!0;if(typeof value=="string")return value==="";if(typeof value=="object")try{if(Array.isArray(value))return value.length===0;const prototype=Object.getPrototypeOf(value);if(prototype===null)return Object.keys(value).length===0;if(Object.getPrototypeOf(prototype)===null){const constructor=Object.getOwnPropertyDescriptor(prototype,"constructor")?.value;if(typeof constructor=="function"&&constructor.name==="Object"&&constructor.prototype===prototype)return Object.keys(value).length===0}}catch{return!1}return!1}const stringFormValueAdapter={empty:"",toFormValue:value=>value,isEmpty:value=>value==="",fromAttribute:attribute=>attribute,toAttribute:value=>value,fromFormState:state=>typeof state=="string"?state:""};function resolveFormValueAdapter(adapter){return adapter===void 0?stringFormValueAdapter:{empty:adapter.empty,toFormValue:value=>adapter.toFormValue(value),...adapter.toFormState?{toFormState:value=>adapter.toFormState(value)}:{},isEmpty:adapter.isEmpty?value=>adapter.isEmpty(value):isEmptyFormValue,fromAttribute:adapter.fromAttribute?attribute=>adapter.fromAttribute(attribute):attribute=>attribute,toAttribute:adapter.toAttribute?value=>adapter.toAttribute(value):value=>value==null?null:String(value),fromFormState:adapter.fromFormState?state=>adapter.fromFormState(state):state=>typeof state=="string"?state:adapter.empty}}function isBarredFromValidation(host,internals){if((host.effectiveDisabled??host.disabled)||host.readonly)return!0;if(internals){const willValidate=readNativeWillValidate(internals);if(willValidate!==void 0)return!willValidate}return!1}function readNativeWillValidate(internals){if(typeof ElementInternals!="function")return;const getter=Object.getOwnPropertyDescriptor(ElementInternals.prototype,"willValidate")?.get;if(typeof getter=="function")try{const value=getter.call(internals);return typeof value=="boolean"?value:void 0}catch{return}}function FormAssociated(Base,valueAdapter){const adapter=resolveFormValueAdapter(valueAdapter),defaultValueConverter={fromAttribute:attribute=>attribute===null?null:adapter.fromAttribute(attribute),toAttribute:value=>value==null?null:adapter.toAttribute(value)};class FormAssociatedElement extends Base{static{this.formAssociated=!0}static{this.properties={name:{reflect:!0,noAccessor:!0,converter:omittedEmptyStringConverter},value:{attribute:!1,noAccessor:!0},defaultValue:{attribute:"value",reflect:!0,useDefault:!0,noAccessor:!0,...valueAdapter?{converter:defaultValueConverter}:{}},customError:{attribute:"custom-error",reflect:!0,noAccessor:!0},form:{noAccessor:!0},disabled:{type:Boolean,reflect:!0,noAccessor:!0},required:{type:Boolean,reflect:!0,noAccessor:!0}}}constructor(...args){super(...args),this._fieldsetDisabled=!1,this._disabled=!1,this._reflectingDisabledAttribute=!1,this._name="",this._value=adapter.empty,this._defaultValue=adapter.empty,this._valueDirty=!1,this.settingDefaultValue=!1,this.reflectingDefaultValue=!1,this.reflectingCustomError=!1,this.reflectingFormOwner=!1,this._required=!1,this._hasInteracted=!1,this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),this.commitFormValue(this._value),installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init));const markInteracted=()=>{this._hasInteracted||(this._hasInteracted=!0,this.syncValidityStates())};this.addEventListener("input",markInteracted),this.addEventListener("change",markInteracted),this.addEventListener("focusout",()=>{this.effectiveDisabled||markInteracted()}),this.syncValidityStates()}get form(){return getFormOwner(this.internals)}set form(owner){if(!this.reflectingFormOwner){this.reflectingFormOwner=!0;try{setFormOwner(this,owner)}finally{this.reflectingFormOwner=!1}}}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}[VALIDITY_ANCHOR](){return this.renderRoot?.querySelector("input:not([type='hidden']), textarea, select, button, [tabindex]:not([tabindex='-1'])")??null}[SET_ANCHORED_VALIDITY](flags,message=""){this.validityController.setValidity(flags,message),this.syncValidityStates()}commitCustomValidity(message){const old=this.customError,normalized=message??"";this.validityController.setCustomValidity(normalized),this.syncValidityStates(),this.reflectingCustomError=!0;try{normalized?this.setAttribute("custom-error",normalized):this.removeAttribute("custom-error")}finally{this.reflectingCustomError=!1}this.requestUpdate("customError",old)}setCustomValidity(message){this.commitCustomValidity(message)}resetValidity(){this.commitCustomValidity(""),this.updateValidity(),this.syncValidityStates()}syncValidityStates(){syncValidityStates(this.internals,{required:this.required,hasInteracted:this._hasInteracted,barred:this.isBarredFromValidation()})}isBarredFromValidation(){return isBarredFromValidation(this,this.internals)}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}commitFormValue(value){const submitted=adapter.toFormValue(value);adapter.toFormState?this.internals.setFormValue(submitted,adapter.toFormState(value)):this.internals.setFormValue(submitted)}get value(){return this._value}set value(next){const old=this._value;this._value=next??adapter.empty,this.settingDefaultValue||(this._valueDirty=!0),this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}captureLiveValueCheckpoint(){return{value:this._value,dirty:this._valueDirty}}restoreLiveValueCheckpoint(checkpoint){const old=this._value;this._value=checkpoint.value,this._valueDirty=checkpoint.dirty,this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}get defaultValue(){return this._defaultValue}set defaultValue(next){if(this.reflectingDefaultValue)return;const old=this._defaultValue;this._defaultValue=next??adapter.empty,this.reflectingDefaultValue=!0;try{const attribute=next==null?null:adapter.toAttribute(this._defaultValue);attribute==null?this.removeAttribute("value"):this.setAttribute("value",attribute)}finally{this.reflectingDefaultValue=!1}this._valueDirty||this.restoreLiveValueFromDefault(),this.requestUpdate("defaultValue",old)}get customError(){return this.validityController.customValidityMessage||null}set customError(next){this.reflectingCustomError||this.commitCustomValidity(next)}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),!this._disabled&&typeof this.matches=="function"&&(this._fieldsetDisabled=this.matches(":disabled")),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("disabled",old)}toggleAttribute(qualifiedName,force){if(qualifiedName!=="disabled")return super.toggleAttribute(qualifiedName,force);const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{return super.toggleAttribute(qualifiedName,force)}finally{this._reflectingDisabledAttribute=wasReflecting}}setAttribute(qualifiedName,value){if(qualifiedName!=="disabled"){super.setAttribute(qualifiedName,value);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.setAttribute(qualifiedName,value)}finally{this._reflectingDisabledAttribute=wasReflecting}}removeAttribute(qualifiedName){if(qualifiedName!=="disabled"){super.removeAttribute(qualifiedName);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.removeAttribute(qualifiedName)}finally{this._reflectingDisabledAttribute=wasReflecting}}get required(){return this._required}set required(next){const old=this._required;this._required=next,this.toggleAttribute("required",next),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("required",old)}get effectiveDisabled(){return this.disabled||this._fieldsetDisabled}setFormValue(next){this.value=next}updateValidity(){if(this.isBarredFromValidation()){this[SET_ANCHORED_VALIDITY]({});return}if(this.required&&adapter.isEmpty(this._value)){const overrides=this.strings,message=resolveLyraString(this,"fieldRequired",overrides,void 0,void 0,FORM_ASSOCIATED_DEFAULT_STRINGS);this[SET_ANCHORED_VALIDITY]({valueMissing:!0},message)}else this[SET_ANCHORED_VALIDITY]({})}syncConstraintsToNative(){const host=this;host.hasUpdated&&host.performUpdate()}checkValidity(){return this.syncConstraintsToNative(),this.updateValidity(),this.internals.checkValidity()}reportValidity(){return this.syncConstraintsToNative(),this.updateValidity(),this._hasInteracted=!0,this.syncValidityStates(),this.internals.reportValidity()}formResetCallback(){this._valueDirty=!1,this.restoreLiveValueFromDefault(),this._hasInteracted=!1,this.syncValidityStates()}restoreLiveValueFromDefault(){this.settingDefaultValue=!0;try{this.value=this._defaultValue}finally{this.settingDefaultValue=!1}this._valueDirty=!1}formStateRestoreCallback(state,reason){this.value=adapter.fromFormState(state)}formDisabledCallback(fieldsetDisabled){if(this._reflectingDisabledAttribute)return;const before=this.effectiveDisabled;this._fieldsetDisabled=fieldsetDisabled,this.effectiveDisabled!==before&&(this.updateValidity(),this.syncValidityStates(),this.requestUpdate())}updated(changed){super.updated(changed),!(!changed.has("readonly")&&!changed.has("disabled"))&&(this.updateValidity(),this.syncValidityStates())}connectedCallback(){super.connectedCallback(),this.updateValidity(),this.syncValidityStates()}}return FormAssociatedElement}export{FormAssociated,attachInternalsSafely,createFallbackInternals,createStringArrayFormDataState,getFormOwner,installCustomErrorProperty,isBarredFromValidation,isEmptyFormValue,readStringArrayFormDataState,setFormOwner,stringFormValueAdapter};
|
|
1
|
+
import{LYRA_DEFAULT_fieldRequired}from"./default-strings.generated.js";import{resolveLyraString}from"./localization-runtime.js";import{AnchoredValidityController,SET_ANCHORED_VALIDITY,VALIDITY_ANCHOR}from"./anchored-validity.js";import{syncValidityStates}from"./custom-states.js";import{installInteractionOnInvalid,installInvalidEventAlias,withStaticValidityCheck}from"./invalid-event-alias.js";import{omittedEmptyStringConverter}from"./converters.js";import{attachInternalsSafely,createFallbackInternals}from"./element-internals.js";import{installFormControlLabelSupport}from"./form-control-labels.js";import{getFormOwner,installCustomErrorProperty,setFormOwner}from"./direct-form-associated.js";installFormControlLabelSupport();const FORM_ASSOCIATED_DEFAULT_STRINGS=Object.freeze({fieldRequired:LYRA_DEFAULT_fieldRequired});function createStringArrayFormDataState(name,values){const state=new FormData,key=name||"value";for(const value of values)state.append(key,value);return state}function readStringArrayFormDataState(state){if(typeof FormData!="function")return[];let entries;try{entries=[...FormData.prototype.values.call(state)]}catch{return[]}return entries.some(entry=>typeof entry!="string")?[]:entries}function isEmptyFormValue(value){if(value==null)return!0;if(typeof value=="string")return value==="";if(typeof value=="object")try{if(Array.isArray(value))return value.length===0;const prototype=Object.getPrototypeOf(value);if(prototype===null)return Object.keys(value).length===0;if(Object.getPrototypeOf(prototype)===null){const constructor=Object.getOwnPropertyDescriptor(prototype,"constructor")?.value;if(typeof constructor=="function"&&constructor.name==="Object"&&constructor.prototype===prototype)return Object.keys(value).length===0}}catch{return!1}return!1}const stringFormValueAdapter={empty:"",toFormValue:value=>value,isEmpty:value=>value==="",fromAttribute:attribute=>attribute,toAttribute:value=>value,fromFormState:state=>typeof state=="string"?state:""};function resolveFormValueAdapter(adapter){return adapter===void 0?stringFormValueAdapter:{empty:adapter.empty,toFormValue:value=>adapter.toFormValue(value),...adapter.toFormState?{toFormState:value=>adapter.toFormState(value)}:{},isEmpty:adapter.isEmpty?value=>adapter.isEmpty(value):isEmptyFormValue,fromAttribute:adapter.fromAttribute?attribute=>adapter.fromAttribute(attribute):attribute=>attribute,toAttribute:adapter.toAttribute?value=>adapter.toAttribute(value):value=>value==null?null:String(value),fromFormState:adapter.fromFormState?state=>adapter.fromFormState(state):state=>typeof state=="string"?state:adapter.empty}}function isBarredFromValidation(host,internals){if((host.effectiveDisabled??host.disabled)||host.readonly)return!0;if(internals){const willValidate=readNativeWillValidate(internals);if(willValidate!==void 0)return!willValidate}return!1}function readNativeWillValidate(internals){if(typeof ElementInternals!="function")return;const getter=Object.getOwnPropertyDescriptor(ElementInternals.prototype,"willValidate")?.get;if(typeof getter=="function")try{const value=getter.call(internals);return typeof value=="boolean"?value:void 0}catch{return}}function FormAssociated(Base,valueAdapter){const adapter=resolveFormValueAdapter(valueAdapter),defaultValueConverter={fromAttribute:attribute=>attribute===null?null:adapter.fromAttribute(attribute),toAttribute:value=>value==null?null:adapter.toAttribute(value)};class FormAssociatedElement extends Base{static{this.formAssociated=!0}static{this.properties={name:{reflect:!0,noAccessor:!0,converter:omittedEmptyStringConverter},value:{attribute:!1,noAccessor:!0},defaultValue:{attribute:"value",reflect:!0,useDefault:!0,noAccessor:!0,...valueAdapter?{converter:defaultValueConverter}:{}},customError:{attribute:"custom-error",reflect:!0,noAccessor:!0},form:{noAccessor:!0},disabled:{type:Boolean,reflect:!0,noAccessor:!0},required:{type:Boolean,reflect:!0,noAccessor:!0}}}constructor(...args){super(...args),this._fieldsetDisabled=!1,this._disabled=!1,this._reflectingDisabledAttribute=!1,this._name="",this._value=adapter.empty,this._defaultValue=adapter.empty,this._valueDirty=!1,this.settingDefaultValue=!1,this.reflectingDefaultValue=!1,this.reflectingCustomError=!1,this.reflectingFormOwner=!1,this._required=!1,this._hasInteracted=!1,this.internals=attachInternalsSafely(this),this.validityController=new AnchoredValidityController(this,this.internals,()=>this[VALIDITY_ANCHOR]()),this.commitFormValue(this._value),installInvalidEventAlias(this,init=>this.emit("lr-invalid",null,init));const markInteracted=()=>{this._hasInteracted||(this._hasInteracted=!0,this.syncValidityStates())};this.addEventListener("input",markInteracted),this.addEventListener("change",markInteracted),this.addEventListener("focusout",()=>{this.effectiveDisabled||markInteracted()}),installInteractionOnInvalid(this,markInteracted),this.syncValidityStates()}get form(){return getFormOwner(this.internals)}set form(owner){if(!this.reflectingFormOwner){this.reflectingFormOwner=!0;try{setFormOwner(this,owner)}finally{this.reflectingFormOwner=!1}}}getForm(){return getFormOwner(this.internals)}get labels(){return this.internals.labels}get validity(){return this.internals.validity}get validationMessage(){return this.internals.validationMessage}get willValidate(){return this.internals.willValidate}[VALIDITY_ANCHOR](){return this.renderRoot?.querySelector("input:not([type='hidden']), textarea, select, button, [tabindex]:not([tabindex='-1'])")??null}[SET_ANCHORED_VALIDITY](flags,message=""){this.validityController.setValidity(flags,message),this.syncValidityStates()}commitCustomValidity(message){const old=this.customError,normalized=message??"";this.validityController.setCustomValidity(normalized),this.syncValidityStates(),this.reflectingCustomError=!0;try{normalized?this.setAttribute("custom-error",normalized):this.removeAttribute("custom-error")}finally{this.reflectingCustomError=!1}this.requestUpdate("customError",old)}setCustomValidity(message){this.commitCustomValidity(message)}resetValidity(){this.commitCustomValidity(""),this.updateValidity(),this.syncValidityStates()}syncValidityStates(){syncValidityStates(this.internals,{required:this.required,hasInteracted:this._hasInteracted,barred:this.isBarredFromValidation()})}isBarredFromValidation(){return isBarredFromValidation(this,this.internals)}get name(){return this._name}set name(next){const old=this._name;this._name=next??"",this._name?this.setAttribute("name",this._name):this.removeAttribute("name"),this.requestUpdate("name",old)}commitFormValue(value){const submitted=adapter.toFormValue(value);adapter.toFormState?this.internals.setFormValue(submitted,adapter.toFormState(value)):this.internals.setFormValue(submitted)}get value(){return this._value}set value(next){const old=this._value;this._value=next??adapter.empty,this.settingDefaultValue||(this._valueDirty=!0),this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}captureLiveValueCheckpoint(){return{value:this._value,dirty:this._valueDirty}}restoreLiveValueCheckpoint(checkpoint){const old=this._value;this._value=checkpoint.value,this._valueDirty=checkpoint.dirty,this.commitFormValue(this._value),this.updateValidity(),this.requestUpdate("value",old)}get defaultValue(){return this._defaultValue}set defaultValue(next){if(this.reflectingDefaultValue)return;const old=this._defaultValue;this._defaultValue=next??adapter.empty,this.reflectingDefaultValue=!0;try{const attribute=next==null?null:adapter.toAttribute(this._defaultValue);attribute==null?this.removeAttribute("value"):this.setAttribute("value",attribute)}finally{this.reflectingDefaultValue=!1}this._valueDirty||this.restoreLiveValueFromDefault(),this.requestUpdate("defaultValue",old)}get customError(){return this.validityController.customValidityMessage||null}set customError(next){this.reflectingCustomError||this.commitCustomValidity(next)}get disabled(){return this._disabled}set disabled(next){const old=this._disabled;this._disabled=!!next,this.toggleAttribute("disabled",this._disabled),!this._disabled&&typeof this.matches=="function"&&(this._fieldsetDisabled=this.matches(":disabled")),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("disabled",old)}toggleAttribute(qualifiedName,force){if(qualifiedName!=="disabled")return super.toggleAttribute(qualifiedName,force);const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{return super.toggleAttribute(qualifiedName,force)}finally{this._reflectingDisabledAttribute=wasReflecting}}setAttribute(qualifiedName,value){if(qualifiedName!=="disabled"){super.setAttribute(qualifiedName,value);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.setAttribute(qualifiedName,value)}finally{this._reflectingDisabledAttribute=wasReflecting}}removeAttribute(qualifiedName){if(qualifiedName!=="disabled"){super.removeAttribute(qualifiedName);return}const wasReflecting=this._reflectingDisabledAttribute;this._reflectingDisabledAttribute=!0;try{super.removeAttribute(qualifiedName)}finally{this._reflectingDisabledAttribute=wasReflecting}}get required(){return this._required}set required(next){const old=this._required;this._required=next,this.toggleAttribute("required",next),this.updateValidity(),this.syncValidityStates(),this.requestUpdate("required",old)}get effectiveDisabled(){return this.disabled||this._fieldsetDisabled}setFormValue(next){this.value=next}updateValidity(){if(this.isBarredFromValidation()){this[SET_ANCHORED_VALIDITY]({});return}if(this.required&&adapter.isEmpty(this._value)){const overrides=this.strings,message=resolveLyraString(this,"fieldRequired",overrides,void 0,void 0,FORM_ASSOCIATED_DEFAULT_STRINGS);this[SET_ANCHORED_VALIDITY]({valueMissing:!0},message)}else this[SET_ANCHORED_VALIDITY]({})}syncConstraintsToNative(){const host=this;host.hasUpdated&&host.performUpdate()}checkValidity(){return this.syncConstraintsToNative(),this.updateValidity(),withStaticValidityCheck(this,()=>this.internals.checkValidity())}reportValidity(){return this.syncConstraintsToNative(),this.updateValidity(),this._hasInteracted=!0,this.syncValidityStates(),this.internals.reportValidity()}formResetCallback(){this._valueDirty=!1,this.restoreLiveValueFromDefault(),this._hasInteracted=!1,this.syncValidityStates()}restoreLiveValueFromDefault(){this.settingDefaultValue=!0;try{this.value=this._defaultValue}finally{this.settingDefaultValue=!1}this._valueDirty=!1}formStateRestoreCallback(state,reason){this.value=adapter.fromFormState(state)}formDisabledCallback(fieldsetDisabled){if(this._reflectingDisabledAttribute)return;const before=this.effectiveDisabled;this._fieldsetDisabled=fieldsetDisabled,this.effectiveDisabled!==before&&(this.updateValidity(),this.syncValidityStates(),this.requestUpdate())}updated(changed){super.updated(changed),!(!changed.has("readonly")&&!changed.has("disabled"))&&(this.updateValidity(),this.syncValidityStates())}connectedCallback(){super.connectedCallback(),this.updateValidity(),this.syncValidityStates()}}return FormAssociatedElement}export{FormAssociated,attachInternalsSafely,createFallbackInternals,createStringArrayFormDataState,getFormOwner,installCustomErrorProperty,isBarredFromValidation,isEmptyFormValue,readStringArrayFormDataState,setFormOwner,stringFormValueAdapter};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs a component's own slot-assignment collector once against a slot's CURRENT assignment, for
|
|
3
|
+
* a call from `firstUpdated()` alongside the component's ordinary `@slotchange` listener.
|
|
4
|
+
*
|
|
5
|
+
* happy-dom (verified through 20.14.5) never fires `slotchange` for a slot's INITIAL assignment --
|
|
6
|
+
* only for a later mutation to an already-connected slot. So a component that derives state (an
|
|
7
|
+
* options list, a selection default, an item collection, ...) exclusively from a `slotchange`
|
|
8
|
+
* handler collects nothing under it when the slotted children already exist before the component
|
|
9
|
+
* first renders -- the ordinary Lit "render only once data is ready" pattern, which slots every
|
|
10
|
+
* child in the same commit as the host itself. A real browser DOES fire the initial event, so
|
|
11
|
+
* calling the same collector from both `firstUpdated()` and `slotchange` keeps the component
|
|
12
|
+
* correct in both environments, provided the collector is idempotent against being run twice with
|
|
13
|
+
* the same assigned elements -- which a real browser firing both does on every connect. This
|
|
14
|
+
* helper only supplies the timing; the caller owns idempotency. `select.class.ts`'s
|
|
15
|
+
* `collectOptionsFromSlot` is the reference: identity-diffing the previous element set against the
|
|
16
|
+
* newly-read one makes a second call over an unchanged set contribute no duplicate
|
|
17
|
+
* selection-seeding side effect.
|
|
18
|
+
*
|
|
19
|
+
* A caller whose one-shot seeding logic must not fire on a legitimately empty result (nothing
|
|
20
|
+
* assigned yet, real content arriving later through its own ordinary `slotchange`) filters that
|
|
21
|
+
* case out of `collect` itself, or checks `slot.assignedElements(...)` before calling this helper
|
|
22
|
+
* at all -- this helper does not special-case emptiness.
|
|
23
|
+
*
|
|
24
|
+
* @param slot The slot to read (e.g. an `@query`-bound field, or
|
|
25
|
+
* `renderRoot.querySelector('slot:not([name])')`). `null`/`undefined` is a no-op -- a component
|
|
26
|
+
* whose relevant slot didn't render for the current props has nothing to collect yet.
|
|
27
|
+
* @param collect The component's own collection logic, given the slot directly rather than an
|
|
28
|
+
* `Event` (`slotchange`'s `e.target`), so it has one calling convention from either origin.
|
|
29
|
+
*/
|
|
30
|
+
export declare function collectInitialSlotAssignment<T extends HTMLSlotElement>(slot:T|null|undefined,collect:(slot:T)=>void):void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function collectInitialSlotAssignment(slot,collect){slot&&collect(slot)}export{collectInitialSlotAssignment};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const MAX_ENTRIES_PER_KIND=64,numberFormatCache=new Map,dateTimeFormatCache=new Map,displayNamesCache=new Map,listFormatCache=new Map,relativeTimeFormatCache=new Map,pluralRulesCache=new Map,collatorCache=new Map,segmenterCache=new Map,resolvedLocaleCache=new Map;function resolveIntlLocale(locale){const raw=locale?.trim()??"",cached=resolvedLocaleCache.get(raw);if(cached!==void 0)return cached;const normalized=raw.replaceAll("_","-");let resolved="en";if(normalized&&normalized.toLowerCase()!=="auto")try{resolved=Intl.getCanonicalLocales(normalized)[0]??"en"}catch{}return resolvedLocaleCache.size>=64&&resolvedLocaleCache.clear(),resolvedLocaleCache.set(raw,resolved),resolved}function cacheKey(locale,options){const localeKey=locale;return options?`${localeKey}\0${JSON.stringify(options,Object.keys(options).sort())}`:localeKey}function getCached(cache,key,create){const existing=cache.get(key);if(existing!==void 0)return cache.delete(key),cache.set(key,existing),existing;if(cache.size>=64){const oldest=cache.keys().next().value;oldest!==void 0&&cache.delete(oldest)}const created=create();return cache.set(key,created),created}function
|
|
1
|
+
const MAX_ENTRIES_PER_KIND=64,numberFormatCache=new Map,dateTimeFormatCache=new Map,displayNamesCache=new Map,listFormatCache=new Map,relativeTimeFormatCache=new Map,pluralRulesCache=new Map,collatorCache=new Map,segmenterCache=new Map,resolvedLocaleCache=new Map;function resolveIntlLocale(locale){const raw=locale?.trim()??"",cached=resolvedLocaleCache.get(raw);if(cached!==void 0)return cached;const normalized=raw.replaceAll("_","-");let resolved="en";if(normalized&&normalized.toLowerCase()!=="auto")try{resolved=Intl.getCanonicalLocales(normalized)[0]??"en"}catch{}return resolvedLocaleCache.size>=64&&resolvedLocaleCache.clear(),resolvedLocaleCache.set(raw,resolved),resolved}function cacheKey(locale,options){const localeKey=locale;return options?`${localeKey}\0${JSON.stringify(options,Object.keys(options).sort())}`:localeKey}function getCached(cache,key,create){const existing=cache.get(key);if(existing!==void 0)return cache.delete(key),cache.set(key,existing),existing;if(cache.size>=64){const oldest=cache.keys().next().value;oldest!==void 0&&cache.delete(oldest)}const created=create();return cache.set(key,created),created}function getFormatter(locale,options,cache,create){const safeLocale=resolveIntlLocale(locale);return getCached(cache,cacheKey(safeLocale,options),()=>create(safeLocale))}function getNumberFormat(locale,options){return getFormatter(locale,options,numberFormatCache,safeLocale=>new Intl.NumberFormat(safeLocale,options))}function getDateTimeFormat(locale,options){return getFormatter(locale,options,dateTimeFormatCache,safeLocale=>new Intl.DateTimeFormat(safeLocale,options))}function getDisplayNames(locale,options){return getFormatter(locale,options,displayNamesCache,safeLocale=>new Intl.DisplayNames([safeLocale],options))}function getListFormat(locale,options){return getFormatter(locale,options,listFormatCache,safeLocale=>new Intl.ListFormat(safeLocale,options))}function getRelativeTimeFormat(locale,options){return getFormatter(locale,options,relativeTimeFormatCache,safeLocale=>new Intl.RelativeTimeFormat(safeLocale,options))}function getPluralRules(locale,options){return getFormatter(locale,options,pluralRulesCache,safeLocale=>new Intl.PluralRules(safeLocale,options))}function getCollator(locale,options){return getFormatter(locale,options,collatorCache,safeLocale=>new Intl.Collator(safeLocale,options))}function getSegmenter(locale,options){return getFormatter(locale,options,segmenterCache,safeLocale=>new Intl.Segmenter(safeLocale,options))}export{getCollator,getDateTimeFormat,getDisplayNames,getListFormat,getNumberFormat,getPluralRules,getRelativeTimeFormat,getSegmenter,resolveIntlLocale};
|
|
@@ -17,3 +17,49 @@
|
|
|
17
17
|
* undefined, init)` — since only an event dispatched `cancelable` can be cancelled at all.
|
|
18
18
|
*/
|
|
19
19
|
export declare function installInvalidEventAlias(host:EventTarget,emitAlias:(init:{cancelable:true;})=>Event|void):void;
|
|
20
|
+
/**
|
|
21
|
+
* Runs `run` (a control's own `internals.checkValidity()` call) in a scope where a synchronously
|
|
22
|
+
* dispatched `invalid` event on `host` is known to come from a **silent, static** validity query,
|
|
23
|
+
* not from interactive validation. Pair with `installInteractionOnInvalid()`, which reads this
|
|
24
|
+
* scope to decide whether that same `invalid` event should mark the control as user-interacted.
|
|
25
|
+
*
|
|
26
|
+
* @param host The control whose `internals.checkValidity()` is about to run.
|
|
27
|
+
* @param run Performs the static check (typically `() => this.internals.checkValidity()`) and
|
|
28
|
+
* returns its result.
|
|
29
|
+
*/
|
|
30
|
+
export declare function withStaticValidityCheck<T>(host:EventTarget,run:()=>T):T;
|
|
31
|
+
/**
|
|
32
|
+
* Reads the scope `withStaticValidityCheck()` sets: true while `host`'s own `internals.checkValidity()`
|
|
33
|
+
* call is synchronously on the stack. For a control whose `invalid` targeting is more than "did this
|
|
34
|
+
* fire on the host itself" (a group that also owns other form-associated children and listens for
|
|
35
|
+
* their `invalid` events in the capture phase, say), this is the lower-level primitive to gate a
|
|
36
|
+
* bespoke listener with directly; `installInteractionOnInvalid()` is the convenience wrapper for the
|
|
37
|
+
* common host-only case.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isStaticValidityCheckInProgress(host:EventTarget):boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Marks `host` as user-interacted whenever a native `invalid` event targets it directly, unless
|
|
42
|
+
* that event was raised synchronously inside a `withStaticValidityCheck()` scope.
|
|
43
|
+
*
|
|
44
|
+
* The platform dispatches the exact same `ElementInternals`-sourced `invalid` event, with no
|
|
45
|
+
* discriminator on it at all, for every path that revalidates a form-associated element:
|
|
46
|
+
* `checkValidity()` (silent — must never touch a pristine control's interaction state, however
|
|
47
|
+
* invalid the control already is), `reportValidity()`, and — the path nothing in this library
|
|
48
|
+
* previously observed — a submission attempt (`requestSubmit()`, a submit button, or implicit
|
|
49
|
+
* Enter submission), which is exactly when native `:user-invalid` starts matching. Listening for
|
|
50
|
+
* `invalid` itself, rather than wrapping `reportValidity()`, is what makes the submission path
|
|
51
|
+
* observable at all: a submission attempt never calls the control's own `reportValidity()` method,
|
|
52
|
+
* it drives `ElementInternals` directly.
|
|
53
|
+
*
|
|
54
|
+
* LIMITATION: a form's own **static** `form.checkValidity()` fires this identical event, from this
|
|
55
|
+
* identical `ElementInternals`, for every invalid participant — nothing distinguishes "the form is
|
|
56
|
+
* quietly asking every control whether it's valid" from "the form is attempting to submit and this
|
|
57
|
+
* control is one of the blockers" once the event reaches an individual control. This function
|
|
58
|
+
* resolves that ambiguity by marking interaction, the same as it would for a real submission
|
|
59
|
+
* attempt, since a form-level static check cannot be told apart from one on the receiving end.
|
|
60
|
+
*
|
|
61
|
+
* @param host The element whose own `invalid` events count toward interaction.
|
|
62
|
+
* @param markInteracted Records that `host` has now been "touched" for `:state(user-valid)`/
|
|
63
|
+
* `:state(user-invalid)` purposes and re-syncs whatever reflects those states.
|
|
64
|
+
*/
|
|
65
|
+
export declare function installInteractionOnInvalid(host:EventTarget,markInteracted:()=>void):void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function installInvalidEventAlias(host,emitAlias){host.addEventListener("invalid",event=>{if(event
|
|
1
|
+
function installInvalidEventAlias(host,emitAlias){host.addEventListener("invalid",event=>{if(!targetsHost(event,host))return;emitAlias({cancelable:!0})?.defaultPrevented&&event.preventDefault()})}function targetsHost(event,host){return event.composedPath()[0]===host}const staticValidityCheckDepth=new WeakMap;function withStaticValidityCheck(host,run){staticValidityCheckDepth.set(host,(staticValidityCheckDepth.get(host)??0)+1);try{return run()}finally{const depth=(staticValidityCheckDepth.get(host)??1)-1;depth<=0?staticValidityCheckDepth.delete(host):staticValidityCheckDepth.set(host,depth)}}function isStaticValidityCheckInProgress(host){return(staticValidityCheckDepth.get(host)??0)>0}function installInteractionOnInvalid(host,markInteracted){host.addEventListener("invalid",event=>{targetsHost(event,host)&&(isStaticValidityCheckInProgress(host)||markInteracted())})}export{installInteractionOnInvalid,installInvalidEventAlias,isStaticValidityCheckInProgress,withStaticValidityCheck};
|
|
@@ -65,6 +65,30 @@ export declare function setLyraLocale(locale:string):void;
|
|
|
65
65
|
/** Return the current page-level locale. */
|
|
66
66
|
export declare function getLyraLocale():string;
|
|
67
67
|
/**
|
|
68
|
+
* Resolves a `locale` argument for a standalone, host-less locale-aware utility function --
|
|
69
|
+
* `formatNumber()`/`formatDate()`/`formatRelativeTime()`/`formatBytes()` (`utilities/format.ts`)
|
|
70
|
+
* and `binValues()` (`components/charts/chart/histogram-bin.ts`) are the current callers. These
|
|
71
|
+
* have no component host to inherit a locale from the way {@link inheritedLocale} does, so an
|
|
72
|
+
* omitted, empty/whitespace, or `'auto'` value means {@link setLyraLocale}'s active locale instead
|
|
73
|
+
* -- the one piece of that inheritance chain a plain function call can still observe. A
|
|
74
|
+
* non-empty, non-`'auto'` value is returned unchanged and stays authoritative over the active
|
|
75
|
+
* locale, exactly like an explicit argument always has.
|
|
76
|
+
*
|
|
77
|
+
* This deliberately stops at the active locale and does NOT fall through to `<html lang>` (let
|
|
78
|
+
* alone `navigator.language`, which no part of this library's resolution chain reads) the way
|
|
79
|
+
* {@link inheritedLocale} does for a component host with no closer signal: a document's `lang`
|
|
80
|
+
* attribute is metadata a *host element* inherits by walking the DOM, and a bare function call
|
|
81
|
+
* has no host to walk from. Silently reading the document here would also break the one
|
|
82
|
+
* compatibility guarantee this function exists to preserve -- see the next paragraph.
|
|
83
|
+
*
|
|
84
|
+
* `activeLocale` is `''` before any `setLyraLocale()` call, and `''` is returned as-is (never
|
|
85
|
+
* coerced to `'en'` here): every `Intl` cache getter's own `resolveIntlLocale()` step
|
|
86
|
+
* (`internal/intl-cache.ts`) already normalizes an empty/undefined locale to `'en'`, so an app
|
|
87
|
+
* that never calls `setLyraLocale()` gets exactly the deterministic English output it always has
|
|
88
|
+
* -- this function changes nothing for that app.
|
|
89
|
+
*/
|
|
90
|
+
export declare function resolveActiveOrExplicitLocale(locale:string|undefined):string|undefined;
|
|
91
|
+
/**
|
|
68
92
|
* Subscribe to active-locale selection changes and registrations that can alter the active
|
|
69
93
|
* locale's messages or direction. Unrelated catalog registrations are registry-only and do not
|
|
70
94
|
* fire this channel. The returned function is safe to call repeatedly.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{devWarnOnce}from"./dev-mode-attribute-warning.js";import{getPluralRules}from"./intl-cache.js";const MAX_LOCALE_CANDIDATES=64,MAX_LOCALE_SUBTAGS=32,MAX_LOCALE_TAG_LENGTH=255,MAX_LOCALE_CACHE_ENTRIES=128,MAX_CACHEABLE_LOCALE_LENGTH=512,LEGACY_LOCALE_PATTERN=/^[a-z0-9]{1,32}(?:-[a-z0-9]{1,32})*$/,locales=new Map,localePublicTags=new Map,localeMeta=new Map,wellFormedLocales=new Set,exactOnlyLocales=new Set,localeCatalogRevisions=new Map,listeners=new Set,hostLocaleListeners=new Set,hostLocaleFinalizer=new FinalizationRegistry(subscription=>{hostLocaleListeners.delete(subscription)}),ownerDocumentsWithBrowsingContext=new WeakSet,registryListeners=new Set;let activeLocale="",catalogRevision=0;const localeIdentityCache=new Map,localeCandidateCache=new Map;function cacheBounded(cache,key,value){cache.size>=MAX_LOCALE_CACHE_ENTRIES&&cache.clear(),cache.set(key,value)}function subtagCountWithinBounds(tag){if(tag.length>MAX_LOCALE_TAG_LENGTH)return!1;let count=tag?1:0;for(let index=0;index<tag.length;index+=1)if(tag.charCodeAt(index)===45&&++count>MAX_LOCALE_SUBTAGS)return!1;return!0}function localeIdentity(locale){const normalized=typeof locale=="string"?locale.trim().replace(/_/g,"-"):"";if(!normalized)return{publicTag:"",lookupKey:"",wellFormed:!1,candidateBounded:!0,storable:!1};const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeIdentityCache.get(normalized):void 0;if(cached)return cached;let publicTag=normalized.toLowerCase(),wellFormed=!1;try{const canonical=Intl.getCanonicalLocales(normalized)[0];canonical&&(publicTag=canonical,wellFormed=!0)}catch{}const lookupKey=publicTag.toLowerCase(),candidateBounded=subtagCountWithinBounds(lookupKey),identity={publicTag,lookupKey,wellFormed,candidateBounded,storable:wellFormed||candidateBounded&&LEGACY_LOCALE_PATTERN.test(lookupKey)};return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeIdentityCache,normalized,identity),identity}function storedLocaleIdentity(locale,required){if(typeof locale!="string")throw new TypeError("A locale must be a string.");const identity=localeIdentity(locale);if(!identity.publicTag){if(!required)return identity;throw new TypeError("A locale is required.")}if(!identity.storable)throw new TypeError("The locale must be BCP-47 or a bounded alphanumeric custom tag.");return identity}function canonicalizeLyraLocale(locale){const identity=localeIdentity(locale);return identity.storable?identity.publicTag:"en"}function regionalFallbacks(requestedKey,limit,wellFormed){if(limit<=0||!wellFormed)return[];const separator=requestedKey.indexOf("-"),language=separator===-1?requestedKey:requestedKey.slice(0,separator);if(!language)return[];const requested=new Set(requestedKey.split("-")),score=key=>key.split("-").filter(subtag=>requested.has(subtag)).length;return[...locales.keys()].filter(key=>wellFormedLocales.has(key)&&!exactOnlyLocales.has(key)&&(key===language||key.startsWith(`${language}-`))&&!isPrefixOf(key,requestedKey)).sort((a,b)=>score(b)-score(a)||(a<b?-1:a>b?1:0)).slice(0,limit)}function isPrefixOf(key,requestedKey){return key===requestedKey||requestedKey.startsWith(`${key}-`)}function localeCandidates(locale){const identity=localeIdentity(locale),normalized=identity.lookupKey;if(!normalized)return["en"];const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeCandidateCache.get(normalized):void 0;if(cached)return[...cached];const candidates=[];if((identity.wellFormed||identity.candidateBounded)&&candidates.push(normalized),identity.candidateBounded){for(let index=normalized.length-1;index>=0;index-=1)normalized.charCodeAt(index)===45&&index>0&&candidates.push(normalized.slice(0,index));const regionalBudget=Math.max(0,MAX_LOCALE_CANDIDATES-candidates.length-1);candidates.push(...regionalFallbacks(normalized,regionalBudget,identity.wellFormed))}else if(identity.wellFormed){const separator=normalized.indexOf("-");separator>0&&candidates.push(normalized.slice(0,separator))}candidates.includes("en")||candidates.push("en");const frozen=Object.freeze([...candidates]);return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeCandidateCache,normalized,frozen),candidates}function lyraLocaleCatalogVersion(locale){return localeCandidates(locale).map(candidate=>localeCatalogRevisions.get(candidate)??0).join(",")}function getRegisteredLyraLocales(){const keys=new Set(["en",...localePublicTags.values()]);return Object.freeze([...keys].sort())}const NO_REGISTERED_LOCALE_KEYS=Object.freeze([]);function getRegisteredLyraLocaleKeys(locale){const identity=localeIdentity(locale);if(!identity.lookupKey)return NO_REGISTERED_LOCALE_KEYS;const catalog=locales.get(identity.lookupKey);return catalog?Object.freeze(Object.keys(catalog)):NO_REGISTERED_LOCALE_KEYS}function subscribeLyraLocaleRegistry(listener){return registryListeners.add(listener),()=>registryListeners.delete(listener)}const MAX_CATALOG_MESSAGES=4096,MAX_CATALOG_PROPERTY_READS=MAX_CATALOG_MESSAGES*2,MAX_MESSAGE_KEY_LENGTH=256,PLURAL_CATEGORIES=new Set(["zero","one","two","few","many","other"]),trustedMessageRecords=new WeakSet;function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;try{const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}catch{return!1}}function ownDataValue(record,key){try{const descriptor=Object.getOwnPropertyDescriptor(record,key);return!descriptor||!("value"in descriptor)?{found:!1}:{found:!0,value:descriptor.value}}catch{return{found:!1}}}function snapshotPluralMessage(value){if(!isPlainRecord(value))return;const snapshot=Object.create(null);let count=0;try{for(const key in value){if(++count>PLURAL_CATEGORIES.size||!PLURAL_CATEGORIES.has(key)||!Object.prototype.hasOwnProperty.call(value,key))return;const entry=ownDataValue(value,key);if(!entry.found||typeof entry.value!="string")return;snapshot[key]=entry.value}}catch{return}if(typeof snapshot.other!="string")return;const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function snapshotMessage(value){return typeof value=="string"?value:snapshotPluralMessage(value)}function snapshotCatalog(strings){const snapshot=Object.create(null);if(!isPlainRecord(strings)){const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let keys;try{keys=Reflect.ownKeys(strings).slice(0,MAX_CATALOG_PROPERTY_READS)}catch{const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let count=0;for(const key of keys){if(count>=MAX_CATALOG_MESSAGES)break;if(typeof key!="string"||!key||key.length>MAX_MESSAGE_KEY_LENGTH)continue;let descriptor;try{descriptor=Reflect.getOwnPropertyDescriptor(strings,key)}catch{continue}if(!descriptor?.enumerable||!("value"in descriptor))continue;count+=1;const message=snapshotMessage(descriptor.value);message!==void 0&&(snapshot[key]=message)}const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function mergeCatalogs(current,incoming){const merged=Object.assign(Object.create(null),current??{},incoming);return Object.freeze(merged),trustedMessageRecords.add(merged),merged}function snapshotLocaleMeta(meta){if(meta===void 0)return;if(!isPlainRecord(meta))return Object.freeze({});const snapshot={},dir=ownDataValue(meta,"dir");dir.found&&(dir.value==="ltr"||dir.value==="rtl")&&(snapshot.dir=dir.value);const name=ownDataValue(meta,"name");return name.found&&typeof name.value=="string"&&(snapshot.name=name.value),Object.freeze(snapshot)}function snapshotLyraLocaleStrings(strings){return snapshotCatalog(strings)}function safeMessageAt(source,key){if(!isPlainRecord(source))return;if(trustedMessageRecords.has(source))return source[key];const entry=ownDataValue(source,key);return entry.found?snapshotMessage(entry.value):void 0}function deliverLocaleListeners(groups,operation){const errors=[];for(const group of groups)for(const listener of group)try{listener()}catch(error){errors.push(error)}if(errors.length>0)throw new AggregateError(errors,`${operation} committed, but ${errors.length} locale subscriber${errors.length===1?"":"s"} failed.`)}function localeUsesCatalog(locale,lookupKey){return localeCandidates(locale).includes(lookupKey)}function ownerView(host){try{return host.ownerDocument.defaultView}catch{return}}function recordLyraOwnerDocumentConnection(host){ownerView(host)&&ownerDocumentsWithBrowsingContext.add(host.ownerDocument)}function forgetHostLocaleSubscription(subscription){hostLocaleListeners.delete(subscription),hostLocaleFinalizer.unregister(subscription)}function liveHostLocaleSubscriptions(){const live=[];for(const subscription of[...hostLocaleListeners]){const host=subscription.host.deref();if(!host||!host.isConnected||ownerDocumentsWithBrowsingContext.has(host.ownerDocument)&&ownerView(host)===null){forgetHostLocaleSubscription(subscription);continue}live.push({host})}return live}function registerLocale(locale,strings,meta,exactOnly){const identity=storedLocaleIdentity(locale,!0),key=identity.lookupKey,incomingStrings=snapshotCatalog(strings),incomingMeta=snapshotLocaleMeta(meta),isNewLocale=!locales.has(key),candidateTopologyChanged=isNewLocale||exactOnly&&!exactOnlyLocales.has(key)||identity.wellFormed&&!wellFormedLocales.has(key);exactOnly&&exactOnlyLocales.add(key),identity.wellFormed&&wellFormedLocales.add(key),locales.set(key,mergeCatalogs(locales.get(key),incomingStrings)),localePublicTags.set(key,identity.publicTag),incomingMeta&&localeMeta.set(key,Object.freeze({...localeMeta.get(key)??{},...incomingMeta})),localeCatalogRevisions.set(key,++catalogRevision),candidateTopologyChanged&&(pluralLocaleCache.clear(),localeCandidateCache.clear());const activeSnapshot=activeLocale&&localeUsesCatalog(activeLocale,key)?[...listeners]:[],hostSnapshot=liveHostLocaleSubscriptions().filter(({host})=>localeUsesCatalog(inheritedLocale(host),key)).map(({host})=>()=>host.requestUpdate()),registrySnapshot=isNewLocale?[...registryListeners]:[];deliverLocaleListeners([activeSnapshot,hostSnapshot,registrySnapshot],`registerLyraLocale(${JSON.stringify(identity.publicTag)})`)}function registerLyraLocale(locale,strings,meta){registerLocale(locale,strings,meta,!1)}function registerLyraExactLocale(locale,strings,meta){registerLocale(locale,strings,meta,!0)}function getLyraLocaleDirection(locale){const identity=localeIdentity(locale);if(!identity.publicTag)return"ltr";for(const candidate of localeCandidates(identity.publicTag)){const declared=localeMeta.get(candidate)?.dir;if(declared)return declared}try{const resolved=new Intl.Locale(identity.publicTag);return(resolved.textInfo?.direction??resolved.getTextInfo?.().direction)==="rtl"?"rtl":"ltr"}catch{return"ltr"}}function setLyraLocale(locale){const next=storedLocaleIdentity(locale,!1).publicTag;if(activeLocale===next)return;const hostSnapshot=liveHostLocaleSubscriptions(),previousHostLocales=hostSnapshot.map(({host})=>inheritedLocale(host));activeLocale=next;const affectedHostListeners=hostSnapshot.filter(({host},index)=>inheritedLocale(host)!==previousHostLocales[index]).map(({host})=>()=>host.requestUpdate());deliverLocaleListeners([[...listeners],affectedHostListeners],`setLyraLocale(${JSON.stringify(next)})`)}function getLyraLocale(){return activeLocale}function subscribeLyraLocale(listener){return listeners.add(listener),()=>listeners.delete(listener)}function subscribeLyraLocaleForHost(host){recordLyraOwnerDocumentConnection(host);const subscription={host:new WeakRef(host)};return hostLocaleListeners.add(subscription),hostLocaleFinalizer.register(host,subscription,subscription),()=>forgetHostLocaleSubscription(subscription)}function composedParentElement(element){if(element.parentElement)return element.parentElement;const root=element.getRootNode(),candidate=root.host;return root.nodeType===11&&candidate!==null&&typeof candidate=="object"&&typeof candidate.getAttribute=="function"?candidate:null}function flattenedParentElement(element){const slot=element.assignedSlot;return slot!==null&&typeof slot=="object"&&typeof slot.getAttribute=="function"?slot:composedParentElement(element)}function inheritedLocale(host){const explicit=host.getAttribute("locale")||host.getAttribute("lang");if(explicit)return canonicalizeLyraLocale(explicit);if(host.getAttribute("lang")==="")return activeLocale||"en";const documentElement=host.ownerDocument?.documentElement;let parent=composedParentElement(host);for(;parent;){const isDocumentElement=parent===documentElement,locale=isDocumentElement?parent.getAttribute("locale"):parent.getAttribute("locale")||parent.getAttribute("lang");if(locale)return canonicalizeLyraLocale(locale);if(!isDocumentElement&&parent.getAttribute("lang")==="")return activeLocale||"en";parent=composedParentElement(parent)}if(activeLocale)return activeLocale;const documentLocale=documentElement?.getAttribute("lang");return documentLocale?canonicalizeLyraLocale(documentLocale):"en"}const cacheableLocaleHosts=new WeakSet,resolvedLocaleCache=new WeakMap,resolvedDirectionCache=new WeakMap;function enableLyraLocaleCache(host){cacheableLocaleHosts.add(host)}function invalidateLyraLocaleCache(host){resolvedLocaleCache.delete(host),resolvedDirectionCache.delete(host)}function resolveLyraLocale(host){if(!cacheableLocaleHosts.has(host))return inheritedLocale(host);let locale=resolvedLocaleCache.get(host);return locale===void 0&&(locale=inheritedLocale(host),resolvedLocaleCache.set(host,locale)),locale}function inheritedDirection(host){const explicit=host.getAttribute("dir")?.toLowerCase();if(explicit==="rtl"||explicit==="ltr")return explicit;const view=ownerView(host);if(view)try{const getComputedStyle=view.getComputedStyle;if(typeof getComputedStyle=="function"){const computed=getComputedStyle.call(view,host).direction;if(computed==="rtl"||computed==="ltr")return computed}}catch{}let parent=flattenedParentElement(host);for(;parent;){const inherited=parent.getAttribute("dir")?.toLowerCase();if(inherited==="rtl"||inherited==="ltr")return inherited;parent=flattenedParentElement(parent)}return"ltr"}function resolveLyraDirection(host){if(!cacheableLocaleHosts.has(host))return inheritedDirection(host);let direction=resolvedDirectionCache.get(host);return direction===void 0&&(direction=inheritedDirection(host),resolvedDirectionCache.set(host,direction)),direction}function peekLyraLocale(host){return resolvedLocaleCache.get(host)}function peekLyraDirection(host){return resolvedDirectionCache.get(host)}const PLURAL_CATEGORY_FALLBACKS={zero:["zero","other"],one:["one","other"],two:["two","few","many","other"],few:["few","many","other"],many:["many","few","other"],other:["other"]};function pluralSelector(values){let raw;try{raw=values.pluralCount??values.count}catch{return}return typeof raw=="number"&&Number.isFinite(raw)?raw:void 0}const pluralLocaleCache=new Map,MAX_PLURAL_LOCALE_ENTRIES=64;function pluralLocale(locale){const cached=pluralLocaleCache.get(locale);if(cached!==void 0)return cached;const resolved=localeCandidates(locale)[0];return pluralLocaleCache.size>=MAX_PLURAL_LOCALE_ENTRIES&&pluralLocaleCache.clear(),pluralLocaleCache.set(locale,resolved),resolved}function selectPluralMessage(message,locale,count){if(count===void 0)return message.other;const tag=pluralLocale(locale),category=getPluralRules(tag).select(count);for(const candidate of PLURAL_CATEGORY_FALLBACKS[category]??PLURAL_CATEGORY_FALLBACKS.other){const text=message[candidate];if(text!==void 0)return text}return message.other}function isEnglishLocale(locale){const lower=locale.toLowerCase();return lower==="en"||lower.startsWith("en-")}function warnLocaleFallback(locale,key){isEnglishLocale(locale)||devWarnOnce(`lyra-locale-fallback:${locale}:${key}`,`Lyra localization: no "${key}" message registered for locale "${locale}"; falling back to the English default. Register it with registerLyraLocale(), or accept the fallback intentionally for a still-partial catalog.`)}function resolveLyraString(host,key,overrides,fallback,values,defaults){let message=safeMessageAt(overrides,key);message===void 0&&typeof fallback=="string"&&(message=fallback);let locale;if(message===void 0){locale=resolveLyraLocale(host);for(const candidate of localeCandidates(locale)){const registered=safeMessageAt(locales.get(candidate),key);if(registered!==void 0){message=registered;break}}message===void 0&&warnLocaleFallback(locale,key)}message??=safeMessageAt(defaults,key)??key;let text;return typeof message!="string"?(locale??=resolveLyraLocale(host),text=selectPluralMessage(message,locale,values?pluralSelector(values):void 0)):text=message,values?text.replace(/\{(\w+)\}/g,(match,name)=>{try{const value=values[name];return typeof value=="string"||typeof value=="number"?String(value):match}catch{return match}}):text}function resolveLocalizedParts(template,interpolate){const privateUse=new Set;for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);code>=57344&&code<=63743&&privateUse.add(code)}let marker="";for(let code=57344;code<=63743;code+=1)if(!privateUse.has(code)){marker=String.fromCharCode(code);break}if(!marker){const counts=new Uint32Array(65536);for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);counts[code]=(counts[code]??0)+1}let leastCode=0,leastCount=Number.POSITIVE_INFINITY;for(let code=0;code<counts.length;code+=1){const count=counts[code]??0;if(count===0){marker=String.fromCharCode(code);break}count<leastCount&&(leastCode=code,leastCount=count)}if(!marker){const followers=new Uint8Array(65536);for(let index=0;index+1<template.length;index+=1)template.charCodeAt(index)===leastCode&&(followers[template.charCodeAt(index+1)]=1);let follower=0;for(;follower<followers.length&&followers[follower]!==0;)follower+=1;marker=String.fromCharCode(leastCode,follower<followers.length?follower:leastCode)}}return interpolate(marker).split(marker)}export{canonicalizeLyraLocale,enableLyraLocaleCache,getLyraLocale,getLyraLocaleDirection,getRegisteredLyraLocaleKeys,getRegisteredLyraLocales,invalidateLyraLocaleCache,lyraLocaleCatalogVersion,peekLyraDirection,peekLyraLocale,recordLyraOwnerDocumentConnection,registerLyraExactLocale,registerLyraLocale,resolveLocalizedParts,resolveLyraDirection,resolveLyraLocale,resolveLyraString,setLyraLocale,snapshotLyraLocaleStrings,subscribeLyraLocale,subscribeLyraLocaleForHost,subscribeLyraLocaleRegistry};
|
|
1
|
+
import{devWarnOnce}from"./dev-mode-attribute-warning.js";import{getPluralRules}from"./intl-cache.js";const MAX_LOCALE_CANDIDATES=64,MAX_LOCALE_SUBTAGS=32,MAX_LOCALE_TAG_LENGTH=255,MAX_LOCALE_CACHE_ENTRIES=128,MAX_CACHEABLE_LOCALE_LENGTH=512,LEGACY_LOCALE_PATTERN=/^[a-z0-9]{1,32}(?:-[a-z0-9]{1,32})*$/,locales=new Map,localePublicTags=new Map,localeMeta=new Map,wellFormedLocales=new Set,exactOnlyLocales=new Set,localeCatalogRevisions=new Map,listeners=new Set,hostLocaleListeners=new Set,hostLocaleFinalizer=new FinalizationRegistry(subscription=>{hostLocaleListeners.delete(subscription)}),ownerDocumentsWithBrowsingContext=new WeakSet,registryListeners=new Set;let activeLocale="",catalogRevision=0;const localeIdentityCache=new Map,localeCandidateCache=new Map;function cacheBounded(cache,key,value){cache.size>=MAX_LOCALE_CACHE_ENTRIES&&cache.clear(),cache.set(key,value)}function subtagCountWithinBounds(tag){if(tag.length>MAX_LOCALE_TAG_LENGTH)return!1;let count=tag?1:0;for(let index=0;index<tag.length;index+=1)if(tag.charCodeAt(index)===45&&++count>MAX_LOCALE_SUBTAGS)return!1;return!0}function localeIdentity(locale){const normalized=typeof locale=="string"?locale.trim().replace(/_/g,"-"):"";if(!normalized)return{publicTag:"",lookupKey:"",wellFormed:!1,candidateBounded:!0,storable:!1};const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeIdentityCache.get(normalized):void 0;if(cached)return cached;let publicTag=normalized.toLowerCase(),wellFormed=!1;try{const canonical=Intl.getCanonicalLocales(normalized)[0];canonical&&(publicTag=canonical,wellFormed=!0)}catch{}const lookupKey=publicTag.toLowerCase(),candidateBounded=subtagCountWithinBounds(lookupKey),identity={publicTag,lookupKey,wellFormed,candidateBounded,storable:wellFormed||candidateBounded&&LEGACY_LOCALE_PATTERN.test(lookupKey)};return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeIdentityCache,normalized,identity),identity}function storedLocaleIdentity(locale,required){if(typeof locale!="string")throw new TypeError("A locale must be a string.");const identity=localeIdentity(locale);if(!identity.publicTag){if(!required)return identity;throw new TypeError("A locale is required.")}if(!identity.storable)throw new TypeError("The locale must be BCP-47 or a bounded alphanumeric custom tag.");return identity}function canonicalizeLyraLocale(locale){const identity=localeIdentity(locale);return identity.storable?identity.publicTag:"en"}function regionalFallbacks(requestedKey,limit,wellFormed){if(limit<=0||!wellFormed)return[];const separator=requestedKey.indexOf("-"),language=separator===-1?requestedKey:requestedKey.slice(0,separator);if(!language)return[];const requested=new Set(requestedKey.split("-")),score=key=>key.split("-").filter(subtag=>requested.has(subtag)).length;return[...locales.keys()].filter(key=>wellFormedLocales.has(key)&&!exactOnlyLocales.has(key)&&(key===language||key.startsWith(`${language}-`))&&!isPrefixOf(key,requestedKey)).sort((a,b)=>score(b)-score(a)||(a<b?-1:a>b?1:0)).slice(0,limit)}function isPrefixOf(key,requestedKey){return key===requestedKey||requestedKey.startsWith(`${key}-`)}function localeCandidates(locale){const identity=localeIdentity(locale),normalized=identity.lookupKey;if(!normalized)return["en"];const cached=normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH?localeCandidateCache.get(normalized):void 0;if(cached)return[...cached];const candidates=[];if((identity.wellFormed||identity.candidateBounded)&&candidates.push(normalized),identity.candidateBounded){for(let index=normalized.length-1;index>=0;index-=1)normalized.charCodeAt(index)===45&&index>0&&candidates.push(normalized.slice(0,index));const regionalBudget=Math.max(0,MAX_LOCALE_CANDIDATES-candidates.length-1);candidates.push(...regionalFallbacks(normalized,regionalBudget,identity.wellFormed))}else if(identity.wellFormed){const separator=normalized.indexOf("-");separator>0&&candidates.push(normalized.slice(0,separator))}candidates.includes("en")||candidates.push("en");const frozen=Object.freeze([...candidates]);return normalized.length<=MAX_CACHEABLE_LOCALE_LENGTH&&cacheBounded(localeCandidateCache,normalized,frozen),candidates}function lyraLocaleCatalogVersion(locale){return localeCandidates(locale).map(candidate=>localeCatalogRevisions.get(candidate)??0).join(",")}function getRegisteredLyraLocales(){const keys=new Set(["en",...localePublicTags.values()]);return Object.freeze([...keys].sort())}const NO_REGISTERED_LOCALE_KEYS=Object.freeze([]);function getRegisteredLyraLocaleKeys(locale){const identity=localeIdentity(locale);if(!identity.lookupKey)return NO_REGISTERED_LOCALE_KEYS;const catalog=locales.get(identity.lookupKey);return catalog?Object.freeze(Object.keys(catalog)):NO_REGISTERED_LOCALE_KEYS}function subscribeLyraLocaleRegistry(listener){return registryListeners.add(listener),()=>registryListeners.delete(listener)}const MAX_CATALOG_MESSAGES=4096,MAX_CATALOG_PROPERTY_READS=MAX_CATALOG_MESSAGES*2,MAX_MESSAGE_KEY_LENGTH=256,PLURAL_CATEGORIES=new Set(["zero","one","two","few","many","other"]),trustedMessageRecords=new WeakSet;function isPlainRecord(value){if(value===null||typeof value!="object"||Array.isArray(value))return!1;try{const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}catch{return!1}}function ownDataValue(record,key){try{const descriptor=Object.getOwnPropertyDescriptor(record,key);return!descriptor||!("value"in descriptor)?{found:!1}:{found:!0,value:descriptor.value}}catch{return{found:!1}}}function snapshotPluralMessage(value){if(!isPlainRecord(value))return;const snapshot=Object.create(null);let count=0;try{for(const key in value){if(++count>PLURAL_CATEGORIES.size||!PLURAL_CATEGORIES.has(key)||!Object.prototype.hasOwnProperty.call(value,key))return;const entry=ownDataValue(value,key);if(!entry.found||typeof entry.value!="string")return;snapshot[key]=entry.value}}catch{return}if(typeof snapshot.other!="string")return;const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function snapshotMessage(value){return typeof value=="string"?value:snapshotPluralMessage(value)}function snapshotCatalog(strings){const snapshot=Object.create(null);if(!isPlainRecord(strings)){const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let keys;try{keys=Reflect.ownKeys(strings).slice(0,MAX_CATALOG_PROPERTY_READS)}catch{const frozen2=Object.freeze(snapshot);return trustedMessageRecords.add(frozen2),frozen2}let count=0;for(const key of keys){if(count>=MAX_CATALOG_MESSAGES)break;if(typeof key!="string"||!key||key.length>MAX_MESSAGE_KEY_LENGTH)continue;let descriptor;try{descriptor=Reflect.getOwnPropertyDescriptor(strings,key)}catch{continue}if(!descriptor?.enumerable||!("value"in descriptor))continue;count+=1;const message=snapshotMessage(descriptor.value);message!==void 0&&(snapshot[key]=message)}const frozen=Object.freeze(snapshot);return trustedMessageRecords.add(frozen),frozen}function mergeCatalogs(current,incoming){const merged=Object.assign(Object.create(null),current??{},incoming);return Object.freeze(merged),trustedMessageRecords.add(merged),merged}function snapshotLocaleMeta(meta){if(meta===void 0)return;if(!isPlainRecord(meta))return Object.freeze({});const snapshot={},dir=ownDataValue(meta,"dir");dir.found&&(dir.value==="ltr"||dir.value==="rtl")&&(snapshot.dir=dir.value);const name=ownDataValue(meta,"name");return name.found&&typeof name.value=="string"&&(snapshot.name=name.value),Object.freeze(snapshot)}function snapshotLyraLocaleStrings(strings){return snapshotCatalog(strings)}function safeMessageAt(source,key){if(!isPlainRecord(source))return;if(trustedMessageRecords.has(source))return source[key];const entry=ownDataValue(source,key);return entry.found?snapshotMessage(entry.value):void 0}function deliverLocaleListeners(groups,operation){const errors=[];for(const group of groups)for(const listener of group)try{listener()}catch(error){errors.push(error)}if(errors.length>0)throw new AggregateError(errors,`${operation} committed, but ${errors.length} locale subscriber${errors.length===1?"":"s"} failed.`)}function localeUsesCatalog(locale,lookupKey){return localeCandidates(locale).includes(lookupKey)}function ownerView(host){try{return host.ownerDocument.defaultView}catch{return}}function recordLyraOwnerDocumentConnection(host){ownerView(host)&&ownerDocumentsWithBrowsingContext.add(host.ownerDocument)}function forgetHostLocaleSubscription(subscription){hostLocaleListeners.delete(subscription),hostLocaleFinalizer.unregister(subscription)}function liveHostLocaleSubscriptions(){const live=[];for(const subscription of[...hostLocaleListeners]){const host=subscription.host.deref();if(!host||!host.isConnected||ownerDocumentsWithBrowsingContext.has(host.ownerDocument)&&ownerView(host)===null){forgetHostLocaleSubscription(subscription);continue}live.push({host})}return live}function registerLocale(locale,strings,meta,exactOnly){const identity=storedLocaleIdentity(locale,!0),key=identity.lookupKey,incomingStrings=snapshotCatalog(strings),incomingMeta=snapshotLocaleMeta(meta),isNewLocale=!locales.has(key),candidateTopologyChanged=isNewLocale||exactOnly&&!exactOnlyLocales.has(key)||identity.wellFormed&&!wellFormedLocales.has(key);exactOnly&&exactOnlyLocales.add(key),identity.wellFormed&&wellFormedLocales.add(key),locales.set(key,mergeCatalogs(locales.get(key),incomingStrings)),localePublicTags.set(key,identity.publicTag),incomingMeta&&localeMeta.set(key,Object.freeze({...localeMeta.get(key)??{},...incomingMeta})),localeCatalogRevisions.set(key,++catalogRevision),candidateTopologyChanged&&(pluralLocaleCache.clear(),localeCandidateCache.clear());const activeSnapshot=activeLocale&&localeUsesCatalog(activeLocale,key)?[...listeners]:[],hostSnapshot=liveHostLocaleSubscriptions().filter(({host})=>localeUsesCatalog(inheritedLocale(host),key)).map(({host})=>()=>host.requestUpdate()),registrySnapshot=isNewLocale?[...registryListeners]:[];deliverLocaleListeners([activeSnapshot,hostSnapshot,registrySnapshot],`registerLyraLocale(${JSON.stringify(identity.publicTag)})`)}function registerLyraLocale(locale,strings,meta){registerLocale(locale,strings,meta,!1)}function registerLyraExactLocale(locale,strings,meta){registerLocale(locale,strings,meta,!0)}function getLyraLocaleDirection(locale){const identity=localeIdentity(locale);if(!identity.publicTag)return"ltr";for(const candidate of localeCandidates(identity.publicTag)){const declared=localeMeta.get(candidate)?.dir;if(declared)return declared}try{const resolved=new Intl.Locale(identity.publicTag);return(resolved.textInfo?.direction??resolved.getTextInfo?.().direction)==="rtl"?"rtl":"ltr"}catch{return"ltr"}}function setLyraLocale(locale){const next=storedLocaleIdentity(locale,!1).publicTag;if(activeLocale===next)return;const hostSnapshot=liveHostLocaleSubscriptions(),previousHostLocales=hostSnapshot.map(({host})=>inheritedLocale(host));activeLocale=next;const affectedHostListeners=hostSnapshot.filter(({host},index)=>inheritedLocale(host)!==previousHostLocales[index]).map(({host})=>()=>host.requestUpdate());deliverLocaleListeners([[...listeners],affectedHostListeners],`setLyraLocale(${JSON.stringify(next)})`)}function getLyraLocale(){return activeLocale}function resolveActiveOrExplicitLocale(locale){const trimmed=locale?.trim();return trimmed&&trimmed.toLowerCase()!=="auto"?locale:activeLocale||void 0}function subscribeLyraLocale(listener){return listeners.add(listener),()=>listeners.delete(listener)}function subscribeLyraLocaleForHost(host){recordLyraOwnerDocumentConnection(host);const subscription={host:new WeakRef(host)};return hostLocaleListeners.add(subscription),hostLocaleFinalizer.register(host,subscription,subscription),()=>forgetHostLocaleSubscription(subscription)}function composedParentElement(element){if(element.parentElement)return element.parentElement;const root=element.getRootNode(),candidate=root.host;return root.nodeType===11&&candidate!==null&&typeof candidate=="object"&&typeof candidate.getAttribute=="function"?candidate:null}function flattenedParentElement(element){const slot=element.assignedSlot;return slot!==null&&typeof slot=="object"&&typeof slot.getAttribute=="function"?slot:composedParentElement(element)}function inheritedLocale(host){const explicit=host.getAttribute("locale")||host.getAttribute("lang");if(explicit)return canonicalizeLyraLocale(explicit);if(host.getAttribute("lang")==="")return activeLocale||"en";const documentElement=host.ownerDocument?.documentElement;let parent=composedParentElement(host);for(;parent;){const isDocumentElement=parent===documentElement,locale=isDocumentElement?parent.getAttribute("locale"):parent.getAttribute("locale")||parent.getAttribute("lang");if(locale)return canonicalizeLyraLocale(locale);if(!isDocumentElement&&parent.getAttribute("lang")==="")return activeLocale||"en";parent=composedParentElement(parent)}if(activeLocale)return activeLocale;const documentLocale=documentElement?.getAttribute("lang");return documentLocale?canonicalizeLyraLocale(documentLocale):"en"}const cacheableLocaleHosts=new WeakSet,resolvedLocaleCache=new WeakMap,resolvedDirectionCache=new WeakMap;function enableLyraLocaleCache(host){cacheableLocaleHosts.add(host)}function invalidateLyraLocaleCache(host){resolvedLocaleCache.delete(host),resolvedDirectionCache.delete(host)}function resolveLyraLocale(host){if(!cacheableLocaleHosts.has(host))return inheritedLocale(host);let locale=resolvedLocaleCache.get(host);return locale===void 0&&(locale=inheritedLocale(host),resolvedLocaleCache.set(host,locale)),locale}function inheritedDirection(host){const explicit=host.getAttribute("dir")?.toLowerCase();if(explicit==="rtl"||explicit==="ltr")return explicit;const view=ownerView(host);if(view)try{const getComputedStyle=view.getComputedStyle;if(typeof getComputedStyle=="function"){const computed=getComputedStyle.call(view,host).direction;if(computed==="rtl"||computed==="ltr")return computed}}catch{}let parent=flattenedParentElement(host);for(;parent;){const inherited=parent.getAttribute("dir")?.toLowerCase();if(inherited==="rtl"||inherited==="ltr")return inherited;parent=flattenedParentElement(parent)}return"ltr"}function resolveLyraDirection(host){if(!cacheableLocaleHosts.has(host))return inheritedDirection(host);let direction=resolvedDirectionCache.get(host);return direction===void 0&&(direction=inheritedDirection(host),resolvedDirectionCache.set(host,direction)),direction}function peekLyraLocale(host){return resolvedLocaleCache.get(host)}function peekLyraDirection(host){return resolvedDirectionCache.get(host)}const PLURAL_CATEGORY_FALLBACKS={zero:["zero","other"],one:["one","other"],two:["two","few","many","other"],few:["few","many","other"],many:["many","few","other"],other:["other"]};function pluralSelector(values){let raw;try{raw=values.pluralCount??values.count}catch{return}return typeof raw=="number"&&Number.isFinite(raw)?raw:void 0}const pluralLocaleCache=new Map,MAX_PLURAL_LOCALE_ENTRIES=64;function pluralLocale(locale){const cached=pluralLocaleCache.get(locale);if(cached!==void 0)return cached;const resolved=localeCandidates(locale)[0];return pluralLocaleCache.size>=MAX_PLURAL_LOCALE_ENTRIES&&pluralLocaleCache.clear(),pluralLocaleCache.set(locale,resolved),resolved}function selectPluralMessage(message,locale,count){if(count===void 0)return message.other;const tag=pluralLocale(locale),category=getPluralRules(tag).select(count);for(const candidate of PLURAL_CATEGORY_FALLBACKS[category]??PLURAL_CATEGORY_FALLBACKS.other){const text=message[candidate];if(text!==void 0)return text}return message.other}function isEnglishLocale(locale){const lower=locale.toLowerCase();return lower==="en"||lower.startsWith("en-")}function warnLocaleFallback(locale,key){isEnglishLocale(locale)||devWarnOnce(`lyra-locale-fallback:${locale}:${key}`,`Lyra localization: no "${key}" message registered for locale "${locale}"; falling back to the English default. Register it with registerLyraLocale(), or accept the fallback intentionally for a still-partial catalog.`)}function resolveLyraString(host,key,overrides,fallback,values,defaults){let message=safeMessageAt(overrides,key);message===void 0&&typeof fallback=="string"&&(message=fallback);let locale;if(message===void 0){locale=resolveLyraLocale(host);for(const candidate of localeCandidates(locale)){const registered=safeMessageAt(locales.get(candidate),key);if(registered!==void 0){message=registered;break}}message===void 0&&warnLocaleFallback(locale,key)}message??=safeMessageAt(defaults,key)??key;let text;return typeof message!="string"?(locale??=resolveLyraLocale(host),text=selectPluralMessage(message,locale,values?pluralSelector(values):void 0)):text=message,values?text.replace(/\{(\w+)\}/g,(match,name)=>{try{const value=values[name];return typeof value=="string"||typeof value=="number"?String(value):match}catch{return match}}):text}function resolveLocalizedParts(template,interpolate){const privateUse=new Set;for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);code>=57344&&code<=63743&&privateUse.add(code)}let marker="";for(let code=57344;code<=63743;code+=1)if(!privateUse.has(code)){marker=String.fromCharCode(code);break}if(!marker){const counts=new Uint32Array(65536);for(let index=0;index<template.length;index+=1){const code=template.charCodeAt(index);counts[code]=(counts[code]??0)+1}let leastCode=0,leastCount=Number.POSITIVE_INFINITY;for(let code=0;code<counts.length;code+=1){const count=counts[code]??0;if(count===0){marker=String.fromCharCode(code);break}count<leastCount&&(leastCode=code,leastCount=count)}if(!marker){const followers=new Uint8Array(65536);for(let index=0;index+1<template.length;index+=1)template.charCodeAt(index)===leastCode&&(followers[template.charCodeAt(index+1)]=1);let follower=0;for(;follower<followers.length&&followers[follower]!==0;)follower+=1;marker=String.fromCharCode(leastCode,follower<followers.length?follower:leastCode)}}return interpolate(marker).split(marker)}export{canonicalizeLyraLocale,enableLyraLocaleCache,getLyraLocale,getLyraLocaleDirection,getRegisteredLyraLocaleKeys,getRegisteredLyraLocales,invalidateLyraLocaleCache,lyraLocaleCatalogVersion,peekLyraDirection,peekLyraLocale,recordLyraOwnerDocumentConnection,registerLyraExactLocale,registerLyraLocale,resolveActiveOrExplicitLocale,resolveLocalizedParts,resolveLyraDirection,resolveLyraLocale,resolveLyraString,setLyraLocale,snapshotLyraLocaleStrings,subscribeLyraLocale,subscribeLyraLocaleForHost,subscribeLyraLocaleRegistry};
|