@julianoczkowski/create-trimble-app 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -0
- package/bin/create-trimble-app.js +9 -0
- package/package.json +67 -0
- package/src/cli.js +134 -0
- package/src/frameworks.js +28 -0
- package/src/scaffold.js +209 -0
- package/src/utils/file.js +47 -0
- package/src/utils/git.js +140 -0
- package/src/utils/install.js +25 -0
- package/src/utils/logger.js +124 -0
- package/templates/angular/.cursor/commands/remove-dev-content.md +394 -0
- package/templates/angular/.cursor/mcp.json +13 -0
- package/templates/angular/.cursor/rules/modus-angular-20.mdc +82 -0
- package/templates/angular/.cursor/rules/modus-angular-accordion-state-management-short.mdc +45 -0
- package/templates/angular/.cursor/rules/modus-angular-accordion-state-management.mdc +322 -0
- package/templates/angular/.cursor/rules/modus-angular-best-practices.mdc +472 -0
- package/templates/angular/.cursor/rules/modus-angular-border-usage-short.mdc +48 -0
- package/templates/angular/.cursor/rules/modus-angular-border-usage.mdc +286 -0
- package/templates/angular/.cursor/rules/modus-angular-button-group-usage-short.mdc +47 -0
- package/templates/angular/.cursor/rules/modus-angular-button-group-usage.mdc +263 -0
- package/templates/angular/.cursor/rules/modus-angular-checkbox-value-inversion-short.mdc +36 -0
- package/templates/angular/.cursor/rules/modus-angular-checkbox-value-inversion.mdc +92 -0
- package/templates/angular/.cursor/rules/modus-angular-chrome-devtools-testing-short.mdc +34 -0
- package/templates/angular/.cursor/rules/modus-angular-chrome-devtools-testing.mdc +185 -0
- package/templates/angular/.cursor/rules/modus-angular-color-usage-short.mdc +56 -0
- package/templates/angular/.cursor/rules/modus-angular-color-usage.mdc +208 -0
- package/templates/angular/.cursor/rules/modus-angular-components-reference.mdc +114 -0
- package/templates/angular/.cursor/rules/modus-angular-design-system.mdc +273 -0
- package/templates/angular/.cursor/rules/modus-angular-development-workflow-short.mdc +43 -0
- package/templates/angular/.cursor/rules/modus-angular-development-workflow.mdc +145 -0
- package/templates/angular/.cursor/rules/modus-angular-essentials.mdc +272 -0
- package/templates/angular/.cursor/rules/modus-angular-forms-validation-short.mdc +56 -0
- package/templates/angular/.cursor/rules/modus-angular-forms-validation.mdc +124 -0
- package/templates/angular/.cursor/rules/modus-angular-icon-names.mdc +70 -0
- package/templates/angular/.cursor/rules/modus-angular-icons-short.mdc +40 -0
- package/templates/angular/.cursor/rules/modus-angular-icons.mdc +137 -0
- package/templates/angular/.cursor/rules/modus-angular-implementation-guides-short.mdc +36 -0
- package/templates/angular/.cursor/rules/modus-angular-implementation-guides.mdc +301 -0
- package/templates/angular/.cursor/rules/modus-angular-integration-short.mdc +60 -0
- package/templates/angular/.cursor/rules/modus-angular-integration.mdc +1096 -0
- package/templates/angular/.cursor/rules/modus-angular-master.mdc +164 -0
- package/templates/angular/.cursor/rules/modus-angular-modal-usage-short.mdc +51 -0
- package/templates/angular/.cursor/rules/modus-angular-modal-usage.mdc +115 -0
- package/templates/angular/.cursor/rules/modus-angular-navbar-usage-short.mdc +49 -0
- package/templates/angular/.cursor/rules/modus-angular-navbar-usage.mdc +146 -0
- package/templates/angular/.cursor/rules/modus-angular-no-emojis.mdc +66 -0
- package/templates/angular/.cursor/rules/modus-angular-opacity-utilities-short.mdc +43 -0
- package/templates/angular/.cursor/rules/modus-angular-opacity-utilities.mdc +160 -0
- package/templates/angular/.cursor/rules/modus-angular-select-vs-dropdown-menu-short.mdc +51 -0
- package/templates/angular/.cursor/rules/modus-angular-select-vs-dropdown-menu.mdc +83 -0
- package/templates/angular/.cursor/rules/modus-angular-semantic-html-short.mdc +36 -0
- package/templates/angular/.cursor/rules/modus-angular-semantic-html.mdc +81 -0
- package/templates/angular/.cursor/rules/modus-angular-side-navigation-usage-short.mdc +50 -0
- package/templates/angular/.cursor/rules/modus-angular-side-navigation-usage.mdc +136 -0
- package/templates/angular/.cursor/rules/modus-angular-table-usage-short.mdc +52 -0
- package/templates/angular/.cursor/rules/modus-angular-table-usage.mdc +151 -0
- package/templates/angular/.cursor/rules/modus-angular-tailwind-usage-short.mdc +44 -0
- package/templates/angular/.cursor/rules/modus-angular-tailwind-usage.mdc +242 -0
- package/templates/angular/.cursor/rules/modus-angular-themes-short.mdc +54 -0
- package/templates/angular/.cursor/rules/modus-angular-themes.mdc +222 -0
- package/templates/angular/.cursor/rules/modus-angular-utility-panel-usage-short.mdc +52 -0
- package/templates/angular/.cursor/rules/modus-angular-utility-panel-usage.mdc +130 -0
- package/templates/angular/.cursor/rules/ux/gestalt-laws-detailed.mdc +514 -0
- package/templates/angular/.cursor/rules/ux/ux-ui-foundations.mdc +235 -0
- package/templates/angular/.cursor/skills/run-lint-checks/SKILL.md +169 -0
- package/templates/angular/.editorconfig +17 -0
- package/templates/angular/.github/dependabot.yml +19 -0
- package/templates/angular/.github/workflows/a11y-check.yml +135 -0
- package/templates/angular/.github/workflows/ci.yml +44 -0
- package/templates/angular/.husky/pre-commit +32 -0
- package/templates/angular/.postcssrc.json +5 -0
- package/templates/angular/.vscode/extensions.json +4 -0
- package/templates/angular/.vscode/launch.json +20 -0
- package/templates/angular/.vscode/tasks.json +42 -0
- package/templates/angular/CLAUDE.md +148 -0
- package/templates/angular/README.md +92 -0
- package/templates/angular/amplify.yml +25 -0
- package/templates/angular/angular.json +106 -0
- package/templates/angular/data/modusIcons.ts +861 -0
- package/templates/angular/package-lock.json +11030 -0
- package/templates/angular/package.json +66 -0
- package/templates/angular/public/angular-icon.svg +12 -0
- package/templates/angular/public/favicon.ico +0 -0
- package/templates/angular/public/modus-icons.css +49 -0
- package/templates/angular/public/vite.svg +1 -0
- package/templates/angular/scripts/README.md +410 -0
- package/templates/angular/scripts/check-border-violations.js +352 -0
- package/templates/angular/scripts/check-icon-names.js +402 -0
- package/templates/angular/scripts/check-inline-styles.js +292 -0
- package/templates/angular/scripts/check-modus-colors.js +282 -0
- package/templates/angular/scripts/check-modus-icons.js +263 -0
- package/templates/angular/scripts/check-opacity-utilities.js +426 -0
- package/templates/angular/scripts/check-semantic-html.js +452 -0
- package/templates/angular/scripts/check-typescript.js +109 -0
- package/templates/angular/src/app/app.config.ts +29 -0
- package/templates/angular/src/app/app.css +0 -0
- package/templates/angular/src/app/app.html +4 -0
- package/templates/angular/src/app/app.routes.ts +351 -0
- package/templates/angular/src/app/app.spec.ts +27 -0
- package/templates/angular/src/app/app.ts +47 -0
- package/templates/angular/src/app/components/README.md +77 -0
- package/templates/angular/src/app/components/index.ts +53 -0
- package/templates/angular/src/app/components/modus-accordion.component.ts +50 -0
- package/templates/angular/src/app/components/modus-alert.component.ts +133 -0
- package/templates/angular/src/app/components/modus-autocomplete.component.ts +262 -0
- package/templates/angular/src/app/components/modus-avatar.component.ts +75 -0
- package/templates/angular/src/app/components/modus-badge.component.ts +84 -0
- package/templates/angular/src/app/components/modus-breadcrumbs.component.ts +65 -0
- package/templates/angular/src/app/components/modus-button-group.component.ts +82 -0
- package/templates/angular/src/app/components/modus-button.component.ts +292 -0
- package/templates/angular/src/app/components/modus-card.component.ts +73 -0
- package/templates/angular/src/app/components/modus-checkbox.component.ts +117 -0
- package/templates/angular/src/app/components/modus-chip.component.ts +97 -0
- package/templates/angular/src/app/components/modus-collapse.component.ts +118 -0
- package/templates/angular/src/app/components/modus-date.component.ts +165 -0
- package/templates/angular/src/app/components/modus-dropdown-menu.component.ts +108 -0
- package/templates/angular/src/app/components/modus-file-dropzone.component.ts +121 -0
- package/templates/angular/src/app/components/modus-handle.component.ts +96 -0
- package/templates/angular/src/app/components/modus-icon.component.ts +81 -0
- package/templates/angular/src/app/components/modus-input-feedback.component.ts +54 -0
- package/templates/angular/src/app/components/modus-input-label.component.ts +62 -0
- package/templates/angular/src/app/components/modus-loader.component.ts +48 -0
- package/templates/angular/src/app/components/modus-logo.component.ts +115 -0
- package/templates/angular/src/app/components/modus-menu-item.component.ts +116 -0
- package/templates/angular/src/app/components/modus-menu.component.ts +58 -0
- package/templates/angular/src/app/components/modus-modal.component.ts +70 -0
- package/templates/angular/src/app/components/modus-navbar.component.ts +303 -0
- package/templates/angular/src/app/components/modus-number-input.component.ts +174 -0
- package/templates/angular/src/app/components/modus-pagination.component.ts +74 -0
- package/templates/angular/src/app/components/modus-panel.component.ts +61 -0
- package/templates/angular/src/app/components/modus-progress.component.ts +62 -0
- package/templates/angular/src/app/components/modus-radio.component.ts +102 -0
- package/templates/angular/src/app/components/modus-rating.component.ts +80 -0
- package/templates/angular/src/app/components/modus-select.component.ts +131 -0
- package/templates/angular/src/app/components/modus-side-navigation.component.ts +90 -0
- package/templates/angular/src/app/components/modus-skeleton.component.ts +54 -0
- package/templates/angular/src/app/components/modus-slider.component.ts +132 -0
- package/templates/angular/src/app/components/modus-stepper.component.ts +65 -0
- package/templates/angular/src/app/components/modus-switch.component.ts +118 -0
- package/templates/angular/src/app/components/modus-table.component.ts +204 -0
- package/templates/angular/src/app/components/modus-tabs.component.ts +82 -0
- package/templates/angular/src/app/components/modus-text-input.component.ts +221 -0
- package/templates/angular/src/app/components/modus-textarea.component.ts +168 -0
- package/templates/angular/src/app/components/modus-theme-switcher.component.ts +45 -0
- package/templates/angular/src/app/components/modus-time-input.component.ts +172 -0
- package/templates/angular/src/app/components/modus-toast.component.ts +63 -0
- package/templates/angular/src/app/components/modus-toolbar.component.ts +43 -0
- package/templates/angular/src/app/components/modus-tooltip.component.ts +83 -0
- package/templates/angular/src/app/components/modus-typography.component.ts +79 -0
- package/templates/angular/src/app/components/modus-utility-panel.component.ts +275 -0
- package/templates/angular/src/app/components/theme-demo.component.ts +1242 -0
- package/templates/angular/src/app/data/component-demos.ts +360 -0
- package/templates/angular/src/app/data/modus-icons.ts +806 -0
- package/templates/angular/src/app/demos/accordion/accordion-demo.component.ts +212 -0
- package/templates/angular/src/app/demos/alert/alert-demo.component.ts +108 -0
- package/templates/angular/src/app/demos/autocomplete/autocomplete-demo.component.ts +174 -0
- package/templates/angular/src/app/demos/avatar/avatar-demo.component.ts +149 -0
- package/templates/angular/src/app/demos/badge/badge-demo.component.ts +148 -0
- package/templates/angular/src/app/demos/breadcrumbs/breadcrumbs-demo.component.ts +96 -0
- package/templates/angular/src/app/demos/button/button-demo.component.ts +256 -0
- package/templates/angular/src/app/demos/button-group/button-group-demo.component.ts +215 -0
- package/templates/angular/src/app/demos/card/card-demo.component.ts +180 -0
- package/templates/angular/src/app/demos/checkbox/checkbox-demo.component.ts +71 -0
- package/templates/angular/src/app/demos/chip/chip-demo.component.ts +183 -0
- package/templates/angular/src/app/demos/date/date-demo.component.ts +193 -0
- package/templates/angular/src/app/demos/dropdown/dropdown-demo.component.ts +196 -0
- package/templates/angular/src/app/demos/file-dropzone/file-dropzone-demo.component.ts +176 -0
- package/templates/angular/src/app/demos/handle/handle-demo.component.ts +265 -0
- package/templates/angular/src/app/demos/icon/icon-demo.component.ts +65 -0
- package/templates/angular/src/app/demos/input-feedback/input-feedback-demo.component.ts +189 -0
- package/templates/angular/src/app/demos/input-label/input-label-demo.component.ts +330 -0
- package/templates/angular/src/app/demos/loader/loader-demo.component.ts +143 -0
- package/templates/angular/src/app/demos/logo/logo-demo.component.ts +191 -0
- package/templates/angular/src/app/demos/menu/menu-demo.component.ts +72 -0
- package/templates/angular/src/app/demos/modal/modal-demo.component.ts +278 -0
- package/templates/angular/src/app/demos/navbar/navbar-demo.component.ts +135 -0
- package/templates/angular/src/app/demos/number-input/number-input-demo.component.ts +175 -0
- package/templates/angular/src/app/demos/pagination/pagination-demo.component.ts +134 -0
- package/templates/angular/src/app/demos/panel/panel-demo.component.ts +235 -0
- package/templates/angular/src/app/demos/progress/progress-demo.component.ts +169 -0
- package/templates/angular/src/app/demos/radio/radio-demo.component.ts +161 -0
- package/templates/angular/src/app/demos/rating/rating-demo.component.ts +97 -0
- package/templates/angular/src/app/demos/select/select-demo.component.ts +107 -0
- package/templates/angular/src/app/demos/shared/demo-example-clean.component.ts +41 -0
- package/templates/angular/src/app/demos/shared/demo-example.component.ts +42 -0
- package/templates/angular/src/app/demos/shared/demo-page.component.ts +97 -0
- package/templates/angular/src/app/demos/shared/index.ts +3 -0
- package/templates/angular/src/app/demos/side-navigation/side-navigation-demo.component.ts +524 -0
- package/templates/angular/src/app/demos/skeleton/skeleton-demo.component.ts +112 -0
- package/templates/angular/src/app/demos/slider/slider-demo.component.ts +76 -0
- package/templates/angular/src/app/demos/stepper/stepper-demo.component.ts +79 -0
- package/templates/angular/src/app/demos/switch/switch-demo.component.ts +113 -0
- package/templates/angular/src/app/demos/table/table-demo.component.ts +405 -0
- package/templates/angular/src/app/demos/tabs/tabs-demo.component.ts +318 -0
- package/templates/angular/src/app/demos/text-input/text-input-demo.component.ts +160 -0
- package/templates/angular/src/app/demos/textarea/textarea-demo.component.ts +95 -0
- package/templates/angular/src/app/demos/theme-switcher/theme-switcher-demo.component.ts +38 -0
- package/templates/angular/src/app/demos/time-input/time-input-demo.component.ts +130 -0
- package/templates/angular/src/app/demos/toast/toast-demo.component.ts +258 -0
- package/templates/angular/src/app/demos/toolbar/toolbar-demo.component.ts +54 -0
- package/templates/angular/src/app/demos/tooltip/tooltip-demo.component.ts +163 -0
- package/templates/angular/src/app/demos/utility-panel/utility-panel-demo.component.ts +197 -0
- package/templates/angular/src/app/dev/dev-config.ts +119 -0
- package/templates/angular/src/app/dev/dev-panel/dev-panel.component.ts +215 -0
- package/templates/angular/src/app/dev/dev-panel.service.ts +63 -0
- package/templates/angular/src/app/dev/index.ts +8 -0
- package/templates/angular/src/app/dev/theme-switcher-dropdown/theme-switcher-dropdown.component.ts +134 -0
- package/templates/angular/src/app/dev-pages/color-palette/color-palette.component.ts +229 -0
- package/templates/angular/src/app/dev-pages/components-gallery/components-gallery.component.ts +486 -0
- package/templates/angular/src/app/dev-pages/icons/icons.component.ts +149 -0
- package/templates/angular/src/app/pages/home/home.component.ts +251 -0
- package/templates/angular/src/app/services/README.md +57 -0
- package/templates/angular/src/app/services/theme.service.ts +163 -0
- package/templates/angular/src/environments/environment.development.ts +8 -0
- package/templates/angular/src/environments/environment.ts +8 -0
- package/templates/angular/src/index.html +14 -0
- package/templates/angular/src/main.ts +6 -0
- package/templates/angular/src/styles.css +1328 -0
- package/templates/angular/tsconfig.app.json +15 -0
- package/templates/angular/tsconfig.json +35 -0
- package/templates/angular/tsconfig.spec.json +14 -0
- package/templates/config.json +23 -0
- package/templates/react/.cursor/commands/remove-dev-content.md +311 -0
- package/templates/react/.cursor/mcp.json +13 -0
- package/templates/react/.cursor/rules/README.md +240 -0
- package/templates/react/.cursor/rules/border-usage-guidelines-short.mdc +22 -0
- package/templates/react/.cursor/rules/border-usage-guidelines.mdc +380 -0
- package/templates/react/.cursor/rules/chrome-devtools-testing-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/development-workflow-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/development-workflow-react.mdc +292 -0
- package/templates/react/.cursor/rules/implementation-guides-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/implementation-guides-react.mdc +446 -0
- package/templates/react/.cursor/rules/modus-accordion-state-management-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-accordion-state-management-react.mdc +445 -0
- package/templates/react/.cursor/rules/modus-button-group-usage-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-button-group-usage-react.mdc +117 -0
- package/templates/react/.cursor/rules/modus-checkbox-value-inversion-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-checkbox-value-inversion-react.mdc +492 -0
- package/templates/react/.cursor/rules/modus-color-usage-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-color-usage-react.mdc +420 -0
- package/templates/react/.cursor/rules/modus-components-reference.mdc +366 -0
- package/templates/react/.cursor/rules/modus-icon-names.mdc +63 -0
- package/templates/react/.cursor/rules/modus-icons-react-short.mdc +24 -0
- package/templates/react/.cursor/rules/modus-icons-react.mdc +402 -0
- package/templates/react/.cursor/rules/modus-modal-implementation-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-modal-implementation-react.mdc +831 -0
- package/templates/react/.cursor/rules/modus-navbar-side-navigation-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-navbar-side-navigation-react.mdc +247 -0
- package/templates/react/.cursor/rules/modus-no-emojis-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-opacity-utilities-react-short.mdc +70 -0
- package/templates/react/.cursor/rules/modus-opacity-utilities-react.mdc +208 -0
- package/templates/react/.cursor/rules/modus-react-best-practices-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-react-best-practices.mdc +508 -0
- package/templates/react/.cursor/rules/modus-react-essentials.mdc +209 -0
- package/templates/react/.cursor/rules/modus-react-integration-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-react-integration.mdc +509 -0
- package/templates/react/.cursor/rules/modus-react-key-warnings-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-react-key-warnings.mdc +805 -0
- package/templates/react/.cursor/rules/modus-react-master.mdc +160 -0
- package/templates/react/.cursor/rules/modus-select-vs-dropdown-menu-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-select-vs-dropdown-menu-react.mdc +442 -0
- package/templates/react/.cursor/rules/modus-semantic-html-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-semantic-html-react.mdc +427 -0
- package/templates/react/.cursor/rules/modus-tailwind-usage-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-tailwind-usage-react.mdc +642 -0
- package/templates/react/.cursor/rules/modus-themes-react-short.mdc +23 -0
- package/templates/react/.cursor/rules/modus-themes-react.mdc +506 -0
- package/templates/react/.cursor/rules/ux/gestalt-laws-detailed.mdc +456 -0
- package/templates/react/.cursor/rules/ux/ux-ui-foundations.mdc +211 -0
- package/templates/react/.cursor/skills/create-modus-form-component/SKILL.md +518 -0
- package/templates/react/.cursor/skills/create-modus-wrapper-component/SKILL.md +252 -0
- package/templates/react/.cursor/skills/fix-modus-component-event-issues/SKILL.md +345 -0
- package/templates/react/.cursor/skills/handle-modus-checkbox-value-bug/SKILL.md +202 -0
- package/templates/react/.cursor/skills/implement-modus-modal-with-refs/SKILL.md +386 -0
- package/templates/react/.cursor/skills/integrate-modus-icons/SKILL.md +300 -0
- package/templates/react/.cursor/skills/run-lint-checks/SKILL.md +235 -0
- package/templates/react/.cursor/skills/set-up-modus-event-listeners/SKILL.md +284 -0
- package/templates/react/.cursor/skills/style-modus-components-with-tailwind/SKILL.md +382 -0
- package/templates/react/.env.development +3 -0
- package/templates/react/.env.production +3 -0
- package/templates/react/.github/CODEOWNERS +28 -0
- package/templates/react/.github/ISSUE_TEMPLATE/bug_report.yml +176 -0
- package/templates/react/.github/ISSUE_TEMPLATE/config.yml +20 -0
- package/templates/react/.github/ISSUE_TEMPLATE/documentation.yml +115 -0
- package/templates/react/.github/ISSUE_TEMPLATE/feature_request.yml +171 -0
- package/templates/react/.github/ISSUE_TEMPLATE/question.yml +139 -0
- package/templates/react/.github/copilot-instructions.md +80 -0
- package/templates/react/.github/instructions/components.instructions.md +82 -0
- package/templates/react/.github/instructions/demos.instructions.md +82 -0
- package/templates/react/.github/instructions/pages.instructions.md +76 -0
- package/templates/react/.github/instructions/styles.instructions.md +77 -0
- package/templates/react/.github/instructions/typescript.instructions.md +101 -0
- package/templates/react/.github/pull_request_template.md +188 -0
- package/templates/react/.github/workflows/ci.yml +43 -0
- package/templates/react/.github/workflows/claude-code-review.yml +44 -0
- package/templates/react/.github/workflows/claude.yml +50 -0
- package/templates/react/.husky/pre-commit +28 -0
- package/templates/react/.vscode/extensions.json +8 -0
- package/templates/react/CLAUDE.md +119 -0
- package/templates/react/CODE_OF_CONDUCT.md +79 -0
- package/templates/react/CONTRIBUTING.md +65 -0
- package/templates/react/LICENSE +21 -0
- package/templates/react/README.md +728 -0
- package/templates/react/SECURITY.md +50 -0
- package/templates/react/eslint.config.js +23 -0
- package/templates/react/index.html +13 -0
- package/templates/react/package-lock.json +5209 -0
- package/templates/react/package.json +49 -0
- package/templates/react/postcss.config.js +6 -0
- package/templates/react/public/react.svg +1 -0
- package/templates/react/public/vite.svg +1 -0
- package/templates/react/readme_assets/getting_started_header.png +0 -0
- package/templates/react/readme_assets/hero.png +0 -0
- package/templates/react/readme_assets/modus_comp.png +0 -0
- package/templates/react/readme_assets/modus_figma_mcp.png +0 -0
- package/templates/react/readme_assets/teaser_comp.gif +0 -0
- package/templates/react/scripts/README.md +343 -0
- package/templates/react/scripts/check-border-violations.js +483 -0
- package/templates/react/scripts/check-icon-names.js +486 -0
- package/templates/react/scripts/check-inline-styles.js +364 -0
- package/templates/react/scripts/check-modus-colors.js +247 -0
- package/templates/react/scripts/check-modus-icons.js +256 -0
- package/templates/react/scripts/check-opacity-utilities.js +481 -0
- package/templates/react/scripts/check-semantic-html.js +476 -0
- package/templates/react/scripts/check-typescript.js +109 -0
- package/templates/react/src/App.css +42 -0
- package/templates/react/src/App.tsx +54 -0
- package/templates/react/src/assets/react.svg +1 -0
- package/templates/react/src/components/DemoExample.tsx +61 -0
- package/templates/react/src/components/DemoPage.tsx +81 -0
- package/templates/react/src/components/ModusAccordion.tsx +89 -0
- package/templates/react/src/components/ModusAlert.tsx +85 -0
- package/templates/react/src/components/ModusAutocomplete.tsx +207 -0
- package/templates/react/src/components/ModusAvatar.tsx +50 -0
- package/templates/react/src/components/ModusBadge.tsx +82 -0
- package/templates/react/src/components/ModusBreadcrumbs.tsx +75 -0
- package/templates/react/src/components/ModusButton.tsx +244 -0
- package/templates/react/src/components/ModusButtonGroup.tsx +91 -0
- package/templates/react/src/components/ModusCard.tsx +70 -0
- package/templates/react/src/components/ModusCheckbox.tsx +168 -0
- package/templates/react/src/components/ModusChip.tsx +93 -0
- package/templates/react/src/components/ModusDate.tsx +154 -0
- package/templates/react/src/components/ModusDropdownMenu.tsx +148 -0
- package/templates/react/src/components/ModusFileDropzone.tsx +140 -0
- package/templates/react/src/components/ModusHandle.tsx +101 -0
- package/templates/react/src/components/ModusIcon.tsx +49 -0
- package/templates/react/src/components/ModusInputFeedback.tsx +52 -0
- package/templates/react/src/components/ModusInputLabel.tsx +50 -0
- package/templates/react/src/components/ModusLoader.tsx +42 -0
- package/templates/react/src/components/ModusLogo.tsx +102 -0
- package/templates/react/src/components/ModusMenu.tsx +119 -0
- package/templates/react/src/components/ModusMenuItem.tsx +86 -0
- package/templates/react/src/components/ModusModal.tsx +145 -0
- package/templates/react/src/components/ModusNavbar.tsx +504 -0
- package/templates/react/src/components/ModusNumberInput.tsx +230 -0
- package/templates/react/src/components/ModusPagination.tsx +94 -0
- package/templates/react/src/components/ModusPanel.tsx +92 -0
- package/templates/react/src/components/ModusProgress.tsx +70 -0
- package/templates/react/src/components/ModusProvider.tsx +18 -0
- package/templates/react/src/components/ModusRadio.tsx +114 -0
- package/templates/react/src/components/ModusRating.tsx +108 -0
- package/templates/react/src/components/ModusSelect.tsx +171 -0
- package/templates/react/src/components/ModusSideNavigation.tsx +149 -0
- package/templates/react/src/components/ModusSkeleton.tsx +42 -0
- package/templates/react/src/components/ModusSlider.tsx +128 -0
- package/templates/react/src/components/ModusStepper.tsx +85 -0
- package/templates/react/src/components/ModusSwitch.tsx +130 -0
- package/templates/react/src/components/ModusTable.tsx +309 -0
- package/templates/react/src/components/ModusTabs.tsx +114 -0
- package/templates/react/src/components/ModusTextInput.tsx +179 -0
- package/templates/react/src/components/ModusTextarea.tsx +164 -0
- package/templates/react/src/components/ModusThemeSwitcher.tsx +58 -0
- package/templates/react/src/components/ModusTimeInput.tsx +176 -0
- package/templates/react/src/components/ModusToast.tsx +207 -0
- package/templates/react/src/components/ModusToolbar.tsx +70 -0
- package/templates/react/src/components/ModusTooltip.tsx +97 -0
- package/templates/react/src/components/ModusUtilityPanel.tsx +198 -0
- package/templates/react/src/components/ThemeSwitcherDropdown.tsx +117 -0
- package/templates/react/src/components/ThemeToggleSimple.tsx +157 -0
- package/templates/react/src/config/routes.ts +196 -0
- package/templates/react/src/contexts/ThemeContext.tsx +81 -0
- package/templates/react/src/contexts/ThemeContextData.tsx +89 -0
- package/templates/react/src/data/modusIcons.ts +865 -0
- package/templates/react/src/demos/accordion-demo/page.tsx +236 -0
- package/templates/react/src/demos/alert-demo/page.tsx +94 -0
- package/templates/react/src/demos/autocomplete-demo/page.tsx +166 -0
- package/templates/react/src/demos/avatar-demo/page.tsx +135 -0
- package/templates/react/src/demos/badge-demo/page.tsx +174 -0
- package/templates/react/src/demos/breadcrumbs-demo/page.tsx +88 -0
- package/templates/react/src/demos/button-demo/page.tsx +261 -0
- package/templates/react/src/demos/button-group-demo/page.tsx +231 -0
- package/templates/react/src/demos/card-demo/page.tsx +241 -0
- package/templates/react/src/demos/checkbox-demo/page.tsx +79 -0
- package/templates/react/src/demos/chip-demo/page.tsx +197 -0
- package/templates/react/src/demos/date-demo/page.tsx +179 -0
- package/templates/react/src/demos/dropdown-demo/page.tsx +150 -0
- package/templates/react/src/demos/file-dropzone-demo/page.tsx +186 -0
- package/templates/react/src/demos/handle-demo/page.tsx +313 -0
- package/templates/react/src/demos/icon-demo/page.tsx +72 -0
- package/templates/react/src/demos/input-feedback-demo/page.tsx +202 -0
- package/templates/react/src/demos/input-label-demo/page.tsx +392 -0
- package/templates/react/src/demos/loader-demo/page.tsx +138 -0
- package/templates/react/src/demos/logo-demo/page.tsx +292 -0
- package/templates/react/src/demos/menu-demo/page.tsx +70 -0
- package/templates/react/src/demos/modal-demo/page.tsx +332 -0
- package/templates/react/src/demos/navbar-demo/page.tsx +141 -0
- package/templates/react/src/demos/number-input-demo/page.tsx +180 -0
- package/templates/react/src/demos/pagination-demo/page.tsx +147 -0
- package/templates/react/src/demos/panel-demo/page.tsx +376 -0
- package/templates/react/src/demos/progress-demo/page.tsx +185 -0
- package/templates/react/src/demos/radio-demo/page.tsx +242 -0
- package/templates/react/src/demos/rating-demo/page.tsx +97 -0
- package/templates/react/src/demos/select-demo/page.tsx +111 -0
- package/templates/react/src/demos/side-navigation-demo/page.tsx +775 -0
- package/templates/react/src/demos/skeleton-demo/page.tsx +107 -0
- package/templates/react/src/demos/slider-demo/page.tsx +78 -0
- package/templates/react/src/demos/stepper-demo/page.tsx +86 -0
- package/templates/react/src/demos/switch-demo/page.tsx +146 -0
- package/templates/react/src/demos/table-demo/page.tsx +489 -0
- package/templates/react/src/demos/tabs-demo/page.tsx +187 -0
- package/templates/react/src/demos/text-input-demo/page.tsx +151 -0
- package/templates/react/src/demos/textarea-demo/page.tsx +73 -0
- package/templates/react/src/demos/theme-switcher-demo/page.tsx +26 -0
- package/templates/react/src/demos/time-input-demo/page.tsx +148 -0
- package/templates/react/src/demos/toast-demo/page.tsx +302 -0
- package/templates/react/src/demos/toolbar-demo/page.tsx +49 -0
- package/templates/react/src/demos/tooltip-demo/page.tsx +209 -0
- package/templates/react/src/demos/typography-test/page.tsx +28 -0
- package/templates/react/src/demos/utility-panel-demo/page.tsx +197 -0
- package/templates/react/src/dev/DevPanel.tsx +219 -0
- package/templates/react/src/dev/DevPanelContext.ts +14 -0
- package/templates/react/src/dev/DevPanelProvider.tsx +63 -0
- package/templates/react/src/dev/DevRoutes.tsx +98 -0
- package/templates/react/src/dev/config.ts +127 -0
- package/templates/react/src/dev/index.ts +8 -0
- package/templates/react/src/dev/useDevPanel.ts +17 -0
- package/templates/react/src/dev-pages/ColorPalettePage.tsx +347 -0
- package/templates/react/src/dev-pages/ComponentsGalleryPage.tsx +489 -0
- package/templates/react/src/dev-pages/IconsPage.tsx +137 -0
- package/templates/react/src/dev-pages/index.ts +3 -0
- package/templates/react/src/hooks/useTheme.ts +15 -0
- package/templates/react/src/index.css +635 -0
- package/templates/react/src/main.tsx +14 -0
- package/templates/react/src/pages/HomePage.tsx +283 -0
- package/templates/react/src/vite-env.d.ts +9 -0
- package/templates/react/tailwind.config.js +58 -0
- package/templates/react/tsconfig.app.json +27 -0
- package/templates/react/tsconfig.json +7 -0
- package/templates/react/tsconfig.node.json +25 -0
- package/templates/react/vite.config.ts +18 -0
|
@@ -0,0 +1,775 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
4
|
+
import DemoExample from "../../components/DemoExample";
|
|
5
|
+
import DemoPage from "../../components/DemoPage";
|
|
6
|
+
import ModusNavbar from "../../components/ModusNavbar";
|
|
7
|
+
import {
|
|
8
|
+
ModusWcSideNavigation,
|
|
9
|
+
ModusWcMenu,
|
|
10
|
+
ModusWcMenuItem,
|
|
11
|
+
ModusWcIcon,
|
|
12
|
+
} from "@trimble-oss/moduswebcomponents-react";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Demo page showcasing the Modus Side Navigation component.
|
|
16
|
+
*
|
|
17
|
+
* Demonstrates side navigation features including:
|
|
18
|
+
* - Navbar integration (recommended pattern)
|
|
19
|
+
* - Icons that remain visible when collapsed
|
|
20
|
+
* - Push mode layout
|
|
21
|
+
* - State management with React hooks
|
|
22
|
+
* - Interactive examples with state management
|
|
23
|
+
*/
|
|
24
|
+
export default function SideNavigationDemoPage() {
|
|
25
|
+
// ============================================
|
|
26
|
+
// First example state (Navbar Integration)
|
|
27
|
+
// ============================================
|
|
28
|
+
const [navbarMenuExpanded, setNavbarMenuExpanded] = useState(false);
|
|
29
|
+
const [selectedItem1, setSelectedItem1] = useState<string | null>("home");
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
+
const sideNavRef1 = useRef<any>(null);
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
const menuRef1 = useRef<any>(null);
|
|
34
|
+
|
|
35
|
+
// User card configuration for first example
|
|
36
|
+
const userCard1 = {
|
|
37
|
+
name: "John Doe",
|
|
38
|
+
email: "john.doe@example.com",
|
|
39
|
+
avatarSrc: "",
|
|
40
|
+
avatarAlt: "User Avatar",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// ============================================
|
|
44
|
+
// Second example state (Sub-Menu)
|
|
45
|
+
// ============================================
|
|
46
|
+
const [subMenuNavbarExpanded, setSubMenuNavbarExpanded] = useState(false);
|
|
47
|
+
const [subMenuStates, setSubMenuStates] = useState<Record<string, boolean>>({
|
|
48
|
+
charts: false,
|
|
49
|
+
maps: false,
|
|
50
|
+
"map-2": false,
|
|
51
|
+
});
|
|
52
|
+
const [selectedSubMenuItem, setSelectedSubMenuItem] = useState<string | null>(
|
|
53
|
+
null,
|
|
54
|
+
);
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
+
const sideNavRef2 = useRef<any>(null);
|
|
57
|
+
|
|
58
|
+
// User card configuration for second example
|
|
59
|
+
const userCard2 = {
|
|
60
|
+
name: "Jane Smith",
|
|
61
|
+
email: "jane.smith@example.com",
|
|
62
|
+
avatarSrc: "",
|
|
63
|
+
avatarAlt: "User Avatar",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// ============================================
|
|
67
|
+
// Helper functions (must be defined before useEffect)
|
|
68
|
+
// ============================================
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Handles expand change events (Storybook pattern).
|
|
72
|
+
* Collapses all child containers and resets icons when side navigation collapses.
|
|
73
|
+
*/
|
|
74
|
+
const handleExpandChange = useCallback((event: CustomEvent<boolean>) => {
|
|
75
|
+
if (!event.detail) {
|
|
76
|
+
const sideNav = sideNavRef2.current;
|
|
77
|
+
if (!sideNav) return;
|
|
78
|
+
|
|
79
|
+
// Find the parent container of the side navigation
|
|
80
|
+
const container = sideNav.closest(
|
|
81
|
+
".layout-with-navbar",
|
|
82
|
+
) as HTMLElement;
|
|
83
|
+
|
|
84
|
+
if (container) {
|
|
85
|
+
// Collapse all child containers if the side navigation is collapsed
|
|
86
|
+
const childrenContainers = container.querySelectorAll(
|
|
87
|
+
".side-nav-children-container",
|
|
88
|
+
);
|
|
89
|
+
childrenContainers.forEach((containerEl: Element) => {
|
|
90
|
+
containerEl.classList.add("side-nav-hidden");
|
|
91
|
+
containerEl.setAttribute("aria-hidden", "true");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Reset all collapse icons to expand_more
|
|
95
|
+
const collapseIcons = container.querySelectorAll(
|
|
96
|
+
".side-nav-dropdown-toggle",
|
|
97
|
+
);
|
|
98
|
+
collapseIcons.forEach((icon: Element) => {
|
|
99
|
+
if (icon.getAttribute("name") === "expand_less") {
|
|
100
|
+
icon.setAttribute("name", "expand_more");
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}, []);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Collapses all sub-menus (called when side navigation collapses).
|
|
109
|
+
*/
|
|
110
|
+
const collapseAllSubMenus = useCallback(() => {
|
|
111
|
+
console.log("Collapsing all sub-menus");
|
|
112
|
+
setSubMenuStates({
|
|
113
|
+
charts: false,
|
|
114
|
+
maps: false,
|
|
115
|
+
"map-2": false,
|
|
116
|
+
});
|
|
117
|
+
}, []);
|
|
118
|
+
|
|
119
|
+
// ============================================
|
|
120
|
+
// Navbar menu change handlers
|
|
121
|
+
// ============================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Handles navbar main menu open state changes for first example.
|
|
125
|
+
* This is triggered when the hamburger menu button is clicked.
|
|
126
|
+
*/
|
|
127
|
+
const handleNavbarMenuOpenChange1 = useCallback((isOpen: boolean) => {
|
|
128
|
+
console.log("Navbar main menu open change 1 - received:", isOpen);
|
|
129
|
+
// Just update React state - useEffect will sync to web component
|
|
130
|
+
setNavbarMenuExpanded(isOpen);
|
|
131
|
+
}, []);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Handles navbar main menu open state changes for second example.
|
|
135
|
+
*/
|
|
136
|
+
const handleNavbarMenuOpenChange2 = useCallback(
|
|
137
|
+
(isOpen: boolean) => {
|
|
138
|
+
console.log("Navbar main menu open change 2 - received:", isOpen);
|
|
139
|
+
// Just update React state - useEffect will sync to web component
|
|
140
|
+
setSubMenuNavbarExpanded(isOpen);
|
|
141
|
+
|
|
142
|
+
// Collapse all sub-menus when side navigation collapses
|
|
143
|
+
if (!isOpen) {
|
|
144
|
+
collapseAllSubMenus();
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
[collapseAllSubMenus],
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// ============================================
|
|
151
|
+
// Sync expanded prop to web component
|
|
152
|
+
// ============================================
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Syncs React state to side navigation web component for first example.
|
|
156
|
+
*/
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
const sideNav = sideNavRef1.current;
|
|
159
|
+
if (sideNav && sideNav.expanded !== navbarMenuExpanded) {
|
|
160
|
+
sideNav.expanded = navbarMenuExpanded;
|
|
161
|
+
}
|
|
162
|
+
}, [navbarMenuExpanded]);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Syncs React state to side navigation web component for second example.
|
|
166
|
+
*/
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
const sideNav = sideNavRef2.current;
|
|
169
|
+
if (sideNav && sideNav.expanded !== subMenuNavbarExpanded) {
|
|
170
|
+
sideNav.expanded = subMenuNavbarExpanded;
|
|
171
|
+
}
|
|
172
|
+
}, [subMenuNavbarExpanded]);
|
|
173
|
+
|
|
174
|
+
// ============================================
|
|
175
|
+
// Side navigation expanded change handlers
|
|
176
|
+
// ============================================
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Handles side navigation expanded state changes for first example.
|
|
180
|
+
* This syncs React state when side nav changes independently (e.g., click outside).
|
|
181
|
+
*/
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
const sideNav = sideNavRef1.current;
|
|
184
|
+
if (!sideNav) return;
|
|
185
|
+
|
|
186
|
+
const handleExpandedChange = (event: Event) => {
|
|
187
|
+
const customEvent = event as CustomEvent<boolean>;
|
|
188
|
+
const isExpanded = customEvent.detail;
|
|
189
|
+
console.log("Side navigation 1 expanded change:", isExpanded);
|
|
190
|
+
|
|
191
|
+
// Only update state if it's different to avoid circular updates
|
|
192
|
+
setNavbarMenuExpanded((prev) => {
|
|
193
|
+
if (prev !== isExpanded) {
|
|
194
|
+
return isExpanded;
|
|
195
|
+
}
|
|
196
|
+
return prev;
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
sideNav.addEventListener("expandedChange", handleExpandedChange);
|
|
201
|
+
|
|
202
|
+
return () => {
|
|
203
|
+
sideNav.removeEventListener("expandedChange", handleExpandedChange);
|
|
204
|
+
};
|
|
205
|
+
}, []);
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Handles side navigation expanded state changes for second example.
|
|
209
|
+
*/
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
const sideNav = sideNavRef2.current;
|
|
212
|
+
if (!sideNav) return;
|
|
213
|
+
|
|
214
|
+
const handleExpandedChange = (event: Event) => {
|
|
215
|
+
const customEvent = event as CustomEvent<boolean>;
|
|
216
|
+
const isExpanded = customEvent.detail;
|
|
217
|
+
console.log("Side navigation 2 expanded change:", isExpanded);
|
|
218
|
+
|
|
219
|
+
// Only update state if it's different to avoid circular updates
|
|
220
|
+
setSubMenuNavbarExpanded((prev) => {
|
|
221
|
+
if (prev !== isExpanded) {
|
|
222
|
+
// Collapse all sub-menus when side navigation collapses
|
|
223
|
+
if (!isExpanded) {
|
|
224
|
+
collapseAllSubMenus();
|
|
225
|
+
handleExpandChange(customEvent);
|
|
226
|
+
}
|
|
227
|
+
return isExpanded;
|
|
228
|
+
}
|
|
229
|
+
return prev;
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
sideNav.addEventListener("expandedChange", handleExpandedChange);
|
|
234
|
+
|
|
235
|
+
return () => {
|
|
236
|
+
sideNav.removeEventListener("expandedChange", handleExpandedChange);
|
|
237
|
+
};
|
|
238
|
+
}, [collapseAllSubMenus, handleExpandChange]);
|
|
239
|
+
|
|
240
|
+
// Handle menu item selection for first example
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
const menu = menuRef1.current;
|
|
243
|
+
if (!menu) return;
|
|
244
|
+
|
|
245
|
+
const handleItemSelect = (e: Event) => {
|
|
246
|
+
const customEvent = e as CustomEvent<{ value: string }>;
|
|
247
|
+
const value = customEvent.detail?.value;
|
|
248
|
+
if (value) {
|
|
249
|
+
setSelectedItem1(value);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
menu.addEventListener("itemSelect", handleItemSelect);
|
|
254
|
+
|
|
255
|
+
return () => {
|
|
256
|
+
menu.removeEventListener("itemSelect", handleItemSelect);
|
|
257
|
+
};
|
|
258
|
+
}, []);
|
|
259
|
+
|
|
260
|
+
// Update selected state for menu items in first example
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
const menu = menuRef1.current;
|
|
263
|
+
if (!menu) return;
|
|
264
|
+
|
|
265
|
+
const menuItems = menu.querySelectorAll("modus-wc-menu-item");
|
|
266
|
+
menuItems.forEach((item: Element) => {
|
|
267
|
+
const value = item.getAttribute("value");
|
|
268
|
+
if (value === selectedItem1) {
|
|
269
|
+
item.setAttribute("selected", "");
|
|
270
|
+
} else {
|
|
271
|
+
item.removeAttribute("selected");
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
}, [selectedItem1]);
|
|
275
|
+
|
|
276
|
+
// ============================================
|
|
277
|
+
// Event handlers
|
|
278
|
+
// ============================================
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Toggles the expanded state of a sub-menu.
|
|
282
|
+
*/
|
|
283
|
+
const toggleSubMenu = (menuKey: string, event: React.MouseEvent) => {
|
|
284
|
+
event.stopPropagation();
|
|
285
|
+
console.log("Toggling sub-menu:", menuKey);
|
|
286
|
+
|
|
287
|
+
setSubMenuStates((prev) => ({
|
|
288
|
+
...prev,
|
|
289
|
+
[menuKey]: !prev[menuKey],
|
|
290
|
+
}));
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Selects a menu item and updates the current selection.
|
|
295
|
+
*/
|
|
296
|
+
const selectMenuItem = (itemKey: string) => {
|
|
297
|
+
console.log("Selected menu item:", itemKey);
|
|
298
|
+
setSelectedSubMenuItem(itemKey);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Handles collapse toggle for sub-menus (Storybook pattern).
|
|
303
|
+
*/
|
|
304
|
+
const handleCollapseToggle = (e: React.MouseEvent) => {
|
|
305
|
+
const clickedEl = e.currentTarget as HTMLElement;
|
|
306
|
+
const parentLi = clickedEl.closest("li");
|
|
307
|
+
if (!parentLi) return;
|
|
308
|
+
|
|
309
|
+
// Find the icon element that needs to be toggled using the dropdown-toggle class
|
|
310
|
+
const iconEl = clickedEl.querySelector(
|
|
311
|
+
".side-nav-dropdown-toggle",
|
|
312
|
+
) as HTMLElement;
|
|
313
|
+
if (!iconEl) return;
|
|
314
|
+
|
|
315
|
+
// Find the parent side nav element
|
|
316
|
+
const sideNav = sideNavRef2.current;
|
|
317
|
+
|
|
318
|
+
// Toggle between expand_more and expand_less icons only if side nav is expanded
|
|
319
|
+
const isExpanded = iconEl.getAttribute("name") === "expand_more";
|
|
320
|
+
if (sideNav?.expanded) {
|
|
321
|
+
iconEl.setAttribute("name", isExpanded ? "expand_less" : "expand_more");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Find and toggle children visibility
|
|
325
|
+
const childContainer = parentLi.nextElementSibling as HTMLElement;
|
|
326
|
+
if (
|
|
327
|
+
childContainer &&
|
|
328
|
+
childContainer.classList.contains("side-nav-children-container") &&
|
|
329
|
+
sideNav?.expanded
|
|
330
|
+
) {
|
|
331
|
+
childContainer.classList.toggle("side-nav-hidden");
|
|
332
|
+
childContainer.setAttribute(
|
|
333
|
+
"aria-hidden",
|
|
334
|
+
!isExpanded ? "true" : "false",
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<>
|
|
341
|
+
<style>{`
|
|
342
|
+
.side-nav-children-container {
|
|
343
|
+
transition: height 0.2s ease-out;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.side-nav-collapse-icon {
|
|
347
|
+
min-width: 24px;
|
|
348
|
+
padding-inline-start: 0.2rem;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.side-nav-dropdown-menu {
|
|
352
|
+
overflow: hidden;
|
|
353
|
+
text-overflow: ellipsis;
|
|
354
|
+
white-space: nowrap;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.side-nav-flex-row {
|
|
358
|
+
align-items: center;
|
|
359
|
+
display: flex;
|
|
360
|
+
gap: 1.3rem;
|
|
361
|
+
padding: 0.8rem 0.25rem;
|
|
362
|
+
padding-left: 1rem;
|
|
363
|
+
cursor: pointer;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.side-nav-hidden {
|
|
367
|
+
display: none;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.side-nav-justify-end {
|
|
371
|
+
margin-left: auto;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.layout-with-navbar {
|
|
375
|
+
box-shadow: rgba(36, 35, 45, 0.3) 1px 0 4px;
|
|
376
|
+
display: flex;
|
|
377
|
+
flex-direction: column;
|
|
378
|
+
height: 100%;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.main-content-row {
|
|
382
|
+
display: flex;
|
|
383
|
+
flex: 1;
|
|
384
|
+
overflow: hidden;
|
|
385
|
+
position: relative;
|
|
386
|
+
min-height: 500px;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.side-nav-menu-width {
|
|
390
|
+
width: 100%;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.side-nav-nested-row {
|
|
394
|
+
padding-left: 4.5rem !important;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.side-nav-deeply-nested-row {
|
|
398
|
+
padding-left: 5.5rem !important;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.panel-content {
|
|
402
|
+
flex: 1;
|
|
403
|
+
padding: 1.5rem;
|
|
404
|
+
overflow: auto;
|
|
405
|
+
margin-left: 4rem; /* Account for collapsed side nav width */
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.side-navigation {
|
|
409
|
+
position: absolute;
|
|
410
|
+
left: 0;
|
|
411
|
+
top: 0;
|
|
412
|
+
height: 100%;
|
|
413
|
+
z-index: 999;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.modus-wc-menu ul {
|
|
417
|
+
list-style: none;
|
|
418
|
+
margin: 0;
|
|
419
|
+
padding: 0;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.modus-wc-menu li ul {
|
|
423
|
+
margin-inline-start: 1.8rem;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.side-nav-menu-item-container {
|
|
427
|
+
list-style: none;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.side-nav-submenu-item {
|
|
431
|
+
padding: 0.8rem 0.25rem;
|
|
432
|
+
padding-left: 1rem;
|
|
433
|
+
cursor: pointer;
|
|
434
|
+
display: flex;
|
|
435
|
+
align-items: center;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.side-nav-nested-submenu {
|
|
439
|
+
margin-left: 1rem;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.side-nav-icon-left {
|
|
443
|
+
flex-shrink: 0;
|
|
444
|
+
}
|
|
445
|
+
`}</style>
|
|
446
|
+
<DemoPage
|
|
447
|
+
title="Modus Side Navigation"
|
|
448
|
+
description="A collapsible vertical navigation component that provides contextual menu options for application navigation. The component collapses to show icons only (4rem width) and expands to show full menu items with labels. Icons remain visible and properly positioned in both states."
|
|
449
|
+
>
|
|
450
|
+
{/* Navbar Integration Example */}
|
|
451
|
+
<DemoExample
|
|
452
|
+
title="Navbar Integration (Recommended Pattern)"
|
|
453
|
+
description="Side navigation controlled by the navbar's main menu button (hamburger menu). This is the standard Modus pattern used in applications."
|
|
454
|
+
>
|
|
455
|
+
<div
|
|
456
|
+
className="layout-with-navbar h-[600px] flex flex-col"
|
|
457
|
+
data-example="basic"
|
|
458
|
+
>
|
|
459
|
+
<ModusNavbar
|
|
460
|
+
userCard={userCard1}
|
|
461
|
+
visibility={{ mainMenu: true, user: true }}
|
|
462
|
+
onMainMenuOpenChange={handleNavbarMenuOpenChange1}
|
|
463
|
+
/>
|
|
464
|
+
|
|
465
|
+
<div className="main-content-row flex flex-1 overflow-hidden">
|
|
466
|
+
<ModusWcSideNavigation
|
|
467
|
+
ref={sideNavRef1}
|
|
468
|
+
expanded={navbarMenuExpanded}
|
|
469
|
+
collapse-on-click-outside={true}
|
|
470
|
+
max-width="256px"
|
|
471
|
+
mode="push"
|
|
472
|
+
target-content="#basic-panel-content"
|
|
473
|
+
className="side-navigation h-full"
|
|
474
|
+
>
|
|
475
|
+
<ModusWcMenu ref={menuRef1} size="lg">
|
|
476
|
+
<ModusWcMenuItem label="Home" value="home" selected={true}>
|
|
477
|
+
<ModusWcIcon
|
|
478
|
+
slot="start-icon"
|
|
479
|
+
name="home"
|
|
480
|
+
decorative={true}
|
|
481
|
+
/>
|
|
482
|
+
</ModusWcMenuItem>
|
|
483
|
+
<ModusWcMenuItem label="Profile" value="profile">
|
|
484
|
+
<ModusWcIcon
|
|
485
|
+
slot="start-icon"
|
|
486
|
+
name="person"
|
|
487
|
+
decorative={true}
|
|
488
|
+
/>
|
|
489
|
+
</ModusWcMenuItem>
|
|
490
|
+
<ModusWcMenuItem label="Settings" value="settings">
|
|
491
|
+
<ModusWcIcon
|
|
492
|
+
slot="start-icon"
|
|
493
|
+
name="settings"
|
|
494
|
+
decorative={true}
|
|
495
|
+
/>
|
|
496
|
+
</ModusWcMenuItem>
|
|
497
|
+
</ModusWcMenu>
|
|
498
|
+
</ModusWcSideNavigation>
|
|
499
|
+
|
|
500
|
+
<div
|
|
501
|
+
id="basic-panel-content"
|
|
502
|
+
className="panel-content flex-1 p-6"
|
|
503
|
+
>
|
|
504
|
+
<div className="text-lg font-semibold text-foreground mb-4">
|
|
505
|
+
Main Content Area
|
|
506
|
+
</div>
|
|
507
|
+
<div className="text-base text-foreground mb-4">
|
|
508
|
+
The side navigation of an application provides context through
|
|
509
|
+
accessible menu options and positions a consistent component
|
|
510
|
+
to connect to various pages in the application.
|
|
511
|
+
</div>
|
|
512
|
+
<div className="text-base text-foreground">
|
|
513
|
+
The side navigation is a collapsible side content of the
|
|
514
|
+
site's pages. It is located alongside the page's primary
|
|
515
|
+
content. The component is designed to add side content to a
|
|
516
|
+
fullscreen application. It is activated through the
|
|
517
|
+
"hamburger" menu in the Navbar.
|
|
518
|
+
</div>
|
|
519
|
+
<div className="mt-4 p-4 rounded-lg bg-card border border-border">
|
|
520
|
+
<div className="text-sm font-medium text-card-foreground mb-1">
|
|
521
|
+
Navigation State:
|
|
522
|
+
</div>
|
|
523
|
+
<div className="text-sm text-muted-foreground">
|
|
524
|
+
{navbarMenuExpanded ? "Expanded" : "Collapsed"}
|
|
525
|
+
</div>
|
|
526
|
+
{selectedItem1 && (
|
|
527
|
+
<div className="mt-2">
|
|
528
|
+
<div className="text-sm font-medium text-card-foreground mb-1">
|
|
529
|
+
Selected Item:
|
|
530
|
+
</div>
|
|
531
|
+
<div className="text-sm text-muted-foreground">
|
|
532
|
+
{selectedItem1}
|
|
533
|
+
</div>
|
|
534
|
+
</div>
|
|
535
|
+
)}
|
|
536
|
+
</div>
|
|
537
|
+
</div>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
540
|
+
</DemoExample>
|
|
541
|
+
|
|
542
|
+
{/* Sub-Menu Example */}
|
|
543
|
+
<DemoExample
|
|
544
|
+
title="Side Navigation with Sub-Menus"
|
|
545
|
+
description="Advanced side navigation with collapsible sub-menus and nested menu items. Demonstrates hierarchical navigation with expand/collapse functionality."
|
|
546
|
+
>
|
|
547
|
+
<div
|
|
548
|
+
className="layout-with-navbar h-[700px] flex flex-col"
|
|
549
|
+
data-example="submenu"
|
|
550
|
+
>
|
|
551
|
+
<ModusNavbar
|
|
552
|
+
userCard={userCard2}
|
|
553
|
+
visibility={{ mainMenu: true, user: true }}
|
|
554
|
+
onMainMenuOpenChange={handleNavbarMenuOpenChange2}
|
|
555
|
+
/>
|
|
556
|
+
|
|
557
|
+
<div className="main-content-row flex flex-1 overflow-hidden">
|
|
558
|
+
<ModusWcSideNavigation
|
|
559
|
+
ref={sideNavRef2}
|
|
560
|
+
expanded={subMenuNavbarExpanded}
|
|
561
|
+
collapse-on-click-outside={true}
|
|
562
|
+
max-width="256px"
|
|
563
|
+
mode="push"
|
|
564
|
+
target-content="#submenu-panel-content"
|
|
565
|
+
className="side-navigation h-full"
|
|
566
|
+
>
|
|
567
|
+
<ModusWcMenu
|
|
568
|
+
aria-label="Custom menu"
|
|
569
|
+
custom-class="side-nav-menu-width"
|
|
570
|
+
>
|
|
571
|
+
{/* Charts Menu with Sub-items */}
|
|
572
|
+
<li>
|
|
573
|
+
<div
|
|
574
|
+
className="side-nav-flex-row hover:bg-muted"
|
|
575
|
+
onClick={handleCollapseToggle}
|
|
576
|
+
>
|
|
577
|
+
<ModusWcIcon
|
|
578
|
+
name="bar_graph"
|
|
579
|
+
decorative={true}
|
|
580
|
+
className="side-nav-collapse-icon side-nav-icon-left"
|
|
581
|
+
/>
|
|
582
|
+
<div className="side-nav-dropdown-menu">Charts</div>
|
|
583
|
+
<div className="side-nav-justify-end">
|
|
584
|
+
<ModusWcIcon
|
|
585
|
+
decorative={true}
|
|
586
|
+
name="expand_more"
|
|
587
|
+
className="side-nav-collapse-icon side-nav-dropdown-toggle"
|
|
588
|
+
/>
|
|
589
|
+
</div>
|
|
590
|
+
</div>
|
|
591
|
+
</li>
|
|
592
|
+
<li
|
|
593
|
+
className="side-nav-children-container side-nav-hidden"
|
|
594
|
+
aria-hidden="true"
|
|
595
|
+
>
|
|
596
|
+
<ul>
|
|
597
|
+
<li>
|
|
598
|
+
<div
|
|
599
|
+
className="side-nav-flex-row side-nav-nested-row hover:bg-muted"
|
|
600
|
+
onClick={() => selectMenuItem("bar-chart")}
|
|
601
|
+
>
|
|
602
|
+
<div>Bar Chart</div>
|
|
603
|
+
</div>
|
|
604
|
+
</li>
|
|
605
|
+
<li>
|
|
606
|
+
<div
|
|
607
|
+
className="side-nav-flex-row side-nav-nested-row hover:bg-muted"
|
|
608
|
+
onClick={() => selectMenuItem("line-chart")}
|
|
609
|
+
>
|
|
610
|
+
<div>Line Chart</div>
|
|
611
|
+
</div>
|
|
612
|
+
</li>
|
|
613
|
+
<li>
|
|
614
|
+
<div
|
|
615
|
+
className="side-nav-flex-row side-nav-nested-row hover:bg-muted"
|
|
616
|
+
onClick={() => selectMenuItem("pie-chart")}
|
|
617
|
+
>
|
|
618
|
+
<div>Pie Chart</div>
|
|
619
|
+
</div>
|
|
620
|
+
</li>
|
|
621
|
+
</ul>
|
|
622
|
+
</li>
|
|
623
|
+
|
|
624
|
+
{/* Calendar Menu (no sub-items) */}
|
|
625
|
+
<li>
|
|
626
|
+
<div
|
|
627
|
+
className="side-nav-flex-row hover:bg-muted"
|
|
628
|
+
onClick={() => selectMenuItem("calendar")}
|
|
629
|
+
>
|
|
630
|
+
<ModusWcIcon
|
|
631
|
+
name="calendar"
|
|
632
|
+
decorative={true}
|
|
633
|
+
className="side-nav-collapse-icon side-nav-icon-left"
|
|
634
|
+
/>
|
|
635
|
+
<div className="side-nav-dropdown-menu">Calendar</div>
|
|
636
|
+
</div>
|
|
637
|
+
</li>
|
|
638
|
+
|
|
639
|
+
{/* Maps Menu with Sub-items (using state-based approach) */}
|
|
640
|
+
<div className="side-nav-menu-item-container">
|
|
641
|
+
<div
|
|
642
|
+
className="side-nav-flex-row hover:bg-muted"
|
|
643
|
+
onClick={(e) => toggleSubMenu("maps", e)}
|
|
644
|
+
>
|
|
645
|
+
<ModusWcIcon
|
|
646
|
+
name="compass"
|
|
647
|
+
decorative={true}
|
|
648
|
+
className="side-nav-collapse-icon side-nav-icon-left"
|
|
649
|
+
/>
|
|
650
|
+
<div className="side-nav-dropdown-menu">Maps</div>
|
|
651
|
+
<div className="side-nav-justify-end">
|
|
652
|
+
<ModusWcIcon
|
|
653
|
+
name={
|
|
654
|
+
subMenuStates["maps"]
|
|
655
|
+
? "expand_less"
|
|
656
|
+
: "expand_more"
|
|
657
|
+
}
|
|
658
|
+
decorative={true}
|
|
659
|
+
className="side-nav-collapse-icon side-nav-dropdown-toggle"
|
|
660
|
+
/>
|
|
661
|
+
</div>
|
|
662
|
+
</div>
|
|
663
|
+
<div
|
|
664
|
+
className={`side-nav-children-container ${
|
|
665
|
+
!subMenuStates["maps"] ? "side-nav-hidden" : ""
|
|
666
|
+
}`}
|
|
667
|
+
aria-hidden={!subMenuStates["maps"]}
|
|
668
|
+
>
|
|
669
|
+
<div
|
|
670
|
+
className="side-nav-submenu-item side-nav-nested-row hover:bg-muted"
|
|
671
|
+
onClick={() => selectMenuItem("map-1")}
|
|
672
|
+
>
|
|
673
|
+
<div>Map 1</div>
|
|
674
|
+
</div>
|
|
675
|
+
<div
|
|
676
|
+
className="side-nav-submenu-item side-nav-nested-row hover:bg-muted"
|
|
677
|
+
onClick={(e) => toggleSubMenu("map-2", e)}
|
|
678
|
+
>
|
|
679
|
+
<div>Map 2</div>
|
|
680
|
+
<div className="side-nav-justify-end">
|
|
681
|
+
<ModusWcIcon
|
|
682
|
+
name={
|
|
683
|
+
subMenuStates["map-2"]
|
|
684
|
+
? "expand_less"
|
|
685
|
+
: "expand_more"
|
|
686
|
+
}
|
|
687
|
+
decorative={true}
|
|
688
|
+
className="side-nav-collapse-icon side-nav-dropdown-toggle"
|
|
689
|
+
/>
|
|
690
|
+
</div>
|
|
691
|
+
</div>
|
|
692
|
+
<div
|
|
693
|
+
className={`side-nav-children-container side-nav-nested-submenu ${
|
|
694
|
+
!subMenuStates["map-2"] ? "side-nav-hidden" : ""
|
|
695
|
+
}`}
|
|
696
|
+
aria-hidden={!subMenuStates["map-2"]}
|
|
697
|
+
>
|
|
698
|
+
<div
|
|
699
|
+
className="side-nav-submenu-item side-nav-deeply-nested-row hover:bg-muted"
|
|
700
|
+
onClick={() => selectMenuItem("map-2-1")}
|
|
701
|
+
>
|
|
702
|
+
<div>Map 2-1</div>
|
|
703
|
+
</div>
|
|
704
|
+
<div
|
|
705
|
+
className="side-nav-submenu-item side-nav-deeply-nested-row hover:bg-muted"
|
|
706
|
+
onClick={() => selectMenuItem("map-2-2")}
|
|
707
|
+
>
|
|
708
|
+
<div>Map 2-2</div>
|
|
709
|
+
</div>
|
|
710
|
+
</div>
|
|
711
|
+
<div
|
|
712
|
+
className="side-nav-submenu-item side-nav-nested-row hover:bg-muted"
|
|
713
|
+
onClick={() => selectMenuItem("map-3")}
|
|
714
|
+
>
|
|
715
|
+
<div>Map 3</div>
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
</ModusWcMenu>
|
|
720
|
+
</ModusWcSideNavigation>
|
|
721
|
+
|
|
722
|
+
<div
|
|
723
|
+
id="submenu-panel-content"
|
|
724
|
+
className="panel-content flex-1 p-6"
|
|
725
|
+
>
|
|
726
|
+
<div className="text-lg font-semibold text-foreground mb-4">
|
|
727
|
+
Sub-Menu Navigation
|
|
728
|
+
</div>
|
|
729
|
+
<div className="text-base text-foreground mb-4">
|
|
730
|
+
This example demonstrates hierarchical navigation with
|
|
731
|
+
collapsible sub-menus. Click on menu items with arrows to
|
|
732
|
+
expand/collapse sub-menus. The navigation maintains state and
|
|
733
|
+
properly handles nested menu structures.
|
|
734
|
+
</div>
|
|
735
|
+
<div className="mt-4 p-4 rounded-lg bg-card border border-border">
|
|
736
|
+
<div className="text-sm font-medium text-card-foreground mb-2">
|
|
737
|
+
Current Selection:
|
|
738
|
+
</div>
|
|
739
|
+
<div className="text-sm text-muted-foreground">
|
|
740
|
+
{selectedSubMenuItem || "No item selected"}
|
|
741
|
+
</div>
|
|
742
|
+
</div>
|
|
743
|
+
<div className="mt-4 p-4 rounded-lg bg-muted">
|
|
744
|
+
<div className="text-sm font-medium text-foreground mb-2">
|
|
745
|
+
Sub-Menu States:
|
|
746
|
+
</div>
|
|
747
|
+
<div className="text-xs text-muted-foreground">
|
|
748
|
+
<div>
|
|
749
|
+
Charts:{" "}
|
|
750
|
+
{subMenuStates["charts"] ? "Expanded" : "Collapsed"}
|
|
751
|
+
</div>
|
|
752
|
+
<div>
|
|
753
|
+
Maps: {subMenuStates["maps"] ? "Expanded" : "Collapsed"}
|
|
754
|
+
</div>
|
|
755
|
+
<div>
|
|
756
|
+
Map 2: {subMenuStates["map-2"] ? "Expanded" : "Collapsed"}
|
|
757
|
+
</div>
|
|
758
|
+
</div>
|
|
759
|
+
</div>
|
|
760
|
+
<div className="mt-4 p-4 rounded-lg bg-card border border-border">
|
|
761
|
+
<div className="text-sm font-medium text-card-foreground mb-1">
|
|
762
|
+
Navigation State:
|
|
763
|
+
</div>
|
|
764
|
+
<div className="text-sm text-muted-foreground">
|
|
765
|
+
{subMenuNavbarExpanded ? "Expanded" : "Collapsed"}
|
|
766
|
+
</div>
|
|
767
|
+
</div>
|
|
768
|
+
</div>
|
|
769
|
+
</div>
|
|
770
|
+
</div>
|
|
771
|
+
</DemoExample>
|
|
772
|
+
</DemoPage>
|
|
773
|
+
</>
|
|
774
|
+
);
|
|
775
|
+
}
|