ngwr 14.3.1 → 14.5.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 +4 -4
- package/avatar/styles/_index.scss +4 -2
- package/badge/styles/_index.scss +4 -1
- package/badge/styles/_tag.scss +3 -0
- package/cascader/styles/_rules.scss +3 -0
- package/command-palette/styles/_index.scss +23 -0
- package/context-menu/styles/_index.scss +13 -1
- package/fesm2022/ngwr-action-sheet.mjs +3 -3
- package/fesm2022/ngwr-affix.mjs +17 -4
- package/fesm2022/ngwr-affix.mjs.map +1 -1
- package/fesm2022/ngwr-alert.mjs +4 -4
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- 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 +18 -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-border-glow.mjs +3 -3
- package/fesm2022/ngwr-breadcrumbs.mjs +7 -7
- 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-testing.mjs +12 -9
- package/fesm2022/ngwr-calendar-heatmap-testing.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap.mjs +35 -7
- package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
- package/fesm2022/ngwr-calendar.mjs +32 -4
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-card.mjs +9 -9
- package/fesm2022/ngwr-carousel.mjs +6 -6
- package/fesm2022/ngwr-cascader-testing.mjs +87 -17
- package/fesm2022/ngwr-cascader-testing.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +76 -5
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox-testing.mjs +13 -2
- package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox.mjs +42 -7
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text.mjs +3 -3
- package/fesm2022/ngwr-click-spark.mjs +3 -3
- package/fesm2022/ngwr-clipboard.mjs +3 -3
- package/fesm2022/ngwr-collapse.mjs +9 -9
- package/fesm2022/ngwr-color-picker.mjs +24 -8
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +16 -3
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-compare.mjs +3 -3
- package/fesm2022/ngwr-confetti.mjs +3 -3
- package/fesm2022/ngwr-context-menu.mjs +47 -15
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-cookie.mjs +3 -3
- package/fesm2022/ngwr-counter.mjs +6 -6
- package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
- package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
- package/fesm2022/ngwr-date-picker.mjs +111 -28
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/ngwr-date.mjs +3 -3
- 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 +27 -16
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +12 -12
- package/fesm2022/ngwr-divider.mjs +3 -3
- package/fesm2022/ngwr-donut-chart-testing.mjs +18 -2
- package/fesm2022/ngwr-donut-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart.mjs +4 -4
- package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +7 -7
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +66 -20
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +54 -16
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-empty.mjs +3 -3
- package/fesm2022/ngwr-event-calendar.mjs +6 -6
- package/fesm2022/ngwr-falling-text.mjs +3 -3
- package/fesm2022/ngwr-file-upload.mjs +18 -5
- package/fesm2022/ngwr-file-upload.mjs.map +1 -1
- package/fesm2022/ngwr-form.mjs +66 -14
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
- package/fesm2022/ngwr-gauge-testing.mjs +16 -2
- package/fesm2022/ngwr-gauge-testing.mjs.map +1 -1
- package/fesm2022/ngwr-gauge.mjs +3 -3
- package/fesm2022/ngwr-glitch-text.mjs +3 -3
- package/fesm2022/ngwr-gradient-text.mjs +3 -3
- package/fesm2022/ngwr-graph-testing.mjs +243 -0
- package/fesm2022/ngwr-graph-testing.mjs.map +1 -0
- package/fesm2022/ngwr-graph.mjs +1112 -0
- package/fesm2022/ngwr-graph.mjs.map +1 -0
- package/fesm2022/ngwr-hotkey.mjs +6 -6
- package/fesm2022/ngwr-i18n-ar.mjs +7 -0
- package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-cs.mjs +7 -0
- package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-de.mjs +7 -0
- package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +23 -2
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-es.mjs +7 -0
- package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-fr.mjs +7 -0
- package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-he.mjs +7 -0
- package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-hi.mjs +7 -0
- package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-id.mjs +7 -0
- package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-it.mjs +7 -0
- package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ja.mjs +7 -0
- package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ko.mjs +7 -0
- package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-nl.mjs +7 -0
- package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pl.mjs +7 -0
- package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pt.mjs +7 -0
- package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +7 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-sv.mjs +7 -0
- package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-tr.mjs +7 -0
- package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-uk.mjs +7 -0
- package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-vi.mjs +7 -0
- package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh-TW.mjs +7 -0
- package/fesm2022/ngwr-i18n-zh-TW.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh.mjs +7 -0
- package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
- package/fesm2022/ngwr-i18n.mjs +9 -9
- package/fesm2022/ngwr-icon.mjs +6 -6
- package/fesm2022/ngwr-image-cropper.mjs +3 -3
- package/fesm2022/ngwr-input-number.mjs +15 -6
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp.mjs +38 -6
- 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-testing.mjs +11 -3
- package/fesm2022/ngwr-knob-testing.mjs.map +1 -1
- package/fesm2022/ngwr-knob.mjs +19 -4
- package/fesm2022/ngwr-knob.mjs.map +1 -1
- package/fesm2022/ngwr-layout.mjs +15 -15
- package/fesm2022/ngwr-lightbox.mjs +27 -6
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart-testing.mjs +18 -2
- package/fesm2022/ngwr-line-chart-testing.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart.mjs +22 -4
- 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 +6 -6
- package/fesm2022/ngwr-markdown.mjs +6 -6
- package/fesm2022/ngwr-marquee.mjs +3 -3
- package/fesm2022/ngwr-media.mjs +3 -3
- package/fesm2022/ngwr-mention.mjs +24 -8
- package/fesm2022/ngwr-mention.mjs.map +1 -1
- package/fesm2022/ngwr-meta.mjs +6 -6
- package/fesm2022/ngwr-meter-group.mjs +3 -3
- package/fesm2022/ngwr-overlay.mjs +125 -10
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-page-header.mjs +3 -3
- package/fesm2022/ngwr-pagination.mjs +33 -6
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +21 -21
- package/fesm2022/ngwr-platform.mjs +9 -9
- package/fesm2022/ngwr-popconfirm.mjs +25 -9
- package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
- package/fesm2022/ngwr-popover-testing.mjs +22 -5
- package/fesm2022/ngwr-popover-testing.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +243 -37
- 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 +3 -3
- package/fesm2022/ngwr-radio.mjs +6 -6
- package/fesm2022/ngwr-rating-testing.mjs +12 -3
- package/fesm2022/ngwr-rating-testing.mjs.map +1 -1
- package/fesm2022/ngwr-rating.mjs +19 -4
- package/fesm2022/ngwr-rating.mjs.map +1 -1
- package/fesm2022/ngwr-result.mjs +13 -13
- package/fesm2022/ngwr-result.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text.mjs +3 -3
- package/fesm2022/ngwr-schema-form.mjs +3 -3
- package/fesm2022/ngwr-scroll.mjs +3 -3
- package/fesm2022/ngwr-segmented.mjs +37 -4
- package/fesm2022/ngwr-segmented.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +24 -10
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +6 -6
- package/fesm2022/ngwr-sidebar.mjs +3 -3
- package/fesm2022/ngwr-skeleton.mjs +3 -3
- package/fesm2022/ngwr-slider.mjs +18 -5
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline.mjs +3 -3
- package/fesm2022/ngwr-speed-dial.mjs +3 -3
- package/fesm2022/ngwr-spinner.mjs +3 -3
- package/fesm2022/ngwr-splash-cursor.mjs +3 -3
- package/fesm2022/ngwr-split-text.mjs +3 -3
- package/fesm2022/ngwr-splitter.mjs +3 -3
- package/fesm2022/ngwr-spotlight-card.mjs +6 -6
- package/fesm2022/ngwr-squircle.mjs +28 -9
- package/fesm2022/ngwr-squircle.mjs.map +1 -1
- package/fesm2022/ngwr-star-border.mjs +3 -3
- package/fesm2022/ngwr-statistic.mjs +20 -13
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-stepper.mjs +6 -6
- package/fesm2022/ngwr-storage.mjs +3 -3
- package/fesm2022/ngwr-switch.mjs +3 -3
- package/fesm2022/ngwr-table.mjs +18 -18
- package/fesm2022/ngwr-tabs-router.mjs +3 -3
- package/fesm2022/ngwr-tabs.mjs +6 -6
- package/fesm2022/ngwr-textarea.mjs +3 -3
- package/fesm2022/ngwr-theme.mjs +3 -3
- package/fesm2022/ngwr-tilt-card.mjs +6 -6
- package/fesm2022/ngwr-timeline.mjs +6 -6
- package/fesm2022/ngwr-toast.mjs +29 -12
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-toolbar.mjs +3 -3
- package/fesm2022/ngwr-tour.mjs +26 -12
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-transfer.mjs +88 -11
- package/fesm2022/ngwr-transfer.mjs.map +1 -1
- package/fesm2022/ngwr-tree-testing.mjs +24 -0
- package/fesm2022/ngwr-tree-testing.mjs.map +1 -1
- package/fesm2022/ngwr-tree.mjs +81 -9
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter.mjs +3 -3
- package/fesm2022/ngwr-typography.mjs +3 -3
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
- package/fesm2022/ngwr-waves.mjs +3 -3
- package/fesm2022/ngwr-window.mjs +30 -13
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/form/styles/_index.scss +63 -0
- package/graph/styles/_index.scss +113 -0
- package/i18n/ar.json +9 -2
- package/i18n/cs.json +9 -2
- package/i18n/de.json +9 -2
- package/i18n/en.json +11 -4
- package/i18n/es.json +9 -2
- package/i18n/fr.json +9 -2
- package/i18n/he.json +9 -2
- package/i18n/hi.json +9 -2
- package/i18n/id.json +9 -2
- package/i18n/it.json +9 -2
- package/i18n/ja.json +9 -2
- package/i18n/ko.json +9 -2
- package/i18n/nl.json +9 -2
- package/i18n/pl.json +9 -2
- package/i18n/pt.json +9 -2
- package/i18n/ru.json +9 -2
- package/i18n/sv.json +9 -2
- package/i18n/tr.json +9 -2
- package/i18n/uk.json +9 -2
- package/i18n/vi.json +9 -2
- package/i18n/zh-TW.json +9 -2
- package/i18n/zh.json +9 -2
- package/input-otp/styles/_index.scss +5 -1
- package/line-chart/styles/_index.scss +5 -3
- package/llms-full.txt +13 -3
- package/llms.txt +8 -6
- package/markdown/styles/_index.scss +4 -1
- package/mention/styles/_index.scss +22 -1
- package/package.json +10 -1
- package/radio/styles/_index.scss +3 -0
- package/result/styles/_index.scss +12 -0
- package/schematics/migrations/v14/index.js +6 -3
- package/schematics/migrations.json +1 -1
- package/schematics/ng-add/index.js +34 -5
- package/schematics/use/symbol-map.json +2 -0
- package/segmented/styles/_index.scss +12 -1
- package/select/styles/_index.scss +20 -1
- package/skills/ngwr/SKILL.md +1 -1
- package/skills/ngwr/references/catalog.md +2 -0
- package/statistic/styles/_index.scss +4 -0
- package/stepper/styles/_index.scss +36 -0
- package/styles.scss +1 -0
- package/switch/styles/_index.scss +3 -0
- package/table/styles/_index.scss +12 -0
- package/tabs/styles/_index.scss +4 -1
- package/textarea/styles/_index.scss +6 -1
- package/theme/styles/_colors.scss +11 -0
- package/theme/styles/_contrast.scss +136 -0
- package/theme/styles/_focus.scss +7 -0
- package/theme/styles/_index.scss +1 -0
- package/theme/styles/_mixins.scss +15 -8
- package/timeline/styles/_index.scss +28 -1
- package/toast/styles/_index.scss +11 -0
- package/tree/styles/_index.scss +27 -1
- package/types/ngwr-badge.d.ts +1 -1
- package/types/ngwr-bar-chart-testing.d.ts +11 -1
- package/types/ngwr-button.d.ts +1 -1
- package/types/ngwr-calendar-heatmap-testing.d.ts +10 -5
- package/types/ngwr-calendar-heatmap.d.ts +22 -0
- package/types/ngwr-calendar.d.ts +21 -0
- package/types/ngwr-cascader-testing.d.ts +74 -17
- package/types/ngwr-cascader.d.ts +35 -0
- package/types/ngwr-checkbox-testing.d.ts +12 -1
- package/types/ngwr-checkbox.d.ts +10 -0
- package/types/ngwr-clipboard.d.ts +1 -1
- package/types/ngwr-color-picker.d.ts +8 -0
- package/types/ngwr-confetti.d.ts +1 -1
- package/types/ngwr-context-menu.d.ts +10 -0
- package/types/ngwr-cookie.d.ts +1 -1
- package/types/ngwr-date-adapters-fns.d.ts +1 -1
- package/types/ngwr-date-adapters-luxon.d.ts +1 -1
- package/types/ngwr-date-picker.d.ts +16 -0
- package/types/ngwr-date.d.ts +9 -3
- package/types/ngwr-density.d.ts +1 -1
- package/types/ngwr-dialog.d.ts +2 -1
- package/types/ngwr-donut-chart-testing.d.ts +11 -1
- package/types/ngwr-drawer.d.ts +29 -1
- package/types/ngwr-dropdown.d.ts +25 -0
- package/types/ngwr-file-upload.d.ts +11 -0
- package/types/ngwr-form.d.ts +25 -0
- package/types/ngwr-gauge-testing.d.ts +9 -1
- package/types/ngwr-graph-testing.d.ts +190 -0
- package/types/ngwr-graph.d.ts +203 -0
- package/types/ngwr-hotkey.d.ts +1 -1
- package/types/ngwr-i18n.d.ts +1 -1
- package/types/ngwr-input-number.d.ts +12 -2
- package/types/ngwr-input-otp.d.ts +12 -0
- package/types/ngwr-knob-testing.d.ts +11 -3
- package/types/ngwr-knob.d.ts +13 -0
- package/types/ngwr-lightbox.d.ts +15 -0
- package/types/ngwr-line-chart-testing.d.ts +11 -1
- package/types/ngwr-line-chart.d.ts +18 -0
- package/types/ngwr-loading-bar.d.ts +1 -1
- package/types/ngwr-markdown.d.ts +1 -1
- package/types/ngwr-media.d.ts +1 -1
- package/types/ngwr-mention.d.ts +7 -0
- package/types/ngwr-meta.d.ts +1 -1
- package/types/ngwr-overlay.d.ts +64 -6
- package/types/ngwr-pagination.d.ts +16 -0
- package/types/ngwr-platform.d.ts +3 -3
- package/types/ngwr-popconfirm.d.ts +1 -0
- package/types/ngwr-popover-testing.d.ts +22 -5
- package/types/ngwr-popover.d.ts +44 -8
- package/types/ngwr-rating-testing.d.ts +12 -3
- package/types/ngwr-rating.d.ts +13 -0
- package/types/ngwr-scroll.d.ts +1 -1
- package/types/ngwr-segmented.d.ts +16 -0
- package/types/ngwr-select.d.ts +7 -0
- package/types/ngwr-squircle.d.ts +22 -3
- package/types/ngwr-statistic.d.ts +0 -1
- package/types/ngwr-storage.d.ts +1 -1
- package/types/ngwr-theme.d.ts +1 -1
- package/types/ngwr-toast.d.ts +3 -1
- package/types/ngwr-tour.d.ts +7 -1
- package/types/ngwr-transfer.d.ts +52 -0
- package/types/ngwr-tree-testing.d.ts +20 -0
- package/types/ngwr-tree.d.ts +43 -1
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-window.d.ts +2 -1
- package/typography/styles/_index.scss +26 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-rating.mjs","sources":["../../../projects/lib/rating/rating.ts","../../../projects/lib/rating/rating.html","../../../projects/lib/rating/ngwr-rating.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 { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input, model, output, signal } from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useFormFieldAria } from 'ngwr/form';\nimport { useI18nText } from 'ngwr/i18n';\nimport { clamp } from 'ngwr/utils';\n\n/**\n * Star rating input. Click or hover to set a value; supports half-star\n * increments via `step=\"0.5\"`. Value is `number | null`.\n *\n * `[0, count]` bounds what this control's OWN edits produce — a click, an arrow\n * key, `End`. A value written from outside is displayed and announced clamped\n * (a slider cannot report an `aria-valuenow` past its own `aria-valuemax`) and\n * left in the model as it stands, the same rule `wr-slider` and\n * `wr-input-number` follow.\n *\n * A signal-forms native control: it implements `FormValueControl<number | null>`,\n * so `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * Keyboard: `←` / `→` bump by `step`, `Home` / `End` jump to 0 / max.\n * Clicking the current value clears it (toggle off).\n *\n * The stars sit on the inline axis, so under `dir=\"rtl\"` the row is mirrored and\n * both halves of the input mirror with it: `→` walks toward the low end, and a\n * click is measured from the star's inline-start (right) edge.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-rating [formField]=\"form.score\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-rating [(value)]=\"score\" [count]=\"10\" step=\"0.5\" />\n * <wr-rating [value]=\"4.5\" [readonly]=\"true\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/rating\n */\nexport type WrRatingSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-rating',\n templateUrl: './rating.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrRating implements FormValueControl<number | null> {\n /** Total number of slots. @default 5 */\n readonly count = input(5, { transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 5)) });\n\n /** Step granularity — `1` for whole stars, `0.5` for halves. @default 1 */\n readonly step = input(1 as 0.5 | 1, {\n transform: (v: unknown): 0.5 | 1 => (Number(v) === 0.5 ? 0.5 : 1),\n });\n\n /** Read-only — value is displayed but not interactive. @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Disable interaction. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Control size — scales the icons + gaps. @default 'md' */\n readonly size = input<WrRatingSize>('md');\n\n /** Accessible label. Falls back to `rating.label`, then `'Rating'`. */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'rating.label', 'Rating');\n\n /** The rating. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<number | null>(null);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /** Transient hover preview — overrides `value` for display when set. */\n protected readonly hoverValue = signal<number | null>(null);\n\n protected readonly interactive = computed(() => !this.disabled() && !this.readonly());\n\n /**\n * Whether the control keeps its tab stop — `disabled` only, never `readonly`.\n *\n * The two states differ precisely here: a disabled control leaves the tab\n * order, a read-only one stays in it and keeps announcing `aria-valuenow`,\n * because a keyboard user still has to be able to READ a value they cannot\n * change. Driving `tabindex` off `interactive()` collapsed that distinction\n * and made `readonly()` unreachable — with an `aria-describedby` pointing at\n * an error message on an element nobody could focus.\n */\n protected readonly focusable = computed(() => !this.disabled());\n\n /**\n * What we actually render — hover wins while hovering.\n *\n * Clamped, because there is no such thing as drawing six stars in a row of\n * five, and the same number is what `aria-valuenow` reports: a `role=\"slider\"`\n * whose value sits outside its own min / max is an invalid slider whatever the\n * model holds. The MODEL is left alone — see the note above `fillFor` for why\n * the clamp is not written back.\n */\n protected readonly displayValue = computed(() => clamp(this.hoverValue() ?? this.value() ?? 0, 0, this.count()));\n\n /**\n * What the slider REPORTS, and where the arrows start from.\n *\n * Deliberately not `displayValue`: a hover preview is a pointer affordance and\n * must not be announced as the current value, and an arrow press after a hover\n * has to step from the committed number rather than from wherever the mouse\n * happened to rest.\n */\n protected readonly announcedValue = computed(() => clamp(this.value() ?? 0, 0, this.count()));\n\n protected readonly slots = computed(() => Array.from({ length: this.count() }, (_, i) => i));\n\n /**\n * Reading direction, for the two places it changes the answer: the arrows and\n * the pointer ratio inside a star.\n *\n * `optional` because a consumer who never set a direction should not have to\n * provide anything — `Directionality` is root-provided, so this only resolves\n * to `null` in a bare `TestBed`, where LTR is the right assumption. Read per\n * interaction rather than cached, so a runtime flip needs no subscription.\n */\n private readonly directionality = inject(Directionality, { optional: true });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n protected readonly classes = computed(() => {\n const parts = ['wr-rating'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-rating--${size}`);\n if (this.readonly()) parts.push('wr-rating--readonly');\n if (this.disabled()) parts.push('wr-rating--disabled');\n return parts.join(' ');\n });\n\n /*\n * There is deliberately no effect re-clamping `value` into `[0, count]`.\n *\n * There was one — it wrote the clamp back into the model, which the old CVA\n * `writeValue` also did — and under `[formField]` that write is\n * indistinguishable from the user moving the stars: a `FormControl(9)` on a\n * five-star rating became `5`, `dirty`, and emitted through `valueChanges`\n * before anything had been touched. So an unsaved-changes guard fired on a\n * form nobody had edited, and the out-of-range value that a `max()` rule\n * exists to REPORT was deleted by the control it was reported on (binding\n * `[count]` beside `[formField]` cannot help — the schema's rules are the only\n * bounds that reach here).\n *\n * `wr-slider` and `wr-input-number` had both already settled this the other\n * way, for the same two reasons, and this one was the odd control out.\n * `displayValue` clamps what is drawn and announced; `computeValue` and\n * `onKeydown` clamp what this control itself produces; the model is the\n * consumer's until they touch a star.\n */\n /** Fill ratio for slot `i` in `[0, 1]` — drives the CSS clip width. */\n protected fillFor(i: number): number {\n return clamp(this.displayValue() - i, 0, 1);\n }\n\n // Template handlers\n\n protected onSlotMove(event: MouseEvent, index: number): void {\n if (!this.interactive()) return;\n this.hoverValue.set(this.computeValue(event, index));\n }\n\n protected onLeave(): void {\n this.hoverValue.set(null);\n }\n\n protected onSlotClick(event: MouseEvent, index: number): void {\n if (!this.interactive()) return;\n const next = this.computeValue(event, index);\n // Click the current value → clear it.\n const final = next === this.value() ? null : next;\n this.commit(final);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!this.interactive()) return;\n const max = this.count();\n const step = this.step();\n // The clamped reading, so an arrow after an out-of-range external write\n // steps from the star the user can see rather than from a number off the row.\n const current = this.announcedValue();\n // Arrows follow VISUAL order (WAI-ARIA APG). The row lays its stars along the\n // inline axis, so under `dir=\"rtl\"` the first star is the RIGHTMOST one and\n // `→` walks down the scale. Up / Down are the block axis and never flip;\n // Home / End mean first / last, a semantic position rather than a physical\n // one, so they don't either.\n const inline = this.isRtl() ? -step : step;\n let next: number | null;\n switch (event.key) {\n case 'ArrowRight':\n next = clamp(current + inline, 0, max);\n break;\n case 'ArrowUp':\n next = clamp(current + step, 0, max);\n break;\n case 'ArrowLeft':\n next = clamp(current - inline, 0, max);\n break;\n case 'ArrowDown':\n next = clamp(current - step, 0, max);\n break;\n case 'Home':\n next = 0;\n break;\n case 'End':\n next = max;\n break;\n case 'Delete':\n case 'Backspace':\n next = null;\n break;\n default:\n return;\n }\n event.preventDefault();\n this.commit(next);\n }\n\n protected onBlur(): void {\n this.touch.emit();\n }\n\n // Internals\n\n /** Whether the row reads right-to-left. */\n private isRtl(): boolean {\n return this.directionality?.value === 'rtl';\n }\n\n /**\n * How far into the star the pointer sits, `0` to `1`, measured from its\n * INLINE-start edge — the left one in LTR, the right one in RTL, where the row\n * is mirrored. Taken from `rect.left` alone it reads 1 exactly where an RTL\n * user sees the start of the star, which inverts every half step.\n */\n private inlineRatio(clientX: number, rect: DOMRect): number {\n const offset = this.isRtl() ? rect.right - clientX : clientX - rect.left;\n return clamp(offset / rect.width, 0, 1);\n }\n\n /** Convert a mouse position over slot `index` to a snapped value. */\n private computeValue(event: MouseEvent, index: number): number {\n const target = event.currentTarget as HTMLElement;\n const rect = target.getBoundingClientRect();\n const ratio = this.inlineRatio(event.clientX, rect);\n const raw = index + ratio;\n const step = this.step();\n const snapped = Math.ceil(raw / step) * step;\n return clamp(snapped, step, this.count());\n }\n\n private commit(value: number | null): void {\n this.value.set(value);\n this.hoverValue.set(null);\n }\n}\n","<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]=\"announcedValue()\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [attr.tabindex]=\"focusable() ? 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","/**\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-rating.mjs","sources":["../../../projects/lib/rating/rating.ts","../../../projects/lib/rating/rating.html","../../../projects/lib/rating/ngwr-rating.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 { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, inject, input, model, output, signal } from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useFormFieldAria } from 'ngwr/form';\nimport { useI18nText } from 'ngwr/i18n';\nimport { clamp } from 'ngwr/utils';\n\n/**\n * Star rating input. Click or hover to set a value; supports half-star\n * increments via `step=\"0.5\"`. Value is `number | null`.\n *\n * `[0, count]` bounds what this control's OWN edits produce — a click, an arrow\n * key, `End`. A value written from outside is displayed and announced clamped\n * (a slider cannot report an `aria-valuenow` past its own `aria-valuemax`) and\n * left in the model as it stands, the same rule `wr-slider` and\n * `wr-input-number` follow.\n *\n * A signal-forms native control: it implements `FormValueControl<number | null>`,\n * so `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * Keyboard: `←` / `→` bump by `step`, `Home` / `End` jump to 0 / max.\n * Clicking the current value clears it (toggle off).\n *\n * The stars sit on the inline axis, so under `dir=\"rtl\"` the row is mirrored and\n * both halves of the input mirror with it: `→` walks toward the low end, and a\n * click is measured from the star's inline-start (right) edge.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-rating [formField]=\"form.score\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-rating [(value)]=\"score\" [count]=\"10\" step=\"0.5\" />\n * <wr-rating [value]=\"4.5\" [readonly]=\"true\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/rating\n */\nexport type WrRatingSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-rating',\n templateUrl: './rating.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrRating implements FormValueControl<number | null> {\n /** Total number of slots. @default 5 */\n readonly count = input(5, { transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 5)) });\n\n /** Step granularity — `1` for whole stars, `0.5` for halves. @default 1 */\n readonly step = input(1 as 0.5 | 1, {\n transform: (v: unknown): 0.5 | 1 => (Number(v) === 0.5 ? 0.5 : 1),\n });\n\n /** Read-only — value is displayed but not interactive. @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Disable interaction. Bound automatically from the field's disabled state\n * when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Control size — scales the icons + gaps. @default 'md' */\n readonly size = input<WrRatingSize>('md');\n\n /** Accessible label. Falls back to `rating.label`, then `'Rating'`. */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'rating.label', 'Rating');\n\n /** The rating. Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<number | null>(null);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /** Transient hover preview — overrides `value` for display when set. */\n protected readonly hoverValue = signal<number | null>(null);\n\n protected readonly interactive = computed(() => !this.disabled() && !this.readonly());\n\n /**\n * Whether the control keeps its tab stop — `disabled` only, never `readonly`.\n *\n * The two states differ precisely here: a disabled control leaves the tab\n * order, a read-only one stays in it and keeps announcing `aria-valuenow`,\n * because a keyboard user still has to be able to READ a value they cannot\n * change. Driving `tabindex` off `interactive()` collapsed that distinction\n * and made `readonly()` unreachable — with an `aria-describedby` pointing at\n * an error message on an element nobody could focus.\n */\n protected readonly focusable = computed(() => !this.disabled());\n\n /**\n * What we actually render — hover wins while hovering.\n *\n * Clamped, because there is no such thing as drawing six stars in a row of\n * five, and the same number is what `aria-valuenow` reports: a `role=\"slider\"`\n * whose value sits outside its own min / max is an invalid slider whatever the\n * model holds. The MODEL is left alone — see the note above `fillFor` for why\n * the clamp is not written back.\n */\n protected readonly displayValue = computed(() => clamp(this.hoverValue() ?? this.value() ?? 0, 0, this.count()));\n\n /**\n * What the slider REPORTS, and where the arrows start from.\n *\n * Deliberately not `displayValue`: a hover preview is a pointer affordance and\n * must not be announced as the current value, and an arrow press after a hover\n * has to step from the committed number rather than from wherever the mouse\n * happened to rest.\n */\n protected readonly announcedValue = computed(() => clamp(this.value() ?? 0, 0, this.count()));\n\n protected readonly slots = computed(() => Array.from({ length: this.count() }, (_, i) => i));\n\n /**\n * Reading direction, for the two places it changes the answer: the arrows and\n * the pointer ratio inside a star.\n *\n * `optional` because a consumer who never set a direction should not have to\n * provide anything — `Directionality` is root-provided, so this only resolves\n * to `null` in a bare `TestBed`, where LTR is the right assumption. Read per\n * interaction rather than cached, so a runtime flip needs no subscription.\n */\n private readonly directionality = inject(Directionality, { optional: true });\n\n /** The surrounding `<wr-form-field>`'s error state. @internal */\n protected readonly fieldAria = useFormFieldAria();\n\n /**\n * The field's label wins over the built-in default, and an explicit\n * `ariaLabel` wins over both.\n *\n * `<wr-form-field label=\"…\">` renders a `<label for>` that cannot reach this\n * control — `for` binds only to a LABELABLE element and the focusable part\n * here carries a role instead — so the field's label named nothing and this\n * announced its own generic default. A consumer who wrote\n * `<wr-form-field label=\"Overall satisfaction\">` heard \"Rating\".\n */\n protected readonly labelledBy = computed(() => (this.ariaLabel() ? null : this.fieldAria.labelledBy()));\n\n /** `null` once `aria-labelledby` is carrying the name, or the two are announced together. */\n protected readonly nameLabel = computed(() => (this.labelledBy() ? null : this.resolvedAriaLabel()));\n\n protected readonly classes = computed(() => {\n const parts = ['wr-rating'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-rating--${size}`);\n if (this.readonly()) parts.push('wr-rating--readonly');\n if (this.disabled()) parts.push('wr-rating--disabled');\n return parts.join(' ');\n });\n\n /*\n * There is deliberately no effect re-clamping `value` into `[0, count]`.\n *\n * There was one — it wrote the clamp back into the model, which the old CVA\n * `writeValue` also did — and under `[formField]` that write is\n * indistinguishable from the user moving the stars: a `FormControl(9)` on a\n * five-star rating became `5`, `dirty`, and emitted through `valueChanges`\n * before anything had been touched. So an unsaved-changes guard fired on a\n * form nobody had edited, and the out-of-range value that a `max()` rule\n * exists to REPORT was deleted by the control it was reported on (binding\n * `[count]` beside `[formField]` cannot help — the schema's rules are the only\n * bounds that reach here).\n *\n * `wr-slider` and `wr-input-number` had both already settled this the other\n * way, for the same two reasons, and this one was the odd control out.\n * `displayValue` clamps what is drawn and announced; `computeValue` and\n * `onKeydown` clamp what this control itself produces; the model is the\n * consumer's until they touch a star.\n */\n /** Fill ratio for slot `i` in `[0, 1]` — drives the CSS clip width. */\n protected fillFor(i: number): number {\n return clamp(this.displayValue() - i, 0, 1);\n }\n\n // Template handlers\n\n protected onSlotMove(event: MouseEvent, index: number): void {\n if (!this.interactive()) return;\n this.hoverValue.set(this.computeValue(event, index));\n }\n\n protected onLeave(): void {\n this.hoverValue.set(null);\n }\n\n protected onSlotClick(event: MouseEvent, index: number): void {\n if (!this.interactive()) return;\n const next = this.computeValue(event, index);\n // Click the current value → clear it.\n const final = next === this.value() ? null : next;\n this.commit(final);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!this.interactive()) return;\n const max = this.count();\n const step = this.step();\n // The clamped reading, so an arrow after an out-of-range external write\n // steps from the star the user can see rather than from a number off the row.\n const current = this.announcedValue();\n // Arrows follow VISUAL order (WAI-ARIA APG). The row lays its stars along the\n // inline axis, so under `dir=\"rtl\"` the first star is the RIGHTMOST one and\n // `→` walks down the scale. Up / Down are the block axis and never flip;\n // Home / End mean first / last, a semantic position rather than a physical\n // one, so they don't either.\n const inline = this.isRtl() ? -step : step;\n let next: number | null;\n switch (event.key) {\n case 'ArrowRight':\n next = clamp(current + inline, 0, max);\n break;\n case 'ArrowUp':\n next = clamp(current + step, 0, max);\n break;\n case 'ArrowLeft':\n next = clamp(current - inline, 0, max);\n break;\n case 'ArrowDown':\n next = clamp(current - step, 0, max);\n break;\n case 'Home':\n next = 0;\n break;\n case 'End':\n next = max;\n break;\n case 'Delete':\n case 'Backspace':\n next = null;\n break;\n default:\n return;\n }\n event.preventDefault();\n this.commit(next);\n }\n\n protected onBlur(): void {\n this.touch.emit();\n }\n\n // Internals\n\n /** Whether the row reads right-to-left. */\n private isRtl(): boolean {\n return this.directionality?.value === 'rtl';\n }\n\n /**\n * How far into the star the pointer sits, `0` to `1`, measured from its\n * INLINE-start edge — the left one in LTR, the right one in RTL, where the row\n * is mirrored. Taken from `rect.left` alone it reads 1 exactly where an RTL\n * user sees the start of the star, which inverts every half step.\n */\n private inlineRatio(clientX: number, rect: DOMRect): number {\n const offset = this.isRtl() ? rect.right - clientX : clientX - rect.left;\n return clamp(offset / rect.width, 0, 1);\n }\n\n /** Convert a mouse position over slot `index` to a snapped value. */\n private computeValue(event: MouseEvent, index: number): number {\n const target = event.currentTarget as HTMLElement;\n const rect = target.getBoundingClientRect();\n const ratio = this.inlineRatio(event.clientX, rect);\n const raw = index + ratio;\n const step = this.step();\n const snapped = Math.ceil(raw / step) * step;\n return clamp(snapped, step, this.count());\n }\n\n private commit(value: number | null): void {\n this.value.set(value);\n this.hoverValue.set(null);\n }\n}\n","<div\n class=\"wr-rating__row\"\n role=\"slider\"\n [attr.aria-label]=\"nameLabel()\"\n [attr.aria-labelledby]=\"labelledBy()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"count()\"\n [attr.aria-valuenow]=\"announcedValue()\"\n [attr.aria-readonly]=\"readonly() || null\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.aria-invalid]=\"fieldAria.ariaInvalid()\"\n [attr.aria-describedby]=\"fieldAria.describedBy()\"\n [attr.tabindex]=\"focusable() ? 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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/fesm2022/ngwr-result.mjs
CHANGED
|
@@ -34,12 +34,12 @@ 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.6", ngImport: i0, type: WrResult, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
38
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", 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 <!-- A TRIANGLE, and the shape is the point twice over. Warning used to sit\n in the same circle as info holding a near-identical exclamation mark \u2014\n the two paths differed by 2 user units, which is under 2px at the\n rendered size \u2014 and `warning` against `info` is a hue difference the\n palette cannot widen. It also brings this component into line with\n `wr-alert`, which has drawn warning as a triangle all along; the two\n disagreeing about what a warning looks like was its own small defect. -->\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <path d=\"M32 8 L60 54 L4 54 Z\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 26 L32 40 M32 47 L32 49\"\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 18 L32 20 M32 28 L32 46\"\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.6", ngImport: i0, type: WrResult, decorators: [{
|
|
41
41
|
type: Component,
|
|
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 <
|
|
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 <!-- A TRIANGLE, and the shape is the point twice over. Warning used to sit\n in the same circle as info holding a near-identical exclamation mark \u2014\n the two paths differed by 2 user units, which is under 2px at the\n rendered size \u2014 and `warning` against `info` is a hue difference the\n palette cannot widen. It also brings this component into line with\n `wr-alert`, which has drawn warning as a triangle all along; the two\n disagreeing about what a warning looks like was its own small defect. -->\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <path d=\"M32 8 L60 54 L4 54 Z\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 26 L32 40 M32 47 L32 49\"\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 18 L32 20 M32 28 L32 46\"\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 }] }] } });
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -67,10 +67,10 @@ class WrResult404 {
|
|
|
67
67
|
description = input(null, /* @ts-ignore */
|
|
68
68
|
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
69
69
|
desc = useI18nText(this.description, 'result.notFound', 'Sorry, the page you visited does not exist.');
|
|
70
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
71
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
70
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrResult404, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", 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 });
|
|
72
72
|
}
|
|
73
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
73
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrResult404, decorators: [{
|
|
74
74
|
type: Component,
|
|
75
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" }]
|
|
76
76
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
@@ -84,10 +84,10 @@ class WrResult403 {
|
|
|
84
84
|
description = input(null, /* @ts-ignore */
|
|
85
85
|
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
86
86
|
desc = useI18nText(this.description, 'result.forbidden', 'Sorry, you are not authorized to access this page.');
|
|
87
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
88
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
87
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrResult403, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
88
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", 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 });
|
|
89
89
|
}
|
|
90
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
90
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrResult403, decorators: [{
|
|
91
91
|
type: Component,
|
|
92
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" }]
|
|
93
93
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
@@ -101,10 +101,10 @@ class WrResult500 {
|
|
|
101
101
|
description = input(null, /* @ts-ignore */
|
|
102
102
|
...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
|
|
103
103
|
desc = useI18nText(this.description, 'result.serverError', 'Sorry, something went wrong.');
|
|
104
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
105
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
104
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrResult500, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
105
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.6", 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 });
|
|
106
106
|
}
|
|
107
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
107
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrResult500, decorators: [{
|
|
108
108
|
type: Component,
|
|
109
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" }]
|
|
110
110
|
}], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }] } });
|
|
@@ -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/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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"}
|
|
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 <!-- A TRIANGLE, and the shape is the point twice over. Warning used to sit\n in the same circle as info holding a near-identical exclamation mark —\n the two paths differed by 2 user units, which is under 2px at the\n rendered size — and `warning` against `info` is a hue difference the\n palette cannot widen. It also brings this component into line with\n `wr-alert`, which has drawn warning as a triangle all along; the two\n disagreeing about what a warning looks like was its own small defect. -->\n @case ('warning') {\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 64 64\">\n <path d=\"M32 8 L60 54 L4 54 Z\" fill=\"currentColor\" opacity=\"0.12\" />\n <path\n d=\"M32 26 L32 40 M32 47 L32 49\"\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 18 L32 20 M32 28 L32 46\"\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.6", ngImport: i0, type: WrRotatingText, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
266
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", 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.6", 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"] }] } });
|
|
@@ -188,10 +188,10 @@ class WrSchemaForm {
|
|
|
188
188
|
return out;
|
|
189
189
|
}, /* @ts-ignore */
|
|
190
190
|
...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
|
|
191
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
192
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
191
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrSchemaForm, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
192
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: WrSchemaForm, isStandalone: true, selector: "wr-schema-form", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.grid-template-columns": "template()" }, classAttribute: "wr-schema-form" }, ngImport: i0, template: "@for (f of fields(); track f.key) {\n @let state = f.field();\n\n <!-- Angular's `hidden()` does not hide anything on its own; the docs are\n explicit that the template has to honour it. -->\n @if (!state.hidden()) {\n <div class=\"wr-schema-form__field\" [style.grid-column]=\"f.column\">\n <wr-form-field [label]=\"f.labelAbove\" [hint]=\"f.spec.hint ?? ''\" [required]=\"state.required()\">\n @switch (f.spec.kind) {\n @case ('textarea') {\n <wr-textarea [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('number') {\n <wr-input-number\n [formField]=\"f.field\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n [step]=\"f.spec.step ?? 1\"\n [ariaLabel]=\"f.label\"\n />\n }\n @case ('select') {\n <wr-select [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? null\" [ariaLabel]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-option [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-option>\n }\n </wr-select>\n }\n @case ('checkbox') {\n <wr-checkbox [formField]=\"f.field\">{{ f.label }}</wr-checkbox>\n }\n @case ('switch') {\n <wr-switch [formField]=\"f.field\">{{ f.label }}</wr-switch>\n }\n @case ('radio') {\n <!-- `wr-radio-group` has no `ariaLabel` input, and needs none: its\n host is a `role=\"radiogroup\"`, where `aria-label` is legal. -->\n <wr-radio-group [formField]=\"f.field\" [attr.aria-label]=\"f.label\">\n @for (option of f.spec.options ?? []; track option.value) {\n <wr-radio [value]=\"option.value\" [disabled]=\"option.disabled ?? false\">{{ option.label }}</wr-radio>\n }\n </wr-radio-group>\n }\n @case ('date') {\n <wr-date-picker [formField]=\"f.field\" [placeholder]=\"f.spec.placeholder ?? ''\" [ariaLabel]=\"f.label\" />\n }\n @case ('slider') {\n <wr-slider [formField]=\"f.field\" [step]=\"f.spec.step ?? 1\" [ariaLabel]=\"f.label\" />\n }\n @default {\n <input\n wrInput\n [formField]=\"f.field\"\n [type]=\"f.spec.type ?? 'text'\"\n [placeholder]=\"f.spec.placeholder ?? ''\"\n />\n }\n }\n </wr-form-field>\n </div>\n }\n}\n", dependencies: [{ kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"], exportAs: ["formField"] }, { kind: "component", type: WrCheckbox, selector: "wr-checkbox", inputs: ["id", "checkboxValue", "ariaLabel", "checked", "disabled", "readonly", "size", "icon", "indeterminate"], outputs: ["checkedChange", "touch"] }, { kind: "component", type: WrDatePicker, selector: "wr-date-picker", inputs: ["mode", "format", "placeholder", "min", "max", "dateFilter", "timeFormat", "showSeconds", "step", "disabled", "readonly", "value", "ariaLabel", "panelAriaLabel"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrFormField, selector: "wr-form-field", inputs: ["label", "hint", "required", "optional", "optionalLabel", "controlId", "autoErrors"] }, { kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["size", "rounded"] }, { kind: "component", type: WrInputNumber, selector: "wr-input-number", inputs: ["min", "max", "step", "decimals", "showSteppers", "size", "rounded", "prefix", "suffix", "placeholder", "ariaLabel", "incrementLabel", "decrementLabel", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrOption, selector: "wr-option", inputs: ["value", "disabled"] }, { kind: "component", type: WrRadio, selector: "wr-radio", inputs: ["id", "value", "icon", "size", "disabled"] }, { kind: "component", type: WrRadioGroup, selector: "wr-radio-group", inputs: ["name", "disabled", "readonly", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrSelect, selector: "wr-select", inputs: ["placeholder", "clearLabel", "ariaLabel", "disabled", "readonly", "rounded", "size", "responsive", "mode", "searchable", "searchQuery", "options", "displayWith", "loader", "serverSearch", "debounceMs", "minChars", "freeText", "virtualScroll", "rowHeight", "viewportHeight", "overscan", "noResultsText", "loadingText", "loading", "separators", "allowDuplicates", "validate", "clearable", "maxItems", "maxTagCount", "value"], outputs: ["searchQueryChange", "searchChange", "valueChange", "touch"] }, { kind: "component", type: WrSlider, selector: "wr-slider", inputs: ["min", "max", "step", "range", "disabled", "readonly", "showLabel", "ariaLabel", "upperLabel", "value"], outputs: ["valueChange", "touch"] }, { kind: "component", type: WrSwitch, selector: "wr-switch", inputs: ["ariaLabel", "id", "disabled", "readonly", "size", "checked"], outputs: ["checkedChange", "touch"] }, { kind: "component", type: WrTextarea, selector: "wr-textarea", inputs: ["placeholder", "ariaLabel", "size", "rows", "resizable", "resize", "readonly", "autosize", "maxRows", "disabled", "value"], outputs: ["valueChange", "touch"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
193
193
|
}
|
|
194
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
194
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrSchemaForm, decorators: [{
|
|
195
195
|
type: Component,
|
|
196
196
|
args: [{ selector: 'wr-schema-form', encapsulation: ViewEncapsulation.None, imports: [
|
|
197
197
|
FormField,
|
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.6", ngImport: i0, type: WrScroll, deps: [], target: i0.ɵɵFactoryTarget.Service });
|
|
96
|
+
static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.6", 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.6", ngImport: i0, type: WrScroll, decorators: [{
|
|
99
99
|
type: Service
|
|
100
100
|
}] });
|
|
101
101
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Directionality } from '@angular/cdk/bidi';
|
|
2
2
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { input, model, output, inject, ElementRef, computed, signal, afterNextRender, ViewEncapsulation, Component } from '@angular/core';
|
|
4
|
+
import { input, model, output, inject, ElementRef, computed, signal, afterNextRender, effect, untracked, ViewEncapsulation, Component } from '@angular/core';
|
|
5
5
|
import { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';
|
|
6
6
|
import { WrIcon } from 'ngwr/icon';
|
|
7
7
|
|
|
@@ -120,8 +120,39 @@ class WrSegmented {
|
|
|
120
120
|
/** Flips true after the first paint so the thumb only animates user-driven changes, not the initial snap. */
|
|
121
121
|
mounted = signal(false, /* @ts-ignore */
|
|
122
122
|
...(ngDevMode ? [{ debugName: "mounted" }] : /* istanbul ignore next */ []));
|
|
123
|
+
/**
|
|
124
|
+
* True for the tick in which the reading direction changed.
|
|
125
|
+
*
|
|
126
|
+
* Mirroring moves the thumb's SLOT by the whole width of the strip (see
|
|
127
|
+
* `thumbStyle`), and animating that is a quarter-second of the pill travelling
|
|
128
|
+
* across options it does not mark — caught under the wrong label every time the
|
|
129
|
+
* docs site's LTR / RTL switch was used, which is a strip inside an overlay that
|
|
130
|
+
* mirrors underneath it. The selection did not move, so neither should the pill:
|
|
131
|
+
* the stylesheet drops its transition while this is set, and the new slot lands
|
|
132
|
+
* in the same pass that removes it.
|
|
133
|
+
*
|
|
134
|
+
* Cleared from a task rather than `afterNextRender`, which runs inside the very
|
|
135
|
+
* change detection that set this and would put the transition back before the
|
|
136
|
+
* new position is painted.
|
|
137
|
+
*/
|
|
138
|
+
flipping = signal(false, /* @ts-ignore */
|
|
139
|
+
...(ngDevMode ? [{ debugName: "flipping" }] : /* istanbul ignore next */ []));
|
|
123
140
|
constructor() {
|
|
124
141
|
afterNextRender(() => this.mounted.set(true));
|
|
142
|
+
// `null` until the first run: an effect always runs once, and that run is not
|
|
143
|
+
// a flip.
|
|
144
|
+
let previous = null;
|
|
145
|
+
effect(() => {
|
|
146
|
+
const rtl = this.isRtl();
|
|
147
|
+
if (previous === rtl)
|
|
148
|
+
return;
|
|
149
|
+
const flipped = previous !== null;
|
|
150
|
+
previous = rtl;
|
|
151
|
+
if (!flipped || typeof setTimeout !== 'function')
|
|
152
|
+
return;
|
|
153
|
+
untracked(() => this.flipping.set(true));
|
|
154
|
+
setTimeout(() => this.flipping.set(false));
|
|
155
|
+
});
|
|
125
156
|
}
|
|
126
157
|
classes = computed(() => {
|
|
127
158
|
const parts = ['wr-segmented'];
|
|
@@ -136,6 +167,8 @@ class WrSegmented {
|
|
|
136
167
|
parts.push('wr-segmented--unselected');
|
|
137
168
|
if (this.mounted())
|
|
138
169
|
parts.push('wr-segmented--mounted');
|
|
170
|
+
if (this.flipping())
|
|
171
|
+
parts.push('wr-segmented--flipping');
|
|
139
172
|
return parts.join(' ');
|
|
140
173
|
}, /* @ts-ignore */
|
|
141
174
|
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
@@ -197,10 +230,10 @@ class WrSegmented {
|
|
|
197
230
|
return;
|
|
198
231
|
this.touch.emit();
|
|
199
232
|
}
|
|
200
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
201
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
233
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrSegmented, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
234
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", 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 }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { attributes: { "role": "group" }, listeners: { "focusout": "onFocusOut($event)" }, properties: { "class": "classes()", "style": "thumbStyle()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "ariaInvalid()" } }, ngImport: i0, template: "<span class=\"wr-segmented__thumb\" aria-hidden=\"true\"></span>\n\n<!--\n `id` on the FIRST segment only: it is the id a surrounding `<wr-form-field>`\n already points its `<label for>` at, and a `for` may only name a labelable\n element \u2014 see `controlId` in the component. `null` without a field, so a bare\n strip stamps no document-global id on anything.\n-->\n@for (option of options(); track option.value) {\n <button\n type=\"button\"\n class=\"wr-segmented__option\"\n [attr.id]=\"$first ? controlId() : null\"\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 });
|
|
202
235
|
}
|
|
203
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
236
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: WrSegmented, decorators: [{
|
|
204
237
|
type: Component,
|
|
205
238
|
args: [{ selector: 'wr-segmented', encapsulation: ViewEncapsulation.None, host: {
|
|
206
239
|
'[class]': 'classes()',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-segmented.mjs","sources":["../../../projects/lib/segmented/segmented.ts","../../../projects/lib/segmented/segmented.html","../../../projects/lib/segmented/ngwr-segmented.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 { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n ViewEncapsulation,\n afterNextRender,\n computed,\n inject,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';\nimport { WrIcon } from 'ngwr/icon';\n\nimport type { WrSegmentedOption } from './interfaces';\n\n/**\n * Single-choice picker rendered as a segmented control. Two-way binds\n * the selected `value`.\n *\n * A signal-forms native control: it implements `FormValueControl<T | null>`, so\n * `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone, and classic\n * `[(ngModel)]` / reactive forms keep working through Angular's bridge.\n *\n * It stays a `role=\"group\"` of `aria-pressed` toggle buttons rather than\n * becoming a `radiogroup`: being a form control changes what the value is bound\n * to, not what the widget is, and a radiogroup would owe a roving tab stop and\n * arrow-key selection — a different keyboard contract for every consumer who\n * already ships this. The group is what the field describes (`aria-describedby`\n * / `aria-invalid` land on the host), while the `<label for>` has to name a\n * labelable element, so the id goes on the first segment.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-segmented [options]=\"ranges\" [formField]=\"form.range\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-segmented\n * [options]=\"[\n * { value: 'day', label: 'Day' },\n * { value: 'week', label: 'Week' },\n * { value: 'month', label: 'Month' },\n * ]\"\n * [(value)]=\"range\"\n * />\n * ```\n *\n * @see https://ngwr.dev/reference/components/segmented\n */\nexport type WrSegmentedSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-segmented',\n templateUrl: './segmented.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n '[style]': 'thumbStyle()',\n role: 'group',\n '[attr.aria-describedby]': 'describedBy()',\n '[attr.aria-invalid]': 'ariaInvalid()',\n '(focusout)': 'onFocusOut($event)',\n },\n imports: [WrIcon],\n})\nexport class WrSegmented<T = unknown> implements FormValueControl<T | null> {\n /** The segments to render. */\n readonly options = input.required<readonly WrSegmentedOption<T>[]>();\n\n // The model keeps the component's own `T`, and the contract is satisfied as\n // `FormValueControl<T | null>` — legal because `FormField<T>` infers its type from\n // the FIELD it is handed and never from the host component, so the interface's\n // parameter describes this model rather than constraining the binding.\n // `wr-cascader` and `wr-tree` widen theirs to `unknown` because their value SHAPE\n // changes with a mode input (`TId | null` in single mode, a `readonly TId[]` in\n // multi) and no one type is true of both. A segmented control has one shape, so\n // widening here would only throw away what `[options]` already proved: every\n // `(valueChange)=\"pick($event)\"` in a typed app would start receiving `unknown`.\n // With the default type parameter this degenerates to exactly the catalog's\n // `FormValueControl<unknown>`.\n /**\n * The picked segment's `value`, `null` when nothing is selected. Bound by\n * `[formField]`, or two-way via `[(value)]`.\n */\n readonly value = model<T | null>(null);\n\n /** Emitted when focus leaves the strip, so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /**\n * Disable the whole control. Bound automatically from the field's disabled\n * state when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse changes while every segment stays focusable and the value still\n * submits. Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * NOTHING is mirrored into ARIA here, deliberately: the strip is a\n * `role=\"group\"` of `aria-pressed` buttons, and ARIA defines `aria-readonly`\n * for neither role — it is a state of `checkbox` / `radiogroup` / `textbox`\n * and their kin, and it is not global. `aria-disabled` is the only attribute\n * that would apply to a button, and it says the wrong thing: these segments\n * are still focusable and the value still submits. So the state is honest in\n * the DOM (`wr-segmented--readonly`) and silent in the accessibility tree\n * rather than announced with a word that means something else.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Control size — shares the `--wr-control-*` contract. @default 'md' */\n readonly size = input<WrSegmentedSize>('md');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Id the surrounding `<wr-form-field>`'s `<label for>` points at, stamped on the\n * FIRST segment.\n *\n * The field renders its label before it can see what was projected into it, so the\n * id travels the other way and the control adopts it, exactly as `[wrInput]`,\n * `wr-slider` and `wr-select` do. Without this the `for` named an element that was\n * nowhere in the document: clicking the label did nothing.\n *\n * It cannot go on the host — only a labelable element can be a label's target, and\n * `<wr-segmented>` is not one — and there is no single control to put it on, so it\n * goes where clicking the label should land a user: the first segment, which is\n * also the strip's first tab stop. The same choice `wr-slider` makes with its low\n * thumb.\n *\n * What this does NOT change is that segment's NAME: it is named by its own label,\n * and a `<label for>` cannot outrank text content in the accname order anyway.\n *\n * The one shape this reads wrong is a strip NESTED inside another control that is\n * itself the field — `<wr-color-picker>`'s own format tabs are the only case in\n * the library — where the id lands on a tab instead of on the picker. That is the\n * same exposure `[wrInput]`, `wr-slider` and `wr-select` all carry, and the fix\n * belongs to the outer control (shield its subtree by providing `WR_FORM_FIELD`\n * as `null`), not to a strip that cannot tell whose field it is in.\n */\n protected readonly controlId = computed(() => this.field?.controlId() ?? null);\n\n /**\n * The field's error message, wired to the GROUP rather than to a segment.\n *\n * A segmented control is one field made of several buttons, so the description\n * belongs to the thing the field describes — repeated on every segment it would be\n * announced once per Tab. `role=\"group\"` supports neither state as a role-specific\n * attribute, but both are ARIA globals, so this is valid where an `aria-checked`\n * would not be.\n *\n * `aria-invalid` is keyed on the message EXISTING rather than on `errorKeys()`,\n * because the field only publishes an id once it is showing something — announcing\n * \"invalid\" while pointing at nothing is worse than staying quiet.\n */\n // Through the shared helper, not a local pair: the hint is described by\n // `hintId`, which only `useFormFieldAria()` composes, and `aria-invalid` keys\n // on the error COUNT rather than on \"something is described\". Hand-rolled here,\n // these three announced the error and never the hint — and `<input wrInput>` is\n // the control the report was filed against.\n private readonly fieldAria = useFormFieldAria();\n protected readonly describedBy = this.fieldAria.describedBy;\n protected readonly ariaInvalid = this.fieldAria.ariaInvalid;\n\n /** Index of the selected option, or `-1` when nothing is selected. */\n protected readonly selectedIndex = computed(() => {\n const v = this.value();\n return this.options().findIndex(o => o.value === v);\n });\n\n /** Flips true after the first paint so the thumb only animates user-driven changes, not the initial snap. */\n private readonly mounted = signal(false);\n\n constructor() {\n afterNextRender(() => this.mounted.set(true));\n }\n\n protected readonly classes = computed(() => {\n const parts = ['wr-segmented'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-segmented--${size}`);\n if (this.disabled()) parts.push('wr-segmented--disabled');\n else if (this.readonly()) parts.push('wr-segmented--readonly');\n if (this.selectedIndex() < 0) parts.push('wr-segmented--unselected');\n if (this.mounted()) parts.push('wr-segmented--mounted');\n return parts.join(' ');\n });\n\n private readonly dir = inject(Directionality, { optional: true });\n\n /**\n * Reading direction of the strip. `Directionality` is root-provided, so this\n * always resolves — `optional` only guards a consumer who has deliberately\n * torn the provider out. A subtree that overrides the direction does it with\n * the CDK's `Dir` directive, which writes `valueSignal`, so `thumbStyle`\n * re-renders instead of leaving the thumb parked on the old segment.\n */\n private readonly isRtl = computed(() => this.dir?.valueSignal() === 'rtl');\n\n /**\n * Inline CSS vars driving the sliding thumb position.\n *\n * `--wr-segmented-thumb-index` is the SLOT the thumb parks in, counted from the\n * physical left, which is the selected index only in LTR. The stylesheet anchors\n * the thumb with a physical `left` and slides it with `translateX` — neither has\n * a logical form — while the options are a grid that mirrors, so under `dir=\"rtl\"`\n * the segment at logical index `i` occupies slot `count - 1 - i`. Left unsigned,\n * the pill sat under a different label than the one it marks (the whole strip's\n * worth of offset at the far end), which is the carousel's `trackStyle` problem\n * one component over.\n */\n protected readonly thumbStyle = computed<Record<string, string>>(() => {\n const i = Math.max(0, this.selectedIndex());\n const count = Math.max(1, this.options().length);\n const slot = this.isRtl() ? count - 1 - i : i;\n return {\n '--wr-segmented-thumb-index': `${slot}`,\n '--wr-segmented-thumb-count': `${count}`,\n };\n });\n\n protected isSelected(option: WrSegmentedOption<T>): boolean {\n return this.value() === option.value;\n }\n\n protected select(option: WrSegmentedOption<T>): void {\n if (this.disabled() || this.readonly() || option.disabled || this.isSelected(option)) return;\n this.value.set(option.value);\n }\n\n protected trackByValue(_: number, option: WrSegmentedOption<T>): unknown {\n return option.value;\n }\n\n /**\n * A bound field learns it may show its validation copy from `touch`, and a click\n * cannot be the source: a strip tabbed into and out of without a pick left the\n * field untouched forever — which is exactly the case `touched` exists for.\n *\n * `wr-knob` and `wr-rating` bind `(blur)` on the one element they own; this\n * component owns one button per option, so it listens for the bubbling `focusout`\n * on its host instead — and ignores the one that only moves focus from one segment\n * to the next, the way `wr-slider` ignores the hop between its two thumbs.\n */\n protected onFocusOut(event: FocusEvent): void {\n if (this.host.nativeElement.contains(event.relatedTarget as Node | null)) return;\n this.touch.emit();\n }\n}\n","<span class=\"wr-segmented__thumb\" aria-hidden=\"true\"></span>\n\n<!--\n `id` on the FIRST segment only: it is the id a surrounding `<wr-form-field>`\n already points its `<label for>` at, and a `for` may only name a labelable\n element — see `controlId` in the component. `null` without a field, so a bare\n strip stamps no document-global id on anything.\n-->\n@for (option of options(); track option.value) {\n <button\n type=\"button\"\n class=\"wr-segmented__option\"\n [attr.id]=\"$first ? controlId() : null\"\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","/**\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.mjs","sources":["../../../projects/lib/segmented/segmented.ts","../../../projects/lib/segmented/segmented.html","../../../projects/lib/segmented/ngwr-segmented.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 { Directionality } from '@angular/cdk/bidi';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n ViewEncapsulation,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n untracked,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { WR_FORM_FIELD, useFormFieldAria } from 'ngwr/form';\nimport { WrIcon } from 'ngwr/icon';\n\nimport type { WrSegmentedOption } from './interfaces';\n\n/**\n * Single-choice picker rendered as a segmented control. Two-way binds\n * the selected `value`.\n *\n * A signal-forms native control: it implements `FormValueControl<T | null>`, so\n * `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone, and classic\n * `[(ngModel)]` / reactive forms keep working through Angular's bridge.\n *\n * It stays a `role=\"group\"` of `aria-pressed` toggle buttons rather than\n * becoming a `radiogroup`: being a form control changes what the value is bound\n * to, not what the widget is, and a radiogroup would owe a roving tab stop and\n * arrow-key selection — a different keyboard contract for every consumer who\n * already ships this. The group is what the field describes (`aria-describedby`\n * / `aria-invalid` land on the host), while the `<label for>` has to name a\n * labelable element, so the id goes on the first segment.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-segmented [options]=\"ranges\" [formField]=\"form.range\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-segmented\n * [options]=\"[\n * { value: 'day', label: 'Day' },\n * { value: 'week', label: 'Week' },\n * { value: 'month', label: 'Month' },\n * ]\"\n * [(value)]=\"range\"\n * />\n * ```\n *\n * @see https://ngwr.dev/reference/components/segmented\n */\nexport type WrSegmentedSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'wr-segmented',\n templateUrl: './segmented.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n '[class]': 'classes()',\n '[style]': 'thumbStyle()',\n role: 'group',\n '[attr.aria-describedby]': 'describedBy()',\n '[attr.aria-invalid]': 'ariaInvalid()',\n '(focusout)': 'onFocusOut($event)',\n },\n imports: [WrIcon],\n})\nexport class WrSegmented<T = unknown> implements FormValueControl<T | null> {\n /** The segments to render. */\n readonly options = input.required<readonly WrSegmentedOption<T>[]>();\n\n // The model keeps the component's own `T`, and the contract is satisfied as\n // `FormValueControl<T | null>` — legal because `FormField<T>` infers its type from\n // the FIELD it is handed and never from the host component, so the interface's\n // parameter describes this model rather than constraining the binding.\n // `wr-cascader` and `wr-tree` widen theirs to `unknown` because their value SHAPE\n // changes with a mode input (`TId | null` in single mode, a `readonly TId[]` in\n // multi) and no one type is true of both. A segmented control has one shape, so\n // widening here would only throw away what `[options]` already proved: every\n // `(valueChange)=\"pick($event)\"` in a typed app would start receiving `unknown`.\n // With the default type parameter this degenerates to exactly the catalog's\n // `FormValueControl<unknown>`.\n /**\n * The picked segment's `value`, `null` when nothing is selected. Bound by\n * `[formField]`, or two-way via `[(value)]`.\n */\n readonly value = model<T | null>(null);\n\n /** Emitted when focus leaves the strip, so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n /**\n * Disable the whole control. Bound automatically from the field's disabled\n * state when used with `[formField]`.\n *\n * @default false\n */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /**\n * Refuse changes while every segment stays focusable and the value still\n * submits. Bound automatically from the field's readonly state when used with\n * `[formField]`.\n *\n * NOTHING is mirrored into ARIA here, deliberately: the strip is a\n * `role=\"group\"` of `aria-pressed` buttons, and ARIA defines `aria-readonly`\n * for neither role — it is a state of `checkbox` / `radiogroup` / `textbox`\n * and their kin, and it is not global. `aria-disabled` is the only attribute\n * that would apply to a button, and it says the wrong thing: these segments\n * are still focusable and the value still submits. So the state is honest in\n * the DOM (`wr-segmented--readonly`) and silent in the accessibility tree\n * rather than announced with a word that means something else.\n *\n * @default false\n */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Control size — shares the `--wr-control-*` contract. @default 'md' */\n readonly size = input<WrSegmentedSize>('md');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Id the surrounding `<wr-form-field>`'s `<label for>` points at, stamped on the\n * FIRST segment.\n *\n * The field renders its label before it can see what was projected into it, so the\n * id travels the other way and the control adopts it, exactly as `[wrInput]`,\n * `wr-slider` and `wr-select` do. Without this the `for` named an element that was\n * nowhere in the document: clicking the label did nothing.\n *\n * It cannot go on the host — only a labelable element can be a label's target, and\n * `<wr-segmented>` is not one — and there is no single control to put it on, so it\n * goes where clicking the label should land a user: the first segment, which is\n * also the strip's first tab stop. The same choice `wr-slider` makes with its low\n * thumb.\n *\n * What this does NOT change is that segment's NAME: it is named by its own label,\n * and a `<label for>` cannot outrank text content in the accname order anyway.\n *\n * The one shape this reads wrong is a strip NESTED inside another control that is\n * itself the field — `<wr-color-picker>`'s own format tabs are the only case in\n * the library — where the id lands on a tab instead of on the picker. That is the\n * same exposure `[wrInput]`, `wr-slider` and `wr-select` all carry, and the fix\n * belongs to the outer control (shield its subtree by providing `WR_FORM_FIELD`\n * as `null`), not to a strip that cannot tell whose field it is in.\n */\n protected readonly controlId = computed(() => this.field?.controlId() ?? null);\n\n /**\n * The field's error message, wired to the GROUP rather than to a segment.\n *\n * A segmented control is one field made of several buttons, so the description\n * belongs to the thing the field describes — repeated on every segment it would be\n * announced once per Tab. `role=\"group\"` supports neither state as a role-specific\n * attribute, but both are ARIA globals, so this is valid where an `aria-checked`\n * would not be.\n *\n * `aria-invalid` is keyed on the message EXISTING rather than on `errorKeys()`,\n * because the field only publishes an id once it is showing something — announcing\n * \"invalid\" while pointing at nothing is worse than staying quiet.\n */\n // Through the shared helper, not a local pair: the hint is described by\n // `hintId`, which only `useFormFieldAria()` composes, and `aria-invalid` keys\n // on the error COUNT rather than on \"something is described\". Hand-rolled here,\n // these three announced the error and never the hint — and `<input wrInput>` is\n // the control the report was filed against.\n private readonly fieldAria = useFormFieldAria();\n protected readonly describedBy = this.fieldAria.describedBy;\n protected readonly ariaInvalid = this.fieldAria.ariaInvalid;\n\n /** Index of the selected option, or `-1` when nothing is selected. */\n protected readonly selectedIndex = computed(() => {\n const v = this.value();\n return this.options().findIndex(o => o.value === v);\n });\n\n /** Flips true after the first paint so the thumb only animates user-driven changes, not the initial snap. */\n private readonly mounted = signal(false);\n\n /**\n * True for the tick in which the reading direction changed.\n *\n * Mirroring moves the thumb's SLOT by the whole width of the strip (see\n * `thumbStyle`), and animating that is a quarter-second of the pill travelling\n * across options it does not mark — caught under the wrong label every time the\n * docs site's LTR / RTL switch was used, which is a strip inside an overlay that\n * mirrors underneath it. The selection did not move, so neither should the pill:\n * the stylesheet drops its transition while this is set, and the new slot lands\n * in the same pass that removes it.\n *\n * Cleared from a task rather than `afterNextRender`, which runs inside the very\n * change detection that set this and would put the transition back before the\n * new position is painted.\n */\n private readonly flipping = signal(false);\n\n constructor() {\n afterNextRender(() => this.mounted.set(true));\n\n // `null` until the first run: an effect always runs once, and that run is not\n // a flip.\n let previous: boolean | null = null;\n effect(() => {\n const rtl = this.isRtl();\n if (previous === rtl) return;\n const flipped = previous !== null;\n previous = rtl;\n if (!flipped || typeof setTimeout !== 'function') return;\n\n untracked(() => this.flipping.set(true));\n setTimeout(() => this.flipping.set(false));\n });\n }\n\n protected readonly classes = computed(() => {\n const parts = ['wr-segmented'];\n const size = this.size();\n if (size !== 'md') parts.push(`wr-segmented--${size}`);\n if (this.disabled()) parts.push('wr-segmented--disabled');\n else if (this.readonly()) parts.push('wr-segmented--readonly');\n if (this.selectedIndex() < 0) parts.push('wr-segmented--unselected');\n if (this.mounted()) parts.push('wr-segmented--mounted');\n if (this.flipping()) parts.push('wr-segmented--flipping');\n return parts.join(' ');\n });\n\n private readonly dir = inject(Directionality, { optional: true });\n\n /**\n * Reading direction of the strip. `Directionality` is root-provided, so this\n * always resolves — `optional` only guards a consumer who has deliberately\n * torn the provider out. A subtree that overrides the direction does it with\n * the CDK's `Dir` directive, which writes `valueSignal`, so `thumbStyle`\n * re-renders instead of leaving the thumb parked on the old segment.\n */\n private readonly isRtl = computed(() => this.dir?.valueSignal() === 'rtl');\n\n /**\n * Inline CSS vars driving the sliding thumb position.\n *\n * `--wr-segmented-thumb-index` is the SLOT the thumb parks in, counted from the\n * physical left, which is the selected index only in LTR. The stylesheet anchors\n * the thumb with a physical `left` and slides it with `translateX` — neither has\n * a logical form — while the options are a grid that mirrors, so under `dir=\"rtl\"`\n * the segment at logical index `i` occupies slot `count - 1 - i`. Left unsigned,\n * the pill sat under a different label than the one it marks (the whole strip's\n * worth of offset at the far end), which is the carousel's `trackStyle` problem\n * one component over.\n */\n protected readonly thumbStyle = computed<Record<string, string>>(() => {\n const i = Math.max(0, this.selectedIndex());\n const count = Math.max(1, this.options().length);\n const slot = this.isRtl() ? count - 1 - i : i;\n return {\n '--wr-segmented-thumb-index': `${slot}`,\n '--wr-segmented-thumb-count': `${count}`,\n };\n });\n\n protected isSelected(option: WrSegmentedOption<T>): boolean {\n return this.value() === option.value;\n }\n\n protected select(option: WrSegmentedOption<T>): void {\n if (this.disabled() || this.readonly() || option.disabled || this.isSelected(option)) return;\n this.value.set(option.value);\n }\n\n protected trackByValue(_: number, option: WrSegmentedOption<T>): unknown {\n return option.value;\n }\n\n /**\n * A bound field learns it may show its validation copy from `touch`, and a click\n * cannot be the source: a strip tabbed into and out of without a pick left the\n * field untouched forever — which is exactly the case `touched` exists for.\n *\n * `wr-knob` and `wr-rating` bind `(blur)` on the one element they own; this\n * component owns one button per option, so it listens for the bubbling `focusout`\n * on its host instead — and ignores the one that only moves focus from one segment\n * to the next, the way `wr-slider` ignores the hop between its two thumbs.\n */\n protected onFocusOut(event: FocusEvent): void {\n if (this.host.nativeElement.contains(event.relatedTarget as Node | null)) return;\n this.touch.emit();\n }\n}\n","<span class=\"wr-segmented__thumb\" aria-hidden=\"true\"></span>\n\n<!--\n `id` on the FIRST segment only: it is the id a surrounding `<wr-form-field>`\n already points its `<label for>` at, and a `for` may only name a labelable\n element — see `controlId` in the component. `null` without a field, so a bare\n strip stamps no document-global id on anything.\n-->\n@for (option of options(); track option.value) {\n <button\n type=\"button\"\n class=\"wr-segmented__option\"\n [attr.id]=\"$first ? controlId() : null\"\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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|