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-rotating-text-testing.mjs","sources":["../../../projects/lib/rotating-text/testing/wr-rotating-text-harness.ts","../../../projects/lib/rotating-text/testing/ngwr-rotating-text-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, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrRotatingTextHarnessFilters } from './interfaces';\n\n/** One animated piece — a grapheme, a word or a line, depending on `splitBy`. */\nconst CHAR = '.wr-rotating-text__char';\n\n/** The whole animated layer, and the one element taken out of the a11y tree. */\nconst INNER = '.wr-rotating-text__inner';\n\n/** The readable copy of the string showing now, carried once outside the animated layer. */\nconst SR_ONLY = '.wr-rotating-text__sr-only';\n\n/** A word group — kept whether the word is drawn whole or exploded into characters. */\nconst WORD = '.wr-rotating-text__word';\n\n/**\n * An inline `opacity: 1` — the end state the enter step commits on every piece.\n *\n * Matched off the `style` ATTRIBUTE, never through `getCssValue`: a computed style would\n * answer `1` for a piece nobody ever wrote to, which is the exact case worth telling\n * apart from a piece the component finished with.\n */\nconst SETTLED_OPACITY = /(?:^|;)\\s*opacity\\s*:\\s*1\\s*(?:;|$)/;\n\n/** Exactly what the element holds — untrimmed, unlike `TestElement.text()`. */\nasync function rawText(element: TestElement): Promise<string> {\n return (await element.getProperty<string | null>('textContent')) ?? '';\n}\n\n/**\n * Test harness for `<wr-rotating-text>`.\n *\n * **What is announced and what is drawn are two questions, and this component is worth a\n * harness mostly because it answers them separately.** The string showing now is carried\n * verbatim in a visually-hidden span; the animated layer beside it is one span per\n * grapheme, word or line and is `aria-hidden` as a whole, so a screen reader hears `one`\n * rather than `o. n. e.` {@link getAccessibleText} is the first, {@link getRenderedText}\n * and {@link getPieces} the second, and {@link isAnimatedLayerHidden} together with\n * {@link hasAccessibleCopy} is the pairing that regresses silently when someone\n * restructures the template — pieces hidden AND no readable copy is an element with no\n * accessible text at all, which reads as a pass on either check alone.\n *\n * **The sr-only span is deliberately not a live region, and no method here implies\n * otherwise.** `auto` advances every two seconds by default, and the APG's answer for\n * self-advancing content is silence, not an announcement on a timer. What the harness\n * pins is that the announced copy TRACKS the current word — nothing about it being\n * spoken.\n *\n * **There is no `getIndex()`, and no `next()` / `previous()` / `jumpTo()` / `reset()`.**\n * The index appears nowhere in the DOM — no attribute, no data hook — so deriving it\n * would mean matching the shown string against a list the harness was never given, and\n * guessing between duplicates. And the component renders no controls at all: rotation is\n * a timer or a method call on the instance, so a harness \"click\" would have nothing to\n * click and reaching into the component would make this a wrapper around the class rather\n * than a reader of the DOM. Drive it from the spec — through the instance, or by\n * advancing the interval — and assert the `nextChange` output for the index.\n *\n * **Nothing here reports the tween.** `duration`, `easing`, `staggerDuration` and\n * `staggerFrom` are passed straight into Web Animation options and never written to the\n * document; `delayFor()` is arithmetic with no rendered trace. So no `getDuration()`, no\n * `getStagger()`, no `isAnimating()`. The pieces do carry inline `opacity` and\n * `transform`, but on the animated path those are the FIRST keyframe — `opacity: 0` on\n * text the user can see perfectly well — which is why the only reading offered is\n * {@link isSettled}, and why it is spelled as a commitment rather than as a state of\n * motion. The host's `overflow: hidden` clipping is layout, and every rect in a unit test\n * is 0×0, so there is no `isClipped()` either.\n *\n * jsdom implements no Web Animations API, so the animated path throws on the first\n * `el.animate` — before any assertion runs. Every spec supplies one half or the other:\n *\n * ```ts\n * // Either: mount under reduced motion, where each swap is instant and nothing tweens.\n * // (jsdom has no matchMedia, so WrPlatform must be provided as a value.)\n * TestBed.configureTestingModule({ providers: [{ provide: WrPlatform, useValue: reducedMotion }] });\n *\n * // Or: stub the API — and remember a stub that never fires `onfinish` never resolves\n * // the exit step, so the rotator stops after one swap.\n * Reflect.set(Element.prototype, 'animate', () => ({ cancel: () => undefined, onfinish: null }));\n * ```\n *\n * @example\n * ```ts\n * const rotator = await loader.getHarness(WrRotatingTextHarness);\n *\n * expect(await rotator.getAccessibleText()).toBe('design');\n * expect(await rotator.getPieces()).toEqual(['d', 'e', 's', 'i', 'g', 'n']);\n * expect(await rotator.isAnimatedLayerHidden()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrRotatingTextHarness extends ComponentHarness {\n static hostSelector = 'wr-rotating-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrRotatingTextHarnessFilters = {}): HarnessPredicate<WrRotatingTextHarness> {\n return new HarnessPredicate(WrRotatingTextHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getAccessibleText(), text)\n )\n .addOption('wordCount', options.wordCount, async (harness, count) => (await harness.getWordCount()) === count);\n }\n\n private readonly chars = this.locatorForAll(CHAR);\n\n /**\n * The string showing right now, as the one readable copy holds it.\n *\n * Literally what a screen reader gets, the animated layer being out of the tree — and\n * the thing to assert a rotation against, since it is where `next()`, `previous()`, a\n * clamped `jumpTo()`, `reset()`, the wrap at either end, the stop when `loop` is off and\n * the shrinking-list clamp all become visible.\n *\n * Throws when the copy is missing rather than answering with the pieces' text: an empty\n * string is what a rotator holding an empty list correctly reports, so a plausible\n * nothing here is indistinguishable from the component having lost its accessible name\n * entirely. Ask {@link hasAccessibleCopy} when presence is the question.\n */\n async getAccessibleText(): Promise<string> {\n const copy = await this.locatorForOptional(SR_ONLY)();\n\n if (!copy) {\n throw new Error(\n 'WrRotatingTextHarness.getAccessibleText(): this <wr-rotating-text> renders no ' +\n `${SR_ONLY} span, so it has no accessible text at all — every piece it draws is aria-hidden. ` +\n 'Reading the pieces instead would report a healthy-looking string for a component a screen ' +\n 'reader cannot see.'\n );\n }\n\n return rawText(copy);\n }\n\n /**\n * Everything the animated layer draws, in document order, as one string.\n *\n * A different fact from {@link getAccessibleText}, and the comparison between them is\n * the point: a split that drops its spacer renders `hellothere` while the readable copy\n * stays perfect, and nothing else in the DOM says so.\n *\n * The spacer between words is a non-breaking space (` `), which is a rendering\n * choice rather than a contract, so it is normalized to a plain space here — otherwise\n * every round-trip assertion would have to spell U+00A0 out to pass against a working\n * component. Note that `splitBy=\"lines\"` genuinely does not round-trip: the newline the\n * readable copy carries is drawn as that same spacer.\n */\n async getRenderedText(): Promise<string> {\n return (await rawText(await this.locatorFor(INNER)())).replace(/\\u00a0/g, ' ');\n }\n\n /**\n * The animated pieces, in document order.\n *\n * The granularity actually applied: one piece per grapheme for `splitBy=\"characters\"`,\n * one per word for `\"words\"`, one per line for `\"lines\"`. It is also where the grapheme\n * contract shows — `a🚀b` must come back as three pieces, not four with two broken\n * halves of a surrogate pair.\n */\n async getPieces(): Promise<string[]> {\n return Promise.all((await this.chars()).map(rawText));\n }\n\n /**\n * How many word groups the split produced.\n *\n * Word boundaries survive every granularity: three words stay three groups even when\n * each is exploded into characters, which is what keeps the line wrapping sane. A\n * splitter that flattened the grouping would leave {@link getPieces} correct and break\n * only this.\n */\n async getWordCount(): Promise<number> {\n return (await this.locatorForAll(WORD)()).length;\n }\n\n /**\n * Whether the animated layer is out of the accessibility tree.\n *\n * ONE attribute answers it — `aria-hidden` sits on the `__inner` wrapper, so the pieces\n * inherit it and none carries it itself, which keeps the attribute off the nodes the\n * tween writes to. Asserting it per piece would fail on a component that is behaving.\n *\n * If it regresses, every rotation is spelled out letter by letter beside the copy that\n * was already read, and nothing changes on screen — so no other check catches it.\n */\n async isAnimatedLayerHidden(): Promise<boolean> {\n return (await (await this.locatorFor(INNER)()).getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Whether the readable copy is rendered at all.\n *\n * The other half of {@link isAnimatedLayerHidden}, and it exists as a separate question\n * because the failure the two catch together is invisible to each alone: a layer\n * correctly hidden with no readable copy beside it is a control with no accessible text\n * whatsoever, and `isAnimatedLayerHidden() === true` is exactly what it reports.\n */\n async hasAccessibleCopy(): Promise<boolean> {\n return (await this.locatorForOptional(SR_ONLY)()) !== null;\n }\n\n /**\n * Whether the enter step committed its end state on every piece — NOT whether an\n * animation finished.\n *\n * The component writes `opacity: 1` inline on each piece when the swap settles: instantly\n * under reduced motion, and from the tween's `onfinish` otherwise. So this answers \"the\n * new word was actually taken over\", which is the bug the deferred enter exists to\n * prevent — a swap that animates the OLD spans leaves the new ones staged at `opacity: 0`\n * and the text invisible, while the readable copy reports the new word correctly.\n *\n * It is all-or-nothing: one piece left staged is one invisible glyph in the middle of a\n * word. On the animated path it stays `false` until each tween finishes, which in a unit\n * test means forever, since a stubbed `Element.animate` never fires anything — that is\n * an honest answer about a swap that never landed, not a limitation to work around.\n *\n * Throws when there are no pieces: \"every piece is settled\" is true of none of them,\n * and that is also what a component that stopped rendering its text would report.\n */\n async isSettled(): Promise<boolean> {\n const pieces = await this.chars();\n\n if (pieces.length === 0) {\n throw new Error(\n 'WrRotatingTextHarness.isSettled(): this <wr-rotating-text> drew no pieces, so \"settled\" would be ' +\n 'vacuously true — the same answer a rotator that stopped rendering its text would give. Check ' +\n '`texts` is not empty, or ask getPieces().'\n );\n }\n\n const styles = await Promise.all(pieces.map(piece => piece.getAttribute('style')));\n return styles.every(style => SETTLED_OPACITY.test(style ?? ''));\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-rotating-text-testing.mjs","sources":["../../../projects/lib/rotating-text/testing/wr-rotating-text-harness.ts","../../../projects/lib/rotating-text/testing/ngwr-rotating-text-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, type TestElement } from '@angular/cdk/testing';\n\nimport type { WrRotatingTextHarnessFilters } from './interfaces';\n\n/** One animated piece — a grapheme, a word or a line, depending on `splitBy`. */\nconst CHAR = '.wr-rotating-text__char';\n\n/** The whole animated layer, and the one element taken out of the a11y tree. */\nconst INNER = '.wr-rotating-text__inner';\n\n/** The readable copy of the string showing now, carried once outside the animated layer. */\nconst SR_ONLY = '.wr-rotating-text__sr-only';\n\n/** A word group — kept whether the word is drawn whole or exploded into characters. */\nconst WORD = '.wr-rotating-text__word';\n\n/**\n * An inline `opacity: 1` — the end state the enter step commits on every piece.\n *\n * Matched off the `style` ATTRIBUTE, never through `getCssValue`: a computed style would\n * answer `1` for a piece nobody ever wrote to, which is the exact case worth telling\n * apart from a piece the component finished with.\n */\nconst SETTLED_OPACITY = /(?:^|;)\\s*opacity\\s*:\\s*1\\s*(?:;|$)/;\n\n/** Exactly what the element holds — untrimmed, unlike `TestElement.text()`. */\nasync function rawText(element: TestElement): Promise<string> {\n return (await element.getProperty<string | null>('textContent')) ?? '';\n}\n\n/**\n * Test harness for `<wr-rotating-text>`.\n *\n * **What is announced and what is drawn are two questions, and this component is worth a\n * harness mostly because it answers them separately.** The string showing now is carried\n * verbatim in a visually-hidden span; the animated layer beside it is one span per\n * grapheme, word or line and is `aria-hidden` as a whole, so a screen reader hears `one`\n * rather than `o. n. e.` {@link getAccessibleText} is the first, {@link getRenderedText}\n * and {@link getPieces} the second, and {@link isAnimatedLayerHidden} together with\n * {@link hasAccessibleCopy} is the pairing that regresses silently when someone\n * restructures the template — pieces hidden AND no readable copy is an element with no\n * accessible text at all, which reads as a pass on either check alone.\n *\n * **The sr-only span is deliberately not a live region, and no method here implies\n * otherwise.** `auto` advances every two seconds by default, and the APG's answer for\n * self-advancing content is silence, not an announcement on a timer. What the harness\n * pins is that the announced copy TRACKS the current word — nothing about it being\n * spoken.\n *\n * **There is no `getIndex()`, and no `next()` / `previous()` / `jumpTo()` / `reset()`.**\n * The index appears nowhere in the DOM — no attribute, no data hook — so deriving it\n * would mean matching the shown string against a list the harness was never given, and\n * guessing between duplicates. And the component renders no controls at all: rotation is\n * a timer or a method call on the instance, so a harness \"click\" would have nothing to\n * click and reaching into the component would make this a wrapper around the class rather\n * than a reader of the DOM. Drive it from the spec — through the instance, or by\n * advancing the interval — and assert the `nextChange` output for the index.\n *\n * **Nothing here reports the tween.** `duration`, `easing`, `staggerDuration` and\n * `staggerFrom` are passed straight into Web Animation options and never written to the\n * document; `delayFor()` is arithmetic with no rendered trace. So no `getDuration()`, no\n * `getStagger()`, no `isAnimating()`. The pieces do carry inline `opacity` and\n * `transform`, but on the animated path those are the FIRST keyframe — `opacity: 0` on\n * text the user can see perfectly well — which is why the only reading offered is\n * {@link isSettled}, and why it is spelled as a commitment rather than as a state of\n * motion. The host's `overflow: hidden` clipping is layout, and every rect in a unit test\n * is 0×0, so there is no `isClipped()` either.\n *\n * jsdom implements no Web Animations API, so the animated path throws on the first\n * `el.animate` — before any assertion runs. Every spec supplies one half or the other:\n *\n * ```ts\n * // Either: mount under reduced motion, where each swap is instant and nothing tweens.\n * // (jsdom has no matchMedia, so WrPlatform must be provided as a value.)\n * TestBed.configureTestingModule({ providers: [{ provide: WrPlatform, useValue: reducedMotion }] });\n *\n * // Or: stub the API — and remember a stub that never fires `onfinish` never resolves\n * // the exit step, so the rotator stops after one swap.\n * Reflect.set(Element.prototype, 'animate', () => ({ cancel: () => undefined, onfinish: null }));\n * ```\n *\n * @example\n * ```ts\n * const rotator = await loader.getHarness(WrRotatingTextHarness);\n *\n * expect(await rotator.getAccessibleText()).toBe('design');\n * expect(await rotator.getPieces()).toEqual(['d', 'e', 's', 'i', 'g', 'n']);\n * expect(await rotator.isAnimatedLayerHidden()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrRotatingTextHarness extends ComponentHarness {\n static hostSelector = 'wr-rotating-text';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrRotatingTextHarnessFilters = {}): HarnessPredicate<WrRotatingTextHarness> {\n return new HarnessPredicate(WrRotatingTextHarness, options)\n .addOption('text', options.text, (harness, text) =>\n HarnessPredicate.stringMatches(harness.getAccessibleText(), text)\n )\n .addOption('wordCount', options.wordCount, async (harness, count) => (await harness.getWordCount()) === count);\n }\n\n private readonly chars = this.locatorForAll(CHAR);\n\n /**\n * The string showing right now, as the one readable copy holds it.\n *\n * Literally what a screen reader gets, the animated layer being out of the tree — and\n * the thing to assert a rotation against, since it is where `next()`, `previous()`, a\n * clamped `jumpTo()`, `reset()`, the wrap at either end, the stop when `loop` is off and\n * the shrinking-list clamp all become visible.\n *\n * Throws when the copy is missing rather than answering with the pieces' text: an empty\n * string is what a rotator holding an empty list correctly reports, so a plausible\n * nothing here is indistinguishable from the component having lost its accessible name\n * entirely. Ask {@link hasAccessibleCopy} when presence is the question.\n */\n async getAccessibleText(): Promise<string> {\n const copy = await this.locatorForOptional(SR_ONLY)();\n\n if (!copy) {\n throw new Error(\n 'WrRotatingTextHarness.getAccessibleText(): this <wr-rotating-text> renders no ' +\n `${SR_ONLY} span, so it has no accessible text at all — every piece it draws is aria-hidden. ` +\n 'Reading the pieces instead would report a healthy-looking string for a component a screen ' +\n 'reader cannot see.'\n );\n }\n\n return rawText(copy);\n }\n\n /**\n * Everything the animated layer draws, in document order, as one string.\n *\n * A different fact from {@link getAccessibleText}, and the comparison between them is\n * the point: a split that drops its spacer renders `hellothere` while the readable copy\n * stays perfect, and nothing else in the DOM says so.\n *\n * The spacer between words is a non-breaking space (` `), which is a rendering\n * choice rather than a contract, so it is normalized to a plain space here — otherwise\n * every round-trip assertion would have to spell U+00A0 out to pass against a working\n * component. Note that `splitBy=\"lines\"` genuinely does not round-trip: the newline the\n * readable copy carries is drawn as that same spacer.\n */\n async getRenderedText(): Promise<string> {\n return (await rawText(await this.locatorFor(INNER)())).replace(/\\u00a0/g, ' ');\n }\n\n /**\n * The animated pieces, in document order.\n *\n * The granularity actually applied: one piece per grapheme for `splitBy=\"characters\"`,\n * one per word for `\"words\"`, one per line for `\"lines\"`. It is also where the grapheme\n * contract shows — `a🚀b` must come back as three pieces, not four with two broken\n * halves of a surrogate pair.\n */\n async getPieces(): Promise<string[]> {\n return Promise.all((await this.chars()).map(rawText));\n }\n\n /**\n * How many word groups the split produced.\n *\n * Word boundaries survive every granularity: three words stay three groups even when\n * each is exploded into characters, which is what keeps the line wrapping sane. A\n * splitter that flattened the grouping would leave {@link getPieces} correct and break\n * only this.\n */\n async getWordCount(): Promise<number> {\n return (await this.locatorForAll(WORD)()).length;\n }\n\n /**\n * Whether the animated layer is out of the accessibility tree.\n *\n * ONE attribute answers it — `aria-hidden` sits on the `__inner` wrapper, so the pieces\n * inherit it and none carries it itself, which keeps the attribute off the nodes the\n * tween writes to. Asserting it per piece would fail on a component that is behaving.\n *\n * If it regresses, every rotation is spelled out letter by letter beside the copy that\n * was already read, and nothing changes on screen — so no other check catches it.\n */\n async isAnimatedLayerHidden(): Promise<boolean> {\n return (await (await this.locatorFor(INNER)()).getAttribute('aria-hidden')) === 'true';\n }\n\n /**\n * Whether the readable copy is rendered at all.\n *\n * The other half of {@link isAnimatedLayerHidden}, and it exists as a separate question\n * because the failure the two catch together is invisible to each alone: a layer\n * correctly hidden with no readable copy beside it is a control with no accessible text\n * whatsoever, and `isAnimatedLayerHidden() === true` is exactly what it reports.\n */\n async hasAccessibleCopy(): Promise<boolean> {\n return (await this.locatorForOptional(SR_ONLY)()) !== null;\n }\n\n /**\n * Whether the enter step committed its end state on every piece — NOT whether an\n * animation finished.\n *\n * The component writes `opacity: 1` inline on each piece when the swap settles: instantly\n * under reduced motion, and from the tween's `onfinish` otherwise. So this answers \"the\n * new word was actually taken over\", which is the bug the deferred enter exists to\n * prevent — a swap that animates the OLD spans leaves the new ones staged at `opacity: 0`\n * and the text invisible, while the readable copy reports the new word correctly.\n *\n * It is all-or-nothing: one piece left staged is one invisible glyph in the middle of a\n * word. On the animated path it stays `false` until each tween finishes, which in a unit\n * test means forever, since a stubbed `Element.animate` never fires anything — that is\n * an honest answer about a swap that never landed, not a limitation to work around.\n *\n * Throws when there are no pieces: \"every piece is settled\" is true of none of them,\n * and that is also what a component that stopped rendering its text would report.\n */\n async isSettled(): Promise<boolean> {\n const pieces = await this.chars();\n\n if (pieces.length === 0) {\n throw new Error(\n 'WrRotatingTextHarness.isSettled(): this <wr-rotating-text> drew no pieces, so \"settled\" would be ' +\n 'vacuously true — the same answer a rotator that stopped rendering its text would give. Check ' +\n '`texts` is not empty, or ask getPieces().'\n );\n }\n\n const styles = await Promise.all(pieces.map(piece => piece.getAttribute('style')));\n return styles.every(style => SETTLED_OPACITY.test(style ?? ''));\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -262,10 +262,10 @@ class WrRotatingText {
|
|
|
262
262
|
return i * stagger;
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
266
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
265
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrRotatingText, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
266
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrRotatingText, isStandalone: true, selector: "wr-rotating-text", inputs: { texts: { classPropertyName: "texts", publicName: "texts", isSignal: true, isRequired: true, transformFunction: null }, rotationInterval: { classPropertyName: "rotationInterval", publicName: "rotationInterval", isSignal: true, isRequired: false, transformFunction: null }, splitBy: { classPropertyName: "splitBy", publicName: "splitBy", isSignal: true, isRequired: false, transformFunction: null }, auto: { classPropertyName: "auto", publicName: "auto", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", 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 }, staggerDuration: { classPropertyName: "staggerDuration", publicName: "staggerDuration", isSignal: true, isRequired: false, transformFunction: null }, staggerFrom: { classPropertyName: "staggerFrom", publicName: "staggerFrom", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nextChange: "nextChange" }, host: { classAttribute: "wr-rotating-text" }, ngImport: i0, template: "<!--\n The readable text, once: the spans below are per-character. Deliberately NOT a\n live region \u2014 `auto` rotates every two seconds by default, and the APG's answer\n for self-advancing content is silence, not an announcement every two seconds.\n-->\n\n<span class=\"wr-rotating-text__sr-only\">{{ current() }}</span>\n\n<!-- Animated visual content. -->\n<span class=\"wr-rotating-text__inner\" aria-hidden=\"true\">\n @for (word of words(); track $index) {\n <span class=\"wr-rotating-text__word\">\n @for (char of word.characters; track $index) {\n <span class=\"wr-rotating-text__char\">{{ char }}</span>\n }\n @if (word.needsSpace) {\n <span class=\"wr-rotating-text__space\"> </span>\n }\n </span>\n }\n</span>\n", styles: [".wr-rotating-text{display:inline-flex;align-items:center;overflow:hidden;vertical-align:bottom}.wr-rotating-text__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.wr-rotating-text__inner{display:inline-flex;flex-wrap:wrap}.wr-rotating-text__word{display:inline-flex;align-items:center}.wr-rotating-text__char{display:inline-block;will-change:transform,opacity}.wr-rotating-text__space{display:inline;white-space:pre}\n"], encapsulation: i0.ViewEncapsulation.None });
|
|
267
267
|
}
|
|
268
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
268
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrRotatingText, decorators: [{
|
|
269
269
|
type: Component,
|
|
270
270
|
args: [{ selector: 'wr-rotating-text', encapsulation: ViewEncapsulation.None, host: { class: 'wr-rotating-text' }, template: "<!--\n The readable text, once: the spans below are per-character. Deliberately NOT a\n live region \u2014 `auto` rotates every two seconds by default, and the APG's answer\n for self-advancing content is silence, not an announcement every two seconds.\n-->\n\n<span class=\"wr-rotating-text__sr-only\">{{ current() }}</span>\n\n<!-- Animated visual content. -->\n<span class=\"wr-rotating-text__inner\" aria-hidden=\"true\">\n @for (word of words(); track $index) {\n <span class=\"wr-rotating-text__word\">\n @for (char of word.characters; track $index) {\n <span class=\"wr-rotating-text__char\">{{ char }}</span>\n }\n @if (word.needsSpace) {\n <span class=\"wr-rotating-text__space\"> </span>\n }\n </span>\n }\n</span>\n", styles: [".wr-rotating-text{display:inline-flex;align-items:center;overflow:hidden;vertical-align:bottom}.wr-rotating-text__sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap}.wr-rotating-text__inner{display:inline-flex;flex-wrap:wrap}.wr-rotating-text__word{display:inline-flex;align-items:center}.wr-rotating-text__char{display:inline-block;will-change:transform,opacity}.wr-rotating-text__space{display:inline;white-space:pre}\n"] }]
|
|
271
271
|
}], ctorParameters: () => [], propDecorators: { texts: [{ type: i0.Input, args: [{ isSignal: true, alias: "texts", required: true }] }], rotationInterval: [{ type: i0.Input, args: [{ isSignal: true, alias: "rotationInterval", required: false }] }], splitBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "splitBy", required: false }] }], auto: [{ type: i0.Input, args: [{ isSignal: true, alias: "auto", required: false }] }], loop: [{ type: i0.Input, args: [{ isSignal: true, alias: "loop", required: false }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }], easing: [{ type: i0.Input, args: [{ isSignal: true, alias: "easing", required: false }] }], staggerDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "staggerDuration", required: false }] }], staggerFrom: [{ type: i0.Input, args: [{ isSignal: true, alias: "staggerFrom", required: false }] }], nextChange: [{ type: i0.Output, args: ["nextChange"] }] } });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-rotating-text.mjs","sources":["../../../projects/lib/rotating-text/rotating-text.ts","../../../projects/lib/rotating-text/rotating-text.html","../../../projects/lib/rotating-text/ngwr-rotating-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 RotatingText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/rotating-text\n *\n * The reactbits version uses `motion/react` + `AnimatePresence`. This\n * port is dependency-free — vanilla DOM split + Web Animations API for\n * the enter/exit transitions.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrRotatingTextSplit, WrRotatingTextStaggerFrom } from './interfaces';\n\nconst DEFAULT_EASING = 'cubic-bezier(0.16, 1, 0.3, 1)';\n\ninterface Word {\n readonly characters: readonly string[];\n readonly needsSpace: boolean;\n}\n\nfunction graphemes(text: string): readonly string[] {\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n const seg = new Intl.Segmenter('en', { granularity: 'grapheme' });\n return Array.from(seg.segment(text), s => s.segment);\n }\n return Array.from(text);\n}\n\nfunction splitWords(text: string, by: WrRotatingTextSplit): readonly Word[] {\n if (!text) return [];\n if (by === 'lines') {\n const lines = text.split('\\n');\n return lines.map((line, i) => ({ characters: [line], needsSpace: i !== lines.length - 1 }));\n }\n if (by === 'words') {\n const words = text.split(' ');\n return words.map((w, i) => ({ characters: [w], needsSpace: i !== words.length - 1 }));\n }\n // characters: split each word into graphemes, keep word boundaries for spacing.\n const words = text.split(' ');\n return words.map((w, i) => ({ characters: graphemes(w), needsSpace: i !== words.length - 1 }));\n}\n\n/**\n * Cycles through a list of strings, animating each transition\n * character-by-character (or word/line). Auto-advances on a timer by\n * default; can also be controlled imperatively via `next()` /\n * `previous()` / `jumpTo()` / `reset()`.\n *\n * @example\n * ```html\n * <wr-rotating-text [texts]=\"['design', 'ship', 'iterate']\" />\n *\n * // Manual control:\n * @ViewChild(WrRotatingText) rotator!: WrRotatingText;\n * onClick(): void { this.rotator.next(); }\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/rotating-text\n */\n@Component({\n selector: 'wr-rotating-text',\n templateUrl: './rotating-text.html',\n styleUrl: './rotating-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-rotating-text' },\n})\nexport class WrRotatingText {\n /** Strings to cycle. Required. */\n readonly texts = input.required<readonly string[]>();\n\n /** Auto-advance interval in ms. @default 2000 */\n readonly rotationInterval = input(2000, { transform: numAttr(2000) });\n\n /** Granularity of the split. @default 'characters' */\n readonly splitBy = input<WrRotatingTextSplit>('characters');\n\n /** Auto-advance on a timer. @default true */\n readonly auto = input(true, { transform: coerceBooleanProperty });\n\n /** Loop back to the first string after the last. @default true */\n readonly loop = input(true, { transform: coerceBooleanProperty });\n\n /** Per-swap tween duration in seconds. @default 0.6 */\n readonly duration = input(0.6, { transform: numAttr(0.6) });\n\n /** CSS easing of the per-piece tween. @default 'cubic-bezier(0.16, 1, 0.3, 1)' (~power3.out) */\n readonly easing = input(DEFAULT_EASING);\n\n /** Per-piece stagger in seconds. @default 0 */\n readonly staggerDuration = input(0, { transform: numAttr(0) });\n\n /** Stagger origin. @default 'first' */\n readonly staggerFrom = input<WrRotatingTextStaggerFrom>('first');\n\n /** Emitted with the new index on every rotation. */\n readonly nextChange = output<number>();\n\n protected readonly index = signal(0);\n\n protected readonly current = computed(() => {\n const arr = this.texts();\n return arr.length === 0 ? '' : arr[Math.min(this.index(), arr.length - 1)];\n });\n\n protected readonly words = computed<readonly Word[]>(() => splitWords(this.current(), this.splitBy()));\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private timerId: ReturnType<typeof setInterval> | undefined;\n private isAnimating = false;\n private destroyed = false;\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => this.animateIn());\n\n // Restart the timer when interval / auto change.\n effect(() => {\n this.rotationInterval();\n this.auto();\n this.restartTimer();\n });\n\n this.destroyRef.onDestroy(() => {\n clearInterval(this.timerId);\n this.destroyed = true;\n });\n }\n\n // Public imperative API\n\n next(): void {\n const arr = this.texts();\n if (arr.length === 0) return;\n const cur = this.index();\n const last = arr.length - 1;\n const target = cur === last ? (this.loop() ? 0 : cur) : cur + 1;\n if (target !== cur) void this.transitionTo(target);\n }\n\n previous(): void {\n const arr = this.texts();\n if (arr.length === 0) return;\n const cur = this.index();\n const last = arr.length - 1;\n const target = cur === 0 ? (this.loop() ? last : cur) : cur - 1;\n if (target !== cur) void this.transitionTo(target);\n }\n\n jumpTo(target: number): void {\n const arr = this.texts();\n if (arr.length === 0) return;\n const clamped = Math.max(0, Math.min(target, arr.length - 1));\n if (clamped !== this.index()) void this.transitionTo(clamped);\n }\n\n reset(): void {\n if (this.index() !== 0) void this.transitionTo(0);\n }\n\n // Internals\n\n private restartTimer(): void {\n clearInterval(this.timerId);\n if (!this.auto()) return;\n this.timerId = setInterval(() => this.next(), this.rotationInterval());\n }\n\n private async transitionTo(target: number): Promise<void> {\n if (this.isAnimating) return;\n this.isAnimating = true;\n\n await this.animateOut();\n\n // `animateOut` is an async gap, and a transition already in flight outlives\n // the component: navigating away destroys it, and `clearInterval` only\n // stops FUTURE ticks — not this call. Everything below touches the view, so\n // resuming on a destroyed component throws NG0911 (\"View has already been\n // destroyed\") and warns NG0953 (emit on a destroyed `OutputRef`).\n if (this.destroyed) return;\n\n this.index.set(target);\n this.nextChange.emit(target);\n // Animate in only AFTER Angular has rendered the new word's spans. A single\n // microtask isn't enough under zoneless change detection — the re-render\n // hasn't flushed yet, so `animateIn()` would query the OLD spans, animate\n // them, and then the render would swap their content mid-flight (and any\n // spans the longer word adds would never get animated). `afterNextRender`\n // fires after the render the `index` change schedules.\n afterNextRender(\n () => {\n this.animateIn();\n this.isAnimating = false;\n },\n { injector: this.injector }\n );\n }\n\n private animateIn(): void {\n const targets = this.host.nativeElement.querySelectorAll<HTMLElement>('.wr-rotating-text__char');\n if (targets.length === 0) return;\n\n // Reduced motion: the word swap itself is content and keeps cycling,\n // but each swap is instant — no per-char rise/fall tween.\n if (this.platform.prefersReducedMotion()) {\n targets.forEach(el => {\n el.style.opacity = '1';\n el.style.transform = 'translate3d(0, 0, 0)';\n });\n return;\n }\n\n const stagger = this.staggerDuration() * 1000;\n targets.forEach((el, i) => {\n const delay = this.delayFor(i, targets.length, stagger);\n el.style.opacity = '0';\n el.style.transform = 'translate3d(0, 100%, 0)';\n const anim = el.animate(\n [\n { opacity: 0, transform: 'translate3d(0, 100%, 0)' },\n { opacity: 1, transform: 'translate3d(0, 0, 0)' },\n ],\n { duration: this.duration() * 1000, delay, easing: this.easing(), fill: 'forwards' }\n );\n anim.onfinish = (): void => {\n el.style.opacity = '1';\n el.style.transform = 'translate3d(0, 0, 0)';\n try {\n anim.cancel();\n } catch {\n /* noop */\n }\n };\n });\n }\n\n private animateOut(): Promise<void> {\n const targets = this.host.nativeElement.querySelectorAll<HTMLElement>('.wr-rotating-text__char');\n if (targets.length === 0) return Promise.resolve();\n if (this.platform.prefersReducedMotion()) return Promise.resolve();\n const stagger = this.staggerDuration() * 1000;\n const promises: Promise<void>[] = [];\n targets.forEach((el, i) => {\n const delay = this.delayFor(i, targets.length, stagger);\n const anim = el.animate(\n [\n { opacity: 1, transform: 'translate3d(0, 0, 0)' },\n { opacity: 0, transform: 'translate3d(0, -120%, 0)' },\n ],\n { duration: this.duration() * 1000, delay, easing: this.easing(), fill: 'forwards' }\n );\n promises.push(\n new Promise<void>(resolve => {\n anim.onfinish = (): void => {\n // Commit the exited (hidden, lifted) state to inline style before\n // cancelling, so the char stays out instead of snapping back to\n // visible-in-place between the swap and the enter animation.\n el.style.opacity = '0';\n el.style.transform = 'translate3d(0, -120%, 0)';\n try {\n anim.cancel();\n } catch {\n /* noop */\n }\n resolve();\n };\n })\n );\n });\n return Promise.all(promises).then(() => undefined);\n }\n\n private delayFor(i: number, total: number, stagger: number): number {\n if (stagger === 0) return 0;\n switch (this.staggerFrom()) {\n case 'last':\n return (total - 1 - i) * stagger;\n case 'center': {\n const center = Math.floor(total / 2);\n return Math.abs(center - i) * stagger;\n }\n case 'first':\n default:\n return i * stagger;\n }\n }\n}\n\nexport type { WrRotatingTextSplit, WrRotatingTextStaggerFrom } from './interfaces';\n","<!--\n The readable text, once: the spans below are per-character. Deliberately NOT a\n live region — `auto` rotates every two seconds by default, and the APG's answer\n for self-advancing content is silence, not an announcement every two seconds.\n-->\n\n<span class=\"wr-rotating-text__sr-only\">{{ current() }}</span>\n\n<!-- Animated visual content. -->\n<span class=\"wr-rotating-text__inner\" aria-hidden=\"true\">\n @for (word of words(); track $index) {\n <span class=\"wr-rotating-text__word\">\n @for (char of word.characters; track $index) {\n <span class=\"wr-rotating-text__char\">{{ char }}</span>\n }\n @if (word.needsSpace) {\n <span class=\"wr-rotating-text__space\"> </span>\n }\n </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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"}
|
|
1
|
+
{"version":3,"file":"ngwr-rotating-text.mjs","sources":["../../../projects/lib/rotating-text/rotating-text.ts","../../../projects/lib/rotating-text/rotating-text.html","../../../projects/lib/rotating-text/ngwr-rotating-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 RotatingText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/rotating-text\n *\n * The reactbits version uses `motion/react` + `AnimatePresence`. This\n * port is dependency-free — vanilla DOM split + Web Animations API for\n * the enter/exit transitions.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrRotatingTextSplit, WrRotatingTextStaggerFrom } from './interfaces';\n\nconst DEFAULT_EASING = 'cubic-bezier(0.16, 1, 0.3, 1)';\n\ninterface Word {\n readonly characters: readonly string[];\n readonly needsSpace: boolean;\n}\n\nfunction graphemes(text: string): readonly string[] {\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n const seg = new Intl.Segmenter('en', { granularity: 'grapheme' });\n return Array.from(seg.segment(text), s => s.segment);\n }\n return Array.from(text);\n}\n\nfunction splitWords(text: string, by: WrRotatingTextSplit): readonly Word[] {\n if (!text) return [];\n if (by === 'lines') {\n const lines = text.split('\\n');\n return lines.map((line, i) => ({ characters: [line], needsSpace: i !== lines.length - 1 }));\n }\n if (by === 'words') {\n const words = text.split(' ');\n return words.map((w, i) => ({ characters: [w], needsSpace: i !== words.length - 1 }));\n }\n // characters: split each word into graphemes, keep word boundaries for spacing.\n const words = text.split(' ');\n return words.map((w, i) => ({ characters: graphemes(w), needsSpace: i !== words.length - 1 }));\n}\n\n/**\n * Cycles through a list of strings, animating each transition\n * character-by-character (or word/line). Auto-advances on a timer by\n * default; can also be controlled imperatively via `next()` /\n * `previous()` / `jumpTo()` / `reset()`.\n *\n * @example\n * ```html\n * <wr-rotating-text [texts]=\"['design', 'ship', 'iterate']\" />\n *\n * // Manual control:\n * @ViewChild(WrRotatingText) rotator!: WrRotatingText;\n * onClick(): void { this.rotator.next(); }\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/rotating-text\n */\n@Component({\n selector: 'wr-rotating-text',\n templateUrl: './rotating-text.html',\n styleUrl: './rotating-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-rotating-text' },\n})\nexport class WrRotatingText {\n /** Strings to cycle. Required. */\n readonly texts = input.required<readonly string[]>();\n\n /** Auto-advance interval in ms. @default 2000 */\n readonly rotationInterval = input(2000, { transform: numAttr(2000) });\n\n /** Granularity of the split. @default 'characters' */\n readonly splitBy = input<WrRotatingTextSplit>('characters');\n\n /** Auto-advance on a timer. @default true */\n readonly auto = input(true, { transform: coerceBooleanProperty });\n\n /** Loop back to the first string after the last. @default true */\n readonly loop = input(true, { transform: coerceBooleanProperty });\n\n /** Per-swap tween duration in seconds. @default 0.6 */\n readonly duration = input(0.6, { transform: numAttr(0.6) });\n\n /** CSS easing of the per-piece tween. @default 'cubic-bezier(0.16, 1, 0.3, 1)' (~power3.out) */\n readonly easing = input(DEFAULT_EASING);\n\n /** Per-piece stagger in seconds. @default 0 */\n readonly staggerDuration = input(0, { transform: numAttr(0) });\n\n /** Stagger origin. @default 'first' */\n readonly staggerFrom = input<WrRotatingTextStaggerFrom>('first');\n\n /** Emitted with the new index on every rotation. */\n readonly nextChange = output<number>();\n\n protected readonly index = signal(0);\n\n protected readonly current = computed(() => {\n const arr = this.texts();\n return arr.length === 0 ? '' : arr[Math.min(this.index(), arr.length - 1)];\n });\n\n protected readonly words = computed<readonly Word[]>(() => splitWords(this.current(), this.splitBy()));\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private timerId: ReturnType<typeof setInterval> | undefined;\n private isAnimating = false;\n private destroyed = false;\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => this.animateIn());\n\n // Restart the timer when interval / auto change.\n effect(() => {\n this.rotationInterval();\n this.auto();\n this.restartTimer();\n });\n\n this.destroyRef.onDestroy(() => {\n clearInterval(this.timerId);\n this.destroyed = true;\n });\n }\n\n // Public imperative API\n\n next(): void {\n const arr = this.texts();\n if (arr.length === 0) return;\n const cur = this.index();\n const last = arr.length - 1;\n const target = cur === last ? (this.loop() ? 0 : cur) : cur + 1;\n if (target !== cur) void this.transitionTo(target);\n }\n\n previous(): void {\n const arr = this.texts();\n if (arr.length === 0) return;\n const cur = this.index();\n const last = arr.length - 1;\n const target = cur === 0 ? (this.loop() ? last : cur) : cur - 1;\n if (target !== cur) void this.transitionTo(target);\n }\n\n jumpTo(target: number): void {\n const arr = this.texts();\n if (arr.length === 0) return;\n const clamped = Math.max(0, Math.min(target, arr.length - 1));\n if (clamped !== this.index()) void this.transitionTo(clamped);\n }\n\n reset(): void {\n if (this.index() !== 0) void this.transitionTo(0);\n }\n\n // Internals\n\n private restartTimer(): void {\n clearInterval(this.timerId);\n if (!this.auto()) return;\n this.timerId = setInterval(() => this.next(), this.rotationInterval());\n }\n\n private async transitionTo(target: number): Promise<void> {\n if (this.isAnimating) return;\n this.isAnimating = true;\n\n await this.animateOut();\n\n // `animateOut` is an async gap, and a transition already in flight outlives\n // the component: navigating away destroys it, and `clearInterval` only\n // stops FUTURE ticks — not this call. Everything below touches the view, so\n // resuming on a destroyed component throws NG0911 (\"View has already been\n // destroyed\") and warns NG0953 (emit on a destroyed `OutputRef`).\n if (this.destroyed) return;\n\n this.index.set(target);\n this.nextChange.emit(target);\n // Animate in only AFTER Angular has rendered the new word's spans. A single\n // microtask isn't enough under zoneless change detection — the re-render\n // hasn't flushed yet, so `animateIn()` would query the OLD spans, animate\n // them, and then the render would swap their content mid-flight (and any\n // spans the longer word adds would never get animated). `afterNextRender`\n // fires after the render the `index` change schedules.\n afterNextRender(\n () => {\n this.animateIn();\n this.isAnimating = false;\n },\n { injector: this.injector }\n );\n }\n\n private animateIn(): void {\n const targets = this.host.nativeElement.querySelectorAll<HTMLElement>('.wr-rotating-text__char');\n if (targets.length === 0) return;\n\n // Reduced motion: the word swap itself is content and keeps cycling,\n // but each swap is instant — no per-char rise/fall tween.\n if (this.platform.prefersReducedMotion()) {\n targets.forEach(el => {\n el.style.opacity = '1';\n el.style.transform = 'translate3d(0, 0, 0)';\n });\n return;\n }\n\n const stagger = this.staggerDuration() * 1000;\n targets.forEach((el, i) => {\n const delay = this.delayFor(i, targets.length, stagger);\n el.style.opacity = '0';\n el.style.transform = 'translate3d(0, 100%, 0)';\n const anim = el.animate(\n [\n { opacity: 0, transform: 'translate3d(0, 100%, 0)' },\n { opacity: 1, transform: 'translate3d(0, 0, 0)' },\n ],\n { duration: this.duration() * 1000, delay, easing: this.easing(), fill: 'forwards' }\n );\n anim.onfinish = (): void => {\n el.style.opacity = '1';\n el.style.transform = 'translate3d(0, 0, 0)';\n try {\n anim.cancel();\n } catch {\n /* noop */\n }\n };\n });\n }\n\n private animateOut(): Promise<void> {\n const targets = this.host.nativeElement.querySelectorAll<HTMLElement>('.wr-rotating-text__char');\n if (targets.length === 0) return Promise.resolve();\n if (this.platform.prefersReducedMotion()) return Promise.resolve();\n const stagger = this.staggerDuration() * 1000;\n const promises: Promise<void>[] = [];\n targets.forEach((el, i) => {\n const delay = this.delayFor(i, targets.length, stagger);\n const anim = el.animate(\n [\n { opacity: 1, transform: 'translate3d(0, 0, 0)' },\n { opacity: 0, transform: 'translate3d(0, -120%, 0)' },\n ],\n { duration: this.duration() * 1000, delay, easing: this.easing(), fill: 'forwards' }\n );\n promises.push(\n new Promise<void>(resolve => {\n anim.onfinish = (): void => {\n // Commit the exited (hidden, lifted) state to inline style before\n // cancelling, so the char stays out instead of snapping back to\n // visible-in-place between the swap and the enter animation.\n el.style.opacity = '0';\n el.style.transform = 'translate3d(0, -120%, 0)';\n try {\n anim.cancel();\n } catch {\n /* noop */\n }\n resolve();\n };\n })\n );\n });\n return Promise.all(promises).then(() => undefined);\n }\n\n private delayFor(i: number, total: number, stagger: number): number {\n if (stagger === 0) return 0;\n switch (this.staggerFrom()) {\n case 'last':\n return (total - 1 - i) * stagger;\n case 'center': {\n const center = Math.floor(total / 2);\n return Math.abs(center - i) * stagger;\n }\n case 'first':\n default:\n return i * stagger;\n }\n }\n}\n\nexport type { WrRotatingTextSplit, WrRotatingTextStaggerFrom } from './interfaces';\n","<!--\n The readable text, once: the spans below are per-character. Deliberately NOT a\n live region — `auto` rotates every two seconds by default, and the APG's answer\n for self-advancing content is silence, not an announcement every two seconds.\n-->\n\n<span class=\"wr-rotating-text__sr-only\">{{ current() }}</span>\n\n<!-- Animated visual content. -->\n<span class=\"wr-rotating-text__inner\" aria-hidden=\"true\">\n @for (word of words(); track $index) {\n <span class=\"wr-rotating-text__word\">\n @for (char of word.characters; track $index) {\n <span class=\"wr-rotating-text__char\">{{ char }}</span>\n }\n @if (word.needsSpace) {\n <span class=\"wr-rotating-text__space\"> </span>\n }\n </span>\n }\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;AAAA;;;;;;;;;;;;AAYG;AAyBH,MAAM,cAAc,GAAG,+BAA+B;AAOtD,SAAS,SAAS,CAAC,IAAY,EAAA;IAC7B,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,WAAW,IAAI,IAAI,EAAE;AACtD,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC;AACjE,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IACtD;AACA,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACzB;AAEA,SAAS,UAAU,CAAC,IAAY,EAAE,EAAuB,EAAA;AACvD,IAAA,IAAI,CAAC,IAAI;AAAE,QAAA,OAAO,EAAE;AACpB,IAAA,IAAI,EAAE,KAAK,OAAO,EAAE;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;AAC9B,QAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7F;AACA,IAAA,IAAI,EAAE,KAAK,OAAO,EAAE;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,QAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;IACvF;;IAEA,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC7B,IAAA,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;AAChG;AAEA;;;;;;;;;;;;;;;;AAgBG;MAQU,cAAc,CAAA;;IAEhB,KAAK,GAAG,KAAK,CAAC,QAAQ;8EAAqB;;AAG3C,IAAA,gBAAgB,GAAG,KAAK,CAAC,IAAI,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,kBAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,EAAA,CAAG;;IAG5D,OAAO,GAAG,KAAK,CAAsB,YAAY;gFAAC;;IAGlD,IAAI,GAAG,KAAK,CAAC,IAAI,4EAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;IAGxD,IAAI,GAAG,KAAK,CAAC,IAAI,4EAAI,SAAS,EAAE,qBAAqB,EAAA,CAAG;;AAGxD,IAAA,QAAQ,GAAG,KAAK,CAAC,GAAG,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,UAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,EAAA,CAAG;;IAGlD,MAAM,GAAG,KAAK,CAAC,cAAc;+EAAC;;AAG9B,IAAA,eAAe,GAAG,KAAK,CAAC,CAAC,EAAA,EAAA,IAAA,SAAA,GAAA,EAAA,SAAA,EAAA,iBAAA,EAAA,8BAAA,EAAA,CAAA,EAAI,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAA,CAAG;;IAGrD,WAAW,GAAG,KAAK,CAA4B,OAAO;oFAAC;;IAGvD,UAAU,GAAG,MAAM,EAAU;IAEnB,KAAK,GAAG,MAAM,CAAC,CAAC;8EAAC;AAEjB,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAK;AACzC,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;AACxB,QAAA,OAAO,GAAG,CAAC,MAAM,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5E,CAAC;gFAAC;AAEiB,IAAA,KAAK,GAAG,QAAQ,CAAkB,MAAM,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;8EAAC;AAErF,IAAA,IAAI,GAAG,MAAM,CAA0B,UAAU,CAAC;AAClD,IAAA,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;AAC3B,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;AAEtC,IAAA,OAAO;IACP,WAAW,GAAG,KAAK;IACnB,SAAS,GAAG,KAAK;AAEzB,IAAA,WAAA,GAAA;QACE,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE;QAErB,eAAe,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;;QAGvC,MAAM,CAAC,MAAK;YACV,IAAI,CAAC,gBAAgB,EAAE;YACvB,IAAI,CAAC,IAAI,EAAE;YACX,IAAI,CAAC,YAAY,EAAE;AACrB,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAK;AAC7B,YAAA,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3B,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI;AACvB,QAAA,CAAC,CAAC;IACJ;;IAIA,IAAI,GAAA;AACF,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;AACxB,QAAA,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE;AACtB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;AACxB,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC;AAC3B,QAAA,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;QAC/D,IAAI,MAAM,KAAK,GAAG;AAAE,YAAA,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IACpD;IAEA,QAAQ,GAAA;AACN,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;AACxB,QAAA,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE;AACtB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;AACxB,QAAA,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC;AAC3B,QAAA,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;QAC/D,IAAI,MAAM,KAAK,GAAG;AAAE,YAAA,KAAK,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;IACpD;AAEA,IAAA,MAAM,CAAC,MAAc,EAAA;AACnB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE;AACxB,QAAA,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC7D,QAAA,IAAI,OAAO,KAAK,IAAI,CAAC,KAAK,EAAE;AAAE,YAAA,KAAK,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;IAC/D;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC;AAAE,YAAA,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IACnD;;IAIQ,YAAY,GAAA;AAClB,QAAA,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;AAC3B,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE;AAClB,QAAA,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACxE;IAEQ,MAAM,YAAY,CAAC,MAAc,EAAA;QACvC,IAAI,IAAI,CAAC,WAAW;YAAE;AACtB,QAAA,IAAI,CAAC,WAAW,GAAG,IAAI;AAEvB,QAAA,MAAM,IAAI,CAAC,UAAU,EAAE;;;;;;QAOvB,IAAI,IAAI,CAAC,SAAS;YAAE;AAEpB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACtB,QAAA,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;;;;;;;QAO5B,eAAe,CACb,MAAK;YACH,IAAI,CAAC,SAAS,EAAE;AAChB,YAAA,IAAI,CAAC,WAAW,GAAG,KAAK;QAC1B,CAAC,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAC5B;IACH;IAEQ,SAAS,GAAA;AACf,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAc,yBAAyB,CAAC;AAChG,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE;;;AAI1B,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE,EAAE;AACxC,YAAA,OAAO,CAAC,OAAO,CAAC,EAAE,IAAG;AACnB,gBAAA,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AACtB,gBAAA,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,sBAAsB;AAC7C,YAAA,CAAC,CAAC;YACF;QACF;QAEA,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,IAAI;QAC7C,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAI;AACxB,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;AACvD,YAAA,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AACtB,YAAA,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,yBAAyB;AAC9C,YAAA,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB;AACE,gBAAA,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,yBAAyB,EAAE;AACpD,gBAAA,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,sBAAsB,EAAE;aAClD,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CACrF;AACD,YAAA,IAAI,CAAC,QAAQ,GAAG,MAAW;AACzB,gBAAA,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AACtB,gBAAA,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,sBAAsB;AAC3C,gBAAA,IAAI;oBACF,IAAI,CAAC,MAAM,EAAE;gBACf;AAAE,gBAAA,MAAM;;gBAER;AACF,YAAA,CAAC;AACH,QAAA,CAAC,CAAC;IACJ;IAEQ,UAAU,GAAA;AAChB,QAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAc,yBAAyB,CAAC;AAChG,QAAA,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,OAAO,OAAO,CAAC,OAAO,EAAE;AAClD,QAAA,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,EAAE;AAAE,YAAA,OAAO,OAAO,CAAC,OAAO,EAAE;QAClE,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,IAAI;QAC7C,MAAM,QAAQ,GAAoB,EAAE;QACpC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,KAAI;AACxB,YAAA,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;AACvD,YAAA,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CACrB;AACE,gBAAA,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,sBAAsB,EAAE;AACjD,gBAAA,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,0BAA0B,EAAE;aACtD,EACD,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CACrF;YACD,QAAQ,CAAC,IAAI,CACX,IAAI,OAAO,CAAO,OAAO,IAAG;AAC1B,gBAAA,IAAI,CAAC,QAAQ,GAAG,MAAW;;;;AAIzB,oBAAA,EAAE,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG;AACtB,oBAAA,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,0BAA0B;AAC/C,oBAAA,IAAI;wBACF,IAAI,CAAC,MAAM,EAAE;oBACf;AAAE,oBAAA,MAAM;;oBAER;AACA,oBAAA,OAAO,EAAE;AACX,gBAAA,CAAC;YACH,CAAC,CAAC,CACH;AACH,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,SAAS,CAAC;IACpD;AAEQ,IAAA,QAAQ,CAAC,CAAS,EAAE,KAAa,EAAE,OAAe,EAAA;QACxD,IAAI,OAAO,KAAK,CAAC;AAAE,YAAA,OAAO,CAAC;AAC3B,QAAA,QAAQ,IAAI,CAAC,WAAW,EAAE;AACxB,YAAA,KAAK,MAAM;gBACT,OAAO,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO;YAClC,KAAK,QAAQ,EAAE;gBACb,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;gBACpC,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,OAAO;YACvC;AACA,YAAA,KAAK,OAAO;AACZ,YAAA;gBACE,OAAO,CAAC,GAAG,OAAO;;IAExB;uGAhOW,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,i0CC3F3B,0wBAqBA,EAAA,MAAA,EAAA,CAAA,8eAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FDsEa,cAAc,EAAA,UAAA,EAAA,CAAA;kBAP1B,SAAS;+BACE,kBAAkB,EAAA,aAAA,EAGb,iBAAiB,CAAC,IAAI,QAC/B,EAAE,KAAK,EAAE,kBAAkB,EAAE,EAAA,QAAA,EAAA,0wBAAA,EAAA,MAAA,EAAA,CAAA,8eAAA,CAAA,EAAA;;;AEzFrC;;AAEG;;"}
|
|
@@ -188,10 +188,10 @@ class WrSchemaForm {
|
|
|
188
188
|
return out;
|
|
189
189
|
}, /* @ts-ignore */
|
|
190
190
|
...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
|
|
191
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
192
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
191
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrSchemaForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
192
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.7", type: WrSchemaForm, isStandalone: true, selector: "wr-schema-form", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.grid-template-columns": "template()" }, classAttribute: "wr-schema-form" }, ngImport: i0, template: "@for (f of fields(); track f.key) {\n @let state = f.field();\n\n <!-- Angular's `hidden()` does not hide anything on its own; the docs are\n explicit that the template has to honour it. -->\n @if (!state.hidden()) {\n <div class=\"wr-schema-form__field\" [style.grid-column]=\"f.column\">\n <wr-form-field [label]=\"f.labelAbove\" [hint]=\"f.spec.hint ?? ''\" [required]=\"state.required()\">\n @switch (f.spec.kind) {\n @case ('textarea') {\n <wr-textarea [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('number') {\n <wr-input-number\n [formField]=\"f.field\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n [step]=\"f.spec.step ?? 1\"\n [ariaLabel]=\"f.label\"\n />\n }\n @case ('select') {\n <wr-select [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? null\" [ariaLabel]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-option [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-option>\n }\n </wr-select>\n }\n @case ('checkbox') {\n <wr-checkbox [formField]=\"f.field\">{{ f.label }}</wr-checkbox>\n }\n @case ('switch') {\n <wr-switch [formField]=\"f.field\">{{ f.label }}</wr-switch>\n }\n @case ('radio') {\n <!-- `wr-radio-group` has no `ariaLabel` input, and needs none: its\n host is a `role=\"radiogroup\"`, where `aria-label` is legal. -->\n <wr-radio-group [formField]=\"f.field\" [attr.aria-label]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-radio [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-radio>\n }\n </wr-radio-group>\n }\n @case ('date') {\n <wr-date-picker [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('slider') {\n <wr-slider [formField]=\"f.field\" [step]=\"f.spec.step ?? 1\" [ariaLabel]=\"f.label\" />\n }\n @default {\n <input\n wrInput\n [formField]=\"f.field\"\n [type]=\"f.spec.type ?? 'text'\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n />\n }\n }\n </wr-form-field>\n </div>\n }\n}\n", dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "component", type: WrCheckbox, selector: "wr-checkbox", inputs: ["id", "checkboxValue", "ariaLabel", "checked", "disabled", "readonly", "size", "icon", "indeterminate"], outputs: ["checkedChange", "touch"] }, { kind: "component", type: WrDatePicker, selector: "wr-date-picker", inputs: ["mode", "format", "placeholder", "min", "max", "dateFilter", "timeFormat", "showSeconds", "step", "disabled", "readonly", "value", "ariaLabel", "panelAriaLabel"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrFormField, selector: "wr-form-field", inputs: ["label", "hint", "required", "optional", "optionalLabel", "controlId", "autoErrors"] }, { kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["size", "rounded"] }, { kind: "component", type: WrInputNumber, selector: "wr-input-number", inputs: ["min", "max", "step", "decimals", "showSteppers", "size", "rounded", "prefix", "suffix", "placeholder", "ariaLabel", "incrementLabel", "decrementLabel", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrOption, selector: "wr-option", inputs: ["value", "disabled", "label"] }, { kind: "component", type: WrRadio, selector: "wr-radio", inputs: ["id", "value", "icon", "size", "disabled"] }, { kind: "component", type: WrRadioGroup, selector: "wr-radio-group", inputs: ["name", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrSelect, selector: "wr-select", inputs: ["placeholder", "clearLabel", "ariaLabel", "disabled", "readonly", "rounded", "size", "responsive", "mode", "searchable", "searchQuery", "options", "displayWith", "loader", "serverSearch", "debounceMs", "minChars", "freeText", "virtualScroll", "rowHeight", "viewportHeight", "overscan", "noResultsText", "loadingText", "loading", "separators", "allowDuplicates", "validate", "clearable", "maxItems", "maxTagCount", "value"], outputs: ["searchQueryChange", "searchChange", "valueChange", "touch"] }, { kind: "component", type: WrSlider, selector: "wr-slider", inputs: ["min", "max", "step", "range", "disabled", "readonly", "showLabel", "ariaLabel", "upperLabel", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrSwitch, selector: "wr-switch", inputs: ["ariaLabel", "id", "disabled", "readonly", "size", "checked"], outputs: ["checkedChange", "touch"] }, { kind: "component", type: WrTextarea, selector: "wr-textarea", inputs: ["placeholder", "ariaLabel", "size", "rows", "resizable", "resize", "readonly", "autosize", "maxRows", "disabled", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
193
193
|
}
|
|
194
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
194
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrSchemaForm, decorators: [{
|
|
195
195
|
type: Component,
|
|
196
196
|
args: [{ selector: 'wr-schema-form', encapsulation: ViewEncapsulation.None, imports: [
|
|
197
197
|
FormField,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-schema-form.mjs","sources":["../../../projects/lib/schema-form/schema-form.ts","../../../projects/lib/schema-form/schema-form.html","../../../projects/lib/schema-form/ngwr-schema-form.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 { Component, ViewEncapsulation, computed, input, isDevMode } from '@angular/core';\nimport { FormField, type Field, type FieldTree, isFieldTree } from '@angular/forms/signals';\n\nimport { WrCheckbox } from 'ngwr/checkbox';\nimport { WrDatePicker } from 'ngwr/date-picker';\nimport { WR_FIELD, WrFormField, wrFieldLabel, type WrFieldSpec } from 'ngwr/form';\nimport { WrInput } from 'ngwr/input';\nimport { WrInputNumber } from 'ngwr/input-number';\nimport { WrRadio, WrRadioGroup } from 'ngwr/radio';\nimport { WrOption, WrSelect } from 'ngwr/select';\nimport { WrSlider } from 'ngwr/slider';\nimport { WrSwitch } from 'ngwr/switch';\nimport { WrTextarea } from 'ngwr/textarea';\nimport { numAttr } from 'ngwr/utils';\n\n/** One field the template draws, resolved once per schema change. */\ninterface WrRenderedField {\n readonly key: string;\n readonly field: Field<never>;\n readonly spec: WrFieldSpec;\n /** `spec.label`, or the key de-camel-cased. */\n readonly label: string;\n /**\n * The same text, or `''` for the two kinds that carry their own label inside\n * the control. Resolved here rather than in the template: a method call in a\n * template is re-run on every pass, and this is decided once per schema.\n */\n readonly labelAbove: string;\n /** `grid-column`, already clamped to the form's own `columns`. */\n readonly column: string;\n}\n\n/**\n * The two kinds that carry their own label. Everything else gets one above the\n * control, from `<wr-form-field>`.\n */\nconst SELF_LABELLING = new Set<WrFieldSpec['kind']>(['checkbox', 'switch']);\n\n/** What each kind writes into the model, for the dev-mode mismatch warning. */\nconst EXPECTED_TYPE: Partial<Record<WrFieldSpec['kind'], string>> = {\n input: 'string',\n textarea: 'string',\n number: 'number',\n checkbox: 'boolean',\n switch: 'boolean',\n slider: 'number',\n};\n\n/**\n * Warn when a group's described fields are about to be drawn by nothing.\n *\n * A field tree is iterated one level deep, so an object-valued field with no\n * `WR_FIELD` of its own is skipped exactly like an undescribed leaf — and its\n * children go with it. That is the right default (a model nests for reasons\n * that have nothing to do with a screen), but it is indistinguishable from a\n * half-drawn form: nothing is missing from the DOM, so nothing looks wrong.\n *\n * Describing the children and getting none of them is never intentional, so\n * that exact shape is what this reports. A group whose children carry no spec\n * either is silent, because it is a model detail this screen does not render.\n */\nfunction warnOnUndrawnGroup(key: string, group: unknown): void {\n // A field tree over a primitive is not iterable, and every undescribed leaf\n // arrives here — so the guard is what keeps this from throwing on the common\n // case rather than a defence against an exotic one.\n const subfields = (group as Partial<Iterable<[string, unknown]>>)[Symbol.iterator];\n if (typeof subfields !== 'function') return;\n\n let described = 0;\n for (const [, child] of group as Iterable<[string, unknown]>) {\n if (isFieldTree(child) && (child as Field<never>)().metadata(WR_FIELD)?.()) described++;\n }\n if (described === 0) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] <wr-schema-form>: \"${key}\" is a group holding ${described} described ` +\n `field(s), and none of them are drawn — a field tree is walked one level deep. ` +\n `Draw the group with a second <wr-schema-form [field]=\"form.${key}\" />, or give ` +\n `\"${key}\" a WR_FIELD of its own if this screen is meant to skip it.`\n );\n}\n\n/**\n * Warn when a `kind` contradicts what the field actually holds.\n *\n * This is the one failure mode of the whole component that nothing else\n * reports: `kind` is a string on a metadata value, so TypeScript cannot hold it\n * against the field's own type, and a `kind: 'number'` on a `string` field\n * renders a `<wr-input-number>` that writes numbers into it forever. The runtime\n * value is the only evidence available, so an empty or nullish one says nothing\n * and is left alone.\n */\nfunction warnOnKindMismatch(f: WrRenderedField): void {\n const expected = EXPECTED_TYPE[f.spec.kind];\n const value = f.field().value();\n if (!expected || value === null || value === undefined || value === '') return;\n if (typeof value === expected) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] <wr-schema-form>: field \"${f.key}\" is described as kind '${f.spec.kind}', ` +\n `which writes a ${expected}, but the field holds a ${typeof value}. ` +\n `The control will overwrite the model with the wrong type.`\n );\n}\n\n/**\n * A form drawn from a Signal Forms schema — one `<wr-form-field>`, one control\n * and one set of error messages per described field, laid out on a grid.\n *\n * The presentation rides on the SAME schema as the validation, through the\n * `WR_FIELD` metadata key from `ngwr/form`:\n *\n * ```ts\n * const profile = form(model, path => {\n * required(path.email);\n * email(path.email);\n * metadata(path.email, WR_FIELD, () => ({ kind: 'input', type: 'email' }));\n * metadata(path.role, WR_FIELD, () => ({ kind: 'select', options: ROLES }));\n * });\n * ```\n * ```html\n * <wr-schema-form [field]=\"profile\" [columns]=\"2\" />\n * ```\n *\n * **A field with no `WR_FIELD` metadata is skipped**, silently and on purpose: a\n * schema may describe more than one screen renders, and guessing a control from\n * a field's type would draw a `wr-switch` for every boolean flag in the model.\n * Order is the model's own key order.\n *\n * **`required`, `disabled`, `readonly` and `hidden` are NOT in the spec.** They\n * are Angular's own schema functions, `[formField]` already applies the first\n * three to the control, and this component reads `hidden()` to decide whether to\n * draw the field at all — which Angular's docs say a template has to do itself.\n * Re-declaring any of them here would be a second source of truth for state the\n * form already owns.\n *\n * **Why its own entry point rather than `ngwr/form`.** Drawing nine kinds means\n * depending on nine controls, and `ngwr/form` is the layout primitive every\n * form imports — folding this in would put a date picker and a slider into the\n * bundle of an app that only wanted `<wr-form-field>`.\n *\n * @see https://ngwr.dev/reference/components/schema-form\n */\n@Component({\n selector: 'wr-schema-form',\n templateUrl: './schema-form.html',\n encapsulation: ViewEncapsulation.None,\n imports: [\n FormField,\n WrCheckbox,\n WrDatePicker,\n WrFormField,\n WrInput,\n WrInputNumber,\n WrOption,\n WrRadio,\n WrRadioGroup,\n WrSelect,\n WrSlider,\n WrSwitch,\n WrTextarea,\n ],\n host: {\n class: 'wr-schema-form',\n '[style.grid-template-columns]': 'template()',\n },\n})\nexport class WrSchemaForm<T extends object> {\n // Generic, rather than `FieldTree<Record<string, unknown>>`, because a model\n // declared as an `interface` has no index signature and is not assignable to\n // that: every consumer would have had to declare their model as a type alias\n // just to bind it. `T extends object` still refuses a field tree over a\n // primitive, which has no subfields and would draw nothing.\n /**\n * The form to draw — the value `form()` returned, or any object-valued field\n * inside one.\n */\n readonly field = input.required<FieldTree<T>>();\n\n /**\n * Grid columns. A field spans one of them unless its spec says otherwise.\n * @default 1\n */\n readonly columns = input(1, { transform: numAttr(1) });\n\n /**\n * The track list, written as a style rather than published as a\n * `--wr-schema-form-columns` hook: `columns` always has a value, so the\n * inline style would win over any declaration a consumer wrote and the hook\n * would be one nobody could use.\n */\n protected readonly template = computed(() => `repeat(${Math.max(1, this.columns())}, minmax(0, 1fr))`);\n\n /**\n * The described fields, in the model's key order.\n *\n * A field tree over an object is iterable as `[key, field]` pairs, which is\n * the whole reason this component needs no field list of its own. `isFieldTree`\n * guards the pair: a model carrying a method or a non-field property would\n * otherwise be read as a field and answer `undefined` to everything.\n */\n protected readonly fields = computed<readonly WrRenderedField[]>(() => {\n const columns = this.columns();\n const out: WrRenderedField[] = [];\n\n for (const [key, child] of this.field() as unknown as Iterable<[string, unknown]>) {\n if (!isFieldTree(child)) continue;\n\n const field = child as Field<never>;\n const spec = field().metadata(WR_FIELD)?.();\n if (!spec) {\n if (isDevMode()) warnOnUndrawnGroup(key, child);\n continue;\n }\n\n const label = spec.label ?? wrFieldLabel(key);\n const span = Math.min(Math.max(Math.round(spec.span ?? 1), 1), columns);\n out.push({\n key,\n field,\n spec,\n label,\n labelAbove: SELF_LABELLING.has(spec.kind) ? '' : label,\n column: `span ${span}`,\n });\n }\n\n if (isDevMode()) out.forEach(f => warnOnKindMismatch(f));\n return out;\n });\n}\n","@for (f of fields(); track f.key) {\n @let state = f.field();\n\n <!-- Angular's `hidden()` does not hide anything on its own; the docs are\n explicit that the template has to honour it. -->\n @if (!state.hidden()) {\n <div class=\"wr-schema-form__field\" [style.grid-column]=\"f.column\">\n <wr-form-field [label]=\"f.labelAbove\" [hint]=\"f.spec.hint ?? ''\" [required]=\"state.required()\">\n @switch (f.spec.kind) {\n @case ('textarea') {\n <wr-textarea [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('number') {\n <wr-input-number\n [formField]=\"f.field\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n [step]=\"f.spec.step ?? 1\"\n [ariaLabel]=\"f.label\"\n />\n }\n @case ('select') {\n <wr-select [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? null\" [ariaLabel]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-option [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-option>\n }\n </wr-select>\n }\n @case ('checkbox') {\n <wr-checkbox [formField]=\"f.field\">{{ f.label }}</wr-checkbox>\n }\n @case ('switch') {\n <wr-switch [formField]=\"f.field\">{{ f.label }}</wr-switch>\n }\n @case ('radio') {\n <!-- `wr-radio-group` has no `ariaLabel` input, and needs none: its\n host is a `role=\"radiogroup\"`, where `aria-label` is legal. -->\n <wr-radio-group [formField]=\"f.field\" [attr.aria-label]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-radio [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-radio>\n }\n </wr-radio-group>\n }\n @case ('date') {\n <wr-date-picker [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('slider') {\n <wr-slider [formField]=\"f.field\" [step]=\"f.spec.step ?? 1\" [ariaLabel]=\"f.label\" />\n }\n @default {\n <input\n wrInput\n [formField]=\"f.field\"\n [type]=\"f.spec.type ?? 'text'\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n />\n }\n }\n </wr-form-field>\n </div>\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-schema-form.mjs","sources":["../../../projects/lib/schema-form/schema-form.ts","../../../projects/lib/schema-form/schema-form.html","../../../projects/lib/schema-form/ngwr-schema-form.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 { Component, ViewEncapsulation, computed, input, isDevMode } from '@angular/core';\nimport { FormField, type Field, type FieldTree, isFieldTree } from '@angular/forms/signals';\n\nimport { WrCheckbox } from 'ngwr/checkbox';\nimport { WrDatePicker } from 'ngwr/date-picker';\nimport { WR_FIELD, WrFormField, wrFieldLabel, type WrFieldSpec } from 'ngwr/form';\nimport { WrInput } from 'ngwr/input';\nimport { WrInputNumber } from 'ngwr/input-number';\nimport { WrRadio, WrRadioGroup } from 'ngwr/radio';\nimport { WrOption, WrSelect } from 'ngwr/select';\nimport { WrSlider } from 'ngwr/slider';\nimport { WrSwitch } from 'ngwr/switch';\nimport { WrTextarea } from 'ngwr/textarea';\nimport { numAttr } from 'ngwr/utils';\n\n/** One field the template draws, resolved once per schema change. */\ninterface WrRenderedField {\n readonly key: string;\n readonly field: Field<never>;\n readonly spec: WrFieldSpec;\n /** `spec.label`, or the key de-camel-cased. */\n readonly label: string;\n /**\n * The same text, or `''` for the two kinds that carry their own label inside\n * the control. Resolved here rather than in the template: a method call in a\n * template is re-run on every pass, and this is decided once per schema.\n */\n readonly labelAbove: string;\n /** `grid-column`, already clamped to the form's own `columns`. */\n readonly column: string;\n}\n\n/**\n * The two kinds that carry their own label. Everything else gets one above the\n * control, from `<wr-form-field>`.\n */\nconst SELF_LABELLING = new Set<WrFieldSpec['kind']>(['checkbox', 'switch']);\n\n/** What each kind writes into the model, for the dev-mode mismatch warning. */\nconst EXPECTED_TYPE: Partial<Record<WrFieldSpec['kind'], string>> = {\n input: 'string',\n textarea: 'string',\n number: 'number',\n checkbox: 'boolean',\n switch: 'boolean',\n slider: 'number',\n};\n\n/**\n * Warn when a group's described fields are about to be drawn by nothing.\n *\n * A field tree is iterated one level deep, so an object-valued field with no\n * `WR_FIELD` of its own is skipped exactly like an undescribed leaf — and its\n * children go with it. That is the right default (a model nests for reasons\n * that have nothing to do with a screen), but it is indistinguishable from a\n * half-drawn form: nothing is missing from the DOM, so nothing looks wrong.\n *\n * Describing the children and getting none of them is never intentional, so\n * that exact shape is what this reports. A group whose children carry no spec\n * either is silent, because it is a model detail this screen does not render.\n */\nfunction warnOnUndrawnGroup(key: string, group: unknown): void {\n // A field tree over a primitive is not iterable, and every undescribed leaf\n // arrives here — so the guard is what keeps this from throwing on the common\n // case rather than a defence against an exotic one.\n const subfields = (group as Partial<Iterable<[string, unknown]>>)[Symbol.iterator];\n if (typeof subfields !== 'function') return;\n\n let described = 0;\n for (const [, child] of group as Iterable<[string, unknown]>) {\n if (isFieldTree(child) && (child as Field<never>)().metadata(WR_FIELD)?.()) described++;\n }\n if (described === 0) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] <wr-schema-form>: \"${key}\" is a group holding ${described} described ` +\n `field(s), and none of them are drawn — a field tree is walked one level deep. ` +\n `Draw the group with a second <wr-schema-form [field]=\"form.${key}\" />, or give ` +\n `\"${key}\" a WR_FIELD of its own if this screen is meant to skip it.`\n );\n}\n\n/**\n * Warn when a `kind` contradicts what the field actually holds.\n *\n * This is the one failure mode of the whole component that nothing else\n * reports: `kind` is a string on a metadata value, so TypeScript cannot hold it\n * against the field's own type, and a `kind: 'number'` on a `string` field\n * renders a `<wr-input-number>` that writes numbers into it forever. The runtime\n * value is the only evidence available, so an empty or nullish one says nothing\n * and is left alone.\n */\nfunction warnOnKindMismatch(f: WrRenderedField): void {\n const expected = EXPECTED_TYPE[f.spec.kind];\n const value = f.field().value();\n if (!expected || value === null || value === undefined || value === '') return;\n if (typeof value === expected) return;\n\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] <wr-schema-form>: field \"${f.key}\" is described as kind '${f.spec.kind}', ` +\n `which writes a ${expected}, but the field holds a ${typeof value}. ` +\n `The control will overwrite the model with the wrong type.`\n );\n}\n\n/**\n * A form drawn from a Signal Forms schema — one `<wr-form-field>`, one control\n * and one set of error messages per described field, laid out on a grid.\n *\n * The presentation rides on the SAME schema as the validation, through the\n * `WR_FIELD` metadata key from `ngwr/form`:\n *\n * ```ts\n * const profile = form(model, path => {\n * required(path.email);\n * email(path.email);\n * metadata(path.email, WR_FIELD, () => ({ kind: 'input', type: 'email' }));\n * metadata(path.role, WR_FIELD, () => ({ kind: 'select', options: ROLES }));\n * });\n * ```\n * ```html\n * <wr-schema-form [field]=\"profile\" [columns]=\"2\" />\n * ```\n *\n * **A field with no `WR_FIELD` metadata is skipped**, silently and on purpose: a\n * schema may describe more than one screen renders, and guessing a control from\n * a field's type would draw a `wr-switch` for every boolean flag in the model.\n * Order is the model's own key order.\n *\n * **`required`, `disabled`, `readonly` and `hidden` are NOT in the spec.** They\n * are Angular's own schema functions, `[formField]` already applies the first\n * three to the control, and this component reads `hidden()` to decide whether to\n * draw the field at all — which Angular's docs say a template has to do itself.\n * Re-declaring any of them here would be a second source of truth for state the\n * form already owns.\n *\n * **Why its own entry point rather than `ngwr/form`.** Drawing nine kinds means\n * depending on nine controls, and `ngwr/form` is the layout primitive every\n * form imports — folding this in would put a date picker and a slider into the\n * bundle of an app that only wanted `<wr-form-field>`.\n *\n * @see https://ngwr.dev/reference/components/schema-form\n */\n@Component({\n selector: 'wr-schema-form',\n templateUrl: './schema-form.html',\n encapsulation: ViewEncapsulation.None,\n imports: [\n FormField,\n WrCheckbox,\n WrDatePicker,\n WrFormField,\n WrInput,\n WrInputNumber,\n WrOption,\n WrRadio,\n WrRadioGroup,\n WrSelect,\n WrSlider,\n WrSwitch,\n WrTextarea,\n ],\n host: {\n class: 'wr-schema-form',\n '[style.grid-template-columns]': 'template()',\n },\n})\nexport class WrSchemaForm<T extends object> {\n // Generic, rather than `FieldTree<Record<string, unknown>>`, because a model\n // declared as an `interface` has no index signature and is not assignable to\n // that: every consumer would have had to declare their model as a type alias\n // just to bind it. `T extends object` still refuses a field tree over a\n // primitive, which has no subfields and would draw nothing.\n /**\n * The form to draw — the value `form()` returned, or any object-valued field\n * inside one.\n */\n readonly field = input.required<FieldTree<T>>();\n\n /**\n * Grid columns. A field spans one of them unless its spec says otherwise.\n * @default 1\n */\n readonly columns = input(1, { transform: numAttr(1) });\n\n /**\n * The track list, written as a style rather than published as a\n * `--wr-schema-form-columns` hook: `columns` always has a value, so the\n * inline style would win over any declaration a consumer wrote and the hook\n * would be one nobody could use.\n */\n protected readonly template = computed(() => `repeat(${Math.max(1, this.columns())}, minmax(0, 1fr))`);\n\n /**\n * The described fields, in the model's key order.\n *\n * A field tree over an object is iterable as `[key, field]` pairs, which is\n * the whole reason this component needs no field list of its own. `isFieldTree`\n * guards the pair: a model carrying a method or a non-field property would\n * otherwise be read as a field and answer `undefined` to everything.\n */\n protected readonly fields = computed<readonly WrRenderedField[]>(() => {\n const columns = this.columns();\n const out: WrRenderedField[] = [];\n\n for (const [key, child] of this.field() as unknown as Iterable<[string, unknown]>) {\n if (!isFieldTree(child)) continue;\n\n const field = child as Field<never>;\n const spec = field().metadata(WR_FIELD)?.();\n if (!spec) {\n if (isDevMode()) warnOnUndrawnGroup(key, child);\n continue;\n }\n\n const label = spec.label ?? wrFieldLabel(key);\n const span = Math.min(Math.max(Math.round(spec.span ?? 1), 1), columns);\n out.push({\n key,\n field,\n spec,\n label,\n labelAbove: SELF_LABELLING.has(spec.kind) ? '' : label,\n column: `span ${span}`,\n });\n }\n\n if (isDevMode()) out.forEach(f => warnOnKindMismatch(f));\n return out;\n });\n}\n","@for (f of fields(); track f.key) {\n @let state = f.field();\n\n <!-- Angular's `hidden()` does not hide anything on its own; the docs are\n explicit that the template has to honour it. -->\n @if (!state.hidden()) {\n <div class=\"wr-schema-form__field\" [style.grid-column]=\"f.column\">\n <wr-form-field [label]=\"f.labelAbove\" [hint]=\"f.spec.hint ?? ''\" [required]=\"state.required()\">\n @switch (f.spec.kind) {\n @case ('textarea') {\n <wr-textarea [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('number') {\n <wr-input-number\n [formField]=\"f.field\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n [step]=\"f.spec.step ?? 1\"\n [ariaLabel]=\"f.label\"\n />\n }\n @case ('select') {\n <wr-select [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? null\" [ariaLabel]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-option [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-option>\n }\n </wr-select>\n }\n @case ('checkbox') {\n <wr-checkbox [formField]=\"f.field\">{{ f.label }}</wr-checkbox>\n }\n @case ('switch') {\n <wr-switch [formField]=\"f.field\">{{ f.label }}</wr-switch>\n }\n @case ('radio') {\n <!-- `wr-radio-group` has no `ariaLabel` input, and needs none: its\n host is a `role=\"radiogroup\"`, where `aria-label` is legal. -->\n <wr-radio-group [formField]=\"f.field\" [attr.aria-label]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-radio [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-radio>\n }\n </wr-radio-group>\n }\n @case ('date') {\n <wr-date-picker [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('slider') {\n <wr-slider [formField]=\"f.field\" [step]=\"f.spec.step ?? 1\" [ariaLabel]=\"f.label\" />\n }\n @default {\n <input\n wrInput\n [formField]=\"f.field\"\n [type]=\"f.spec.type ?? 'text'\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n />\n }\n }\n </wr-form-field>\n </div>\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/fesm2022/ngwr-scroll.mjs
CHANGED
|
@@ -92,10 +92,10 @@ class WrScroll {
|
|
|
92
92
|
else
|
|
93
93
|
container.scrollTo(options);
|
|
94
94
|
}
|
|
95
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
96
|
-
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.
|
|
95
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrScroll, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
96
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.7", ngImport: i0, type: WrScroll });
|
|
97
97
|
}
|
|
98
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
98
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.7", ngImport: i0, type: WrScroll, decorators: [{
|
|
99
99
|
type: Service
|
|
100
100
|
}] });
|
|
101
101
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-scroll.mjs","sources":["../../../projects/lib/scroll/wr-scroll.ts","../../../projects/lib/scroll/ngwr-scroll.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 { WrPlatform } from 'ngwr/platform';\n\nimport type { WrScrollOptions, WrScrollTarget } from './interfaces';\n\n/**\n * Smooth-scroll utility. Resolves `id` / selector / element / coords\n * targets; subtracts an `offset` (for sticky headers); respects\n * `prefers-reduced-motion` — automatically falls back to instant\n * scrolling when the user has opted out.\n *\n * SSR-safe — all methods no-op on the server.\n *\n * @example\n * ```ts\n * const scroll = inject(WrScroll);\n * scroll.to('#section-three', { offset: 80 });\n * scroll.toTop({ smooth: false });\n * scroll.intoView(myEl, { offset: 64 });\n * ```\n *\n * @see https://ngwr.dev/reference/services/scroll\n */\n@Service()\nexport class WrScroll {\n private readonly doc = inject(DOCUMENT);\n private readonly platform = inject(WrPlatform);\n\n /** Scroll to an arbitrary target. */\n to(target: WrScrollTarget, options: WrScrollOptions = {}): void {\n if (!this.platform.isBrowser) return;\n const win = this.doc.defaultView;\n if (!win) return;\n\n const offset = options.offset ?? 0;\n const behavior = this.behavior(options.smooth);\n const container = options.container ?? win;\n\n if (typeof target === 'object' && 'top' in target) {\n this.scroll(container, { top: target.top - offset, left: target.left ?? 0, behavior });\n return;\n }\n\n const el = typeof target === 'string' ? this.resolveSelector(target) : target;\n if (!el) return;\n\n const rect = el.getBoundingClientRect();\n if (container === win) {\n const top = rect.top + win.scrollY - offset;\n this.scroll(container, { top, left: 0, behavior });\n } else {\n const ctx = container as Element;\n const ctxRect = ctx.getBoundingClientRect();\n const top = rect.top - ctxRect.top + ctx.scrollTop - offset;\n this.scroll(container, { top, left: 0, behavior });\n }\n }\n\n /** Convenience for an element — accepts the same options. */\n intoView(el: Element, options: WrScrollOptions = {}): void {\n this.to(el, options);\n }\n\n /** Scroll the page (or container) to the top. */\n toTop(options: WrScrollOptions = {}): void {\n this.to({ top: 0 }, options);\n }\n\n // Internals\n\n private resolveSelector(value: string): Element | null {\n if (value.startsWith('#')) {\n return this.doc.getElementById(value.slice(1));\n }\n try {\n return this.doc.querySelector(value);\n } catch {\n return null;\n }\n }\n\n private behavior(requested: boolean | undefined): ScrollBehavior {\n if (requested === false) return 'auto';\n if (this.platform.prefersReducedMotion()) return 'auto';\n return 'smooth';\n }\n\n private scroll(container: Window | Element, options: ScrollToOptions): void {\n if (container instanceof Window) container.scrollTo(options);\n else container.scrollTo(options);\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-scroll.mjs","sources":["../../../projects/lib/scroll/wr-scroll.ts","../../../projects/lib/scroll/ngwr-scroll.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 { WrPlatform } from 'ngwr/platform';\n\nimport type { WrScrollOptions, WrScrollTarget } from './interfaces';\n\n/**\n * Smooth-scroll utility. Resolves `id` / selector / element / coords\n * targets; subtracts an `offset` (for sticky headers); respects\n * `prefers-reduced-motion` — automatically falls back to instant\n * scrolling when the user has opted out.\n *\n * SSR-safe — all methods no-op on the server.\n *\n * @example\n * ```ts\n * const scroll = inject(WrScroll);\n * scroll.to('#section-three', { offset: 80 });\n * scroll.toTop({ smooth: false });\n * scroll.intoView(myEl, { offset: 64 });\n * ```\n *\n * @see https://ngwr.dev/reference/services/scroll\n */\n@Service()\nexport class WrScroll {\n private readonly doc = inject(DOCUMENT);\n private readonly platform = inject(WrPlatform);\n\n /** Scroll to an arbitrary target. */\n to(target: WrScrollTarget, options: WrScrollOptions = {}): void {\n if (!this.platform.isBrowser) return;\n const win = this.doc.defaultView;\n if (!win) return;\n\n const offset = options.offset ?? 0;\n const behavior = this.behavior(options.smooth);\n const container = options.container ?? win;\n\n if (typeof target === 'object' && 'top' in target) {\n this.scroll(container, { top: target.top - offset, left: target.left ?? 0, behavior });\n return;\n }\n\n const el = typeof target === 'string' ? this.resolveSelector(target) : target;\n if (!el) return;\n\n const rect = el.getBoundingClientRect();\n if (container === win) {\n const top = rect.top + win.scrollY - offset;\n this.scroll(container, { top, left: 0, behavior });\n } else {\n const ctx = container as Element;\n const ctxRect = ctx.getBoundingClientRect();\n const top = rect.top - ctxRect.top + ctx.scrollTop - offset;\n this.scroll(container, { top, left: 0, behavior });\n }\n }\n\n /** Convenience for an element — accepts the same options. */\n intoView(el: Element, options: WrScrollOptions = {}): void {\n this.to(el, options);\n }\n\n /** Scroll the page (or container) to the top. */\n toTop(options: WrScrollOptions = {}): void {\n this.to({ top: 0 }, options);\n }\n\n // Internals\n\n private resolveSelector(value: string): Element | null {\n if (value.startsWith('#')) {\n return this.doc.getElementById(value.slice(1));\n }\n try {\n return this.doc.querySelector(value);\n } catch {\n return null;\n }\n }\n\n private behavior(requested: boolean | undefined): ScrollBehavior {\n if (requested === false) return 'auto';\n if (this.platform.prefersReducedMotion()) return 'auto';\n return 'smooth';\n }\n\n private scroll(container: Window | Element, options: ScrollToOptions): void {\n if (container instanceof Window) container.scrollTo(options);\n else container.scrollTo(options);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|