@ojiepermana/angular 22.1.10 → 22.1.12
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 +32 -26
- package/chart/README.md +272 -0
- package/component/README.md +89 -0
- package/component/accordion/README.md +195 -0
- package/component/alert/README.md +184 -0
- package/component/alert-dialog/README.md +255 -0
- package/component/aspect-ratio/README.md +116 -0
- package/component/avatar/README.md +182 -0
- package/component/badge/README.md +143 -0
- package/component/breadcrumb/README.md +223 -0
- package/component/button/README.md +141 -0
- package/component/button-group/README.md +214 -0
- package/component/calendar/README.md +137 -0
- package/component/card/README.md +232 -0
- package/component/carousel/README.md +276 -0
- package/component/checkbox/README.md +153 -0
- package/component/collapsible/README.md +216 -0
- package/component/combobox/README.md +202 -0
- package/component/command/README.md +287 -0
- package/component/composer/README.md +241 -0
- package/component/context-menu/README.md +268 -0
- package/component/date-picker/README.md +202 -0
- package/component/dialog/README.md +276 -0
- package/component/drawer/README.md +147 -0
- package/component/dropdown-menu/README.md +336 -0
- package/component/editor/README.md +152 -0
- package/component/empty/README.md +193 -0
- package/component/form/README.md +216 -0
- package/component/hover-card/README.md +150 -0
- package/component/icon/README.md +25 -0
- package/component/input/README.md +160 -0
- package/component/input-group/README.md +245 -0
- package/component/input-otp/README.md +331 -0
- package/component/item/README.md +254 -0
- package/component/kanban/README.md +81 -0
- package/component/kbd/README.md +141 -0
- package/component/label/README.md +137 -0
- package/component/menubar/README.md +270 -0
- package/component/native-select/README.md +176 -0
- package/component/navigation-menu/README.md +165 -0
- package/component/pagination/README.md +151 -0
- package/component/pillbox/README.md +68 -0
- package/component/popover/README.md +54 -0
- package/component/progress/README.md +160 -0
- package/component/radio/README.md +212 -0
- package/component/resizable/README.md +178 -0
- package/component/scroll-area/README.md +150 -0
- package/component/select/README.md +228 -0
- package/component/separator/README.md +175 -0
- package/component/sheet/README.md +190 -0
- package/component/skeleton/README.md +158 -0
- package/component/slider/README.md +207 -0
- package/component/spinner/README.md +160 -0
- package/component/switch/README.md +170 -0
- package/component/table/README.md +292 -0
- package/component/tabs/README.md +220 -0
- package/component/textarea/README.md +169 -0
- package/component/timeline/README.md +94 -0
- package/component/toast/README.md +173 -0
- package/component/toggle/README.md +133 -0
- package/component/toggle-group/README.md +234 -0
- package/component/tooltip/README.md +230 -0
- package/fesm2022/ojiepermana-angular-chart-area.mjs +289 -3
- package/fesm2022/ojiepermana-angular-chart-bar.mjs +722 -3
- package/fesm2022/ojiepermana-angular-chart-core.mjs +1482 -3
- package/fesm2022/ojiepermana-angular-chart-line.mjs +294 -3
- package/fesm2022/ojiepermana-angular-chart-pie.mjs +291 -3
- package/fesm2022/ojiepermana-angular-chart-primitives.mjs +1301 -3
- package/fesm2022/ojiepermana-angular-chart-radar.mjs +421 -3
- package/fesm2022/ojiepermana-angular-chart-radial.mjs +295 -3
- package/fesm2022/ojiepermana-angular-chart-scatter.mjs +306 -3
- package/fesm2022/ojiepermana-angular-chart.mjs +12 -3
- package/fesm2022/ojiepermana-angular-component-accordion.mjs +267 -3
- package/fesm2022/ojiepermana-angular-component-alert-dialog.mjs +359 -3
- package/fesm2022/ojiepermana-angular-component-alert.mjs +101 -3
- package/fesm2022/ojiepermana-angular-component-aspect-ratio.mjs +31 -3
- package/fesm2022/ojiepermana-angular-component-avatar.mjs +139 -3
- package/fesm2022/ojiepermana-angular-component-badge.mjs +57 -3
- package/fesm2022/ojiepermana-angular-component-breadcrumb.mjs +192 -3
- package/fesm2022/ojiepermana-angular-component-button-group.mjs +95 -3
- package/fesm2022/ojiepermana-angular-component-button.mjs +73 -3
- package/fesm2022/ojiepermana-angular-component-calendar.mjs +718 -3
- package/fesm2022/ojiepermana-angular-component-card.mjs +167 -3
- package/fesm2022/ojiepermana-angular-component-carousel.mjs +326 -3
- package/fesm2022/ojiepermana-angular-component-checkbox.mjs +190 -3
- package/fesm2022/ojiepermana-angular-component-collapsible.mjs +117 -3
- package/fesm2022/ojiepermana-angular-component-combobox.mjs +327 -3
- package/fesm2022/ojiepermana-angular-component-command.mjs +351 -3
- package/fesm2022/ojiepermana-angular-component-composer.mjs +359 -3
- package/fesm2022/ojiepermana-angular-component-context-menu.mjs +158 -3
- package/fesm2022/ojiepermana-angular-component-date-picker.mjs +482 -3
- package/fesm2022/ojiepermana-angular-component-dialog.mjs +400 -3
- package/fesm2022/ojiepermana-angular-component-drawer.mjs +1 -3
- package/fesm2022/ojiepermana-angular-component-dropdown-menu.mjs +689 -3
- package/fesm2022/ojiepermana-angular-component-editor.mjs +511 -3
- package/fesm2022/ojiepermana-angular-component-empty.mjs +134 -3
- package/fesm2022/ojiepermana-angular-component-form.mjs +438 -3
- package/fesm2022/ojiepermana-angular-component-hover-card.mjs +273 -3
- package/fesm2022/ojiepermana-angular-component-icon.mjs +139 -3
- package/fesm2022/ojiepermana-angular-component-input-group.mjs +176 -3
- package/fesm2022/ojiepermana-angular-component-input-otp.mjs +550 -3
- package/fesm2022/ojiepermana-angular-component-input.mjs +52 -3
- package/fesm2022/ojiepermana-angular-component-item.mjs +264 -3
- package/fesm2022/ojiepermana-angular-component-kanban.mjs +310 -3
- package/fesm2022/ojiepermana-angular-component-kbd.mjs +48 -3
- package/fesm2022/ojiepermana-angular-component-label.mjs +27 -3
- package/fesm2022/ojiepermana-angular-component-menubar.mjs +327 -3
- package/fesm2022/ojiepermana-angular-component-native-select.mjs +62 -3
- package/fesm2022/ojiepermana-angular-component-navigation-menu.mjs +378 -3
- package/fesm2022/ojiepermana-angular-component-pagination.mjs +238 -3
- package/fesm2022/ojiepermana-angular-component-pillbox.mjs +999 -3
- package/fesm2022/ojiepermana-angular-component-popover.mjs +201 -3
- package/fesm2022/ojiepermana-angular-component-progress.mjs +57 -3
- package/fesm2022/ojiepermana-angular-component-radio.mjs +180 -3
- package/fesm2022/ojiepermana-angular-component-resizable.mjs +493 -3
- package/fesm2022/ojiepermana-angular-component-scroll-area.mjs +51 -3
- package/fesm2022/ojiepermana-angular-component-segmented-control.mjs +227 -3
- package/fesm2022/ojiepermana-angular-component-select.mjs +609 -3
- package/fesm2022/ojiepermana-angular-component-separator.mjs +31 -3
- package/fesm2022/ojiepermana-angular-component-sheet.mjs +407 -3
- package/fesm2022/ojiepermana-angular-component-skeleton.mjs +25 -3
- package/fesm2022/ojiepermana-angular-component-slider.mjs +456 -3
- package/fesm2022/ojiepermana-angular-component-spinner.mjs +56 -3
- package/fesm2022/ojiepermana-angular-component-switch.mjs +145 -3
- package/fesm2022/ojiepermana-angular-component-table.mjs +155 -3
- package/fesm2022/ojiepermana-angular-component-tabs.mjs +315 -3
- package/fesm2022/ojiepermana-angular-component-textarea.mjs +46 -3
- package/fesm2022/ojiepermana-angular-component-timeline.mjs +237 -3
- package/fesm2022/ojiepermana-angular-component-toast.mjs +241 -3
- package/fesm2022/ojiepermana-angular-component-toggle-group.mjs +290 -3
- package/fesm2022/ojiepermana-angular-component-toggle.mjs +76 -3
- package/fesm2022/ojiepermana-angular-component-tooltip.mjs +519 -3
- package/fesm2022/ojiepermana-angular-component-utils-core.mjs +310 -3
- package/fesm2022/ojiepermana-angular-component-utils-overlay.mjs +62 -3
- package/fesm2022/ojiepermana-angular-component-utils-scale.mjs +34 -3
- package/fesm2022/ojiepermana-angular-component-utils.mjs +3 -2
- package/fesm2022/ojiepermana-angular-component.mjs +4 -4
- package/fesm2022/ojiepermana-angular-navigation-core.mjs +21 -3
- package/fesm2022/ojiepermana-angular-navigation-icon.mjs +20 -3
- package/fesm2022/ojiepermana-angular-navigation-navigation-badge-count.component-CDBxQ8rk.mjs +91 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-dockbar-menu.component-DBQHdvGa.mjs +512 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-entry-grid.component-Cd-jh6tg.mjs +623 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-flyout-menu.component-BCGvhoYj.mjs +404 -0
- package/fesm2022/ojiepermana-angular-navigation-navigation-horizontal.component-Dk_03e-6.mjs +466 -0
- package/fesm2022/ojiepermana-angular-navigation-ojiepermana-angular-navigation-DNKU6viC.mjs +2642 -0
- package/fesm2022/ojiepermana-angular-navigation-service.mjs +725 -3
- package/fesm2022/ojiepermana-angular-navigation-types.mjs +65 -4
- package/fesm2022/ojiepermana-angular-navigation.mjs +4 -10
- package/fesm2022/ojiepermana-angular-sdk.mjs +204 -4
- package/fesm2022/ojiepermana-angular-theme-component-settings.mjs +1387 -3
- package/fesm2022/ojiepermana-angular-theme-layout-services.mjs +331 -3
- package/fesm2022/ojiepermana-angular-theme-layout-types.mjs +45 -4
- package/fesm2022/ojiepermana-angular-theme-layout-wrapper.mjs +1044 -3
- package/fesm2022/ojiepermana-angular-theme-layout.mjs +729 -3
- package/fesm2022/ojiepermana-angular-theme-page-core.mjs +381 -3
- package/fesm2022/ojiepermana-angular-theme-page-filter.mjs +267 -3
- package/fesm2022/ojiepermana-angular-theme-page-root.mjs +361 -3
- package/fesm2022/ojiepermana-angular-theme-page-side.mjs +198 -3
- package/fesm2022/ojiepermana-angular-theme-page-slots.mjs +110 -3
- package/fesm2022/ojiepermana-angular-theme-page.mjs +7 -2
- package/fesm2022/ojiepermana-angular-theme-shell-services.mjs +338 -3
- package/fesm2022/ojiepermana-angular-theme-shell-types.mjs +160 -4
- package/fesm2022/ojiepermana-angular-theme-shell.mjs +811 -3
- package/fesm2022/ojiepermana-angular-theme-styles.mjs +783 -3
- package/fesm2022/ojiepermana-angular-theme.mjs +4 -4
- package/fesm2022/ojiepermana-angular.mjs +6 -11
- package/navigation/README.md +374 -0
- package/package.json +81 -20
- package/sdk/README.md +212 -0
- package/sdk/schematics/collection.json +20 -0
- package/sdk/schematics/init/index.js +83 -0
- package/sdk/schematics/init/schema.json +19 -0
- package/sdk/schematics/ng-add/index.js +147 -0
- package/sdk/schematics/ng-add/schema.json +14 -0
- package/sdk/schematics/package.json +3 -0
- package/sdk/schematics/sdk/index.js +175 -0
- package/sdk/schematics/sdk/schema.json +19 -0
- package/sdk/sdk.config.example.json +24 -0
- package/sdk/src/config/loader.js +43 -0
- package/sdk/src/config/schema.js +59 -0
- package/sdk/src/emit/client.js +251 -0
- package/sdk/src/emit/metadata.js +310 -0
- package/sdk/src/emit/models.js +104 -0
- package/sdk/src/emit/navigation.js +56 -0
- package/sdk/src/emit/operations.js +118 -0
- package/sdk/src/emit/public-api.js +54 -0
- package/sdk/src/emit/services.js +110 -0
- package/sdk/src/engine.js +67 -0
- package/sdk/src/layout/per-domain.js +360 -0
- package/sdk/src/package.json +3 -0
- package/sdk/src/parser/bundle.js +25 -0
- package/sdk/src/parser/ir.js +429 -0
- package/sdk/src/parser/types.js +7 -0
- package/sdk/src/render/template.js +152 -0
- package/sdk/src/writer/index.js +286 -0
- package/theme/README.md +126 -0
- package/theme/component/settings/README.md +135 -0
- package/theme/layout/README.md +539 -0
- package/theme/page/README.md +453 -0
- package/theme/shell/README.md +340 -0
- package/theme/styles/README.md +178 -0
- package/theme/styles/css/base/components.css +553 -0
- package/theme/styles/css/base/index.css +14 -0
- package/theme/styles/css/base/package.css +9 -0
- package/theme/styles/css/base/prefers-dark.css +86 -0
- package/theme/styles/css/base/print.css +62 -0
- package/theme/styles/css/base/status.css +38 -0
- package/theme/styles/css/base/tailwind.css +165 -0
- package/theme/styles/css/base/theme.css +373 -0
- package/theme/styles/css/base/tokens.css +361 -0
- package/theme/styles/css/color/amber.css +72 -0
- package/theme/styles/css/color/blue.css +72 -0
- package/theme/styles/css/color/brand.css +38 -0
- package/theme/styles/css/color/cyan.css +72 -0
- package/theme/styles/css/color/emerald.css +72 -0
- package/theme/styles/css/color/fuchsia.css +72 -0
- package/theme/styles/css/color/green.css +72 -0
- package/theme/styles/css/color/index.css +19 -0
- package/theme/styles/css/color/indigo.css +72 -0
- package/theme/styles/css/color/lime.css +72 -0
- package/theme/styles/css/color/orange.css +72 -0
- package/theme/styles/css/color/pink.css +72 -0
- package/theme/styles/css/color/purple.css +72 -0
- package/theme/styles/css/color/red.css +72 -0
- package/theme/styles/css/color/rose.css +72 -0
- package/theme/styles/css/color/sky.css +72 -0
- package/theme/styles/css/color/teal.css +72 -0
- package/theme/styles/css/color/violet.css +72 -0
- package/theme/styles/css/color/yellow.css +72 -0
- package/theme/styles/css/index.css +18 -0
- package/theme/styles/css/neutral/gray.css +63 -0
- package/theme/styles/css/neutral/index.css +11 -0
- package/theme/styles/css/neutral/mauve.css +63 -0
- package/theme/styles/css/neutral/mist.css +63 -0
- package/theme/styles/css/neutral/neutral.css +63 -0
- package/theme/styles/css/neutral/olive.css +63 -0
- package/theme/styles/css/neutral/slate.css +63 -0
- package/theme/styles/css/neutral/stone.css +63 -0
- package/theme/styles/css/neutral/taupe.css +63 -0
- package/theme/styles/css/neutral/zinc.css +63 -0
- package/theme/styles/css/radius/index.css +30 -0
- package/theme/styles/css/space/index.css +20 -0
- package/types/ojiepermana-angular-chart-area.d.ts +76 -1
- package/types/ojiepermana-angular-chart-bar.d.ts +201 -1
- package/types/ojiepermana-angular-chart-core.d.ts +811 -1
- package/types/ojiepermana-angular-chart-line.d.ts +75 -1
- package/types/ojiepermana-angular-chart-pie.d.ts +131 -1
- package/types/ojiepermana-angular-chart-primitives.d.ts +291 -1
- package/types/ojiepermana-angular-chart-radar.d.ts +116 -1
- package/types/ojiepermana-angular-chart-radial.d.ts +116 -1
- package/types/ojiepermana-angular-chart-scatter.d.ts +125 -1
- package/types/ojiepermana-angular-chart.d.ts +2 -1
- package/types/ojiepermana-angular-component-accordion.d.ts +85 -1
- package/types/ojiepermana-angular-component-alert-dialog.d.ts +140 -1
- package/types/ojiepermana-angular-component-alert.d.ts +42 -1
- package/types/ojiepermana-angular-component-aspect-ratio.d.ts +12 -1
- package/types/ojiepermana-angular-component-avatar.d.ts +56 -1
- package/types/ojiepermana-angular-component-badge.d.ts +24 -1
- package/types/ojiepermana-angular-component-breadcrumb.d.ts +46 -1
- package/types/ojiepermana-angular-component-button-group.d.ts +26 -1
- package/types/ojiepermana-angular-component-button.d.ts +27 -1
- package/types/ojiepermana-angular-component-calendar.d.ts +111 -1
- package/types/ojiepermana-angular-component-card.d.ts +69 -1
- package/types/ojiepermana-angular-component-carousel.d.ts +86 -1
- package/types/ojiepermana-angular-component-checkbox.d.ts +42 -1
- package/types/ojiepermana-angular-component-collapsible.d.ts +42 -1
- package/types/ojiepermana-angular-component-combobox.d.ts +60 -1
- package/types/ojiepermana-angular-component-command.d.ts +130 -1
- package/types/ojiepermana-angular-component-composer.d.ts +90 -1
- package/types/ojiepermana-angular-component-context-menu.d.ts +54 -1
- package/types/ojiepermana-angular-component-date-picker.d.ts +109 -1
- package/types/ojiepermana-angular-component-dialog.d.ts +136 -1
- package/types/ojiepermana-angular-component-drawer.d.ts +1 -1
- package/types/ojiepermana-angular-component-dropdown-menu.d.ts +248 -1
- package/types/ojiepermana-angular-component-editor.d.ts +135 -1
- package/types/ojiepermana-angular-component-empty.d.ts +50 -1
- package/types/ojiepermana-angular-component-form.d.ts +159 -1
- package/types/ojiepermana-angular-component-hover-card.d.ts +75 -1
- package/types/ojiepermana-angular-component-icon.d.ts +89 -1
- package/types/ojiepermana-angular-component-input-group.d.ts +51 -1
- package/types/ojiepermana-angular-component-input-otp.d.ts +155 -1
- package/types/ojiepermana-angular-component-input.d.ts +21 -1
- package/types/ojiepermana-angular-component-item.d.ts +93 -1
- package/types/ojiepermana-angular-component-kanban.d.ts +70 -1
- package/types/ojiepermana-angular-component-kbd.d.ts +16 -1
- package/types/ojiepermana-angular-component-label.d.ts +11 -1
- package/types/ojiepermana-angular-component-menubar.d.ts +93 -1
- package/types/ojiepermana-angular-component-native-select.d.ts +26 -1
- package/types/ojiepermana-angular-component-navigation-menu.d.ts +104 -1
- package/types/ojiepermana-angular-component-pagination.d.ts +33 -1
- package/types/ojiepermana-angular-component-pillbox.d.ts +222 -1
- package/types/ojiepermana-angular-component-popover.d.ts +66 -1
- package/types/ojiepermana-angular-component-progress.d.ts +17 -1
- package/types/ojiepermana-angular-component-radio.d.ts +60 -1
- package/types/ojiepermana-angular-component-resizable.d.ts +117 -1
- package/types/ojiepermana-angular-component-scroll-area.d.ts +19 -1
- package/types/ojiepermana-angular-component-segmented-control.d.ts +58 -1
- package/types/ojiepermana-angular-component-select.d.ts +122 -1
- package/types/ojiepermana-angular-component-separator.d.ts +14 -1
- package/types/ojiepermana-angular-component-sheet.d.ts +130 -1
- package/types/ojiepermana-angular-component-skeleton.d.ts +10 -1
- package/types/ojiepermana-angular-component-slider.d.ts +83 -1
- package/types/ojiepermana-angular-component-spinner.d.ts +13 -1
- package/types/ojiepermana-angular-component-switch.d.ts +44 -1
- package/types/ojiepermana-angular-component-table.d.ts +57 -1
- package/types/ojiepermana-angular-component-tabs.d.ts +124 -1
- package/types/ojiepermana-angular-component-textarea.d.ts +17 -1
- package/types/ojiepermana-angular-component-timeline.d.ts +64 -1
- package/types/ojiepermana-angular-component-toast.d.ts +64 -1
- package/types/ojiepermana-angular-component-toggle-group.d.ts +90 -1
- package/types/ojiepermana-angular-component-toggle.d.ts +25 -1
- package/types/ojiepermana-angular-component-tooltip.d.ts +143 -1
- package/types/ojiepermana-angular-component-utils-core.d.ts +184 -1
- package/types/ojiepermana-angular-component-utils-overlay.d.ts +21 -1
- package/types/ojiepermana-angular-component-utils-scale.d.ts +19 -1
- package/types/ojiepermana-angular-component-utils.d.ts +2 -1
- package/types/ojiepermana-angular-component.d.ts +2 -1
- package/types/ojiepermana-angular-navigation-core.d.ts +59 -1
- package/types/ojiepermana-angular-navigation-icon.d.ts +12 -1
- package/types/ojiepermana-angular-navigation-service.d.ts +116 -1
- package/types/ojiepermana-angular-navigation-types.d.ts +144 -1
- package/types/ojiepermana-angular-navigation.d.ts +507 -1
- package/types/ojiepermana-angular-sdk.d.ts +89 -1
- package/types/ojiepermana-angular-theme-component-settings.d.ts +154 -1
- package/types/ojiepermana-angular-theme-layout-services.d.ts +147 -1
- package/types/ojiepermana-angular-theme-layout-types.d.ts +40 -1
- package/types/ojiepermana-angular-theme-layout-wrapper.d.ts +299 -1
- package/types/ojiepermana-angular-theme-layout.d.ts +129 -1
- package/types/ojiepermana-angular-theme-page-core.d.ts +157 -1
- package/types/ojiepermana-angular-theme-page-filter.d.ts +77 -1
- package/types/ojiepermana-angular-theme-page-root.d.ts +88 -1
- package/types/ojiepermana-angular-theme-page-side.d.ts +50 -1
- package/types/ojiepermana-angular-theme-page-slots.d.ts +40 -1
- package/types/ojiepermana-angular-theme-page.d.ts +5 -1
- package/types/ojiepermana-angular-theme-shell-services.d.ts +193 -1
- package/types/ojiepermana-angular-theme-shell-types.d.ts +105 -1
- package/types/ojiepermana-angular-theme-shell.d.ts +100 -1
- package/types/ojiepermana-angular-theme-styles.d.ts +319 -1
- package/types/ojiepermana-angular-theme.d.ts +2 -1
- package/types/ojiepermana-angular.d.ts +5 -5
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Date Picker
|
|
2
|
+
|
|
3
|
+
Popup ISO-date input backed by the local native `Calendar` primitive and a CDK overlay.
|
|
4
|
+
|
|
5
|
+
The upstream shadcn Date Picker is composed from Popover and Calendar. This Angular library exposes `DatePicker` as the app-level wrapper while preserving the same product behavior: an input trigger, a calendar popup, selected state, and date constraints.
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { DatePickerComponent } from '@ojiepermana/angular/component/date-picker';
|
|
11
|
+
import { LabelComponent } from '@ojiepermana/angular/component/label';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
Pair the picker with a visible label through the `id` input, then bind the selected date through the signal model.
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<label Label for="date-picker-demo">Date</label>
|
|
20
|
+
<DatePicker id="date-picker-demo" class="w-72" [(value)]="date" placeholder="Pick a date" />
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The component also implements `ControlValueAccessor`, so it can be used with reactive forms or `ngModel`.
|
|
24
|
+
|
|
25
|
+
## Common patterns
|
|
26
|
+
|
|
27
|
+
### Basic
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<label Label for="date-picker-simple">Date</label>
|
|
31
|
+
<DatePicker id="date-picker-simple" class="w-44" [(value)]="basicDate" placeholder="Pick a date" />
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Coordinated range
|
|
35
|
+
|
|
36
|
+
Use two date pickers when the product needs a start and end date but does not need a dedicated range-calendar primitive.
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<div class="grid gap-4 sm:grid-cols-2">
|
|
40
|
+
<div class="grid gap-2">
|
|
41
|
+
<label Label for="date-range-start">Start date</label>
|
|
42
|
+
<DatePicker id="date-range-start" [(value)]="rangeStart" [max]="rangeEnd()" />
|
|
43
|
+
</div>
|
|
44
|
+
<div class="grid gap-2">
|
|
45
|
+
<label Label for="date-range-end">End date</label>
|
|
46
|
+
<DatePicker id="date-range-end" [(value)]="rangeEnd" [min]="rangeStart()" />
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Date of birth
|
|
52
|
+
|
|
53
|
+
Use `startView="multi-year"` and `startAt` for dates that are usually far away from the current month.
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<label Label for="date-picker-birth">Date of birth</label>
|
|
57
|
+
<DatePicker
|
|
58
|
+
id="date-picker-birth"
|
|
59
|
+
class="w-48"
|
|
60
|
+
[(value)]="birthDate"
|
|
61
|
+
placeholder="Select date"
|
|
62
|
+
[startAt]="birthStartAt"
|
|
63
|
+
startView="multi-year"
|
|
64
|
+
/>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Date plus time
|
|
68
|
+
|
|
69
|
+
Pair the date picker with a native `input[type="time"]` for date-time forms.
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<div class="grid gap-4 sm:grid-cols-[minmax(0,12rem)_8rem]">
|
|
73
|
+
<div class="grid gap-2">
|
|
74
|
+
<label Label for="date-picker-time-date">Date</label>
|
|
75
|
+
<DatePicker id="date-picker-time-date" [(value)]="timeDate" />
|
|
76
|
+
</div>
|
|
77
|
+
<div class="grid gap-2">
|
|
78
|
+
<label Label for="date-picker-time-input">Time</label>
|
|
79
|
+
<input id="date-picker-time-input" Input type="time" step="1" [value]="timeValue()" />
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Disabled dates
|
|
85
|
+
|
|
86
|
+
Use `min`, `max`, and `dateFilter` to prevent invalid choices in the calendar before submit.
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
readonly minBookingDate = new Date(2026, 0, 1);
|
|
90
|
+
readonly maxBookingDate = new Date(2026, 11, 31);
|
|
91
|
+
readonly weekdayFilter = (date: Date | null): boolean => {
|
|
92
|
+
const day = date?.getDay();
|
|
93
|
+
return day !== 0 && day !== 6;
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<DatePicker
|
|
99
|
+
id="date-picker-subscription"
|
|
100
|
+
[(value)]="subscriptionDate"
|
|
101
|
+
[min]="minBookingDate"
|
|
102
|
+
[max]="maxBookingDate"
|
|
103
|
+
[dateFilter]="weekdayFilter"
|
|
104
|
+
/>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### RTL
|
|
108
|
+
|
|
109
|
+
Set `dir="rtl"` on a wrapping container or at the application shell. The picker follows the surrounding direction.
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<div dir="rtl" lang="ar" class="grid max-w-xs gap-2 text-right">
|
|
113
|
+
<label Label for="date-picker-rtl">Date</label>
|
|
114
|
+
<DatePicker id="date-picker-rtl" [(value)]="rtlDate" placeholder="Pick a date" />
|
|
115
|
+
</div>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## API reference
|
|
119
|
+
|
|
120
|
+
| Input / Model | Type | Default |
|
|
121
|
+
| ---------------------- | ----------------------------------- | -------------------- |
|
|
122
|
+
| `value` | `Date \| null` | `null` |
|
|
123
|
+
| `id` | `string \| null` | `null` |
|
|
124
|
+
| `placeholder` | `string` | `'Pick a date'` |
|
|
125
|
+
| `required` | `boolean` | `false` |
|
|
126
|
+
| `min` | `Date \| null` | `null` |
|
|
127
|
+
| `max` | `Date \| null` | `null` |
|
|
128
|
+
| `startAt` | `Date \| null` | `null` |
|
|
129
|
+
| `startView` | `'month' \| 'year' \| 'multi-year'` | `'month'` |
|
|
130
|
+
| `touchUi` | `boolean` | `false` |
|
|
131
|
+
| `dateFilter` | `(date: Date \| null) => boolean` | `null` |
|
|
132
|
+
| `panelClass` | `string \| string[]` | `'datepicker-panel'` |
|
|
133
|
+
| `panelAriaLabel` | `string` | `'Choose a date'` |
|
|
134
|
+
| `invalidFormatMessage` | `string` | ISO-format guidance |
|
|
135
|
+
| `aria-label` | `string \| null` | `null` |
|
|
136
|
+
| `aria-labelledby` | `string \| null` | `null` |
|
|
137
|
+
| `aria-describedby` | `string \| null` | `null` |
|
|
138
|
+
| `disabled` | `boolean` | `false` |
|
|
139
|
+
| `class` | `string` | `''` |
|
|
140
|
+
|
|
141
|
+
## Validation
|
|
142
|
+
|
|
143
|
+
The picker is a validator as well as a value accessor, so a draft the field refuses is a draft the
|
|
144
|
+
form refuses. The rejected text stays in the input — the control keeps the last date it successfully
|
|
145
|
+
committed, and turns invalid until the draft parses and passes the constraints.
|
|
146
|
+
|
|
147
|
+
| Error key | Payload | Raised when |
|
|
148
|
+
| ------------ | ----------------------------- | ---------------------------------------------- |
|
|
149
|
+
| `dateParse` | `{ text: string }` | The committed draft is not a `YYYY-MM-DD` date |
|
|
150
|
+
| `dateMin` | `{ min: Date, actual: Date }` | The date falls before `min` (compared by day) |
|
|
151
|
+
| `dateMax` | `{ max: Date, actual: Date }` | The date falls after `max` (compared by day) |
|
|
152
|
+
| `dateFilter` | `{ actual: Date }` | `dateFilter` returns `false` for the date |
|
|
153
|
+
|
|
154
|
+
A committed value is re-checked against `min`, `max`, and `dateFilter` too, so a date written into
|
|
155
|
+
the control programmatically cannot slip past the same constraints the field enforces. An empty
|
|
156
|
+
draft in a `required` picker commits as `dateParse` with empty text; pair the picker with
|
|
157
|
+
`Validators.required` when the form should name that case itself.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
readonly bookingDate = new FormControl<Date | null>(null);
|
|
161
|
+
|
|
162
|
+
readonly bookingError = computed(() => {
|
|
163
|
+
const errors = this.bookingDate.errors;
|
|
164
|
+
return errors?.['dateMax'] ? 'Pick a date inside the booking window.' : null;
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Styling and theming
|
|
169
|
+
|
|
170
|
+
The host accepts `class` for width and layout utilities. The native input is full width, so classes such as `w-44`, `w-72`, and `w-full` should be placed on `DatePicker`.
|
|
171
|
+
|
|
172
|
+
The popup panel defaults to `datepicker-panel`, and calendar colors come from the shared popover, foreground, primary, and ring tokens.
|
|
173
|
+
|
|
174
|
+
## Accessibility
|
|
175
|
+
|
|
176
|
+
- Pair the date picker with a visible label using the `id` input, or provide `aria-label` / `aria-labelledby`.
|
|
177
|
+
- The input and toggle expose `aria-controls`, `aria-expanded`, and `aria-haspopup`; the labelled dialog moves focus to the calendar's single roving tab stop.
|
|
178
|
+
- Invalid typed drafts remain visible and are associated with a polite error message (`role="status"`, one live-region semantic rather than two) instead of being silently replaced.
|
|
179
|
+
- Use constraints such as `min`, `max`, and `dateFilter` when dates are not selectable.
|
|
180
|
+
- Keep the visible label specific, such as `Start date`, `End date`, or `Subscription date`.
|
|
181
|
+
|
|
182
|
+
## Keyboard interactions
|
|
183
|
+
|
|
184
|
+
- Tab moves focus to the date input and toggle button.
|
|
185
|
+
- Enter or Space on the toggle opens the calendar popup.
|
|
186
|
+
- Arrow keys navigate dates while the calendar is open.
|
|
187
|
+
- Enter selects the focused date.
|
|
188
|
+
- Escape closes the popup and returns focus to the trigger.
|
|
189
|
+
|
|
190
|
+
## Angular notes
|
|
191
|
+
|
|
192
|
+
- Dates use the built-in ISO `YYYY-MM-DD` parser and native `Date` values; no Material date adapter is required.
|
|
193
|
+
- Use `[(value)]` when binding to a signal-backed `Date | null` value.
|
|
194
|
+
- Use the component as a CVA inside Angular forms when validation and form submission belong to a `FormControl`; it registers as an `NG_VALIDATORS` provider too, so refused drafts show up as control errors.
|
|
195
|
+
- `startView="multi-year"` is useful for birthdays and other far-past dates.
|
|
196
|
+
- For range selection today, coordinate two `DatePicker` instances with reciprocal `min` and `max` bindings.
|
|
197
|
+
|
|
198
|
+
## Source parity
|
|
199
|
+
|
|
200
|
+
This Angular implementation follows the current shadcn Date Picker information architecture while translating React Popover plus Calendar composition into the local native Calendar/CDK-overlay wrapper.
|
|
201
|
+
|
|
202
|
+
The upstream Range Picker example is represented as two coordinated `DatePicker` controls rather than a single range-calendar API. The upstream Natural Language example can be built by parsing text into a `Date | null` value and binding that value to `DatePicker`.
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
Displays a modal surface over the current page, traps focus while open, and restores focus to the previously active element when it closes.
|
|
4
|
+
|
|
5
|
+
Use Dialog for confirmation flows, compact forms, link sharing, and long-form review tasks that should keep the user in the current context.
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { ButtonComponent } from '@ojiepermana/angular/component/button';
|
|
11
|
+
import {
|
|
12
|
+
DialogCloseDirective,
|
|
13
|
+
DialogComponent,
|
|
14
|
+
DialogContentComponent,
|
|
15
|
+
DialogDescriptionComponent,
|
|
16
|
+
DialogFooterComponent,
|
|
17
|
+
DialogHeaderComponent,
|
|
18
|
+
DialogTitleComponent,
|
|
19
|
+
} from '@ojiepermana/angular/component/dialog';
|
|
20
|
+
import { InputComponent } from '@ojiepermana/angular/component/input';
|
|
21
|
+
import { LabelComponent } from '@ojiepermana/angular/component/label';
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Composition
|
|
25
|
+
|
|
26
|
+
The Angular composition tracks the shadcn structure, with one intentional mapping difference: shadcn `DialogTrigger` becomes any external control that toggles the `open` signal.
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
button[Button] (external trigger; sets the open signal)
|
|
30
|
+
Dialog
|
|
31
|
+
├── built-in close button (optional)
|
|
32
|
+
├── DialogHeader
|
|
33
|
+
│ ├── DialogTitle
|
|
34
|
+
│ └── DialogDescription
|
|
35
|
+
├── DialogContent (optional body wrapper)
|
|
36
|
+
└── DialogFooter
|
|
37
|
+
└── button[DialogClose] (optional custom close action)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Basic usage
|
|
41
|
+
|
|
42
|
+
Use an external button or link to toggle the `open` signal, then declare the dialog structure inside `Dialog`.
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<button type="button" Button variant="outline" (click)="open.set(true)">Edit profile</button>
|
|
46
|
+
|
|
47
|
+
<dialog
|
|
48
|
+
[(open)]="open"
|
|
49
|
+
aria-labelledby="dialog-title"
|
|
50
|
+
aria-describedby="dialog-description"
|
|
51
|
+
class="sm:max-w-sm"
|
|
52
|
+
>
|
|
53
|
+
<DialogHeader>
|
|
54
|
+
<DialogTitle id="dialog-title">Edit profile</DialogTitle>
|
|
55
|
+
<DialogDescription id="dialog-description">
|
|
56
|
+
Make changes to your profile here. Click save when you are done.
|
|
57
|
+
</DialogDescription>
|
|
58
|
+
</DialogHeader>
|
|
59
|
+
|
|
60
|
+
<DialogContent class="grid gap-4 py-2">
|
|
61
|
+
<div class="grid gap-2">
|
|
62
|
+
<label Label for="name">Name</label>
|
|
63
|
+
<input Input id="name" value="Pedro Duarte" />
|
|
64
|
+
</div>
|
|
65
|
+
<div class="grid gap-2">
|
|
66
|
+
<label Label for="username">Username</label>
|
|
67
|
+
<input Input id="username" value="@peduarte" />
|
|
68
|
+
</div>
|
|
69
|
+
</DialogContent>
|
|
70
|
+
|
|
71
|
+
<DialogFooter>
|
|
72
|
+
<button type="button" Button variant="outline" DialogClose>Cancel</button>
|
|
73
|
+
<button type="button" Button (click)="open.set(false)">Save changes</button>
|
|
74
|
+
</DialogFooter>
|
|
75
|
+
</dialog>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Common patterns
|
|
79
|
+
|
|
80
|
+
### Destructive confirmation
|
|
81
|
+
|
|
82
|
+
Use a short title, short body copy, and explicit cancel/confirm actions for destructive flows.
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<button type="button" Button variant="destructive" (click)="confirmOpen.set(true)">
|
|
86
|
+
Delete project
|
|
87
|
+
</button>
|
|
88
|
+
|
|
89
|
+
<dialog [(open)]="confirmOpen">
|
|
90
|
+
<DialogHeader>
|
|
91
|
+
<DialogTitle>Delete this project?</DialogTitle>
|
|
92
|
+
<DialogDescription>
|
|
93
|
+
This action cannot be undone. This permanently deletes your project.
|
|
94
|
+
</DialogDescription>
|
|
95
|
+
</DialogHeader>
|
|
96
|
+
<DialogFooter>
|
|
97
|
+
<button type="button" Button variant="outline" DialogClose>Cancel</button>
|
|
98
|
+
<button type="button" Button variant="destructive" (click)="confirmOpen.set(false)">
|
|
99
|
+
Delete
|
|
100
|
+
</button>
|
|
101
|
+
</DialogFooter>
|
|
102
|
+
</dialog>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Custom close button
|
|
106
|
+
|
|
107
|
+
Hide the built-in corner close control with `[showCloseButton]="false"` and place `button[DialogClose]` wherever dismissal should live.
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<dialog [(open)]="shareOpen" [showCloseButton]="false" class="sm:max-w-md">
|
|
111
|
+
<DialogHeader>
|
|
112
|
+
<DialogTitle>Share link</DialogTitle>
|
|
113
|
+
<DialogDescription> Anyone who has this link can view this workspace. </DialogDescription>
|
|
114
|
+
</DialogHeader>
|
|
115
|
+
<DialogContent class="grid gap-4 py-2">
|
|
116
|
+
<div class="grid gap-2">
|
|
117
|
+
<label Label for="share-link">Link</label>
|
|
118
|
+
<input
|
|
119
|
+
Input
|
|
120
|
+
id="share-link"
|
|
121
|
+
readonly
|
|
122
|
+
value="https://ui.shadcn.com/docs/components/radix/dialog"
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
</DialogContent>
|
|
126
|
+
<DialogFooter class="sm:justify-start">
|
|
127
|
+
<button type="button" Button DialogClose>Close</button>
|
|
128
|
+
</DialogFooter>
|
|
129
|
+
</dialog>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### No close button
|
|
133
|
+
|
|
134
|
+
Use `[showCloseButton]="false"` without an internal close action when Escape and backdrop dismissal are enough.
|
|
135
|
+
|
|
136
|
+
```html
|
|
137
|
+
<dialog [(open)]="noCloseOpen" [showCloseButton]="false">
|
|
138
|
+
<DialogHeader>
|
|
139
|
+
<DialogTitle>No Close Button</DialogTitle>
|
|
140
|
+
<DialogDescription>
|
|
141
|
+
Dismiss this dialog with Escape, the backdrop, or another action you control.
|
|
142
|
+
</DialogDescription>
|
|
143
|
+
</DialogHeader>
|
|
144
|
+
</dialog>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Backdrop appearance
|
|
148
|
+
|
|
149
|
+
The area outside the surface is dimmed by default (`backdrop="dim"`), using the shared
|
|
150
|
+
`--overlay-backdrop` theme token so it recolors with the active theme and light/dark mode. Switch
|
|
151
|
+
to a frosted overlay with `backdrop="blur"`, or disable dimming entirely with
|
|
152
|
+
`backdrop="transparent"` when the dialog should float over a fully visible page.
|
|
153
|
+
|
|
154
|
+
```html
|
|
155
|
+
<!-- Dimmed (default) -->
|
|
156
|
+
<dialog [(open)]="open">…</dialog>
|
|
157
|
+
|
|
158
|
+
<!-- Frosted blur behind the surface -->
|
|
159
|
+
<dialog [(open)]="open" backdrop="blur">…</dialog>
|
|
160
|
+
|
|
161
|
+
<!-- No dimming; page stays fully visible -->
|
|
162
|
+
<dialog [(open)]="open" backdrop="transparent">…</dialog>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Sticky footer for long content
|
|
166
|
+
|
|
167
|
+
Move the scroll region into `DialogContent` and keep the footer outside that overflow container so primary actions remain visible.
|
|
168
|
+
|
|
169
|
+
```html
|
|
170
|
+
<dialog
|
|
171
|
+
[(open)]="stickyOpen"
|
|
172
|
+
[showCloseButton]="false"
|
|
173
|
+
class="max-h-[85vh] overflow-hidden p-0 sm:max-w-lg"
|
|
174
|
+
>
|
|
175
|
+
<DialogHeader class="px-6 pt-6">
|
|
176
|
+
<DialogTitle>Sticky Footer</DialogTitle>
|
|
177
|
+
<DialogDescription>Keep actions visible while the content scrolls.</DialogDescription>
|
|
178
|
+
</DialogHeader>
|
|
179
|
+
<DialogContent class="max-h-[45vh] overflow-y-auto px-6 pb-6">
|
|
180
|
+
<!-- long content -->
|
|
181
|
+
</DialogContent>
|
|
182
|
+
<DialogFooter class="border-t border-border bg-background px-6 py-4 sm:justify-start">
|
|
183
|
+
<button type="button" Button variant="outline" DialogClose>Close</button>
|
|
184
|
+
<button type="button" Button (click)="stickyOpen.set(false)">Save changes</button>
|
|
185
|
+
</DialogFooter>
|
|
186
|
+
</dialog>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### RTL
|
|
190
|
+
|
|
191
|
+
Wrap the trigger and dialog in a `dir="rtl"` container or set direction globally in the app shell.
|
|
192
|
+
|
|
193
|
+
```html
|
|
194
|
+
<div dir="rtl" lang="ar" class="text-right">
|
|
195
|
+
<button type="button" Button variant="outline" (click)="rtlOpen.set(true)">فتح الحوار</button>
|
|
196
|
+
|
|
197
|
+
<dialog [(open)]="rtlOpen" [showCloseButton]="false" class="sm:max-w-sm">
|
|
198
|
+
<DialogHeader>
|
|
199
|
+
<DialogTitle>تعديل الملف الشخصي</DialogTitle>
|
|
200
|
+
<DialogDescription>
|
|
201
|
+
قم بإجراء تغييرات على ملفك الشخصي هنا. انقر فوق حفظ عند الانتهاء.
|
|
202
|
+
</DialogDescription>
|
|
203
|
+
</DialogHeader>
|
|
204
|
+
<DialogContent class="grid gap-4 py-2">
|
|
205
|
+
<div class="grid gap-2">...</div>
|
|
206
|
+
<div class="grid gap-2">...</div>
|
|
207
|
+
</DialogContent>
|
|
208
|
+
<DialogFooter>
|
|
209
|
+
<button type="button" Button variant="outline" DialogClose>إلغاء</button>
|
|
210
|
+
<button type="button" Button (click)="rtlOpen.set(false)">حفظ التغييرات</button>
|
|
211
|
+
</DialogFooter>
|
|
212
|
+
</dialog>
|
|
213
|
+
</div>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## API reference
|
|
217
|
+
|
|
218
|
+
### `DialogComponent`
|
|
219
|
+
|
|
220
|
+
| Input | Type | Default |
|
|
221
|
+
| ---------------------- | ---------------------------------- | --------- |
|
|
222
|
+
| `open` (model) | `boolean` | `false` |
|
|
223
|
+
| `closeOnEscape` | `boolean` | `true` |
|
|
224
|
+
| `closeOnBackdropClick` | `boolean` | `true` |
|
|
225
|
+
| `backdrop` | `'dim' \| 'blur' \| 'transparent'` | `'dim'` |
|
|
226
|
+
| `showCloseButton` | `boolean` | `true` |
|
|
227
|
+
| `closeButtonLabel` | `string` | `'Close'` |
|
|
228
|
+
| `aria-labelledby` | `string \| null` | `null` |
|
|
229
|
+
| `aria-describedby` | `string \| null` | `null` |
|
|
230
|
+
| `class` | `string` | `''` |
|
|
231
|
+
|
|
232
|
+
Output: `openedChange: boolean`. Method: `close()`.
|
|
233
|
+
|
|
234
|
+
### Parts
|
|
235
|
+
|
|
236
|
+
| Part | Purpose |
|
|
237
|
+
| --------------------- | -------------------------------------------------------- |
|
|
238
|
+
| `DialogHeader` | Title and description wrapper |
|
|
239
|
+
| `DialogTitle` | Primary dialog label |
|
|
240
|
+
| `DialogDescription` | Supporting copy announced by assistive tech |
|
|
241
|
+
| `DialogContent` | Optional body wrapper for forms, grids, and scroll areas |
|
|
242
|
+
| `DialogFooter` | Action row |
|
|
243
|
+
| `button[DialogClose]` | Custom close action mapped to shadcn `DialogClose` |
|
|
244
|
+
|
|
245
|
+
Lower-level behavior is based on the Radix Dialog pattern: <https://www.radix-ui.com/primitives/docs/components/dialog#api-reference>.
|
|
246
|
+
|
|
247
|
+
## Styling and theming
|
|
248
|
+
|
|
249
|
+
The dialog surface uses the shared theme tokens for background, border, foreground, and ring colors. Pass `class` to `Dialog` when you need to adjust width, max height, overflow strategy, or padding for a specific modal pattern.
|
|
250
|
+
|
|
251
|
+
Use `DialogContent` and `DialogFooter` classes to create scroll regions, sticky action rows, or wider content layouts without forking the primitive.
|
|
252
|
+
|
|
253
|
+
## Accessibility
|
|
254
|
+
|
|
255
|
+
- The surface renders with `role="dialog"` and `aria-modal="true"`.
|
|
256
|
+
- Focus is trapped inside with `FocusTrap` from `@angular/cdk/a11y`.
|
|
257
|
+
- Focus returns to the previously active element when the dialog closes.
|
|
258
|
+
- Escape and backdrop dismissal are enabled by default but can be disabled for stricter flows.
|
|
259
|
+
- Keep titles and descriptions concise so screen readers announce useful context immediately.
|
|
260
|
+
|
|
261
|
+
## Keyboard interactions
|
|
262
|
+
|
|
263
|
+
- `Tab` and `Shift+Tab` stay inside the dialog while it is open.
|
|
264
|
+
- `Escape` closes the dialog unless `closeOnEscape` is disabled.
|
|
265
|
+
- Native button activation handles `Enter` and `Space` for dialog actions.
|
|
266
|
+
|
|
267
|
+
## Angular notes
|
|
268
|
+
|
|
269
|
+
- This implementation intentionally maps shadcn `DialogTrigger` to an external control that owns the `open` signal.
|
|
270
|
+
- `button[DialogClose]` is the Angular-friendly equivalent of shadcn `DialogClose` for internal dismissal actions.
|
|
271
|
+
- Seed open state with a signal in the owning component and keep the dialog content declarative.
|
|
272
|
+
- Hide the built-in close affordance with `[showCloseButton]="false"` when the footer or body owns dismissal explicitly.
|
|
273
|
+
|
|
274
|
+
## Source parity
|
|
275
|
+
|
|
276
|
+
This Angular implementation follows the shadcn Dialog information architecture and examples while translating the interaction model to Angular selectors, signal-driven state, and explicit ownership of the trigger outside the modal content.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Drawer
|
|
2
|
+
|
|
3
|
+
Bottom-first modal drawer built on the local Sheet overlay primitive. It mirrors the shadcn Drawer composition while using Angular signals and explicit standalone imports.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { ButtonComponent } from '@ojiepermana/angular/component/button';
|
|
9
|
+
import {
|
|
10
|
+
DrawerCloseDirective,
|
|
11
|
+
DrawerComponent,
|
|
12
|
+
DrawerContentComponent,
|
|
13
|
+
DrawerDescriptionComponent,
|
|
14
|
+
DrawerFooterComponent,
|
|
15
|
+
DrawerHeaderComponent,
|
|
16
|
+
DrawerTitleComponent,
|
|
17
|
+
} from '@ojiepermana/angular/component/drawer';
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
|
|
24
|
+
import { ButtonComponent } from '@ojiepermana/angular/component/button';
|
|
25
|
+
import {
|
|
26
|
+
DrawerCloseDirective,
|
|
27
|
+
DrawerComponent,
|
|
28
|
+
DrawerDescriptionComponent,
|
|
29
|
+
DrawerFooterComponent,
|
|
30
|
+
DrawerHeaderComponent,
|
|
31
|
+
DrawerTitleComponent,
|
|
32
|
+
} from '@ojiepermana/angular/component/drawer';
|
|
33
|
+
|
|
34
|
+
@Component({
|
|
35
|
+
selector: 'app-drawer-example',
|
|
36
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
37
|
+
imports: [
|
|
38
|
+
ButtonComponent,
|
|
39
|
+
DrawerCloseDirective,
|
|
40
|
+
DrawerComponent,
|
|
41
|
+
DrawerDescriptionComponent,
|
|
42
|
+
DrawerFooterComponent,
|
|
43
|
+
DrawerHeaderComponent,
|
|
44
|
+
DrawerTitleComponent,
|
|
45
|
+
],
|
|
46
|
+
template: `
|
|
47
|
+
<button type="button" Button variant="outline" (click)="open.set(true)">Open Drawer</button>
|
|
48
|
+
|
|
49
|
+
<Drawer [(open)]="open" aria-labelledby="drawer-title" aria-describedby="drawer-description">
|
|
50
|
+
<div class="mx-auto w-full max-w-sm">
|
|
51
|
+
<DrawerHeader>
|
|
52
|
+
<DrawerTitle id="drawer-title">Move Goal</DrawerTitle>
|
|
53
|
+
<DrawerDescription id="drawer-description"
|
|
54
|
+
>Set your daily activity goal.</DrawerDescription
|
|
55
|
+
>
|
|
56
|
+
</DrawerHeader>
|
|
57
|
+
<DrawerFooter>
|
|
58
|
+
<button type="button" Button>Submit</button>
|
|
59
|
+
<button type="button" Button variant="outline" DrawerClose>Cancel</button>
|
|
60
|
+
</DrawerFooter>
|
|
61
|
+
</div>
|
|
62
|
+
</Drawer>
|
|
63
|
+
`,
|
|
64
|
+
})
|
|
65
|
+
export class DrawerExampleComponent {
|
|
66
|
+
protected readonly open = signal(false);
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Common Patterns
|
|
71
|
+
|
|
72
|
+
### Sides
|
|
73
|
+
|
|
74
|
+
Drawer defaults to `bottom`, matching the common shadcn and Vaul pattern. Set `side` when the drawer should enter from a different edge.
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<Drawer [(open)]="open" side="right" aria-labelledby="drawer-side-title">
|
|
78
|
+
<DrawerHeader>
|
|
79
|
+
<DrawerTitle id="drawer-side-title">Scrollable Content</DrawerTitle>
|
|
80
|
+
</DrawerHeader>
|
|
81
|
+
<DrawerContent class="max-h-[50vh] overflow-y-auto px-1">
|
|
82
|
+
<!-- long content -->
|
|
83
|
+
</DrawerContent>
|
|
84
|
+
</Drawer>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Responsive Dialog
|
|
88
|
+
|
|
89
|
+
Use a desktop breakpoint in the owning component and render Dialog for larger viewports, Drawer for smaller viewports. Keep both surfaces bound to the same `open` signal so trigger and submit actions stay consistent.
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
@if (isDesktop()) {
|
|
93
|
+
<dialog [(open)]="open">...</dialog>
|
|
94
|
+
} @else {
|
|
95
|
+
<Drawer [(open)]="open">...</Drawer>
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## API Reference
|
|
100
|
+
|
|
101
|
+
### DrawerComponent
|
|
102
|
+
|
|
103
|
+
| Input | Type | Default |
|
|
104
|
+
| ---------------------- | ---------------------------------------- | ----------------------- |
|
|
105
|
+
| `open` | `boolean` model | `false` |
|
|
106
|
+
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'bottom'` for `Drawer` |
|
|
107
|
+
| `closeOnEscape` | `boolean` | `true` |
|
|
108
|
+
| `closeOnBackdropClick` | `boolean` | `true` |
|
|
109
|
+
| `aria-labelledby` | `string \| null` | `null` |
|
|
110
|
+
| `aria-describedby` | `string \| null` | `null` |
|
|
111
|
+
| `class` | `string` | empty string |
|
|
112
|
+
|
|
113
|
+
### Parts
|
|
114
|
+
|
|
115
|
+
| Part | Purpose |
|
|
116
|
+
| --------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
117
|
+
| `DrawerHeader` | Title and description wrapper. |
|
|
118
|
+
| `DrawerTitle` | Accessible title. Provide an `id` and connect it with `aria-labelledby`. |
|
|
119
|
+
| `DrawerDescription` | Supporting text. Provide an `id` and connect it with `aria-describedby` when useful. |
|
|
120
|
+
| `DrawerContent` | Optional scroll/body region inside the surface. |
|
|
121
|
+
| `DrawerFooter` | Action row. |
|
|
122
|
+
| `button[DrawerClose]`, `a[DrawerClose]` | Projected close action equivalent to shadcn `DrawerClose`. |
|
|
123
|
+
|
|
124
|
+
## Styling And Theming
|
|
125
|
+
|
|
126
|
+
The drawer uses the same theme tokens as Sheet: `bg-background`, `border-border`, `text-foreground`, and `text-muted-foreground`. Pass `class` to tune dimensions such as `max-h-[85vh]`, `sm:max-w-md`, or side-specific scroll behavior.
|
|
127
|
+
|
|
128
|
+
## Accessibility
|
|
129
|
+
|
|
130
|
+
- The surface renders with `role="dialog"` and `aria-modal="true"`.
|
|
131
|
+
- Focus is trapped inside the CDK overlay while open and restored to the previously focused element on close.
|
|
132
|
+
- Provide `aria-labelledby` and `aria-describedby` when the drawer contains a title and description.
|
|
133
|
+
- Use native buttons for open, submit, and close actions.
|
|
134
|
+
|
|
135
|
+
## Keyboard Interactions
|
|
136
|
+
|
|
137
|
+
- `Tab` and `Shift+Tab` move within the focus-trapped drawer content.
|
|
138
|
+
- `Escape` closes the drawer when `closeOnEscape` is `true`.
|
|
139
|
+
- Enter and Space activate native buttons, including `button[DrawerClose]`.
|
|
140
|
+
|
|
141
|
+
## Angular Notes
|
|
142
|
+
|
|
143
|
+
The Angular Drawer deliberately uses an external trigger button and `[(open)]` signal binding instead of a `DrawerTrigger` component. This keeps ownership of state explicit and avoids hidden context wiring across overlay portals. `DrawerComponent` is exported as an alias over the same implementation as `SheetComponent`, so fixes to focus management, backdrop dismissal, and edge positioning are shared.
|
|
144
|
+
|
|
145
|
+
## Source Parity
|
|
146
|
+
|
|
147
|
+
shadcn Drawer is built on Vaul and includes drag gestures and scale-background options. This Angular version maps the core modal drawer behavior to CDK Overlay and FocusTrap: bottom-first direction, side selection, focus trapping, Escape/backdrop dismissal, close actions, scrollable content, responsive dialog composition, and RTL-friendly content. It does not implement Vaul drag gestures.
|