ngwr 11.2.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/burger/styles/_index.scss +1 -1
- package/button/styles/_index.scss +2 -2
- package/calendar/styles/_index.scss +32 -12
- package/calendar-heatmap/styles/_index.scss +20 -0
- package/carousel/styles/_index.scss +23 -1
- package/cascader/styles/_index.scss +15 -3
- package/checkbox/styles/_index.scss +2 -2
- package/collapse/styles/_index.scss +2 -2
- package/color-picker/styles/_index.scss +3 -3
- package/compare/styles/_index.scss +18 -2
- package/context-menu/styles/_index.scss +21 -2
- package/date-picker/styles/_index.scss +5 -5
- package/descriptions/styles/_index.scss +1 -1
- package/drag-drop/styles/_index.scss +28 -1
- package/drawer/styles/_index.scss +37 -0
- package/dropdown/styles/_index.scss +2 -2
- package/event-calendar/styles/_index.scss +67 -10
- package/fesm2022/ngwr-action-sheet.mjs +3 -3
- package/fesm2022/ngwr-affix.mjs +3 -3
- package/fesm2022/ngwr-alert.mjs +3 -3
- package/fesm2022/ngwr-anchor.mjs +3 -3
- package/fesm2022/ngwr-aurora.mjs +3 -3
- package/fesm2022/ngwr-avatar.mjs +3 -3
- package/fesm2022/ngwr-back-top.mjs +3 -3
- package/fesm2022/ngwr-badge.mjs +6 -6
- package/fesm2022/ngwr-bar-chart-testing.mjs +20 -2
- package/fesm2022/ngwr-bar-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-bar-chart.mjs +3 -3
- package/fesm2022/ngwr-blur-text.mjs +3 -3
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow.mjs +4 -4
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +29 -17
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-burger.mjs +3 -3
- package/fesm2022/ngwr-button.mjs +6 -6
- package/fesm2022/ngwr-calendar-heatmap.mjs +17 -5
- package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-testing.mjs +1 -1
- package/fesm2022/ngwr-calendar-testing.mjs.map +1 -1
- package/fesm2022/ngwr-calendar.mjs +187 -9
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-card.mjs +10 -10
- package/fesm2022/ngwr-card.mjs.map +1 -1
- package/fesm2022/ngwr-carousel.mjs +124 -24
- package/fesm2022/ngwr-carousel.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +48 -5
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +6 -6
- package/fesm2022/ngwr-circular-text.mjs +4 -4
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-click-spark.mjs +27 -7
- package/fesm2022/ngwr-click-spark.mjs.map +1 -1
- package/fesm2022/ngwr-clipboard.mjs +3 -3
- package/fesm2022/ngwr-collapse.mjs +9 -9
- package/fesm2022/ngwr-color-picker-testing.mjs +26 -6
- package/fesm2022/ngwr-color-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-color-picker.mjs +98 -8
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +14 -5
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-compare.mjs +3 -3
- package/fesm2022/ngwr-confetti.mjs +31 -6
- package/fesm2022/ngwr-confetti.mjs.map +1 -1
- package/fesm2022/ngwr-config.mjs +9 -0
- package/fesm2022/ngwr-config.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu-testing.mjs +30 -11
- package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +333 -43
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-cookie.mjs +3 -3
- package/fesm2022/ngwr-counter.mjs +25 -9
- package/fesm2022/ngwr-counter.mjs.map +1 -1
- package/fesm2022/{ngwr-date-adapter-fns.mjs → ngwr-date-adapters-fns.mjs} +37 -10
- package/fesm2022/ngwr-date-adapters-fns.mjs.map +1 -0
- package/fesm2022/{ngwr-date-adapter-luxon.mjs → ngwr-date-adapters-luxon.mjs} +5 -5
- package/fesm2022/ngwr-date-adapters-luxon.mjs.map +1 -0
- package/fesm2022/ngwr-date-picker-testing.mjs +11 -6
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker.mjs +119 -37
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/{ngwr-date-adapter.mjs → ngwr-date.mjs} +36 -10
- package/fesm2022/ngwr-date.mjs.map +1 -0
- package/fesm2022/ngwr-decrypt-text.mjs +3 -3
- package/fesm2022/ngwr-density.mjs +6 -6
- package/fesm2022/ngwr-descriptions.mjs +6 -6
- package/fesm2022/ngwr-dialog.mjs +73 -18
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +12 -12
- package/fesm2022/ngwr-divider.mjs +52 -5
- package/fesm2022/ngwr-divider.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart-testing.mjs +8 -4
- package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart.mjs +7 -7
- package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +160 -11
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +121 -58
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +26 -10
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-empty.mjs +3 -3
- package/fesm2022/ngwr-event-calendar.mjs +28 -15
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text-testing.mjs +5 -3
- package/fesm2022/ngwr-falling-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text.mjs +75 -46
- package/fesm2022/ngwr-falling-text.mjs.map +1 -1
- package/fesm2022/ngwr-file-upload.mjs +3 -3
- package/fesm2022/ngwr-form.mjs +32 -15
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +21 -11
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-gauge.mjs +3 -3
- package/fesm2022/ngwr-glitch-text-testing.mjs +51 -17
- package/fesm2022/ngwr-glitch-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-glitch-text.mjs +7 -7
- package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text-testing.mjs +46 -11
- package/fesm2022/ngwr-gradient-text-testing.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text.mjs +4 -4
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
- package/fesm2022/ngwr-hotkey.mjs +24 -9
- package/fesm2022/ngwr-hotkey.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +73 -1
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +55 -1
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n.mjs +26 -15
- package/fesm2022/ngwr-i18n.mjs.map +1 -1
- package/fesm2022/ngwr-icon.mjs +6 -6
- package/fesm2022/ngwr-image-cropper-testing.mjs +53 -9
- package/fesm2022/ngwr-image-cropper-testing.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper.mjs +150 -12
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
- package/fesm2022/ngwr-input-number-testing.mjs +15 -10
- package/fesm2022/ngwr-input-number-testing.mjs.map +1 -1
- package/fesm2022/ngwr-input-number.mjs +17 -10
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp-testing.mjs +12 -6
- package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp.mjs +24 -5
- package/fesm2022/ngwr-input-otp.mjs.map +1 -1
- package/fesm2022/ngwr-input.mjs +15 -15
- package/fesm2022/ngwr-keyboard.mjs +3 -3
- package/fesm2022/ngwr-knob.mjs +3 -3
- package/fesm2022/ngwr-layout.mjs +15 -15
- package/fesm2022/ngwr-lightbox.mjs +4 -4
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart.mjs +73 -26
- package/fesm2022/ngwr-line-chart.mjs.map +1 -1
- package/fesm2022/ngwr-list.mjs +7 -7
- package/fesm2022/ngwr-list.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar.mjs +7 -7
- package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
- package/fesm2022/ngwr-markdown.mjs +66 -8
- package/fesm2022/ngwr-markdown.mjs.map +1 -1
- package/fesm2022/ngwr-marquee.mjs +4 -4
- package/fesm2022/ngwr-marquee.mjs.map +1 -1
- package/fesm2022/ngwr-media.mjs +3 -3
- package/fesm2022/ngwr-mention.mjs +108 -13
- package/fesm2022/ngwr-mention.mjs.map +1 -1
- package/fesm2022/ngwr-meta.mjs +6 -6
- package/fesm2022/ngwr-meter-group-testing.mjs +26 -6
- package/fesm2022/ngwr-meter-group-testing.mjs.map +1 -1
- package/fesm2022/ngwr-meter-group.mjs +3 -3
- package/fesm2022/ngwr-overlay.mjs +6 -6
- package/fesm2022/ngwr-page-header.mjs +3 -3
- package/fesm2022/ngwr-pagination-testing.mjs +6 -6
- package/fesm2022/ngwr-pagination-testing.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +17 -13
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +39 -26
- package/fesm2022/ngwr-pipes.mjs.map +1 -1
- package/fesm2022/ngwr-platform.mjs +9 -9
- package/fesm2022/ngwr-popconfirm.mjs +6 -6
- package/fesm2022/ngwr-popover-testing.mjs +7 -2
- package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +155 -33
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-progress.mjs +3 -3
- package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
- package/fesm2022/ngwr-qr.mjs +42 -5
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-radio.mjs +6 -6
- package/fesm2022/ngwr-rating.mjs +3 -3
- package/fesm2022/ngwr-result.mjs +21 -30
- package/fesm2022/ngwr-result.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text.mjs +3 -3
- package/fesm2022/ngwr-scroll.mjs +3 -3
- package/fesm2022/ngwr-segmented-testing.mjs +14 -1
- package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
- package/fesm2022/ngwr-segmented.mjs +29 -6
- package/fesm2022/ngwr-segmented.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +159 -34
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +11 -9
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-sidebar.mjs +31 -16
- package/fesm2022/ngwr-sidebar.mjs.map +1 -1
- package/fesm2022/ngwr-skeleton.mjs +3 -3
- package/fesm2022/ngwr-slider.mjs +100 -9
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline.mjs +3 -3
- package/fesm2022/ngwr-speed-dial-testing.mjs +15 -13
- package/fesm2022/ngwr-speed-dial-testing.mjs.map +1 -1
- package/fesm2022/ngwr-speed-dial.mjs +27 -12
- package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
- package/fesm2022/ngwr-spinner.mjs +3 -3
- package/fesm2022/ngwr-splash-cursor.mjs +3 -3
- package/fesm2022/ngwr-split-text.mjs +17 -5
- package/fesm2022/ngwr-split-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter.mjs +3 -3
- package/fesm2022/ngwr-spotlight-card.mjs +7 -7
- package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
- package/fesm2022/ngwr-squircle.mjs +6 -6
- package/fesm2022/ngwr-star-border.mjs +4 -4
- package/fesm2022/ngwr-star-border.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +9 -9
- package/fesm2022/ngwr-stepper-testing.mjs +8 -8
- package/fesm2022/ngwr-stepper-testing.mjs.map +1 -1
- package/fesm2022/ngwr-stepper.mjs +33 -8
- package/fesm2022/ngwr-stepper.mjs.map +1 -1
- package/fesm2022/ngwr-storage.mjs +17 -5
- package/fesm2022/ngwr-storage.mjs.map +1 -1
- package/fesm2022/ngwr-switch.mjs +3 -3
- package/fesm2022/ngwr-table.mjs +99 -39
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs-testing.mjs +11 -10
- package/fesm2022/ngwr-tabs-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +36 -10
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-textarea.mjs +3 -3
- package/fesm2022/ngwr-theme.mjs +181 -4
- package/fesm2022/ngwr-theme.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card.mjs +7 -7
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
- package/fesm2022/ngwr-timeline.mjs +6 -6
- package/fesm2022/ngwr-toast.mjs +9 -9
- package/fesm2022/ngwr-toolbar.mjs +3 -3
- package/fesm2022/ngwr-tour.mjs +34 -10
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-transfer.mjs +3 -3
- package/fesm2022/ngwr-tree.mjs +28 -10
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter-testing.mjs +15 -1
- package/fesm2022/ngwr-typewriter-testing.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter.mjs +13 -5
- package/fesm2022/ngwr-typewriter.mjs.map +1 -1
- package/fesm2022/ngwr-typography.mjs +3 -3
- package/fesm2022/ngwr-utils.mjs +5 -2
- package/fesm2022/ngwr-utils.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 +4 -4
- package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
- package/fesm2022/ngwr-waves.mjs +4 -4
- package/fesm2022/ngwr-waves.mjs.map +1 -1
- package/fesm2022/ngwr-window.mjs +94 -24
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/file-upload/styles/_index.scss +2 -2
- package/glitch-text/styles/_index.scss +27 -12
- package/i18n/en.json +56 -6
- package/i18n/ru.json +56 -6
- package/image-cropper/styles/_index.scss +19 -0
- package/input/styles/_index.scss +2 -2
- package/input-number/styles/_index.scss +2 -2
- package/input-otp/styles/_index.scss +9 -2
- package/knob/styles/_index.scss +1 -1
- package/lightbox/styles/_index.scss +16 -2
- package/line-chart/styles/_index.scss +28 -14
- package/list/styles/_index.scss +1 -1
- package/llms-full.txt +18 -23
- package/llms.txt +22 -6
- package/markdown/styles/_index.scss +3 -3
- package/mcp/api.js +6 -4
- package/mcp/catalog.js +40 -3
- package/mcp/providers.js +16 -3
- package/mcp/tools.js +21 -1
- package/meter-group/styles/_index.scss +1 -1
- package/overlay/styles/_index.scss +33 -1
- package/package.json +17 -12
- package/pagination/styles/_index.scss +23 -1
- package/popover/styles/_index.scss +16 -7
- package/progress/styles/_index.scss +1 -1
- package/radio/styles/_index.scss +2 -2
- package/rating/styles/_index.scss +1 -1
- package/schematics/collection.json +1 -1
- package/schematics/migrations/v12/index.js +65 -0
- package/schematics/migrations/v7/index.js +12 -1
- package/schematics/migrations/v8/index.js +10 -1
- package/schematics/migrations.json +5 -0
- package/schematics/ng-add/index.js +8 -3
- package/schematics/provider/index.js +80 -13
- package/schematics/use/index.js +9 -129
- package/schematics/use/rule.js +206 -0
- package/schematics/use/symbol-map.json +4 -4
- package/segmented/styles/_index.scss +14 -3
- package/select/styles/_index.scss +14 -2
- package/sidebar/styles/_index.scss +12 -10
- package/skills/ngwr/SKILL.md +7 -5
- package/skills/ngwr/references/catalog.md +9 -9
- package/skills/ngwr/references/setup.md +10 -5
- package/slider/styles/_index.scss +1 -1
- package/speed-dial/styles/_index.scss +1 -1
- package/stepper/styles/_index.scss +12 -3
- package/switch/styles/_index.scss +2 -2
- package/table/styles/_index.scss +61 -12
- package/tabs/styles/_index.scss +1 -1
- package/textarea/styles/_index.scss +1 -1
- package/theme/styles/_colors.scss +142 -56
- package/theme/styles/_dark.scss +46 -3
- package/theme/styles/_focus.scss +28 -5
- package/theme/styles/_mixins.scss +1 -1
- package/theme/styles/_variables.scss +67 -0
- package/transfer/styles/_index.scss +26 -3
- package/tree/styles/_index.scss +29 -6
- package/types/ngwr-bar-chart-testing.d.ts +9 -1
- package/types/ngwr-blur-text.d.ts +8 -4
- package/types/ngwr-breadcrumbs.d.ts +17 -10
- package/types/ngwr-calendar-testing.d.ts +1 -1
- package/types/ngwr-calendar.d.ts +66 -0
- package/types/ngwr-carousel.d.ts +85 -6
- package/types/ngwr-cascader.d.ts +17 -0
- package/types/ngwr-click-spark.d.ts +4 -0
- package/types/ngwr-color-picker-testing.d.ts +8 -0
- package/types/ngwr-color-picker.d.ts +21 -1
- package/types/ngwr-confetti.d.ts +8 -0
- package/types/ngwr-config.d.ts +10 -1
- package/types/ngwr-context-menu-testing.d.ts +24 -11
- package/types/ngwr-context-menu.d.ts +56 -0
- package/types/ngwr-counter.d.ts +1 -0
- package/types/{ngwr-date-adapter-fns.d.ts → ngwr-date-adapters-fns.d.ts} +33 -6
- package/types/{ngwr-date-adapter-luxon.d.ts → ngwr-date-adapters-luxon.d.ts} +1 -1
- package/types/ngwr-date-picker-testing.d.ts +11 -6
- package/types/ngwr-date-picker.d.ts +8 -4
- package/types/{ngwr-date-adapter.d.ts → ngwr-date.d.ts} +24 -5
- package/types/ngwr-dialog.d.ts +38 -1
- package/types/ngwr-divider.d.ts +25 -0
- package/types/ngwr-donut-chart-testing.d.ts +7 -3
- package/types/ngwr-donut-chart.d.ts +3 -3
- package/types/ngwr-drag-drop.d.ts +56 -2
- package/types/ngwr-drawer.d.ts +56 -5
- package/types/ngwr-event-calendar.d.ts +8 -2
- package/types/ngwr-falling-text-testing.d.ts +5 -3
- package/types/ngwr-falling-text.d.ts +1 -1
- package/types/ngwr-form.d.ts +12 -2
- package/types/ngwr-glitch-text-testing.d.ts +37 -8
- package/types/ngwr-gradient-text-testing.d.ts +16 -3
- package/types/ngwr-i18n.d.ts +13 -4
- package/types/ngwr-image-cropper-testing.d.ts +49 -10
- package/types/ngwr-image-cropper.d.ts +70 -5
- package/types/ngwr-input-number-testing.d.ts +15 -10
- package/types/ngwr-input-number.d.ts +11 -4
- package/types/ngwr-input-otp-testing.d.ts +12 -6
- package/types/ngwr-input-otp.d.ts +15 -1
- package/types/ngwr-line-chart.d.ts +20 -3
- package/types/ngwr-markdown.d.ts +11 -0
- package/types/ngwr-mention.d.ts +32 -0
- package/types/ngwr-meter-group-testing.d.ts +12 -2
- package/types/ngwr-overlay.d.ts +1 -0
- package/types/ngwr-pagination-testing.d.ts +4 -4
- package/types/ngwr-pipes.d.ts +1 -1
- package/types/ngwr-popover-testing.d.ts +7 -2
- package/types/ngwr-popover.d.ts +1 -0
- package/types/ngwr-result.d.ts +6 -0
- package/types/ngwr-segmented-testing.d.ts +9 -0
- package/types/ngwr-segmented.d.ts +21 -1
- package/types/ngwr-select.d.ts +68 -6
- package/types/ngwr-shiny-text.d.ts +4 -2
- package/types/ngwr-sidebar.d.ts +14 -5
- package/types/ngwr-slider.d.ts +69 -1
- package/types/ngwr-speed-dial-testing.d.ts +15 -11
- package/types/ngwr-speed-dial.d.ts +22 -3
- package/types/ngwr-split-text.d.ts +9 -0
- package/types/ngwr-stepper-testing.d.ts +5 -5
- package/types/ngwr-stepper.d.ts +8 -0
- package/types/ngwr-storage.d.ts +1 -0
- package/types/ngwr-table.d.ts +104 -11
- package/types/ngwr-tabs-testing.d.ts +11 -10
- package/types/ngwr-tabs.d.ts +2 -0
- package/types/ngwr-theme.d.ts +82 -1
- package/types/ngwr-tour.d.ts +22 -4
- package/types/ngwr-tree.d.ts +5 -4
- package/types/ngwr-typewriter-testing.d.ts +10 -0
- package/types/ngwr-utils.d.ts +5 -2
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-window.d.ts +39 -11
- package/typography/styles/_index.scss +1 -1
- package/window/styles/_index.scss +72 -26
- package/fesm2022/ngwr-date-adapter-fns.mjs.map +0 -1
- package/fesm2022/ngwr-date-adapter-luxon.mjs.map +0 -1
- package/fesm2022/ngwr-date-adapter.mjs.map +0 -1
package/fesm2022/ngwr-rating.mjs
CHANGED
|
@@ -177,10 +177,10 @@ class WrRating {
|
|
|
177
177
|
this.value.set(value);
|
|
178
178
|
this.hoverValue.set(null);
|
|
179
179
|
}
|
|
180
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
181
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
180
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrRating, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
181
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrRating, isStandalone: true, selector: "wr-rating", inputs: { count: { classPropertyName: "count", publicName: "count", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div\n class=\"wr-rating__row\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"count()\"\n [attr.aria-valuenow]=\"value() ?? 0\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n (keydown)=\"onKeydown($event)\"\n (mouseleave)=\"onLeave()\"\n (blur)=\"onBlur()\"\n>\n @for (slot of slots(); track $index) {\n <!-- The parent row owns keyboard focus + handlers; slots are pointer-only\n click targets, so the a11y rules below are intentionally suppressed. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n <span\n class=\"wr-rating__slot\"\n [class.wr-rating__slot--interactive]=\"interactive()\"\n [style.--wr-rating-fill]=\"fillFor($index)\"\n (mousemove)=\"onSlotMove($event, $index)\"\n (click)=\"onSlotClick($event, $index)\"\n >\n <!-- Outline (always visible) -->\n <svg class=\"wr-rating__icon wr-rating__icon--bg\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 2.5l2.95 5.98 6.6.96-4.78 4.66 1.13 6.58L12 17.6l-5.9 3.08 1.13-6.58L2.45 9.44l6.6-.96L12 2.5z\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <!-- Filled overlay, clipped by --wr-rating-fill (0..1) -->\n <svg class=\"wr-rating__icon wr-rating__icon--fg\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 2.5l2.95 5.98 6.6.96-4.78 4.66 1.13 6.58L12 17.6l-5.9 3.08 1.13-6.58L2.45 9.44l6.6-.96L12 2.5z\"\n fill=\"currentColor\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n }\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
|
|
182
182
|
}
|
|
183
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
183
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrRating, decorators: [{
|
|
184
184
|
type: Component,
|
|
185
185
|
args: [{ selector: 'wr-rating', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div\n class=\"wr-rating__row\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"count()\"\n [attr.aria-valuenow]=\"value() ?? 0\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n (keydown)=\"onKeydown($event)\"\n (mouseleave)=\"onLeave()\"\n (blur)=\"onBlur()\"\n>\n @for (slot of slots(); track $index) {\n <!-- The parent row owns keyboard focus + handlers; slots are pointer-only\n click targets, so the a11y rules below are intentionally suppressed. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n <span\n class=\"wr-rating__slot\"\n [class.wr-rating__slot--interactive]=\"interactive()\"\n [style.--wr-rating-fill]=\"fillFor($index)\"\n (mousemove)=\"onSlotMove($event, $index)\"\n (click)=\"onSlotClick($event, $index)\"\n >\n <!-- Outline (always visible) -->\n <svg class=\"wr-rating__icon wr-rating__icon--bg\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 2.5l2.95 5.98 6.6.96-4.78 4.66 1.13 6.58L12 17.6l-5.9 3.08 1.13-6.58L2.45 9.44l6.6-.96L12 2.5z\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linejoin=\"round\"\n />\n </svg>\n <!-- Filled overlay, clipped by --wr-rating-fill (0..1) -->\n <svg class=\"wr-rating__icon wr-rating__icon--fg\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path\n d=\"M12 2.5l2.95 5.98 6.6.96-4.78 4.66 1.13 6.58L12 17.6l-5.9 3.08 1.13-6.58L2.45 9.44l6.6-.96L12 2.5z\"\n fill=\"currentColor\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </span>\n }\n</div>\n" }]
|
|
186
186
|
}], ctorParameters: () => [], propDecorators: { count: [{ type: i0.Input, args: [{ isSignal: true, alias: "count", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
|
package/fesm2022/ngwr-result.mjs
CHANGED
|
@@ -34,10 +34,10 @@ class WrResult {
|
|
|
34
34
|
...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
35
35
|
classes = computed(() => `wr-result wr-result--${this.status()}`, /* @ts-ignore */
|
|
36
36
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
37
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
38
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
37
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
38
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrResult, isStandalone: true, selector: "wr-result", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div class=\"wr-result__icon\" aria-hidden=\"true\">\n @switch (status()) {\n @case ('success') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M20 32 L28 40 L44 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 18 L32 36 M32 44 L32 46\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('error') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M22 22 L42 42 M42 22 L22 42\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('empty') {\n <svg width=\"72\" height=\"56\" viewBox=\"0 0 72 56\">\n <rect x=\"6\" y=\"14\" width=\"60\" height=\"36\" rx=\"4\" fill=\"currentColor\" opacity=\"0.12\" />\n <path d=\"M6 26 L36 26 L40 20 L66 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\n </svg>\n }\n @default {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 20 L32 36 M32 42 L32 44\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n }\n</div>\n\n@if (title()) {\n <h2 class=\"wr-result__title\">{{ title() }}</h2>\n}\n@if (description()) {\n <p class=\"wr-result__description\">{{ description() }}</p>\n}\n\n<div class=\"wr-result__extra\">\n <ng-content select=\"[wrResultExtra]\" />\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
|
|
39
39
|
}
|
|
40
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
40
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult, decorators: [{
|
|
41
41
|
type: Component,
|
|
42
42
|
args: [{ selector: 'wr-result', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div class=\"wr-result__icon\" aria-hidden=\"true\">\n @switch (status()) {\n @case ('success') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M20 32 L28 40 L44 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 18 L32 36 M32 44 L32 46\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('error') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M22 22 L42 42 M42 22 L22 42\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('empty') {\n <svg width=\"72\" height=\"56\" viewBox=\"0 0 72 56\">\n <rect x=\"6\" y=\"14\" width=\"60\" height=\"36\" rx=\"4\" fill=\"currentColor\" opacity=\"0.12\" />\n <path d=\"M6 26 L36 26 L40 20 L66 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\n </svg>\n }\n @default {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 20 L32 36 M32 42 L32 44\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n }\n</div>\n\n@if (title()) {\n <h2 class=\"wr-result__title\">{{ title() }}</h2>\n}\n@if (description()) {\n <p class=\"wr-result__description\">{{ description() }}</p>\n}\n\n<div class=\"wr-result__extra\">\n <ng-content select=\"[wrResultExtra]\" />\n</div>\n" }]
|
|
43
43
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }] } });
|
|
@@ -59,63 +59,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
61
|
class WrResult404 {
|
|
62
|
+
/** Bound by the shared template; not an input — a preset IS its status. */
|
|
63
|
+
status = 'warning';
|
|
62
64
|
title = input('404', /* @ts-ignore */
|
|
63
65
|
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
64
66
|
/** Body text. Falls back to `result.notFound` from WrI18n. */
|
|
65
67
|
description = input(null, /* @ts-ignore */
|
|
66
68
|
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
67
69
|
desc = useI18nText(this.description, 'result.notFound', 'Sorry, the page you visited does not exist.');
|
|
68
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
69
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult404, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.2", type: WrResult404, isStandalone: true, selector: "wr-result-404", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently \u2014\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\n", dependencies: [{ kind: "component", type: WrResult, selector: "wr-result", inputs: ["title", "description", "status"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
70
72
|
}
|
|
71
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
73
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult404, decorators: [{
|
|
72
74
|
type: Component,
|
|
73
|
-
args: [{
|
|
74
|
-
selector: 'wr-result-404',
|
|
75
|
-
template: `<wr-result status="warning" [title]="title()" [description]="desc()"><ng-content /></wr-result>`,
|
|
76
|
-
encapsulation: ViewEncapsulation.None,
|
|
77
|
-
imports: [WrResult],
|
|
78
|
-
}]
|
|
75
|
+
args: [{ selector: 'wr-result-404', encapsulation: ViewEncapsulation.None, imports: [WrResult], template: "<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently \u2014\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\n" }]
|
|
79
76
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
80
77
|
/** Pre-set 403 result — forbidden / no access. */
|
|
81
78
|
class WrResult403 {
|
|
79
|
+
/** Bound by the shared template; not an input — a preset IS its status. */
|
|
80
|
+
status = 'error';
|
|
82
81
|
title = input('403', /* @ts-ignore */
|
|
83
82
|
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
84
83
|
/** Body text. Falls back to `result.forbidden` from WrI18n. */
|
|
85
84
|
description = input(null, /* @ts-ignore */
|
|
86
85
|
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
87
86
|
desc = useI18nText(this.description, 'result.forbidden', 'Sorry, you are not authorized to access this page.');
|
|
88
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
89
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
87
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult403, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
88
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.2", type: WrResult403, isStandalone: true, selector: "wr-result-403", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently \u2014\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\n", dependencies: [{ kind: "component", type: WrResult, selector: "wr-result", inputs: ["title", "description", "status"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
90
89
|
}
|
|
91
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
90
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult403, decorators: [{
|
|
92
91
|
type: Component,
|
|
93
|
-
args: [{
|
|
94
|
-
selector: 'wr-result-403',
|
|
95
|
-
template: `<wr-result status="error" [title]="title()" [description]="desc()"><ng-content /></wr-result>`,
|
|
96
|
-
encapsulation: ViewEncapsulation.None,
|
|
97
|
-
imports: [WrResult],
|
|
98
|
-
}]
|
|
92
|
+
args: [{ selector: 'wr-result-403', encapsulation: ViewEncapsulation.None, imports: [WrResult], template: "<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently \u2014\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\n" }]
|
|
99
93
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
100
94
|
/** Pre-set 500 result — internal server error. */
|
|
101
95
|
class WrResult500 {
|
|
96
|
+
/** Bound by the shared template; not an input — a preset IS its status. */
|
|
97
|
+
status = 'error';
|
|
102
98
|
title = input('500', /* @ts-ignore */
|
|
103
99
|
...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
104
100
|
/** Body text. Falls back to `result.serverError` from WrI18n. */
|
|
105
101
|
description = input(null, /* @ts-ignore */
|
|
106
102
|
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
107
103
|
desc = useI18nText(this.description, 'result.serverError', 'Sorry, something went wrong.');
|
|
108
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
109
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
104
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult500, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
105
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.2", type: WrResult500, isStandalone: true, selector: "wr-result-500", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently \u2014\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\n", dependencies: [{ kind: "component", type: WrResult, selector: "wr-result", inputs: ["title", "description", "status"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
110
106
|
}
|
|
111
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
107
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrResult500, decorators: [{
|
|
112
108
|
type: Component,
|
|
113
|
-
args: [{
|
|
114
|
-
selector: 'wr-result-500',
|
|
115
|
-
template: `<wr-result status="error" [title]="title()" [description]="desc()"><ng-content /></wr-result>`,
|
|
116
|
-
encapsulation: ViewEncapsulation.None,
|
|
117
|
-
imports: [WrResult],
|
|
118
|
-
}]
|
|
109
|
+
args: [{ selector: 'wr-result-500', encapsulation: ViewEncapsulation.None, imports: [WrResult], template: "<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently \u2014\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\n" }]
|
|
119
110
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
120
111
|
|
|
121
112
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-result.mjs","sources":["../../../projects/lib/result/result.ts","../../../projects/lib/result/result.html","../../../projects/lib/result/presets.ts","../../../projects/lib/result/ngwr-result.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 } from '@angular/core';\n\nimport type { WrResultStatus } from './interfaces';\n\n/**\n * Large-illustration result / empty-state. Use after a successful action,\n * for empty list states, or 404 / 500 pages.\n *\n * @example\n * ```html\n * <wr-result status=\"success\" title=\"Submitted!\" description=\"We'll be in touch.\">\n * <button wr-btn color=\"primary\" wrResultExtra>Continue</button>\n * </wr-result>\n *\n * <wr-result status=\"empty\" title=\"No projects yet\">\n * <button wr-btn wrResultExtra>Create one</button>\n * </wr-result>\n * ```\n *\n * @see https://ngwr.dev/reference/components/result\n */\n@Component({\n selector: 'wr-result',\n templateUrl: './result.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrResult {\n readonly title = input<string>('');\n readonly description = input<string>('');\n readonly status = input<WrResultStatus>('info');\n\n protected readonly classes = computed(() => `wr-result wr-result--${this.status()}`);\n}\n\nexport type { WrResultStatus } from './interfaces';\n","<div class=\"wr-result__icon\" aria-hidden=\"true\">\n @switch (status()) {\n @case ('success') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M20 32 L28 40 L44 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 18 L32 36 M32 44 L32 46\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('error') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M22 22 L42 42 M42 22 L22 42\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('empty') {\n <svg width=\"72\" height=\"56\" viewBox=\"0 0 72 56\">\n <rect x=\"6\" y=\"14\" width=\"60\" height=\"36\" rx=\"4\" fill=\"currentColor\" opacity=\"0.12\" />\n <path d=\"M6 26 L36 26 L40 20 L66 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\n </svg>\n }\n @default {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 20 L32 36 M32 42 L32 44\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n }\n</div>\n\n@if (title()) {\n <h2 class=\"wr-result__title\">{{ title() }}</h2>\n}\n@if (description()) {\n <p class=\"wr-result__description\">{{ description() }}</p>\n}\n\n<div class=\"wr-result__extra\">\n <ng-content select=\"[wrResultExtra]\" />\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, input } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\nimport { WrResult } from './result';\n\n/**\n * Pre-set 404 result. Override `title` / `description` for localisation.\n *\n * @example\n * ```html\n * <wr-result-404>\n * <button wr-btn wrResultExtra>Back home</button>\n * </wr-result-404>\n * ```\n */\n@Component({\n selector: 'wr-result-404',\n template: `<wr-result status=\"warning\" [title]=\"title()\" [description]=\"desc()\"><ng-content /></wr-result>`,\n encapsulation: ViewEncapsulation.None,\n imports: [WrResult],\n})\nexport class WrResult404 {\n readonly title = input<string>('404');\n\n /** Body text. Falls back to `result.notFound` from WrI18n. */\n readonly description = input<string | null>(null);\n\n protected readonly desc = useI18nText(\n this.description,\n 'result.notFound',\n 'Sorry, the page you visited does not exist.'\n );\n}\n\n/** Pre-set 403 result — forbidden / no access. */\n@Component({\n selector: 'wr-result-403',\n template: `<wr-result status=\"error\" [title]=\"title()\" [description]=\"desc()\"><ng-content /></wr-result>`,\n encapsulation: ViewEncapsulation.None,\n imports: [WrResult],\n})\nexport class WrResult403 {\n readonly title = input<string>('403');\n\n /** Body text. Falls back to `result.forbidden` from WrI18n. */\n readonly description = input<string | null>(null);\n\n protected readonly desc = useI18nText(\n this.description,\n 'result.forbidden',\n 'Sorry, you are not authorized to access this page.'\n );\n}\n\n/** Pre-set 500 result — internal server error. */\n@Component({\n selector: 'wr-result-500',\n template: `<wr-result status=\"error\" [title]=\"title()\" [description]=\"desc()\"><ng-content /></wr-result>`,\n encapsulation: ViewEncapsulation.None,\n imports: [WrResult],\n})\nexport class WrResult500 {\n readonly title = input<string>('500');\n\n /** Body text. Falls back to `result.serverError` from WrI18n. */\n readonly description = input<string | null>(null);\n\n protected readonly desc = useI18nText(this.description, 'result.serverError', 'Sorry, something went wrong.');\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-result.mjs","sources":["../../../projects/lib/result/result.ts","../../../projects/lib/result/result.html","../../../projects/lib/result/presets.ts","../../../projects/lib/result/presets.html","../../../projects/lib/result/ngwr-result.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 } from '@angular/core';\n\nimport type { WrResultStatus } from './interfaces';\n\n/**\n * Large-illustration result / empty-state. Use after a successful action,\n * for empty list states, or 404 / 500 pages.\n *\n * @example\n * ```html\n * <wr-result status=\"success\" title=\"Submitted!\" description=\"We'll be in touch.\">\n * <button wr-btn color=\"primary\" wrResultExtra>Continue</button>\n * </wr-result>\n *\n * <wr-result status=\"empty\" title=\"No projects yet\">\n * <button wr-btn wrResultExtra>Create one</button>\n * </wr-result>\n * ```\n *\n * @see https://ngwr.dev/reference/components/result\n */\n@Component({\n selector: 'wr-result',\n templateUrl: './result.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrResult {\n readonly title = input<string>('');\n readonly description = input<string>('');\n readonly status = input<WrResultStatus>('info');\n\n protected readonly classes = computed(() => `wr-result wr-result--${this.status()}`);\n}\n\nexport type { WrResultStatus } from './interfaces';\n","<div class=\"wr-result__icon\" aria-hidden=\"true\">\n @switch (status()) {\n @case ('success') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M20 32 L28 40 L44 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 18 L32 36 M32 44 L32 46\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('error') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M22 22 L42 42 M42 22 L22 42\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n @case ('empty') {\n <svg width=\"72\" height=\"56\" viewBox=\"0 0 72 56\">\n <rect x=\"6\" y=\"14\" width=\"60\" height=\"36\" rx=\"4\" fill=\"currentColor\" opacity=\"0.12\" />\n <path d=\"M6 26 L36 26 L40 20 L66 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" />\n </svg>\n }\n @default {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <circle cx=\"32\" cy=\"32\" r=\"28\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 20 L32 36 M32 42 L32 44\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3.5\"\n stroke-linecap=\"round\"\n />\n </svg>\n }\n }\n</div>\n\n@if (title()) {\n <h2 class=\"wr-result__title\">{{ title() }}</h2>\n}\n@if (description()) {\n <p class=\"wr-result__description\">{{ description() }}</p>\n}\n\n<div class=\"wr-result__extra\">\n <ng-content select=\"[wrResultExtra]\" />\n</div>\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, input } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\nimport type { WrResultStatus } from './interfaces';\nimport { WrResult } from './result';\n\n/**\n * Pre-set 404 result. Override `title` / `description` for localisation.\n *\n * @example\n * ```html\n * <wr-result-404>\n * <button wr-btn wrResultExtra>Back home</button>\n * </wr-result-404>\n * ```\n */\n@Component({\n selector: 'wr-result-404',\n templateUrl: './presets.html',\n encapsulation: ViewEncapsulation.None,\n imports: [WrResult],\n})\nexport class WrResult404 {\n /** Bound by the shared template; not an input — a preset IS its status. */\n protected readonly status: WrResultStatus = 'warning';\n\n readonly title = input<string>('404');\n\n /** Body text. Falls back to `result.notFound` from WrI18n. */\n readonly description = input<string | null>(null);\n\n protected readonly desc = useI18nText(\n this.description,\n 'result.notFound',\n 'Sorry, the page you visited does not exist.'\n );\n}\n\n/** Pre-set 403 result — forbidden / no access. */\n@Component({\n selector: 'wr-result-403',\n templateUrl: './presets.html',\n encapsulation: ViewEncapsulation.None,\n imports: [WrResult],\n})\nexport class WrResult403 {\n /** Bound by the shared template; not an input — a preset IS its status. */\n protected readonly status: WrResultStatus = 'error';\n\n readonly title = input<string>('403');\n\n /** Body text. Falls back to `result.forbidden` from WrI18n. */\n readonly description = input<string | null>(null);\n\n protected readonly desc = useI18nText(\n this.description,\n 'result.forbidden',\n 'Sorry, you are not authorized to access this page.'\n );\n}\n\n/** Pre-set 500 result — internal server error. */\n@Component({\n selector: 'wr-result-500',\n templateUrl: './presets.html',\n encapsulation: ViewEncapsulation.None,\n imports: [WrResult],\n})\nexport class WrResult500 {\n /** Bound by the shared template; not an input — a preset IS its status. */\n protected readonly status: WrResultStatus = 'error';\n\n readonly title = input<string>('500');\n\n /** Body text. Falls back to `result.serverError` from WrI18n. */\n readonly description = input<string | null>(null);\n\n protected readonly desc = useI18nText(this.description, 'result.serverError', 'Sorry, something went wrong.');\n}\n","<!--\n Shared by the three status presets, which differ only in the `status` each\n class declares.\n\n `ngProjectAs` is load-bearing: `<wr-result>` projects one slot,\n `select=\"[wrResultExtra]\"`, and it matches that selector against the nodes in\n THIS template. A bare `<ng-content />` does not carry the attribute, so\n everything a consumer projected into `<wr-result-404>` was dropped silently —\n including the button each preset's own `@example` shows. `ngProjectAs` is what\n tells the outer slot what this pass-through stands for.\n-->\n<wr-result [status]=\"status\" [title]=\"title()\" [description]=\"desc()\">\n <ng-content ngProjectAs=\"[wrResultExtra]\" />\n</wr-result>\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.2", ngImport: i0, type: WrRotatingText, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
266
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", 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.2", 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"] }] } });
|
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.2", ngImport: i0, type: WrScroll, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
96
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.2", 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.2", ngImport: i0, type: WrScroll, decorators: [{
|
|
99
99
|
type: Service
|
|
100
100
|
}] });
|
|
101
101
|
|
|
@@ -492,9 +492,22 @@ class WrSegmentedHarness extends ComponentHarness {
|
|
|
492
492
|
async describe(options) {
|
|
493
493
|
return Promise.all(options.map(async (option) => (await option.getAccessibleName()) ?? '(unnamed)'));
|
|
494
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* One custom property off the host's `style` ATTRIBUTE.
|
|
497
|
+
*
|
|
498
|
+
* Not `getCssValue()`, which is `getComputedStyle`: with the entry point's own
|
|
499
|
+
* stylesheet loaded that resolves the sheet's declaration, so the method
|
|
500
|
+
* answers plausibly at exactly the moment the host binding — the thing under
|
|
501
|
+
* test — is what broke. The attribute holds only what the component wrote.
|
|
502
|
+
*/
|
|
503
|
+
async inlineVar(property) {
|
|
504
|
+
const attr = (await (await this.host()).getAttribute('style')) ?? '';
|
|
505
|
+
const found = new RegExp(`(?:^|;)\\s*${property}\\s*:\\s*([^;]+)`).exec(attr);
|
|
506
|
+
return (found?.[1] ?? '').trim();
|
|
507
|
+
}
|
|
495
508
|
/** One of the thumb's inline custom properties, as a number. */
|
|
496
509
|
async thumbVar(property) {
|
|
497
|
-
const raw =
|
|
510
|
+
const raw = await this.inlineVar(property);
|
|
498
511
|
const value = Number.parseInt(raw, 10);
|
|
499
512
|
if (Number.isNaN(value)) {
|
|
500
513
|
throw new Error(`WrSegmentedHarness: could not read \`${property}\`, which computed to "${raw}". The component sets it ` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-segmented-testing.mjs","sources":["../../../projects/lib/segmented/testing/wr-segmented-option-harness.ts","../../../projects/lib/segmented/testing/wr-segmented-harness.ts","../../../projects/lib/segmented/testing/ngwr-segmented-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrSegmentedOptionHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one segment of a `<wr-segmented>` — an option, not a control.\n *\n * A segment is a real `<button type=\"button\">` carrying `aria-pressed`, so it is a\n * TOGGLE BUTTON to a screen reader: it announces its own pressed state and its own\n * name, and it is its own tab stop. That is why this exists as a harness of its own,\n * and why the questions below are worth asking per segment rather than in bulk on\n * `WrSegmentedHarness` — which is where the SELECTION lives.\n *\n * Three name-shaped methods, because a segment has three different names and only\n * one of them is what a person hears:\n *\n * - {@link getText} — the visible label, `null` for an icon-only segment.\n * - {@link getAccessibleName} — what is announced, `null` when nothing names it.\n * - {@link getLabel} — the same, but it refuses to answer `null`, so a spec\n * addressing segments by label fails where the mistake is rather than three\n * lines later.\n *\n * @example\n * ```ts\n * const segmented = await loader.getHarness(WrSegmentedHarness);\n * const [, week] = await segmented.getOptions();\n *\n * await week.select();\n * expect(await week.isSelected()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrSegmentedOptionHarness extends ComponentHarness {\n /** The segment is a plain `<button>` — the BEM class is what identifies it. */\n static hostSelector = '.wr-segmented__option';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrSegmentedOptionHarnessFilters = {}): HarnessPredicate<WrSegmentedOptionHarness> {\n return (\n new HarnessPredicate(WrSegmentedOptionHarness, options)\n // Matched on the nullable name, not on `getLabel()`: a predicate runs against\n // EVERY segment, so one unnamed sibling would otherwise throw a query for the\n // others out of the water.\n .addOption('label', options.label, (harness, label) =>\n HarnessPredicate.stringMatches(harness.getAccessibleName(), label)\n )\n .addOption('selected', options.selected, async (harness, selected) => (await harness.isSelected()) === selected)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n );\n }\n\n private readonly labelText = this.locatorForOptional('.wr-segmented__label');\n private readonly icon = this.locatorForOptional('.wr-segmented__icon');\n\n /**\n * The visible label, or `null` for an icon-only segment.\n *\n * `null` rather than `''`: the label element is only rendered when the option\n * carries a `label`, and \"no text at all\" and \"an empty label\" are different\n * mistakes to be looking at.\n */\n async getText(): Promise<string | null> {\n const label = await this.labelText();\n return label ? label.text() : null;\n }\n\n /**\n * The name a screen reader announces for this segment, or `null` when nothing\n * names it.\n *\n * The component's own fallback chain, read back off the page: a labelled segment\n * is named by its text and carries no `aria-label`; an icon-only one is named by\n * `aria-label`, which the template fills from the option's `ariaLabel` or — as a\n * last resort — from its stringified `value`.\n *\n * `null` is a finding, not a detail: an icon-only segment whose option supplied\n * neither an `ariaLabel` nor a stringifiable value is announced as a bare unnamed\n * button.\n */\n async getAccessibleName(): Promise<string | null> {\n const text = await this.getText();\n if (text !== null) return text;\n return (await this.host()).getAttribute('aria-label');\n }\n\n /**\n * The segment's accessible name, for addressing it — and a targeted failure when\n * it has none.\n *\n * {@link getAccessibleName} is the same answer without the refusal; use that one\n * when `null` is what a spec is checking for.\n */\n async getLabel(): Promise<string> {\n const name = await this.getAccessibleName();\n if (name === null) {\n throw new Error(\n 'WrSegmentedOptionHarness.getLabel(): this segment has no name — it renders no label and carries no ' +\n '`aria-label`, so a screen reader announces an unnamed button. Give the option a `label`, or an ' +\n '`ariaLabel` when it is icon-only.'\n );\n }\n return name;\n }\n\n /**\n * Whether this segment is the control's current answer.\n *\n * From `aria-pressed`, in preference to the `wr-segmented__option--selected`\n * class: both are public and they move together, but the class only recolours the\n * label while the attribute is the entire state a screen reader is given.\n */\n async isSelected(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-pressed')) === 'true';\n }\n\n /**\n * Whether the segment refuses selection — for either reason.\n *\n * The native `disabled` PROPERTY, which is what actually blocks activation. The\n * option's own `disabled` and the whole control's land on it identically, and from\n * outside they are the same thing: this segment cannot be picked. Ask\n * `WrSegmentedHarness.isDisabled()` for which of the two it was.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).getProperty<boolean>('disabled');\n }\n\n /** Whether the segment renders an icon beside (or instead of) its label. */\n async hasIcon(): Promise<boolean> {\n return (await this.icon()) !== null;\n }\n\n /**\n * The name of the segment's icon, or `null` when it renders none.\n *\n * From `data-icon`, which `<wr-icon>` reflects. The glyph itself is markup the\n * icon registry writes into the element, and an UNREGISTERED name leaves that\n * empty — so the attribute is the only place the wiring survives, and it is the\n * one that tells \"no icon asked for\" from \"icon asked for, never registered\".\n */\n async getIconName(): Promise<string | null> {\n const icon = await this.icon();\n return icon ? icon.getAttribute('data-icon') : null;\n }\n\n /**\n * Pick this segment.\n *\n * A click, and deliberately not a keypress: activating a `<button>` from the\n * keyboard is the BROWSER's default action for Enter / Space — the component\n * implements no key handling of its own — and jsdom implements none of it either,\n * so there is nothing here for a key to drive. A no-arg CDK click needs no\n * layout, which is the other half of why this is the drivable path.\n *\n * Nothing happens when the segment is already selected (a segmented control has no\n * untoggle), and nothing happens when it is disabled — but not for the reason the\n * `pointer-events: none` on a whole disabled control suggests, which is CSS a unit\n * test never applies. The CDK's own `click()` reads the native `disabled` PROPERTY\n * and dispatches the mouse sequence WITHOUT the final `click` event, so on a\n * disabled segment the component's handler is never reached at all (measured: zero\n * click events). Either way the value does not move and this resolves quietly, so\n * assert the result rather than assume it, or reach for\n * `WrSegmentedHarness.select()`, which says which of the two it was.\n */\n async select(): Promise<void> {\n return (await this.host()).click();\n }\n\n /** Move keyboard focus to the segment. Each segment is its own tab stop. */\n async focus(): Promise<void> {\n return (await this.host()).focus();\n }\n\n /** Take focus off the segment. */\n async blur(): Promise<void> {\n return (await this.host()).blur();\n }\n\n async isFocused(): Promise<boolean> {\n return (await this.host()).isFocused();\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrSegmentedSize } from 'ngwr/segmented';\n\nimport type { WrSegmentedHarnessFilters, WrSegmentedOptionHarnessFilters } from './interfaces';\nimport { WrSegmentedOptionHarness } from './wr-segmented-option-harness';\n\n/** Sizes that earn a modifier class — `md` is the default and carries none. */\nconst SIZES: readonly WrSegmentedSize[] = ['sm', 'lg'];\n\n/**\n * Test harness for `<wr-segmented>` — the root of a two-class family with\n * {@link WrSegmentedOptionHarness}.\n *\n * **What the control actually is**, because it decides everything below: not a\n * `radiogroup`, not a `tablist` and not native radios. The host is a plain\n * `role=\"group\"` and each segment is a `<button aria-pressed>` — a row of toggle\n * buttons over one value. Three consequences a spec has to know about:\n *\n * - The selection is `aria-pressed`, on exactly one segment. There is no\n * `aria-checked`, no `aria-selected`, and no \"2 of 3\" position announced.\n * - **There is no roving tab stop.** The component authors no `tabindex` and no\n * arrow-key handler, so every enabled segment is its OWN tab stop —\n * {@link getTabStopLabels} returns a list where a radiogroup or a tablist would\n * have one entry. Focus and selection are therefore independent here:\n * {@link getFocusedLabel} implies nothing about {@link getSelectedIndex}, and\n * arrowing along the strip moves neither.\n * - Activation is the browser's own default action on a button, which jsdom does not\n * implement, so {@link select} clicks — see {@link WrSegmentedOptionHarness.select}.\n *\n * **There is deliberately no `getValue()` and no selection by value.** `options` is\n * a bound array of `{ value, label, … }` and the value is a generic `T` the component\n * writes nowhere — not on the host, not on a segment. The single exception is an\n * accident rather than an addressing scheme: an icon-only option with no `ariaLabel`\n * has its value stringified into the segment's `aria-label`, which for an object\n * value reads `[object Object]`. So address segments by their label\n * ({@link select}) or by position ({@link selectAt}), and assert the picked value on\n * the host's own model — the only place it exists, and the assertion that would have\n * caught the bug anyway.\n *\n * The sliding thumb is decoration (`aria-hidden`), and the four methods that mention\n * it read what the component PUBLISHES for the stylesheet — two custom properties and\n * two modifier classes — never painted geometry, which a DOM without layout does not\n * have. {@link getThumbIndex} in particular is not the selection; it is the trap that\n * method documents.\n *\n * @example\n * ```ts\n * const range = await loader.getHarness(WrSegmentedHarness.with({ label: 'Range' }));\n *\n * expect(await range.getOptionLabels()).toEqual(['Day', 'Week', 'Month']);\n * await range.select({ label: 'Week' });\n * expect(await range.getSelectedIndex()).toBe(1);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrSegmentedHarness extends ComponentHarness {\n static hostSelector = 'wr-segmented';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrSegmentedHarnessFilters = {}): HarnessPredicate<WrSegmentedHarness> {\n return new HarnessPredicate(WrSegmentedHarness, options)\n .addOption('label', options.label, (harness, label) =>\n HarnessPredicate.stringMatches(harness.getAccessibleName(), label)\n )\n .addOption('size', options.size, async (harness, size) => (await harness.getSize()) === size)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n /**\n * The role the host announces — `group`.\n *\n * Worth pinning precisely because it is the weaker of the shapes this component\n * could have had: a `group` of toggle buttons tells a screen reader that the\n * segments belong together, and nothing more. Were this to become a `radiogroup` or\n * a `tablist`, the keyboard contract would change with it (one tab stop, arrow keys\n * moving the selection), and every spec written against {@link getTabStopLabels}\n * would need to change too.\n */\n async getRole(): Promise<string | null> {\n return (await this.host()).getAttribute('role');\n }\n\n /**\n * The control's accessible name, resolved the way a screen reader resolves it: the\n * text of every element `aria-labelledby` points at, and `aria-label` only when\n * that named nothing. `null` when the consumer wired neither.\n *\n * The order is not interchangeable — `aria-labelledby` WINS in the accessible-name\n * computation — so a control carrying both is announced by the heading it points at,\n * and reporting the `aria-label` would describe a name nobody hears.\n *\n * The component ships no label input on purpose (the question is the consumer's own\n * heading), so this is the only way to check that wiring held, and a `null` on a\n * group of three unrelated-sounding buttons is a real finding.\n */\n async getAccessibleName(): Promise<string | null> {\n const host = await this.host();\n\n const labelledBy = await host.getAttribute('aria-labelledby');\n if (labelledBy !== null) {\n // Resolved from the document root: `aria-labelledby` may point anywhere on the\n // page, and the heading above a control is normally outside it.\n const root = this.documentRootLocatorFactory();\n const texts: string[] = [];\n for (const id of labelledBy.split(/\\s+/).filter(Boolean)) {\n const target = await root.locatorForOptional(`#${id}`)();\n if (target) texts.push(await target.text());\n }\n\n // A reference that resolves to nothing names nothing, and the computation falls\n // through to `aria-label` exactly as it does in a browser.\n if (texts.length) return texts.join(' ');\n }\n\n return host.getAttribute('aria-label');\n }\n\n /** This control's own segments, in DOM order. A sibling control's are not here. */\n async getOptions(filters: WrSegmentedOptionHarnessFilters = {}): Promise<WrSegmentedOptionHarness[]> {\n return this.locatorForAll(WrSegmentedOptionHarness.with(filters))();\n }\n\n /**\n * The accessible name of every segment, in DOM order — the visible labels, with an\n * icon-only segment answering with the `aria-label` that stands in for its text.\n *\n * Throws when a segment has no name at all, rather than leaving a hole in the list:\n * see {@link WrSegmentedOptionHarness.getLabel}.\n */\n async getOptionLabels(): Promise<string[]> {\n const options = await this.getOptions();\n return Promise.all(options.map(option => option.getLabel()));\n }\n\n /** The pressed segment, or `null` when nothing is selected. */\n async getSelectedOption(): Promise<WrSegmentedOptionHarness | null> {\n const [selected] = await this.getOptions({ selected: true });\n return selected ?? null;\n }\n\n /**\n * The accessible name of the pressed segment, or `null` when nothing is selected.\n *\n * `null` is also the answer for a bound value that matches no option — the control\n * holds it, no segment is pressed, and the page shows an unanswered control. See\n * {@link getThumbIndex}, which does NOT answer `null` in that state.\n */\n async getSelectedLabel(): Promise<string | null> {\n const selected = await this.getSelectedOption();\n return selected ? selected.getLabel() : null;\n }\n\n /**\n * The position of the pressed segment, or `-1` when nothing is selected.\n *\n * Derived from `aria-pressed`, which is the selection. The other index on the page —\n * the thumb's — is not; it clamps at 0 (see {@link getThumbIndex}).\n */\n async getSelectedIndex(): Promise<number> {\n const options = await this.getOptions();\n for (let index = 0; index < options.length; index++) {\n if (await options[index].isSelected()) return index;\n }\n return -1;\n }\n\n /**\n * Pick the first segment matching the filters — this is how the control's value\n * changes.\n *\n * Throws when nothing matches, naming the segments that do exist, and throws again\n * when the segment is still unpressed afterwards. That second failure has exactly\n * two causes and reports both, because a click that quietly did nothing surfaces as\n * an unrelated assertion three lines later.\n */\n async select(filters: WrSegmentedOptionHarnessFilters): Promise<void> {\n const [option] = await this.getOptions(filters);\n if (!option) {\n throw new Error(\n `WrSegmentedHarness.select(): no segment matched ${JSON.stringify(filters)}. This control offers: ` +\n `${(await this.describeOptions()).join(', ')}.`\n );\n }\n await this.pick(option, 'select');\n }\n\n /**\n * Pick the segment at a position, counting from zero — the addressing route for an\n * icon-only strip, or for one whose labels a spec would rather not hard-code.\n *\n * Throws on an index outside the control, saying how many segments there are: an\n * off-by-one that resolved to nothing would otherwise read as \"the click did not\n * take\".\n */\n async selectAt(index: number): Promise<void> {\n const options = await this.getOptions();\n const option = options[index];\n if (!option) {\n throw new Error(\n `WrSegmentedHarness.selectAt(): index ${index} is outside this control, which has ${options.length} ` +\n `segment(s): ${(await this.describeOptions()).join(', ')}.`\n );\n }\n await this.pick(option, 'selectAt');\n }\n\n /**\n * Whether the control was disabled AS A WHOLE, from the `wr-segmented--disabled`\n * modifier.\n *\n * Deliberately not \"every segment is disabled\": a control whose options each carry\n * their own `disabled` looks identical to a user, and the modifier is the only thing\n * on the page that tells the two apart. What actually blocks a click is the native\n * `disabled` each button gets either way — ask a segment\n * ({@link WrSegmentedOptionHarness.isDisabled}) for that.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-segmented--disabled');\n }\n\n /**\n * The rendered control size.\n *\n * `md` is the component's own default and earns NO modifier class, so a bare host\n * IS `md` — the absence is the answer rather than a missing one. Read from the\n * class instead of the input, which is also why this reports what was rendered:\n * unlike the form controls, `<wr-segmented>` does not resolve its size through\n * `provideWrConfig()`, so an app-wide default set there does not reach it and this\n * will say so.\n */\n async getSize(): Promise<WrSegmentedSize> {\n const host = await this.host();\n for (const size of SIZES) {\n if (await host.hasClass(`wr-segmented--${size}`)) return size;\n }\n return 'md';\n }\n\n /**\n * The accessible name of every segment a Tab press can reach, in tab order.\n *\n * A LIST, not one label, and that is the shape worth pinning: the component authors\n * no roving `tabindex`, so each enabled segment is its own tab stop and reaching the\n * third one takes three Tabs. An all-disabled control is skipped over entirely and\n * answers `[]`.\n *\n * Unnamed segments are reported as `(unnamed)` rather than throwing — a tab order is\n * still a fact worth reading on a page that has that bug in it.\n */\n async getTabStopLabels(): Promise<string[]> {\n const enabled = await this.getOptions({ disabled: false });\n return this.describe(enabled);\n }\n\n /**\n * The accessible name of the segment that currently holds focus, or `null` when\n * focus is elsewhere.\n *\n * Independent of the selection here — see the note on the class. Reported as\n * `(unnamed)` for a segment with no name, for the reason\n * {@link getTabStopLabels} gives.\n */\n async getFocusedLabel(): Promise<string | null> {\n for (const option of await this.getOptions()) {\n if (await option.isFocused()) {\n return (await option.getAccessibleName()) ?? '(unnamed)';\n }\n }\n return null;\n }\n\n /**\n * The index the component publishes for the thumb, from the\n * `--wr-segmented-thumb-index` custom property it sets inline.\n *\n * **Not the selection, and this is the difference that bites.** The property is\n * `Math.max(0, selectedIndex)`, so a control holding a value that matches no option\n * publishes `0` — the thumb parks under the FIRST segment and is hidden by\n * {@link isThumbVisible} instead of being moved out of the way. A harness that read\n * this to answer \"which segment is selected\" would report segment one for a control\n * with no selection at all. {@link getSelectedIndex} is the selection.\n *\n * It is also not where the thumb IS: the stylesheet turns this into a `translateX`,\n * and no measurement of that survives a DOM without layout. This is the input to\n * that, which is the part a unit test can honestly check.\n */\n async getThumbIndex(): Promise<number> {\n return this.thumbVar('--wr-segmented-thumb-index');\n }\n\n /**\n * The segment count the component publishes for the thumb, from\n * `--wr-segmented-thumb-count` — the divisor the stylesheet computes the thumb's\n * width with.\n *\n * Should always equal the number of segments, and the reason to ask is that nothing\n * else notices when it does not: a count that fell out of step with the options\n * leaves the thumb the wrong width and sliding to the wrong place, while every ARIA\n * state on the page stays correct. It is clamped to a minimum of `1`, so an empty\n * control reports `1` rather than dividing by zero.\n */\n async getThumbCount(): Promise<number> {\n return this.thumbVar('--wr-segmented-thumb-count');\n }\n\n /**\n * Whether the thumb is being shown at all.\n *\n * Read from the ABSENCE of the `wr-segmented--unselected` modifier, which is the\n * hook the stylesheet zeroes the thumb's opacity through. The computed opacity is\n * not the answer here — a unit test applies no stylesheet — so the public modifier\n * is the contract, and it is what tells \"parked under segment one\" from \"hidden\n * because nothing is selected\".\n */\n async isThumbVisible(): Promise<boolean> {\n return !(await (await this.host()).hasClass('wr-segmented--unselected'));\n }\n\n /**\n * Whether the thumb will animate its next move, from the `wr-segmented--mounted`\n * modifier that gates the transition.\n *\n * Not \"the thumb is animating now\": nothing about a running animation is visible to\n * a unit test. What this pins is the deliberate asymmetry — the class is added in\n * `afterNextRender`, so the FIRST snap to the initial value is instant and every\n * user-driven move after it slides. Deferred work like that only lands once the\n * fixture is stable, which every harness read already waits for.\n */\n async isThumbTransitionEnabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-segmented--mounted');\n }\n\n /** Click a segment and turn a click that did nothing into a failure that says why. */\n private async pick(option: WrSegmentedOptionHarness, caller: 'select' | 'selectAt'): Promise<void> {\n await option.select();\n\n if (!(await option.isSelected())) {\n const name = (await option.getAccessibleName()) ?? '(unnamed)';\n throw new Error(\n `WrSegmentedHarness.${caller}(): \"${name}\" is still unpressed after being clicked — either that ` +\n 'option carries `disabled` or the whole control does.'\n );\n }\n }\n\n /** Segment names for an error message, which must not throw on its way out. */\n private async describeOptions(): Promise<string[]> {\n return this.describe(await this.getOptions());\n }\n\n private async describe(options: readonly WrSegmentedOptionHarness[]): Promise<string[]> {\n return Promise.all(options.map(async option => (await option.getAccessibleName()) ?? '(unnamed)'));\n }\n\n /** One of the thumb's inline custom properties, as a number. */\n private async thumbVar(property: string): Promise<number> {\n const raw = (await (await this.host()).getCssValue(property)).trim();\n const value = Number.parseInt(raw, 10);\n if (Number.isNaN(value)) {\n throw new Error(\n `WrSegmentedHarness: could not read \\`${property}\\`, which computed to \"${raw}\". The component sets it ` +\n 'inline on the host; an environment that drops custom properties cannot answer this.'\n );\n }\n return value;\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-segmented-testing.mjs","sources":["../../../projects/lib/segmented/testing/wr-segmented-option-harness.ts","../../../projects/lib/segmented/testing/wr-segmented-harness.ts","../../../projects/lib/segmented/testing/ngwr-segmented-testing.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrSegmentedOptionHarnessFilters } from './interfaces';\n\n/**\n * Test harness for one segment of a `<wr-segmented>` — an option, not a control.\n *\n * A segment is a real `<button type=\"button\">` carrying `aria-pressed`, so it is a\n * TOGGLE BUTTON to a screen reader: it announces its own pressed state and its own\n * name, and it is its own tab stop. That is why this exists as a harness of its own,\n * and why the questions below are worth asking per segment rather than in bulk on\n * `WrSegmentedHarness` — which is where the SELECTION lives.\n *\n * Three name-shaped methods, because a segment has three different names and only\n * one of them is what a person hears:\n *\n * - {@link getText} — the visible label, `null` for an icon-only segment.\n * - {@link getAccessibleName} — what is announced, `null` when nothing names it.\n * - {@link getLabel} — the same, but it refuses to answer `null`, so a spec\n * addressing segments by label fails where the mistake is rather than three\n * lines later.\n *\n * @example\n * ```ts\n * const segmented = await loader.getHarness(WrSegmentedHarness);\n * const [, week] = await segmented.getOptions();\n *\n * await week.select();\n * expect(await week.isSelected()).toBe(true);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrSegmentedOptionHarness extends ComponentHarness {\n /** The segment is a plain `<button>` — the BEM class is what identifies it. */\n static hostSelector = '.wr-segmented__option';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrSegmentedOptionHarnessFilters = {}): HarnessPredicate<WrSegmentedOptionHarness> {\n return (\n new HarnessPredicate(WrSegmentedOptionHarness, options)\n // Matched on the nullable name, not on `getLabel()`: a predicate runs against\n // EVERY segment, so one unnamed sibling would otherwise throw a query for the\n // others out of the water.\n .addOption('label', options.label, (harness, label) =>\n HarnessPredicate.stringMatches(harness.getAccessibleName(), label)\n )\n .addOption('selected', options.selected, async (harness, selected) => (await harness.isSelected()) === selected)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled)\n );\n }\n\n private readonly labelText = this.locatorForOptional('.wr-segmented__label');\n private readonly icon = this.locatorForOptional('.wr-segmented__icon');\n\n /**\n * The visible label, or `null` for an icon-only segment.\n *\n * `null` rather than `''`: the label element is only rendered when the option\n * carries a `label`, and \"no text at all\" and \"an empty label\" are different\n * mistakes to be looking at.\n */\n async getText(): Promise<string | null> {\n const label = await this.labelText();\n return label ? label.text() : null;\n }\n\n /**\n * The name a screen reader announces for this segment, or `null` when nothing\n * names it.\n *\n * The component's own fallback chain, read back off the page: a labelled segment\n * is named by its text and carries no `aria-label`; an icon-only one is named by\n * `aria-label`, which the template fills from the option's `ariaLabel` or — as a\n * last resort — from its stringified `value`.\n *\n * `null` is a finding, not a detail: an icon-only segment whose option supplied\n * neither an `ariaLabel` nor a stringifiable value is announced as a bare unnamed\n * button.\n */\n async getAccessibleName(): Promise<string | null> {\n const text = await this.getText();\n if (text !== null) return text;\n return (await this.host()).getAttribute('aria-label');\n }\n\n /**\n * The segment's accessible name, for addressing it — and a targeted failure when\n * it has none.\n *\n * {@link getAccessibleName} is the same answer without the refusal; use that one\n * when `null` is what a spec is checking for.\n */\n async getLabel(): Promise<string> {\n const name = await this.getAccessibleName();\n if (name === null) {\n throw new Error(\n 'WrSegmentedOptionHarness.getLabel(): this segment has no name — it renders no label and carries no ' +\n '`aria-label`, so a screen reader announces an unnamed button. Give the option a `label`, or an ' +\n '`ariaLabel` when it is icon-only.'\n );\n }\n return name;\n }\n\n /**\n * Whether this segment is the control's current answer.\n *\n * From `aria-pressed`, in preference to the `wr-segmented__option--selected`\n * class: both are public and they move together, but the class only recolours the\n * label while the attribute is the entire state a screen reader is given.\n */\n async isSelected(): Promise<boolean> {\n return (await (await this.host()).getAttribute('aria-pressed')) === 'true';\n }\n\n /**\n * Whether the segment refuses selection — for either reason.\n *\n * The native `disabled` PROPERTY, which is what actually blocks activation. The\n * option's own `disabled` and the whole control's land on it identically, and from\n * outside they are the same thing: this segment cannot be picked. Ask\n * `WrSegmentedHarness.isDisabled()` for which of the two it was.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).getProperty<boolean>('disabled');\n }\n\n /** Whether the segment renders an icon beside (or instead of) its label. */\n async hasIcon(): Promise<boolean> {\n return (await this.icon()) !== null;\n }\n\n /**\n * The name of the segment's icon, or `null` when it renders none.\n *\n * From `data-icon`, which `<wr-icon>` reflects. The glyph itself is markup the\n * icon registry writes into the element, and an UNREGISTERED name leaves that\n * empty — so the attribute is the only place the wiring survives, and it is the\n * one that tells \"no icon asked for\" from \"icon asked for, never registered\".\n */\n async getIconName(): Promise<string | null> {\n const icon = await this.icon();\n return icon ? icon.getAttribute('data-icon') : null;\n }\n\n /**\n * Pick this segment.\n *\n * A click, and deliberately not a keypress: activating a `<button>` from the\n * keyboard is the BROWSER's default action for Enter / Space — the component\n * implements no key handling of its own — and jsdom implements none of it either,\n * so there is nothing here for a key to drive. A no-arg CDK click needs no\n * layout, which is the other half of why this is the drivable path.\n *\n * Nothing happens when the segment is already selected (a segmented control has no\n * untoggle), and nothing happens when it is disabled — but not for the reason the\n * `pointer-events: none` on a whole disabled control suggests, which is CSS a unit\n * test never applies. The CDK's own `click()` reads the native `disabled` PROPERTY\n * and dispatches the mouse sequence WITHOUT the final `click` event, so on a\n * disabled segment the component's handler is never reached at all (measured: zero\n * click events). Either way the value does not move and this resolves quietly, so\n * assert the result rather than assume it, or reach for\n * `WrSegmentedHarness.select()`, which says which of the two it was.\n */\n async select(): Promise<void> {\n return (await this.host()).click();\n }\n\n /** Move keyboard focus to the segment. Each segment is its own tab stop. */\n async focus(): Promise<void> {\n return (await this.host()).focus();\n }\n\n /** Take focus off the segment. */\n async blur(): Promise<void> {\n return (await this.host()).blur();\n }\n\n async isFocused(): Promise<boolean> {\n return (await this.host()).isFocused();\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';\n\nimport type { WrSegmentedSize } from 'ngwr/segmented';\n\nimport type { WrSegmentedHarnessFilters, WrSegmentedOptionHarnessFilters } from './interfaces';\nimport { WrSegmentedOptionHarness } from './wr-segmented-option-harness';\n\n/** Sizes that earn a modifier class — `md` is the default and carries none. */\nconst SIZES: readonly WrSegmentedSize[] = ['sm', 'lg'];\n\n/**\n * Test harness for `<wr-segmented>` — the root of a two-class family with\n * {@link WrSegmentedOptionHarness}.\n *\n * **What the control actually is**, because it decides everything below: not a\n * `radiogroup`, not a `tablist` and not native radios. The host is a plain\n * `role=\"group\"` and each segment is a `<button aria-pressed>` — a row of toggle\n * buttons over one value. Three consequences a spec has to know about:\n *\n * - The selection is `aria-pressed`, on exactly one segment. There is no\n * `aria-checked`, no `aria-selected`, and no \"2 of 3\" position announced.\n * - **There is no roving tab stop.** The component authors no `tabindex` and no\n * arrow-key handler, so every enabled segment is its OWN tab stop —\n * {@link getTabStopLabels} returns a list where a radiogroup or a tablist would\n * have one entry. Focus and selection are therefore independent here:\n * {@link getFocusedLabel} implies nothing about {@link getSelectedIndex}, and\n * arrowing along the strip moves neither.\n * - Activation is the browser's own default action on a button, which jsdom does not\n * implement, so {@link select} clicks — see {@link WrSegmentedOptionHarness.select}.\n *\n * **There is deliberately no `getValue()` and no selection by value.** `options` is\n * a bound array of `{ value, label, … }` and the value is a generic `T` the component\n * writes nowhere — not on the host, not on a segment. The single exception is an\n * accident rather than an addressing scheme: an icon-only option with no `ariaLabel`\n * has its value stringified into the segment's `aria-label`, which for an object\n * value reads `[object Object]`. So address segments by their label\n * ({@link select}) or by position ({@link selectAt}), and assert the picked value on\n * the host's own model — the only place it exists, and the assertion that would have\n * caught the bug anyway.\n *\n * The sliding thumb is decoration (`aria-hidden`), and the four methods that mention\n * it read what the component PUBLISHES for the stylesheet — two custom properties and\n * two modifier classes — never painted geometry, which a DOM without layout does not\n * have. {@link getThumbIndex} in particular is not the selection; it is the trap that\n * method documents.\n *\n * @example\n * ```ts\n * const range = await loader.getHarness(WrSegmentedHarness.with({ label: 'Range' }));\n *\n * expect(await range.getOptionLabels()).toEqual(['Day', 'Week', 'Month']);\n * await range.select({ label: 'Week' });\n * expect(await range.getSelectedIndex()).toBe(1);\n * ```\n *\n * @see https://ngwr.dev/guides/testing\n */\nexport class WrSegmentedHarness extends ComponentHarness {\n static hostSelector = 'wr-segmented';\n\n /** Build a predicate that narrows the query — pass to `getHarness` / `getAllHarnesses`. */\n static with(options: WrSegmentedHarnessFilters = {}): HarnessPredicate<WrSegmentedHarness> {\n return new HarnessPredicate(WrSegmentedHarness, options)\n .addOption('label', options.label, (harness, label) =>\n HarnessPredicate.stringMatches(harness.getAccessibleName(), label)\n )\n .addOption('size', options.size, async (harness, size) => (await harness.getSize()) === size)\n .addOption('disabled', options.disabled, async (harness, disabled) => (await harness.isDisabled()) === disabled);\n }\n\n /**\n * The role the host announces — `group`.\n *\n * Worth pinning precisely because it is the weaker of the shapes this component\n * could have had: a `group` of toggle buttons tells a screen reader that the\n * segments belong together, and nothing more. Were this to become a `radiogroup` or\n * a `tablist`, the keyboard contract would change with it (one tab stop, arrow keys\n * moving the selection), and every spec written against {@link getTabStopLabels}\n * would need to change too.\n */\n async getRole(): Promise<string | null> {\n return (await this.host()).getAttribute('role');\n }\n\n /**\n * The control's accessible name, resolved the way a screen reader resolves it: the\n * text of every element `aria-labelledby` points at, and `aria-label` only when\n * that named nothing. `null` when the consumer wired neither.\n *\n * The order is not interchangeable — `aria-labelledby` WINS in the accessible-name\n * computation — so a control carrying both is announced by the heading it points at,\n * and reporting the `aria-label` would describe a name nobody hears.\n *\n * The component ships no label input on purpose (the question is the consumer's own\n * heading), so this is the only way to check that wiring held, and a `null` on a\n * group of three unrelated-sounding buttons is a real finding.\n */\n async getAccessibleName(): Promise<string | null> {\n const host = await this.host();\n\n const labelledBy = await host.getAttribute('aria-labelledby');\n if (labelledBy !== null) {\n // Resolved from the document root: `aria-labelledby` may point anywhere on the\n // page, and the heading above a control is normally outside it.\n const root = this.documentRootLocatorFactory();\n const texts: string[] = [];\n for (const id of labelledBy.split(/\\s+/).filter(Boolean)) {\n const target = await root.locatorForOptional(`#${id}`)();\n if (target) texts.push(await target.text());\n }\n\n // A reference that resolves to nothing names nothing, and the computation falls\n // through to `aria-label` exactly as it does in a browser.\n if (texts.length) return texts.join(' ');\n }\n\n return host.getAttribute('aria-label');\n }\n\n /** This control's own segments, in DOM order. A sibling control's are not here. */\n async getOptions(filters: WrSegmentedOptionHarnessFilters = {}): Promise<WrSegmentedOptionHarness[]> {\n return this.locatorForAll(WrSegmentedOptionHarness.with(filters))();\n }\n\n /**\n * The accessible name of every segment, in DOM order — the visible labels, with an\n * icon-only segment answering with the `aria-label` that stands in for its text.\n *\n * Throws when a segment has no name at all, rather than leaving a hole in the list:\n * see {@link WrSegmentedOptionHarness.getLabel}.\n */\n async getOptionLabels(): Promise<string[]> {\n const options = await this.getOptions();\n return Promise.all(options.map(option => option.getLabel()));\n }\n\n /** The pressed segment, or `null` when nothing is selected. */\n async getSelectedOption(): Promise<WrSegmentedOptionHarness | null> {\n const [selected] = await this.getOptions({ selected: true });\n return selected ?? null;\n }\n\n /**\n * The accessible name of the pressed segment, or `null` when nothing is selected.\n *\n * `null` is also the answer for a bound value that matches no option — the control\n * holds it, no segment is pressed, and the page shows an unanswered control. See\n * {@link getThumbIndex}, which does NOT answer `null` in that state.\n */\n async getSelectedLabel(): Promise<string | null> {\n const selected = await this.getSelectedOption();\n return selected ? selected.getLabel() : null;\n }\n\n /**\n * The position of the pressed segment, or `-1` when nothing is selected.\n *\n * Derived from `aria-pressed`, which is the selection. The other index on the page —\n * the thumb's — is not; it clamps at 0 (see {@link getThumbIndex}).\n */\n async getSelectedIndex(): Promise<number> {\n const options = await this.getOptions();\n for (let index = 0; index < options.length; index++) {\n if (await options[index].isSelected()) return index;\n }\n return -1;\n }\n\n /**\n * Pick the first segment matching the filters — this is how the control's value\n * changes.\n *\n * Throws when nothing matches, naming the segments that do exist, and throws again\n * when the segment is still unpressed afterwards. That second failure has exactly\n * two causes and reports both, because a click that quietly did nothing surfaces as\n * an unrelated assertion three lines later.\n */\n async select(filters: WrSegmentedOptionHarnessFilters): Promise<void> {\n const [option] = await this.getOptions(filters);\n if (!option) {\n throw new Error(\n `WrSegmentedHarness.select(): no segment matched ${JSON.stringify(filters)}. This control offers: ` +\n `${(await this.describeOptions()).join(', ')}.`\n );\n }\n await this.pick(option, 'select');\n }\n\n /**\n * Pick the segment at a position, counting from zero — the addressing route for an\n * icon-only strip, or for one whose labels a spec would rather not hard-code.\n *\n * Throws on an index outside the control, saying how many segments there are: an\n * off-by-one that resolved to nothing would otherwise read as \"the click did not\n * take\".\n */\n async selectAt(index: number): Promise<void> {\n const options = await this.getOptions();\n const option = options[index];\n if (!option) {\n throw new Error(\n `WrSegmentedHarness.selectAt(): index ${index} is outside this control, which has ${options.length} ` +\n `segment(s): ${(await this.describeOptions()).join(', ')}.`\n );\n }\n await this.pick(option, 'selectAt');\n }\n\n /**\n * Whether the control was disabled AS A WHOLE, from the `wr-segmented--disabled`\n * modifier.\n *\n * Deliberately not \"every segment is disabled\": a control whose options each carry\n * their own `disabled` looks identical to a user, and the modifier is the only thing\n * on the page that tells the two apart. What actually blocks a click is the native\n * `disabled` each button gets either way — ask a segment\n * ({@link WrSegmentedOptionHarness.isDisabled}) for that.\n */\n async isDisabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-segmented--disabled');\n }\n\n /**\n * The rendered control size.\n *\n * `md` is the component's own default and earns NO modifier class, so a bare host\n * IS `md` — the absence is the answer rather than a missing one. Read from the\n * class instead of the input, which is also why this reports what was rendered:\n * unlike the form controls, `<wr-segmented>` does not resolve its size through\n * `provideWrConfig()`, so an app-wide default set there does not reach it and this\n * will say so.\n */\n async getSize(): Promise<WrSegmentedSize> {\n const host = await this.host();\n for (const size of SIZES) {\n if (await host.hasClass(`wr-segmented--${size}`)) return size;\n }\n return 'md';\n }\n\n /**\n * The accessible name of every segment a Tab press can reach, in tab order.\n *\n * A LIST, not one label, and that is the shape worth pinning: the component authors\n * no roving `tabindex`, so each enabled segment is its own tab stop and reaching the\n * third one takes three Tabs. An all-disabled control is skipped over entirely and\n * answers `[]`.\n *\n * Unnamed segments are reported as `(unnamed)` rather than throwing — a tab order is\n * still a fact worth reading on a page that has that bug in it.\n */\n async getTabStopLabels(): Promise<string[]> {\n const enabled = await this.getOptions({ disabled: false });\n return this.describe(enabled);\n }\n\n /**\n * The accessible name of the segment that currently holds focus, or `null` when\n * focus is elsewhere.\n *\n * Independent of the selection here — see the note on the class. Reported as\n * `(unnamed)` for a segment with no name, for the reason\n * {@link getTabStopLabels} gives.\n */\n async getFocusedLabel(): Promise<string | null> {\n for (const option of await this.getOptions()) {\n if (await option.isFocused()) {\n return (await option.getAccessibleName()) ?? '(unnamed)';\n }\n }\n return null;\n }\n\n /**\n * The index the component publishes for the thumb, from the\n * `--wr-segmented-thumb-index` custom property it sets inline.\n *\n * **Not the selection, and this is the difference that bites.** The property is\n * `Math.max(0, selectedIndex)`, so a control holding a value that matches no option\n * publishes `0` — the thumb parks under the FIRST segment and is hidden by\n * {@link isThumbVisible} instead of being moved out of the way. A harness that read\n * this to answer \"which segment is selected\" would report segment one for a control\n * with no selection at all. {@link getSelectedIndex} is the selection.\n *\n * It is also not where the thumb IS: the stylesheet turns this into a `translateX`,\n * and no measurement of that survives a DOM without layout. This is the input to\n * that, which is the part a unit test can honestly check.\n */\n async getThumbIndex(): Promise<number> {\n return this.thumbVar('--wr-segmented-thumb-index');\n }\n\n /**\n * The segment count the component publishes for the thumb, from\n * `--wr-segmented-thumb-count` — the divisor the stylesheet computes the thumb's\n * width with.\n *\n * Should always equal the number of segments, and the reason to ask is that nothing\n * else notices when it does not: a count that fell out of step with the options\n * leaves the thumb the wrong width and sliding to the wrong place, while every ARIA\n * state on the page stays correct. It is clamped to a minimum of `1`, so an empty\n * control reports `1` rather than dividing by zero.\n */\n async getThumbCount(): Promise<number> {\n return this.thumbVar('--wr-segmented-thumb-count');\n }\n\n /**\n * Whether the thumb is being shown at all.\n *\n * Read from the ABSENCE of the `wr-segmented--unselected` modifier, which is the\n * hook the stylesheet zeroes the thumb's opacity through. The computed opacity is\n * not the answer here — a unit test applies no stylesheet — so the public modifier\n * is the contract, and it is what tells \"parked under segment one\" from \"hidden\n * because nothing is selected\".\n */\n async isThumbVisible(): Promise<boolean> {\n return !(await (await this.host()).hasClass('wr-segmented--unselected'));\n }\n\n /**\n * Whether the thumb will animate its next move, from the `wr-segmented--mounted`\n * modifier that gates the transition.\n *\n * Not \"the thumb is animating now\": nothing about a running animation is visible to\n * a unit test. What this pins is the deliberate asymmetry — the class is added in\n * `afterNextRender`, so the FIRST snap to the initial value is instant and every\n * user-driven move after it slides. Deferred work like that only lands once the\n * fixture is stable, which every harness read already waits for.\n */\n async isThumbTransitionEnabled(): Promise<boolean> {\n return (await this.host()).hasClass('wr-segmented--mounted');\n }\n\n /** Click a segment and turn a click that did nothing into a failure that says why. */\n private async pick(option: WrSegmentedOptionHarness, caller: 'select' | 'selectAt'): Promise<void> {\n await option.select();\n\n if (!(await option.isSelected())) {\n const name = (await option.getAccessibleName()) ?? '(unnamed)';\n throw new Error(\n `WrSegmentedHarness.${caller}(): \"${name}\" is still unpressed after being clicked — either that ` +\n 'option carries `disabled` or the whole control does.'\n );\n }\n }\n\n /** Segment names for an error message, which must not throw on its way out. */\n private async describeOptions(): Promise<string[]> {\n return this.describe(await this.getOptions());\n }\n\n private async describe(options: readonly WrSegmentedOptionHarness[]): Promise<string[]> {\n return Promise.all(options.map(async option => (await option.getAccessibleName()) ?? '(unnamed)'));\n }\n\n /**\n * One custom property off the host's `style` ATTRIBUTE.\n *\n * Not `getCssValue()`, which is `getComputedStyle`: with the entry point's own\n * stylesheet loaded that resolves the sheet's declaration, so the method\n * answers plausibly at exactly the moment the host binding — the thing under\n * test — is what broke. The attribute holds only what the component wrote.\n */\n private async inlineVar(property: string): Promise<string> {\n const attr = (await (await this.host()).getAttribute('style')) ?? '';\n const found = new RegExp(`(?:^|;)\\\\s*${property}\\\\s*:\\\\s*([^;]+)`).exec(attr);\n return (found?.[1] ?? '').trim();\n }\n\n /** One of the thumb's inline custom properties, as a number. */\n private async thumbVar(property: string): Promise<number> {\n const raw = await this.inlineVar(property);\n const value = Number.parseInt(raw, 10);\n if (Number.isNaN(value)) {\n throw new Error(\n `WrSegmentedHarness: could not read \\`${property}\\`, which computed to \"${raw}\". The component sets it ` +\n 'inline on the host; an environment that drops custom properties cannot answer this.'\n );\n }\n return value;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;AAAA;;;;;AAKG;AAMH;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;AACG,MAAO,wBAAyB,SAAQ,gBAAgB,CAAA;;AAE5D,IAAA,OAAO,YAAY,GAAG,uBAAuB;;AAG7C,IAAA,OAAO,IAAI,CAAC,OAAA,GAA2C,EAAE,EAAA;AACvD,QAAA,QACE,IAAI,gBAAgB,CAAC,wBAAwB,EAAE,OAAO;;;;aAInD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,KAChD,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,KAAK,CAAC;aAEnE,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,QAAQ;aAC9G,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC;IAEtH;AAEiB,IAAA,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,sBAAsB,CAAC;AAC3D,IAAA,IAAI,GAAG,IAAI,CAAC,kBAAkB,CAAC,qBAAqB,CAAC;AAEtE;;;;;;AAMG;AACH,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE;AACpC,QAAA,OAAO,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI;IACpC;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,MAAM,iBAAiB,GAAA;AACrB,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE;QACjC,IAAI,IAAI,KAAK,IAAI;AAAE,YAAA,OAAO,IAAI;AAC9B,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,YAAY,CAAC;IACvD;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,QAAQ,GAAA;AACZ,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE;AAC3C,QAAA,IAAI,IAAI,KAAK,IAAI,EAAE;YACjB,MAAM,IAAI,KAAK,CACb,qGAAqG;gBACnG,iGAAiG;AACjG,gBAAA,mCAAmC,CACtC;QACH;AACA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,cAAc,CAAC,MAAM,MAAM;IAC5E;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,WAAW,CAAU,UAAU,CAAC;IAC7D;;AAGA,IAAA,MAAM,OAAO,GAAA;QACX,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI;IACrC;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,WAAW,GAAA;AACf,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE;AAC9B,QAAA,OAAO,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI;IACrD;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACH,IAAA,MAAM,MAAM,GAAA;QACV,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACpC;;AAGA,IAAA,MAAM,KAAK,GAAA;QACT,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE;IACpC;;AAGA,IAAA,MAAM,IAAI,GAAA;QACR,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE;IACnC;AAEA,IAAA,MAAM,SAAS,GAAA;QACb,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE;IACxC;;;AC5LF;;;;;AAKG;AASH;AACA,MAAM,KAAK,GAA+B,CAAC,IAAI,EAAE,IAAI,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CG;AACG,MAAO,kBAAmB,SAAQ,gBAAgB,CAAA;AACtD,IAAA,OAAO,YAAY,GAAG,cAAc;;AAGpC,IAAA,OAAO,IAAI,CAAC,OAAA,GAAqC,EAAE,EAAA;AACjD,QAAA,OAAO,IAAI,gBAAgB,CAAC,kBAAkB,EAAE,OAAO;aACpD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,KAChD,gBAAgB,CAAC,aAAa,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,KAAK,CAAC;aAEnE,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,OAAO,EAAE,IAAI,KAAK,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI;aAC3F,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,MAAM,QAAQ,CAAC;IACpH;AAEA;;;;;;;;;AASG;AACH,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,MAAM,CAAC;IACjD;AAEA;;;;;;;;;;;;AAYG;AACH,IAAA,MAAM,iBAAiB,GAAA;AACrB,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE;QAE9B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC;AAC7D,QAAA,IAAI,UAAU,KAAK,IAAI,EAAE;;;AAGvB,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,0BAA0B,EAAE;YAC9C,MAAM,KAAK,GAAa,EAAE;AAC1B,YAAA,KAAK,MAAM,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;AACxD,gBAAA,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC,EAAE;AACxD,gBAAA,IAAI,MAAM;oBAAE,KAAK,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YAC7C;;;YAIA,IAAI,KAAK,CAAC,MAAM;AAAE,gBAAA,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;QAC1C;AAEA,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC;IACxC;;AAGA,IAAA,MAAM,UAAU,CAAC,OAAA,GAA2C,EAAE,EAAA;AAC5D,QAAA,OAAO,IAAI,CAAC,aAAa,CAAC,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE;IACrE;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,eAAe,GAAA;AACnB,QAAA,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;AACvC,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D;;AAGA,IAAA,MAAM,iBAAiB,GAAA;AACrB,QAAA,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC5D,OAAO,QAAQ,IAAI,IAAI;IACzB;AAEA;;;;;;AAMG;AACH,IAAA,MAAM,gBAAgB,GAAA;AACpB,QAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,iBAAiB,EAAE;AAC/C,QAAA,OAAO,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,IAAI;IAC9C;AAEA;;;;;AAKG;AACH,IAAA,MAAM,gBAAgB,GAAA;AACpB,QAAA,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;AACvC,QAAA,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;AACnD,YAAA,IAAI,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE;AAAE,gBAAA,OAAO,KAAK;QACrD;QACA,OAAO,CAAC,CAAC;IACX;AAEA;;;;;;;;AAQG;IACH,MAAM,MAAM,CAAC,OAAwC,EAAA;QACnD,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAC/C,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,KAAK,CACb,CAAA,gDAAA,EAAmD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA,uBAAA,CAAyB;AACjG,gBAAA,CAAA,EAAG,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAClD;QACH;QACA,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC;IACnC;AAEA;;;;;;;AAOG;IACH,MAAM,QAAQ,CAAC,KAAa,EAAA;AAC1B,QAAA,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE;AACvC,QAAA,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,KAAK,CACb,CAAA,qCAAA,EAAwC,KAAK,CAAA,oCAAA,EAAuC,OAAO,CAAC,MAAM,CAAA,CAAA,CAAG;AACnG,gBAAA,CAAA,YAAA,EAAe,CAAC,MAAM,IAAI,CAAC,eAAe,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAC9D;QACH;QACA,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;IACrC;AAEA;;;;;;;;;AASG;AACH,IAAA,MAAM,UAAU,GAAA;AACd,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,wBAAwB,CAAC;IAC/D;AAEA;;;;;;;;;AASG;AACH,IAAA,MAAM,OAAO,GAAA;AACX,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE;AAC9B,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,IAAI,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA,cAAA,EAAiB,IAAI,EAAE,CAAC;AAAE,gBAAA,OAAO,IAAI;QAC/D;AACA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;AAUG;AACH,IAAA,MAAM,gBAAgB,GAAA;AACpB,QAAA,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAC1D,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;IAC/B;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,eAAe,GAAA;QACnB,KAAK,MAAM,MAAM,IAAI,MAAM,IAAI,CAAC,UAAU,EAAE,EAAE;AAC5C,YAAA,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE;gBAC5B,OAAO,CAAC,MAAM,MAAM,CAAC,iBAAiB,EAAE,KAAK,WAAW;YAC1D;QACF;AACA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;;;;;AAcG;AACH,IAAA,MAAM,aAAa,GAAA;AACjB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC;IACpD;AAEA;;;;;;;;;;AAUG;AACH,IAAA,MAAM,aAAa,GAAA;AACjB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC;IACpD;AAEA;;;;;;;;AAQG;AACH,IAAA,MAAM,cAAc,GAAA;AAClB,QAAA,OAAO,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,0BAA0B,CAAC,CAAC;IAC1E;AAEA;;;;;;;;;AASG;AACH,IAAA,MAAM,wBAAwB,GAAA;AAC5B,QAAA,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,uBAAuB,CAAC;IAC9D;;AAGQ,IAAA,MAAM,IAAI,CAAC,MAAgC,EAAE,MAA6B,EAAA;AAChF,QAAA,MAAM,MAAM,CAAC,MAAM,EAAE;QAErB,IAAI,EAAE,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE;YAChC,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,iBAAiB,EAAE,KAAK,WAAW;AAC9D,YAAA,MAAM,IAAI,KAAK,CACb,sBAAsB,MAAM,CAAA,KAAA,EAAQ,IAAI,CAAA,uDAAA,CAAyD;AAC/F,gBAAA,sDAAsD,CACzD;QACH;IACF;;AAGQ,IAAA,MAAM,eAAe,GAAA;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;IAC/C;IAEQ,MAAM,QAAQ,CAAC,OAA4C,EAAA;QACjE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAM,MAAM,KAAI,CAAC,MAAM,MAAM,CAAC,iBAAiB,EAAE,KAAK,WAAW,CAAC,CAAC;IACpG;AAEA;;;;;;;AAOG;IACK,MAAM,SAAS,CAAC,QAAgB,EAAA;AACtC,QAAA,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE;AACpE,QAAA,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,CAAA,WAAA,EAAc,QAAQ,CAAA,gBAAA,CAAkB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AAC7E,QAAA,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE;IAClC;;IAGQ,MAAM,QAAQ,CAAC,QAAgB,EAAA;QACrC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;AACtC,QAAA,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;AACvB,YAAA,MAAM,IAAI,KAAK,CACb,wCAAwC,QAAQ,CAAA,uBAAA,EAA0B,GAAG,CAAA,yBAAA,CAA2B;AACtG,gBAAA,qFAAqF,CACxF;QACH;AACA,QAAA,OAAO,KAAK;IACd;;;ACpYF;;AAEG;;;;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { Directionality } from '@angular/cdk/bidi';
|
|
1
2
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
2
3
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { input, model, computed, signal, afterNextRender, ViewEncapsulation, Component } from '@angular/core';
|
|
4
|
+
import { input, model, computed, signal, afterNextRender, inject, ViewEncapsulation, Component } from '@angular/core';
|
|
4
5
|
import { WrIcon } from 'ngwr/icon';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -47,12 +48,34 @@ class WrSegmented {
|
|
|
47
48
|
return parts.join(' ');
|
|
48
49
|
}, /* @ts-ignore */
|
|
49
50
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
50
|
-
|
|
51
|
+
dir = inject(Directionality, { optional: true });
|
|
52
|
+
/**
|
|
53
|
+
* Reading direction of the strip. `Directionality` is root-provided, so this
|
|
54
|
+
* always resolves — `optional` only guards a consumer who has deliberately
|
|
55
|
+
* torn the provider out. A subtree that overrides the direction does it with
|
|
56
|
+
* the CDK's `Dir` directive, which writes `valueSignal`, so `thumbStyle`
|
|
57
|
+
* re-renders instead of leaving the thumb parked on the old segment.
|
|
58
|
+
*/
|
|
59
|
+
isRtl = computed(() => this.dir?.valueSignal() === 'rtl', /* @ts-ignore */
|
|
60
|
+
...(ngDevMode ? [{ debugName: "isRtl" }] : /* istanbul ignore next */ []));
|
|
61
|
+
/**
|
|
62
|
+
* Inline CSS vars driving the sliding thumb position.
|
|
63
|
+
*
|
|
64
|
+
* `--wr-segmented-thumb-index` is the SLOT the thumb parks in, counted from the
|
|
65
|
+
* physical left, which is the selected index only in LTR. The stylesheet anchors
|
|
66
|
+
* the thumb with a physical `left` and slides it with `translateX` — neither has
|
|
67
|
+
* a logical form — while the options are a grid that mirrors, so under `dir="rtl"`
|
|
68
|
+
* the segment at logical index `i` occupies slot `count - 1 - i`. Left unsigned,
|
|
69
|
+
* the pill sat under a different label than the one it marks (the whole strip's
|
|
70
|
+
* worth of offset at the far end), which is the carousel's `trackStyle` problem
|
|
71
|
+
* one component over.
|
|
72
|
+
*/
|
|
51
73
|
thumbStyle = computed(() => {
|
|
52
74
|
const i = Math.max(0, this.selectedIndex());
|
|
53
75
|
const count = Math.max(1, this.options().length);
|
|
76
|
+
const slot = this.isRtl() ? count - 1 - i : i;
|
|
54
77
|
return {
|
|
55
|
-
'--wr-segmented-thumb-index': `${
|
|
78
|
+
'--wr-segmented-thumb-index': `${slot}`,
|
|
56
79
|
'--wr-segmented-thumb-count': `${count}`,
|
|
57
80
|
};
|
|
58
81
|
}, /* @ts-ignore */
|
|
@@ -68,10 +91,10 @@ class WrSegmented {
|
|
|
68
91
|
trackByValue(_, option) {
|
|
69
92
|
return option.value;
|
|
70
93
|
}
|
|
71
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
72
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
94
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrSegmented, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
95
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrSegmented, isStandalone: true, selector: "wr-segmented", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { attributes: { "role": "group" }, properties: { "class": "classes()", "style": "thumbStyle()" } }, ngImport: i0, template: "<span class=\"wr-segmented__thumb\" aria-hidden=\"true\"></span>\n\n@for (option of options(); track option.value) {\n <button\n type=\"button\"\n class=\"wr-segmented__option\"\n [class.wr-segmented__option--selected]=\"isSelected(option)\"\n [disabled]=\"disabled() || !!option.disabled\"\n [attr.aria-pressed]=\"isSelected(option)\"\n [attr.aria-label]=\"option.label ? null : (option.ariaLabel ?? option.value)\"\n (click)=\"select(option)\"\n >\n @if (option.icon) {\n <wr-icon class=\"wr-segmented__icon\" [name]=\"option.icon\" />\n }\n @if (option.label) {\n <span class=\"wr-segmented__label\">{{ option.label }}</span>\n }\n </button>\n}\n", dependencies: [{ kind: "component", type: WrIcon, selector: "wr-icon", inputs: ["name"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
73
96
|
}
|
|
74
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
97
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrSegmented, decorators: [{
|
|
75
98
|
type: Component,
|
|
76
99
|
args: [{ selector: 'wr-segmented', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()', '[style]': 'thumbStyle()', role: 'group' }, imports: [WrIcon], template: "<span class=\"wr-segmented__thumb\" aria-hidden=\"true\"></span>\n\n@for (option of options(); track option.value) {\n <button\n type=\"button\"\n class=\"wr-segmented__option\"\n [class.wr-segmented__option--selected]=\"isSelected(option)\"\n [disabled]=\"disabled() || !!option.disabled\"\n [attr.aria-pressed]=\"isSelected(option)\"\n [attr.aria-label]=\"option.label ? null : (option.ariaLabel ?? option.value)\"\n (click)=\"select(option)\"\n >\n @if (option.icon) {\n <wr-icon class=\"wr-segmented__icon\" [name]=\"option.icon\" />\n }\n @if (option.label) {\n <span class=\"wr-segmented__label\">{{ option.label }}</span>\n }\n </button>\n}\n" }]
|
|
77
100
|
}], ctorParameters: () => [], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
|