@masmarino/gabarit 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -85
- package/accordion/README.md +56 -0
- package/alert/README.md +87 -0
- package/app-shell/README.md +133 -0
- package/auth/README.md +155 -0
- package/auth-activate/README.md +119 -0
- package/auth-login/README.md +113 -0
- package/auth-register/README.md +104 -0
- package/auth-reset-password/README.md +120 -0
- package/autocomplete/README.md +77 -0
- package/avatar/README.md +34 -0
- package/avatar-group/README.md +47 -0
- package/badge/README.md +177 -0
- package/bar-chart/README.md +44 -0
- package/breadcrumb/README.md +38 -0
- package/button/README.md +175 -0
- package/card/README.md +179 -0
- package/checkbox/README.md +50 -0
- package/checkbox-group/README.md +78 -0
- package/confirm-danger-modal/README.md +77 -0
- package/copy-button/README.md +90 -0
- package/copy-field/README.md +54 -0
- package/date-picker/README.md +84 -0
- package/description-list/README.md +63 -0
- package/dimension-card/README.md +39 -0
- package/disclosure/README.md +48 -0
- package/divider/README.md +31 -0
- package/drawer/README.md +49 -0
- package/empty-state/README.md +84 -0
- package/fesm2022/masmarino-gabarit-accordion.mjs +243 -0
- package/fesm2022/masmarino-gabarit-accordion.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-alert.mjs +208 -0
- package/fesm2022/masmarino-gabarit-alert.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-app-shell.mjs +378 -0
- package/fesm2022/masmarino-gabarit-app-shell.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-auth-activate.mjs +415 -0
- package/fesm2022/masmarino-gabarit-auth-activate.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-auth-login.mjs +467 -0
- package/fesm2022/masmarino-gabarit-auth-login.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-auth-register.mjs +457 -0
- package/fesm2022/masmarino-gabarit-auth-register.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-auth-reset-password.mjs +364 -0
- package/fesm2022/masmarino-gabarit-auth-reset-password.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-auth.mjs +844 -0
- package/fesm2022/masmarino-gabarit-auth.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-autocomplete.mjs +475 -0
- package/fesm2022/masmarino-gabarit-autocomplete.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-avatar-group.mjs +202 -0
- package/fesm2022/masmarino-gabarit-avatar-group.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-avatar.mjs +107 -0
- package/fesm2022/masmarino-gabarit-avatar.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-badge.mjs +449 -0
- package/fesm2022/masmarino-gabarit-badge.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-bar-chart.mjs +408 -0
- package/fesm2022/masmarino-gabarit-bar-chart.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-breadcrumb.mjs +59 -0
- package/fesm2022/masmarino-gabarit-breadcrumb.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-button.mjs +374 -0
- package/fesm2022/masmarino-gabarit-button.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-card.mjs +400 -0
- package/fesm2022/masmarino-gabarit-card.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-chart.mjs +1289 -0
- package/fesm2022/masmarino-gabarit-chart.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-checkbox-group.mjs +335 -0
- package/fesm2022/masmarino-gabarit-checkbox-group.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-checkbox.mjs +170 -0
- package/fesm2022/masmarino-gabarit-checkbox.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-confirm-danger-modal.mjs +387 -0
- package/fesm2022/masmarino-gabarit-confirm-danger-modal.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-copy-button.mjs +407 -0
- package/fesm2022/masmarino-gabarit-copy-button.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-copy-field.mjs +229 -0
- package/fesm2022/masmarino-gabarit-copy-field.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-date-picker.mjs +1242 -0
- package/fesm2022/masmarino-gabarit-date-picker.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-description-list.mjs +127 -0
- package/fesm2022/masmarino-gabarit-description-list.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-dimension-card.mjs +162 -0
- package/fesm2022/masmarino-gabarit-dimension-card.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-disclosure.mjs +154 -0
- package/fesm2022/masmarino-gabarit-disclosure.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-divider.mjs +90 -0
- package/fesm2022/masmarino-gabarit-divider.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-docs.mjs +16 -2
- package/fesm2022/masmarino-gabarit-docs.mjs.map +1 -1
- package/fesm2022/masmarino-gabarit-drawer.mjs +209 -0
- package/fesm2022/masmarino-gabarit-drawer.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-empty-state.mjs +226 -0
- package/fesm2022/masmarino-gabarit-empty-state.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-file-upload.mjs +335 -0
- package/fesm2022/masmarino-gabarit-file-upload.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-floating-panel.mjs +24 -0
- package/fesm2022/masmarino-gabarit-floating-panel.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-format.mjs +345 -0
- package/fesm2022/masmarino-gabarit-format.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-funnel-chart.mjs +247 -0
- package/fesm2022/masmarino-gabarit-funnel-chart.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-gauge-bar.mjs +180 -0
- package/fesm2022/masmarino-gabarit-gauge-bar.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-git-field.mjs +127 -0
- package/fesm2022/masmarino-gabarit-git-field.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-icon-marker.mjs +150 -0
- package/fesm2022/masmarino-gabarit-icon-marker.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-icon.mjs +308 -0
- package/fesm2022/masmarino-gabarit-icon.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-input.mjs +493 -0
- package/fesm2022/masmarino-gabarit-input.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-job-graph.mjs +216 -0
- package/fesm2022/masmarino-gabarit-job-graph.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-job-status.mjs +104 -0
- package/fesm2022/masmarino-gabarit-job-status.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-line-chart.mjs +574 -0
- package/fesm2022/masmarino-gabarit-line-chart.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-list-card.mjs +320 -0
- package/fesm2022/masmarino-gabarit-list-card.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-list-row.mjs +58 -0
- package/fesm2022/masmarino-gabarit-list-row.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-list-toolbar.mjs +369 -0
- package/fesm2022/masmarino-gabarit-list-toolbar.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-menu.mjs +464 -0
- package/fesm2022/masmarino-gabarit-menu.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-mfa-enrollment.mjs +897 -0
- package/fesm2022/masmarino-gabarit-mfa-enrollment.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-mfa-settings.mjs +629 -0
- package/fesm2022/masmarino-gabarit-mfa-settings.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-modal.mjs +260 -0
- package/fesm2022/masmarino-gabarit-modal.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-nav-tabs.mjs +332 -0
- package/fesm2022/masmarino-gabarit-nav-tabs.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-notification-dot.mjs +119 -0
- package/fesm2022/masmarino-gabarit-notification-dot.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-page-header.mjs +78 -0
- package/fesm2022/masmarino-gabarit-page-header.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-page-layout.mjs +157 -0
- package/fesm2022/masmarino-gabarit-page-layout.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-pagination.mjs +415 -0
- package/fesm2022/masmarino-gabarit-pagination.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-panel.mjs +80 -0
- package/fesm2022/masmarino-gabarit-panel.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-passkey-settings.mjs +606 -0
- package/fesm2022/masmarino-gabarit-passkey-settings.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-pie-chart.mjs +317 -0
- package/fesm2022/masmarino-gabarit-pie-chart.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-popover.mjs +142 -0
- package/fesm2022/masmarino-gabarit-popover.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-radio-group.mjs +202 -0
- package/fesm2022/masmarino-gabarit-radio-group.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-save-status.mjs +142 -0
- package/fesm2022/masmarino-gabarit-save-status.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-search-bar.mjs +576 -0
- package/fesm2022/masmarino-gabarit-search-bar.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-secret-reveal.mjs +348 -0
- package/fesm2022/masmarino-gabarit-secret-reveal.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-segmented-control.mjs +272 -0
- package/fesm2022/masmarino-gabarit-segmented-control.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-select.mjs +512 -0
- package/fesm2022/masmarino-gabarit-select.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-skeleton-list.mjs +189 -0
- package/fesm2022/masmarino-gabarit-skeleton-list.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-skeleton.mjs +109 -0
- package/fesm2022/masmarino-gabarit-skeleton.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-slider.mjs +239 -0
- package/fesm2022/masmarino-gabarit-slider.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-sparkline.mjs +276 -0
- package/fesm2022/masmarino-gabarit-sparkline.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-spinner.mjs +86 -0
- package/fesm2022/masmarino-gabarit-spinner.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-stat-grid.mjs +139 -0
- package/fesm2022/masmarino-gabarit-stat-grid.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-stat-tile.mjs +312 -0
- package/fesm2022/masmarino-gabarit-stat-tile.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-stepper.mjs +219 -0
- package/fesm2022/masmarino-gabarit-stepper.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-switch.mjs +151 -0
- package/fesm2022/masmarino-gabarit-switch.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-table.mjs +206 -0
- package/fesm2022/masmarino-gabarit-table.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-tabs.mjs +210 -0
- package/fesm2022/masmarino-gabarit-tabs.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-tag-input.mjs +288 -0
- package/fesm2022/masmarino-gabarit-tag-input.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-tag.mjs +155 -0
- package/fesm2022/masmarino-gabarit-tag.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-textarea.mjs +369 -0
- package/fesm2022/masmarino-gabarit-textarea.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-timeline-chart.mjs +521 -0
- package/fesm2022/masmarino-gabarit-timeline-chart.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-toaster.mjs +220 -0
- package/fesm2022/masmarino-gabarit-toaster.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-tooltip.mjs +185 -0
- package/fesm2022/masmarino-gabarit-tooltip.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-tree.mjs +258 -0
- package/fesm2022/masmarino-gabarit-tree.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit-user-chip.mjs +106 -0
- package/fesm2022/masmarino-gabarit-user-chip.mjs.map +1 -0
- package/fesm2022/masmarino-gabarit.mjs +83 -24785
- package/fesm2022/masmarino-gabarit.mjs.map +1 -1
- package/file-upload/README.md +47 -0
- package/funnel-chart/README.md +39 -0
- package/gauge-bar/README.md +35 -0
- package/git-field/README.md +34 -0
- package/icon/README.md +52 -0
- package/icon-marker/README.md +37 -0
- package/input/README.md +120 -0
- package/job-graph/README.md +76 -0
- package/job-status/README.md +34 -0
- package/line-chart/README.md +52 -0
- package/list-card/README.md +144 -0
- package/list-row/README.md +72 -0
- package/list-toolbar/README.md +52 -0
- package/menu/README.md +90 -0
- package/mfa-enrollment/README.md +189 -0
- package/mfa-settings/README.md +154 -0
- package/modal/README.md +72 -0
- package/nav-tabs/README.md +106 -0
- package/notification-dot/README.md +43 -0
- package/package.json +329 -1
- package/page-header/README.md +56 -0
- package/page-layout/README.md +76 -0
- package/pagination/README.md +73 -0
- package/panel/README.md +56 -0
- package/passkey-settings/README.md +120 -0
- package/pie-chart/README.md +85 -0
- package/popover/README.md +62 -0
- package/radio-group/README.md +47 -0
- package/save-status/README.md +44 -0
- package/search-bar/README.md +84 -0
- package/secret-reveal/README.md +60 -0
- package/segmented-control/README.md +79 -0
- package/select/README.md +61 -0
- package/skeleton/README.md +49 -0
- package/skeleton-list/README.md +40 -0
- package/slider/README.md +44 -0
- package/sparkline/README.md +37 -0
- package/spinner/README.md +41 -0
- package/stat-grid/README.md +47 -0
- package/stat-tile/README.md +75 -0
- package/stepper/README.md +67 -0
- package/switch/README.md +51 -0
- package/table/README.md +75 -0
- package/tabs/README.md +34 -0
- package/tag/README.md +34 -0
- package/tag-input/README.md +45 -0
- package/textarea/README.md +76 -0
- package/timeline-chart/README.md +49 -0
- package/toaster/README.md +92 -0
- package/tooltip/README.md +50 -0
- package/tree/README.md +79 -0
- package/types/masmarino-gabarit-accordion.d.ts +54 -0
- package/types/masmarino-gabarit-alert.d.ts +65 -0
- package/types/masmarino-gabarit-app-shell.d.ts +102 -0
- package/types/masmarino-gabarit-auth-activate.d.ts +70 -0
- package/types/masmarino-gabarit-auth-login.d.ts +63 -0
- package/types/masmarino-gabarit-auth-register.d.ts +66 -0
- package/types/masmarino-gabarit-auth-reset-password.d.ts +53 -0
- package/types/masmarino-gabarit-auth.d.ts +543 -0
- package/types/masmarino-gabarit-autocomplete.d.ts +140 -0
- package/types/masmarino-gabarit-avatar-group.d.ts +60 -0
- package/types/masmarino-gabarit-avatar.d.ts +31 -0
- package/types/masmarino-gabarit-badge.d.ts +139 -0
- package/types/masmarino-gabarit-bar-chart.d.ts +111 -0
- package/types/masmarino-gabarit-breadcrumb.d.ts +12 -0
- package/types/masmarino-gabarit-button.d.ts +108 -0
- package/types/masmarino-gabarit-card.d.ts +102 -0
- package/types/masmarino-gabarit-chart.d.ts +361 -0
- package/types/masmarino-gabarit-checkbox-group.d.ts +113 -0
- package/types/masmarino-gabarit-checkbox.d.ts +49 -0
- package/types/masmarino-gabarit-confirm-danger-modal.d.ts +94 -0
- package/types/masmarino-gabarit-copy-button.d.ts +111 -0
- package/types/masmarino-gabarit-copy-field.d.ts +64 -0
- package/types/masmarino-gabarit-date-picker.d.ts +399 -0
- package/types/masmarino-gabarit-description-list.d.ts +40 -0
- package/types/masmarino-gabarit-dimension-card.d.ts +55 -0
- package/types/masmarino-gabarit-disclosure.d.ts +44 -0
- package/types/masmarino-gabarit-divider.d.ts +20 -0
- package/types/masmarino-gabarit-docs.d.ts +2 -1
- package/types/masmarino-gabarit-drawer.d.ts +51 -0
- package/types/masmarino-gabarit-empty-state.d.ts +67 -0
- package/types/masmarino-gabarit-file-upload.d.ts +95 -0
- package/types/masmarino-gabarit-floating-panel.d.ts +14 -0
- package/types/masmarino-gabarit-format.d.ts +54 -0
- package/types/masmarino-gabarit-funnel-chart.d.ts +78 -0
- package/types/masmarino-gabarit-gauge-bar.d.ts +54 -0
- package/types/masmarino-gabarit-git-field.d.ts +39 -0
- package/types/masmarino-gabarit-icon-marker.d.ts +47 -0
- package/types/masmarino-gabarit-icon.d.ts +23 -0
- package/types/masmarino-gabarit-input.d.ts +181 -0
- package/types/masmarino-gabarit-job-graph.d.ts +63 -0
- package/types/masmarino-gabarit-job-status.d.ts +20 -0
- package/types/masmarino-gabarit-line-chart.d.ts +153 -0
- package/types/masmarino-gabarit-list-card.d.ts +87 -0
- package/types/masmarino-gabarit-list-row.d.ts +14 -0
- package/types/masmarino-gabarit-list-toolbar.d.ts +100 -0
- package/types/masmarino-gabarit-menu.d.ts +93 -0
- package/types/masmarino-gabarit-mfa-enrollment.d.ts +142 -0
- package/types/masmarino-gabarit-mfa-settings.d.ts +89 -0
- package/types/masmarino-gabarit-modal.d.ts +60 -0
- package/types/masmarino-gabarit-nav-tabs.d.ts +65 -0
- package/types/masmarino-gabarit-notification-dot.d.ts +34 -0
- package/types/masmarino-gabarit-page-header.d.ts +20 -0
- package/types/masmarino-gabarit-page-layout.d.ts +46 -0
- package/types/masmarino-gabarit-pagination.d.ts +109 -0
- package/types/masmarino-gabarit-panel.d.ts +21 -0
- package/types/masmarino-gabarit-passkey-settings.d.ts +94 -0
- package/types/masmarino-gabarit-pie-chart.d.ts +94 -0
- package/types/masmarino-gabarit-popover.d.ts +33 -0
- package/types/masmarino-gabarit-radio-group.d.ts +66 -0
- package/types/masmarino-gabarit-save-status.d.ts +39 -0
- package/types/masmarino-gabarit-search-bar.d.ts +183 -0
- package/types/masmarino-gabarit-secret-reveal.d.ts +95 -0
- package/types/masmarino-gabarit-segmented-control.d.ts +76 -0
- package/types/masmarino-gabarit-select.d.ts +146 -0
- package/types/masmarino-gabarit-skeleton-list.d.ts +54 -0
- package/types/masmarino-gabarit-skeleton.d.ts +26 -0
- package/types/masmarino-gabarit-slider.d.ts +73 -0
- package/types/masmarino-gabarit-sparkline.d.ts +70 -0
- package/types/masmarino-gabarit-spinner.d.ts +20 -0
- package/types/masmarino-gabarit-stat-grid.d.ts +39 -0
- package/types/masmarino-gabarit-stat-tile.d.ts +79 -0
- package/types/masmarino-gabarit-stepper.d.ts +67 -0
- package/types/masmarino-gabarit-switch.d.ts +42 -0
- package/types/masmarino-gabarit-table.d.ts +60 -0
- package/types/masmarino-gabarit-tabs.d.ts +40 -0
- package/types/masmarino-gabarit-tag-input.d.ts +78 -0
- package/types/masmarino-gabarit-tag.d.ts +35 -0
- package/types/masmarino-gabarit-textarea.d.ts +109 -0
- package/types/masmarino-gabarit-timeline-chart.d.ts +145 -0
- package/types/masmarino-gabarit-toaster.d.ts +62 -0
- package/types/masmarino-gabarit-tooltip.d.ts +39 -0
- package/types/masmarino-gabarit-tree.d.ts +71 -0
- package/types/masmarino-gabarit-user-chip.d.ts +26 -0
- package/types/masmarino-gabarit.d.ts +83 -6599
- package/user-chip/README.md +42 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"masmarino-gabarit-passkey-settings.mjs","names":[],"sources":["../../../projects/gabarit/passkey-settings/passkey-settings.ts","../../../projects/gabarit/passkey-settings/passkey-settings.html"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common'\nimport {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n untracked,\n} from '@angular/core'\nimport { FormsModule } from '@angular/forms'\nimport { EMPTY, catchError, forkJoin, from, of, switchMap } from 'rxjs'\nimport { Button } from '@masmarino/gabarit/button'\nimport { IconMarker } from '@masmarino/gabarit/icon-marker'\nimport { GbtInput } from '@masmarino/gabarit/input'\nimport { SaveStatus } from '@masmarino/gabarit/save-status'\nimport { Alert } from '@masmarino/gabarit/alert'\nimport { Card } from '@masmarino/gabarit/card'\nimport { EmptyState } from '@masmarino/gabarit/empty-state'\nimport { SkeletonList } from '@masmarino/gabarit/skeleton-list'\nimport { ConfirmDangerModal } from '@masmarino/gabarit/confirm-danger-modal'\nimport { GbtDateTimePipe, GbtRelativeTimePipe } from '@masmarino/gabarit/format'\nimport {\n DEFAULT_PASSKEY_SETTINGS_LABELS,\n type PasskeySettingsLabels,\n authLabels,\n} from '@masmarino/gabarit/auth'\nimport { AUTH_PORT } from '@masmarino/gabarit/auth'\nimport { MFA_PORT, type Passkey } from '@masmarino/gabarit/auth'\nimport { focusAfterRender } from '@masmarino/gabarit/auth'\nimport {\n classifyMfaFailure,\n classifyPasswordFailure,\n isTooManyPasskeys,\n} from '@masmarino/gabarit/auth'\nimport { MfaSettingsState } from '@masmarino/gabarit/auth'\nimport { PASSKEY_NAME_MAX, passkeyNameProblem } from '@masmarino/gabarit/auth'\nimport { isAuthPortError } from '@masmarino/gabarit/auth'\nimport {\n classifyPasskeyError,\n createPasskeyCredential,\n passkeysSupported,\n} from '@masmarino/gabarit/auth'\n\ntype View = 'loading' | 'failed' | 'ready' | 'revoked'\n\nlet nextId = 0\n\nconst ABSOLUTE_AFTER_DAYS = 30\nconst DAY = 86_400_000\n\n@Component({\n selector: 'gbt-passkey-settings',\n standalone: true,\n imports: [\n FormsModule,\n NgTemplateOutlet,\n Alert,\n EmptyState,\n Button,\n GbtInput,\n IconMarker,\n SaveStatus,\n SkeletonList,\n ConfirmDangerModal,\n Card,\n GbtRelativeTimePipe,\n GbtDateTimePipe,\n ],\n templateUrl: './passkey-settings.html',\n styleUrl: './passkey-settings.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PasskeySettings {\n private readonly mfa = inject(MFA_PORT)\n private readonly auth = inject(AUTH_PORT, { optional: true })\n private readonly state = inject(MfaSettingsState)\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef)\n private readonly injector = inject(Injector)\n\n labels = input<Partial<PasskeySettingsLabels>>({})\n locale = input<string | null>(null)\n sessionRevoked = output<void>()\n\n protected readonly text = authLabels(\n 'passkeySettings',\n DEFAULT_PASSKEY_SETTINGS_LABELS,\n this.labels,\n )\n protected readonly id = `gbt-passkey-settings-${nextId++}`\n protected readonly relativeOptions = computed(() => ({\n style: 'short' as const,\n maxUnit: 'day' as const,\n absoluteAfterDays: ABSOLUTE_AFTER_DAYS,\n locale: this.locale() ?? undefined,\n }))\n protected readonly dateOptions = computed(() => ({\n day: '2-digit' as const,\n month: '2-digit' as const,\n year: 'numeric' as const,\n hour: '2-digit' as const,\n minute: '2-digit' as const,\n locale: this.locale() ?? undefined,\n }))\n protected readonly absolute = (iso: string): boolean =>\n Math.abs(Date.now() - Date.parse(iso)) >= ABSOLUTE_AFTER_DAYS * DAY\n\n protected view = signal<View>('loading')\n protected passkeys = signal<Passkey[]>([])\n protected totpEnabled = signal(false)\n private serverAvailable = signal<boolean | null>(null)\n private readonly browserSupported = passkeysSupported()\n\n protected blockedReason = computed(() => {\n if (!this.browserSupported) {\n return this.text().browserBlocked\n }\n return this.serverAvailable() === false ? this.text().serverBlocked : null\n })\n\n protected result = signal<string | null>(null)\n\n protected adding = signal(false)\n protected name = signal('')\n protected nameError = signal<string | null>(null)\n protected password = signal('')\n protected passwordError = signal<string | null>(null)\n protected notice = signal('')\n protected noticeVariant = signal<'error' | 'info'>('error')\n protected busy = signal(false)\n protected promptOpen = signal(false)\n private ceremony = 0\n\n protected deleting = signal<Passkey | null>(null)\n protected deletePassword = signal('')\n protected deletePasswordError = signal<string | null>(null)\n protected deleteNotice = signal('')\n protected confirmingDelete = signal(false)\n protected deleteBusy = signal(false)\n\n protected count = computed(() =>\n this.view() === 'ready' && this.passkeys().length > 0 ? this.passkeys().length : null,\n )\n protected appBusy = this.state.appFlowActive\n protected lastFactor = computed(\n () => this.passkeys().length === 1 && !(this.state.totpEnabled() ?? this.totpEnabled()),\n )\n protected deleteMessage = computed(() =>\n this.text().deleteDialogMessage(this.deleting()?.name ?? '', this.lastFactor()),\n )\n\n constructor() {\n this.load()\n effect(() => {\n if (this.state.formOwner() === 'app') {\n untracked(() => {\n this.cancelAddQuietly()\n this.closeDelete()\n })\n }\n })\n inject(DestroyRef).onDestroy(() => {\n this.ceremony++\n this.password.set('')\n this.deletePassword.set('')\n })\n }\n\n protected load(): void {\n this.view.set('loading')\n const config = this.auth ? this.auth.authConfig().pipe(catchError(() => of(null))) : of(null)\n forkJoin([this.mfa.status(), config]).subscribe({\n next: ([status, config]) => {\n this.state.statusLoaded(status)\n this.passkeys.set(status.passkeys)\n this.totpEnabled.set(status.totpEnabled)\n this.serverAvailable.set(config ? config.passkeysAvailable === true : null)\n this.view.set('ready')\n },\n error: () => this.view.set('failed'),\n })\n }\n\n protected openAdd(): void {\n if (this.blockedReason() || this.appBusy()) {\n return\n }\n this.state.claimForm('passkeys')\n this.closeDelete()\n this.resetAdd()\n this.result.set(null)\n this.adding.set(true)\n this.focus(`#${this.id}-name`)\n }\n\n protected cancelAdd(): void {\n this.resetAdd()\n this.adding.set(false)\n this.focus('[data-opener=\"add\"] button')\n }\n\n protected setName(value: string): void {\n this.name.set(value)\n this.nameError.set(null)\n this.clearNotice()\n }\n\n protected setPassword(value: string): void {\n this.password.set(value)\n this.passwordError.set(null)\n this.clearNotice()\n }\n\n protected submitAdd(): void {\n if (this.busy()) {\n return\n }\n const text = this.text()\n const name = this.name().trim() || text.defaultPasskeyName\n const nameProblem = passkeyNameProblem(name)\n if (nameProblem) {\n this.nameError.set(\n nameProblem === 'too-long'\n ? text.nameTooLong(PASSKEY_NAME_MAX)\n : text.nameControlCharacters,\n )\n this.focus(`#${this.id}-name`)\n return\n }\n if (this.password() === '') {\n this.passwordError.set(text.enterPassword)\n this.focus(`#${this.id}-password`)\n return\n }\n this.clearNotice()\n this.busy.set(true)\n const attempt = ++this.ceremony\n this.mfa\n .startPasskeyRegistration(this.password())\n .pipe(\n switchMap((challenge) => {\n if (attempt !== this.ceremony) {\n return EMPTY\n }\n this.promptOpen.set(true)\n return from(createPasskeyCredential(challenge.publicKey)).pipe(\n switchMap((credential) =>\n attempt === this.ceremony\n ? this.mfa.finishPasskeyRegistration(challenge.challengeId, credential, name)\n : EMPTY,\n ),\n )\n }),\n )\n .subscribe({\n next: (passkey) => {\n this.state.passkeyAdded()\n if (attempt !== this.ceremony) {\n return\n }\n this.busy.set(false)\n this.promptOpen.set(false)\n this.resetAdd()\n this.adding.set(false)\n this.passkeys.update((list) => [...list, passkey])\n this.result.set(this.text().passkeyAdded(passkey.name))\n this.focus(`[data-passkey-id=\"${CSS.escape(passkey.id)}\"]`)\n },\n error: (err: unknown) => {\n if (attempt === this.ceremony) {\n this.addFailed(err)\n }\n },\n })\n }\n\n private addFailed(err: unknown): void {\n const text = this.text()\n this.busy.set(false)\n this.promptOpen.set(false)\n if (isAuthPortError(err)) {\n if (isTooManyPasskeys(err)) {\n return this.fail(text.tooManyPasskeys)\n }\n if (err.status === 409) {\n return this.fail(text.alreadyRegistered)\n }\n if (classifyMfaFailure(err) === 'unavailable') {\n return this.fail(text.passkeysUnavailable)\n }\n switch (classifyPasswordFailure(err)) {\n case 'wrong-password':\n this.passwordError.set(text.wrongPassword)\n this.focus(`#${this.id}-password`)\n return\n case 'rate-limited':\n return this.fail(text.tooManyAttempts)\n default:\n return this.fail(text.addFailed)\n }\n }\n switch (classifyPasskeyError(err)) {\n case 'cancelled':\n return this.fail(text.cancelled, 'info')\n case 'already-registered':\n return this.fail(text.alreadyRegistered)\n case 'unsupported':\n return this.fail(text.browserUnsupported)\n default:\n return this.fail(text.addFailed)\n }\n }\n\n private fail(message: string, variant: 'error' | 'info' = 'error'): void {\n this.noticeVariant.set(variant)\n this.notice.set(message)\n this.focus('.gbt-passkey-settings__submit button')\n }\n\n private clearNotice(): void {\n this.notice.set('')\n this.noticeVariant.set('error')\n }\n\n private resetAdd(): void {\n this.ceremony++\n this.name.set('')\n this.nameError.set(null)\n this.password.set('')\n this.passwordError.set(null)\n this.clearNotice()\n this.busy.set(false)\n this.promptOpen.set(false)\n }\n\n protected openDelete(passkey: Passkey): void {\n this.state.claimForm('passkeys')\n if (this.adding()) {\n this.cancelAddQuietly()\n }\n this.resetDelete()\n this.result.set(null)\n this.deleting.set(passkey)\n this.focus(`#${this.id}-delete-password`)\n }\n\n protected cancelDelete(): void {\n const target = this.deleting()\n this.closeDelete()\n if (target) {\n this.focus(`[data-passkey-id=\"${CSS.escape(target.id)}\"] [data-opener=\"delete\"] button`)\n }\n }\n\n protected setDeletePassword(value: string): void {\n this.deletePassword.set(value)\n this.deletePasswordError.set(null)\n this.deleteNotice.set('')\n }\n\n protected submitDelete(): void {\n if (this.deleteBusy() || !this.deleting()) {\n return\n }\n if (this.deletePassword() === '') {\n this.deletePasswordError.set(this.text().enterPassword)\n this.focus(`#${this.id}-delete-password`)\n return\n }\n this.deletePasswordError.set(null)\n this.deleteNotice.set('')\n this.confirmingDelete.set(true)\n }\n\n protected closeDeleteDialog(): void {\n if (!this.deleteBusy()) {\n this.confirmingDelete.set(false)\n this.focus(`#${this.id}-delete-password`)\n }\n }\n\n protected delete(): void {\n const target = this.deleting()\n if (this.deleteBusy() || !target) {\n return\n }\n this.deleteBusy.set(true)\n this.mfa.deletePasskey(target.id, this.deletePassword()).subscribe({\n next: () => {\n this.state.passkeyGone()\n this.deleteBusy.set(false)\n this.confirmingDelete.set(false)\n this.closeDelete()\n this.passkeys.update((list) => list.filter((passkey) => passkey.id !== target.id))\n this.result.set(null)\n this.view.set('revoked')\n this.focus('[data-passkeys-anchor]')\n this.sessionRevoked.emit()\n },\n error: (err: unknown) => this.deleteFailed(err, target),\n })\n }\n\n private deleteFailed(err: unknown, target: Passkey): void {\n this.deleteBusy.set(false)\n this.confirmingDelete.set(false)\n if (isAuthPortError(err) && err.status === 404) {\n this.closeDelete()\n this.passkeys.update((list) => list.filter((passkey) => passkey.id !== target.id))\n this.state.passkeyGone()\n this.result.set(this.text().passkeyGone(target.name))\n this.focus('[data-passkeys-anchor]')\n return\n }\n switch (classifyPasswordFailure(err)) {\n case 'wrong-password':\n this.deletePasswordError.set(this.text().wrongPassword)\n break\n case 'rate-limited':\n this.deleteNotice.set(this.text().tooManyAttempts)\n break\n default:\n this.deleteNotice.set(this.text().deleteFailed)\n }\n this.focus(`#${this.id}-delete-password`)\n }\n\n private closeDelete(): void {\n this.resetDelete()\n this.deleting.set(null)\n }\n\n private resetDelete(): void {\n this.deletePassword.set('')\n this.deletePasswordError.set(null)\n this.deleteNotice.set('')\n this.confirmingDelete.set(false)\n }\n\n private cancelAddQuietly(): void {\n this.resetAdd()\n this.adding.set(false)\n }\n\n private focus(selector: string): void {\n focusAfterRender(this.host, this.injector, selector)\n }\n}\n","<gbt-card\n variant=\"outlined\"\n icon=\"key\"\n [heading]=\"text().heading\"\n [description]=\"text().description\"\n [count]=\"count()\"\n>\n @switch (view()) {\n @case ('loading') {\n <gbt-skeleton-list\n [rows]=\"2\"\n leading=\"square\"\n leadingSize=\"2rem\"\n [padded]=\"false\"\n [loadingLabel]=\"text().loading\"\n />\n }\n\n @case ('failed') {\n <gbt-alert variant=\"error\" appearance=\"subtle\">\n {{ text().loadFailed }}\n <gbt-button\n alert-actions\n variant=\"secondary\"\n size=\"small\"\n [text]=\"text().retry\"\n (clicked)=\"load()\"\n />\n </gbt-alert>\n }\n\n @case ('revoked') {\n <div class=\"gbt-passkey-settings__anchor\" data-passkeys-anchor tabindex=\"-1\">\n <gbt-alert variant=\"info\" appearance=\"subtle\" iconAlign=\"start\" live=\"off\">{{\n text().signedOut\n }}</gbt-alert>\n </div>\n }\n\n @default {\n <div class=\"gbt-passkey-settings__stack\">\n @if (blockedReason(); as reason) {\n <gbt-alert variant=\"info\" appearance=\"subtle\" iconAlign=\"start\" live=\"off\">{{\n reason\n }}</gbt-alert>\n }\n\n <div class=\"gbt-passkey-settings__anchor\" data-passkeys-anchor tabindex=\"-1\">\n @if (passkeys().length === 0) {\n <gbt-empty-state\n size=\"compact\"\n icon=\"key\"\n [heading]=\"text().emptyHeading\"\n [message]=\"text().emptyMessage\"\n />\n } @else {\n <ul class=\"gbt-passkey-settings__rows\" [attr.aria-label]=\"text().listLabel\">\n @for (passkey of passkeys(); track passkey.id) {\n <li\n class=\"gbt-passkey-settings__row\"\n [attr.data-passkey-id]=\"passkey.id\"\n tabindex=\"-1\"\n >\n <div class=\"gbt-passkey-settings__row-head\">\n <gbt-icon-marker shape=\"tile\" icon=\"key\" />\n <div class=\"gbt-passkey-settings__row-text\">\n <p class=\"gbt-passkey-settings__name\" [title]=\"passkey.name\">\n {{ passkey.name }}\n </p>\n <p class=\"gbt-passkey-settings__meta\">\n <span\n >{{ text().added(absolute(passkey.createdAt)) }}\n <time\n [attr.datetime]=\"passkey.createdAt\"\n [title]=\"passkey.createdAt | gbtDateTime: dateOptions()\"\n >{{ passkey.createdAt | gbtRelativeTime: relativeOptions() }}</time\n ></span\n >\n <span\n class=\"gbt-passkey-settings__last-used\"\n [class.gbt-passkey-settings__last-used--never]=\"!passkey.lastUsedAt\"\n >\n @if (passkey.lastUsedAt; as lastUsed) {\n {{ text().lastUsed(absolute(lastUsed)) }}\n <time\n [attr.datetime]=\"lastUsed\"\n [title]=\"lastUsed | gbtDateTime: dateOptions()\"\n >{{ lastUsed | gbtRelativeTime: relativeOptions() }}</time\n >\n } @else {\n {{ text().neverUsed }}\n }\n </span>\n </p>\n </div>\n @if (deleting()?.id !== passkey.id) {\n <gbt-button\n class=\"gbt-passkey-settings__row-action\"\n data-opener=\"delete\"\n variant=\"secondary\"\n size=\"small\"\n iconName=\"trash-2\"\n [text]=\"text().delete\"\n [ariaLabel]=\"text().deleteKey(passkey.name)\"\n (clicked)=\"openDelete(passkey)\"\n />\n }\n </div>\n @if (deleting()?.id === passkey.id) {\n <ng-container [ngTemplateOutlet]=\"deletePrompt\" />\n }\n </li>\n }\n </ul>\n }\n </div>\n\n <gbt-save-status\n class=\"gbt-passkey-settings__result\"\n [class.sr-only]=\"!result()\"\n [state]=\"result() ? 'saved' : 'idle'\"\n [message]=\"result()\"\n />\n\n @if (adding()) {\n <ng-container [ngTemplateOutlet]=\"addForm\" />\n } @else {\n <div\n class=\"gbt-passkey-settings__actions\"\n [class.gbt-passkey-settings__actions--divided]=\"passkeys().length > 0\"\n [class.gbt-passkey-settings__actions--centered]=\"passkeys().length === 0\"\n >\n <gbt-button\n data-opener=\"add\"\n variant=\"secondary\"\n iconName=\"plus\"\n [text]=\"text().addPasskey\"\n [disabled]=\"!!blockedReason() || appBusy()\"\n (clicked)=\"openAdd()\"\n />\n @if (appBusy()) {\n <p class=\"gbt-passkey-settings__hint\">{{ text().finishAppFirst }}</p>\n }\n </div>\n }\n </div>\n }\n }\n</gbt-card>\n\n@if (confirmingDelete()) {\n <gbt-confirm-danger-modal\n [isOpen]=\"true\"\n [heading]=\"text().deleteDialogHeading\"\n [message]=\"deleteMessage()\"\n [confirmLabel]=\"text().deleteConfirm\"\n confirmIcon=\"trash-2\"\n [cancelLabel]=\"text().cancel\"\n [closeLabel]=\"text().close\"\n [busyLabel]=\"text().deleting\"\n [busy]=\"deleteBusy()\"\n (confirmed)=\"delete()\"\n (closed)=\"closeDeleteDialog()\"\n />\n}\n\n<ng-template #addForm>\n <form ngNoForm class=\"gbt-passkey-settings__form\" (submit)=\"$event.preventDefault(); submitAdd()\">\n <p class=\"gbt-passkey-settings__form-lead\">{{ text().addLead }}</p>\n\n @if (notice()) {\n <gbt-alert [variant]=\"noticeVariant()\" appearance=\"subtle\" iconAlign=\"start\">{{\n notice()\n }}</gbt-alert>\n }\n @if (promptOpen()) {\n <gbt-alert variant=\"info\" appearance=\"subtle\" iconAlign=\"start\" live=\"polite\">{{\n text().promptOpen\n }}</gbt-alert>\n }\n\n <div class=\"gbt-passkey-settings__fields\">\n <div class=\"gbt-passkey-settings__field\">\n <gbt-input\n [id]=\"id + '-name'\"\n name=\"passkeyName\"\n autocomplete=\"off\"\n [label]=\"text().nameLabel\"\n [placeholder]=\"text().defaultPasskeyName\"\n [errorMessage]=\"nameError()\"\n [ngModel]=\"name()\"\n (ngModelChange)=\"setName($event)\"\n />\n </div>\n <div class=\"gbt-passkey-settings__field\">\n <gbt-input\n [id]=\"id + '-password'\"\n name=\"currentPassword\"\n type=\"password\"\n autocomplete=\"current-password\"\n [label]=\"text().currentPassword\"\n [showPasswordLabel]=\"text().showPassword\"\n [hidePasswordLabel]=\"text().hidePassword\"\n [errorMessage]=\"passwordError()\"\n [ngModel]=\"password()\"\n (ngModelChange)=\"setPassword($event)\"\n />\n </div>\n </div>\n\n <div class=\"gbt-passkey-settings__buttons\">\n <gbt-button\n class=\"gbt-passkey-settings__submit\"\n type=\"submit\"\n iconName=\"key\"\n [text]=\"text().create\"\n [loading]=\"busy()\"\n [loadingLabel]=\"text().creating\"\n />\n <gbt-button variant=\"secondary\" [text]=\"text().cancel\" (clicked)=\"cancelAdd()\" />\n </div>\n </form>\n</ng-template>\n\n<ng-template #deletePrompt>\n <form\n ngNoForm\n class=\"gbt-passkey-settings__form\"\n (submit)=\"$event.preventDefault(); submitDelete()\"\n >\n <p class=\"gbt-passkey-settings__form-lead\">{{ text().deleteLead(deleting()?.name ?? '') }}</p>\n\n @if (lastFactor()) {\n <gbt-alert variant=\"warning\" appearance=\"subtle\" iconAlign=\"start\">{{\n text().lastFactorWarning\n }}</gbt-alert>\n }\n\n @if (deleteNotice()) {\n <gbt-alert variant=\"error\" appearance=\"subtle\" iconAlign=\"start\">{{\n deleteNotice()\n }}</gbt-alert>\n }\n\n <div class=\"gbt-passkey-settings__fields\">\n <div class=\"gbt-passkey-settings__field\">\n <gbt-input\n [id]=\"id + '-delete-password'\"\n name=\"currentPassword\"\n type=\"password\"\n autocomplete=\"current-password\"\n [label]=\"text().currentPassword\"\n [showPasswordLabel]=\"text().showPassword\"\n [hidePasswordLabel]=\"text().hidePassword\"\n [errorMessage]=\"deletePasswordError()\"\n [ngModel]=\"deletePassword()\"\n (ngModelChange)=\"setDeletePassword($event)\"\n />\n </div>\n </div>\n\n <div class=\"gbt-passkey-settings__buttons\">\n <gbt-button\n type=\"submit\"\n variant=\"secondary\"\n [text]=\"text().continue\"\n [loading]=\"deleteBusy()\"\n [loadingLabel]=\"text().checking\"\n />\n <gbt-button\n variant=\"secondary\"\n [text]=\"text().cancel\"\n [disabled]=\"deleteBusy()\"\n (clicked)=\"cancelDelete()\"\n />\n </div>\n </form>\n</ng-template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, computed, effect, input, isDevMode, signal } from "@angular/core";
|
|
3
|
+
import { ChartEmpty, ChartLegend, ChartTable, arcPath } from "@masmarino/gabarit/chart";
|
|
4
|
+
import { formatNumber, formatPercent } from "@masmarino/gabarit/format";
|
|
5
|
+
const OUTER_RADIUS = 90;
|
|
6
|
+
const LABEL_RADIUS = 104;
|
|
7
|
+
const LABEL_SHARE_THRESHOLD = .15;
|
|
8
|
+
const PALETTE_SIZE = 6;
|
|
9
|
+
var PieChart = class PieChart {
|
|
10
|
+
slices = input.required(...ngDevMode ? [{ debugName: "slices" }] : /* istanbul ignore next */ []);
|
|
11
|
+
label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
|
|
12
|
+
locale = input.required(...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
|
|
13
|
+
emptyMessage = input.required(...ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []);
|
|
14
|
+
tableCaption = input.required(...ngDevMode ? [{ debugName: "tableCaption" }] : /* istanbul ignore next */ []);
|
|
15
|
+
categoryColumn = input.required(...ngDevMode ? [{ debugName: "categoryColumn" }] : /* istanbul ignore next */ []);
|
|
16
|
+
valueColumn = input.required(...ngDevMode ? [{ debugName: "valueColumn" }] : /* istanbul ignore next */ []);
|
|
17
|
+
shareColumn = input.required(...ngDevMode ? [{ debugName: "shareColumn" }] : /* istanbul ignore next */ []);
|
|
18
|
+
sliceAnnouncement = input.required(...ngDevMode ? [{ debugName: "sliceAnnouncement" }] : /* istanbul ignore next */ []);
|
|
19
|
+
innerRadiusRatio = input(0, ...ngDevMode ? [{ debugName: "innerRadiusRatio" }] : /* istanbul ignore next */ []);
|
|
20
|
+
activeIndex = signal(null, ...ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []);
|
|
21
|
+
total = computed(() => this.slices().reduce((sum, slice) => sum + slice.value, 0), ...ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []);
|
|
22
|
+
renderedSlices = computed(() => {
|
|
23
|
+
const total = this.total();
|
|
24
|
+
const innerRadius = OUTER_RADIUS * this.innerRadiusRatio();
|
|
25
|
+
let angle = 0;
|
|
26
|
+
return this.slices().map((slice, index) => {
|
|
27
|
+
const share = total <= 0 ? 0 : slice.value / total;
|
|
28
|
+
const startAngle = angle;
|
|
29
|
+
const endAngle = angle + share * Math.PI * 2;
|
|
30
|
+
angle = endAngle;
|
|
31
|
+
const midAngle = (startAngle + endAngle) / 2;
|
|
32
|
+
const labelX = Math.round(LABEL_RADIUS * Math.sin(midAngle) * 100) / 100;
|
|
33
|
+
const labelY = Math.round(-104 * Math.cos(midAngle) * 100) / 100;
|
|
34
|
+
const formattedValue = formatNumber(slice.value, this.locale());
|
|
35
|
+
const formattedShare = formatPercent(share, this.locale());
|
|
36
|
+
return {
|
|
37
|
+
label: slice.label,
|
|
38
|
+
formattedValue,
|
|
39
|
+
formattedShare,
|
|
40
|
+
path: arcPath({
|
|
41
|
+
startAngle,
|
|
42
|
+
endAngle,
|
|
43
|
+
innerRadius,
|
|
44
|
+
outerRadius: OUTER_RADIUS
|
|
45
|
+
}),
|
|
46
|
+
color: this.colorFor(index),
|
|
47
|
+
showLabel: share >= LABEL_SHARE_THRESHOLD,
|
|
48
|
+
labelX,
|
|
49
|
+
labelY,
|
|
50
|
+
labelAnchor: labelX > 5 ? "start" : labelX < -5 ? "end" : "middle",
|
|
51
|
+
accessibleLabel: `${slice.label} — ${formattedValue}`
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}, ...ngDevMode ? [{ debugName: "renderedSlices" }] : /* istanbul ignore next */ []);
|
|
55
|
+
legendEntries = computed(() => this.renderedSlices().map((slice) => ({
|
|
56
|
+
label: slice.label,
|
|
57
|
+
value: slice.formattedValue,
|
|
58
|
+
color: slice.color
|
|
59
|
+
})), ...ngDevMode ? [{ debugName: "legendEntries" }] : /* istanbul ignore next */ []);
|
|
60
|
+
activeSlice = computed(() => {
|
|
61
|
+
const index = this.activeIndex();
|
|
62
|
+
if (index === null) return null;
|
|
63
|
+
return this.renderedSlices()[index] ?? null;
|
|
64
|
+
}, ...ngDevMode ? [{ debugName: "activeSlice" }] : /* istanbul ignore next */ []);
|
|
65
|
+
columns = computed(() => [
|
|
66
|
+
this.categoryColumn(),
|
|
67
|
+
this.valueColumn(),
|
|
68
|
+
this.shareColumn()
|
|
69
|
+
], ...ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []);
|
|
70
|
+
tableRows = computed(() => this.renderedSlices().map((slice) => [
|
|
71
|
+
slice.label,
|
|
72
|
+
slice.formattedValue,
|
|
73
|
+
slice.formattedShare
|
|
74
|
+
]), ...ngDevMode ? [{ debugName: "tableRows" }] : /* istanbul ignore next */ []);
|
|
75
|
+
colorFor(index) {
|
|
76
|
+
return `var(--chart-series-${index % PALETTE_SIZE + 1}-base)`;
|
|
77
|
+
}
|
|
78
|
+
onMouseLeave(event) {
|
|
79
|
+
const target = event.currentTarget;
|
|
80
|
+
if (target.ownerDocument.activeElement === target) return;
|
|
81
|
+
this.activeIndex.set(null);
|
|
82
|
+
}
|
|
83
|
+
constructor() {
|
|
84
|
+
if (isDevMode()) effect(() => {
|
|
85
|
+
const count = this.slices().length;
|
|
86
|
+
if (count > PALETTE_SIZE) console.warn(`gbt-pie-chart: ${count} slices received for ${PALETTE_SIZE} distinguishable colors. The palette cycles.`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
90
|
+
minVersion: "12.0.0",
|
|
91
|
+
version: "22.2.0",
|
|
92
|
+
ngImport: i0,
|
|
93
|
+
type: PieChart,
|
|
94
|
+
deps: [],
|
|
95
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
96
|
+
});
|
|
97
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
98
|
+
minVersion: "17.0.0",
|
|
99
|
+
version: "22.2.0",
|
|
100
|
+
type: PieChart,
|
|
101
|
+
isStandalone: true,
|
|
102
|
+
selector: "gbt-pie-chart",
|
|
103
|
+
inputs: {
|
|
104
|
+
slices: {
|
|
105
|
+
classPropertyName: "slices",
|
|
106
|
+
publicName: "slices",
|
|
107
|
+
isSignal: true,
|
|
108
|
+
isRequired: true,
|
|
109
|
+
transformFunction: null
|
|
110
|
+
},
|
|
111
|
+
label: {
|
|
112
|
+
classPropertyName: "label",
|
|
113
|
+
publicName: "label",
|
|
114
|
+
isSignal: true,
|
|
115
|
+
isRequired: true,
|
|
116
|
+
transformFunction: null
|
|
117
|
+
},
|
|
118
|
+
locale: {
|
|
119
|
+
classPropertyName: "locale",
|
|
120
|
+
publicName: "locale",
|
|
121
|
+
isSignal: true,
|
|
122
|
+
isRequired: true,
|
|
123
|
+
transformFunction: null
|
|
124
|
+
},
|
|
125
|
+
emptyMessage: {
|
|
126
|
+
classPropertyName: "emptyMessage",
|
|
127
|
+
publicName: "emptyMessage",
|
|
128
|
+
isSignal: true,
|
|
129
|
+
isRequired: true,
|
|
130
|
+
transformFunction: null
|
|
131
|
+
},
|
|
132
|
+
tableCaption: {
|
|
133
|
+
classPropertyName: "tableCaption",
|
|
134
|
+
publicName: "tableCaption",
|
|
135
|
+
isSignal: true,
|
|
136
|
+
isRequired: true,
|
|
137
|
+
transformFunction: null
|
|
138
|
+
},
|
|
139
|
+
categoryColumn: {
|
|
140
|
+
classPropertyName: "categoryColumn",
|
|
141
|
+
publicName: "categoryColumn",
|
|
142
|
+
isSignal: true,
|
|
143
|
+
isRequired: true,
|
|
144
|
+
transformFunction: null
|
|
145
|
+
},
|
|
146
|
+
valueColumn: {
|
|
147
|
+
classPropertyName: "valueColumn",
|
|
148
|
+
publicName: "valueColumn",
|
|
149
|
+
isSignal: true,
|
|
150
|
+
isRequired: true,
|
|
151
|
+
transformFunction: null
|
|
152
|
+
},
|
|
153
|
+
shareColumn: {
|
|
154
|
+
classPropertyName: "shareColumn",
|
|
155
|
+
publicName: "shareColumn",
|
|
156
|
+
isSignal: true,
|
|
157
|
+
isRequired: true,
|
|
158
|
+
transformFunction: null
|
|
159
|
+
},
|
|
160
|
+
sliceAnnouncement: {
|
|
161
|
+
classPropertyName: "sliceAnnouncement",
|
|
162
|
+
publicName: "sliceAnnouncement",
|
|
163
|
+
isSignal: true,
|
|
164
|
+
isRequired: true,
|
|
165
|
+
transformFunction: null
|
|
166
|
+
},
|
|
167
|
+
innerRadiusRatio: {
|
|
168
|
+
classPropertyName: "innerRadiusRatio",
|
|
169
|
+
publicName: "innerRadiusRatio",
|
|
170
|
+
isSignal: true,
|
|
171
|
+
isRequired: false,
|
|
172
|
+
transformFunction: null
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
ngImport: i0,
|
|
176
|
+
template: "@if (renderedSlices().length > 0) {\n <div class=\"gbt-pie-chart\">\n <svg\n class=\"gbt-pie-chart__svg\"\n viewBox=\"-100 -100 200 200\"\n role=\"group\"\n [attr.aria-label]=\"label()\"\n >\n @for (slice of renderedSlices(); track $index) {\n <path\n class=\"gbt-pie-chart__slice\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"slice.accessibleLabel\"\n [attr.data-active]=\"$index === activeIndex() ? '' : null\"\n [attr.d]=\"slice.path\"\n [attr.fill]=\"slice.color\"\n (mouseenter)=\"activeIndex.set($index)\"\n (mouseleave)=\"onMouseLeave($event)\"\n (focus)=\"activeIndex.set($index)\"\n (blur)=\"activeIndex.set(null)\"\n />\n }\n @for (slice of renderedSlices(); track $index) {\n @if (slice.showLabel) {\n <!-- prettier-ignore -->\n <text\n class=\"gbt-pie-chart__label\"\n aria-hidden=\"true\"\n [attr.x]=\"slice.labelX\"\n [attr.y]=\"slice.labelY\"\n [attr.text-anchor]=\"slice.labelAnchor\"\n >{{ slice.formattedShare }}</text\n >\n }\n }\n </svg>\n <gbt-chart-legend\n [entries]=\"legendEntries()\"\n interactive\n [activeIndex]=\"activeIndex()\"\n (activeIndexChange)=\"activeIndex.set($event)\"\n />\n <div class=\"gbt-sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n @if (activeSlice(); as slice) {\n {{ sliceAnnouncement()(slice.label, slice.formattedValue, slice.formattedShare) }}\n }\n </div>\n <gbt-chart-table [caption]=\"tableCaption()\" [columns]=\"columns()\" [rows]=\"tableRows()\" />\n </div>\n} @else {\n <gbt-chart-empty [message]=\"emptyMessage()\">\n <svg\n gbtChartEmptyIcon\n viewBox=\"0 0 96 96\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"48\" cy=\"48\" r=\"30\" />\n <path\n d=\"M48 48 L48 18 A30 30 0 0 1 74 63 Z\"\n fill=\"currentColor\"\n stroke=\"none\"\n opacity=\"0.85\"\n />\n </svg>\n </gbt-chart-empty>\n}\n",
|
|
177
|
+
styles: [":host{display:block}.gbt-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.gbt-pie-chart{display:flex;flex-direction:column;align-items:center;gap:1rem}.gbt-pie-chart__svg{width:100%;max-width:280px;height:auto;overflow:visible}.gbt-pie-chart__slice{stroke:var(--bg-principal);stroke-width:1.5;transition:opacity var(--site-transition-fast)}.gbt-pie-chart__slice:hover,.gbt-pie-chart__slice[data-active]{opacity:.85}.gbt-pie-chart__slice:focus-visible{outline:none;stroke:var(--primary);stroke-width:3}.gbt-pie-chart__label{fill:var(--text-secondary);font-size:9px;font-variant-numeric:tabular-nums;dominant-baseline:middle}\n"],
|
|
178
|
+
dependencies: [
|
|
179
|
+
{
|
|
180
|
+
kind: "component",
|
|
181
|
+
type: ChartTable,
|
|
182
|
+
selector: "gbt-chart-table",
|
|
183
|
+
inputs: [
|
|
184
|
+
"caption",
|
|
185
|
+
"columns",
|
|
186
|
+
"rows"
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
kind: "component",
|
|
191
|
+
type: ChartEmpty,
|
|
192
|
+
selector: "gbt-chart-empty",
|
|
193
|
+
inputs: ["message", "actionLabel"],
|
|
194
|
+
outputs: ["action"]
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
kind: "component",
|
|
198
|
+
type: ChartLegend,
|
|
199
|
+
selector: "gbt-chart-legend",
|
|
200
|
+
inputs: [
|
|
201
|
+
"entries",
|
|
202
|
+
"interactive",
|
|
203
|
+
"activeIndex"
|
|
204
|
+
],
|
|
205
|
+
outputs: ["activeIndexChange"]
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
209
|
+
});
|
|
210
|
+
};
|
|
211
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
212
|
+
minVersion: "12.0.0",
|
|
213
|
+
version: "22.2.0",
|
|
214
|
+
ngImport: i0,
|
|
215
|
+
type: PieChart,
|
|
216
|
+
decorators: [{
|
|
217
|
+
type: Component,
|
|
218
|
+
args: [{
|
|
219
|
+
selector: "gbt-pie-chart",
|
|
220
|
+
standalone: true,
|
|
221
|
+
imports: [
|
|
222
|
+
ChartTable,
|
|
223
|
+
ChartEmpty,
|
|
224
|
+
ChartLegend
|
|
225
|
+
],
|
|
226
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
227
|
+
template: "@if (renderedSlices().length > 0) {\n <div class=\"gbt-pie-chart\">\n <svg\n class=\"gbt-pie-chart__svg\"\n viewBox=\"-100 -100 200 200\"\n role=\"group\"\n [attr.aria-label]=\"label()\"\n >\n @for (slice of renderedSlices(); track $index) {\n <path\n class=\"gbt-pie-chart__slice\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"slice.accessibleLabel\"\n [attr.data-active]=\"$index === activeIndex() ? '' : null\"\n [attr.d]=\"slice.path\"\n [attr.fill]=\"slice.color\"\n (mouseenter)=\"activeIndex.set($index)\"\n (mouseleave)=\"onMouseLeave($event)\"\n (focus)=\"activeIndex.set($index)\"\n (blur)=\"activeIndex.set(null)\"\n />\n }\n @for (slice of renderedSlices(); track $index) {\n @if (slice.showLabel) {\n <!-- prettier-ignore -->\n <text\n class=\"gbt-pie-chart__label\"\n aria-hidden=\"true\"\n [attr.x]=\"slice.labelX\"\n [attr.y]=\"slice.labelY\"\n [attr.text-anchor]=\"slice.labelAnchor\"\n >{{ slice.formattedShare }}</text\n >\n }\n }\n </svg>\n <gbt-chart-legend\n [entries]=\"legendEntries()\"\n interactive\n [activeIndex]=\"activeIndex()\"\n (activeIndexChange)=\"activeIndex.set($event)\"\n />\n <div class=\"gbt-sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n @if (activeSlice(); as slice) {\n {{ sliceAnnouncement()(slice.label, slice.formattedValue, slice.formattedShare) }}\n }\n </div>\n <gbt-chart-table [caption]=\"tableCaption()\" [columns]=\"columns()\" [rows]=\"tableRows()\" />\n </div>\n} @else {\n <gbt-chart-empty [message]=\"emptyMessage()\">\n <svg\n gbtChartEmptyIcon\n viewBox=\"0 0 96 96\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"48\" cy=\"48\" r=\"30\" />\n <path\n d=\"M48 48 L48 18 A30 30 0 0 1 74 63 Z\"\n fill=\"currentColor\"\n stroke=\"none\"\n opacity=\"0.85\"\n />\n </svg>\n </gbt-chart-empty>\n}\n",
|
|
228
|
+
styles: [":host{display:block}.gbt-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.gbt-pie-chart{display:flex;flex-direction:column;align-items:center;gap:1rem}.gbt-pie-chart__svg{width:100%;max-width:280px;height:auto;overflow:visible}.gbt-pie-chart__slice{stroke:var(--bg-principal);stroke-width:1.5;transition:opacity var(--site-transition-fast)}.gbt-pie-chart__slice:hover,.gbt-pie-chart__slice[data-active]{opacity:.85}.gbt-pie-chart__slice:focus-visible{outline:none;stroke:var(--primary);stroke-width:3}.gbt-pie-chart__label{fill:var(--text-secondary);font-size:9px;font-variant-numeric:tabular-nums;dominant-baseline:middle}\n"]
|
|
229
|
+
}]
|
|
230
|
+
}],
|
|
231
|
+
ctorParameters: () => [],
|
|
232
|
+
propDecorators: {
|
|
233
|
+
slices: [{
|
|
234
|
+
type: i0.Input,
|
|
235
|
+
args: [{
|
|
236
|
+
isSignal: true,
|
|
237
|
+
alias: "slices",
|
|
238
|
+
required: true
|
|
239
|
+
}]
|
|
240
|
+
}],
|
|
241
|
+
label: [{
|
|
242
|
+
type: i0.Input,
|
|
243
|
+
args: [{
|
|
244
|
+
isSignal: true,
|
|
245
|
+
alias: "label",
|
|
246
|
+
required: true
|
|
247
|
+
}]
|
|
248
|
+
}],
|
|
249
|
+
locale: [{
|
|
250
|
+
type: i0.Input,
|
|
251
|
+
args: [{
|
|
252
|
+
isSignal: true,
|
|
253
|
+
alias: "locale",
|
|
254
|
+
required: true
|
|
255
|
+
}]
|
|
256
|
+
}],
|
|
257
|
+
emptyMessage: [{
|
|
258
|
+
type: i0.Input,
|
|
259
|
+
args: [{
|
|
260
|
+
isSignal: true,
|
|
261
|
+
alias: "emptyMessage",
|
|
262
|
+
required: true
|
|
263
|
+
}]
|
|
264
|
+
}],
|
|
265
|
+
tableCaption: [{
|
|
266
|
+
type: i0.Input,
|
|
267
|
+
args: [{
|
|
268
|
+
isSignal: true,
|
|
269
|
+
alias: "tableCaption",
|
|
270
|
+
required: true
|
|
271
|
+
}]
|
|
272
|
+
}],
|
|
273
|
+
categoryColumn: [{
|
|
274
|
+
type: i0.Input,
|
|
275
|
+
args: [{
|
|
276
|
+
isSignal: true,
|
|
277
|
+
alias: "categoryColumn",
|
|
278
|
+
required: true
|
|
279
|
+
}]
|
|
280
|
+
}],
|
|
281
|
+
valueColumn: [{
|
|
282
|
+
type: i0.Input,
|
|
283
|
+
args: [{
|
|
284
|
+
isSignal: true,
|
|
285
|
+
alias: "valueColumn",
|
|
286
|
+
required: true
|
|
287
|
+
}]
|
|
288
|
+
}],
|
|
289
|
+
shareColumn: [{
|
|
290
|
+
type: i0.Input,
|
|
291
|
+
args: [{
|
|
292
|
+
isSignal: true,
|
|
293
|
+
alias: "shareColumn",
|
|
294
|
+
required: true
|
|
295
|
+
}]
|
|
296
|
+
}],
|
|
297
|
+
sliceAnnouncement: [{
|
|
298
|
+
type: i0.Input,
|
|
299
|
+
args: [{
|
|
300
|
+
isSignal: true,
|
|
301
|
+
alias: "sliceAnnouncement",
|
|
302
|
+
required: true
|
|
303
|
+
}]
|
|
304
|
+
}],
|
|
305
|
+
innerRadiusRatio: [{
|
|
306
|
+
type: i0.Input,
|
|
307
|
+
args: [{
|
|
308
|
+
isSignal: true,
|
|
309
|
+
alias: "innerRadiusRatio",
|
|
310
|
+
required: false
|
|
311
|
+
}]
|
|
312
|
+
}]
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
export { PieChart };
|
|
316
|
+
|
|
317
|
+
//# sourceMappingURL=masmarino-gabarit-pie-chart.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"masmarino-gabarit-pie-chart.mjs","names":[],"sources":["../../../projects/gabarit/pie-chart/pie-chart.ts","../../../projects/gabarit/pie-chart/pie-chart.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n isDevMode,\n input,\n signal,\n} from '@angular/core'\nimport { ChartEmpty } from '@masmarino/gabarit/chart'\nimport { ChartLegend, type LegendEntry } from '@masmarino/gabarit/chart'\nimport { ChartTable } from '@masmarino/gabarit/chart'\nimport { arcPath } from '@masmarino/gabarit/chart'\nimport { formatNumber, formatPercent } from '@masmarino/gabarit/format'\n\nexport interface PieSlice {\n label: string\n value: number\n}\n\ninterface RenderedSlice {\n label: string\n formattedValue: string\n formattedShare: string\n path: string\n color: string\n showLabel: boolean\n labelX: number\n labelY: number\n labelAnchor: 'start' | 'middle' | 'end'\n accessibleLabel: string\n}\n\nconst OUTER_RADIUS = 90\nconst LABEL_RADIUS = OUTER_RADIUS + 14\nconst LABEL_SHARE_THRESHOLD = 0.15\nconst PALETTE_SIZE = 6\n\n@Component({\n selector: 'gbt-pie-chart',\n standalone: true,\n imports: [ChartTable, ChartEmpty, ChartLegend],\n templateUrl: './pie-chart.html',\n styleUrl: './pie-chart.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class PieChart {\n slices = input.required<PieSlice[]>()\n label = input.required<string>()\n locale = input.required<string>()\n emptyMessage = input.required<string>()\n tableCaption = input.required<string>()\n categoryColumn = input.required<string>()\n valueColumn = input.required<string>()\n shareColumn = input.required<string>()\n sliceAnnouncement = input.required<(label: string, value: string, share: string) => string>()\n\n innerRadiusRatio = input<number>(0)\n\n protected readonly activeIndex = signal<number | null>(null)\n\n private readonly total = computed(() =>\n this.slices().reduce((sum, slice) => sum + slice.value, 0),\n )\n\n protected readonly renderedSlices = computed<RenderedSlice[]>(() => {\n const total = this.total()\n const innerRadius = OUTER_RADIUS * this.innerRadiusRatio()\n let angle = 0\n return this.slices().map((slice, index) => {\n const share = total <= 0 ? 0 : slice.value / total\n const startAngle = angle\n const endAngle = angle + share * Math.PI * 2\n angle = endAngle\n\n const midAngle = (startAngle + endAngle) / 2\n const labelX = Math.round(LABEL_RADIUS * Math.sin(midAngle) * 100) / 100\n const labelY = Math.round(-LABEL_RADIUS * Math.cos(midAngle) * 100) / 100\n\n const formattedValue = formatNumber(slice.value, this.locale())\n const formattedShare = formatPercent(share, this.locale())\n\n return {\n label: slice.label,\n formattedValue,\n formattedShare,\n path: arcPath({ startAngle, endAngle, innerRadius, outerRadius: OUTER_RADIUS }),\n color: this.colorFor(index),\n showLabel: share >= LABEL_SHARE_THRESHOLD,\n labelX,\n labelY,\n labelAnchor: labelX > 5 ? 'start' : labelX < -5 ? 'end' : 'middle',\n accessibleLabel: `${slice.label} — ${formattedValue}`,\n }\n })\n })\n\n protected readonly legendEntries = computed<LegendEntry[]>(() =>\n this.renderedSlices().map((slice) => ({\n label: slice.label,\n value: slice.formattedValue,\n color: slice.color,\n })),\n )\n\n protected readonly activeSlice = computed<RenderedSlice | null>(() => {\n const index = this.activeIndex()\n if (index === null) return null\n return this.renderedSlices()[index] ?? null\n })\n\n protected readonly columns = computed(() => [\n this.categoryColumn(),\n this.valueColumn(),\n this.shareColumn(),\n ])\n\n protected readonly tableRows = computed<(string | number)[][]>(() =>\n this.renderedSlices().map((slice) => [slice.label, slice.formattedValue, slice.formattedShare]),\n )\n\n private colorFor(index: number): string {\n return `var(--chart-series-${(index % PALETTE_SIZE) + 1}-base)`\n }\n\n protected onMouseLeave(event: MouseEvent): void {\n const target = event.currentTarget as HTMLElement\n if (target.ownerDocument.activeElement === target) return\n this.activeIndex.set(null)\n }\n\n constructor() {\n if (isDevMode()) {\n effect(() => {\n const count = this.slices().length\n if (count > PALETTE_SIZE) {\n console.warn(\n `gbt-pie-chart: ${count} slices received for ${PALETTE_SIZE} distinguishable colors. The palette cycles.`,\n )\n }\n })\n }\n }\n}\n","@if (renderedSlices().length > 0) {\n <div class=\"gbt-pie-chart\">\n <svg\n class=\"gbt-pie-chart__svg\"\n viewBox=\"-100 -100 200 200\"\n role=\"group\"\n [attr.aria-label]=\"label()\"\n >\n @for (slice of renderedSlices(); track $index) {\n <path\n class=\"gbt-pie-chart__slice\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"slice.accessibleLabel\"\n [attr.data-active]=\"$index === activeIndex() ? '' : null\"\n [attr.d]=\"slice.path\"\n [attr.fill]=\"slice.color\"\n (mouseenter)=\"activeIndex.set($index)\"\n (mouseleave)=\"onMouseLeave($event)\"\n (focus)=\"activeIndex.set($index)\"\n (blur)=\"activeIndex.set(null)\"\n />\n }\n @for (slice of renderedSlices(); track $index) {\n @if (slice.showLabel) {\n <!-- prettier-ignore -->\n <text\n class=\"gbt-pie-chart__label\"\n aria-hidden=\"true\"\n [attr.x]=\"slice.labelX\"\n [attr.y]=\"slice.labelY\"\n [attr.text-anchor]=\"slice.labelAnchor\"\n >{{ slice.formattedShare }}</text\n >\n }\n }\n </svg>\n <gbt-chart-legend\n [entries]=\"legendEntries()\"\n interactive\n [activeIndex]=\"activeIndex()\"\n (activeIndexChange)=\"activeIndex.set($event)\"\n />\n <div class=\"gbt-sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n @if (activeSlice(); as slice) {\n {{ sliceAnnouncement()(slice.label, slice.formattedValue, slice.formattedShare) }}\n }\n </div>\n <gbt-chart-table [caption]=\"tableCaption()\" [columns]=\"columns()\" [rows]=\"tableRows()\" />\n </div>\n} @else {\n <gbt-chart-empty [message]=\"emptyMessage()\">\n <svg\n gbtChartEmptyIcon\n viewBox=\"0 0 96 96\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <circle cx=\"48\" cy=\"48\" r=\"30\" />\n <path\n d=\"M48 48 L48 18 A30 30 0 0 1 74 63 Z\"\n fill=\"currentColor\"\n stroke=\"none\"\n opacity=\"0.85\"\n />\n </svg>\n </gbt-chart-empty>\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, Component, ElementRef, inject, input, signal, viewChild } from "@angular/core";
|
|
3
|
+
import { followPageScroll } from "@masmarino/gabarit/floating-panel";
|
|
4
|
+
let nextPopoverId = 0;
|
|
5
|
+
var Popover = class Popover {
|
|
6
|
+
elementRef = inject(ElementRef);
|
|
7
|
+
triggerSlot = viewChild("triggerSlot", ...ngDevMode ? [{ debugName: "triggerSlot" }] : /* istanbul ignore next */ []);
|
|
8
|
+
align = input("start", ...ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []);
|
|
9
|
+
panelId = `gbt-popover-${++nextPopoverId}`;
|
|
10
|
+
isOpen = signal(false, ...ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []);
|
|
11
|
+
open = this.isOpen.asReadonly();
|
|
12
|
+
position = signal(null, ...ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []);
|
|
13
|
+
toggle() {
|
|
14
|
+
this.isOpen.update((value) => !value);
|
|
15
|
+
if (this.isOpen()) this.updatePosition();
|
|
16
|
+
}
|
|
17
|
+
close(returnFocus = false) {
|
|
18
|
+
if (!this.isOpen()) return;
|
|
19
|
+
this.isOpen.set(false);
|
|
20
|
+
if (returnFocus) this.focusTrigger();
|
|
21
|
+
}
|
|
22
|
+
onTriggerClick(event) {
|
|
23
|
+
if ((this.triggerSlot()?.nativeElement)?.contains(event.target)) this.toggle();
|
|
24
|
+
}
|
|
25
|
+
constructor() {
|
|
26
|
+
followPageScroll(() => this.updatePosition());
|
|
27
|
+
}
|
|
28
|
+
updatePosition() {
|
|
29
|
+
if (!this.isOpen()) return;
|
|
30
|
+
const trigger = this.triggerSlot()?.nativeElement;
|
|
31
|
+
if (!trigger) return;
|
|
32
|
+
const rect = trigger.getBoundingClientRect();
|
|
33
|
+
this.position.set(this.align() === "end" ? {
|
|
34
|
+
top: `${rect.bottom + 6}px`,
|
|
35
|
+
left: null,
|
|
36
|
+
right: `${window.innerWidth - rect.right}px`
|
|
37
|
+
} : {
|
|
38
|
+
top: `${rect.bottom + 6}px`,
|
|
39
|
+
left: `${rect.left}px`,
|
|
40
|
+
right: null
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
handleClickOutside(event) {
|
|
44
|
+
if (this.isOpen() && !this.elementRef.nativeElement.contains(event.target)) this.close(false);
|
|
45
|
+
}
|
|
46
|
+
onKeydown(event) {
|
|
47
|
+
if (event.key === "Escape" && this.isOpen()) {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
event.stopPropagation();
|
|
50
|
+
this.close(true);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
focusTrigger() {
|
|
54
|
+
(this.triggerSlot()?.nativeElement)?.querySelector("button, a[href], input, select, textarea, [tabindex]")?.focus();
|
|
55
|
+
}
|
|
56
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
57
|
+
minVersion: "12.0.0",
|
|
58
|
+
version: "22.2.0",
|
|
59
|
+
ngImport: i0,
|
|
60
|
+
type: Popover,
|
|
61
|
+
deps: [],
|
|
62
|
+
target: i0.ɵɵFactoryTarget.Component
|
|
63
|
+
});
|
|
64
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({
|
|
65
|
+
minVersion: "17.0.0",
|
|
66
|
+
version: "22.2.0",
|
|
67
|
+
type: Popover,
|
|
68
|
+
isStandalone: true,
|
|
69
|
+
selector: "gbt-popover",
|
|
70
|
+
inputs: { align: {
|
|
71
|
+
classPropertyName: "align",
|
|
72
|
+
publicName: "align",
|
|
73
|
+
isSignal: true,
|
|
74
|
+
isRequired: false,
|
|
75
|
+
transformFunction: null
|
|
76
|
+
} },
|
|
77
|
+
host: {
|
|
78
|
+
listeners: {
|
|
79
|
+
"click": "onTriggerClick($event)",
|
|
80
|
+
"document:click": "handleClickOutside($event)",
|
|
81
|
+
"keydown": "onKeydown($event)",
|
|
82
|
+
"window:resize": "updatePosition()"
|
|
83
|
+
},
|
|
84
|
+
classAttribute: "gbt-popover-host"
|
|
85
|
+
},
|
|
86
|
+
viewQueries: [{
|
|
87
|
+
propertyName: "triggerSlot",
|
|
88
|
+
first: true,
|
|
89
|
+
predicate: ["triggerSlot"],
|
|
90
|
+
descendants: true,
|
|
91
|
+
isSignal: true
|
|
92
|
+
}],
|
|
93
|
+
exportAs: ["gbtPopover"],
|
|
94
|
+
ngImport: i0,
|
|
95
|
+
template: "<span #triggerSlot class=\"gbt-popover__trigger\">\n <ng-content></ng-content>\n</span>\n@if (open() && position(); as pos) {\n <div\n class=\"gbt-popover__panel\"\n [id]=\"panelId\"\n [style.top]=\"pos.top\"\n [style.left]=\"pos.left\"\n [style.right]=\"pos.right\"\n >\n <ng-content select=\"[popover-content]\"></ng-content>\n </div>\n}\n",
|
|
96
|
+
styles: [":host{position:relative;display:inline-block}.gbt-popover__trigger{display:inline-block;cursor:pointer}.gbt-popover__panel{box-sizing:border-box;position:fixed;z-index:1000;min-width:200px;padding:1rem;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);box-shadow:var(--site-shadow-lg);color:var(--text-primary);animation:gbt-popover-scale-in .15s cubic-bezier(.34,1.56,.64,1) both}@keyframes gbt-popover-scale-in{0%{opacity:0;transform:scale(.97) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(prefers-reduced-motion:reduce){.gbt-popover__panel{animation:none}}\n"],
|
|
97
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
101
|
+
minVersion: "12.0.0",
|
|
102
|
+
version: "22.2.0",
|
|
103
|
+
ngImport: i0,
|
|
104
|
+
type: Popover,
|
|
105
|
+
decorators: [{
|
|
106
|
+
type: Component,
|
|
107
|
+
args: [{
|
|
108
|
+
selector: "gbt-popover",
|
|
109
|
+
standalone: true,
|
|
110
|
+
exportAs: "gbtPopover",
|
|
111
|
+
imports: [],
|
|
112
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
113
|
+
host: {
|
|
114
|
+
class: "gbt-popover-host",
|
|
115
|
+
"(click)": "onTriggerClick($event)",
|
|
116
|
+
"(document:click)": "handleClickOutside($event)",
|
|
117
|
+
"(keydown)": "onKeydown($event)",
|
|
118
|
+
"(window:resize)": "updatePosition()"
|
|
119
|
+
},
|
|
120
|
+
template: "<span #triggerSlot class=\"gbt-popover__trigger\">\n <ng-content></ng-content>\n</span>\n@if (open() && position(); as pos) {\n <div\n class=\"gbt-popover__panel\"\n [id]=\"panelId\"\n [style.top]=\"pos.top\"\n [style.left]=\"pos.left\"\n [style.right]=\"pos.right\"\n >\n <ng-content select=\"[popover-content]\"></ng-content>\n </div>\n}\n",
|
|
121
|
+
styles: [":host{position:relative;display:inline-block}.gbt-popover__trigger{display:inline-block;cursor:pointer}.gbt-popover__panel{box-sizing:border-box;position:fixed;z-index:1000;min-width:200px;padding:1rem;background:var(--bg-principal);border:1px solid var(--border-color);border-radius:var(--site-border-radius-sm);box-shadow:var(--site-shadow-lg);color:var(--text-primary);animation:gbt-popover-scale-in .15s cubic-bezier(.34,1.56,.64,1) both}@keyframes gbt-popover-scale-in{0%{opacity:0;transform:scale(.97) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(prefers-reduced-motion:reduce){.gbt-popover__panel{animation:none}}\n"]
|
|
122
|
+
}]
|
|
123
|
+
}],
|
|
124
|
+
ctorParameters: () => [],
|
|
125
|
+
propDecorators: {
|
|
126
|
+
triggerSlot: [{
|
|
127
|
+
type: i0.ViewChild,
|
|
128
|
+
args: ["triggerSlot", { isSignal: true }]
|
|
129
|
+
}],
|
|
130
|
+
align: [{
|
|
131
|
+
type: i0.Input,
|
|
132
|
+
args: [{
|
|
133
|
+
isSignal: true,
|
|
134
|
+
alias: "align",
|
|
135
|
+
required: false
|
|
136
|
+
}]
|
|
137
|
+
}]
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
export { Popover };
|
|
141
|
+
|
|
142
|
+
//# sourceMappingURL=masmarino-gabarit-popover.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"masmarino-gabarit-popover.mjs","names":[],"sources":["../../../projects/gabarit/popover/popover.ts","../../../projects/gabarit/popover/popover.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n inject,\n input,\n signal,\n viewChild,\n} from '@angular/core'\nimport { followPageScroll } from '@masmarino/gabarit/floating-panel'\n\nexport type PopoverAlign = 'start' | 'end'\n\ninterface PopoverPosition {\n top: string\n left: string | null\n right: string | null\n}\n\nlet nextPopoverId = 0\n\n@Component({\n selector: 'gbt-popover',\n standalone: true,\n exportAs: 'gbtPopover',\n imports: [],\n templateUrl: './popover.html',\n styleUrl: './popover.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'gbt-popover-host',\n '(click)': 'onTriggerClick($event)',\n '(document:click)': 'handleClickOutside($event)',\n '(keydown)': 'onKeydown($event)',\n '(window:resize)': 'updatePosition()',\n },\n})\nexport class Popover {\n private readonly elementRef = inject(ElementRef<HTMLElement>)\n private readonly triggerSlot = viewChild<ElementRef<HTMLElement>>('triggerSlot')\n\n align = input<PopoverAlign>('start')\n\n readonly panelId = `gbt-popover-${++nextPopoverId}`\n\n private readonly isOpen = signal(false)\n readonly open = this.isOpen.asReadonly()\n\n protected readonly position = signal<PopoverPosition | null>(null)\n\n toggle(): void {\n this.isOpen.update((value) => !value)\n if (this.isOpen()) {\n this.updatePosition()\n }\n }\n\n close(returnFocus = false): void {\n if (!this.isOpen()) {\n return\n }\n this.isOpen.set(false)\n if (returnFocus) {\n this.focusTrigger()\n }\n }\n\n protected onTriggerClick(event: MouseEvent): void {\n const trigger = this.triggerSlot()?.nativeElement\n if (trigger?.contains(event.target as Node)) {\n this.toggle()\n }\n }\n\n constructor() {\n followPageScroll(() => this.updatePosition())\n }\n\n protected updatePosition(): void {\n if (!this.isOpen()) {\n return\n }\n const trigger = this.triggerSlot()?.nativeElement\n if (!trigger) {\n return\n }\n const rect = trigger.getBoundingClientRect()\n this.position.set(\n this.align() === 'end'\n ? { top: `${rect.bottom + 6}px`, left: null, right: `${window.innerWidth - rect.right}px` }\n : { top: `${rect.bottom + 6}px`, left: `${rect.left}px`, right: null },\n )\n }\n\n protected handleClickOutside(event: MouseEvent): void {\n if (this.isOpen() && !this.elementRef.nativeElement.contains(event.target as Node)) {\n this.close(false)\n }\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape' && this.isOpen()) {\n event.preventDefault()\n event.stopPropagation()\n this.close(true)\n }\n }\n\n private focusTrigger(): void {\n const trigger = this.triggerSlot()?.nativeElement\n trigger\n ?.querySelector<HTMLElement>('button, a[href], input, select, textarea, [tabindex]')\n ?.focus()\n }\n}\n","<span #triggerSlot class=\"gbt-popover__trigger\">\n <ng-content></ng-content>\n</span>\n@if (open() && position(); as pos) {\n <div\n class=\"gbt-popover__panel\"\n [id]=\"panelId\"\n [style.top]=\"pos.top\"\n [style.left]=\"pos.left\"\n [style.right]=\"pos.right\"\n >\n <ng-content select=\"[popover-content]\"></ng-content>\n </div>\n}\n"],"mappings":"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"}
|