ngwr 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -3
- package/README.md +179 -32
- package/affix/styles/_index.scss +12 -0
- package/alert/styles/_index.scss +75 -32
- package/anchor/styles/_index.scss +59 -0
- package/aurora/aurora.scss +1 -0
- package/aurora/styles/_index.scss +30 -0
- package/avatar/styles/_index.scss +30 -14
- package/back-top/styles/_index.scss +42 -0
- package/badge/styles/_index.scss +80 -0
- package/badge/styles/_tag.scss +81 -0
- package/bar-chart/styles/_index.scss +56 -0
- package/blur-text/blur-text.scss +1 -0
- package/blur-text/styles/_index.scss +14 -0
- package/border-glow/border-glow.scss +4 -0
- package/border-glow/styles/_index.scss +228 -0
- package/breadcrumbs/breadcrumbs.scss +1 -0
- package/breadcrumbs/styles/_index.scss +76 -0
- package/button/styles/_index.scss +148 -125
- package/calendar/styles/_index.scss +252 -0
- package/calendar-heatmap/styles/_index.scss +69 -0
- package/card/card.scss +1 -0
- package/card/styles/_index.scss +96 -0
- package/carousel/styles/_index.scss +102 -0
- package/cascader/cascader.scss +1 -0
- package/cascader/styles/_index.scss +174 -0
- package/checkbox/styles/_index.scss +76 -60
- package/circular-text/circular-text.scss +1 -0
- package/circular-text/styles/_index.scss +45 -0
- package/click-spark/click-spark.scss +1 -0
- package/click-spark/styles/_index.scss +16 -0
- package/collapse/styles/_index.scss +92 -0
- package/color-picker/styles/_index.scss +247 -0
- package/command-palette/styles/_index.scss +188 -0
- package/compare/styles/_index.scss +100 -0
- package/context-menu/styles/_index.scss +112 -0
- package/counter/styles/_index.scss +44 -0
- package/date-picker/styles/_index.scss +204 -0
- package/decrypt-text/decrypt-text.scss +1 -0
- package/decrypt-text/styles/_index.scss +26 -0
- package/density/styles/_index.scss +37 -0
- package/descriptions/styles/_index.scss +104 -0
- package/dialog/styles/_index.scss +101 -27
- package/divider/styles/_index.scss +43 -24
- package/donut-chart/styles/_index.scss +76 -0
- package/drag-drop/sortable-list.scss +1 -0
- package/drag-drop/styles/_index.scss +99 -0
- package/drawer/styles/_index.scss +164 -0
- package/dropdown/styles/_index.scss +76 -56
- package/empty/styles/_index.scss +49 -0
- package/falling-text/falling-text.scss +1 -0
- package/falling-text/styles/_index.scss +30 -0
- package/fesm2022/ngwr-affix.mjs +102 -0
- package/fesm2022/ngwr-affix.mjs.map +1 -0
- package/fesm2022/ngwr-alert.mjs +70 -52
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- package/fesm2022/ngwr-anchor.mjs +103 -0
- package/fesm2022/ngwr-anchor.mjs.map +1 -0
- package/fesm2022/ngwr-aurora.mjs +309 -0
- package/fesm2022/ngwr-aurora.mjs.map +1 -0
- package/fesm2022/ngwr-avatar.mjs +81 -71
- package/fesm2022/ngwr-avatar.mjs.map +1 -1
- package/fesm2022/ngwr-back-top.mjs +81 -0
- package/fesm2022/ngwr-back-top.mjs.map +1 -0
- package/fesm2022/ngwr-badge.mjs +192 -0
- package/fesm2022/ngwr-badge.mjs.map +1 -0
- package/fesm2022/ngwr-bar-chart.mjs +69 -0
- package/fesm2022/ngwr-bar-chart.mjs.map +1 -0
- package/fesm2022/ngwr-blur-text.mjs +181 -0
- package/fesm2022/ngwr-blur-text.mjs.map +1 -0
- package/fesm2022/ngwr-border-glow.mjs +278 -0
- package/fesm2022/ngwr-border-glow.mjs.map +1 -0
- package/fesm2022/ngwr-breadcrumbs.mjs +101 -0
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -0
- package/fesm2022/ngwr-button.mjs +179 -104
- package/fesm2022/ngwr-button.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap.mjs +145 -0
- package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -0
- package/fesm2022/ngwr-calendar.mjs +402 -0
- package/fesm2022/ngwr-calendar.mjs.map +1 -0
- package/fesm2022/ngwr-card.mjs +100 -0
- package/fesm2022/ngwr-card.mjs.map +1 -0
- package/fesm2022/ngwr-carousel.mjs +128 -0
- package/fesm2022/ngwr-carousel.mjs.map +1 -0
- package/fesm2022/ngwr-cascader.mjs +280 -0
- package/fesm2022/ngwr-cascader.mjs.map +1 -0
- package/fesm2022/ngwr-checkbox.mjs +214 -54
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text.mjs +168 -0
- package/fesm2022/ngwr-circular-text.mjs.map +1 -0
- package/fesm2022/ngwr-click-spark.mjs +163 -0
- package/fesm2022/ngwr-click-spark.mjs.map +1 -0
- package/fesm2022/ngwr-clipboard.mjs +130 -0
- package/fesm2022/ngwr-clipboard.mjs.map +1 -0
- package/fesm2022/ngwr-collapse.mjs +232 -0
- package/fesm2022/ngwr-collapse.mjs.map +1 -0
- package/fesm2022/ngwr-color-picker.mjs +646 -0
- package/fesm2022/ngwr-color-picker.mjs.map +1 -0
- package/fesm2022/ngwr-command-palette.mjs +259 -0
- package/fesm2022/ngwr-command-palette.mjs.map +1 -0
- package/fesm2022/ngwr-compare.mjs +137 -0
- package/fesm2022/ngwr-compare.mjs.map +1 -0
- package/fesm2022/ngwr-confetti.mjs +160 -0
- package/fesm2022/ngwr-confetti.mjs.map +1 -0
- package/fesm2022/ngwr-context-menu.mjs +653 -0
- package/fesm2022/ngwr-context-menu.mjs.map +1 -0
- package/fesm2022/ngwr-cookie.mjs +127 -0
- package/fesm2022/ngwr-cookie.mjs.map +1 -0
- package/fesm2022/ngwr-counter.mjs +415 -0
- package/fesm2022/ngwr-counter.mjs.map +1 -0
- package/fesm2022/ngwr-date-adapter-fns.mjs +180 -0
- package/fesm2022/ngwr-date-adapter-fns.mjs.map +1 -0
- package/fesm2022/ngwr-date-adapter-luxon.mjs +201 -0
- package/fesm2022/ngwr-date-adapter-luxon.mjs.map +1 -0
- package/fesm2022/ngwr-date-adapter.mjs +419 -0
- package/fesm2022/ngwr-date-adapter.mjs.map +1 -0
- package/fesm2022/ngwr-date-picker.mjs +624 -0
- package/fesm2022/ngwr-date-picker.mjs.map +1 -0
- package/fesm2022/ngwr-decrypt-text.mjs +396 -0
- package/fesm2022/ngwr-decrypt-text.mjs.map +1 -0
- package/fesm2022/ngwr-density.mjs +157 -0
- package/fesm2022/ngwr-density.mjs.map +1 -0
- package/fesm2022/ngwr-descriptions.mjs +83 -0
- package/fesm2022/ngwr-descriptions.mjs.map +1 -0
- package/fesm2022/ngwr-dialog.mjs +249 -383
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +315 -0
- package/fesm2022/ngwr-directives.mjs.map +1 -0
- package/fesm2022/ngwr-divider.mjs +74 -59
- package/fesm2022/ngwr-divider.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart.mjs +131 -0
- package/fesm2022/ngwr-donut-chart.mjs.map +1 -0
- package/fesm2022/ngwr-drag-drop.mjs +117 -0
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -0
- package/fesm2022/ngwr-drawer.mjs +315 -0
- package/fesm2022/ngwr-drawer.mjs.map +1 -0
- package/fesm2022/ngwr-dropdown.mjs +276 -229
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-empty.mjs +57 -0
- package/fesm2022/ngwr-empty.mjs.map +1 -0
- package/fesm2022/ngwr-falling-text.mjs +316 -0
- package/fesm2022/ngwr-falling-text.mjs.map +1 -0
- package/fesm2022/ngwr-file-upload.mjs +260 -0
- package/fesm2022/ngwr-file-upload.mjs.map +1 -0
- package/fesm2022/ngwr-form.mjs +133 -48
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +373 -0
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -0
- package/fesm2022/ngwr-gauge.mjs +83 -0
- package/fesm2022/ngwr-gauge.mjs.map +1 -0
- package/fesm2022/ngwr-glitch-text.mjs +67 -0
- package/fesm2022/ngwr-glitch-text.mjs.map +1 -0
- package/fesm2022/ngwr-gradient-text.mjs +109 -0
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -0
- package/fesm2022/ngwr-hotkey.mjs +263 -0
- package/fesm2022/ngwr-hotkey.mjs.map +1 -0
- package/fesm2022/ngwr-i18n-en.mjs +168 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -0
- package/fesm2022/ngwr-i18n-ru.mjs +156 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -0
- package/fesm2022/ngwr-i18n.mjs +478 -0
- package/fesm2022/ngwr-i18n.mjs.map +1 -0
- package/fesm2022/ngwr-icon-adapters-feather.mjs +74 -0
- package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -0
- package/fesm2022/ngwr-icon-adapters-lucide.mjs +88 -0
- package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -0
- package/fesm2022/ngwr-icon.mjs +189 -650
- package/fesm2022/ngwr-icon.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper.mjs +299 -0
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -0
- package/fesm2022/ngwr-input-number.mjs +239 -0
- package/fesm2022/ngwr-input-number.mjs.map +1 -0
- package/fesm2022/ngwr-input-otp.mjs +216 -0
- package/fesm2022/ngwr-input-otp.mjs.map +1 -0
- package/fesm2022/ngwr-input.mjs +183 -104
- package/fesm2022/ngwr-input.mjs.map +1 -1
- package/fesm2022/ngwr-keyboard.mjs +47 -0
- package/fesm2022/ngwr-keyboard.mjs.map +1 -0
- package/fesm2022/ngwr-knob.mjs +227 -0
- package/fesm2022/ngwr-knob.mjs.map +1 -0
- package/fesm2022/ngwr-layout.mjs +197 -0
- package/fesm2022/ngwr-layout.mjs.map +1 -0
- package/fesm2022/ngwr-lightbox.mjs +131 -0
- package/fesm2022/ngwr-lightbox.mjs.map +1 -0
- package/fesm2022/ngwr-line-chart.mjs +176 -0
- package/fesm2022/ngwr-line-chart.mjs.map +1 -0
- package/fesm2022/ngwr-list.mjs +132 -0
- package/fesm2022/ngwr-list.mjs.map +1 -0
- package/fesm2022/ngwr-loading-bar.mjs +160 -0
- package/fesm2022/ngwr-loading-bar.mjs.map +1 -0
- package/fesm2022/ngwr-marquee.mjs +224 -0
- package/fesm2022/ngwr-marquee.mjs.map +1 -0
- package/fesm2022/ngwr-media.mjs +132 -0
- package/fesm2022/ngwr-media.mjs.map +1 -0
- package/fesm2022/ngwr-mention.mjs +374 -0
- package/fesm2022/ngwr-mention.mjs.map +1 -0
- package/fesm2022/ngwr-meta.mjs +266 -0
- package/fesm2022/ngwr-meta.mjs.map +1 -0
- package/fesm2022/ngwr-meter-group.mjs +73 -0
- package/fesm2022/ngwr-meter-group.mjs.map +1 -0
- package/fesm2022/ngwr-overlay.mjs +145 -0
- package/fesm2022/ngwr-overlay.mjs.map +1 -0
- package/fesm2022/ngwr-page-header.mjs +53 -0
- package/fesm2022/ngwr-page-header.mjs.map +1 -0
- package/fesm2022/ngwr-pagination.mjs +152 -96
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +290 -11
- package/fesm2022/ngwr-pipes.mjs.map +1 -1
- package/fesm2022/ngwr-platform.mjs +63 -0
- package/fesm2022/ngwr-platform.mjs.map +1 -0
- package/fesm2022/ngwr-popconfirm.mjs +188 -0
- package/fesm2022/ngwr-popconfirm.mjs.map +1 -0
- package/fesm2022/ngwr-popover.mjs +361 -0
- package/fesm2022/ngwr-popover.mjs.map +1 -0
- package/fesm2022/ngwr-progress.mjs +47 -39
- package/fesm2022/ngwr-progress.mjs.map +1 -1
- package/fesm2022/ngwr-qr.mjs +168 -190
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-radio.mjs +204 -0
- package/fesm2022/ngwr-radio.mjs.map +1 -0
- package/fesm2022/ngwr-rating.mjs +180 -0
- package/fesm2022/ngwr-rating.mjs.map +1 -0
- package/fesm2022/ngwr-result.mjs +119 -0
- package/fesm2022/ngwr-result.mjs.map +1 -0
- package/fesm2022/ngwr-rotating-text.mjs +256 -0
- package/fesm2022/ngwr-rotating-text.mjs.map +1 -0
- package/fesm2022/ngwr-scramble-text.mjs +165 -0
- package/fesm2022/ngwr-scramble-text.mjs.map +1 -0
- package/fesm2022/ngwr-scroll.mjs +107 -0
- package/fesm2022/ngwr-scroll.mjs.map +1 -0
- package/fesm2022/ngwr-segmented.mjs +96 -0
- package/fesm2022/ngwr-segmented.mjs.map +1 -0
- package/fesm2022/ngwr-select.mjs +842 -307
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +127 -0
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -0
- package/fesm2022/ngwr-sidebar.mjs +134 -0
- package/fesm2022/ngwr-sidebar.mjs.map +1 -0
- package/fesm2022/ngwr-skeleton.mjs +59 -34
- package/fesm2022/ngwr-skeleton.mjs.map +1 -1
- package/fesm2022/ngwr-slider.mjs +234 -0
- package/fesm2022/ngwr-slider.mjs.map +1 -0
- package/fesm2022/ngwr-sparkline.mjs +104 -0
- package/fesm2022/ngwr-sparkline.mjs.map +1 -0
- package/fesm2022/ngwr-speed-dial.mjs +79 -0
- package/fesm2022/ngwr-speed-dial.mjs.map +1 -0
- package/fesm2022/ngwr-spinner.mjs +34 -28
- package/fesm2022/ngwr-spinner.mjs.map +1 -1
- package/fesm2022/ngwr-splash-cursor.mjs +970 -0
- package/fesm2022/ngwr-splash-cursor.mjs.map +1 -0
- package/fesm2022/ngwr-split-text.mjs +200 -0
- package/fesm2022/ngwr-split-text.mjs.map +1 -0
- package/fesm2022/ngwr-splitter.mjs +125 -0
- package/fesm2022/ngwr-splitter.mjs.map +1 -0
- package/fesm2022/ngwr-spotlight-card.mjs +138 -0
- package/fesm2022/ngwr-spotlight-card.mjs.map +1 -0
- package/fesm2022/ngwr-squircle.mjs +320 -0
- package/fesm2022/ngwr-squircle.mjs.map +1 -0
- package/fesm2022/ngwr-star-border.mjs +72 -0
- package/fesm2022/ngwr-star-border.mjs.map +1 -0
- package/fesm2022/ngwr-statistic.mjs +220 -0
- package/fesm2022/ngwr-statistic.mjs.map +1 -0
- package/fesm2022/ngwr-stepper.mjs +186 -0
- package/fesm2022/ngwr-stepper.mjs.map +1 -0
- package/fesm2022/ngwr-storage.mjs +317 -0
- package/fesm2022/ngwr-storage.mjs.map +1 -0
- package/fesm2022/ngwr-switch.mjs +99 -0
- package/fesm2022/ngwr-switch.mjs.map +1 -0
- package/fesm2022/ngwr-table.mjs +218 -207
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +217 -0
- package/fesm2022/ngwr-tabs.mjs.map +1 -0
- package/fesm2022/ngwr-textarea.mjs +106 -120
- package/fesm2022/ngwr-textarea.mjs.map +1 -1
- package/fesm2022/ngwr-theme.mjs +152 -0
- package/fesm2022/ngwr-theme.mjs.map +1 -0
- package/fesm2022/ngwr-tilt-card.mjs +137 -0
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -0
- package/fesm2022/ngwr-timeline.mjs +73 -0
- package/fesm2022/ngwr-timeline.mjs.map +1 -0
- package/fesm2022/ngwr-toast.mjs +446 -0
- package/fesm2022/ngwr-toast.mjs.map +1 -0
- package/fesm2022/ngwr-toolbar.mjs +46 -0
- package/fesm2022/ngwr-toolbar.mjs.map +1 -0
- package/fesm2022/ngwr-tree.mjs +483 -0
- package/fesm2022/ngwr-tree.mjs.map +1 -0
- package/fesm2022/ngwr-typewriter.mjs +229 -0
- package/fesm2022/ngwr-typewriter.mjs.map +1 -0
- package/fesm2022/ngwr-typography.mjs +79 -0
- package/fesm2022/ngwr-typography.mjs.map +1 -0
- package/fesm2022/ngwr-utils.mjs +535 -0
- package/fesm2022/ngwr-utils.mjs.map +1 -0
- package/fesm2022/ngwr-validators.mjs +214 -0
- package/fesm2022/ngwr-validators.mjs.map +1 -0
- package/fesm2022/ngwr-version.mjs +51 -0
- package/fesm2022/ngwr-version.mjs.map +1 -0
- package/fesm2022/ngwr-virtual-scroll.mjs +99 -0
- package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -0
- package/fesm2022/ngwr-waves.mjs +356 -0
- package/fesm2022/ngwr-waves.mjs.map +1 -0
- package/fesm2022/ngwr-window.mjs +1141 -0
- package/fesm2022/ngwr-window.mjs.map +1 -0
- package/fesm2022/ngwr.mjs +0 -3
- package/fesm2022/ngwr.mjs.map +1 -1
- package/file-upload/styles/_index.scss +152 -0
- package/form/styles/_index.scss +85 -42
- package/gauge/styles/_index.scss +37 -0
- package/glitch-text/glitch-text.scss +1 -0
- package/glitch-text/styles/_index.scss +144 -0
- package/gradient-text/gradient-text.scss +1 -0
- package/gradient-text/styles/_index.scss +113 -0
- package/icon/styles/_index.scss +21 -15
- package/image-cropper/styles/_index.scss +114 -0
- package/input/styles/_index.scss +133 -93
- package/input-number/styles/_index.scss +75 -0
- package/input-otp/styles/_index.scss +53 -0
- package/keyboard/styles/_index.scss +55 -0
- package/knob/styles/_index.scss +54 -0
- package/layout/styles/_index.scss +65 -0
- package/lightbox/lightbox.scss +1 -0
- package/lightbox/styles/_index.scss +144 -0
- package/line-chart/styles/_index.scss +93 -0
- package/list/list.scss +1 -0
- package/list/styles/_index.scss +101 -0
- package/loading-bar/loading-bar.scss +1 -0
- package/loading-bar/styles/_index.scss +29 -0
- package/marquee/marquee.scss +1 -0
- package/marquee/styles/_index.scss +138 -0
- package/mention/styles/_index.scss +47 -0
- package/meter-group/styles/_index.scss +61 -0
- package/package.json +576 -99
- package/page-header/styles/_index.scss +78 -0
- package/pagination/styles/_index.scss +89 -34
- package/popconfirm/styles/_index.scss +32 -0
- package/popover/styles/_index.scss +83 -0
- package/progress/styles/_index.scss +29 -14
- package/qr/styles/_index.scss +6 -3
- package/radio/styles/_index.scss +111 -0
- package/rating/styles/_index.scss +63 -0
- package/result/styles/_index.scss +69 -0
- package/rotating-text/rotating-text.scss +1 -0
- package/rotating-text/styles/_index.scss +39 -0
- package/schematics/collection.json +37 -0
- package/schematics/component-style/index.js +49 -0
- package/{alert/alert-type.d.ts → schematics/component-style/schema.js} +2 -1
- package/schematics/component-style/schema.json +20 -0
- package/schematics/icon-set/index.js +96 -0
- package/{avatar/public-api.d.ts → schematics/icon-set/schema.js} +2 -1
- package/schematics/icon-set/schema.json +39 -0
- package/schematics/migrations/v7/index.js +187 -0
- package/schematics/migrations.json +10 -0
- package/schematics/ng-add/index.js +180 -0
- package/{cdk/public-api.d.ts → schematics/ng-add/schema.js} +2 -1
- package/schematics/ng-add/schema.json +80 -0
- package/schematics/page/index.js +63 -0
- package/{alert/public-api.d.ts → schematics/page/schema.js} +2 -2
- package/schematics/page/schema.json +39 -0
- package/schematics/page/templates.js +198 -0
- package/schematics/provider/index.js +126 -0
- package/schematics/provider/schema.js +8 -0
- package/schematics/provider/schema.json +52 -0
- package/schematics/use/index.js +143 -0
- package/schematics/use/schema.js +8 -0
- package/schematics/use/schema.json +25 -0
- package/schematics/use/symbol-map.json +356 -0
- package/scramble-text/scramble-text.scss +1 -0
- package/scramble-text/styles/_index.scss +8 -0
- package/segmented/styles/_index.scss +92 -0
- package/select/styles/_index.scss +245 -159
- package/shiny-text/shiny-text.scss +1 -0
- package/shiny-text/styles/_index.scss +101 -0
- package/sidebar/styles/_index.scss +208 -0
- package/skeleton/styles/_index.scss +33 -33
- package/slider/styles/_index.scss +77 -0
- package/sparkline/styles/_index.scss +9 -0
- package/speed-dial/styles/_index.scss +158 -0
- package/spinner/styles/_index.scss +38 -22
- package/splash-cursor/splash-cursor.scss +1 -0
- package/splash-cursor/styles/_index.scss +27 -0
- package/split-text/split-text.scss +1 -0
- package/split-text/styles/_index.scss +22 -0
- package/splitter/styles/_index.scss +85 -0
- package/spotlight-card/spotlight-card.scss +1 -0
- package/spotlight-card/styles/_index.scss +43 -0
- package/squircle/styles/_index.scss +34 -0
- package/star-border/star-border.scss +1 -0
- package/star-border/styles/_index.scss +118 -0
- package/statistic/styles/_index.scss +54 -0
- package/stepper/styles/_index.scss +162 -0
- package/styles/_animations.scss +198 -0
- package/styles/_breakpoints.scss +75 -0
- package/styles/_grid.scss +71 -0
- package/styles/_reset.scss +123 -0
- package/styles/_typography.scss +122 -0
- package/styles.scss +102 -13
- package/switch/styles/_index.scss +82 -0
- package/table/styles/_index.scss +255 -4
- package/tabs/styles/_index.scss +71 -0
- package/textarea/styles/_index.scss +47 -56
- package/theme/styles/_colors.scss +83 -0
- package/theme/styles/_dark.scss +85 -0
- package/theme/styles/_focus.scss +93 -0
- package/theme/styles/_index.scss +5 -0
- package/theme/styles/_mixins.scss +57 -0
- package/theme/styles/_variables.scss +118 -0
- package/tilt-card/styles/_index.scss +40 -0
- package/tilt-card/tilt-card.scss +1 -0
- package/timeline/styles/_index.scss +127 -0
- package/toast/styles/_index.scss +263 -0
- package/toolbar/styles/_index.scss +65 -0
- package/tree/styles/_index.scss +271 -0
- package/types/ngwr-affix.d.ts +43 -0
- package/types/ngwr-alert.d.ts +68 -0
- package/types/ngwr-anchor.d.ts +53 -0
- package/types/ngwr-aurora.d.ts +52 -0
- package/types/ngwr-avatar.d.ts +90 -0
- package/types/ngwr-back-top.d.ts +37 -0
- package/types/ngwr-badge.d.ts +158 -0
- package/types/ngwr-bar-chart.d.ts +47 -0
- package/types/ngwr-blur-text.d.ts +62 -0
- package/types/ngwr-border-glow.d.ts +66 -0
- package/types/ngwr-breadcrumbs.d.ts +61 -0
- package/types/ngwr-button.d.ts +176 -0
- package/types/ngwr-calendar-heatmap.d.ts +58 -0
- package/types/ngwr-calendar.d.ts +116 -0
- package/types/ngwr-card.d.ts +50 -0
- package/types/ngwr-carousel.d.ts +57 -0
- package/types/ngwr-cascader.d.ts +107 -0
- package/types/ngwr-checkbox.d.ts +139 -0
- package/types/ngwr-circular-text.d.ts +49 -0
- package/types/ngwr-click-spark.d.ts +52 -0
- package/types/ngwr-clipboard.d.ts +53 -0
- package/types/ngwr-collapse.d.ts +139 -0
- package/types/ngwr-color-picker.d.ts +302 -0
- package/types/ngwr-command-palette.d.ts +113 -0
- package/types/ngwr-compare.d.ts +55 -0
- package/types/ngwr-confetti.d.ts +70 -0
- package/types/ngwr-context-menu.d.ts +207 -0
- package/types/ngwr-cookie.d.ts +60 -0
- package/types/ngwr-counter.d.ts +182 -0
- package/types/ngwr-date-adapter-fns.d.ts +73 -0
- package/types/ngwr-date-adapter-luxon.d.ts +73 -0
- package/types/ngwr-date-adapter.d.ts +198 -0
- package/types/ngwr-date-picker.d.ts +117 -0
- package/types/ngwr-decrypt-text.d.ts +85 -0
- package/types/ngwr-density.d.ts +97 -0
- package/types/ngwr-descriptions.d.ts +41 -0
- package/types/ngwr-dialog.d.ts +210 -0
- package/types/ngwr-directives.d.ts +125 -0
- package/types/ngwr-divider.d.ts +73 -0
- package/types/ngwr-donut-chart.d.ts +53 -0
- package/types/ngwr-drag-drop.d.ts +83 -0
- package/types/ngwr-drawer.d.ts +155 -0
- package/types/ngwr-dropdown.d.ts +124 -0
- package/types/ngwr-empty.d.ts +38 -0
- package/types/ngwr-falling-text.d.ts +63 -0
- package/types/ngwr-file-upload.d.ts +94 -0
- package/types/ngwr-form.d.ts +95 -0
- package/types/ngwr-fuzzy-text.d.ts +74 -0
- package/types/ngwr-gauge.d.ts +39 -0
- package/types/ngwr-glitch-text.d.ts +31 -0
- package/types/ngwr-gradient-text.d.ts +46 -0
- package/types/ngwr-hotkey.d.ts +142 -0
- package/types/ngwr-i18n-en.d.ts +18 -0
- package/types/ngwr-i18n-ru.d.ts +6 -0
- package/types/ngwr-i18n.d.ts +336 -0
- package/types/ngwr-icon-adapters-feather.d.ts +44 -0
- package/types/ngwr-icon-adapters-lucide.d.ts +54 -0
- package/types/ngwr-icon.d.ts +180 -0
- package/types/ngwr-image-cropper.d.ts +110 -0
- package/types/ngwr-input-number.d.ts +77 -0
- package/types/ngwr-input-otp.d.ts +78 -0
- package/types/ngwr-input.d.ts +131 -0
- package/types/ngwr-keyboard.d.ts +34 -0
- package/types/ngwr-knob.d.ts +77 -0
- package/types/ngwr-layout.d.ts +89 -0
- package/types/ngwr-lightbox.d.ts +50 -0
- package/types/ngwr-line-chart.d.ts +90 -0
- package/types/ngwr-list.d.ts +71 -0
- package/types/ngwr-loading-bar.d.ts +79 -0
- package/types/ngwr-marquee.d.ts +95 -0
- package/types/ngwr-media.d.ts +74 -0
- package/types/ngwr-mention.d.ts +110 -0
- package/types/ngwr-meta.d.ts +164 -0
- package/types/ngwr-meter-group.d.ts +57 -0
- package/types/ngwr-overlay.d.ts +110 -0
- package/types/ngwr-page-header.d.ts +35 -0
- package/types/ngwr-pagination.d.ts +119 -0
- package/types/ngwr-pipes.d.ts +177 -0
- package/types/ngwr-platform.d.ts +38 -0
- package/types/ngwr-popconfirm.d.ts +79 -0
- package/types/ngwr-popover.d.ts +90 -0
- package/types/ngwr-progress.d.ts +33 -0
- package/types/ngwr-qr.d.ts +56 -0
- package/types/ngwr-radio.d.ts +120 -0
- package/types/ngwr-rating.d.ts +62 -0
- package/types/ngwr-result.d.ts +64 -0
- package/types/ngwr-rotating-text.d.ts +72 -0
- package/types/ngwr-scramble-text.d.ts +49 -0
- package/types/ngwr-scroll.d.ts +65 -0
- package/types/ngwr-segmented.d.ts +65 -0
- package/types/ngwr-select.d.ts +413 -0
- package/types/ngwr-shiny-text.d.ts +70 -0
- package/types/ngwr-sidebar.d.ts +83 -0
- package/types/ngwr-skeleton.d.ts +41 -0
- package/types/ngwr-slider.d.ts +86 -0
- package/types/ngwr-sparkline.d.ts +48 -0
- package/types/ngwr-speed-dial.d.ts +51 -0
- package/types/ngwr-spinner.d.ts +41 -0
- package/types/ngwr-splash-cursor.d.ts +94 -0
- package/types/ngwr-split-text.d.ts +83 -0
- package/types/ngwr-splitter.d.ts +52 -0
- package/types/ngwr-spotlight-card.d.ts +71 -0
- package/types/ngwr-squircle.d.ts +132 -0
- package/types/ngwr-star-border.d.ts +40 -0
- package/types/ngwr-statistic.d.ts +88 -0
- package/types/ngwr-stepper.d.ts +99 -0
- package/types/ngwr-storage.d.ts +178 -0
- package/types/ngwr-switch.d.ts +39 -0
- package/types/ngwr-table.d.ts +237 -0
- package/types/ngwr-tabs.d.ts +125 -0
- package/types/ngwr-textarea.d.ts +60 -0
- package/types/ngwr-theme.d.ts +124 -0
- package/types/ngwr-tilt-card.d.ts +63 -0
- package/types/ngwr-timeline.d.ts +40 -0
- package/types/ngwr-toast.d.ts +230 -0
- package/types/ngwr-toolbar.d.ts +30 -0
- package/types/ngwr-tree.d.ts +150 -0
- package/types/ngwr-typewriter.d.ts +84 -0
- package/types/ngwr-typography.d.ts +56 -0
- package/types/ngwr-utils.d.ts +447 -0
- package/types/ngwr-validators.d.ts +70 -0
- package/types/ngwr-version.d.ts +44 -0
- package/types/ngwr-virtual-scroll.d.ts +64 -0
- package/types/ngwr-waves.d.ts +71 -0
- package/types/ngwr-window.d.ts +437 -0
- package/types/ngwr.d.ts +2 -0
- package/typewriter/styles/_index.scss +33 -0
- package/typewriter/typewriter.scss +1 -0
- package/typography/styles/_index.scss +211 -0
- package/virtual-scroll/styles/_index.scss +27 -0
- package/virtual-scroll/virtual-scroll.scss +1 -0
- package/waves/styles/_index.scss +24 -0
- package/waves/waves.scss +1 -0
- package/window/styles/_index.scss +430 -0
- package/alert/alert.component.d.ts +0 -21
- package/alert/index.d.ts +0 -5
- package/alert/styles/theming.scss +0 -26
- package/alert/styles/vars.scss +0 -11
- package/avatar/avatar.component.d.ts +0 -27
- package/avatar/index.d.ts +0 -5
- package/button/button-group.component.d.ts +0 -12
- package/button/button.component.d.ts +0 -31
- package/button/index.d.ts +0 -5
- package/button/public-api.d.ts +0 -8
- package/button/styles/vars.scss +0 -13
- package/cdk/base.directive.d.ts +0 -20
- package/cdk/index.d.ts +0 -5
- package/cdk/rxjs/index.d.ts +0 -5
- package/cdk/rxjs/is-array.d.ts +0 -8
- package/cdk/rxjs/is-defined.d.ts +0 -8
- package/cdk/rxjs/is-not-empty-array.d.ts +0 -8
- package/cdk/rxjs/is-observable.d.ts +0 -9
- package/cdk/rxjs/public-api.d.ts +0 -10
- package/cdk/types/index.d.ts +0 -5
- package/cdk/types/maybe.d.ts +0 -7
- package/cdk/types/public-api.d.ts +0 -9
- package/cdk/types/safe-any.d.ts +0 -7
- package/cdk/types/theme-color.d.ts +0 -8
- package/cdk/utils/generate-random-id.d.ts +0 -12
- package/cdk/utils/index.d.ts +0 -5
- package/cdk/utils/public-api.d.ts +0 -7
- package/checkbox/checkbox.component.d.ts +0 -28
- package/checkbox/index.d.ts +0 -5
- package/checkbox/public-api.d.ts +0 -7
- package/checkbox/styles/vars.scss +0 -16
- package/dialog/dialog-animations.d.ts +0 -22
- package/dialog/dialog-base.directive.d.ts +0 -40
- package/dialog/dialog-close.directive.d.ts +0 -9
- package/dialog/dialog-content.directive.d.ts +0 -6
- package/dialog/dialog-data.token.d.ts +0 -8
- package/dialog/dialog-footer.directive.d.ts +0 -8
- package/dialog/dialog-options.d.ts +0 -19
- package/dialog/dialog-ref.d.ts +0 -26
- package/dialog/dialog-title.directive.d.ts +0 -6
- package/dialog/dialog.component.d.ts +0 -28
- package/dialog/dialog.module.d.ts +0 -6
- package/dialog/dialog.service.d.ts +0 -28
- package/dialog/index.d.ts +0 -5
- package/dialog/public-api.d.ts +0 -18
- package/dialog/styles/vars.scss +0 -7
- package/divider/divider.component.d.ts +0 -13
- package/divider/index.d.ts +0 -5
- package/divider/public-api.d.ts +0 -7
- package/dropdown/dropdown-menu-item.component.d.ts +0 -12
- package/dropdown/dropdown-menu.component.d.ts +0 -14
- package/dropdown/dropdown.directive.d.ts +0 -29
- package/dropdown/dropdown.types.d.ts +0 -9
- package/dropdown/index.d.ts +0 -5
- package/dropdown/public-api.d.ts +0 -10
- package/dropdown/styles/vars.scss +0 -18
- package/fesm2022/ngwr-cdk-rxjs.mjs +0 -53
- package/fesm2022/ngwr-cdk-rxjs.mjs.map +0 -1
- package/fesm2022/ngwr-cdk-types.mjs +0 -44
- package/fesm2022/ngwr-cdk-types.mjs.map +0 -1
- package/fesm2022/ngwr-cdk-utils.mjs +0 -30
- package/fesm2022/ngwr-cdk-utils.mjs.map +0 -1
- package/fesm2022/ngwr-cdk.mjs +0 -46
- package/fesm2022/ngwr-cdk.mjs.map +0 -1
- package/fesm2022/ngwr-tag.mjs +0 -87
- package/fesm2022/ngwr-tag.mjs.map +0 -1
- package/form/form-error.component.d.ts +0 -11
- package/form/form-item.component.d.ts +0 -14
- package/form/index.d.ts +0 -5
- package/form/public-api.d.ts +0 -8
- package/icon/icon.component.d.ts +0 -24
- package/icon/icon.service.d.ts +0 -23
- package/icon/icons.d.ts +0 -770
- package/icon/index.d.ts +0 -5
- package/icon/provide-wr-icons.d.ts +0 -9
- package/icon/public-api.d.ts +0 -10
- package/icon/styles/vars.scss +0 -3
- package/index.d.ts +0 -5
- package/input/index.d.ts +0 -5
- package/input/input-types.d.ts +0 -1
- package/input/input.component.d.ts +0 -38
- package/input/public-api.d.ts +0 -8
- package/input/styles/vars.scss +0 -17
- package/pagination/index.d.ts +0 -5
- package/pagination/pagination.component.d.ts +0 -23
- package/pagination/pagination.types.d.ts +0 -7
- package/pagination/public-api.d.ts +0 -8
- package/pagination/styles/vars.scss +0 -14
- package/pipes/index.d.ts +0 -5
- package/pipes/new-array.pipe.d.ts +0 -13
- package/pipes/public-api.d.ts +0 -7
- package/progress/index.d.ts +0 -5
- package/progress/progress.component.d.ts +0 -10
- package/progress/public-api.d.ts +0 -7
- package/progress/styles/theming.scss +0 -8
- package/progress/styles/vars.scss +0 -6
- package/public-api.d.ts +0 -2
- package/qr/generator.d.ts +0 -7
- package/qr/index.d.ts +0 -5
- package/qr/public-api.d.ts +0 -7
- package/qr/qr.component.d.ts +0 -31
- package/qr/qrcodegen.d.ts +0 -94
- package/select/index.d.ts +0 -5
- package/select/public-api.d.ts +0 -10
- package/select/select-option-group.component.d.ts +0 -19
- package/select/select-option.component.d.ts +0 -22
- package/select/select.component.d.ts +0 -63
- package/select/select.types.d.ts +0 -17
- package/select/styles/vars.scss +0 -32
- package/skeleton/index.d.ts +0 -1
- package/skeleton/skeleton.component.d.ts +0 -10
- package/spinner/index.d.ts +0 -1
- package/spinner/spinner.component.d.ts +0 -13
- package/spinner/spinner.types.d.ts +0 -7
- package/styles/animations.scss +0 -92
- package/styles/cdk.scss +0 -5
- package/styles/colors.scss +0 -72
- package/styles/grid.scss +0 -99
- package/styles/maps.scss +0 -31
- package/styles/reset.scss +0 -112
- package/styles/variables.scss +0 -72
- package/table/index.d.ts +0 -5
- package/table/public-api.d.ts +0 -11
- package/table/styles/table-filter.scss +0 -202
- package/table/styles/table-sort.scss +0 -47
- package/table/styles/table.scss +0 -232
- package/table/styles/vars.scss +0 -21
- package/table/table-cell/index.d.ts +0 -7
- package/table/table-cell/table-cell.directive.d.ts +0 -8
- package/table/table-filter/index.d.ts +0 -7
- package/table/table-filter/table-filter.component.d.ts +0 -18
- package/table/table-sort/index.d.ts +0 -7
- package/table/table-sort/table-sort.component.d.ts +0 -8
- package/table/table.component.d.ts +0 -33
- package/table/types/index.d.ts +0 -6
- package/table/types/table-cell-context.d.ts +0 -6
- package/table/types/table-columns.d.ts +0 -7
- package/table/types/table-filter-emit.d.ts +0 -5
- package/table/types/table-filter-item.d.ts +0 -6
- package/table/types/table-order-item.d.ts +0 -5
- package/table/types/table-order.enum.d.ts +0 -5
- package/tag/index.d.ts +0 -5
- package/tag/public-api.d.ts +0 -7
- package/tag/styles/_index.scss +0 -32
- package/tag/styles/theming.scss +0 -21
- package/tag/styles/vars.scss +0 -12
- package/tag/tag.component.d.ts +0 -21
- package/textarea/index.d.ts +0 -7
- package/textarea/public-api.d.ts +0 -7
- package/textarea/styles/vars.scss +0 -17
- package/textarea/textarea.component.d.ts +0 -44
package/fesm2022/ngwr-select.mjs
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
|
2
|
+
import { ScrollStrategyOptions } from '@angular/cdk/overlay';
|
|
3
|
+
import { TemplatePortal } from '@angular/cdk/portal';
|
|
2
4
|
import * as i0 from '@angular/core';
|
|
3
|
-
import {
|
|
4
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import { InjectionToken, input, inject, ElementRef, computed, effect, DestroyRef, ViewEncapsulation, Component, signal, viewChild, TemplateRef, ViewContainerRef, forwardRef } from '@angular/core';
|
|
6
|
+
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
7
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { debounceTime, switchMap, of, isObservable, from, finalize } from 'rxjs';
|
|
9
|
+
import { useI18nText, useI18nFormatter } from 'ngwr/i18n';
|
|
10
|
+
import { WR_OVERLAY } from 'ngwr/overlay';
|
|
11
|
+
import { noop } from 'ngwr/utils';
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* @license
|
|
@@ -14,64 +16,13 @@ import { WrTagComponent } from 'ngwr/tag';
|
|
|
14
16
|
* Use of this source code is governed by an MIT-style license that can be
|
|
15
17
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
16
18
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.selectComponent = inject(WrSelectComponent);
|
|
25
|
-
}
|
|
26
|
-
get hostClasses() {
|
|
27
|
-
return {
|
|
28
|
-
'wr-option': true,
|
|
29
|
-
'wr-option--selected': this.isSelected,
|
|
30
|
-
'wr-option--disabled': this.disabled,
|
|
31
|
-
'wr-option--highlighted': this.isHighlighted,
|
|
32
|
-
'wr-option--filtered': this.isFiltered,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
get isSelected() {
|
|
36
|
-
const currentValue = this.selectComponent.currentValue;
|
|
37
|
-
if (this.selectComponent.isMultiple) {
|
|
38
|
-
return Array.isArray(currentValue) && currentValue.includes(this.value);
|
|
39
|
-
}
|
|
40
|
-
return currentValue === this.value;
|
|
41
|
-
}
|
|
42
|
-
get isHighlighted() {
|
|
43
|
-
return this.selectComponent.isHighlightedOption(this);
|
|
44
|
-
}
|
|
45
|
-
get isFiltered() {
|
|
46
|
-
return this.selectComponent.isFilteredOption(this);
|
|
47
|
-
}
|
|
48
|
-
select() {
|
|
49
|
-
if (!this.disabled) {
|
|
50
|
-
this.selectComponent.onOptionSelect(this);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: WrOptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
54
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.5", type: WrOptionComponent, isStandalone: true, selector: "wr-option", inputs: { value: "value", label: "label", disabled: ["disabled", "disabled", booleanAttribute] }, host: { listeners: { "click": "select()" }, properties: { "class": "this.hostClasses" } }, queries: [{ propertyName: "customTemplate", first: true, predicate: TemplateRef, descendants: true }], ngImport: i0, template: "<div class=\"wr-option__content\">\n @if (customTemplate) {\n <ng-container *ngTemplateOutlet=\"customTemplate; context: context\"> </ng-container>\n } @else {\n {{ label }}\n }\n</div>\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
55
|
-
}
|
|
56
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: WrOptionComponent, decorators: [{
|
|
57
|
-
type: Component,
|
|
58
|
-
args: [{ selector: 'wr-option', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
|
|
59
|
-
'(click)': 'select()',
|
|
60
|
-
}, imports: [NgTemplateOutlet], template: "<div class=\"wr-option__content\">\n @if (customTemplate) {\n <ng-container *ngTemplateOutlet=\"customTemplate; context: context\"> </ng-container>\n } @else {\n {{ label }}\n }\n</div>\n" }]
|
|
61
|
-
}], propDecorators: { value: [{
|
|
62
|
-
type: Input
|
|
63
|
-
}], label: [{
|
|
64
|
-
type: Input
|
|
65
|
-
}], disabled: [{
|
|
66
|
-
type: Input,
|
|
67
|
-
args: [{ transform: booleanAttribute }]
|
|
68
|
-
}], customTemplate: [{
|
|
69
|
-
type: ContentChild,
|
|
70
|
-
args: [TemplateRef]
|
|
71
|
-
}], hostClasses: [{
|
|
72
|
-
type: HostBinding,
|
|
73
|
-
args: ['class']
|
|
74
|
-
}] } });
|
|
19
|
+
/**
|
|
20
|
+
* Token a `<wr-option>` injects to register itself with and notify its
|
|
21
|
+
* parent `<wr-select>`.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
const WR_SELECT = new InjectionToken('WR_SELECT');
|
|
75
26
|
|
|
76
27
|
/**
|
|
77
28
|
* @license
|
|
@@ -79,40 +30,115 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImpor
|
|
|
79
30
|
* Use of this source code is governed by an MIT-style license that can be
|
|
80
31
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
81
32
|
*/
|
|
82
|
-
|
|
33
|
+
let uid = 0;
|
|
34
|
+
/**
|
|
35
|
+
* Single option inside a `<wr-select>`.
|
|
36
|
+
*
|
|
37
|
+
* The option's display label is taken from its projected text content;
|
|
38
|
+
* the form value is its `value` input.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```html
|
|
42
|
+
* <wr-option value="sm">Small</wr-option>
|
|
43
|
+
* <wr-option [value]="42">Forty-two</wr-option>
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
class WrOption {
|
|
47
|
+
/** The value contributed when this option is chosen. Required. */
|
|
48
|
+
value = input.required(/* @ts-ignore */
|
|
49
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
50
|
+
/** Disable this option. @default false */
|
|
51
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
52
|
+
/** Stable id used for `aria-activedescendant`. */
|
|
53
|
+
id = `wr-option-${++uid}`;
|
|
54
|
+
host = inject(ElementRef);
|
|
55
|
+
parent = inject(WR_SELECT, { optional: true });
|
|
56
|
+
/**
|
|
57
|
+
* @internal — true when this option is currently selected. Works for
|
|
58
|
+
* both single and multi-select parents via `WrSelectContext.isSelected`.
|
|
59
|
+
*/
|
|
60
|
+
selected = computed(() => {
|
|
61
|
+
const parent = this.parent;
|
|
62
|
+
if (!parent)
|
|
63
|
+
return false;
|
|
64
|
+
// Re-read parent's value signal so the computed recomputes on change.
|
|
65
|
+
parent.value();
|
|
66
|
+
return parent.isSelected(this.value());
|
|
67
|
+
}, /* @ts-ignore */
|
|
68
|
+
...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
|
|
69
|
+
/** @internal — true when this option is the keyboard cursor target. */
|
|
70
|
+
active = computed(() => this.parent?.activeOptionId() === this.id, /* @ts-ignore */
|
|
71
|
+
...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
72
|
+
/**
|
|
73
|
+
* @internal — search mode only. True when the parent has a query that
|
|
74
|
+
* the option's text content does not match (case-insensitive substring).
|
|
75
|
+
* Hidden options stay in the DOM so registration order survives but
|
|
76
|
+
* collapse via CSS.
|
|
77
|
+
*/
|
|
78
|
+
hidden = computed(() => {
|
|
79
|
+
const parent = this.parent;
|
|
80
|
+
if (!parent?.isSearch())
|
|
81
|
+
return false;
|
|
82
|
+
const q = parent.searchQuery().trim().toLowerCase();
|
|
83
|
+
if (!q)
|
|
84
|
+
return false;
|
|
85
|
+
const label = (this.host.nativeElement.textContent ?? '').trim().toLowerCase();
|
|
86
|
+
return !label.includes(q);
|
|
87
|
+
}, /* @ts-ignore */
|
|
88
|
+
...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
|
|
89
|
+
classes = computed(() => {
|
|
90
|
+
const parts = ['wr-option'];
|
|
91
|
+
if (this.selected())
|
|
92
|
+
parts.push('wr-option--selected');
|
|
93
|
+
if (this.active())
|
|
94
|
+
parts.push('wr-option--active');
|
|
95
|
+
if (this.disabled())
|
|
96
|
+
parts.push('wr-option--disabled');
|
|
97
|
+
if (this.hidden())
|
|
98
|
+
parts.push('wr-option--hidden');
|
|
99
|
+
return parts.join(' ');
|
|
100
|
+
}, /* @ts-ignore */
|
|
101
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
83
102
|
constructor() {
|
|
84
|
-
this.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
if (this.parent) {
|
|
104
|
+
const parent = this.parent;
|
|
105
|
+
// Re-register when disabled or value changes so the parent has fresh metadata.
|
|
106
|
+
effect(onCleanup => {
|
|
107
|
+
const unreg = parent.registerOption({
|
|
108
|
+
id: this.id,
|
|
109
|
+
value: this.value(),
|
|
110
|
+
disabled: this.disabled(),
|
|
111
|
+
getLabel: () => this.host.nativeElement.textContent?.trim() ?? '',
|
|
112
|
+
});
|
|
113
|
+
onCleanup(() => unreg());
|
|
114
|
+
});
|
|
115
|
+
inject(DestroyRef);
|
|
96
116
|
}
|
|
97
117
|
}
|
|
98
|
-
|
|
99
|
-
|
|
118
|
+
onClick() {
|
|
119
|
+
if (this.disabled() || !this.parent)
|
|
120
|
+
return;
|
|
121
|
+
this.parent.selectOption(this.value());
|
|
122
|
+
}
|
|
123
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: WrOption, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
124
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.1", type: WrOption, isStandalone: true, selector: "wr-option", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "option" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "id", "class": "classes()", "attr.aria-selected": "selected()", "attr.aria-disabled": "disabled() ? true : null" } }, ngImport: i0, template: '<ng-content />', isInline: true, encapsulation: i0.ViewEncapsulation.None });
|
|
100
125
|
}
|
|
101
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
126
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: WrOption, decorators: [{
|
|
102
127
|
type: Component,
|
|
103
|
-
args: [{
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
args: [{
|
|
129
|
+
selector: 'wr-option',
|
|
130
|
+
template: '<ng-content />',
|
|
131
|
+
encapsulation: ViewEncapsulation.None,
|
|
132
|
+
host: {
|
|
133
|
+
role: 'option',
|
|
134
|
+
'[attr.id]': 'id',
|
|
135
|
+
'[class]': 'classes()',
|
|
136
|
+
'[attr.aria-selected]': 'selected()',
|
|
137
|
+
'[attr.aria-disabled]': 'disabled() ? true : null',
|
|
138
|
+
'(click)': 'onClick()',
|
|
139
|
+
},
|
|
140
|
+
}]
|
|
141
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
116
142
|
|
|
117
143
|
/**
|
|
118
144
|
* @license
|
|
@@ -120,275 +146,762 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImpor
|
|
|
120
146
|
* Use of this source code is governed by an MIT-style license that can be
|
|
121
147
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
122
148
|
*/
|
|
149
|
+
let listboxUid = 0;
|
|
123
150
|
/**
|
|
124
|
-
*
|
|
151
|
+
* Combobox primitive. Renders a button that opens a CDK overlay
|
|
152
|
+
* containing the projected `<wr-option>` (and optionally
|
|
153
|
+
* `<wr-option-group>`) children. Every shape is the same component
|
|
154
|
+
* with a different `[mode]`:
|
|
155
|
+
*
|
|
156
|
+
* - `'single'` (default) — one value, no input. Classic dropdown.
|
|
157
|
+
* - `'multi'` — array value, chips on the trigger; clicking an option
|
|
158
|
+
* toggles instead of closing, Backspace removes the last chip.
|
|
159
|
+
* - `'search'` — type-ahead with sync `[options]` filter or async
|
|
160
|
+
* `[loader]`. Replaces the standalone `<wr-autocomplete>`.
|
|
161
|
+
* - `'tag'` — free-text + chips with `[separators]` / `[validate]` /
|
|
162
|
+
* `[allowDuplicates]`. Replaces `<wr-chips-input>`.
|
|
125
163
|
*
|
|
126
|
-
*
|
|
164
|
+
* Implements `ControlValueAccessor` — usable with `[(ngModel)]`,
|
|
165
|
+
* `formControl`, or `formControlName`.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```html
|
|
169
|
+
* <!-- Single -->
|
|
170
|
+
* <wr-select placeholder="Pick a size" [(ngModel)]="size">
|
|
171
|
+
* <wr-option value="sm">Small</wr-option>
|
|
172
|
+
* <wr-option value="md">Medium</wr-option>
|
|
173
|
+
* <wr-option value="lg">Large</wr-option>
|
|
174
|
+
* </wr-select>
|
|
175
|
+
*
|
|
176
|
+
* <!-- Multi -->
|
|
177
|
+
* <wr-select mode="multi" placeholder="Pick tags" [(ngModel)]="tags">
|
|
178
|
+
* <wr-option value="ts">TypeScript</wr-option>
|
|
179
|
+
* <wr-option value="ng">Angular</wr-option>
|
|
180
|
+
* </wr-select>
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* The legacy `[multi]="true"` boolean is still accepted but is now an
|
|
184
|
+
* alias for `[mode]="'multi'"` — prefer the explicit mode.
|
|
185
|
+
*
|
|
186
|
+
* @see https://ngwr.dev/components/select
|
|
127
187
|
*/
|
|
128
|
-
class
|
|
188
|
+
class WrSelect {
|
|
189
|
+
/** Placeholder shown when no option is selected. Falls back to `select.placeholder`. */
|
|
190
|
+
placeholder = input(null, /* @ts-ignore */
|
|
191
|
+
...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
|
|
192
|
+
/** Clear-selection (×) button aria-label. Falls back to `select.clearSelection`. */
|
|
193
|
+
clearLabel = input(null, /* @ts-ignore */
|
|
194
|
+
...(ngDevMode ? [{ debugName: "clearLabel" }] : /* istanbul ignore next */ []));
|
|
195
|
+
resolvedPlaceholder = useI18nText(this.placeholder, 'select.placeholder', '');
|
|
196
|
+
resolvedClear = useI18nText(this.clearLabel, 'select.clearSelection', 'Clear selection');
|
|
197
|
+
/** Per-chip ARIA label — interpolates `{{label}}`. @internal */
|
|
198
|
+
chipRemoveLabel = useI18nFormatter('select.removeItem', 'Remove {{label}}');
|
|
199
|
+
/** Disable the select. Also set by Angular forms via `setDisabledState`. */
|
|
200
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
201
|
+
/** Pill-shaped corners on the trigger. @default false */
|
|
202
|
+
rounded = input(false, { ...(ngDevMode ? { debugName: "rounded" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
203
|
+
/**
|
|
204
|
+
* Behavior mode. `<wr-select>` is the unified combobox primitive —
|
|
205
|
+
* pick the shape via `[mode]`:
|
|
206
|
+
*
|
|
207
|
+
* - `'single'` (default) — one value, no input. Classic dropdown.
|
|
208
|
+
* - `'multi'` — array value, chips on the trigger.
|
|
209
|
+
* - `'search'` *(planned)* — type-ahead with sync filter or async loader.
|
|
210
|
+
* - `'tag'` *(planned)* — free-text + chips with optional `allowCreate`.
|
|
211
|
+
*
|
|
212
|
+
*/
|
|
213
|
+
mode = input(null, /* @ts-ignore */
|
|
214
|
+
...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
215
|
+
/** Resolved mode — `'single'` unless `[mode]` says otherwise. */
|
|
216
|
+
effectiveMode = computed(() => this.mode() ?? 'single', /* @ts-ignore */
|
|
217
|
+
...(ngDevMode ? [{ debugName: "effectiveMode" }] : /* istanbul ignore next */ []));
|
|
218
|
+
/** Convenience — `effectiveMode() === 'multi'`. */
|
|
219
|
+
isMulti = computed(() => this.effectiveMode() === 'multi', /* @ts-ignore */
|
|
220
|
+
...(ngDevMode ? [{ debugName: "isMulti" }] : /* istanbul ignore next */ []));
|
|
221
|
+
/** Convenience — `effectiveMode() === 'tag'`. */
|
|
222
|
+
isTag = computed(() => this.effectiveMode() === 'tag', /* @ts-ignore */
|
|
223
|
+
...(ngDevMode ? [{ debugName: "isTag" }] : /* istanbul ignore next */ []));
|
|
224
|
+
/** Convenience — `effectiveMode() === 'search'`. Exposed via context for options. */
|
|
225
|
+
isSearch = computed(() => this.effectiveMode() === 'search', /* @ts-ignore */
|
|
226
|
+
...(ngDevMode ? [{ debugName: "isSearch" }] : /* istanbul ignore next */ []));
|
|
227
|
+
/** WrSelectContext — resolved multi-selection flag for child options. */
|
|
228
|
+
multi = computed(() => this.effectiveMode() === 'multi' || this.effectiveMode() === 'tag', /* @ts-ignore */
|
|
229
|
+
...(ngDevMode ? [{ debugName: "multi" }] : /* istanbul ignore next */ []));
|
|
230
|
+
/** Both multi and tag render chips on the trigger. */
|
|
231
|
+
hasChips = computed(() => {
|
|
232
|
+
const m = this.effectiveMode();
|
|
233
|
+
return m === 'multi' || m === 'tag';
|
|
234
|
+
}, /* @ts-ignore */
|
|
235
|
+
...(ngDevMode ? [{ debugName: "hasChips" }] : /* istanbul ignore next */ []));
|
|
236
|
+
/**
|
|
237
|
+
* Search-mode query. Empty string = no filter. Exposed via context so
|
|
238
|
+
* each `<wr-option>` can self-hide non-matching rows.
|
|
239
|
+
*/
|
|
240
|
+
searchQuery = signal('', /* @ts-ignore */
|
|
241
|
+
...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
242
|
+
// Search-mode-only inputs (ignored in other modes)
|
|
243
|
+
/**
|
|
244
|
+
* Search mode: dynamic option array. Each item is rendered as a
|
|
245
|
+
* `<wr-option>` whose label comes from `[displayWith]`. Works
|
|
246
|
+
* alongside projected `<wr-option>` children — both lists are
|
|
247
|
+
* filtered by the search query.
|
|
248
|
+
*/
|
|
249
|
+
options = input([], /* @ts-ignore */
|
|
250
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
251
|
+
/** Search mode: map a dynamic option item to its display label. @default String */
|
|
252
|
+
displayWith = input((item) => String(item), /* @ts-ignore */
|
|
253
|
+
...(ngDevMode ? [{ debugName: "displayWith" }] : /* istanbul ignore next */ []));
|
|
254
|
+
/**
|
|
255
|
+
* Search mode: async loader. When set, the loader is called on every
|
|
256
|
+
* (debounced) keystroke and its result replaces `[options]`. Supports
|
|
257
|
+
* Observables, Promises, and plain arrays.
|
|
258
|
+
*/
|
|
259
|
+
loader = input(null, /* @ts-ignore */
|
|
260
|
+
...(ngDevMode ? [{ debugName: "loader" }] : /* istanbul ignore next */ []));
|
|
261
|
+
/** Search mode: debounce (ms) applied to the loader. @default 250 */
|
|
262
|
+
debounceMs = input(250, { ...(ngDevMode ? { debugName: "debounceMs" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, Number(v) || 0) });
|
|
263
|
+
/** Search mode: minimum query length before the panel opens / loader fires. @default 0 */
|
|
264
|
+
minChars = input(0, { ...(ngDevMode ? { debugName: "minChars" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, Number(v) || 0) });
|
|
265
|
+
/**
|
|
266
|
+
* Search mode: allow values not in the options list. Enter on an
|
|
267
|
+
* unmatched query commits the raw text as the form value. @default false
|
|
268
|
+
*/
|
|
269
|
+
freeText = input(false, { ...(ngDevMode ? { debugName: "freeText" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
270
|
+
/** Search mode: text shown when the filter / loader returns nothing. Falls back to `select.noResults`. */
|
|
271
|
+
noResultsText = input(null, /* @ts-ignore */
|
|
272
|
+
...(ngDevMode ? [{ debugName: "noResultsText" }] : /* istanbul ignore next */ []));
|
|
273
|
+
/** Search mode: text shown while the async loader is in flight. Falls back to `select.loading`. */
|
|
274
|
+
loadingText = input(null, /* @ts-ignore */
|
|
275
|
+
...(ngDevMode ? [{ debugName: "loadingText" }] : /* istanbul ignore next */ []));
|
|
276
|
+
resolvedNoResults = useI18nText(this.noResultsText, 'select.noResults', 'No results');
|
|
277
|
+
resolvedLoading = useI18nText(this.loadingText, 'select.loading', 'Loading…');
|
|
278
|
+
/** Search mode: results returned by the async loader. @internal */
|
|
279
|
+
loadedOptions = signal([], /* @ts-ignore */
|
|
280
|
+
...(ngDevMode ? [{ debugName: "loadedOptions" }] : /* istanbul ignore next */ []));
|
|
281
|
+
/** Search mode: true while the loader is in flight. @internal */
|
|
282
|
+
loading = signal(false, /* @ts-ignore */
|
|
283
|
+
...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
|
|
284
|
+
// Tag-mode-only inputs (ignored in other modes)
|
|
285
|
+
/**
|
|
286
|
+
* Tag mode: keys / characters that commit the current draft into a chip.
|
|
287
|
+
* `'Enter'` is the key name; everything else is a literal character watched
|
|
288
|
+
* in keypresses and pastes. @default ['Enter', ',']
|
|
289
|
+
*/
|
|
290
|
+
separators = input(['Enter', ','], /* @ts-ignore */
|
|
291
|
+
...(ngDevMode ? [{ debugName: "separators" }] : /* istanbul ignore next */ []));
|
|
292
|
+
/** Tag mode: allow the same value to appear more than once. @default false */
|
|
293
|
+
allowDuplicates = input(false, { ...(ngDevMode ? { debugName: "allowDuplicates" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
294
|
+
/**
|
|
295
|
+
* Tag mode: custom validator — return `true` to accept the value, `false`
|
|
296
|
+
* to silently reject. Receives the trimmed draft + the existing chips.
|
|
297
|
+
*/
|
|
298
|
+
validate = input(null, /* @ts-ignore */
|
|
299
|
+
...(ngDevMode ? [{ debugName: "validate" }] : /* istanbul ignore next */ []));
|
|
300
|
+
/** Tag-mode draft (text currently typed in the inline input). @internal */
|
|
301
|
+
draft = signal('', /* @ts-ignore */
|
|
302
|
+
...(ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []));
|
|
303
|
+
/**
|
|
304
|
+
* Show a clear-all (×) button at the end of the chip row when at
|
|
305
|
+
* least one option is selected (multi mode only). @default true
|
|
306
|
+
*/
|
|
307
|
+
clearable = input(true, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
|
|
308
|
+
/**
|
|
309
|
+
* Cap on selected items (multi mode). `0` = unlimited. Once reached,
|
|
310
|
+
* additional clicks on unselected options are ignored. @default 0
|
|
311
|
+
*/
|
|
312
|
+
maxItems = input(0, { ...(ngDevMode ? { debugName: "maxItems" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, Number(v) || 0) });
|
|
313
|
+
/**
|
|
314
|
+
* Maximum number of chips rendered before collapsing the rest into a
|
|
315
|
+
* `+N more` indicator. `0` = render every chip. @default 0
|
|
316
|
+
*/
|
|
317
|
+
maxTagCount = input(0, { ...(ngDevMode ? { debugName: "maxTagCount" } : /* istanbul ignore next */ {}), transform: (v) => Math.max(0, Number(v) || 0) });
|
|
318
|
+
/**
|
|
319
|
+
* Unified value signal. Single mode holds `T | null`; multi mode
|
|
320
|
+
* holds `readonly T[]`. Internal — consumers go through `[(ngModel)]`
|
|
321
|
+
* or `[formControl]` via CVA.
|
|
322
|
+
* @internal
|
|
323
|
+
*/
|
|
324
|
+
value = signal(null, /* @ts-ignore */
|
|
325
|
+
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
326
|
+
/** Listbox id used by the trigger's `aria-controls`. */
|
|
327
|
+
listboxId = `wr-select-listbox-${++listboxUid}`;
|
|
328
|
+
/** Registered options (insertion order). Internal — distinct from the public `[options]` input. */
|
|
329
|
+
registry = signal([], /* @ts-ignore */
|
|
330
|
+
...(ngDevMode ? [{ debugName: "registry" }] : /* istanbul ignore next */ []));
|
|
331
|
+
/** Keyboard cursor index into `options`. -1 = none. */
|
|
332
|
+
activeIndex = signal(-1, /* @ts-ignore */
|
|
333
|
+
...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
334
|
+
/** Id of the active option (for `aria-activedescendant`). */
|
|
335
|
+
activeOptionId = computed(() => {
|
|
336
|
+
const idx = this.activeIndex();
|
|
337
|
+
const list = this.registry();
|
|
338
|
+
return idx >= 0 && idx < list.length ? list[idx].id : null;
|
|
339
|
+
}, /* @ts-ignore */
|
|
340
|
+
...(ngDevMode ? [{ debugName: "activeOptionId" }] : /* istanbul ignore next */ []));
|
|
341
|
+
open = signal(false, /* @ts-ignore */
|
|
342
|
+
...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
|
|
343
|
+
selectedLabel = signal(null, /* @ts-ignore */
|
|
344
|
+
...(ngDevMode ? [{ debugName: "selectedLabel" }] : /* istanbul ignore next */ []));
|
|
345
|
+
/**
|
|
346
|
+
* Selected chips (multi + tag modes). Multi reads labels from the
|
|
347
|
+
* registered `<wr-option>` children; tag uses each raw string as
|
|
348
|
+
* both value and label.
|
|
349
|
+
*/
|
|
350
|
+
selectedChips = computed(() => {
|
|
351
|
+
if (!this.hasChips())
|
|
352
|
+
return [];
|
|
353
|
+
const arr = this.asArray(this.value());
|
|
354
|
+
if (this.isTag()) {
|
|
355
|
+
return arr.map(v => ({ value: v, label: String(v) }));
|
|
356
|
+
}
|
|
357
|
+
const list = this.registry();
|
|
358
|
+
return arr.map(v => {
|
|
359
|
+
const found = list.find(o => o.value === v);
|
|
360
|
+
return { value: v, label: found?.getLabel() ?? String(v) };
|
|
361
|
+
});
|
|
362
|
+
}, /* @ts-ignore */
|
|
363
|
+
...(ngDevMode ? [{ debugName: "selectedChips" }] : /* istanbul ignore next */ []));
|
|
364
|
+
visibleChips = computed(() => {
|
|
365
|
+
const cap = this.maxTagCount();
|
|
366
|
+
const chips = this.selectedChips();
|
|
367
|
+
return cap > 0 && chips.length > cap ? chips.slice(0, cap) : chips;
|
|
368
|
+
}, /* @ts-ignore */
|
|
369
|
+
...(ngDevMode ? [{ debugName: "visibleChips" }] : /* istanbul ignore next */ []));
|
|
370
|
+
hiddenChipCount = computed(() => {
|
|
371
|
+
const cap = this.maxTagCount();
|
|
372
|
+
const total = this.selectedChips().length;
|
|
373
|
+
return cap > 0 && total > cap ? total - cap : 0;
|
|
374
|
+
}, /* @ts-ignore */
|
|
375
|
+
...(ngDevMode ? [{ debugName: "hiddenChipCount" }] : /* istanbul ignore next */ []));
|
|
376
|
+
hasSelection = computed(() => {
|
|
377
|
+
if (this.hasChips())
|
|
378
|
+
return this.selectedChips().length > 0;
|
|
379
|
+
return this.value() != null;
|
|
380
|
+
}, /* @ts-ignore */
|
|
381
|
+
...(ngDevMode ? [{ debugName: "hasSelection" }] : /* istanbul ignore next */ []));
|
|
382
|
+
disabledFromCva = signal(false, /* @ts-ignore */
|
|
383
|
+
...(ngDevMode ? [{ debugName: "disabledFromCva" }] : /* istanbul ignore next */ []));
|
|
384
|
+
/** Effective disabled state — input wins, CVA second. */
|
|
385
|
+
isDisabled = computed(() => this.disabled() || this.disabledFromCva(), /* @ts-ignore */
|
|
386
|
+
...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
|
|
387
|
+
classes = computed(() => {
|
|
388
|
+
const parts = ['wr-select'];
|
|
389
|
+
if (this.open())
|
|
390
|
+
parts.push('wr-select--open');
|
|
391
|
+
if (this.rounded())
|
|
392
|
+
parts.push('wr-select--rounded');
|
|
393
|
+
if (this.isMulti())
|
|
394
|
+
parts.push('wr-select--multi');
|
|
395
|
+
if (this.isTag())
|
|
396
|
+
parts.push('wr-select--tag');
|
|
397
|
+
if (this.isSearch())
|
|
398
|
+
parts.push('wr-select--search');
|
|
399
|
+
if (this.isDisabled())
|
|
400
|
+
parts.push('wr-select--disabled');
|
|
401
|
+
return parts.join(' ');
|
|
402
|
+
}, /* @ts-ignore */
|
|
403
|
+
...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
|
|
404
|
+
/**
|
|
405
|
+
* Search-mode dynamic options. Loader results win when the loader is
|
|
406
|
+
* set; otherwise the static `[options]` array. Each item is rendered
|
|
407
|
+
* as an internal `<wr-option>` in the panel.
|
|
408
|
+
*/
|
|
409
|
+
dynamicOptions = computed(() => this.loader() ? this.loadedOptions() : this.options(), /* @ts-ignore */
|
|
410
|
+
...(ngDevMode ? [{ debugName: "dynamicOptions" }] : /* istanbul ignore next */ []));
|
|
411
|
+
/**
|
|
412
|
+
* Count of registered options that pass the current search filter.
|
|
413
|
+
* Hides the noResults state when the panel has at least one visible row.
|
|
414
|
+
*/
|
|
415
|
+
visibleCount = computed(() => {
|
|
416
|
+
const list = this.registry();
|
|
417
|
+
if (!this.isSearch())
|
|
418
|
+
return list.length;
|
|
419
|
+
const q = this.searchQuery().trim().toLowerCase();
|
|
420
|
+
if (!q)
|
|
421
|
+
return list.length;
|
|
422
|
+
let count = 0;
|
|
423
|
+
for (const o of list) {
|
|
424
|
+
if (o.getLabel().toLowerCase().includes(q))
|
|
425
|
+
count++;
|
|
426
|
+
}
|
|
427
|
+
return count;
|
|
428
|
+
}, /* @ts-ignore */
|
|
429
|
+
...(ngDevMode ? [{ debugName: "visibleCount" }] : /* istanbul ignore next */ []));
|
|
430
|
+
/** Search mode: show "no results" when the panel has nothing to offer. */
|
|
431
|
+
hasNoResults = computed(() => {
|
|
432
|
+
if (!this.isSearch() || !this.open() || this.loading())
|
|
433
|
+
return false;
|
|
434
|
+
if (this.searchQuery().trim().length < this.minChars())
|
|
435
|
+
return false;
|
|
436
|
+
return this.visibleCount() === 0;
|
|
437
|
+
}, /* @ts-ignore */
|
|
438
|
+
...(ngDevMode ? [{ debugName: "hasNoResults" }] : /* istanbul ignore next */ []));
|
|
439
|
+
/** Search mode: is this option hidden by the current query? @internal */
|
|
440
|
+
isOptionHidden(label) {
|
|
441
|
+
if (!this.isSearch())
|
|
442
|
+
return false;
|
|
443
|
+
const q = this.searchQuery().trim().toLowerCase();
|
|
444
|
+
if (!q)
|
|
445
|
+
return false;
|
|
446
|
+
return !label.toLowerCase().includes(q);
|
|
447
|
+
}
|
|
448
|
+
panelTpl = viewChild.required('panelTpl', { read: TemplateRef });
|
|
449
|
+
/** Tag-mode inline input. Present only when `mode="tag"`. @internal */
|
|
450
|
+
tagInputEl = viewChild('tagInput', /* @ts-ignore */
|
|
451
|
+
...(ngDevMode ? [{ debugName: "tagInputEl" }] : /* istanbul ignore next */ []));
|
|
452
|
+
/** Search-mode inline input. Present only when `mode="search"`. @internal */
|
|
453
|
+
searchInputEl = viewChild('searchInput', /* @ts-ignore */
|
|
454
|
+
...(ngDevMode ? [{ debugName: "searchInputEl" }] : /* istanbul ignore next */ []));
|
|
455
|
+
focusTagInput() {
|
|
456
|
+
this.tagInputEl()?.nativeElement.focus();
|
|
457
|
+
}
|
|
458
|
+
focusSearchInput() {
|
|
459
|
+
this.searchInputEl()?.nativeElement.focus();
|
|
460
|
+
}
|
|
461
|
+
// Search-mode handlers
|
|
462
|
+
onSearchInput(event) {
|
|
463
|
+
if (this.isDisabled())
|
|
464
|
+
return;
|
|
465
|
+
const value = event.target.value;
|
|
466
|
+
this.searchQuery.set(value);
|
|
467
|
+
if (!this.open())
|
|
468
|
+
this.open.set(true);
|
|
469
|
+
}
|
|
470
|
+
onSearchFocus() {
|
|
471
|
+
if (this.isDisabled())
|
|
472
|
+
return;
|
|
473
|
+
if (!this.open()) {
|
|
474
|
+
this.seedActiveIndex();
|
|
475
|
+
this.open.set(true);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
onSearchKey(event) {
|
|
479
|
+
// freeText: Enter on an unmatched query commits the typed string
|
|
480
|
+
// as the value. Skips when an active option is highlighted (the
|
|
481
|
+
// normal Enter-selects behaviour wins).
|
|
482
|
+
if (event.key === 'Enter' && this.freeText() && this.open()) {
|
|
483
|
+
const q = this.searchQuery().trim();
|
|
484
|
+
const idx = this.activeIndex();
|
|
485
|
+
const list = this.registry();
|
|
486
|
+
const hasActive = idx >= 0 && idx < list.length && !list[idx].disabled && !this.isOptionHidden(list[idx].getLabel());
|
|
487
|
+
if (!hasActive && q) {
|
|
488
|
+
event.preventDefault();
|
|
489
|
+
this.value.set(q);
|
|
490
|
+
this.onChange(q);
|
|
491
|
+
this.onTouched();
|
|
492
|
+
this.open.set(false);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// Otherwise route through the same keyboard plumbing as the button trigger.
|
|
497
|
+
this.onTriggerKey(event);
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Display text for the search input. Shows the selected option's
|
|
501
|
+
* label when collapsed, or the live query while typing / panel open.
|
|
502
|
+
* @internal
|
|
503
|
+
*/
|
|
504
|
+
searchDisplay = computed(() => {
|
|
505
|
+
if (this.open())
|
|
506
|
+
return this.searchQuery();
|
|
507
|
+
return this.selectedLabel() ?? '';
|
|
508
|
+
}, /* @ts-ignore */
|
|
509
|
+
...(ngDevMode ? [{ debugName: "searchDisplay" }] : /* istanbul ignore next */ []));
|
|
510
|
+
host = inject(ElementRef);
|
|
511
|
+
overlay = inject(WR_OVERLAY);
|
|
512
|
+
vcr = inject(ViewContainerRef);
|
|
513
|
+
scrollStrategies = inject(ScrollStrategyOptions);
|
|
514
|
+
destroyRef = inject(DestroyRef);
|
|
515
|
+
overlayRef = null;
|
|
516
|
+
onChange = noop;
|
|
517
|
+
onTouched = noop;
|
|
129
518
|
constructor() {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.searchValue = signal('');
|
|
141
|
-
this.highlightedOptionIndex = signal(-1);
|
|
142
|
-
this.selectedOptions = computed(() => {
|
|
143
|
-
const currentValue = this.value();
|
|
144
|
-
const optionsArray = this.options?.toArray() || [];
|
|
145
|
-
if (this.multiple) {
|
|
146
|
-
return optionsArray.filter(option => Array.isArray(currentValue) && currentValue.includes(option.value));
|
|
519
|
+
effect(() => {
|
|
520
|
+
if (this.open()) {
|
|
521
|
+
this.openOverlay();
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
this.closeOverlay();
|
|
525
|
+
// Reset the search query when the panel closes so a re-open
|
|
526
|
+
// doesn't carry a stale filter.
|
|
527
|
+
if (this.isSearch())
|
|
528
|
+
this.searchQuery.set('');
|
|
147
529
|
}
|
|
148
|
-
return optionsArray.filter(option => option.value === currentValue);
|
|
149
|
-
});
|
|
150
|
-
this.selectedLabel = computed(() => {
|
|
151
|
-
const selected = this.selectedOptions();
|
|
152
|
-
return selected.length ? selected[0].label || selected[0].value : '';
|
|
153
530
|
});
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
531
|
+
// Async loader pipeline (search mode only). `switchMap` cancels
|
|
532
|
+
// in-flight requests when a new keystroke arrives.
|
|
533
|
+
toObservable(this.searchQuery)
|
|
534
|
+
.pipe(debounceTime(this.debounceMs()), switchMap(query => {
|
|
535
|
+
const loader = this.loader();
|
|
536
|
+
if (!loader || !this.isSearch() || query.length < this.minChars()) {
|
|
537
|
+
this.loading.set(false);
|
|
538
|
+
return of([]);
|
|
161
539
|
}
|
|
162
|
-
|
|
163
|
-
|
|
540
|
+
this.loading.set(true);
|
|
541
|
+
const result = loader(query);
|
|
542
|
+
const source = isObservable(result) ? result : from(Promise.resolve(result));
|
|
543
|
+
return source.pipe(finalize(() => this.loading.set(false)));
|
|
544
|
+
}), takeUntilDestroyed(this.destroyRef))
|
|
545
|
+
.subscribe(items => this.loadedOptions.set(items));
|
|
546
|
+
// Resolve the single-mode trigger label whenever the value or
|
|
547
|
+
// options change. Multi mode reads `selectedChips` instead and
|
|
548
|
+
// doesn't need this.
|
|
549
|
+
effect(() => {
|
|
550
|
+
const v = this.value();
|
|
551
|
+
const list = this.registry();
|
|
552
|
+
if (this.isMulti()) {
|
|
553
|
+
this.selectedLabel.set(null);
|
|
554
|
+
return;
|
|
164
555
|
}
|
|
165
|
-
|
|
556
|
+
const match = list.find(o => o.value === v);
|
|
557
|
+
this.selectedLabel.set(match ? match.getLabel() : null);
|
|
166
558
|
});
|
|
167
|
-
this.elementRef = inject(ElementRef);
|
|
168
|
-
this.cdr = inject(ChangeDetectorRef);
|
|
169
|
-
this.onChange = noop;
|
|
170
|
-
this.onTouch = noop;
|
|
171
|
-
}
|
|
172
|
-
set disabled(value) {
|
|
173
|
-
this.isDisabled.set(value);
|
|
174
|
-
}
|
|
175
|
-
get disabled() {
|
|
176
|
-
return this.isDisabled();
|
|
177
|
-
}
|
|
178
|
-
get hostClasses() {
|
|
179
|
-
return {
|
|
180
|
-
'wr-select': true,
|
|
181
|
-
'wr-select--open': this.isOpen(),
|
|
182
|
-
'wr-select--multiple': this.multiple,
|
|
183
|
-
'wr-select--disabled': this.isDisabled(),
|
|
184
|
-
'wr-select--focused': this.isFocused(),
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
onKeyDown(event) {
|
|
188
|
-
if (!this.isOpen()) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const filteredOpts = this.filteredOptions();
|
|
192
|
-
const currentIndex = this.highlightedOptionIndex();
|
|
193
|
-
switch (event.key) {
|
|
194
|
-
case 'ArrowDown':
|
|
195
|
-
event.preventDefault();
|
|
196
|
-
this.highlightedOptionIndex.set(currentIndex < filteredOpts.length - 1 ? currentIndex + 1 : 0);
|
|
197
|
-
break;
|
|
198
|
-
case 'ArrowUp':
|
|
199
|
-
event.preventDefault();
|
|
200
|
-
this.highlightedOptionIndex.set(currentIndex > 0 ? currentIndex - 1 : filteredOpts.length - 1);
|
|
201
|
-
break;
|
|
202
|
-
case 'Enter':
|
|
203
|
-
event.preventDefault();
|
|
204
|
-
if (currentIndex >= 0 && filteredOpts[currentIndex]) {
|
|
205
|
-
this.onOptionSelect(filteredOpts[currentIndex]);
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
case 'Backspace':
|
|
209
|
-
if (this.multiple && !this.searchValue() && this.selectedOptions().length) {
|
|
210
|
-
const selectedOptionsArray = this.selectedOptions();
|
|
211
|
-
const lastSelected = selectedOptionsArray[selectedOptionsArray.length - 1];
|
|
212
|
-
this.onOptionSelect(lastSelected);
|
|
213
|
-
}
|
|
214
|
-
break;
|
|
215
|
-
case 'Escape':
|
|
216
|
-
event.preventDefault();
|
|
217
|
-
this.close();
|
|
218
|
-
break;
|
|
219
|
-
}
|
|
220
559
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
560
|
+
// WrSelectContext
|
|
561
|
+
isSelected(value) {
|
|
562
|
+
if (this.isMulti())
|
|
563
|
+
return this.asArray(this.value()).includes(value);
|
|
564
|
+
return this.value() === value;
|
|
225
565
|
}
|
|
226
|
-
|
|
227
|
-
|
|
566
|
+
selectOption(value) {
|
|
567
|
+
if (this.isMulti()) {
|
|
568
|
+
const current = this.asArray(this.value());
|
|
569
|
+
const idx = current.indexOf(value);
|
|
570
|
+
let next;
|
|
571
|
+
if (idx >= 0) {
|
|
572
|
+
next = [...current.slice(0, idx), ...current.slice(idx + 1)];
|
|
573
|
+
}
|
|
574
|
+
else {
|
|
575
|
+
const cap = this.maxItems();
|
|
576
|
+
if (cap > 0 && current.length >= cap)
|
|
577
|
+
return;
|
|
578
|
+
next = [...current, value];
|
|
579
|
+
}
|
|
580
|
+
this.value.set(next);
|
|
581
|
+
this.onChange(next);
|
|
582
|
+
this.onTouched();
|
|
583
|
+
// Keep the panel open in multi mode so the user can keep picking.
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
this.value.set(value);
|
|
587
|
+
this.onChange(value);
|
|
588
|
+
this.onTouched();
|
|
589
|
+
this.open.set(false);
|
|
228
590
|
}
|
|
229
|
-
|
|
230
|
-
|
|
591
|
+
registerOption(reg) {
|
|
592
|
+
this.registry.update(list => [...list, reg]);
|
|
593
|
+
return () => this.registry.update(list => list.filter(o => o.id !== reg.id));
|
|
231
594
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
595
|
+
// Chip handlers (multi + tag)
|
|
596
|
+
/** Remove one selection (chip × button). Works for multi and tag modes. */
|
|
597
|
+
removeChip(value, event) {
|
|
598
|
+
event.stopPropagation();
|
|
599
|
+
if (this.isDisabled() || !this.hasChips())
|
|
600
|
+
return;
|
|
601
|
+
const next = this.asArray(this.value()).filter(v => v !== value);
|
|
602
|
+
this.value.set(next);
|
|
603
|
+
this.onChange(next);
|
|
604
|
+
this.onTouched();
|
|
236
605
|
}
|
|
237
|
-
|
|
606
|
+
/** Clear every selection (× button). Multi/tag → empty array; search → null. */
|
|
607
|
+
clearAll(event) {
|
|
608
|
+
event.stopPropagation();
|
|
238
609
|
if (this.isDisabled())
|
|
239
610
|
return;
|
|
240
|
-
if (this.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
this.writeValue(newValue);
|
|
249
|
-
this.searchValue.set('');
|
|
611
|
+
if (this.hasChips()) {
|
|
612
|
+
this.value.set([]);
|
|
613
|
+
this.onChange([]);
|
|
614
|
+
}
|
|
615
|
+
else if (this.isSearch()) {
|
|
616
|
+
this.value.set(null);
|
|
617
|
+
this.onChange(null);
|
|
618
|
+
this.searchQuery.set('');
|
|
250
619
|
}
|
|
251
620
|
else {
|
|
252
|
-
|
|
253
|
-
this.close();
|
|
621
|
+
return;
|
|
254
622
|
}
|
|
623
|
+
this.onTouched();
|
|
255
624
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
625
|
+
// Tag-mode draft handlers
|
|
626
|
+
/** Capacity check used by tag mode to refuse the next add. */
|
|
627
|
+
atCapacity = computed(() => {
|
|
628
|
+
const cap = this.maxItems();
|
|
629
|
+
return cap > 0 && this.asArray(this.value()).length >= cap;
|
|
630
|
+
}, /* @ts-ignore */
|
|
631
|
+
...(ngDevMode ? [{ debugName: "atCapacity" }] : /* istanbul ignore next */ []));
|
|
632
|
+
onTagInput(event) {
|
|
633
|
+
if (this.isDisabled())
|
|
634
|
+
return;
|
|
635
|
+
this.draft.set(event.target.value);
|
|
259
636
|
}
|
|
260
|
-
|
|
261
|
-
if (this.
|
|
262
|
-
return
|
|
637
|
+
onTagKeydown(event) {
|
|
638
|
+
if (this.isDisabled())
|
|
639
|
+
return;
|
|
640
|
+
const seps = this.separators();
|
|
641
|
+
if (seps.includes(event.key)) {
|
|
642
|
+
event.preventDefault();
|
|
643
|
+
this.commitDraft();
|
|
644
|
+
return;
|
|
263
645
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (this.multiple) {
|
|
270
|
-
const currentValue = this.value();
|
|
271
|
-
if (Array.isArray(currentValue) && currentValue.includes(option.value)) {
|
|
272
|
-
return true;
|
|
646
|
+
if (event.key === 'Backspace' && this.draft() === '') {
|
|
647
|
+
const chips = this.selectedChips();
|
|
648
|
+
if (chips.length > 0) {
|
|
649
|
+
event.preventDefault();
|
|
650
|
+
this.removeChip(chips[chips.length - 1].value, event);
|
|
273
651
|
}
|
|
274
652
|
}
|
|
275
|
-
const search = this.searchValue().toLowerCase();
|
|
276
|
-
if (search) {
|
|
277
|
-
return !(option.label || option.value.toString()).toLowerCase().includes(search);
|
|
278
|
-
}
|
|
279
|
-
return false;
|
|
280
653
|
}
|
|
654
|
+
onTagPaste(event) {
|
|
655
|
+
if (this.isDisabled())
|
|
656
|
+
return;
|
|
657
|
+
const text = event.clipboardData?.getData('text') ?? '';
|
|
658
|
+
if (!text)
|
|
659
|
+
return;
|
|
660
|
+
const seps = this.separators().filter(s => s !== 'Enter');
|
|
661
|
+
if (seps.length === 0)
|
|
662
|
+
return;
|
|
663
|
+
event.preventDefault();
|
|
664
|
+
const escaped = seps.map(s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('');
|
|
665
|
+
const splitRegex = new RegExp(`[${escaped}\\n]+`);
|
|
666
|
+
for (const part of text.split(splitRegex))
|
|
667
|
+
this.tryAddTag(part);
|
|
668
|
+
}
|
|
669
|
+
onTagBlur() {
|
|
670
|
+
if (this.draft().trim())
|
|
671
|
+
this.commitDraft();
|
|
672
|
+
this.onTouched();
|
|
673
|
+
}
|
|
674
|
+
commitDraft() {
|
|
675
|
+
const v = this.draft().trim();
|
|
676
|
+
this.draft.set('');
|
|
677
|
+
if (v)
|
|
678
|
+
this.tryAddTag(v);
|
|
679
|
+
}
|
|
680
|
+
tryAddTag(raw) {
|
|
681
|
+
if (!this.isTag() || this.atCapacity())
|
|
682
|
+
return;
|
|
683
|
+
const value = raw.trim();
|
|
684
|
+
if (!value)
|
|
685
|
+
return;
|
|
686
|
+
const existing = this.asArray(this.value()).map(String);
|
|
687
|
+
if (!this.allowDuplicates() && existing.includes(value))
|
|
688
|
+
return;
|
|
689
|
+
const validator = this.validate();
|
|
690
|
+
if (validator && !validator(value, existing))
|
|
691
|
+
return;
|
|
692
|
+
const next = [...existing, value];
|
|
693
|
+
this.value.set(next);
|
|
694
|
+
this.onChange(next);
|
|
695
|
+
this.onTouched();
|
|
696
|
+
}
|
|
697
|
+
// ControlValueAccessor
|
|
281
698
|
writeValue(value) {
|
|
282
|
-
this.
|
|
283
|
-
|
|
284
|
-
|
|
699
|
+
if (this.hasChips()) {
|
|
700
|
+
this.value.set(Array.isArray(value) ? value : []);
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
this.value.set(value);
|
|
704
|
+
}
|
|
285
705
|
}
|
|
286
706
|
registerOnChange(fn) {
|
|
287
707
|
this.onChange = fn;
|
|
288
708
|
}
|
|
289
709
|
registerOnTouched(fn) {
|
|
290
|
-
this.
|
|
710
|
+
this.onTouched = fn;
|
|
291
711
|
}
|
|
292
712
|
setDisabledState(isDisabled) {
|
|
293
|
-
this.
|
|
713
|
+
this.disabledFromCva.set(coerceBooleanProperty(isDisabled));
|
|
714
|
+
if (isDisabled)
|
|
715
|
+
this.open.set(false);
|
|
294
716
|
}
|
|
295
|
-
|
|
296
|
-
|
|
717
|
+
// Template handlers
|
|
718
|
+
onTriggerClick() {
|
|
297
719
|
if (this.isDisabled())
|
|
298
720
|
return;
|
|
299
|
-
|
|
300
|
-
|
|
721
|
+
// Tag mode has no panel — clicks should land on the inline input,
|
|
722
|
+
// not toggle an overlay that's never created.
|
|
723
|
+
if (this.isTag())
|
|
724
|
+
return;
|
|
725
|
+
this.open.update(v => !v);
|
|
726
|
+
}
|
|
727
|
+
onTriggerKey(event) {
|
|
728
|
+
if (this.isDisabled())
|
|
729
|
+
return;
|
|
730
|
+
if (!this.open()) {
|
|
731
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
732
|
+
event.preventDefault();
|
|
733
|
+
this.seedActiveIndex();
|
|
734
|
+
this.open.set(true);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
// Multi mode: Backspace on closed trigger removes last chip. Tag
|
|
738
|
+
// mode has its own input handler — never reaches this branch.
|
|
739
|
+
if (event.key === 'Backspace' && this.isMulti() && this.hasSelection()) {
|
|
740
|
+
event.preventDefault();
|
|
741
|
+
const chips = this.selectedChips();
|
|
742
|
+
const last = chips[chips.length - 1];
|
|
743
|
+
if (last)
|
|
744
|
+
this.removeChip(last.value, event);
|
|
745
|
+
}
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
// Open — navigation/selection.
|
|
749
|
+
switch (event.key) {
|
|
750
|
+
case 'ArrowDown':
|
|
751
|
+
event.preventDefault();
|
|
752
|
+
this.moveActive(1);
|
|
753
|
+
break;
|
|
754
|
+
case 'ArrowUp':
|
|
755
|
+
event.preventDefault();
|
|
756
|
+
this.moveActive(-1);
|
|
757
|
+
break;
|
|
758
|
+
case 'Home':
|
|
759
|
+
event.preventDefault();
|
|
760
|
+
this.activeIndex.set(this.firstEnabled());
|
|
761
|
+
break;
|
|
762
|
+
case 'End':
|
|
763
|
+
event.preventDefault();
|
|
764
|
+
this.activeIndex.set(this.lastEnabled());
|
|
765
|
+
break;
|
|
766
|
+
case 'Enter':
|
|
767
|
+
case ' ': {
|
|
768
|
+
event.preventDefault();
|
|
769
|
+
const idx = this.activeIndex();
|
|
770
|
+
const list = this.registry();
|
|
771
|
+
if (idx >= 0 && idx < list.length && !list[idx].disabled) {
|
|
772
|
+
const id = list[idx].id;
|
|
773
|
+
const el = this.overlayRef?.overlayElement.querySelector(`#${CSS.escape(id)}`);
|
|
774
|
+
el?.click();
|
|
775
|
+
}
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
default:
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
seedActiveIndex() {
|
|
783
|
+
const list = this.registry();
|
|
784
|
+
let selectedIdx = -1;
|
|
785
|
+
if (this.isMulti()) {
|
|
786
|
+
const arr = this.asArray(this.value());
|
|
787
|
+
if (arr.length > 0)
|
|
788
|
+
selectedIdx = list.findIndex(o => o.value === arr[0]);
|
|
301
789
|
}
|
|
302
790
|
else {
|
|
303
|
-
this.
|
|
791
|
+
selectedIdx = list.findIndex(o => o.value === this.value());
|
|
304
792
|
}
|
|
793
|
+
this.activeIndex.set(selectedIdx >= 0 ? selectedIdx : this.firstEnabled());
|
|
305
794
|
}
|
|
306
|
-
|
|
307
|
-
|
|
795
|
+
moveActive(delta) {
|
|
796
|
+
const list = this.registry();
|
|
797
|
+
if (list.length === 0)
|
|
308
798
|
return;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.
|
|
316
|
-
|
|
799
|
+
let i = this.activeIndex();
|
|
800
|
+
let attempts = list.length;
|
|
801
|
+
while (attempts-- > 0) {
|
|
802
|
+
i = (i + delta + list.length) % list.length;
|
|
803
|
+
const o = list[i];
|
|
804
|
+
if (!o.disabled && !this.isOptionHidden(o.getLabel())) {
|
|
805
|
+
this.activeIndex.set(i);
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
317
808
|
}
|
|
318
809
|
}
|
|
319
|
-
|
|
320
|
-
this.
|
|
321
|
-
this.isFocused.set(false);
|
|
322
|
-
this.searchValue.set('');
|
|
323
|
-
this.highlightedOptionIndex.set(-1);
|
|
810
|
+
firstEnabled() {
|
|
811
|
+
return this.registry().findIndex(o => !o.disabled && !this.isOptionHidden(o.getLabel()));
|
|
324
812
|
}
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
813
|
+
lastEnabled() {
|
|
814
|
+
const list = this.registry();
|
|
815
|
+
let found = -1;
|
|
816
|
+
list.forEach((o, i) => {
|
|
817
|
+
if (!o.disabled && !this.isOptionHidden(o.getLabel()))
|
|
818
|
+
found = i;
|
|
819
|
+
});
|
|
820
|
+
return found;
|
|
821
|
+
}
|
|
822
|
+
/** Coerce the multi-mode value signal into an array (handles writeValue from non-array). */
|
|
823
|
+
asArray(value) {
|
|
824
|
+
if (Array.isArray(value))
|
|
825
|
+
return value;
|
|
826
|
+
if (value == null)
|
|
827
|
+
return [];
|
|
828
|
+
return [value];
|
|
331
829
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
830
|
+
// Overlay
|
|
831
|
+
openOverlay() {
|
|
832
|
+
if (this.overlayRef)
|
|
833
|
+
return;
|
|
834
|
+
const positionStrategy = this.overlay
|
|
835
|
+
.position()
|
|
836
|
+
.flexibleConnectedTo(this.host)
|
|
837
|
+
.withPositions([
|
|
838
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' },
|
|
839
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' },
|
|
840
|
+
])
|
|
841
|
+
.withPush(true);
|
|
842
|
+
this.overlayRef = this.overlay.create({
|
|
843
|
+
positionStrategy,
|
|
844
|
+
scrollStrategy: this.scrollStrategies.reposition(),
|
|
845
|
+
width: this.host.nativeElement.getBoundingClientRect().width,
|
|
846
|
+
panelClass: 'wr-select-overlay',
|
|
847
|
+
});
|
|
848
|
+
const portal = new TemplatePortal(this.panelTpl(), this.vcr);
|
|
849
|
+
this.overlayRef.attach(portal);
|
|
850
|
+
this.overlayRef
|
|
851
|
+
.outsidePointerEvents()
|
|
852
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
853
|
+
.subscribe(event => {
|
|
854
|
+
if (this.host.nativeElement.contains(event.target))
|
|
855
|
+
return;
|
|
856
|
+
this.open.set(false);
|
|
857
|
+
});
|
|
858
|
+
this.overlayRef
|
|
859
|
+
.keydownEvents()
|
|
860
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
861
|
+
.subscribe(event => {
|
|
862
|
+
if (event.key === 'Escape') {
|
|
863
|
+
event.preventDefault();
|
|
864
|
+
this.open.set(false);
|
|
865
|
+
}
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
closeOverlay() {
|
|
869
|
+
if (!this.overlayRef)
|
|
870
|
+
return;
|
|
871
|
+
this.overlayRef.dispose();
|
|
872
|
+
this.overlayRef = null;
|
|
873
|
+
}
|
|
874
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: WrSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
875
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.1", type: WrSelect, isStandalone: true, selector: "wr-select", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, clearLabel: { classPropertyName: "clearLabel", publicName: "clearLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, displayWith: { classPropertyName: "displayWith", publicName: "displayWith", isSignal: true, isRequired: false, transformFunction: null }, loader: { classPropertyName: "loader", publicName: "loader", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null }, freeText: { classPropertyName: "freeText", publicName: "freeText", isSignal: true, isRequired: false, transformFunction: null }, noResultsText: { classPropertyName: "noResultsText", publicName: "noResultsText", isSignal: true, isRequired: false, transformFunction: null }, loadingText: { classPropertyName: "loadingText", publicName: "loadingText", isSignal: true, isRequired: false, transformFunction: null }, separators: { classPropertyName: "separators", publicName: "separators", isSignal: true, isRequired: false, transformFunction: null }, allowDuplicates: { classPropertyName: "allowDuplicates", publicName: "allowDuplicates", isSignal: true, isRequired: false, transformFunction: null }, validate: { classPropertyName: "validate", publicName: "validate", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, maxItems: { classPropertyName: "maxItems", publicName: "maxItems", isSignal: true, isRequired: false, transformFunction: null }, maxTagCount: { classPropertyName: "maxTagCount", publicName: "maxTagCount", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, providers: [
|
|
335
876
|
{
|
|
336
877
|
provide: NG_VALUE_ACCESSOR,
|
|
337
878
|
// eslint-disable-next-line @angular-eslint/no-forward-ref
|
|
338
|
-
useExisting: forwardRef(() =>
|
|
879
|
+
useExisting: forwardRef(() => WrSelect),
|
|
339
880
|
multi: true,
|
|
340
881
|
},
|
|
341
|
-
|
|
882
|
+
{
|
|
883
|
+
provide: WR_SELECT,
|
|
884
|
+
// eslint-disable-next-line @angular-eslint/no-forward-ref
|
|
885
|
+
useExisting: forwardRef(() => WrSelect),
|
|
886
|
+
},
|
|
887
|
+
], viewQueries: [{ propertyName: "panelTpl", first: true, predicate: ["panelTpl"], descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "tagInputEl", first: true, predicate: ["tagInput"], descendants: true, isSignal: true }, { propertyName: "searchInputEl", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isSearch()) {\n <!-- Search mode: a real text input drives a filtered overlay panel.\n The wrapper isn't itself focusable \u2014 the input is the tabstop. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n <div class=\"wr-select__trigger wr-select__trigger--search\" (click)=\"focusSearchInput()\">\n <input\n #searchInput\n type=\"text\"\n role=\"combobox\"\n class=\"wr-select__search-input\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [disabled]=\"isDisabled()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-activedescendant]=\"open() ? activeOptionId() || null : null\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"searchDisplay()\"\n (input)=\"onSearchInput($event)\"\n (focus)=\"onSearchFocus()\"\n (keydown)=\"onSearchKey($event)\"\n (blur)=\"onTouched()\"\n />\n @if (clearable() && hasSelection() && !isDisabled()) {\n <span\n class=\"wr-select__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClear()\"\n tabindex=\"-1\"\n (click)=\"clearAll($event)\"\n (keydown.enter)=\"clearAll($event)\"\n (keydown.space)=\"clearAll($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n <svg\n class=\"wr-icon__svg wr-select__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n} @else if (isTag()) {\n <!-- Tag mode: a focusable input lives inside, so the wrapper itself\n only exists to host chips and forward whitespace clicks to the\n input. Keyboard users tab straight into the input \u2014 no need for a\n separate role. The click handler is a mouse-only convenience. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"wr-select__trigger wr-select__trigger--tag\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n (click)=\"focusTagInput()\"\n >\n <span class=\"wr-select__chips\">\n @for (chip of visibleChips(); track $index) {\n <span class=\"wr-select__chip\">\n <span class=\"wr-select__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-select__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.value, $event)\"\n (keydown.enter)=\"removeChip(chip.value, $event)\"\n (keydown.space)=\"removeChip(chip.value, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-select__chip wr-select__chip--more\">+{{ extra }} more</span>\n }\n <input\n #tagInput\n type=\"text\"\n class=\"wr-select__tag-input\"\n [value]=\"draft()\"\n [disabled]=\"isDisabled() || atCapacity()\"\n [placeholder]=\"hasSelection() ? '' : resolvedPlaceholder()\"\n (input)=\"onTagInput($event)\"\n (keydown)=\"onTagKeydown($event)\"\n (paste)=\"onTagPaste($event)\"\n (blur)=\"onTagBlur()\"\n />\n </span>\n\n @if (clearable() && hasSelection() && !isDisabled()) {\n <span\n class=\"wr-select__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClear()\"\n tabindex=\"-1\"\n (click)=\"clearAll($event)\"\n (keydown.enter)=\"clearAll($event)\"\n (keydown.space)=\"clearAll($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n </div>\n} @else {\n <button\n type=\"button\"\n class=\"wr-select__trigger\"\n role=\"combobox\"\n [disabled]=\"isDisabled()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n [attr.aria-activedescendant]=\"open() ? activeOptionId() || null : null\"\n (click)=\"onTriggerClick()\"\n (keydown)=\"onTriggerKey($event)\"\n (blur)=\"onTouched()\"\n >\n @if (isMulti()) {\n @if (hasSelection()) {\n <span class=\"wr-select__chips\">\n @for (chip of visibleChips(); track $index) {\n <span class=\"wr-select__chip\">\n <span class=\"wr-select__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-select__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.value, $event)\"\n (keydown.enter)=\"removeChip(chip.value, $event)\"\n (keydown.space)=\"removeChip(chip.value, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-select__chip wr-select__chip--more\">+{{ extra }} more</span>\n }\n </span>\n } @else {\n <span class=\"wr-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n } @else {\n @if (selectedLabel(); as label) {\n <span class=\"wr-select__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n }\n\n @if (isMulti() && clearable() && hasSelection() && !isDisabled()) {\n <span\n class=\"wr-select__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClear()\"\n tabindex=\"-1\"\n (click)=\"clearAll($event)\"\n (keydown.enter)=\"clearAll($event)\"\n (keydown.space)=\"clearAll($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n\n <svg\n class=\"wr-icon__svg wr-select__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n}\n\n<ng-template #panelTpl>\n <div\n class=\"wr-select-panel\"\n role=\"listbox\"\n [attr.id]=\"listboxId\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n >\n @if (loading()) {\n <div class=\"wr-select-panel__loading\" aria-busy=\"true\">{{ resolvedLoading() }}</div>\n }\n\n <!-- Dynamic options from [options] or async [loader] (search mode).\n Rendered as wr-option so the standard registration / filter\n pipeline applies uniformly. -->\n @for (item of dynamicOptions(); track $index) {\n <wr-option [value]=\"item\">{{ displayWith()(item) }}</wr-option>\n }\n\n <!-- Projected static options. -->\n <ng-content />\n\n @if (hasNoResults()) {\n <div class=\"wr-select-panel__empty\">{{ resolvedNoResults() }}</div>\n }\n </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: WrOption, selector: "wr-option", inputs: ["value", "disabled"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
342
888
|
}
|
|
343
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
889
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: WrSelect, decorators: [{
|
|
344
890
|
type: Component,
|
|
345
|
-
args: [{ selector: 'wr-select',
|
|
346
|
-
provideWrIcons([chevronDown, close]),
|
|
891
|
+
args: [{ selector: 'wr-select', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrOption], providers: [
|
|
347
892
|
{
|
|
348
893
|
provide: NG_VALUE_ACCESSOR,
|
|
349
894
|
// eslint-disable-next-line @angular-eslint/no-forward-ref
|
|
350
|
-
useExisting: forwardRef(() =>
|
|
895
|
+
useExisting: forwardRef(() => WrSelect),
|
|
351
896
|
multi: true,
|
|
352
897
|
},
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}],
|
|
359
|
-
|
|
360
|
-
args: [{ transform: booleanAttribute }]
|
|
361
|
-
}], searchable: [{
|
|
362
|
-
type: Input,
|
|
363
|
-
args: [{ transform: booleanAttribute }]
|
|
364
|
-
}], clearable: [{
|
|
365
|
-
type: Input,
|
|
366
|
-
args: [{ transform: booleanAttribute }]
|
|
367
|
-
}], maxMultipleCount: [{
|
|
368
|
-
type: Input,
|
|
369
|
-
args: [{ transform: numberAttribute }]
|
|
370
|
-
}], disabled: [{
|
|
371
|
-
type: Input,
|
|
372
|
-
args: [{ transform: booleanAttribute }]
|
|
373
|
-
}], searchInput: [{
|
|
374
|
-
type: ViewChild,
|
|
375
|
-
args: ['searchInput']
|
|
376
|
-
}], options: [{
|
|
377
|
-
type: ContentChildren,
|
|
378
|
-
args: [WrOptionComponent, { descendants: true }]
|
|
379
|
-
}], optionGroups: [{
|
|
380
|
-
type: ContentChildren,
|
|
381
|
-
args: [WrOptionGroupComponent]
|
|
382
|
-
}], hostClasses: [{
|
|
383
|
-
type: HostBinding,
|
|
384
|
-
args: ['class']
|
|
385
|
-
}], onKeyDown: [{
|
|
386
|
-
type: HostListener,
|
|
387
|
-
args: ['document:keydown', ['$event']]
|
|
388
|
-
}], onClickOutside: [{
|
|
389
|
-
type: HostListener,
|
|
390
|
-
args: ['document:click', ['$event']]
|
|
391
|
-
}] } });
|
|
898
|
+
{
|
|
899
|
+
provide: WR_SELECT,
|
|
900
|
+
// eslint-disable-next-line @angular-eslint/no-forward-ref
|
|
901
|
+
useExisting: forwardRef(() => WrSelect),
|
|
902
|
+
},
|
|
903
|
+
], template: "@if (isSearch()) {\n <!-- Search mode: a real text input drives a filtered overlay panel.\n The wrapper isn't itself focusable \u2014 the input is the tabstop. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n <div class=\"wr-select__trigger wr-select__trigger--search\" (click)=\"focusSearchInput()\">\n <input\n #searchInput\n type=\"text\"\n role=\"combobox\"\n class=\"wr-select__search-input\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [disabled]=\"isDisabled()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-activedescendant]=\"open() ? activeOptionId() || null : null\"\n [placeholder]=\"resolvedPlaceholder()\"\n [value]=\"searchDisplay()\"\n (input)=\"onSearchInput($event)\"\n (focus)=\"onSearchFocus()\"\n (keydown)=\"onSearchKey($event)\"\n (blur)=\"onTouched()\"\n />\n @if (clearable() && hasSelection() && !isDisabled()) {\n <span\n class=\"wr-select__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClear()\"\n tabindex=\"-1\"\n (click)=\"clearAll($event)\"\n (keydown.enter)=\"clearAll($event)\"\n (keydown.space)=\"clearAll($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n <svg\n class=\"wr-icon__svg wr-select__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </div>\n} @else if (isTag()) {\n <!-- Tag mode: a focusable input lives inside, so the wrapper itself\n only exists to host chips and forward whitespace clicks to the\n input. Keyboard users tab straight into the input \u2014 no need for a\n separate role. The click handler is a mouse-only convenience. -->\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events,@angular-eslint/template/interactive-supports-focus -->\n <div\n class=\"wr-select__trigger wr-select__trigger--tag\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n (click)=\"focusTagInput()\"\n >\n <span class=\"wr-select__chips\">\n @for (chip of visibleChips(); track $index) {\n <span class=\"wr-select__chip\">\n <span class=\"wr-select__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-select__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.value, $event)\"\n (keydown.enter)=\"removeChip(chip.value, $event)\"\n (keydown.space)=\"removeChip(chip.value, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-select__chip wr-select__chip--more\">+{{ extra }} more</span>\n }\n <input\n #tagInput\n type=\"text\"\n class=\"wr-select__tag-input\"\n [value]=\"draft()\"\n [disabled]=\"isDisabled() || atCapacity()\"\n [placeholder]=\"hasSelection() ? '' : resolvedPlaceholder()\"\n (input)=\"onTagInput($event)\"\n (keydown)=\"onTagKeydown($event)\"\n (paste)=\"onTagPaste($event)\"\n (blur)=\"onTagBlur()\"\n />\n </span>\n\n @if (clearable() && hasSelection() && !isDisabled()) {\n <span\n class=\"wr-select__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClear()\"\n tabindex=\"-1\"\n (click)=\"clearAll($event)\"\n (keydown.enter)=\"clearAll($event)\"\n (keydown.space)=\"clearAll($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n </div>\n} @else {\n <button\n type=\"button\"\n class=\"wr-select__trigger\"\n role=\"combobox\"\n [disabled]=\"isDisabled()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n [attr.aria-activedescendant]=\"open() ? activeOptionId() || null : null\"\n (click)=\"onTriggerClick()\"\n (keydown)=\"onTriggerKey($event)\"\n (blur)=\"onTouched()\"\n >\n @if (isMulti()) {\n @if (hasSelection()) {\n <span class=\"wr-select__chips\">\n @for (chip of visibleChips(); track $index) {\n <span class=\"wr-select__chip\">\n <span class=\"wr-select__chip-label\">{{ chip.label }}</span>\n <span\n class=\"wr-select__chip-remove\"\n role=\"button\"\n [attr.aria-label]=\"chipRemoveLabel({ label: chip.label })\"\n tabindex=\"-1\"\n (click)=\"removeChip(chip.value, $event)\"\n (keydown.enter)=\"removeChip(chip.value, $event)\"\n (keydown.space)=\"removeChip(chip.value, $event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n </span>\n }\n @if (hiddenChipCount(); as extra) {\n <span class=\"wr-select__chip wr-select__chip--more\">+{{ extra }} more</span>\n }\n </span>\n } @else {\n <span class=\"wr-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n } @else {\n @if (selectedLabel(); as label) {\n <span class=\"wr-select__value\">{{ label }}</span>\n } @else {\n <span class=\"wr-select__placeholder\">{{ resolvedPlaceholder() }}</span>\n }\n }\n\n @if (isMulti() && clearable() && hasSelection() && !isDisabled()) {\n <span\n class=\"wr-select__clear\"\n role=\"button\"\n [attr.aria-label]=\"resolvedClear()\"\n tabindex=\"-1\"\n (click)=\"clearAll($event)\"\n (keydown.enter)=\"clearAll($event)\"\n (keydown.space)=\"clearAll($event)\"\n >\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n </span>\n }\n\n <svg\n class=\"wr-icon__svg wr-select__chevron\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n </button>\n}\n\n<ng-template #panelTpl>\n <div\n class=\"wr-select-panel\"\n role=\"listbox\"\n [attr.id]=\"listboxId\"\n [attr.aria-multiselectable]=\"isMulti() ? 'true' : null\"\n >\n @if (loading()) {\n <div class=\"wr-select-panel__loading\" aria-busy=\"true\">{{ resolvedLoading() }}</div>\n }\n\n <!-- Dynamic options from [options] or async [loader] (search mode).\n Rendered as wr-option so the standard registration / filter\n pipeline applies uniformly. -->\n @for (item of dynamicOptions(); track $index) {\n <wr-option [value]=\"item\">{{ displayWith()(item) }}</wr-option>\n }\n\n <!-- Projected static options. -->\n <ng-content />\n\n @if (hasNoResults()) {\n <div class=\"wr-select-panel__empty\">{{ resolvedNoResults() }}</div>\n }\n </div>\n</ng-template>\n" }]
|
|
904
|
+
}], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], clearLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], displayWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayWith", required: false }] }], loader: [{ type: i0.Input, args: [{ isSignal: true, alias: "loader", required: false }] }], debounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceMs", required: false }] }], minChars: [{ type: i0.Input, args: [{ isSignal: true, alias: "minChars", required: false }] }], freeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "freeText", required: false }] }], noResultsText: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsText", required: false }] }], loadingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingText", required: false }] }], separators: [{ type: i0.Input, args: [{ isSignal: true, alias: "separators", required: false }] }], allowDuplicates: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowDuplicates", required: false }] }], validate: [{ type: i0.Input, args: [{ isSignal: true, alias: "validate", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], maxItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxItems", required: false }] }], maxTagCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxTagCount", required: false }] }], panelTpl: [{ type: i0.ViewChild, args: ['panelTpl', { ...{ read: TemplateRef }, isSignal: true }] }], tagInputEl: [{ type: i0.ViewChild, args: ['tagInput', { isSignal: true }] }], searchInputEl: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }] } });
|
|
392
905
|
|
|
393
906
|
/**
|
|
394
907
|
* @license
|
|
@@ -396,10 +909,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImpor
|
|
|
396
909
|
* Use of this source code is governed by an MIT-style license that can be
|
|
397
910
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
398
911
|
*/
|
|
912
|
+
/**
|
|
913
|
+
* Visually groups options under a label inside a `<wr-select>`.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```html
|
|
917
|
+
* <wr-option-group label="Sizes">
|
|
918
|
+
* <wr-option value="sm">Small</wr-option>
|
|
919
|
+
* <wr-option value="md">Medium</wr-option>
|
|
920
|
+
* </wr-option-group>
|
|
921
|
+
* ```
|
|
922
|
+
*/
|
|
923
|
+
class WrOptionGroup {
|
|
924
|
+
/** Section heading shown above the options. */
|
|
925
|
+
label = input.required(/* @ts-ignore */
|
|
926
|
+
...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
927
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: WrOptionGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
928
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.1", type: WrOptionGroup, isStandalone: true, selector: "wr-option-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "group" }, classAttribute: "wr-option-group" }, ngImport: i0, template: "<div class=\"wr-option-group__label\">{{ label() }}</div>\n<ng-content />\n", encapsulation: i0.ViewEncapsulation.None });
|
|
929
|
+
}
|
|
930
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.1", ngImport: i0, type: WrOptionGroup, decorators: [{
|
|
931
|
+
type: Component,
|
|
932
|
+
args: [{ selector: 'wr-option-group', encapsulation: ViewEncapsulation.None, host: { class: 'wr-option-group', role: 'group' }, template: "<div class=\"wr-option-group__label\">{{ label() }}</div>\n<ng-content />\n" }]
|
|
933
|
+
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }] } });
|
|
399
934
|
|
|
400
935
|
/**
|
|
401
936
|
* Generated bundle index. Do not edit.
|
|
402
937
|
*/
|
|
403
938
|
|
|
404
|
-
export {
|
|
939
|
+
export { WR_SELECT, WrOption, WrOptionGroup, WrSelect };
|
|
405
940
|
//# sourceMappingURL=ngwr-select.mjs.map
|