@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,286 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeStandalone = writeStandalone;
|
|
4
|
+
exports.writeLibrary = writeLibrary;
|
|
5
|
+
exports.writeSecondaryEntrypoint = writeSecondaryEntrypoint;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const template_1 = require("../render/template");
|
|
9
|
+
const ROOT_ENTRYPOINT = '';
|
|
10
|
+
const VIRTUAL_ROOT = '/__sdk__';
|
|
11
|
+
/**
|
|
12
|
+
* No-op writer for the standalone mode — returns emitted files unchanged. Kept
|
|
13
|
+
* as a named function so modes are composable from a single switch at the
|
|
14
|
+
* engine layer.
|
|
15
|
+
*/
|
|
16
|
+
function writeStandalone(files) {
|
|
17
|
+
return files;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Library mode: add `ng-package.json`, `package.json`, and a top-level README
|
|
21
|
+
* so the `output` folder can be built with ng-packagr directly.
|
|
22
|
+
*/
|
|
23
|
+
function writeLibrary(files, ir, target, workspaceRoot, outputDir) {
|
|
24
|
+
const normalizedFiles = rewriteCrossEntrypointImports(files, target, workspaceRoot, outputDir);
|
|
25
|
+
const ngPackage = {
|
|
26
|
+
$schema: toPosixPath((0, node_path_1.relative)(outputDir, (0, node_path_1.resolve)(workspaceRoot, 'node_modules/ng-packagr/ng-package.schema.json'))),
|
|
27
|
+
dest: resolveLibraryDestPath(workspaceRoot, outputDir),
|
|
28
|
+
lib: { entryFile: 'public-api.ts' },
|
|
29
|
+
};
|
|
30
|
+
const pkg = {
|
|
31
|
+
name: target.packageName,
|
|
32
|
+
version: target.packageVersion,
|
|
33
|
+
description: `Generated SDK for ${ir.title} ${ir.version}`,
|
|
34
|
+
peerDependencies: {
|
|
35
|
+
'@angular/common': '>=22.1.0',
|
|
36
|
+
'@angular/core': '>=22.1.0',
|
|
37
|
+
rxjs: '>=7.8.0',
|
|
38
|
+
},
|
|
39
|
+
sideEffects: false,
|
|
40
|
+
};
|
|
41
|
+
return [
|
|
42
|
+
...normalizedFiles,
|
|
43
|
+
createNgPackageFile('ng-package.json', ngPackage),
|
|
44
|
+
...createNestedEntrypointNgPackages(normalizedFiles),
|
|
45
|
+
{
|
|
46
|
+
path: 'package.json',
|
|
47
|
+
content: (0, template_1.finalize)(JSON.stringify(pkg, null, 2)),
|
|
48
|
+
},
|
|
49
|
+
...createLibraryTsConfigFiles(workspaceRoot, outputDir),
|
|
50
|
+
{
|
|
51
|
+
path: 'README.md',
|
|
52
|
+
content: (0, template_1.finalize)(`# ${target.packageName}\n\nGenerated SDK for **${ir.title}** v${ir.version}.\n\nThis folder was generated by the local SDK generator. Do not edit by hand.\n`),
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Secondary-entrypoint mode: same file set as standalone, plus a minimal
|
|
58
|
+
* `ng-package.json` pointing at `public-api.ts`. Meant to live **inside** an
|
|
59
|
+
* existing library (e.g. `projects/angular/sdk-api/`) so ng-packagr picks it
|
|
60
|
+
* up automatically as a secondary entrypoint of the parent library.
|
|
61
|
+
*/
|
|
62
|
+
function writeSecondaryEntrypoint(files, _ir, target, workspaceRoot, outputDir) {
|
|
63
|
+
const normalizedFiles = rewriteCrossEntrypointImports(files, target, workspaceRoot, outputDir);
|
|
64
|
+
const ngPackage = {
|
|
65
|
+
lib: { entryFile: 'public-api.ts' },
|
|
66
|
+
};
|
|
67
|
+
return [
|
|
68
|
+
...normalizedFiles,
|
|
69
|
+
createNgPackageFile('ng-package.json', ngPackage),
|
|
70
|
+
...createNestedEntrypointNgPackages(normalizedFiles),
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
function rewriteCrossEntrypointImports(files, target, workspaceRoot, outputDir) {
|
|
74
|
+
const entrypointDirs = collectEntrypointDirs(files);
|
|
75
|
+
if (entrypointDirs.length <= 1) {
|
|
76
|
+
return [...files];
|
|
77
|
+
}
|
|
78
|
+
const packageImportBase = resolvePackageImportBase(target, workspaceRoot, outputDir);
|
|
79
|
+
if (!packageImportBase) {
|
|
80
|
+
return [...files];
|
|
81
|
+
}
|
|
82
|
+
const knownFiles = new Set(files.map((file) => file.path));
|
|
83
|
+
return files.map((file) => {
|
|
84
|
+
const owner = findEntrypointOwner(file.path, entrypointDirs);
|
|
85
|
+
return {
|
|
86
|
+
...file,
|
|
87
|
+
content: file.content.replace(/(from\s+['"])([^'"]+)(['"])/g, (_match, prefix, spec, suffix) => {
|
|
88
|
+
const nextSpec = rewriteModuleSpecifier(spec, file.path, owner, entrypointDirs, knownFiles, packageImportBase);
|
|
89
|
+
return `${prefix}${nextSpec}${suffix}`;
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function rewriteModuleSpecifier(specifier, currentPath, currentOwner, entrypointDirs, knownFiles, packageImportBase) {
|
|
95
|
+
if (!specifier.startsWith('./') && !specifier.startsWith('../')) {
|
|
96
|
+
return specifier;
|
|
97
|
+
}
|
|
98
|
+
const targetPath = resolveVirtualFilePath(currentPath, specifier, knownFiles);
|
|
99
|
+
if (!targetPath) {
|
|
100
|
+
return specifier;
|
|
101
|
+
}
|
|
102
|
+
const targetOwner = findEntrypointOwner(targetPath, entrypointDirs);
|
|
103
|
+
if (targetOwner === currentOwner) {
|
|
104
|
+
return specifier;
|
|
105
|
+
}
|
|
106
|
+
return buildEntrypointImport(packageImportBase, targetOwner);
|
|
107
|
+
}
|
|
108
|
+
function resolveVirtualFilePath(currentPath, specifier, knownFiles) {
|
|
109
|
+
const currentAbs = node_path_1.posix.join(VIRTUAL_ROOT, currentPath);
|
|
110
|
+
const resolved = node_path_1.posix.normalize(node_path_1.posix.join((0, node_path_1.dirname)(currentAbs), specifier));
|
|
111
|
+
const candidates = [
|
|
112
|
+
`${resolved}.ts`,
|
|
113
|
+
`${resolved}/index.ts`,
|
|
114
|
+
`${resolved}/public-api.ts`,
|
|
115
|
+
resolved,
|
|
116
|
+
];
|
|
117
|
+
for (const candidate of candidates) {
|
|
118
|
+
if (!candidate.startsWith(`${VIRTUAL_ROOT}/`)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const relativePath = candidate.slice(VIRTUAL_ROOT.length + 1);
|
|
122
|
+
if (knownFiles.has(relativePath)) {
|
|
123
|
+
return relativePath;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
function resolvePackageImportBase(target, workspaceRoot, outputDir) {
|
|
129
|
+
if (target.mode === 'library') {
|
|
130
|
+
return target.packageName;
|
|
131
|
+
}
|
|
132
|
+
if (target.mode !== 'secondary-entrypoint') {
|
|
133
|
+
return '';
|
|
134
|
+
}
|
|
135
|
+
return inferSecondaryEntrypointPackageName(workspaceRoot, outputDir, target.packageName);
|
|
136
|
+
}
|
|
137
|
+
function inferSecondaryEntrypointPackageName(workspaceRoot, outputDir, fallback) {
|
|
138
|
+
let currentDir = outputDir;
|
|
139
|
+
let nearestPackageDir;
|
|
140
|
+
let nearestPackagrDir;
|
|
141
|
+
while (isWithinWorkspace(currentDir, workspaceRoot)) {
|
|
142
|
+
const packageJsonPath = (0, node_path_1.resolve)(currentDir, 'package.json');
|
|
143
|
+
if ((0, node_fs_1.existsSync)(packageJsonPath)) {
|
|
144
|
+
nearestPackageDir ??= currentDir;
|
|
145
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(currentDir, 'ng-package.json'))) {
|
|
146
|
+
nearestPackagrDir = currentDir;
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (currentDir === workspaceRoot) {
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
const parentDir = (0, node_path_1.dirname)(currentDir);
|
|
154
|
+
if (parentDir === currentDir) {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
currentDir = parentDir;
|
|
158
|
+
}
|
|
159
|
+
const packageDir = nearestPackagrDir ?? nearestPackageDir;
|
|
160
|
+
if (!packageDir) {
|
|
161
|
+
return fallback;
|
|
162
|
+
}
|
|
163
|
+
const packageName = readPackageName(packageDir);
|
|
164
|
+
if (!packageName) {
|
|
165
|
+
return fallback;
|
|
166
|
+
}
|
|
167
|
+
const relativeOutput = toPosixPath((0, node_path_1.relative)(packageDir, outputDir)).replace(/^\.\//, '');
|
|
168
|
+
if (!relativeOutput || relativeOutput === '.') {
|
|
169
|
+
return packageName;
|
|
170
|
+
}
|
|
171
|
+
return `${packageName}/${relativeOutput}`;
|
|
172
|
+
}
|
|
173
|
+
function readPackageName(packageDir) {
|
|
174
|
+
const packageJsonPath = (0, node_path_1.resolve)(packageDir, 'package.json');
|
|
175
|
+
if (!(0, node_fs_1.existsSync)(packageJsonPath)) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
let raw;
|
|
179
|
+
try {
|
|
180
|
+
raw = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf8'));
|
|
181
|
+
}
|
|
182
|
+
catch (cause) {
|
|
183
|
+
throw new Error(`Failed to read ${packageJsonPath}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
184
|
+
}
|
|
185
|
+
return typeof raw.name === 'string' && raw.name.length > 0 ? raw.name : undefined;
|
|
186
|
+
}
|
|
187
|
+
function isWithinWorkspace(candidate, workspaceRoot) {
|
|
188
|
+
const rel = (0, node_path_1.relative)(workspaceRoot, candidate);
|
|
189
|
+
return rel === '' || (!rel.startsWith('..') && !(0, node_path_1.isAbsolute)(rel));
|
|
190
|
+
}
|
|
191
|
+
function collectEntrypointDirs(files) {
|
|
192
|
+
const dirs = new Set();
|
|
193
|
+
for (const file of files) {
|
|
194
|
+
if (file.path === 'public-api.ts') {
|
|
195
|
+
dirs.add(ROOT_ENTRYPOINT);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (!file.path.endsWith('/public-api.ts')) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
dirs.add(file.path.slice(0, -'/public-api.ts'.length));
|
|
202
|
+
}
|
|
203
|
+
return [...dirs].sort((left, right) => right.length - left.length || left.localeCompare(right));
|
|
204
|
+
}
|
|
205
|
+
function findEntrypointOwner(filePath, entrypointDirs) {
|
|
206
|
+
for (const entrypointDir of entrypointDirs) {
|
|
207
|
+
if (entrypointDir === ROOT_ENTRYPOINT) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (filePath === `${entrypointDir}/public-api.ts` || filePath.startsWith(`${entrypointDir}/`)) {
|
|
211
|
+
return entrypointDir;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return ROOT_ENTRYPOINT;
|
|
215
|
+
}
|
|
216
|
+
function buildEntrypointImport(packageImportBase, entrypointDir) {
|
|
217
|
+
return entrypointDir ? `${packageImportBase}/${entrypointDir}` : packageImportBase;
|
|
218
|
+
}
|
|
219
|
+
function createNestedEntrypointNgPackages(files) {
|
|
220
|
+
return collectSecondaryEntrypointDirs(files).map((dir) => createNgPackageFile(`${dir}/ng-package.json`, {
|
|
221
|
+
lib: { entryFile: 'public-api.ts' },
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
function collectSecondaryEntrypointDirs(files) {
|
|
225
|
+
const dirs = new Set();
|
|
226
|
+
for (const file of files) {
|
|
227
|
+
if (!file.path.endsWith('/public-api.ts')) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
dirs.add(file.path.slice(0, -'/public-api.ts'.length));
|
|
231
|
+
}
|
|
232
|
+
return [...dirs].sort();
|
|
233
|
+
}
|
|
234
|
+
function resolveLibraryDestPath(workspaceRoot, outputDir) {
|
|
235
|
+
const outputFolderName = (0, node_path_1.basename)(outputDir) || 'sdk';
|
|
236
|
+
return toPosixPath((0, node_path_1.relative)(outputDir, (0, node_path_1.resolve)(workspaceRoot, 'dist', outputFolderName)));
|
|
237
|
+
}
|
|
238
|
+
function createLibraryTsConfigFiles(workspaceRoot, outputDir) {
|
|
239
|
+
const rootTsConfig = toPosixPath((0, node_path_1.relative)(outputDir, (0, node_path_1.resolve)(workspaceRoot, 'tsconfig.json')));
|
|
240
|
+
const outDir = toPosixPath((0, node_path_1.relative)(outputDir, (0, node_path_1.resolve)(workspaceRoot, 'out-tsc/lib')));
|
|
241
|
+
const distDir = toRecursiveGlob((0, node_path_1.relative)(outputDir, (0, node_path_1.resolve)(workspaceRoot, 'dist')));
|
|
242
|
+
const nodeModulesDir = toRecursiveGlob((0, node_path_1.relative)(outputDir, (0, node_path_1.resolve)(workspaceRoot, 'node_modules')));
|
|
243
|
+
const tsconfigLib = {
|
|
244
|
+
extends: rootTsConfig,
|
|
245
|
+
compilerOptions: {
|
|
246
|
+
outDir,
|
|
247
|
+
declaration: true,
|
|
248
|
+
declarationMap: true,
|
|
249
|
+
types: [],
|
|
250
|
+
},
|
|
251
|
+
include: ['public-api.ts', '**/public-api.ts'],
|
|
252
|
+
exclude: ['**/*.spec.ts', distDir, nodeModulesDir],
|
|
253
|
+
};
|
|
254
|
+
const tsconfigLibProd = {
|
|
255
|
+
extends: './tsconfig.lib.json',
|
|
256
|
+
compilerOptions: {
|
|
257
|
+
declarationMap: false,
|
|
258
|
+
},
|
|
259
|
+
angularCompilerOptions: {
|
|
260
|
+
compilationMode: 'partial',
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
return [
|
|
264
|
+
{
|
|
265
|
+
path: 'tsconfig.lib.json',
|
|
266
|
+
content: (0, template_1.finalize)(JSON.stringify(tsconfigLib, null, 2)),
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
path: 'tsconfig.lib.prod.json',
|
|
270
|
+
content: (0, template_1.finalize)(JSON.stringify(tsconfigLibProd, null, 2)),
|
|
271
|
+
},
|
|
272
|
+
];
|
|
273
|
+
}
|
|
274
|
+
function toRecursiveGlob(value) {
|
|
275
|
+
const normalized = toPosixPath(value).replace(/\/+$/, '');
|
|
276
|
+
return normalized === '.' ? './**' : `${normalized}/**`;
|
|
277
|
+
}
|
|
278
|
+
function toPosixPath(value) {
|
|
279
|
+
return value.split('\\').join('/');
|
|
280
|
+
}
|
|
281
|
+
function createNgPackageFile(path, content) {
|
|
282
|
+
return {
|
|
283
|
+
path,
|
|
284
|
+
content: (0, template_1.finalize)(JSON.stringify(content, null, 2)),
|
|
285
|
+
};
|
|
286
|
+
}
|
package/theme/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @ojiepermana/angular/theme
|
|
2
|
+
|
|
3
|
+
Theme layer for the `@ojiepermana/angular` design system: a runtime provider
|
|
4
|
+
(mode / color / neutral / brand), design tokens, and the Tailwind v4 CSS that the
|
|
5
|
+
components are styled against.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @ojiepermana/angular
|
|
9
|
+
# or: npm install @ojiepermana/angular
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Everything below is reached through the `theme` subpath of that one package.
|
|
13
|
+
|
|
14
|
+
## Entry points
|
|
15
|
+
|
|
16
|
+
| Import path | Contents |
|
|
17
|
+
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| `@ojiepermana/angular/theme/styles` | `provideUiTheme`, `ThemeModeService`, `ThemeColorService`, `ThemeBrandService`, `ThemeRadiusService`, `ThemeSpaceService`, … |
|
|
19
|
+
| `@ojiepermana/angular/theme/component/settings` | Navigation-aligned right-side settings drawer; theme axes plus optional consumer-owned layout/navigation adapter |
|
|
20
|
+
| `@ojiepermana/angular/theme/layout` | Layout shell building blocks |
|
|
21
|
+
| `@ojiepermana/angular/theme/shell` | Application shell root: `<Shell>` with `mode` / `device` / `color` axes, its own desktop titlebar, and the Tauri/Electron window bridge |
|
|
22
|
+
| `@ojiepermana/angular/theme/page` | Page-level scaffolding |
|
|
23
|
+
| `@ojiepermana/angular/theme/theme.css` | Base tokens + component styles only — lightweight, no runtime axes |
|
|
24
|
+
| `@ojiepermana/angular/theme/theme-full.css` | Base + every runtime axis (color, neutral, radius, space) — needed for `ThemeColorService`/`ThemeNeutralService` switching |
|
|
25
|
+
| `@ojiepermana/angular/theme/styles/css/*` | Raw CSS assets (per-axis color + neutral palettes, Tailwind map) |
|
|
26
|
+
|
|
27
|
+
## Tailwind v4 setup
|
|
28
|
+
|
|
29
|
+
The CSS is published with the package and addressable by name. Use `theme-full.css`
|
|
30
|
+
for the full design system (runtime color/neutral switching); use the lightweight
|
|
31
|
+
`theme.css` plus only the axes you need for a smaller bundle.
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
/* styles.css — full design system */
|
|
35
|
+
@import '@ojiepermana/angular/theme/theme-full.css'; /* base + all color + neutral palettes */
|
|
36
|
+
@import 'tailwindcss';
|
|
37
|
+
@import '@ojiepermana/angular/theme/styles/css/base/tailwind.css'; /* maps tokens → bg-primary, bg-brand, text-foreground, … */
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For a lightweight setup, import the base then opt in to specific axes:
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
/* styles.css — base + only the axes you use */
|
|
44
|
+
@import '@ojiepermana/angular/theme/theme.css'; /* base tokens + components, no axes */
|
|
45
|
+
@import 'tailwindcss';
|
|
46
|
+
@import '@ojiepermana/angular/theme/styles/css/base/tailwind.css';
|
|
47
|
+
@import '@ojiepermana/angular/theme/styles/css/color/index.css'; /* opt in to accent palettes */
|
|
48
|
+
@import '@ojiepermana/angular/theme/styles/css/neutral/index.css'; /* opt in to neutral families */
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Requires Tailwind CSS `^4.3.0`.
|
|
52
|
+
|
|
53
|
+
## Provider
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { provideUiTheme } from '@ojiepermana/angular/theme/styles';
|
|
57
|
+
|
|
58
|
+
export const appConfig = {
|
|
59
|
+
providers: [
|
|
60
|
+
provideUiTheme({
|
|
61
|
+
mode: 'light',
|
|
62
|
+
color: 'base', // accent palette (base, red…rose, brand)
|
|
63
|
+
neutral: 'base', // gray family (base, slate, gray, zinc, …)
|
|
64
|
+
radius: 'md', // corner radius preset (none, xs, sm, md, xl, full)
|
|
65
|
+
space: 'normal', // spacing density preset (compact, normal, relaxed, spacious)
|
|
66
|
+
brand: { color: '221 83% 53%', foreground: '0 0% 100%' }, // consumer brand
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `mode` — bootstraps `ThemeModeService` and persists the default mode (`light` / `dark` / `system`).
|
|
73
|
+
- `color` — bootstraps `ThemeColorService`; initial accent palette (`<html theme-color>`).
|
|
74
|
+
- `neutral` — initial neutral family (`<html theme-neutral>`); composes with any accent.
|
|
75
|
+
- `radius` — bootstraps `ThemeRadiusService`; initial corner-radius preset (`<html theme-radius>`).
|
|
76
|
+
Drives the single `--radius-base` knob so the whole `--radius-*` scale and `rounded-*`
|
|
77
|
+
utilities follow. Values: `none`, `xs`, `sm`, `md` (default), `xl`, `full`;
|
|
78
|
+
each uses Tailwind's stock radius value with the same name.
|
|
79
|
+
- `space` — bootstraps `ThemeSpaceService`; initial spacing-density preset (`<html theme-space>`).
|
|
80
|
+
Drives the single `--spacing-base` knob so every `p-*` / `m-*` / `gap-*` / `w-*` / `h-*`
|
|
81
|
+
utility follows. Values: `compact`, `normal` (default), `relaxed`, `spacious`.
|
|
82
|
+
- `brand` — bootstraps `ThemeBrandService`; sets `--brand` / `bg-brand` and the
|
|
83
|
+
`theme-color='brand'` accent preset. Accepts an HSL triplet string (`'221 83% 53%'`)
|
|
84
|
+
or `{ color, foreground }`. Settable at runtime via `setBrand()`.
|
|
85
|
+
|
|
86
|
+
A persisted choice (localStorage `theme-color` / `theme-neutral` / `theme-radius` /
|
|
87
|
+
`theme-space` / `theme-brand`) always wins over the configured default.
|
|
88
|
+
|
|
89
|
+
### Color system (FluxUI-style)
|
|
90
|
+
|
|
91
|
+
Four independent axes switch at runtime via attribute selectors on `<html>`:
|
|
92
|
+
|
|
93
|
+
- **accent** (`theme-color`) — `base` (core), `red … rose`, and `brand`. Each
|
|
94
|
+
re-tints the full palette. `base` = no override.
|
|
95
|
+
- **neutral** (`theme-neutral`) — `base` (core), `slate`, `gray`, `zinc`, `neutral`,
|
|
96
|
+
`stone`, `mauve`, `olive`, `mist`, `taupe`. Overrides the gray family and Layout's
|
|
97
|
+
decorative pattern source, and is layered after accent so it wins both token groups.
|
|
98
|
+
With neutral `base`, surface patterns follow the active accent; every other neutral
|
|
99
|
+
gives them its own soft family hue.
|
|
100
|
+
- **radius** (`theme-radius`) — `none`, `xs`, `sm`, `md` (default), `xl`, `full`.
|
|
101
|
+
Sets the `--radius-base` knob; the full `--radius-*` scale and `rounded-*` utilities follow.
|
|
102
|
+
- **space** (`theme-space`) — `compact`, `normal` (default), `relaxed`, `spacious`.
|
|
103
|
+
Sets the `--spacing-base` knob; every `p-*` / `m-*` / `gap-*` / `w-*` / `h-*` utility follows.
|
|
104
|
+
|
|
105
|
+
`theme-full.css` (i.e. `styles/css/index.css`) bundles the core base theme plus
|
|
106
|
+
every accent and neutral palette, so switching needs no runtime CSS loading. The
|
|
107
|
+
lightweight `theme.css` ships base only — import the axis files you need on top of
|
|
108
|
+
it (or use `theme-full.css`) to enable runtime switching.
|
|
109
|
+
|
|
110
|
+
### Material Symbols icons (opt-in)
|
|
111
|
+
|
|
112
|
+
`provideUiTheme()` makes **no external network request by default**. To preload the
|
|
113
|
+
Material Symbols font from Google Fonts:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
provideUiTheme({ icons: { materialSymbols: true } });
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Leave it off (the default) for privacy / offline / strict CSP, and self-host the
|
|
120
|
+
font in your own stylesheet if you need it.
|
|
121
|
+
|
|
122
|
+
## Support and security
|
|
123
|
+
|
|
124
|
+
Angular 22.1–22.x CSR/browser usage is supported; SSR, prerendering, and hydration are not. See the
|
|
125
|
+
bundled `SUPPORT.md`. Report suspected vulnerabilities privately using the instructions in the
|
|
126
|
+
bundled `SECURITY.md`. This package is MIT licensed; see the bundled `LICENSE`.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Theme settings
|
|
2
|
+
|
|
3
|
+
Navigation-aligned settings inspector for the runtime theme axes. It is a
|
|
4
|
+
right-side drawer with an optional native button or link-style trigger. Theme
|
|
5
|
+
choices apply and persist immediately; an optional adapter also exposes layout
|
|
6
|
+
and navigation preferences.
|
|
7
|
+
|
|
8
|
+
## Import
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { ThemeSettingsComponent } from '@ojiepermana/angular/theme/component/settings';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Navigation button
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
@Component({
|
|
18
|
+
imports: [ThemeSettingsComponent],
|
|
19
|
+
template: `
|
|
20
|
+
<NavigationFooterAction>
|
|
21
|
+
<ThemeSettings trigger-icon-only />
|
|
22
|
+
</NavigationFooterAction>
|
|
23
|
+
`,
|
|
24
|
+
})
|
|
25
|
+
export class AppNavigation {}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The built-in button is focusable, exposes `aria-haspopup="dialog"` and reflects
|
|
29
|
+
the drawer state with `aria-expanded`. Use `trigger="link"` when the trigger
|
|
30
|
+
should read as a text link while retaining button semantics for the action.
|
|
31
|
+
|
|
32
|
+
## External state
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<button type="button" (click)="themeOpen.set(true)">Personalize theme</button>
|
|
36
|
+
<ThemeSettings [(open)]="themeOpen" [show-trigger]="false" />
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The drawer uses the shared Drawer/Sheet overlay: focus is trapped while it is
|
|
40
|
+
open; Escape, backdrop click, and the close controls dismiss it; focus returns
|
|
41
|
+
to the opening trigger. Its header and footer use the navigation topbar height,
|
|
42
|
+
semantic borders, and theme tokens so it sits naturally beside a layout shell.
|
|
43
|
+
|
|
44
|
+
## Shell
|
|
45
|
+
|
|
46
|
+
Directly below **Theme** sits a **Shell** section with all three shell axes, driven
|
|
47
|
+
by `ShellService` — so they need no adapter and each persists to its own key:
|
|
48
|
+
|
|
49
|
+
| Control | Values | Storage key |
|
|
50
|
+
| -------------- | --------------------------------------- | -------------- |
|
|
51
|
+
| `Shell mode` | `web` / `desktop` / `tablet` / `mobile` | `shell-mode` |
|
|
52
|
+
| `Shell device` | the devices the active mode can host | `shell-device` |
|
|
53
|
+
| `Shell color` | `Sync` / `Native` | `shell-color` |
|
|
54
|
+
|
|
55
|
+
`Shell device` is filtered by the active mode rather than showing all seven with
|
|
56
|
+
most disabled — `web` hosts one device, `desktop` three. It also displays the value
|
|
57
|
+
`<Shell>` would actually render: `ShellService.device()` is a _preference_ that may
|
|
58
|
+
belong to another form factor (a stored `macos` survives a temporary `web` mode), so
|
|
59
|
+
the control shows that preference corrected to the current mode.
|
|
60
|
+
|
|
61
|
+
`Shell color` decides whether the desktop titlebar follows the theme axes above
|
|
62
|
+
(`sync`) or paints the active device's own native chrome (`default`).
|
|
63
|
+
|
|
64
|
+
`Shell mode` constrains the next section: everything but `web` owns the whole surface, so
|
|
65
|
+
there is no page for the layout frame to be inset within. On those modes the width
|
|
66
|
+
picker is disabled down to `full` and says why — see
|
|
67
|
+
[`@ojiepermana/angular/theme/shell`](../../shell/README.md#mode-locks-the-layout-width).
|
|
68
|
+
The user's own width choice is preserved, not overwritten, so switching back to
|
|
69
|
+
`web` restores it.
|
|
70
|
+
|
|
71
|
+
## Layout and navigation adapter
|
|
72
|
+
|
|
73
|
+
The Theme and Shell sections are always available in any app using
|
|
74
|
+
`provideUiTheme()`. The ordered **Layout** and **Navigation** sections need an
|
|
75
|
+
adapter on `THEME_SETTINGS_ADAPTER`. Use the published default:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { provideThemeSettingsAdapter } from '@ojiepermana/angular/theme/component/settings';
|
|
79
|
+
|
|
80
|
+
export const appConfig = {
|
|
81
|
+
providers: [provideUiTheme({ ... }), provideThemeSettingsAdapter()],
|
|
82
|
+
};
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`ThemeSettingsDefaultAdapter` delegates surface, appearance, and width to
|
|
86
|
+
`LayoutService`, and owns layout type, nav type, and nav type mode itself —
|
|
87
|
+
`<Layout>` writes `type` back to follow nav orientation, so reading
|
|
88
|
+
`layout.type()` would drift from the operator's choice. It persists those three
|
|
89
|
+
under `layout-type`, `nav-type`, and `nav-type-mode`, reads them back with a safe
|
|
90
|
+
fallback, and stores nothing but presentation choices. Storage that is missing,
|
|
91
|
+
blocked, or holding a foreign value falls back to the default without throwing.
|
|
92
|
+
|
|
93
|
+
Incoherent axis pairs auto-correct, so the rendered shell never lands in an
|
|
94
|
+
impossible state. The rules are exported for consumers building their own
|
|
95
|
+
settings panel:
|
|
96
|
+
|
|
97
|
+
| Helper | Answers |
|
|
98
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
99
|
+
| `allowedNavTypes()` | which nav types a layout type and shell mode allow |
|
|
100
|
+
| `allowedNavTypeModes()` | which presentation modes a nav type offers |
|
|
101
|
+
| `isWidthEnabled()` | whether `fluid` width means anything for a layout type |
|
|
102
|
+
|
|
103
|
+
A consumer that needs different behavior can still implement
|
|
104
|
+
`ThemeSettingsAdapter` by hand and provide it on the token directly; the default
|
|
105
|
+
adapter is a convenience, not a requirement.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import {
|
|
109
|
+
THEME_SETTINGS_ADAPTER,
|
|
110
|
+
type ThemeSettingsAdapter,
|
|
111
|
+
} from '@ojiepermana/angular/theme/component/settings';
|
|
112
|
+
|
|
113
|
+
@Service()
|
|
114
|
+
export class AppLayoutSettings implements ThemeSettingsAdapter {
|
|
115
|
+
// Signals: appearance, surface, layoutType, width, navType, navTypeMode
|
|
116
|
+
// Setters for each axis; persist the values in the consumer app.
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export const appConfig = {
|
|
120
|
+
providers: [{ provide: THEME_SETTINGS_ADAPTER, useExisting: AppLayoutSettings }],
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`navTypeMode` is contextual: sidebar supports **Default** / **Collapsed**,
|
|
125
|
+
dockbar supports **Sticky** / **Drawer**, and horizontal navigation stays at
|
|
126
|
+
**Default**.
|
|
127
|
+
|
|
128
|
+
For `shell mode = desktop` together with `layoutType = horizontal`, `navType`
|
|
129
|
+
has exactly one valid value: **Desktop**. This is a shell choice rather than a
|
|
130
|
+
fifth navigation primitive: the desktop titlebar remains the chrome, while the
|
|
131
|
+
wrapper hides desktop/mobile navigation and gives the content the same focused
|
|
132
|
+
behavior as an `empty` layout. Persist it through
|
|
133
|
+
`ThemeSettingsNavigationType`; entering that shell/layout pair normalizes the
|
|
134
|
+
value to `desktop`, while leaving it normalizes to the first valid nav for the
|
|
135
|
+
new combination.
|