ngwr 14.7.0 → 14.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -332
- package/alert/styles/_index.scss +10 -0
- package/avatar/styles/_index.scss +18 -7
- package/badge/styles/_index.scss +7 -0
- package/badge/styles/_tag.scss +7 -1
- package/bar-chart/styles/_index.scss +1 -0
- package/button/styles/_index.scss +6 -0
- package/calendar-heatmap/styles/_index.scss +1 -0
- package/cascader/styles/_rules.scss +87 -15
- package/checkbox/styles/_index.scss +4 -0
- package/command-palette/styles/_index.scss +1 -1
- package/date-picker/styles/_index.scss +30 -0
- package/density/styles/_index.scss +4 -2
- package/divider/styles/_index.scss +2 -0
- package/donut-chart/styles/_index.scss +10 -0
- package/dropdown/styles/_index.scss +67 -5
- package/editor/styles/_index.scss +441 -0
- package/event-calendar/styles/_index.scss +209 -35
- package/fesm2022/ngwr-action-sheet-testing.mjs.map +1 -1
- package/fesm2022/ngwr-action-sheet.mjs +3 -3
- package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
- package/fesm2022/ngwr-affix.mjs +3 -3
- package/fesm2022/ngwr-affix.mjs.map +1 -1
- package/fesm2022/ngwr-alert.mjs +3 -3
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- package/fesm2022/ngwr-anchor.mjs +3 -3
- package/fesm2022/ngwr-anchor.mjs.map +1 -1
- package/fesm2022/ngwr-aurora.mjs +3 -3
- package/fesm2022/ngwr-aurora.mjs.map +1 -1
- package/fesm2022/ngwr-avatar.mjs +3 -3
- package/fesm2022/ngwr-avatar.mjs.map +1 -1
- package/fesm2022/ngwr-back-top.mjs +3 -3
- package/fesm2022/ngwr-back-top.mjs.map +1 -1
- package/fesm2022/ngwr-badge.mjs +28 -13
- package/fesm2022/ngwr-badge.mjs.map +1 -1
- package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-bar-chart.mjs +31 -6
- package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
- package/fesm2022/ngwr-blur-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-blur-text.mjs +3 -3
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow-testing.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow.mjs +3 -3
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-burger.mjs +3 -3
- package/fesm2022/ngwr-burger.mjs.map +1 -1
- package/fesm2022/ngwr-button-testing.mjs.map +1 -1
- package/fesm2022/ngwr-button.mjs +6 -6
- package/fesm2022/ngwr-button.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap.mjs +61 -6
- package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-calendar.mjs +3 -3
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-card.mjs +9 -9
- package/fesm2022/ngwr-card.mjs.map +1 -1
- package/fesm2022/ngwr-carousel-testing.mjs.map +1 -1
- package/fesm2022/ngwr-carousel.mjs +6 -6
- package/fesm2022/ngwr-carousel.mjs.map +1 -1
- package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +4 -4
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +18 -8
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text.mjs +3 -3
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-click-spark.mjs +3 -3
- package/fesm2022/ngwr-click-spark.mjs.map +1 -1
- package/fesm2022/ngwr-clipboard.mjs +3 -3
- package/fesm2022/ngwr-clipboard.mjs.map +1 -1
- package/fesm2022/ngwr-collapse-testing.mjs.map +1 -1
- package/fesm2022/ngwr-collapse.mjs +9 -9
- package/fesm2022/ngwr-collapse.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker.mjs +6 -6
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +3 -3
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-compare.mjs +3 -3
- package/fesm2022/ngwr-compare.mjs.map +1 -1
- package/fesm2022/ngwr-confetti.mjs +3 -3
- package/fesm2022/ngwr-confetti.mjs.map +1 -1
- package/fesm2022/ngwr-config.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +12 -12
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-cookie.mjs +3 -3
- package/fesm2022/ngwr-cookie.mjs.map +1 -1
- package/fesm2022/ngwr-counter.mjs +6 -6
- package/fesm2022/ngwr-counter.mjs.map +1 -1
- package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
- package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -1
- package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
- package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker.mjs +721 -62
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/ngwr-date.mjs +3 -3
- package/fesm2022/ngwr-date.mjs.map +1 -1
- package/fesm2022/ngwr-decrypt-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-decrypt-text.mjs +3 -3
- package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
- package/fesm2022/ngwr-density.mjs +6 -6
- package/fesm2022/ngwr-density.mjs.map +1 -1
- package/fesm2022/ngwr-descriptions.mjs +6 -6
- package/fesm2022/ngwr-descriptions.mjs.map +1 -1
- package/fesm2022/ngwr-dialog-testing.mjs.map +1 -1
- package/fesm2022/ngwr-dialog.mjs +15 -15
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +12 -12
- package/fesm2022/ngwr-directives.mjs.map +1 -1
- package/fesm2022/ngwr-divider.mjs +3 -3
- package/fesm2022/ngwr-divider.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart.mjs +48 -6
- package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +6 -6
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer-testing.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +18 -18
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +174 -25
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-editor-testing.mjs +568 -0
- package/fesm2022/ngwr-editor-testing.mjs.map +1 -0
- package/fesm2022/ngwr-editor.mjs +2601 -0
- package/fesm2022/ngwr-editor.mjs.map +1 -0
- package/fesm2022/ngwr-empty.mjs +3 -3
- package/fesm2022/ngwr-empty.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar.mjs +14 -7
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text.mjs +3 -3
- package/fesm2022/ngwr-falling-text.mjs.map +1 -1
- package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -1
- package/fesm2022/ngwr-file-upload.mjs +3 -3
- package/fesm2022/ngwr-file-upload.mjs.map +1 -1
- package/fesm2022/ngwr-form-testing.mjs.map +1 -1
- package/fesm2022/ngwr-form.mjs +61 -10
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
- package/fesm2022/ngwr-gauge.mjs +35 -6
- package/fesm2022/ngwr-gauge.mjs.map +1 -1
- package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-glitch-text.mjs +3 -3
- package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text.mjs +3 -3
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
- package/fesm2022/ngwr-graph-testing.mjs.map +1 -1
- package/fesm2022/ngwr-graph.mjs +6 -6
- package/fesm2022/ngwr-graph.mjs.map +1 -1
- package/fesm2022/ngwr-hotkey.mjs +6 -6
- package/fesm2022/ngwr-hotkey.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ar.mjs +31 -0
- package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-cs.mjs +31 -0
- package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-de.mjs +31 -0
- package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +39 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-es.mjs +31 -0
- package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-fr.mjs +31 -0
- package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-he.mjs +31 -0
- package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-hi.mjs +31 -0
- package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-id.mjs +31 -0
- package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-it.mjs +31 -0
- package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ja.mjs +31 -0
- package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ko.mjs +31 -0
- package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-nl.mjs +31 -0
- package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pl.mjs +31 -0
- package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pt.mjs +31 -0
- package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +31 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-sv.mjs +31 -0
- package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-tr.mjs +31 -0
- package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-uk.mjs +31 -0
- package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-vi.mjs +31 -0
- package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh-TW.mjs +31 -0
- package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh.mjs +31 -0
- package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
- package/fesm2022/ngwr-i18n.mjs +9 -9
- package/fesm2022/ngwr-i18n.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
- package/fesm2022/ngwr-icon.mjs +6 -6
- package/fesm2022/ngwr-icon.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper.mjs +3 -3
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
- package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +15 -3
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp.mjs +3 -3
- package/fesm2022/ngwr-input-otp.mjs.map +1 -1
- package/fesm2022/ngwr-input-testing.mjs.map +1 -1
- package/fesm2022/ngwr-input.mjs +15 -15
- package/fesm2022/ngwr-input.mjs.map +1 -1
- package/fesm2022/ngwr-keyboard.mjs +3 -3
- package/fesm2022/ngwr-keyboard.mjs.map +1 -1
- package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
- package/fesm2022/ngwr-knob.mjs +3 -3
- package/fesm2022/ngwr-knob.mjs.map +1 -1
- package/fesm2022/ngwr-layout.mjs +15 -15
- package/fesm2022/ngwr-layout.mjs.map +1 -1
- package/fesm2022/ngwr-lightbox-testing.mjs.map +1 -1
- package/fesm2022/ngwr-lightbox.mjs +3 -3
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart.mjs +18 -7
- package/fesm2022/ngwr-line-chart.mjs.map +1 -1
- package/fesm2022/ngwr-list.mjs +6 -6
- package/fesm2022/ngwr-list.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar-router.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar.mjs +6 -6
- package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
- package/fesm2022/ngwr-markdown-testing.mjs.map +1 -1
- package/fesm2022/ngwr-markdown.mjs +798 -17
- package/fesm2022/ngwr-markdown.mjs.map +1 -1
- package/fesm2022/ngwr-marquee-testing.mjs.map +1 -1
- package/fesm2022/ngwr-marquee.mjs +3 -3
- package/fesm2022/ngwr-marquee.mjs.map +1 -1
- package/fesm2022/ngwr-media.mjs +3 -3
- package/fesm2022/ngwr-media.mjs.map +1 -1
- package/fesm2022/ngwr-mention-testing.mjs.map +1 -1
- package/fesm2022/ngwr-mention.mjs +6 -6
- package/fesm2022/ngwr-mention.mjs.map +1 -1
- package/fesm2022/ngwr-meta.mjs +6 -6
- package/fesm2022/ngwr-meta.mjs.map +1 -1
- package/fesm2022/ngwr-meter-group-testing.mjs +7 -3
- package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
- package/fesm2022/ngwr-meter-group.mjs +26 -6
- package/fesm2022/ngwr-meter-group.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +6 -6
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-page-header.mjs +13 -5
- package/fesm2022/ngwr-page-header.mjs.map +1 -1
- package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +3 -3
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +21 -21
- package/fesm2022/ngwr-pipes.mjs.map +1 -1
- package/fesm2022/ngwr-platform.mjs +9 -9
- package/fesm2022/ngwr-platform.mjs.map +1 -1
- package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -1
- package/fesm2022/ngwr-popconfirm.mjs +6 -6
- package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
- package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +578 -16
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-progress.mjs +3 -3
- package/fesm2022/ngwr-progress.mjs.map +1 -1
- package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
- package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
- package/fesm2022/ngwr-qr.mjs +3 -3
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-radio-testing.mjs.map +1 -1
- package/fesm2022/ngwr-radio.mjs +6 -6
- package/fesm2022/ngwr-radio.mjs.map +1 -1
- package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
- package/fesm2022/ngwr-rating.mjs +3 -3
- package/fesm2022/ngwr-rating.mjs.map +1 -1
- package/fesm2022/ngwr-result.mjs +12 -12
- package/fesm2022/ngwr-result.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text.mjs +3 -3
- package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
- package/fesm2022/ngwr-schema-form.mjs +3 -3
- package/fesm2022/ngwr-schema-form.mjs.map +1 -1
- package/fesm2022/ngwr-scroll.mjs +3 -3
- package/fesm2022/ngwr-scroll.mjs.map +1 -1
- package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
- package/fesm2022/ngwr-segmented.mjs +3 -3
- package/fesm2022/ngwr-segmented.mjs.map +1 -1
- package/fesm2022/ngwr-select-testing.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +12 -12
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +6 -6
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-sidebar.mjs +10 -3
- package/fesm2022/ngwr-sidebar.mjs.map +1 -1
- package/fesm2022/ngwr-skeleton.mjs +3 -3
- package/fesm2022/ngwr-skeleton.mjs.map +1 -1
- package/fesm2022/ngwr-slider-testing.mjs.map +1 -1
- package/fesm2022/ngwr-slider.mjs +3 -3
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline-testing.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline.mjs +84 -10
- package/fesm2022/ngwr-sparkline.mjs.map +1 -1
- package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
- package/fesm2022/ngwr-speed-dial.mjs +3 -3
- package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
- package/fesm2022/ngwr-spinner.mjs +3 -3
- package/fesm2022/ngwr-spinner.mjs.map +1 -1
- package/fesm2022/ngwr-splash-cursor-testing.mjs.map +1 -1
- package/fesm2022/ngwr-splash-cursor.mjs +3 -3
- package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
- package/fesm2022/ngwr-split-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-split-text.mjs +3 -3
- package/fesm2022/ngwr-split-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter-testing.mjs.map +1 -1
- package/fesm2022/ngwr-splitter.mjs +3 -3
- package/fesm2022/ngwr-splitter.mjs.map +1 -1
- package/fesm2022/ngwr-spotlight-card-testing.mjs.map +1 -1
- package/fesm2022/ngwr-spotlight-card.mjs +6 -6
- package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
- package/fesm2022/ngwr-squircle.mjs +6 -6
- package/fesm2022/ngwr-squircle.mjs.map +1 -1
- package/fesm2022/ngwr-star-border-testing.mjs.map +1 -1
- package/fesm2022/ngwr-star-border.mjs +3 -3
- package/fesm2022/ngwr-star-border.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +9 -9
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
- package/fesm2022/ngwr-stepper.mjs +6 -6
- package/fesm2022/ngwr-stepper.mjs.map +1 -1
- package/fesm2022/ngwr-storage.mjs +3 -3
- package/fesm2022/ngwr-storage.mjs.map +1 -1
- package/fesm2022/ngwr-switch-testing.mjs.map +1 -1
- package/fesm2022/ngwr-switch.mjs +3 -3
- package/fesm2022/ngwr-switch.mjs.map +1 -1
- package/fesm2022/ngwr-table-testing.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +18 -18
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs-router.mjs +3 -3
- package/fesm2022/ngwr-tabs-router.mjs.map +1 -1
- package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +6 -6
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-textarea-testing.mjs.map +1 -1
- package/fesm2022/ngwr-textarea.mjs +3 -3
- package/fesm2022/ngwr-textarea.mjs.map +1 -1
- package/fesm2022/ngwr-theme.mjs +3 -3
- package/fesm2022/ngwr-theme.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card.mjs +6 -6
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
- package/fesm2022/ngwr-timeline.mjs +6 -6
- package/fesm2022/ngwr-timeline.mjs.map +1 -1
- package/fesm2022/ngwr-toast-testing.mjs.map +1 -1
- package/fesm2022/ngwr-toast.mjs +9 -9
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-toolbar.mjs +10 -3
- package/fesm2022/ngwr-toolbar.mjs.map +1 -1
- package/fesm2022/ngwr-tour-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tour.mjs +6 -6
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-transfer-testing.mjs.map +1 -1
- package/fesm2022/ngwr-transfer.mjs +3 -3
- package/fesm2022/ngwr-transfer.mjs.map +1 -1
- package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tree.mjs +3 -3
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter.mjs +3 -3
- package/fesm2022/ngwr-typewriter.mjs.map +1 -1
- package/fesm2022/ngwr-typography.mjs +7 -3
- package/fesm2022/ngwr-typography.mjs.map +1 -1
- package/fesm2022/ngwr-utils.mjs.map +1 -1
- package/fesm2022/ngwr-validators.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
- package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
- package/fesm2022/ngwr-waves-testing.mjs.map +1 -1
- package/fesm2022/ngwr-waves.mjs +3 -3
- package/fesm2022/ngwr-waves.mjs.map +1 -1
- package/fesm2022/ngwr-window-testing.mjs.map +1 -1
- package/fesm2022/ngwr-window.mjs +12 -12
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/form/styles/_index.scss +16 -1
- package/gauge/styles/_index.scss +1 -0
- package/i18n/ar.json +32 -1
- package/i18n/cs.json +32 -1
- package/i18n/de.json +32 -1
- package/i18n/en.json +32 -1
- package/i18n/es.json +32 -1
- package/i18n/fr.json +32 -1
- package/i18n/he.json +32 -1
- package/i18n/hi.json +32 -1
- package/i18n/id.json +32 -1
- package/i18n/it.json +32 -1
- package/i18n/ja.json +32 -1
- package/i18n/ko.json +32 -1
- package/i18n/nl.json +32 -1
- package/i18n/pl.json +32 -1
- package/i18n/pt.json +32 -1
- package/i18n/ru.json +32 -1
- package/i18n/sv.json +32 -1
- package/i18n/tr.json +32 -1
- package/i18n/uk.json +32 -1
- package/i18n/vi.json +32 -1
- package/i18n/zh-TW.json +32 -1
- package/i18n/zh.json +32 -1
- package/input/styles/_index.scss +24 -1
- package/input-number/styles/_index.scss +69 -0
- package/input-otp/styles/_index.scss +5 -5
- package/line-chart/styles/_index.scss +30 -2
- package/llms-full.txt +14 -4
- package/llms.txt +188 -132
- package/mcp/providers.js +2 -2
- package/mcp/server.js +1 -1
- package/meter-group/styles/_index.scss +1 -0
- package/overlay/styles/_arrow.scss +30 -2
- package/package.json +43 -2
- package/page-header/styles/_index.scss +37 -1
- package/pagination/styles/_index.scss +9 -5
- package/popover/styles/_index.scss +73 -5
- package/progress/styles/_index.scss +4 -0
- package/radio/styles/_index.scss +4 -1
- package/schematics/use/symbol-map.json +1 -0
- package/select/styles/_index.scss +51 -12
- package/sidebar/styles/_index.scss +44 -2
- package/skeleton/styles/_index.scss +3 -0
- package/skills/ngwr/SKILL.md +5 -5
- package/skills/ngwr/references/catalog.md +2 -0
- package/skills/ngwr/references/setup.md +3 -3
- package/sparkline/styles/_index.scss +19 -0
- package/styles.scss +1 -0
- package/table/styles/_index.scss +7 -0
- package/textarea/styles/_index.scss +12 -3
- package/theme/styles/_colors.scss +39 -13
- package/theme/styles/_contrast.scss +9 -7
- package/toast/styles/_index.scss +4 -0
- package/toolbar/styles/_index.scss +35 -1
- package/tree/styles/_index.scss +46 -7
- package/types/ngwr-badge.d.ts +22 -7
- package/types/ngwr-bar-chart.d.ts +19 -1
- package/types/ngwr-calendar-heatmap.d.ts +29 -1
- package/types/ngwr-checkbox.d.ts +2 -0
- package/types/ngwr-config.d.ts +12 -0
- package/types/ngwr-date-picker.d.ts +308 -43
- package/types/ngwr-donut-chart.d.ts +24 -1
- package/types/ngwr-dropdown.d.ts +22 -2
- package/types/ngwr-editor-testing.d.ts +378 -0
- package/types/ngwr-editor.d.ts +449 -0
- package/types/ngwr-event-calendar.d.ts +8 -0
- package/types/ngwr-form.d.ts +35 -5
- package/types/ngwr-gauge.d.ts +20 -1
- package/types/ngwr-input-number.d.ts +7 -0
- package/types/ngwr-line-chart.d.ts +9 -1
- package/types/ngwr-markdown.d.ts +61 -2
- package/types/ngwr-meter-group-testing.d.ts +3 -2
- package/types/ngwr-meter-group.d.ts +14 -1
- package/types/ngwr-page-header.d.ts +10 -2
- package/types/ngwr-popover.d.ts +154 -3
- package/types/ngwr-sidebar.d.ts +7 -0
- package/types/ngwr-sparkline.d.ts +43 -1
- package/types/ngwr-toolbar.d.ts +7 -0
- package/types/ngwr-typography.d.ts +4 -0
- package/types/ngwr-version.d.ts +1 -1
- package/typography/styles/_index.scss +16 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-circular-text.mjs","sources":["../../../projects/lib/circular-text/circular-text.ts","../../../projects/lib/circular-text/circular-text.html","../../../projects/lib/circular-text/ngwr-circular-text.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the CircularText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/circular-text\n *\n * Reactbits drives the rotation with `motion/react`, which lets the spin\n * angle persist across speed changes. CSS keyframes can't do that — when\n * `animation-duration` changes mid-flight, the browser recomputes the\n * progress as `(elapsed % newDuration) / newDuration`, which visibly\n * jumps the rotation. So this port drives the rotation through the\n * Web Animations API and preserves the current angle when hover swaps\n * the duration. Bonkers `scale` is still CSS-driven (no conflict — the\n * rotation lives on an inner wrapper).\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n type ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrCircularTextHover } from './interfaces';\n\ninterface Char {\n readonly ch: string;\n readonly transform: string;\n}\n\n/**\n * Text laid out around a circle, with the whole circle spinning. Hover\n * behaviour swaps the spin rate (or pauses it) — the current rotation\n * angle is preserved across the swap so there's no visible jump.\n *\n * @example\n * ```html\n * <wr-circular-text text=\"HELLO * NGWR * \" />\n * <wr-circular-text text=\"GO BONKERS\" onHover=\"goBonkers\" [spinDuration]=\"12\" />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/circular-text\n */\n@Component({\n selector: 'wr-circular-text',\n templateUrl: './circular-text.html',\n styleUrl: './circular-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-circular-text',\n '[class.wr-circular-text--bonkers]': \"onHover() === 'goBonkers'\",\n },\n})\nexport class WrCircularText {\n /** Text to lay out around the circle. */\n readonly text = input.required<string>();\n\n /** Seconds per full revolution at rest. @default 20 */\n readonly spinDuration = input(20, { transform: numAttr(20) });\n\n /** Hover behaviour. `null` disables hover reactivity. @default 'speedUp' */\n readonly onHover = input<WrCircularTextHover>('speedUp');\n\n protected readonly chars = computed<readonly Char[]>(() => {\n const letters = Array.from(this.text());\n const len = letters.length;\n if (len === 0) return [];\n return letters.map((ch, i) => {\n const rotation = (360 / len) * i;\n // Rotate around the spinner's centre, then push each char outward\n // by the orbit radius (set via CSS var). All chars end up on a\n // circle of constant radius — not a diagonal line.\n const transform = `rotate(${rotation}deg) translateY(calc(-1 * var(--wr-circular-text-radius)))`;\n return { ch, transform };\n });\n });\n\n private readonly spinEl = viewChild.required<ElementRef<HTMLElement>>('spin');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n private rotation: Animation | null = null;\n private hovered = false;\n\n /**\n * The effect below reaches `startOrSwap()` through a `queueMicrotask`, so the\n * ring can be destroyed between the two. Without this flag the continuation\n * then starts an infinite Web Animation on a host Angular has already\n * detached — and an animation keeps its target alive, so the whole `#spin`\n * subtree is retained for the life of the page. Same hazard, and same flag, as\n * `wr-split-text` and `wr-fuzzy-text`.\n */\n private destroyed = false;\n\n /** Active spin duration in seconds — base, or hover-modified. */\n private effectiveDuration(): number | 'pause' {\n const base = this.spinDuration();\n if (!this.hovered) return base;\n switch (this.onHover()) {\n case 'speedUp':\n return base / 4;\n case 'slowDown':\n return base * 2;\n case 'pause':\n return 'pause';\n case 'goBonkers':\n return base / 20;\n default:\n return base;\n }\n }\n\n constructor() {\n if (!this.isBrowser) return;\n\n // Component-scoped, NOT inside the render hook below: `startOrSwap()` is\n // reachable from the effect's microtask, which can create the animation\n // before that hook has run — and a cleanup registered inside a callback that\n // never ran is not registered at all. The listeners stay paired with the\n // element they are added to.\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.rotation?.cancel();\n });\n\n afterNextRender(() => {\n this.startOrSwap();\n\n const host = this.spinEl().nativeElement.parentElement!;\n const onEnter = (): void => {\n this.hovered = true;\n this.startOrSwap();\n };\n const onLeave = (): void => {\n this.hovered = false;\n this.startOrSwap();\n };\n host.addEventListener('mouseenter', onEnter);\n host.addEventListener('mouseleave', onLeave);\n this.destroyRef.onDestroy(() => {\n host.removeEventListener('mouseenter', onEnter);\n host.removeEventListener('mouseleave', onLeave);\n });\n });\n\n // React to input changes (spinDuration, onHover) — and the OS\n // reduced-motion setting — without losing angle.\n effect(() => {\n this.spinDuration();\n this.onHover();\n this.platform.prefersReducedMotion();\n queueMicrotask(() => this.startOrSwap());\n });\n }\n\n /**\n * Start the rotation, or swap its duration while preserving the\n * current angle. If the new mode is `pause`, just pause the animation.\n */\n private startOrSwap(): void {\n if (this.destroyed) return;\n if (!this.spinEl()) return;\n\n // Reduced motion: hold the ring still — the circular layout is the\n // point of the component; only the revolution is decorative.\n if (this.platform.prefersReducedMotion()) {\n this.rotation?.pause();\n return;\n }\n\n const target = this.effectiveDuration();\n\n if (target === 'pause') {\n this.rotation?.pause();\n return;\n }\n\n const newDurMs = Math.max(1, target * 1000);\n\n // First start — no previous animation to preserve.\n if (!this.rotation) {\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n return;\n }\n\n // Compute the current angle (0..1 of a full turn) under the old\n // timing, then restart with the new duration seeked to the same\n // angle — keeps the visual continuous across speed changes.\n const oldEffect = this.rotation.effect as KeyframeEffect | null;\n const oldDurMs = (oldEffect?.getTiming().duration as number) || newDurMs || newDurMs;\n const oldTime = (this.rotation.currentTime as number) ?? 0;\n const ratio = (((oldTime % oldDurMs) + oldDurMs) % oldDurMs) / oldDurMs;\n\n this.rotation.cancel();\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n this.rotation.currentTime = ratio * newDurMs;\n }\n}\n\nexport type { WrCircularTextHover } from './interfaces';\n","<!--\n The readable text, once: the ring below is per-character spans, which a screen\n reader may read out one letter at a time. Same shape as `wr-blur-text` and\n `wr-decrypt-text` — the string is carried here and the pieces are taken out of\n the tree with one `aria-hidden` on the wrapper rather than N on the chars, so\n the attribute stays off the nodes the rotation touches. It sits OUTSIDE\n `__spin`, or it would be hidden with the chars and would spin with them.\n-->\n<span class=\"wr-circular-text__sr-only\">{{ text() }}</span>\n<span class=\"wr-circular-text__spin\" aria-hidden=\"true\" #spin>\n @for (c of chars(); track $index) {\n <span class=\"wr-circular-text__char\" [style.transform]=\"c.transform\">{{ c.ch }}</span>\n }\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;AAiBG;AA2BH;;;;;;;;;;;;AAYG;MAWU,cAAc,CAAA;;IAEhB,IAAI,GAAG,KAAK,CAAC,QAAQ;6EAAU;;AAG/B,IAAA,YAAY,GAAG,KAAK,CAAC,EAAE,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,cAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,EAAA,CAAG;;IAGpD,OAAO,GAAG,KAAK,CAAsB,SAAS;gFAAC;AAErC,IAAA,KAAK,GAAG,QAAQ,CAAkB,MAAK;QACxD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACvC,QAAA,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM;QAC1B,IAAI,GAAG,KAAK,CAAC;AAAE,YAAA,OAAO,EAAE;QACxB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,KAAI;YAC3B,MAAM,QAAQ,GAAG,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;;;;AAIhC,YAAA,MAAM,SAAS,GAAG,CAAA,OAAA,EAAU,QAAQ,4DAA4D;AAChG,YAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE;AAC1B,QAAA,CAAC,CAAC;IACJ,CAAC;8EAAC;AAEe,IAAA,MAAM,GAAG,SAAS,CAAC,QAAQ,CAA0B,MAAM;+EAAC;AAE5D,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAC/B,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AAClD,IAAA,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC;IACtC,QAAQ,GAAqB,IAAI;IACjC,OAAO,GAAG,KAAK;AAEvB;;;;;;;AAOG;IACK,SAAS,GAAG,KAAK;;IAGjB,iBAAiB,GAAA;AACvB,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE;QAChC,IAAI,CAAC,IAAI,CAAC,OAAO;AAAE,YAAA,OAAO,IAAI;AAC9B,QAAA,QAAQ,IAAI,CAAC,OAAO,EAAE;AACpB,YAAA,KAAK,SAAS;gBACZ,OAAO,IAAI,GAAG,CAAC;AACjB,YAAA,KAAK,UAAU;gBACb,OAAO,IAAI,GAAG,CAAC;AACjB,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,OAAO;AAChB,YAAA,KAAK,WAAW;gBACd,OAAO,IAAI,GAAG,EAAE;AAClB,YAAA;AACE,gBAAA,OAAO,IAAI;;IAEjB;AAEA,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE;;;;;;AAOrB,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;AAC7B,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACrB,YAAA,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE;AACzB,QAAA,CAAC,CAAC;QAEF,eAAe,CAAC,MAAK;YACnB,IAAI,CAAC,WAAW,EAAE;YAElB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,aAAc;YACvD,MAAM,OAAO,GAAG,MAAW;AACzB,gBAAA,IAAI,CAAC,OAAO,GAAG,IAAI;gBACnB,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,CAAC;YACD,MAAM,OAAO,GAAG,MAAW;AACzB,gBAAA,IAAI,CAAC,OAAO,GAAG,KAAK;gBACpB,IAAI,CAAC,WAAW,EAAE;AACpB,YAAA,CAAC;AACD,YAAA,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC5C,YAAA,IAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC5C,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;AAC7B,gBAAA,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC;AAC/C,gBAAA,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,OAAO,CAAC;AACjD,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;;;QAIF,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,YAAY,EAAE;YACnB,IAAI,CAAC,OAAO,EAAE;AACd,YAAA,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE;YACpC,cAAc,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;AAC1C,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;IACK,WAAW,GAAA;QACjB,IAAI,IAAI,CAAC,SAAS;YAAE;AACpB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE;;;AAIpB,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,EAAE;AACxC,YAAA,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE;YACtB;QACF;AAEA,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE;AAEvC,QAAA,IAAI,MAAM,KAAK,OAAO,EAAE;AACtB,YAAA,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE;YACtB;QACF;AAEA,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;;AAG3C,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,OAAO,CACjD,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,EAChE,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAC/D;YACD;QACF;;;;AAKA,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,MAA+B;AAC/D,QAAA,MAAM,QAAQ,GAAI,SAAS,EAAE,SAAS,EAAE,CAAC,QAAmB,IAAI,QAAQ,IAAI,QAAQ;QACpF,MAAM,OAAO,GAAI,IAAI,CAAC,QAAQ,CAAC,WAAsB,IAAI,CAAC;AAC1D,QAAA,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,QAAQ,IAAI,QAAQ,IAAI,QAAQ,IAAI,QAAQ;AAEvE,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;AACtB,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,aAAa,CAAC,OAAO,CACjD,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,EAChE,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAC/D;QACD,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,KAAK,GAAG,QAAQ;IAC9C;uGAtJW,cAAc,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,cAAc,qsBCnE3B,owBAcA,EAAA,MAAA,EAAA,CAAA,6vBAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDqDa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAV1B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,aAAA,EAGb,iBAAiB,CAAC,IAAI,EAAA,IAAA,EAC/B;AACJ,wBAAA,KAAK,EAAE,kBAAkB;AACzB,wBAAA,mCAAmC,EAAE,2BAA2B;AACjE,qBAAA,EAAA,QAAA,EAAA,owBAAA,EAAA,MAAA,EAAA,CAAA,6vBAAA,CAAA,EAAA;2XA0BqE,MAAM,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AE3F9E;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngwr-circular-text.mjs","sources":["../../../projects/lib/circular-text/circular-text.ts","../../../projects/lib/circular-text/circular-text.html","../../../projects/lib/circular-text/ngwr-circular-text.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the CircularText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/circular-text\n *\n * Reactbits drives the rotation with `motion/react`, which lets the spin\n * angle persist across speed changes. CSS keyframes can't do that — when\n * `animation-duration` changes mid-flight, the browser recomputes the\n * progress as `(elapsed % newDuration) / newDuration`, which visibly\n * jumps the rotation. So this port drives the rotation through the\n * Web Animations API and preserves the current angle when hover swaps\n * the duration. Bonkers `scale` is still CSS-driven (no conflict — the\n * rotation lives on an inner wrapper).\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n type ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrCircularTextHover } from './interfaces';\n\ninterface Char {\n readonly ch: string;\n readonly transform: string;\n}\n\n/**\n * Text laid out around a circle, with the whole circle spinning. Hover\n * behaviour swaps the spin rate (or pauses it) — the current rotation\n * angle is preserved across the swap so there's no visible jump.\n *\n * @example\n * ```html\n * <wr-circular-text text=\"HELLO * NGWR * \" />\n * <wr-circular-text text=\"GO BONKERS\" onHover=\"goBonkers\" [spinDuration]=\"12\" />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/circular-text\n */\n@Component({\n selector: 'wr-circular-text',\n templateUrl: './circular-text.html',\n styleUrl: './circular-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-circular-text',\n '[class.wr-circular-text--bonkers]': \"onHover() === 'goBonkers'\",\n },\n})\nexport class WrCircularText {\n /** Text to lay out around the circle. */\n readonly text = input.required<string>();\n\n /** Seconds per full revolution at rest. @default 20 */\n readonly spinDuration = input(20, { transform: numAttr(20) });\n\n /** Hover behaviour. `null` disables hover reactivity. @default 'speedUp' */\n readonly onHover = input<WrCircularTextHover>('speedUp');\n\n protected readonly chars = computed<readonly Char[]>(() => {\n const letters = Array.from(this.text());\n const len = letters.length;\n if (len === 0) return [];\n return letters.map((ch, i) => {\n const rotation = (360 / len) * i;\n // Rotate around the spinner's centre, then push each char outward\n // by the orbit radius (set via CSS var). All chars end up on a\n // circle of constant radius — not a diagonal line.\n const transform = `rotate(${rotation}deg) translateY(calc(-1 * var(--wr-circular-text-radius)))`;\n return { ch, transform };\n });\n });\n\n private readonly spinEl = viewChild.required<ElementRef<HTMLElement>>('spin');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n private rotation: Animation | null = null;\n private hovered = false;\n\n /**\n * The effect below reaches `startOrSwap()` through a `queueMicrotask`, so the\n * ring can be destroyed between the two. Without this flag the continuation\n * then starts an infinite Web Animation on a host Angular has already\n * detached — and an animation keeps its target alive, so the whole `#spin`\n * subtree is retained for the life of the page. Same hazard, and same flag, as\n * `wr-split-text` and `wr-fuzzy-text`.\n */\n private destroyed = false;\n\n /** Active spin duration in seconds — base, or hover-modified. */\n private effectiveDuration(): number | 'pause' {\n const base = this.spinDuration();\n if (!this.hovered) return base;\n switch (this.onHover()) {\n case 'speedUp':\n return base / 4;\n case 'slowDown':\n return base * 2;\n case 'pause':\n return 'pause';\n case 'goBonkers':\n return base / 20;\n default:\n return base;\n }\n }\n\n constructor() {\n if (!this.isBrowser) return;\n\n // Component-scoped, NOT inside the render hook below: `startOrSwap()` is\n // reachable from the effect's microtask, which can create the animation\n // before that hook has run — and a cleanup registered inside a callback that\n // never ran is not registered at all. The listeners stay paired with the\n // element they are added to.\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.rotation?.cancel();\n });\n\n afterNextRender(() => {\n this.startOrSwap();\n\n const host = this.spinEl().nativeElement.parentElement!;\n const onEnter = (): void => {\n this.hovered = true;\n this.startOrSwap();\n };\n const onLeave = (): void => {\n this.hovered = false;\n this.startOrSwap();\n };\n host.addEventListener('mouseenter', onEnter);\n host.addEventListener('mouseleave', onLeave);\n this.destroyRef.onDestroy(() => {\n host.removeEventListener('mouseenter', onEnter);\n host.removeEventListener('mouseleave', onLeave);\n });\n });\n\n // React to input changes (spinDuration, onHover) — and the OS\n // reduced-motion setting — without losing angle.\n effect(() => {\n this.spinDuration();\n this.onHover();\n this.platform.prefersReducedMotion();\n queueMicrotask(() => this.startOrSwap());\n });\n }\n\n /**\n * Start the rotation, or swap its duration while preserving the\n * current angle. If the new mode is `pause`, just pause the animation.\n */\n private startOrSwap(): void {\n if (this.destroyed) return;\n if (!this.spinEl()) return;\n\n // Reduced motion: hold the ring still — the circular layout is the\n // point of the component; only the revolution is decorative.\n if (this.platform.prefersReducedMotion()) {\n this.rotation?.pause();\n return;\n }\n\n const target = this.effectiveDuration();\n\n if (target === 'pause') {\n this.rotation?.pause();\n return;\n }\n\n const newDurMs = Math.max(1, target * 1000);\n\n // First start — no previous animation to preserve.\n if (!this.rotation) {\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n return;\n }\n\n // Compute the current angle (0..1 of a full turn) under the old\n // timing, then restart with the new duration seeked to the same\n // angle — keeps the visual continuous across speed changes.\n const oldEffect = this.rotation.effect as KeyframeEffect | null;\n const oldDurMs = (oldEffect?.getTiming().duration as number) || newDurMs || newDurMs;\n const oldTime = (this.rotation.currentTime as number) ?? 0;\n const ratio = (((oldTime % oldDurMs) + oldDurMs) % oldDurMs) / oldDurMs;\n\n this.rotation.cancel();\n this.rotation = this.spinEl().nativeElement.animate(\n [{ transform: 'rotate(0deg)' }, { transform: 'rotate(360deg)' }],\n { duration: newDurMs, iterations: Infinity, easing: 'linear' }\n );\n this.rotation.currentTime = ratio * newDurMs;\n }\n}\n\nexport type { WrCircularTextHover } from './interfaces';\n","<!--\n The readable text, once: the ring below is per-character spans, which a screen\n reader may read out one letter at a time. Same shape as `wr-blur-text` and\n `wr-decrypt-text` — the string is carried here and the pieces are taken out of\n the tree with one `aria-hidden` on the wrapper rather than N on the chars, so\n the attribute stays off the nodes the rotation touches. It sits OUTSIDE\n `__spin`, or it would be hidden with the chars and would spin with them.\n-->\n<span class=\"wr-circular-text__sr-only\">{{ text() }}</span>\n<span class=\"wr-circular-text__spin\" aria-hidden=\"true\" #spin>\n @for (c of chars(); track $index) {\n <span class=\"wr-circular-text__char\" [style.transform]=\"c.transform\">{{ c.ch }}</span>\n }\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -184,10 +184,10 @@ class WrClickSpark {
|
|
|
184
184
|
this.raf = requestAnimationFrame(draw);
|
|
185
185
|
this.destroyRef.onDestroy(() => cancelAnimationFrame(this.raf));
|
|
186
186
|
}
|
|
187
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
188
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.
|
|
187
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrClickSpark, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
188
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.7", type: WrClickSpark, isStandalone: true, selector: "wr-click-spark", inputs: { sparkColor: { classPropertyName: "sparkColor", publicName: "sparkColor", isSignal: true, isRequired: false, transformFunction: null }, sparkSize: { classPropertyName: "sparkSize", publicName: "sparkSize", isSignal: true, isRequired: false, transformFunction: null }, sparkRadius: { classPropertyName: "sparkRadius", publicName: "sparkRadius", isSignal: true, isRequired: false, transformFunction: null }, sparkCount: { classPropertyName: "sparkCount", publicName: "sparkCount", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, easing: { classPropertyName: "easing", publicName: "easing", isSignal: true, isRequired: false, transformFunction: null }, extraScale: { classPropertyName: "extraScale", publicName: "extraScale", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick($event)" }, classAttribute: "wr-click-spark" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- Decoration over the projected content \u2014 the same treatment `WrConfetti`\n gives its own canvas. -->\n<canvas #canvas class=\"wr-click-spark__canvas\" aria-hidden=\"true\"></canvas>\n<ng-content />\n", styles: [".wr-click-spark{position:relative;display:block}.wr-click-spark__canvas{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;user-select:none;z-index:1}\n"], encapsulation: i0.ViewEncapsulation.None });
|
|
189
189
|
}
|
|
190
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrClickSpark, decorators: [{
|
|
191
191
|
type: Component,
|
|
192
192
|
args: [{ selector: 'wr-click-spark', encapsulation: ViewEncapsulation.None, host: {
|
|
193
193
|
class: 'wr-click-spark',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-click-spark.mjs","sources":["../../../projects/lib/click-spark/click-spark.ts","../../../projects/lib/click-spark/click-spark.html","../../../projects/lib/click-spark/ngwr-click-spark.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the ClickSpark effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/animations/click-spark\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrClickSparkEasing } from './interfaces';\n\ninterface Spark {\n readonly x: number;\n readonly y: number;\n readonly angle: number;\n readonly startTime: number;\n}\n\nconst EASINGS: Readonly<Record<WrClickSparkEasing, (t: number) => number>> = {\n linear: t => t,\n 'ease-in': t => t * t,\n 'ease-in-out': t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\n 'ease-out': t => t * (2 - t),\n};\n\n/**\n * Click ripple — bursts a ring of short line sparks from the click point\n * across any projected content. Wraps children in a positioned container\n * with a `pointer-events: none` canvas overlay, so projected DOM stays\n * fully interactive.\n *\n * @example\n * ```html\n * <wr-click-spark>\n * <h1>Click anywhere</h1>\n * <button>Buttons still work</button>\n * </wr-click-spark>\n * ```\n *\n * @see https://www.reactbits.dev/animations/click-spark\n */\n@Component({\n selector: 'wr-click-spark',\n templateUrl: './click-spark.html',\n styleUrl: './click-spark.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-click-spark',\n '(click)': 'onClick($event)',\n },\n})\nexport class WrClickSpark {\n /**\n * Spark line colour. Accepts any CSS colour, or a `var(--wr-…)` token which is\n * resolved against the host so it tracks the theme. The default flips with the\n * theme — dark sparks in light mode, light sparks in dark.\n * @default 'var(--wr-color-dark)'\n */\n readonly sparkColor = input('var(--wr-color-dark)');\n\n /** Length of each spark line in pixels (at t=0; tapers to 0 at t=1). @default 10 */\n readonly sparkSize = input(10, { transform: numAttr(10) });\n\n /** Distance each spark travels from origin in pixels. @default 15 */\n readonly sparkRadius = input(15, { transform: numAttr(15) });\n\n /** Number of sparks per click (evenly distributed around the circle). @default 8 */\n readonly sparkCount = input(8, { transform: numAttr(8) });\n\n /** Animation duration in ms. @default 400 */\n readonly duration = input(400, { transform: numAttr(400) });\n\n /** Easing function applied to the travel distance. @default 'ease-out' */\n readonly easing = input<WrClickSparkEasing>('ease-out');\n\n /** Multiplier on the travel distance — bumps the radius without changing `sparkRadius`. @default 1 */\n readonly extraScale = input(1, { transform: numAttr(1) });\n\n private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private sparks: Spark[] = [];\n\n /** Pending frame id, or `0` while the loop is parked. `cancelAnimationFrame(0)` is a no-op. */\n private raf = 0;\n\n /** The frame callback, once a context was obtained. `null` means there is no loop to wake. */\n private drawFrame: FrameRequestCallback | null = null;\n\n constructor() {\n if (!this.isBrowser) return;\n afterNextRender(() => {\n this.syncCanvasSize();\n this.watchResize();\n this.startLoop();\n });\n }\n\n protected onClick(event: MouseEvent): void {\n // Reduced motion: no spark bursts — same policy as wr-confetti.\n if (this.platform.prefersReducedMotion()) return;\n const canvas = this.canvasRef().nativeElement;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const now = performance.now();\n const count = this.sparkCount();\n for (let i = 0; i < count; i++) {\n this.sparks.push({ x, y, angle: (2 * Math.PI * i) / count, startTime: now });\n }\n // The loop parks itself once the last spark retires, so a burst has to wake\n // it — same shape as `WrConfetti.fire()`.\n if (this.drawFrame && !this.raf) this.raf = requestAnimationFrame(this.drawFrame);\n }\n\n // Internals\n\n /**\n * Canvas `strokeStyle` can't read CSS custom properties, so a `var(--wr-…)`\n * token is resolved against the host's computed style here. Plain colours\n * pass through untouched. Falls back to a dark literal if the custom\n * property resolves to nothing.\n */\n private resolveColor(): string {\n const color = this.sparkColor();\n const match = /^var\\((--[\\w-]+)\\)$/.exec(color.trim());\n if (!match) return color;\n const resolved = getComputedStyle(this.host.nativeElement).getPropertyValue(match[1]).trim();\n return resolved || '#0f172a';\n }\n\n private syncCanvasSize(): void {\n const canvas = this.canvasRef().nativeElement;\n const host = this.host.nativeElement;\n const { width, height } = host.getBoundingClientRect();\n if (canvas.width !== Math.round(width)) canvas.width = Math.round(width);\n if (canvas.height !== Math.round(height)) canvas.height = Math.round(height);\n }\n\n private watchResize(): void {\n if (typeof ResizeObserver === 'undefined') return;\n let resizeTimer: ReturnType<typeof setTimeout> | undefined;\n const ro = new ResizeObserver(() => {\n clearTimeout(resizeTimer);\n resizeTimer = setTimeout(() => this.syncCanvasSize(), 100);\n });\n ro.observe(this.host.nativeElement);\n this.destroyRef.onDestroy(() => {\n ro.disconnect();\n clearTimeout(resizeTimer);\n });\n }\n\n private startLoop(): void {\n const canvas = this.canvasRef().nativeElement;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const draw = (ts: number): void => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n const ease = EASINGS[this.easing()];\n const duration = this.duration();\n const sparkRadius = this.sparkRadius();\n const sparkSize = this.sparkSize();\n const extraScale = this.extraScale();\n const color = this.resolveColor();\n\n this.sparks = this.sparks.filter(spark => {\n const elapsed = ts - spark.startTime;\n if (elapsed >= duration) return false;\n const progress = elapsed / duration;\n const eased = ease(progress);\n const distance = eased * sparkRadius * extraScale;\n const lineLength = sparkSize * (1 - eased);\n\n const x1 = spark.x + distance * Math.cos(spark.angle);\n const y1 = spark.y + distance * Math.sin(spark.angle);\n const x2 = spark.x + (distance + lineLength) * Math.cos(spark.angle);\n const y2 = spark.y + (distance + lineLength) * Math.sin(spark.angle);\n\n ctx.strokeStyle = color;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n return true;\n });\n\n // Park with nothing left to paint, and only HERE — after the filter, and so\n // after the `clearRect` that opens the frame. The pass that retires the last\n // spark has already blanked the canvas, so a parked loop leaves nothing frozen\n // behind it. Parking matters because this component is built to wrap a page\n // region, so its canvas is as large as whatever it wraps: left running, an\n // instance nobody ever clicks — and every instance under reduced motion, where\n // `onClick` returns before pushing anything — clears that canvas and resolves\n // the colour token once a frame for its whole lifetime, with nothing to draw.\n if (this.sparks.length === 0) {\n this.raf = 0;\n return;\n }\n\n this.raf = requestAnimationFrame(draw);\n };\n\n this.drawFrame = draw;\n this.raf = requestAnimationFrame(draw);\n this.destroyRef.onDestroy(() => cancelAnimationFrame(this.raf));\n }\n}\n\nexport type { WrClickSparkEasing } from './interfaces';\n","<!-- Decoration over the projected content — the same treatment `WrConfetti`\n gives its own canvas. -->\n<canvas #canvas class=\"wr-click-spark__canvas\" aria-hidden=\"true\"></canvas>\n<ng-content />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-click-spark.mjs","sources":["../../../projects/lib/click-spark/click-spark.ts","../../../projects/lib/click-spark/click-spark.html","../../../projects/lib/click-spark/ngwr-click-spark.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the ClickSpark effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/animations/click-spark\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrClickSparkEasing } from './interfaces';\n\ninterface Spark {\n readonly x: number;\n readonly y: number;\n readonly angle: number;\n readonly startTime: number;\n}\n\nconst EASINGS: Readonly<Record<WrClickSparkEasing, (t: number) => number>> = {\n linear: t => t,\n 'ease-in': t => t * t,\n 'ease-in-out': t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\n 'ease-out': t => t * (2 - t),\n};\n\n/**\n * Click ripple — bursts a ring of short line sparks from the click point\n * across any projected content. Wraps children in a positioned container\n * with a `pointer-events: none` canvas overlay, so projected DOM stays\n * fully interactive.\n *\n * @example\n * ```html\n * <wr-click-spark>\n * <h1>Click anywhere</h1>\n * <button>Buttons still work</button>\n * </wr-click-spark>\n * ```\n *\n * @see https://www.reactbits.dev/animations/click-spark\n */\n@Component({\n selector: 'wr-click-spark',\n templateUrl: './click-spark.html',\n styleUrl: './click-spark.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-click-spark',\n '(click)': 'onClick($event)',\n },\n})\nexport class WrClickSpark {\n /**\n * Spark line colour. Accepts any CSS colour, or a `var(--wr-…)` token which is\n * resolved against the host so it tracks the theme. The default flips with the\n * theme — dark sparks in light mode, light sparks in dark.\n * @default 'var(--wr-color-dark)'\n */\n readonly sparkColor = input('var(--wr-color-dark)');\n\n /** Length of each spark line in pixels (at t=0; tapers to 0 at t=1). @default 10 */\n readonly sparkSize = input(10, { transform: numAttr(10) });\n\n /** Distance each spark travels from origin in pixels. @default 15 */\n readonly sparkRadius = input(15, { transform: numAttr(15) });\n\n /** Number of sparks per click (evenly distributed around the circle). @default 8 */\n readonly sparkCount = input(8, { transform: numAttr(8) });\n\n /** Animation duration in ms. @default 400 */\n readonly duration = input(400, { transform: numAttr(400) });\n\n /** Easing function applied to the travel distance. @default 'ease-out' */\n readonly easing = input<WrClickSparkEasing>('ease-out');\n\n /** Multiplier on the travel distance — bumps the radius without changing `sparkRadius`. @default 1 */\n readonly extraScale = input(1, { transform: numAttr(1) });\n\n private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private sparks: Spark[] = [];\n\n /** Pending frame id, or `0` while the loop is parked. `cancelAnimationFrame(0)` is a no-op. */\n private raf = 0;\n\n /** The frame callback, once a context was obtained. `null` means there is no loop to wake. */\n private drawFrame: FrameRequestCallback | null = null;\n\n constructor() {\n if (!this.isBrowser) return;\n afterNextRender(() => {\n this.syncCanvasSize();\n this.watchResize();\n this.startLoop();\n });\n }\n\n protected onClick(event: MouseEvent): void {\n // Reduced motion: no spark bursts — same policy as wr-confetti.\n if (this.platform.prefersReducedMotion()) return;\n const canvas = this.canvasRef().nativeElement;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const now = performance.now();\n const count = this.sparkCount();\n for (let i = 0; i < count; i++) {\n this.sparks.push({ x, y, angle: (2 * Math.PI * i) / count, startTime: now });\n }\n // The loop parks itself once the last spark retires, so a burst has to wake\n // it — same shape as `WrConfetti.fire()`.\n if (this.drawFrame && !this.raf) this.raf = requestAnimationFrame(this.drawFrame);\n }\n\n // Internals\n\n /**\n * Canvas `strokeStyle` can't read CSS custom properties, so a `var(--wr-…)`\n * token is resolved against the host's computed style here. Plain colours\n * pass through untouched. Falls back to a dark literal if the custom\n * property resolves to nothing.\n */\n private resolveColor(): string {\n const color = this.sparkColor();\n const match = /^var\\((--[\\w-]+)\\)$/.exec(color.trim());\n if (!match) return color;\n const resolved = getComputedStyle(this.host.nativeElement).getPropertyValue(match[1]).trim();\n return resolved || '#0f172a';\n }\n\n private syncCanvasSize(): void {\n const canvas = this.canvasRef().nativeElement;\n const host = this.host.nativeElement;\n const { width, height } = host.getBoundingClientRect();\n if (canvas.width !== Math.round(width)) canvas.width = Math.round(width);\n if (canvas.height !== Math.round(height)) canvas.height = Math.round(height);\n }\n\n private watchResize(): void {\n if (typeof ResizeObserver === 'undefined') return;\n let resizeTimer: ReturnType<typeof setTimeout> | undefined;\n const ro = new ResizeObserver(() => {\n clearTimeout(resizeTimer);\n resizeTimer = setTimeout(() => this.syncCanvasSize(), 100);\n });\n ro.observe(this.host.nativeElement);\n this.destroyRef.onDestroy(() => {\n ro.disconnect();\n clearTimeout(resizeTimer);\n });\n }\n\n private startLoop(): void {\n const canvas = this.canvasRef().nativeElement;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const draw = (ts: number): void => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n const ease = EASINGS[this.easing()];\n const duration = this.duration();\n const sparkRadius = this.sparkRadius();\n const sparkSize = this.sparkSize();\n const extraScale = this.extraScale();\n const color = this.resolveColor();\n\n this.sparks = this.sparks.filter(spark => {\n const elapsed = ts - spark.startTime;\n if (elapsed >= duration) return false;\n const progress = elapsed / duration;\n const eased = ease(progress);\n const distance = eased * sparkRadius * extraScale;\n const lineLength = sparkSize * (1 - eased);\n\n const x1 = spark.x + distance * Math.cos(spark.angle);\n const y1 = spark.y + distance * Math.sin(spark.angle);\n const x2 = spark.x + (distance + lineLength) * Math.cos(spark.angle);\n const y2 = spark.y + (distance + lineLength) * Math.sin(spark.angle);\n\n ctx.strokeStyle = color;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n return true;\n });\n\n // Park with nothing left to paint, and only HERE — after the filter, and so\n // after the `clearRect` that opens the frame. The pass that retires the last\n // spark has already blanked the canvas, so a parked loop leaves nothing frozen\n // behind it. Parking matters because this component is built to wrap a page\n // region, so its canvas is as large as whatever it wraps: left running, an\n // instance nobody ever clicks — and every instance under reduced motion, where\n // `onClick` returns before pushing anything — clears that canvas and resolves\n // the colour token once a frame for its whole lifetime, with nothing to draw.\n if (this.sparks.length === 0) {\n this.raf = 0;\n return;\n }\n\n this.raf = requestAnimationFrame(draw);\n };\n\n this.drawFrame = draw;\n this.raf = requestAnimationFrame(draw);\n this.destroyRef.onDestroy(() => cancelAnimationFrame(this.raf));\n }\n}\n\nexport type { WrClickSparkEasing } from './interfaces';\n","<!-- Decoration over the projected content — the same treatment `WrConfetti`\n gives its own canvas. -->\n<canvas #canvas class=\"wr-click-spark__canvas\" aria-hidden=\"true\"></canvas>\n<ng-content />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -150,10 +150,10 @@ class WrClipboard {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
154
|
-
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
153
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrClipboard, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
154
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: WrClipboard });
|
|
155
155
|
}
|
|
156
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
156
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrClipboard, decorators: [{
|
|
157
157
|
type: Service
|
|
158
158
|
}] });
|
|
159
159
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-clipboard.mjs","sources":["../../../projects/lib/clipboard/clipboard.ts","../../../projects/lib/clipboard/ngwr-clipboard.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { DOCUMENT } from '@angular/common';\nimport { Service, inject } from '@angular/core';\n\nimport type { WrClipboardPermission } from './interfaces';\n\n/**\n * Programmatic clipboard read / write.\n *\n * - **Write** uses `navigator.clipboard.writeText` with a hidden\n * `<textarea>` + `execCommand('copy')` fallback for non-secure contexts.\n * - **Read** uses `navigator.clipboard.readText` (no fallback — older\n * browsers expose no equivalent).\n * - **Available** / **permission** check what the current browser allows\n * so UI can disable the action when it would silently no-op.\n *\n * SSR-safe: every method short-circuits when there's no `document.defaultView`.\n *\n * @example\n * ```ts\n * const clip = inject(WrClipboard);\n *\n * await clip.write('Hello'); // resolves to true on success\n * const text = await clip.read(); // string | null\n * clip.available(); // boolean\n * await clip.permission('write'); // 'granted' | 'denied' | 'prompt' | 'unsupported'\n * ```\n *\n * @see https://ngwr.dev/reference/services/clipboard\n */\n@Service()\nexport class WrClipboard {\n private readonly doc = inject(DOCUMENT);\n\n /** Is any clipboard write path available (async API or `execCommand`)? */\n available(): boolean {\n const view = this.doc.defaultView;\n if (!view) return false;\n if (view.navigator?.clipboard) return true;\n return typeof this.doc.execCommand === 'function';\n }\n\n /**\n * Write text. Resolves to `true` on success, `false` on failure (denied\n * permission, no clipboard, etc).\n */\n async write(text: string): Promise<boolean> {\n const view = this.doc.defaultView;\n if (!view) return false;\n\n try {\n if (view.navigator?.clipboard) {\n await view.navigator.clipboard.writeText(text);\n return true;\n }\n return this.legacyWrite(text);\n } catch {\n return this.legacyWrite(text);\n }\n }\n\n /**\n * Read text from the clipboard. Returns `null` when unsupported or\n * when the user denied the permission prompt.\n */\n async read(): Promise<string | null> {\n const view = this.doc.defaultView;\n if (!view?.navigator?.clipboard?.readText) return null;\n try {\n return await view.navigator.clipboard.readText();\n } catch {\n return null;\n }\n }\n\n /**\n * Report whether clipboard read / write is available and, when the\n * browser exposes it, what the user has granted.\n *\n * The answer is grounded in the actual Clipboard API capability\n * (`writeText` / `readText`), then refined by the Permissions API when\n * it can speak for the requested name. `clipboard-read` / `clipboard-write`\n * are not recognised everywhere — Firefox and Safari throw on the query —\n * so a missing or throwing Permissions API is treated as \"supported,\n * will resolve at use time\" (`'prompt'`), not `'unsupported'`. We only\n * return `'unsupported'` when the capability genuinely isn't there.\n */\n async permission(name: 'read' | 'write'): Promise<WrClipboardPermission> {\n const view = this.doc.defaultView;\n if (!view) return 'unsupported';\n\n const clipboard = view.navigator?.clipboard;\n const capable =\n name === 'write'\n ? typeof clipboard?.writeText === 'function' || typeof this.doc.execCommand === 'function'\n : typeof clipboard?.readText === 'function';\n if (!capable) return 'unsupported';\n\n // Capability exists; ask the Permissions API to refine the state when it can.\n if (typeof view.navigator?.permissions?.query !== 'function') return 'prompt';\n try {\n const status = await view.navigator.permissions.query({\n name: `clipboard-${name}` as PermissionName,\n });\n return status.state;\n } catch {\n // Name not recognised by this browser — capability is still present.\n return 'prompt';\n }\n }\n\n // Internals\n\n /**\n * Hidden-textarea + `execCommand('copy')` write. Synchronous, no permissions.\n *\n * `select()` takes focus, and the textarea is removed a moment later — so\n * without putting focus back, every copy on a non-secure origin (plain\n * `http://`, which is exactly where the async clipboard is missing) leaves\n * focus on `<body>` and the user's next Tab restarts from the top of the page.\n */\n private legacyWrite(text: string): boolean {\n const previouslyFocused = this.doc.activeElement;\n const node = this.doc.createElement('textarea');\n node.value = text;\n node.setAttribute('readonly', '');\n node.style.position = 'fixed';\n node.style.top = '0';\n node.style.left = '0';\n node.style.opacity = '0';\n node.style.pointerEvents = 'none';\n this.doc.body.appendChild(node);\n node.select();\n try {\n return this.doc.execCommand('copy');\n } catch {\n return false;\n } finally {\n this.doc.body.removeChild(node);\n // Guarded on `isConnected`: the copy handler may well have re-rendered\n // whatever was focused, and focusing a detached node throws focus away\n // just as thoroughly as not restoring it.\n if (previouslyFocused instanceof HTMLElement && previouslyFocused.isConnected) {\n previouslyFocused.focus();\n }\n }\n }\n}\n\nexport type { WrClipboardPermission } from './interfaces';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ngwr-clipboard.mjs","sources":["../../../projects/lib/clipboard/clipboard.ts","../../../projects/lib/clipboard/ngwr-clipboard.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { DOCUMENT } from '@angular/common';\nimport { Service, inject } from '@angular/core';\n\nimport type { WrClipboardPermission } from './interfaces';\n\n/**\n * Programmatic clipboard read / write.\n *\n * - **Write** uses `navigator.clipboard.writeText` with a hidden\n * `<textarea>` + `execCommand('copy')` fallback for non-secure contexts.\n * - **Read** uses `navigator.clipboard.readText` (no fallback — older\n * browsers expose no equivalent).\n * - **Available** / **permission** check what the current browser allows\n * so UI can disable the action when it would silently no-op.\n *\n * SSR-safe: every method short-circuits when there's no `document.defaultView`.\n *\n * @example\n * ```ts\n * const clip = inject(WrClipboard);\n *\n * await clip.write('Hello'); // resolves to true on success\n * const text = await clip.read(); // string | null\n * clip.available(); // boolean\n * await clip.permission('write'); // 'granted' | 'denied' | 'prompt' | 'unsupported'\n * ```\n *\n * @see https://ngwr.dev/reference/services/clipboard\n */\n@Service()\nexport class WrClipboard {\n private readonly doc = inject(DOCUMENT);\n\n /** Is any clipboard write path available (async API or `execCommand`)? */\n available(): boolean {\n const view = this.doc.defaultView;\n if (!view) return false;\n if (view.navigator?.clipboard) return true;\n return typeof this.doc.execCommand === 'function';\n }\n\n /**\n * Write text. Resolves to `true` on success, `false` on failure (denied\n * permission, no clipboard, etc).\n */\n async write(text: string): Promise<boolean> {\n const view = this.doc.defaultView;\n if (!view) return false;\n\n try {\n if (view.navigator?.clipboard) {\n await view.navigator.clipboard.writeText(text);\n return true;\n }\n return this.legacyWrite(text);\n } catch {\n return this.legacyWrite(text);\n }\n }\n\n /**\n * Read text from the clipboard. Returns `null` when unsupported or\n * when the user denied the permission prompt.\n */\n async read(): Promise<string | null> {\n const view = this.doc.defaultView;\n if (!view?.navigator?.clipboard?.readText) return null;\n try {\n return await view.navigator.clipboard.readText();\n } catch {\n return null;\n }\n }\n\n /**\n * Report whether clipboard read / write is available and, when the\n * browser exposes it, what the user has granted.\n *\n * The answer is grounded in the actual Clipboard API capability\n * (`writeText` / `readText`), then refined by the Permissions API when\n * it can speak for the requested name. `clipboard-read` / `clipboard-write`\n * are not recognised everywhere — Firefox and Safari throw on the query —\n * so a missing or throwing Permissions API is treated as \"supported,\n * will resolve at use time\" (`'prompt'`), not `'unsupported'`. We only\n * return `'unsupported'` when the capability genuinely isn't there.\n */\n async permission(name: 'read' | 'write'): Promise<WrClipboardPermission> {\n const view = this.doc.defaultView;\n if (!view) return 'unsupported';\n\n const clipboard = view.navigator?.clipboard;\n const capable =\n name === 'write'\n ? typeof clipboard?.writeText === 'function' || typeof this.doc.execCommand === 'function'\n : typeof clipboard?.readText === 'function';\n if (!capable) return 'unsupported';\n\n // Capability exists; ask the Permissions API to refine the state when it can.\n if (typeof view.navigator?.permissions?.query !== 'function') return 'prompt';\n try {\n const status = await view.navigator.permissions.query({\n name: `clipboard-${name}` as PermissionName,\n });\n return status.state;\n } catch {\n // Name not recognised by this browser — capability is still present.\n return 'prompt';\n }\n }\n\n // Internals\n\n /**\n * Hidden-textarea + `execCommand('copy')` write. Synchronous, no permissions.\n *\n * `select()` takes focus, and the textarea is removed a moment later — so\n * without putting focus back, every copy on a non-secure origin (plain\n * `http://`, which is exactly where the async clipboard is missing) leaves\n * focus on `<body>` and the user's next Tab restarts from the top of the page.\n */\n private legacyWrite(text: string): boolean {\n const previouslyFocused = this.doc.activeElement;\n const node = this.doc.createElement('textarea');\n node.value = text;\n node.setAttribute('readonly', '');\n node.style.position = 'fixed';\n node.style.top = '0';\n node.style.left = '0';\n node.style.opacity = '0';\n node.style.pointerEvents = 'none';\n this.doc.body.appendChild(node);\n node.select();\n try {\n return this.doc.execCommand('copy');\n } catch {\n return false;\n } finally {\n this.doc.body.removeChild(node);\n // Guarded on `isConnected`: the copy handler may well have re-rendered\n // whatever was focused, and focusing a detached node throws focus away\n // just as thoroughly as not restoring it.\n if (previouslyFocused instanceof HTMLElement && previouslyFocused.isConnected) {\n previouslyFocused.focus();\n }\n }\n }\n}\n\nexport type { WrClipboardPermission } from './interfaces';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-collapse-testing.mjs","sources":["../../../projects/lib/collapse/testing/wr-collapse-harness.ts","../../../projects/lib/collapse/testing/wr-collapse-group-harness.ts","../../../projects/lib/collapse/testing/ngwr-collapse-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrCollapseHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one `<wr-collapse>` — a disclosure: a header button, and the region\n * it opens. {@link WrCollapseGroupHarness} is the container several of them sit in.\n *\n * Open and closed are read from the header's `aria-expanded`, never from the panel's\n * size, and that is not merely a jsdom workaround. The body animates through\n * `grid-template-rows: 0fr → 1fr`, so a measured box answers with whatever frame the\n * transition happens to be on; a unit test has no layout at all, which makes every box\n * 0×0 and every such answer wrong in the same direction. The attribute is also the only\n * thing a screen-reader user gets — a panel that slides open without flipping it is\n * closed as far as they are concerned.\n *\n * The body stays in the DOM while the panel is closed. It has to: there would be no\n * height to animate otherwise. So its text is READABLE from a spec long before it is\n * visible on screen, which is why {@link getContentText} refuses to answer for a closed\n * panel instead of handing back invisible text, and why {@link isContentHidden} exists\n * to assert that a closed panel really is out of reach.\n *\n * The region itself is a plain `<div>` — the component gives it no `role=\"region\"` — so\n * `aria-expanded` plus `aria-controls` is the whole of the wiring, and\n * {@link isRegionBound} is how a spec checks it still points at this panel's own body.\n *\n * @example\n * ```ts\n * const loader = TestbedHarnessEnvironment.loader(fixture);\n * const shipping = await loader.getHarness(WrCollapseHarness.with({ title: 'Shipping' }));\n *\n * await shipping.open();\n * expect(await shipping.getContentText()).toContain('Ships Monday');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCollapseHarness extends ComponentHarness {\n static hostSelector = 'wr-collapse';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCollapseHarnessFilters = {}): HarnessPredicate<WrCollapseHarness> {\n return new HarnessPredicate(WrCollapseHarness, options)\n .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title))\n .addOption('open', options.open, async (harness, open) => (await harness.isOpen()) === open)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n private readonly header = this.locatorFor('button.wr-collapse__header');\n private readonly body = this.locatorFor('.wr-collapse__body');\n\n /**\n * The header text, trimmed.\n *\n * Read from `.wr-collapse__title` rather than from the header button. Reading the\n * button would return the same string today — the chevron beside the title is an\n * `<svg>`, and an `<svg>` contributes no text — but the title element is the thing that\n * holds the name, so an icon that ever grows a `<text>` node or a label, or a badge\n * added next to the title, cannot leak into it.\n */\n async getTitle(): Promise<string> {\n return (await this.locatorFor('.wr-collapse__title')()).text();\n }\n\n /**\n * Whether the panel is open, from the header's `aria-expanded`.\n *\n * The `wr-collapse--open` modifier on the host is equally public and says the same\n * thing today, but the attribute is the one a screen reader acts on: a panel that\n * looks open while announcing `false` is the bug worth catching, and reading the class\n * would agree with the animation and miss it.\n */\n async isOpen(): Promise<boolean> {\n return (await (await this.header()).getAttribute('aria-expanded')) === 'true';\n }\n\n /**\n * Whether the panel refuses interaction.\n *\n * From the header's own `disabled` property — the thing that actually turns a click\n * away, and what the CDK consults before dispatching one — rather than from the\n * `wr-collapse--disabled` modifier the host also carries. Both are public, but the\n * class is styling: a panel could lose it and still refuse every click, and what a\n * spec wants to know is whether the control is inert.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.header()).getProperty<boolean>('disabled');\n }\n\n /**\n * The id the header's `aria-controls` names, or `null` when it names nothing.\n *\n * Per-instance and generated, so a spec cannot predict it — what it can do is check\n * that two panels do not share one, and {@link isRegionBound} does the rest.\n */\n async getRegionId(): Promise<string | null> {\n return (await this.header()).getAttribute('aria-controls');\n }\n\n /**\n * Whether the header points at THIS panel's body, and at nothing else on the page.\n *\n * Both halves matter, and neither is provable from the header alone. The id is\n * resolved inside the host first, so a header naming a SIBLING panel's body — which\n * resolves perfectly well from the document and would look correctly wired — fails\n * here. Then it is counted across the document, because two bodies answering to one\n * id hand every reference to whichever comes first, and the second panel's region\n * becomes unreachable to anything that follows the reference.\n */\n async isRegionBound(): Promise<boolean> {\n const id = await this.getRegionId();\n if (id === null) return false;\n\n const own = await this.locatorForOptional(`.wr-collapse__body#${id}`)();\n if (!own) return false;\n\n const everywhere = await this.documentRootLocatorFactory().locatorForAll(`#${id}`)();\n return everywhere.length === 1;\n }\n\n /**\n * Whether the region is hidden from assistive tech AND from the keyboard.\n *\n * Two attributes, because a closed panel needs both and they cover different people:\n * `aria-hidden` keeps the content out of the screen reader's document, `inert` keeps\n * Tab from landing on a link inside a panel nobody can see. The body is never removed\n * from the DOM — the height animation needs it — so these are the only thing standing\n * between a collapsed panel and a keyboard user, and losing either is invisible on\n * screen.\n *\n * They are asserted together on purpose: this answers \"is the closed content actually\n * out of reach\", and half of it is not.\n */\n async isContentHidden(): Promise<boolean> {\n const body = await this.body();\n const hiddenFromAt = (await body.getAttribute('aria-hidden')) === 'true';\n const inert = (await body.getAttribute('inert')) !== null;\n return hiddenFromAt && inert;\n }\n\n /**\n * The text of an OPEN panel's region, trimmed.\n *\n * Throws while the panel is closed rather than answering, because the body is still in\n * the DOM and the text would come back exactly as it does when open — a spec asserting\n * it would be pinning content the user cannot see, and would keep passing if the panel\n * stopped opening at all.\n */\n async getContentText(): Promise<string> {\n if (!(await this.isOpen())) {\n throw new Error(\n `WrCollapseHarness.getContentText(): \"${await this.getTitle()}\" is closed. Its content stays in the ` +\n 'DOM while collapsed — the body has to be there for the height to animate — so reading it now would ' +\n 'assert text nobody can see. Open the panel first, or ask isContentHidden().'\n );\n }\n return (await this.locatorFor('.wr-collapse__inner')()).text();\n }\n\n /** Open the panel. An already-open one is left alone; a disabled one throws. */\n async open(): Promise<void> {\n if (await this.isOpen()) return;\n await this.toggle();\n\n if (!(await this.isOpen())) {\n throw new Error(\n `WrCollapseHarness.open(): \"${await this.getTitle()}\" did not open. A disabled panel refuses its own ` +\n 'header — the button carries `disabled`, and the component checks it again before toggling.'\n );\n }\n }\n\n /** Close the panel. An already-closed one is left alone; a disabled one throws. */\n async close(): Promise<void> {\n if (!(await this.isOpen())) return;\n await this.toggle();\n\n if (await this.isOpen()) {\n throw new Error(\n `WrCollapseHarness.close(): \"${await this.getTitle()}\" did not close. A disabled panel that was opened ` +\n 'through `[open]` cannot be closed from the page at all: the toggle refuses while `disabled` is set, ' +\n 'whichever direction the click would have gone.'\n );\n }\n }\n\n /**\n * Click the header — the panel's entire interactive surface.\n *\n * A click rather than Enter / Space, and nothing is lost by it: the header is a native\n * `<button>`, so a real keyboard activation is the BROWSER synthesising a click from\n * the key press, and jsdom synthesises none. The click is dispatched onto the header\n * itself, so it needs no coordinate and cannot miss in a test that has no layout.\n *\n * A disabled panel ignores this and stays as it was, twice over: the CDK withholds the\n * `click` from an element carrying `disabled`, and the component checks `disabled`\n * again inside its own toggle. Assert rather than assume, or reach for {@link open} /\n * {@link close}, which say so.\n */\n async toggle(): Promise<void> {\n return (await this.header()).click();\n }\n\n /**\n * Move keyboard focus to the header — the only focusable element the component itself\n * renders. Projected content can of course hold its own (which is why a closed panel is\n * `inert`), but that belongs to the consumer, not to this harness.\n */\n async focus(): Promise<void> {\n return (await this.header()).focus();\n }\n\n /** Whether the header currently holds focus. */\n async isFocused(): Promise<boolean> {\n return (await this.header()).isFocused();\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrCollapseGroupHarnessFilters, WrCollapseHarnessFilters } from './interfaces';\nimport { WrCollapseHarness } from './wr-collapse-harness';\n\n/**\n * Test harness for `<wr-collapse-group>` and `<wr-accordion>` — the container a set of\n * {@link WrCollapseHarness} panels sits in, matched in both of its element shapes.\n *\n * There is deliberately no `isAccordion()`, and the reason is worth knowing before a\n * spec goes looking for one: single-open behaviour is not written down anywhere on the\n * page. `<wr-accordion>` carries the marker class `wr-collapse-group--accordion`, but\n * `<wr-collapse-group [accordion]=\"true\">` enforces exactly the same rule and carries\n * nothing — a bound input reaches the component without touching the DOM, and even the\n * literal `accordion` attribute survives only because Angular leaves a static attribute\n * alone. So the class answers \"which element did the template use\", not \"does this group\n * close siblings\", and a harness reporting it would call the group form false. Assert the\n * BEHAVIOUR instead: open two panels and read {@link getOpenTitles} — the assertion that\n * would catch a broken accordion anyway.\n *\n * A collapse group is also not a composite widget. Every header is a native `<button>`\n * in the normal tab order, with no roving `tabindex` and no arrow-key navigation (the\n * APG lists both as optional for an accordion), so there is no \"active\" panel to tell\n * apart from the open one — {@link getFocusedTitle} is the only cursor there is.\n *\n * @example\n * ```ts\n * const settings = await loader.getHarness(WrCollapseGroupHarness.with({ panelTitle: 'Profile' }));\n *\n * await settings.openPanel({ title: 'Security' });\n * expect(await settings.getOpenTitles()).toEqual(['Security']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCollapseGroupHarness extends ComponentHarness {\n /** Both shapes the container ships in: the plain group, and the always-accordion one. */\n static hostSelector = 'wr-collapse-group, wr-accordion';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCollapseGroupHarnessFilters = {}): HarnessPredicate<WrCollapseGroupHarness> {\n return new HarnessPredicate(WrCollapseGroupHarness, options)\n .addOption('panelTitle', options.panelTitle, async (harness, title) => {\n for (const panel of await harness.getPanelTitles()) {\n if (await HarnessPredicate.stringMatches(panel, title)) return true;\n }\n return false;\n })\n .addOption('openPanelTitle', options.openPanelTitle, async (harness, title) => {\n for (const open of await harness.getOpenTitles()) {\n if (await HarnessPredicate.stringMatches(open, title)) return true;\n }\n return false;\n });\n }\n\n /**\n * The group's panels, in DOM order.\n *\n * Every `<wr-collapse>` inside the host, which includes one nested in another panel's\n * content and every panel of a nested group — the group scopes no more tightly than\n * the DOM does, and a nested accordion's children are still descendants of this one.\n */\n async getPanels(filters: WrCollapseHarnessFilters = {}): Promise<WrCollapseHarness[]> {\n return this.locatorForAll(WrCollapseHarness.with(filters))();\n }\n\n /** The header text of every panel, in DOM order. */\n async getPanelTitles(): Promise<string[]> {\n const panels = await this.getPanels();\n return Promise.all(panels.map(panel => panel.getTitle()));\n }\n\n /** The first panel matching the filters, or a failure naming the panels that exist. */\n async getPanel(filters: WrCollapseHarnessFilters): Promise<WrCollapseHarness> {\n const [panel] = await this.getPanels(filters);\n if (!panel) {\n throw new Error(\n `WrCollapseGroupHarness.getPanel(): no panel matched ${JSON.stringify(filters)}. This group holds: ` +\n `${(await this.getPanelTitles()).join(', ')}.`\n );\n }\n return panel;\n }\n\n /**\n * The panel at a 0-based position in DOM order — the other half of \"by text or by\n * index\", and the only way to address a panel whose title is not unique.\n *\n * Throws for an index past the end rather than resolving to nothing, and says how many\n * panels there are: an out-of-range index is a mistake in the spec, and a `undefined`\n * handed back would surface three lines later as a failure about something else.\n */\n async getPanelAt(index: number): Promise<WrCollapseHarness> {\n const panels = await this.getPanels();\n const panel = panels[index];\n if (!panel) {\n throw new Error(\n `WrCollapseGroupHarness.getPanelAt(): index ${index} is out of range — this group holds ` +\n `${panels.length} panel(s), so the last index is ${panels.length - 1}.`\n );\n }\n return panel;\n }\n\n /** The panels that are open, in DOM order. In accordion mode there is at most one. */\n async getOpenPanels(): Promise<WrCollapseHarness[]> {\n return this.getPanels({ open: true });\n }\n\n /**\n * The header text of every open panel, in DOM order.\n *\n * The assertion an accordion is worth pinning with: opening a second panel has to leave\n * this a list of ONE, and it reads the state from each header's `aria-expanded`, so a\n * sibling that collapsed on screen while still announcing itself open fails here.\n */\n async getOpenTitles(): Promise<string[]> {\n const open = await this.getOpenPanels();\n return Promise.all(open.map(panel => panel.getTitle()));\n }\n\n /**\n * Open the first panel matching the filters.\n *\n * In accordion mode this is also what CLOSES the siblings — the group is told by the\n * panel that opened, not by the click — so a spec that opens two panels in a row is\n * asserting the mode, and {@link getOpenTitles} is where the answer shows up. Throws\n * when nothing matched, and again when the panel refused to open (it is disabled).\n */\n async openPanel(filters: WrCollapseHarnessFilters): Promise<void> {\n await (await this.getPanel(filters)).open();\n }\n\n /** Close the first panel matching the filters. */\n async closePanel(filters: WrCollapseHarnessFilters): Promise<void> {\n await (await this.getPanel(filters)).close();\n }\n\n /**\n * Close every open panel.\n *\n * The open panels are resolved first and then closed one at a time. Every click a\n * harness makes already awaits its own change detection, so closing them concurrently\n * would work too — this reads in the order a user would click, and keeps each failure\n * attributable to the panel that caused it. A disabled panel that was opened through\n * `[open]` cannot be closed from the page and throws — the same failure\n * {@link WrCollapseHarness.close} reports, for the same reason.\n */\n async closeAll(): Promise<void> {\n for (const panel of await this.getOpenPanels()) {\n await panel.close();\n }\n }\n\n /**\n * The header text of the panel whose header holds focus, or `null` when focus is\n * elsewhere.\n *\n * Every header is its own tab stop here, so this reports where focus actually IS\n * rather than where the group would send it — there is no roving tab stop to diverge\n * from.\n */\n async getFocusedTitle(): Promise<string | null> {\n for (const panel of await this.getPanels()) {\n if (await panel.isFocused()) return panel.getTitle();\n }\n return null;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-collapse-testing.mjs","sources":["../../../projects/lib/collapse/testing/wr-collapse-harness.ts","../../../projects/lib/collapse/testing/wr-collapse-group-harness.ts","../../../projects/lib/collapse/testing/ngwr-collapse-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrCollapseHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one `<wr-collapse>` — a disclosure: a header button, and the region\n * it opens. {@link WrCollapseGroupHarness} is the container several of them sit in.\n *\n * Open and closed are read from the header's `aria-expanded`, never from the panel's\n * size, and that is not merely a jsdom workaround. The body animates through\n * `grid-template-rows: 0fr → 1fr`, so a measured box answers with whatever frame the\n * transition happens to be on; a unit test has no layout at all, which makes every box\n * 0×0 and every such answer wrong in the same direction. The attribute is also the only\n * thing a screen-reader user gets — a panel that slides open without flipping it is\n * closed as far as they are concerned.\n *\n * The body stays in the DOM while the panel is closed. It has to: there would be no\n * height to animate otherwise. So its text is READABLE from a spec long before it is\n * visible on screen, which is why {@link getContentText} refuses to answer for a closed\n * panel instead of handing back invisible text, and why {@link isContentHidden} exists\n * to assert that a closed panel really is out of reach.\n *\n * The region itself is a plain `<div>` — the component gives it no `role=\"region\"` — so\n * `aria-expanded` plus `aria-controls` is the whole of the wiring, and\n * {@link isRegionBound} is how a spec checks it still points at this panel's own body.\n *\n * @example\n * ```ts\n * const loader = TestbedHarnessEnvironment.loader(fixture);\n * const shipping = await loader.getHarness(WrCollapseHarness.with({ title: 'Shipping' }));\n *\n * await shipping.open();\n * expect(await shipping.getContentText()).toContain('Ships Monday');\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCollapseHarness extends ComponentHarness {\n static hostSelector = 'wr-collapse';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCollapseHarnessFilters = {}): HarnessPredicate<WrCollapseHarness> {\n return new HarnessPredicate(WrCollapseHarness, options)\n .addOption('title', options.title, (harness, title) => HarnessPredicate.stringMatches(harness.getTitle(), title))\n .addOption('open', options.open, async (harness, open) => (await harness.isOpen()) === open)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n private readonly header = this.locatorFor('button.wr-collapse__header');\n private readonly body = this.locatorFor('.wr-collapse__body');\n\n /**\n * The header text, trimmed.\n *\n * Read from `.wr-collapse__title` rather than from the header button. Reading the\n * button would return the same string today — the chevron beside the title is an\n * `<svg>`, and an `<svg>` contributes no text — but the title element is the thing that\n * holds the name, so an icon that ever grows a `<text>` node or a label, or a badge\n * added next to the title, cannot leak into it.\n */\n async getTitle(): Promise<string> {\n return (await this.locatorFor('.wr-collapse__title')()).text();\n }\n\n /**\n * Whether the panel is open, from the header's `aria-expanded`.\n *\n * The `wr-collapse--open` modifier on the host is equally public and says the same\n * thing today, but the attribute is the one a screen reader acts on: a panel that\n * looks open while announcing `false` is the bug worth catching, and reading the class\n * would agree with the animation and miss it.\n */\n async isOpen(): Promise<boolean> {\n return (await (await this.header()).getAttribute('aria-expanded')) === 'true';\n }\n\n /**\n * Whether the panel refuses interaction.\n *\n * From the header's own `disabled` property — the thing that actually turns a click\n * away, and what the CDK consults before dispatching one — rather than from the\n * `wr-collapse--disabled` modifier the host also carries. Both are public, but the\n * class is styling: a panel could lose it and still refuse every click, and what a\n * spec wants to know is whether the control is inert.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.header()).getProperty<boolean>('disabled');\n }\n\n /**\n * The id the header's `aria-controls` names, or `null` when it names nothing.\n *\n * Per-instance and generated, so a spec cannot predict it — what it can do is check\n * that two panels do not share one, and {@link isRegionBound} does the rest.\n */\n async getRegionId(): Promise<string | null> {\n return (await this.header()).getAttribute('aria-controls');\n }\n\n /**\n * Whether the header points at THIS panel's body, and at nothing else on the page.\n *\n * Both halves matter, and neither is provable from the header alone. The id is\n * resolved inside the host first, so a header naming a SIBLING panel's body — which\n * resolves perfectly well from the document and would look correctly wired — fails\n * here. Then it is counted across the document, because two bodies answering to one\n * id hand every reference to whichever comes first, and the second panel's region\n * becomes unreachable to anything that follows the reference.\n */\n async isRegionBound(): Promise<boolean> {\n const id = await this.getRegionId();\n if (id === null) return false;\n\n const own = await this.locatorForOptional(`.wr-collapse__body#${id}`)();\n if (!own) return false;\n\n const everywhere = await this.documentRootLocatorFactory().locatorForAll(`#${id}`)();\n return everywhere.length === 1;\n }\n\n /**\n * Whether the region is hidden from assistive tech AND from the keyboard.\n *\n * Two attributes, because a closed panel needs both and they cover different people:\n * `aria-hidden` keeps the content out of the screen reader's document, `inert` keeps\n * Tab from landing on a link inside a panel nobody can see. The body is never removed\n * from the DOM — the height animation needs it — so these are the only thing standing\n * between a collapsed panel and a keyboard user, and losing either is invisible on\n * screen.\n *\n * They are asserted together on purpose: this answers \"is the closed content actually\n * out of reach\", and half of it is not.\n */\n async isContentHidden(): Promise<boolean> {\n const body = await this.body();\n const hiddenFromAt = (await body.getAttribute('aria-hidden')) === 'true';\n const inert = (await body.getAttribute('inert')) !== null;\n return hiddenFromAt && inert;\n }\n\n /**\n * The text of an OPEN panel's region, trimmed.\n *\n * Throws while the panel is closed rather than answering, because the body is still in\n * the DOM and the text would come back exactly as it does when open — a spec asserting\n * it would be pinning content the user cannot see, and would keep passing if the panel\n * stopped opening at all.\n */\n async getContentText(): Promise<string> {\n if (!(await this.isOpen())) {\n throw new Error(\n `WrCollapseHarness.getContentText(): \"${await this.getTitle()}\" is closed. Its content stays in the ` +\n 'DOM while collapsed — the body has to be there for the height to animate — so reading it now would ' +\n 'assert text nobody can see. Open the panel first, or ask isContentHidden().'\n );\n }\n return (await this.locatorFor('.wr-collapse__inner')()).text();\n }\n\n /** Open the panel. An already-open one is left alone; a disabled one throws. */\n async open(): Promise<void> {\n if (await this.isOpen()) return;\n await this.toggle();\n\n if (!(await this.isOpen())) {\n throw new Error(\n `WrCollapseHarness.open(): \"${await this.getTitle()}\" did not open. A disabled panel refuses its own ` +\n 'header — the button carries `disabled`, and the component checks it again before toggling.'\n );\n }\n }\n\n /** Close the panel. An already-closed one is left alone; a disabled one throws. */\n async close(): Promise<void> {\n if (!(await this.isOpen())) return;\n await this.toggle();\n\n if (await this.isOpen()) {\n throw new Error(\n `WrCollapseHarness.close(): \"${await this.getTitle()}\" did not close. A disabled panel that was opened ` +\n 'through `[open]` cannot be closed from the page at all: the toggle refuses while `disabled` is set, ' +\n 'whichever direction the click would have gone.'\n );\n }\n }\n\n /**\n * Click the header — the panel's entire interactive surface.\n *\n * A click rather than Enter / Space, and nothing is lost by it: the header is a native\n * `<button>`, so a real keyboard activation is the BROWSER synthesising a click from\n * the key press, and jsdom synthesises none. The click is dispatched onto the header\n * itself, so it needs no coordinate and cannot miss in a test that has no layout.\n *\n * A disabled panel ignores this and stays as it was, twice over: the CDK withholds the\n * `click` from an element carrying `disabled`, and the component checks `disabled`\n * again inside its own toggle. Assert rather than assume, or reach for {@link open} /\n * {@link close}, which say so.\n */\n async toggle(): Promise<void> {\n return (await this.header()).click();\n }\n\n /**\n * Move keyboard focus to the header — the only focusable element the component itself\n * renders. Projected content can of course hold its own (which is why a closed panel is\n * `inert`), but that belongs to the consumer, not to this harness.\n */\n async focus(): Promise<void> {\n return (await this.header()).focus();\n }\n\n /** Whether the header currently holds focus. */\n async isFocused(): Promise<boolean> {\n return (await this.header()).isFocused();\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrCollapseGroupHarnessFilters, WrCollapseHarnessFilters } from './interfaces';\nimport { WrCollapseHarness } from './wr-collapse-harness';\n\n/**\n * Test harness for `<wr-collapse-group>` and `<wr-accordion>` — the container a set of\n * {@link WrCollapseHarness} panels sits in, matched in both of its element shapes.\n *\n * There is deliberately no `isAccordion()`, and the reason is worth knowing before a\n * spec goes looking for one: single-open behaviour is not written down anywhere on the\n * page. `<wr-accordion>` carries the marker class `wr-collapse-group--accordion`, but\n * `<wr-collapse-group [accordion]=\"true\">` enforces exactly the same rule and carries\n * nothing — a bound input reaches the component without touching the DOM, and even the\n * literal `accordion` attribute survives only because Angular leaves a static attribute\n * alone. So the class answers \"which element did the template use\", not \"does this group\n * close siblings\", and a harness reporting it would call the group form false. Assert the\n * BEHAVIOUR instead: open two panels and read {@link getOpenTitles} — the assertion that\n * would catch a broken accordion anyway.\n *\n * A collapse group is also not a composite widget. Every header is a native `<button>`\n * in the normal tab order, with no roving `tabindex` and no arrow-key navigation (the\n * APG lists both as optional for an accordion), so there is no \"active\" panel to tell\n * apart from the open one — {@link getFocusedTitle} is the only cursor there is.\n *\n * @example\n * ```ts\n * const settings = await loader.getHarness(WrCollapseGroupHarness.with({ panelTitle: 'Profile' }));\n *\n * await settings.openPanel({ title: 'Security' });\n * expect(await settings.getOpenTitles()).toEqual(['Security']);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrCollapseGroupHarness extends ComponentHarness {\n /** Both shapes the container ships in: the plain group, and the always-accordion one. */\n static hostSelector = 'wr-collapse-group, wr-accordion';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrCollapseGroupHarnessFilters = {}): HarnessPredicate<WrCollapseGroupHarness> {\n return new HarnessPredicate(WrCollapseGroupHarness, options)\n .addOption('panelTitle', options.panelTitle, async (harness, title) => {\n for (const panel of await harness.getPanelTitles()) {\n if (await HarnessPredicate.stringMatches(panel, title)) return true;\n }\n return false;\n })\n .addOption('openPanelTitle', options.openPanelTitle, async (harness, title) => {\n for (const open of await harness.getOpenTitles()) {\n if (await HarnessPredicate.stringMatches(open, title)) return true;\n }\n return false;\n });\n }\n\n /**\n * The group's panels, in DOM order.\n *\n * Every `<wr-collapse>` inside the host, which includes one nested in another panel's\n * content and every panel of a nested group — the group scopes no more tightly than\n * the DOM does, and a nested accordion's children are still descendants of this one.\n */\n async getPanels(filters: WrCollapseHarnessFilters = {}): Promise<WrCollapseHarness[]> {\n return this.locatorForAll(WrCollapseHarness.with(filters))();\n }\n\n /** The header text of every panel, in DOM order. */\n async getPanelTitles(): Promise<string[]> {\n const panels = await this.getPanels();\n return Promise.all(panels.map(panel => panel.getTitle()));\n }\n\n /** The first panel matching the filters, or a failure naming the panels that exist. */\n async getPanel(filters: WrCollapseHarnessFilters): Promise<WrCollapseHarness> {\n const [panel] = await this.getPanels(filters);\n if (!panel) {\n throw new Error(\n `WrCollapseGroupHarness.getPanel(): no panel matched ${JSON.stringify(filters)}. This group holds: ` +\n `${(await this.getPanelTitles()).join(', ')}.`\n );\n }\n return panel;\n }\n\n /**\n * The panel at a 0-based position in DOM order — the other half of \"by text or by\n * index\", and the only way to address a panel whose title is not unique.\n *\n * Throws for an index past the end rather than resolving to nothing, and says how many\n * panels there are: an out-of-range index is a mistake in the spec, and a `undefined`\n * handed back would surface three lines later as a failure about something else.\n */\n async getPanelAt(index: number): Promise<WrCollapseHarness> {\n const panels = await this.getPanels();\n const panel = panels[index];\n if (!panel) {\n throw new Error(\n `WrCollapseGroupHarness.getPanelAt(): index ${index} is out of range — this group holds ` +\n `${panels.length} panel(s), so the last index is ${panels.length - 1}.`\n );\n }\n return panel;\n }\n\n /** The panels that are open, in DOM order. In accordion mode there is at most one. */\n async getOpenPanels(): Promise<WrCollapseHarness[]> {\n return this.getPanels({ open: true });\n }\n\n /**\n * The header text of every open panel, in DOM order.\n *\n * The assertion an accordion is worth pinning with: opening a second panel has to leave\n * this a list of ONE, and it reads the state from each header's `aria-expanded`, so a\n * sibling that collapsed on screen while still announcing itself open fails here.\n */\n async getOpenTitles(): Promise<string[]> {\n const open = await this.getOpenPanels();\n return Promise.all(open.map(panel => panel.getTitle()));\n }\n\n /**\n * Open the first panel matching the filters.\n *\n * In accordion mode this is also what CLOSES the siblings — the group is told by the\n * panel that opened, not by the click — so a spec that opens two panels in a row is\n * asserting the mode, and {@link getOpenTitles} is where the answer shows up. Throws\n * when nothing matched, and again when the panel refused to open (it is disabled).\n */\n async openPanel(filters: WrCollapseHarnessFilters): Promise<void> {\n await (await this.getPanel(filters)).open();\n }\n\n /** Close the first panel matching the filters. */\n async closePanel(filters: WrCollapseHarnessFilters): Promise<void> {\n await (await this.getPanel(filters)).close();\n }\n\n /**\n * Close every open panel.\n *\n * The open panels are resolved first and then closed one at a time. Every click a\n * harness makes already awaits its own change detection, so closing them concurrently\n * would work too — this reads in the order a user would click, and keeps each failure\n * attributable to the panel that caused it. A disabled panel that was opened through\n * `[open]` cannot be closed from the page and throws — the same failure\n * {@link WrCollapseHarness.close} reports, for the same reason.\n */\n async closeAll(): Promise<void> {\n for (const panel of await this.getOpenPanels()) {\n await panel.close();\n }\n }\n\n /**\n * The header text of the panel whose header holds focus, or `null` when focus is\n * elsewhere.\n *\n * Every header is its own tab stop here, so this reports where focus actually IS\n * rather than where the group would send it — there is no roving tab stop to diverge\n * from.\n */\n async getFocusedTitle(): Promise<string | null> {\n for (const panel of await this.getPanels()) {\n if (await panel.isFocused()) return panel.getTitle();\n }\n return null;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -94,10 +94,10 @@ class WrCollapse {
|
|
|
94
94
|
return;
|
|
95
95
|
this.open.update(v => !v);
|
|
96
96
|
}
|
|
97
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
98
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
97
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCollapse, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
98
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: WrCollapse, isStandalone: true, selector: "wr-collapse", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"wr-collapse__header\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n>\n <span class=\"wr-collapse__title\">{{ title() }}</span>\n <svg\n class=\"wr-icon__svg wr-collapse__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n</button>\n\n<div\n class=\"wr-collapse__body\"\n [attr.id]=\"bodyId\"\n [class.wr-collapse__body--open]=\"open()\"\n [attr.aria-hidden]=\"!open()\"\n [attr.inert]=\"!open() ? '' : null\"\n>\n <div class=\"wr-collapse__content\">\n <div class=\"wr-collapse__inner\">\n <ng-content />\n </div>\n </div>\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
|
|
99
99
|
}
|
|
100
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
100
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCollapse, decorators: [{
|
|
101
101
|
type: Component,
|
|
102
102
|
args: [{ selector: 'wr-collapse', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<button\n type=\"button\"\n class=\"wr-collapse__header\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n>\n <span class=\"wr-collapse__title\">{{ title() }}</span>\n <svg\n class=\"wr-icon__svg wr-collapse__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n</button>\n\n<div\n class=\"wr-collapse__body\"\n [attr.id]=\"bodyId\"\n [class.wr-collapse__body--open]=\"open()\"\n [attr.aria-hidden]=\"!open()\"\n [attr.inert]=\"!open() ? '' : null\"\n>\n <div class=\"wr-collapse__content\">\n <div class=\"wr-collapse__inner\">\n <ng-content />\n </div>\n </div>\n</div>\n" }]
|
|
103
103
|
}], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
@@ -132,8 +132,8 @@ class WrCollapseGroup {
|
|
|
132
132
|
member.close();
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
136
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
135
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCollapseGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
136
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.7", type: WrCollapseGroup, isStandalone: true, selector: "wr-collapse-group", inputs: { accordion: { classPropertyName: "accordion", publicName: "accordion", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "wr-collapse-group" }, providers: [
|
|
137
137
|
{
|
|
138
138
|
provide: WR_COLLAPSE_GROUP,
|
|
139
139
|
// eslint-disable-next-line @angular-eslint/no-forward-ref
|
|
@@ -141,7 +141,7 @@ class WrCollapseGroup {
|
|
|
141
141
|
},
|
|
142
142
|
], ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
|
|
143
143
|
}
|
|
144
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
144
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrCollapseGroup, decorators: [{
|
|
145
145
|
type: Component,
|
|
146
146
|
args: [{
|
|
147
147
|
selector: 'wr-collapse-group',
|
|
@@ -198,8 +198,8 @@ class WrAccordion {
|
|
|
198
198
|
member.close();
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
202
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.
|
|
201
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrAccordion, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
202
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.7", type: WrAccordion, isStandalone: true, selector: "wr-accordion", host: { classAttribute: "wr-collapse-group wr-collapse-group--accordion" }, providers: [
|
|
203
203
|
{
|
|
204
204
|
provide: WR_COLLAPSE_GROUP,
|
|
205
205
|
// eslint-disable-next-line @angular-eslint/no-forward-ref
|
|
@@ -207,7 +207,7 @@ class WrAccordion {
|
|
|
207
207
|
},
|
|
208
208
|
], ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
|
|
209
209
|
}
|
|
210
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
210
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrAccordion, decorators: [{
|
|
211
211
|
type: Component,
|
|
212
212
|
args: [{
|
|
213
213
|
selector: 'wr-accordion',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-collapse.mjs","sources":["../../../projects/lib/collapse/tokens/collapse-group.token.ts","../../../projects/lib/collapse/collapse.ts","../../../projects/lib/collapse/collapse.html","../../../projects/lib/collapse/collapse-group.ts","../../../projects/lib/collapse/accordion.ts","../../../projects/lib/collapse/ngwr-collapse.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * What a `<wr-collapse>` hands its parent group when it registers.\n *\n * A named export rather than the structural type it used to be spelled as. Both\n * group components declared their OWN local `interface Member`, so d.ts\n * flattening had two of one name to resolve and published the second as\n * `Member$1` — a bundler-assigned identifier in the signature of a public method,\n * which no consumer could import and nobody had authored.\n */\nexport interface WrCollapseGroupMember {\n /** Close this collapse — the group calls it on siblings in accordion mode. */\n close(): void;\n /** Identity of the registering collapse, used as the map key and by `notifyOpened`. */\n readonly id: object;\n}\n\n/**\n * Contract a collapse uses to talk to its parent `<wr-collapse-group>`.\n *\n * @internal\n */\nexport interface WrCollapseGroupContext {\n /** When true, only one child collapse may be open at a time. */\n readonly accordion: Signal<boolean>;\n /** Called by a child when it opens — closes siblings in accordion mode. */\n notifyOpened(opener: object): void;\n /** Register a child so the group can call `closeAll()` etc. */\n register(member: WrCollapseGroupMember): void;\n /** Unregister on destroy. */\n unregister(memberId: object): void;\n}\n\n/**\n * Token a `<wr-collapse>` injects to register itself with — and notify of\n * open events — its parent `<wr-collapse-group>`. Drives the accordion\n * behaviour when the group has `accordion` enabled.\n *\n * @internal\n */\nexport const WR_COLLAPSE_GROUP = new InjectionToken<WrCollapseGroupContext>('WR_COLLAPSE_GROUP');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, DestroyRef, ViewEncapsulation, computed, effect, inject, input, model } from '@angular/core';\n\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_COLLAPSE_GROUP } from './tokens';\n\n/**\n * Expandable panel with a clickable header. Two-way binds the `open`\n * state. When wrapped in `<wr-collapse-group accordion>`, only one\n * sibling can be open at a time.\n *\n * @example\n * ```html\n * <wr-collapse title=\"Section title\">\n * Section body…\n * </wr-collapse>\n *\n * <wr-collapse-group accordion>\n * <wr-collapse title=\"A\">…</wr-collapse>\n * <wr-collapse title=\"B\">…</wr-collapse>\n * </wr-collapse-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse',\n templateUrl: './collapse.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCollapse {\n /** Header text. */\n readonly title = input.required<string>();\n\n /** Two-way bindable open/closed state. @default false */\n readonly open = model<boolean>(false);\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Identity used by the parent group when tracking children. @internal */\n readonly id = { name: randomId('wr-collapse') };\n\n /** DOM id for the body element, referenced by header's `aria-controls`. */\n protected readonly bodyId = `wr-collapse-body-${this.id.name}`;\n\n private readonly group = inject(WR_COLLAPSE_GROUP, { optional: true });\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-collapse'];\n if (this.open()) parts.push('wr-collapse--open');\n if (this.disabled()) parts.push('wr-collapse--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n if (this.group) {\n this.group.register({ id: this.id, close: () => this.open.set(false) });\n this.destroyRef.onDestroy(() => this.group?.unregister(this.id));\n\n // Tell the group whenever we open — group decides whether to close siblings.\n effect(() => {\n if (this.open()) this.group?.notifyOpened(this.id);\n });\n }\n }\n\n /** Open the panel. */\n openPanel(): void {\n if (this.disabled()) return;\n this.open.set(true);\n }\n\n /** Close the panel. */\n close(): void {\n this.open.set(false);\n }\n\n /** Toggle the panel. */\n toggle(): void {\n if (this.disabled()) return;\n this.open.update(v => !v);\n }\n}\n","<button\n type=\"button\"\n class=\"wr-collapse__header\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n>\n <span class=\"wr-collapse__title\">{{ title() }}</span>\n <svg\n class=\"wr-icon__svg wr-collapse__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n</button>\n\n<div\n class=\"wr-collapse__body\"\n [attr.id]=\"bodyId\"\n [class.wr-collapse__body--open]=\"open()\"\n [attr.aria-hidden]=\"!open()\"\n [attr.inert]=\"!open() ? '' : null\"\n>\n <div class=\"wr-collapse__content\">\n <div class=\"wr-collapse__inner\">\n <ng-content />\n </div>\n </div>\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, forwardRef, input } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext, type WrCollapseGroupMember } from './tokens';\n\n/**\n * Visual + behavioral grouping of `<wr-collapse>` children. When\n * `accordion` is true, opening one child closes the others.\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrCollapseGroup),\n },\n ],\n})\nexport class WrCollapseGroup implements WrCollapseGroupContext {\n /** When true, only one child may be open at a time. @default false */\n readonly accordion = input(false, { transform: coerceBooleanProperty });\n\n private readonly members = new Map<object, WrCollapseGroupMember>();\n\n register(member: WrCollapseGroupMember): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n if (!this.accordion()) return;\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, forwardRef, signal } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext, type WrCollapseGroupMember } from './tokens';\n\n/**\n * Accordion — a `<wr-collapse>` container that enforces single-open\n * behavior: opening a child closes its siblings.\n *\n * Use `<wr-collapse-group>` when you only need visual grouping without\n * the mutually-exclusive open semantics.\n *\n * @example\n * ```html\n * <wr-accordion>\n * <wr-collapse title=\"Profile\">…</wr-collapse>\n * <wr-collapse title=\"Security\">…</wr-collapse>\n * <wr-collapse title=\"Notifications\">…</wr-collapse>\n * </wr-accordion>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-accordion',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group wr-collapse-group--accordion' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrAccordion),\n },\n ],\n})\nexport class WrAccordion implements WrCollapseGroupContext {\n /** Always behaves as an accordion. Provided for context-interface symmetry. */\n readonly accordion = signal(true).asReadonly();\n\n private readonly members = new Map<object, WrCollapseGroupMember>();\n\n register(member: WrCollapseGroupMember): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;AAAA;;;;;AAKG;AAoCH;;;;;;AAMG;MACU,iBAAiB,GAAG,IAAI,cAAc,CAAyB,mBAAmB;;AChD/F;;;;;AAKG;AASH;;;;;;;;;;;;;;;;;;AAkBG;MAOU,UAAU,CAAA;;IAEZ,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAU;;IAGhC,IAAI,GAAG,KAAK,CAAU,KAAK;6EAAC;;IAG5B,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAG7D,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE;;IAG5B,MAAM,GAAG,oBAAoB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;IAE7C,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACrD,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE7B,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,KAAK,GAAG,CAAC,aAAa,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC;QAChD,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC;AACxD,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;IACxB,CAAC;gFAAC;AAEF,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;AACvE,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YAGhE,MAAM,CAAC,MAAK;gBACV,IAAI,IAAI,CAAC,IAAI,EAAE;oBAAE,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;AACpD,YAAA,CAAC,CAAC;QACJ;IACF;;IAGA,SAAS,GAAA;QACP,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACrB;;IAGA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACtB;;IAGA,MAAM,GAAA;QACJ,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3B;uGArDW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,ihBCvCvB,84BAqCA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDEa,UAAU,EAAA,UAAA,EAAA,CAAA;kBANtB,SAAS;+BACE,aAAa,EAAA,aAAA,EAER,iBAAiB,CAAC,IAAI,QAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,84BAAA,EAAA;;;AErClC;;;;;AAKG;AAOH;;;;;AAKG;MAcU,eAAe,CAAA;;IAEjB,SAAS,GAAG,KAAK,CAAC,KAAK,iFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;AAEtD,IAAA,OAAO,GAAG,IAAI,GAAG,EAAiC;AAEnE,IAAA,QAAQ,CAAC,MAA6B,EAAA;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC;AAEA,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/B;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;AACzB,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAAE;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,EAAE,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE;QACnC;IACF;uGAnBW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,SAAA,EARf;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;;AAE1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,eAAe,CAAC;AAC/C,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EATS,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAWf,eAAe,EAAA,UAAA,EAAA,CAAA;kBAb3B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE;AACpC,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;;AAE1B,4BAAA,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC;AAC/C,yBAAA;AACF,qBAAA;AACF,iBAAA;;;AC9BD;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;AAiBG;MAcU,WAAW,CAAA;;IAEb,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;AAE7B,IAAA,OAAO,GAAG,IAAI,GAAG,EAAiC;AAEnE,IAAA,QAAQ,CAAC,MAA6B,EAAA;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC;AAEA,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/B;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;QACzB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,EAAE,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE;QACnC;IACF;uGAlBW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,gDAAA,EAAA,EAAA,SAAA,EARX;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;;AAE1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,WAAW,CAAC;AAC3C,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EATS,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAWf,WAAW,EAAA,UAAA,EAAA,CAAA;kBAbvB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,cAAc;AACxB,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,gDAAgD,EAAE;AACjE,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;;AAE1B,4BAAA,WAAW,EAAE,UAAU,CAAC,iBAAiB,CAAC;AAC3C,yBAAA;AACF,qBAAA;AACF,iBAAA;;;ACzCD;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"ngwr-collapse.mjs","sources":["../../../projects/lib/collapse/tokens/collapse-group.token.ts","../../../projects/lib/collapse/collapse.ts","../../../projects/lib/collapse/collapse.html","../../../projects/lib/collapse/collapse-group.ts","../../../projects/lib/collapse/accordion.ts","../../../projects/lib/collapse/ngwr-collapse.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * What a `<wr-collapse>` hands its parent group when it registers.\n *\n * A named export rather than the structural type it used to be spelled as. Both\n * group components declared their OWN local `interface Member`, so d.ts\n * flattening had two of one name to resolve and published the second as\n * `Member$1` — a bundler-assigned identifier in the signature of a public method,\n * which no consumer could import and nobody had authored.\n */\nexport interface WrCollapseGroupMember {\n /** Close this collapse — the group calls it on siblings in accordion mode. */\n close(): void;\n /** Identity of the registering collapse, used as the map key and by `notifyOpened`. */\n readonly id: object;\n}\n\n/**\n * Contract a collapse uses to talk to its parent `<wr-collapse-group>`.\n *\n * @internal\n */\nexport interface WrCollapseGroupContext {\n /** When true, only one child collapse may be open at a time. */\n readonly accordion: Signal<boolean>;\n /** Called by a child when it opens — closes siblings in accordion mode. */\n notifyOpened(opener: object): void;\n /** Register a child so the group can call `closeAll()` etc. */\n register(member: WrCollapseGroupMember): void;\n /** Unregister on destroy. */\n unregister(memberId: object): void;\n}\n\n/**\n * Token a `<wr-collapse>` injects to register itself with — and notify of\n * open events — its parent `<wr-collapse-group>`. Drives the accordion\n * behaviour when the group has `accordion` enabled.\n *\n * @internal\n */\nexport const WR_COLLAPSE_GROUP = new InjectionToken<WrCollapseGroupContext>('WR_COLLAPSE_GROUP');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, DestroyRef, ViewEncapsulation, computed, effect, inject, input, model } from '@angular/core';\n\nimport { randomId } from 'ngwr/utils';\n\nimport { WR_COLLAPSE_GROUP } from './tokens';\n\n/**\n * Expandable panel with a clickable header. Two-way binds the `open`\n * state. When wrapped in `<wr-collapse-group accordion>`, only one\n * sibling can be open at a time.\n *\n * @example\n * ```html\n * <wr-collapse title=\"Section title\">\n * Section body…\n * </wr-collapse>\n *\n * <wr-collapse-group accordion>\n * <wr-collapse title=\"A\">…</wr-collapse>\n * <wr-collapse title=\"B\">…</wr-collapse>\n * </wr-collapse-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse',\n templateUrl: './collapse.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrCollapse {\n /** Header text. */\n readonly title = input.required<string>();\n\n /** Two-way bindable open/closed state. @default false */\n readonly open = model<boolean>(false);\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Identity used by the parent group when tracking children. @internal */\n readonly id = { name: randomId('wr-collapse') };\n\n /** DOM id for the body element, referenced by header's `aria-controls`. */\n protected readonly bodyId = `wr-collapse-body-${this.id.name}`;\n\n private readonly group = inject(WR_COLLAPSE_GROUP, { optional: true });\n private readonly destroyRef = inject(DestroyRef);\n\n protected readonly classes = computed(() => {\n const parts = ['wr-collapse'];\n if (this.open()) parts.push('wr-collapse--open');\n if (this.disabled()) parts.push('wr-collapse--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n if (this.group) {\n this.group.register({ id: this.id, close: () => this.open.set(false) });\n this.destroyRef.onDestroy(() => this.group?.unregister(this.id));\n\n // Tell the group whenever we open — group decides whether to close siblings.\n effect(() => {\n if (this.open()) this.group?.notifyOpened(this.id);\n });\n }\n }\n\n /** Open the panel. */\n openPanel(): void {\n if (this.disabled()) return;\n this.open.set(true);\n }\n\n /** Close the panel. */\n close(): void {\n this.open.set(false);\n }\n\n /** Toggle the panel. */\n toggle(): void {\n if (this.disabled()) return;\n this.open.update(v => !v);\n }\n}\n","<button\n type=\"button\"\n class=\"wr-collapse__header\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n [disabled]=\"disabled()\"\n (click)=\"toggle()\"\n>\n <span class=\"wr-collapse__title\">{{ title() }}</span>\n <svg\n class=\"wr-icon__svg wr-collapse__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n</button>\n\n<div\n class=\"wr-collapse__body\"\n [attr.id]=\"bodyId\"\n [class.wr-collapse__body--open]=\"open()\"\n [attr.aria-hidden]=\"!open()\"\n [attr.inert]=\"!open() ? '' : null\"\n>\n <div class=\"wr-collapse__content\">\n <div class=\"wr-collapse__inner\">\n <ng-content />\n </div>\n </div>\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, forwardRef, input } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext, type WrCollapseGroupMember } from './tokens';\n\n/**\n * Visual + behavioral grouping of `<wr-collapse>` children. When\n * `accordion` is true, opening one child closes the others.\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-collapse-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrCollapseGroup),\n },\n ],\n})\nexport class WrCollapseGroup implements WrCollapseGroupContext {\n /** When true, only one child may be open at a time. @default false */\n readonly accordion = input(false, { transform: coerceBooleanProperty });\n\n private readonly members = new Map<object, WrCollapseGroupMember>();\n\n register(member: WrCollapseGroupMember): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n if (!this.accordion()) return;\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, forwardRef, signal } from '@angular/core';\n\nimport { WR_COLLAPSE_GROUP, type WrCollapseGroupContext, type WrCollapseGroupMember } from './tokens';\n\n/**\n * Accordion — a `<wr-collapse>` container that enforces single-open\n * behavior: opening a child closes its siblings.\n *\n * Use `<wr-collapse-group>` when you only need visual grouping without\n * the mutually-exclusive open semantics.\n *\n * @example\n * ```html\n * <wr-accordion>\n * <wr-collapse title=\"Profile\">…</wr-collapse>\n * <wr-collapse title=\"Security\">…</wr-collapse>\n * <wr-collapse title=\"Notifications\">…</wr-collapse>\n * </wr-accordion>\n * ```\n *\n * @see https://ngwr.dev/reference/components/collapse\n */\n@Component({\n selector: 'wr-accordion',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-collapse-group wr-collapse-group--accordion' },\n providers: [\n {\n provide: WR_COLLAPSE_GROUP,\n // eslint-disable-next-line @angular-eslint/no-forward-ref\n useExisting: forwardRef(() => WrAccordion),\n },\n ],\n})\nexport class WrAccordion implements WrCollapseGroupContext {\n /** Always behaves as an accordion. Provided for context-interface symmetry. */\n readonly accordion = signal(true).asReadonly();\n\n private readonly members = new Map<object, WrCollapseGroupMember>();\n\n register(member: WrCollapseGroupMember): void {\n this.members.set(member.id, member);\n }\n\n unregister(memberId: object): void {\n this.members.delete(memberId);\n }\n\n notifyOpened(opener: object): void {\n for (const [id, member] of this.members) {\n if (id !== opener) member.close();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;AAAA;;;;;AAKG;AAoCH;;;;;;AAMG;MACU,iBAAiB,GAAG,IAAI,cAAc,CAAyB,mBAAmB;;AChD/F;;;;;AAKG;AASH;;;;;;;;;;;;;;;;;;AAkBG;MAOU,UAAU,CAAA;;IAEZ,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAU;;IAGhC,IAAI,GAAG,KAAK,CAAU,KAAK;6EAAC;;IAG5B,QAAQ,GAAG,KAAK,CAAC,KAAK,gFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAG7D,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE;;IAG5B,MAAM,GAAG,oBAAoB,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;IAE7C,KAAK,GAAG,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACrD,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE7B,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,KAAK,GAAG,CAAC,aAAa,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC;QAChD,IAAI,IAAI,CAAC,QAAQ,EAAE;AAAE,YAAA,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC;AACxD,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;IACxB,CAAC;gFAAC;AAEF,IAAA,WAAA,GAAA;AACE,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;AACvE,YAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YAGhE,MAAM,CAAC,MAAK;gBACV,IAAI,IAAI,CAAC,IAAI,EAAE;oBAAE,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;AACpD,YAAA,CAAC,CAAC;QACJ;IACF;;IAGA,SAAS,GAAA;QACP,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACrB;;IAGA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACtB;;IAGA,MAAM,GAAA;QACJ,IAAI,IAAI,CAAC,QAAQ,EAAE;YAAE;AACrB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3B;uGArDW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,ihBCvCvB,84BAqCA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDEa,UAAU,EAAA,UAAA,EAAA,CAAA;kBANtB,SAAS;+BACE,aAAa,EAAA,aAAA,EAER,iBAAiB,CAAC,IAAI,QAC/B,EAAE,SAAS,EAAE,WAAW,EAAE,EAAA,QAAA,EAAA,84BAAA,EAAA;;;AErClC;;;;;AAKG;AAOH;;;;;AAKG;MAcU,eAAe,CAAA;;IAEjB,SAAS,GAAG,KAAK,CAAC,KAAK,iFAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;AAEtD,IAAA,OAAO,GAAG,IAAI,GAAG,EAAiC;AAEnE,IAAA,QAAQ,CAAC,MAA6B,EAAA;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC;AAEA,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/B;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;AACzB,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;YAAE;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,EAAE,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE;QACnC;IACF;uGAnBW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,mBAAA,EAAA,EAAA,SAAA,EARf;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;;AAE1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,eAAe,CAAC;AAC/C,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EATS,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAWf,eAAe,EAAA,UAAA,EAAA,CAAA;kBAb3B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE;AACpC,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;;AAE1B,4BAAA,WAAW,EAAE,UAAU,CAAC,qBAAqB,CAAC;AAC/C,yBAAA;AACF,qBAAA;AACF,iBAAA;;;AC9BD;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;AAiBG;MAcU,WAAW,CAAA;;IAEb,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;AAE7B,IAAA,OAAO,GAAG,IAAI,GAAG,EAAiC;AAEnE,IAAA,QAAQ,CAAC,MAA6B,EAAA;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC;IACrC;AAEA,IAAA,UAAU,CAAC,QAAgB,EAAA;AACzB,QAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC/B;AAEA,IAAA,YAAY,CAAC,MAAc,EAAA;QACzB,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,EAAE,KAAK,MAAM;gBAAE,MAAM,CAAC,KAAK,EAAE;QACnC;IACF;uGAlBW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAX,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,WAAW,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,gDAAA,EAAA,EAAA,SAAA,EARX;AACT,YAAA;AACE,gBAAA,OAAO,EAAE,iBAAiB;;AAE1B,gBAAA,WAAW,EAAE,UAAU,CAAC,MAAM,WAAW,CAAC;AAC3C,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EATS,gBAAgB,EAAA,QAAA,EAAA,IAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAWf,WAAW,EAAA,UAAA,EAAA,CAAA;kBAbvB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,cAAc;AACxB,oBAAA,QAAQ,EAAE,gBAAgB;oBAC1B,aAAa,EAAE,iBAAiB,CAAC,IAAI;AACrC,oBAAA,IAAI,EAAE,EAAE,KAAK,EAAE,gDAAgD,EAAE;AACjE,oBAAA,SAAS,EAAE;AACT,wBAAA;AACE,4BAAA,OAAO,EAAE,iBAAiB;;AAE1B,4BAAA,WAAW,EAAE,UAAU,CAAC,iBAAiB,CAAC;AAC3C,yBAAA;AACF,qBAAA;AACF,iBAAA;;;ACzCD;;AAEG;;"}
|