@codyswann/lisa 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +867 -0
- package/all/copy-overwrite/.claude/README.md +205 -0
- package/all/copy-overwrite/.claude/agents/agent-architect.md +311 -0
- package/all/copy-overwrite/.claude/agents/codebase-analyzer.md +146 -0
- package/all/copy-overwrite/.claude/agents/codebase-locator.md +125 -0
- package/all/copy-overwrite/.claude/agents/codebase-pattern-finder.md +237 -0
- package/all/copy-overwrite/.claude/agents/git-history-analyzer.md +183 -0
- package/all/copy-overwrite/.claude/agents/hooks-expert.md +74 -0
- package/all/copy-overwrite/.claude/agents/skill-evaluator.md +246 -0
- package/all/copy-overwrite/.claude/agents/slash-command-architect.md +87 -0
- package/all/copy-overwrite/.claude/agents/web-search-researcher.md +112 -0
- package/all/copy-overwrite/.claude/commands/git/commit-and-submit-pr.md +8 -0
- package/all/copy-overwrite/.claude/commands/git/commit.md +44 -0
- package/all/copy-overwrite/.claude/commands/git/prune.md +34 -0
- package/all/copy-overwrite/.claude/commands/git/submit-pr.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/create.md +50 -0
- package/all/copy-overwrite/.claude/commands/jira/verify.md +34 -0
- package/all/copy-overwrite/.claude/commands/project/archive.md +8 -0
- package/all/copy-overwrite/.claude/commands/project/bootstrap.md +49 -0
- package/all/copy-overwrite/.claude/commands/project/complete-task.md +7 -0
- package/all/copy-overwrite/.claude/commands/project/debrief.md +65 -0
- package/all/copy-overwrite/.claude/commands/project/execute.md +94 -0
- package/all/copy-overwrite/.claude/commands/project/implement.md +42 -0
- package/all/copy-overwrite/.claude/commands/project/local-code-review.md +88 -0
- package/all/copy-overwrite/.claude/commands/project/lower-code-complexity.md +74 -0
- package/all/copy-overwrite/.claude/commands/project/plan.md +314 -0
- package/all/copy-overwrite/.claude/commands/project/research.md +248 -0
- package/all/copy-overwrite/.claude/commands/project/review.md +63 -0
- package/all/copy-overwrite/.claude/commands/project/setup.md +19 -0
- package/all/copy-overwrite/.claude/commands/project/verify.md +38 -0
- package/all/copy-overwrite/.claude/commands/pull-request/review.md +12 -0
- package/all/copy-overwrite/.claude/commands/rules/format-md.md +72 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/check.md +6 -0
- package/all/copy-overwrite/.claude/commands/sonarqube/fix.md +3 -0
- package/all/copy-overwrite/.claude/hooks/README.md +301 -0
- package/all/copy-overwrite/.claude/hooks/notify-ntfy.sh +181 -0
- package/all/copy-overwrite/.claude/settings.json +41 -0
- package/all/copy-overwrite/.claude/settings.local.json.example +14 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/SKILL.md +405 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/function-structure.md +416 -0
- package/all/copy-overwrite/.claude/skills/coding-philosophy/references/immutable-patterns.md +316 -0
- package/all/copy-overwrite/.claude/skills/prompt-complexity-scorer/SKILL.md +118 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/SKILL.md +210 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/__pycache__/quick_validate.cpython-312.pyc +0 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/all/copy-overwrite/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/all/copy-overwrite/CLAUDE.md +77 -0
- package/all/copy-overwrite/HUMAN.md +17 -0
- package/all/copy-overwrite/specs/.keep +0 -0
- package/all/create-only/PROJECT_RULES.md +0 -0
- package/cdk/merge/package.json +20 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +107 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +45 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +58 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/core/config.d.ts +73 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +36 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lisa.d.ts +81 -0
- package/dist/core/lisa.d.ts.map +1 -0
- package/dist/core/lisa.js +459 -0
- package/dist/core/lisa.js.map +1 -0
- package/dist/core/manifest.d.ts +58 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +104 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/detection/detector.interface.d.ts +15 -0
- package/dist/detection/detector.interface.d.ts.map +1 -0
- package/dist/detection/detector.interface.js +2 -0
- package/dist/detection/detector.interface.js.map +1 -0
- package/dist/detection/detectors/cdk.d.ts +10 -0
- package/dist/detection/detectors/cdk.d.ts.map +1 -0
- package/dist/detection/detectors/cdk.js +34 -0
- package/dist/detection/detectors/cdk.js.map +1 -0
- package/dist/detection/detectors/expo.d.ts +10 -0
- package/dist/detection/detectors/expo.d.ts.map +1 -0
- package/dist/detection/detectors/expo.js +30 -0
- package/dist/detection/detectors/expo.js.map +1 -0
- package/dist/detection/detectors/nestjs.d.ts +10 -0
- package/dist/detection/detectors/nestjs.d.ts.map +1 -0
- package/dist/detection/detectors/nestjs.js +34 -0
- package/dist/detection/detectors/nestjs.js.map +1 -0
- package/dist/detection/detectors/npm-package.d.ts +13 -0
- package/dist/detection/detectors/npm-package.d.ts.map +1 -0
- package/dist/detection/detectors/npm-package.js +30 -0
- package/dist/detection/detectors/npm-package.js.map +1 -0
- package/dist/detection/detectors/typescript.d.ts +10 -0
- package/dist/detection/detectors/typescript.d.ts.map +1 -0
- package/dist/detection/detectors/typescript.js +25 -0
- package/dist/detection/detectors/typescript.js.map +1 -0
- package/dist/detection/index.d.ts +24 -0
- package/dist/detection/index.d.ts.map +1 -0
- package/dist/detection/index.js +57 -0
- package/dist/detection/index.js.map +1 -0
- package/dist/errors/index.d.ts +69 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +110 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/console-logger.d.ts +12 -0
- package/dist/logging/console-logger.d.ts.map +1 -0
- package/dist/logging/console-logger.js +22 -0
- package/dist/logging/console-logger.js.map +1 -0
- package/dist/logging/index.d.ts +4 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.interface.d.ts +20 -0
- package/dist/logging/logger.interface.d.ts.map +1 -0
- package/dist/logging/logger.interface.js +2 -0
- package/dist/logging/logger.interface.js.map +1 -0
- package/dist/logging/silent-logger.d.ts +12 -0
- package/dist/logging/silent-logger.d.ts.map +1 -0
- package/dist/logging/silent-logger.js +21 -0
- package/dist/logging/silent-logger.js.map +1 -0
- package/dist/strategies/copy-contents.d.ts +14 -0
- package/dist/strategies/copy-contents.d.ts.map +1 -0
- package/dist/strategies/copy-contents.js +69 -0
- package/dist/strategies/copy-contents.js.map +1 -0
- package/dist/strategies/copy-overwrite.d.ts +14 -0
- package/dist/strategies/copy-overwrite.d.ts.map +1 -0
- package/dist/strategies/copy-overwrite.js +47 -0
- package/dist/strategies/copy-overwrite.js.map +1 -0
- package/dist/strategies/create-only.d.ts +13 -0
- package/dist/strategies/create-only.d.ts.map +1 -0
- package/dist/strategies/create-only.js +30 -0
- package/dist/strategies/create-only.js.map +1 -0
- package/dist/strategies/index.d.ts +31 -0
- package/dist/strategies/index.d.ts.map +1 -0
- package/dist/strategies/index.js +52 -0
- package/dist/strategies/index.js.map +1 -0
- package/dist/strategies/merge.d.ts +13 -0
- package/dist/strategies/merge.d.ts.map +1 -0
- package/dist/strategies/merge.js +60 -0
- package/dist/strategies/merge.js.map +1 -0
- package/dist/strategies/strategy.interface.d.ts +31 -0
- package/dist/strategies/strategy.interface.d.ts.map +1 -0
- package/dist/strategies/strategy.interface.js +2 -0
- package/dist/strategies/strategy.interface.js.map +1 -0
- package/dist/transaction/backup.d.ts +38 -0
- package/dist/transaction/backup.d.ts.map +1 -0
- package/dist/transaction/backup.js +97 -0
- package/dist/transaction/backup.js.map +1 -0
- package/dist/transaction/index.d.ts +4 -0
- package/dist/transaction/index.d.ts.map +1 -0
- package/dist/transaction/index.js +3 -0
- package/dist/transaction/index.js.map +1 -0
- package/dist/transaction/transaction.d.ts +34 -0
- package/dist/transaction/transaction.d.ts.map +1 -0
- package/dist/transaction/transaction.js +68 -0
- package/dist/transaction/transaction.js.map +1 -0
- package/dist/utils/file-operations.d.ts +29 -0
- package/dist/utils/file-operations.d.ts.map +1 -0
- package/dist/utils/file-operations.js +84 -0
- package/dist/utils/file-operations.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json-utils.d.ts +22 -0
- package/dist/utils/json-utils.d.ts.map +1 -0
- package/dist/utils/json-utils.js +57 -0
- package/dist/utils/json-utils.js.map +1 -0
- package/dist/utils/path-utils.d.ts +21 -0
- package/dist/utils/path-utils.d.ts.map +1 -0
- package/dist/utils/path-utils.js +35 -0
- package/dist/utils/path-utils.js.map +1 -0
- package/eslint-plugin-code-organization/README.md +149 -0
- package/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/eslint-plugin-code-organization/index.js +23 -0
- package/eslint-plugin-code-organization/package.json +10 -0
- package/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/SKILL.md +238 -0
- package/expo/copy-overwrite/.claude/skills/apollo-client/references/mutation-patterns.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/SKILL.md +360 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/atomic-levels.md +417 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/folder-structure.md +257 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/references/gluestack-mapping.md +233 -0
- package/expo/copy-overwrite/.claude/skills/atomic-design-gluestack/scripts/validate_atomic_structure.py +327 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/SKILL.md +299 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/examples.md +749 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/references/patterns.md +318 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/create_component.py +198 -0
- package/expo/copy-overwrite/.claude/skills/container-view-pattern/scripts/validate_component.py +207 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/SKILL.md +268 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/common-issues.md +619 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/file-extensions.md +340 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/references/platform-api.md +276 -0
- package/expo/copy-overwrite/.claude/skills/cross-platform-compatibility/scripts/validate_cross_platform.py +414 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/SKILL.md +202 -0
- package/expo/copy-overwrite/.claude/skills/directory-structure/scripts/validate_structure.py +443 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/SKILL.md +309 -0
- package/expo/copy-overwrite/.claude/skills/expo-env-config/references/validation-patterns.md +417 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/SKILL.md +431 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/references/official-docs.md +290 -0
- package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py +169 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/SKILL.md +411 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/color-tokens.md +343 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/component-mapping.md +307 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/references/spacing-scale.md +300 -0
- package/expo/copy-overwrite/.claude/skills/gluestack-nativewind/scripts/validate_styling.py +354 -0
- package/expo/copy-overwrite/.claude/skills/local-state/SKILL.md +362 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/async-storage.md +505 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/persistence-patterns.md +711 -0
- package/expo/copy-overwrite/.claude/skills/local-state/references/reactive-variables.md +446 -0
- package/expo/copy-overwrite/.claude/skills/playwright-selectors/SKILL.md +223 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/SKILL.md +319 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/async-patterns.md +420 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/expo-router-testing.md +556 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/mocking-patterns.md +590 -0
- package/expo/copy-overwrite/.claude/skills/testing-library/references/query-priority.md +291 -0
- package/expo/copy-overwrite/.easignore.extra +2 -0
- package/expo/copy-overwrite/.mcp.json +33 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/README.md +234 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/plugin-index.test.js +84 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/require-memo-in-view.test.js +196 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/__tests__/single-component-per-file.test.js +289 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/index.js +32 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/enforce-component-structure.js +230 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/no-return-in-view.js +91 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/require-memo-in-view.js +178 -0
- package/expo/copy-overwrite/eslint-plugin-component-structure/rules/single-component-per-file.js +238 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/README.md +260 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/index.js +29 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/package.json +10 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-classname-outside-ui.js +51 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-direct-rn-imports.js +55 -0
- package/expo/copy-overwrite/eslint-plugin-ui-standards/rules/no-inline-styles.js +73 -0
- package/expo/copy-overwrite/eslint.config.mjs +560 -0
- package/expo/copy-overwrite/lighthouserc.js +194 -0
- package/expo/create-only/lighthouserc-config.json +28 -0
- package/expo/merge/package.json +132 -0
- package/lisa.sh +35 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/SKILL.md +176 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/advanced-features.md +527 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/project-patterns.md +483 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/quick-start.md +257 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/resolvers-mutations.md +413 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-graphql/references/types-scalars.md +513 -0
- package/nestjs/copy-overwrite/.claude/skills/nestjs-rules/SKILL.md +536 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/SKILL.md +275 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/configuration-patterns.md +487 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/entity-patterns.md +450 -0
- package/nestjs/copy-overwrite/.claude/skills/typeorm-patterns/references/observability-patterns.md +536 -0
- package/nestjs/merge/package.json +75 -0
- package/package.json +124 -0
- package/typescript/copy-contents/.husky/commit-msg +91 -0
- package/typescript/copy-contents/.husky/pre-commit +96 -0
- package/typescript/copy-contents/.husky/pre-push +211 -0
- package/typescript/copy-overwrite/.claude/hooks/format-on-edit.sh +74 -0
- package/typescript/copy-overwrite/.claude/hooks/install_pkgs.sh +59 -0
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +103 -0
- package/typescript/copy-overwrite/.claude/skills/jsdoc-best-practices/SKILL.md +388 -0
- package/typescript/copy-overwrite/.github/README.md +455 -0
- package/typescript/copy-overwrite/.github/dependabot.yml +40 -0
- package/typescript/copy-overwrite/.github/k6/BROWSER_TESTING_NOTE.md +129 -0
- package/typescript/copy-overwrite/.github/k6/INTEGRATION_GUIDE.md +354 -0
- package/typescript/copy-overwrite/.github/k6/README.md +386 -0
- package/typescript/copy-overwrite/.github/k6/SCENARIO_SELECTION_GUIDE.md +264 -0
- package/typescript/copy-overwrite/.github/k6/examples/customer-deploy-integration.yml +115 -0
- package/typescript/copy-overwrite/.github/k6/examples/data-driven-test.js +268 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.js +142 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/load.json +27 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.js +26 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/smoke.json +20 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.js +244 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/soak.json +29 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.js +180 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/spike.json +32 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.js +206 -0
- package/typescript/copy-overwrite/.github/k6/scenarios/stress.json +38 -0
- package/typescript/copy-overwrite/.github/k6/scripts/api-test.js +452 -0
- package/typescript/copy-overwrite/.github/k6/scripts/default-test.js +185 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/normal.json +30 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/relaxed.json +21 -0
- package/typescript/copy-overwrite/.github/k6/thresholds/strict.json +29 -0
- package/typescript/copy-overwrite/.github/workflows/build.yml +72 -0
- package/typescript/copy-overwrite/.github/workflows/ci.yml +49 -0
- package/typescript/copy-overwrite/.github/workflows/claude.yml +51 -0
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +113 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +195 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +267 -0
- package/typescript/copy-overwrite/.github/workflows/deploy.yml +228 -0
- package/typescript/copy-overwrite/.github/workflows/k6-load-test-README.md +230 -0
- package/typescript/copy-overwrite/.github/workflows/lighthouse.yml +68 -0
- package/typescript/copy-overwrite/.github/workflows/load-test.yml +282 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +1737 -0
- package/typescript/copy-overwrite/.github/workflows/release.yml +1599 -0
- package/typescript/copy-overwrite/.gitleaksignore +28 -0
- package/typescript/copy-overwrite/.nvmrc +1 -0
- package/typescript/copy-overwrite/.prettierignore +23 -0
- package/typescript/copy-overwrite/.prettierrc.json +22 -0
- package/typescript/copy-overwrite/.versionrc +42 -0
- package/typescript/copy-overwrite/.yamllint +20 -0
- package/typescript/copy-overwrite/commitlint.config.js +11 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/README.md +149 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/__tests__/enforce-statement-order.test.js +468 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/index.js +23 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/package.json +10 -0
- package/typescript/copy-overwrite/eslint-plugin-code-organization/rules/enforce-statement-order.js +157 -0
- package/typescript/copy-overwrite/eslint.config.mjs +390 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +57 -0
- package/typescript/copy-overwrite/eslint.thresholds.config.json +5 -0
- package/typescript/github-rulesets/base.json +106 -0
- package/typescript/merge/.claude/settings.json +28 -0
- package/typescript/merge/package.json +71 -0
package/expo/copy-overwrite/.claude/skills/expo-router-best-practices/scripts/generate-route.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Route Generator for Expo Router
|
|
4
|
+
|
|
5
|
+
Creates route files following best practices:
|
|
6
|
+
- Thin wrapper pattern (imports feature screen)
|
|
7
|
+
- Descriptive component names
|
|
8
|
+
- JSDoc with URL pattern
|
|
9
|
+
- Proper TypeScript types
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
generate-route.py <route-path> <feature-name> [--layout] [--dynamic]
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
generate-route.py players/compare compare-players
|
|
16
|
+
generate-route.py players/[playerId] player-detail --dynamic
|
|
17
|
+
generate-route.py (tabs)/feed feed --layout
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
import os
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def to_pascal_case(name: str) -> str:
|
|
26
|
+
"""Convert hyphen-case to PascalCase."""
|
|
27
|
+
return ''.join(word.capitalize() for word in name.replace('_', '-').split('-'))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_route_url(route_path: str) -> str:
|
|
31
|
+
"""Convert file path to URL pattern."""
|
|
32
|
+
# Remove file extension if present
|
|
33
|
+
route_path = route_path.replace('.tsx', '')
|
|
34
|
+
|
|
35
|
+
# Handle route groups - they don't appear in URL
|
|
36
|
+
parts = []
|
|
37
|
+
for part in route_path.split('/'):
|
|
38
|
+
if not part.startswith('(') or not part.endswith(')'):
|
|
39
|
+
parts.append(part)
|
|
40
|
+
|
|
41
|
+
url = '/' + '/'.join(parts)
|
|
42
|
+
return url if url != '/' else '/'
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def generate_route_content(route_path: str, feature_name: str, is_dynamic: bool = False) -> str:
|
|
46
|
+
"""Generate route file content."""
|
|
47
|
+
pascal_feature = to_pascal_case(feature_name)
|
|
48
|
+
|
|
49
|
+
# Determine screen name from route path
|
|
50
|
+
path_parts = route_path.replace('.tsx', '').split('/')
|
|
51
|
+
last_part = path_parts[-1] if path_parts else 'Index'
|
|
52
|
+
|
|
53
|
+
# Handle dynamic routes
|
|
54
|
+
if last_part.startswith('[') and last_part.endswith(']'):
|
|
55
|
+
# [playerId] -> PlayerDetail
|
|
56
|
+
param_name = last_part[1:-1]
|
|
57
|
+
screen_name = to_pascal_case(param_name.replace('Id', '')) + 'DetailScreen'
|
|
58
|
+
elif last_part == 'index':
|
|
59
|
+
screen_name = pascal_feature + 'Screen'
|
|
60
|
+
else:
|
|
61
|
+
screen_name = to_pascal_case(last_part) + 'Screen'
|
|
62
|
+
|
|
63
|
+
url_pattern = get_route_url(route_path)
|
|
64
|
+
|
|
65
|
+
return f'''import {{ Main }} from "@/features/{feature_name}/screens/Main";
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* {screen_name.replace('Screen', '')} route.
|
|
69
|
+
* URL: {url_pattern}
|
|
70
|
+
*/
|
|
71
|
+
export default function {screen_name}() {{
|
|
72
|
+
return <Main />;
|
|
73
|
+
}}
|
|
74
|
+
'''
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def generate_layout_content(route_path: str) -> str:
|
|
78
|
+
"""Generate layout file content."""
|
|
79
|
+
# Determine if this is tabs, stack, or drawer
|
|
80
|
+
path_parts = route_path.split('/')
|
|
81
|
+
|
|
82
|
+
# Check for (tabs) in path
|
|
83
|
+
is_tabs = any(part == '(tabs)' for part in path_parts)
|
|
84
|
+
|
|
85
|
+
if is_tabs:
|
|
86
|
+
return '''import { Tabs } from "expo-router";
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Tab layout configuration.
|
|
90
|
+
*/
|
|
91
|
+
export default function TabLayout() {
|
|
92
|
+
return (
|
|
93
|
+
<Tabs screenOptions={{ headerShown: false }}>
|
|
94
|
+
<Tabs.Screen
|
|
95
|
+
name="index"
|
|
96
|
+
options={{
|
|
97
|
+
title: "Home",
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
{/* Add more tabs here */}
|
|
101
|
+
</Tabs>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
'''
|
|
105
|
+
else:
|
|
106
|
+
return '''import { Stack } from "expo-router";
|
|
107
|
+
|
|
108
|
+
export const unstable_settings = {
|
|
109
|
+
initialRouteName: "index",
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Stack layout configuration.
|
|
114
|
+
*/
|
|
115
|
+
export default function StackLayout() {
|
|
116
|
+
return (
|
|
117
|
+
<Stack>
|
|
118
|
+
<Stack.Screen name="index" options={{ headerShown: true }} />
|
|
119
|
+
</Stack>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
'''
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def main():
|
|
126
|
+
if len(sys.argv) < 3:
|
|
127
|
+
print("Usage: generate-route.py <route-path> <feature-name> [--layout] [--dynamic]")
|
|
128
|
+
print("")
|
|
129
|
+
print("Arguments:")
|
|
130
|
+
print(" route-path Path relative to app/ directory (e.g., players/[playerId])")
|
|
131
|
+
print(" feature-name Feature directory name (e.g., player-detail)")
|
|
132
|
+
print("")
|
|
133
|
+
print("Options:")
|
|
134
|
+
print(" --layout Generate a _layout.tsx file instead of a route")
|
|
135
|
+
print(" --dynamic Indicates this is a dynamic route with parameters")
|
|
136
|
+
print("")
|
|
137
|
+
print("Examples:")
|
|
138
|
+
print(" generate-route.py players/compare compare-players")
|
|
139
|
+
print(" generate-route.py players/[playerId] player-detail --dynamic")
|
|
140
|
+
print(" generate-route.py \"(tabs)/feed\" feed --layout")
|
|
141
|
+
sys.exit(1)
|
|
142
|
+
|
|
143
|
+
route_path = sys.argv[1]
|
|
144
|
+
feature_name = sys.argv[2]
|
|
145
|
+
is_layout = '--layout' in sys.argv
|
|
146
|
+
is_dynamic = '--dynamic' in sys.argv
|
|
147
|
+
|
|
148
|
+
if is_layout:
|
|
149
|
+
content = generate_layout_content(route_path)
|
|
150
|
+
filename = '_layout.tsx'
|
|
151
|
+
else:
|
|
152
|
+
content = generate_route_content(route_path, feature_name, is_dynamic)
|
|
153
|
+
# Determine filename from path
|
|
154
|
+
path_parts = route_path.split('/')
|
|
155
|
+
filename = path_parts[-1] if path_parts else 'index'
|
|
156
|
+
if not filename.endswith('.tsx'):
|
|
157
|
+
filename += '.tsx'
|
|
158
|
+
|
|
159
|
+
print(f"Generated {filename}:")
|
|
160
|
+
print("-" * 40)
|
|
161
|
+
print(content)
|
|
162
|
+
print("-" * 40)
|
|
163
|
+
print("")
|
|
164
|
+
print("To create this file, save the above content to:")
|
|
165
|
+
print(f" app/{route_path.rsplit('/', 1)[0] + '/' if '/' in route_path else ''}{filename}")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
main()
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gluestack-nativewind
|
|
3
|
+
description: This skill enforces Gluestack UI v3 and NativeWind v4 design patterns for consistent, performant, and maintainable styling. It should be used when creating or reviewing components, fixing styling issues, or refactoring styles to follow the constrained design system.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Gluestack NativeWind Design Patterns
|
|
7
|
+
|
|
8
|
+
This skill enforces constrained, opinionated styling patterns that reduce decision fatigue, improve performance, enable consistent theming, and limit the solution space to canonical patterns.
|
|
9
|
+
|
|
10
|
+
## Core Principles
|
|
11
|
+
|
|
12
|
+
1. **Gluestack components over React Native primitives** - Gluestack wraps RN with theming, accessibility, and cross-platform consistency
|
|
13
|
+
2. **Semantic tokens over arbitrary values** - Tokens encode intent, not just appearance
|
|
14
|
+
3. **className over inline styles** - Inline styles bypass optimization and consistency
|
|
15
|
+
4. **Spacing scale over pixel values** - Arbitrary values create unsustainable exceptions
|
|
16
|
+
5. **Remove dead code** - Unused patterns mislead AI and increase cognitive load
|
|
17
|
+
|
|
18
|
+
## When to Use This Skill
|
|
19
|
+
|
|
20
|
+
- Creating new components with styling
|
|
21
|
+
- Reviewing existing component styles
|
|
22
|
+
- Refactoring styles to follow the design system
|
|
23
|
+
- Fixing styling inconsistencies
|
|
24
|
+
- Adding dark mode support
|
|
25
|
+
- Theming components
|
|
26
|
+
|
|
27
|
+
## Rule 1: Gluestack Components Over React Native Primitives
|
|
28
|
+
|
|
29
|
+
Always use Gluestack components instead of direct React Native imports:
|
|
30
|
+
|
|
31
|
+
| React Native | Gluestack Equivalent |
|
|
32
|
+
| -------------------------------------- | -------------------------------------------------- |
|
|
33
|
+
| `View` from "react-native" | `Box` from "@/components/ui/box" |
|
|
34
|
+
| `Text` from "react-native" | `Text` from "@/components/ui/text" |
|
|
35
|
+
| `TouchableOpacity` from "react-native" | `Pressable` from "@/components/ui/pressable" |
|
|
36
|
+
| `ScrollView` from "react-native" | `ScrollView` from "@/components/ui/scroll-view" |
|
|
37
|
+
| `Image` from "react-native" | `Image` from "@/components/ui/image" |
|
|
38
|
+
| `TextInput` from "react-native" | `Input`, `InputField` from "@/components/ui/input" |
|
|
39
|
+
| `FlatList` from "react-native" | `FlashList` from "@shopify/flash-list" |
|
|
40
|
+
|
|
41
|
+
### Correct Pattern
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { Box } from "@/components/ui/box";
|
|
45
|
+
import { Text } from "@/components/ui/text";
|
|
46
|
+
import { Pressable } from "@/components/ui/pressable";
|
|
47
|
+
|
|
48
|
+
const Component = () => (
|
|
49
|
+
<Box className="p-4">
|
|
50
|
+
<Text className="text-typography-900">Hello</Text>
|
|
51
|
+
<Pressable onPress={handlePress}>
|
|
52
|
+
<Text>Press Me</Text>
|
|
53
|
+
</Pressable>
|
|
54
|
+
</Box>
|
|
55
|
+
);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Incorrect Pattern
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { View, Text, TouchableOpacity } from "react-native";
|
|
62
|
+
|
|
63
|
+
const Component = () => (
|
|
64
|
+
<View style={{ padding: 16 }}>
|
|
65
|
+
<Text style={{ color: "#333" }}>Hello</Text>
|
|
66
|
+
<TouchableOpacity onPress={handlePress}>
|
|
67
|
+
<Text>Press Me</Text>
|
|
68
|
+
</TouchableOpacity>
|
|
69
|
+
</View>
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Exceptions
|
|
74
|
+
|
|
75
|
+
- Platform-specific code where RN primitives are explicitly required
|
|
76
|
+
- Deep integration with native modules
|
|
77
|
+
- Performance-critical paths where wrapper overhead matters (rare, must document)
|
|
78
|
+
|
|
79
|
+
## Rule 2: Semantic Color Tokens Over Raw Values
|
|
80
|
+
|
|
81
|
+
Use Gluestack semantic tokens instead of raw Tailwind colors:
|
|
82
|
+
|
|
83
|
+
| Instead of | Use |
|
|
84
|
+
| ------------------ | --------------------- |
|
|
85
|
+
| `text-red-500` | `text-error-500` |
|
|
86
|
+
| `text-green-500` | `text-success-500` |
|
|
87
|
+
| `text-yellow-500` | `text-warning-500` |
|
|
88
|
+
| `text-blue-500` | `text-info-500` |
|
|
89
|
+
| `text-gray-500` | `text-typography-500` |
|
|
90
|
+
| `bg-blue-600` | `bg-primary-600` |
|
|
91
|
+
| `border-gray-200` | `border-outline-200` |
|
|
92
|
+
| `#DC2626` (inline) | `text-error-600` |
|
|
93
|
+
|
|
94
|
+
### Available Semantic Token Categories
|
|
95
|
+
|
|
96
|
+
| Token | Purpose | Scale |
|
|
97
|
+
| -------------------- | ---------------------------------------- | ----- |
|
|
98
|
+
| `primary-{0-950}` | Brand identity, key interactive elements | 0-950 |
|
|
99
|
+
| `secondary-{0-950}` | Secondary actions, supporting elements | 0-950 |
|
|
100
|
+
| `tertiary-{0-950}` | Tertiary accents | 0-950 |
|
|
101
|
+
| `error-{0-950}` | Validation errors, destructive actions | 0-950 |
|
|
102
|
+
| `success-{0-950}` | Positive feedback, completions | 0-950 |
|
|
103
|
+
| `warning-{0-950}` | Alerts, attention-required states | 0-950 |
|
|
104
|
+
| `info-{0-950}` | Informational content | 0-950 |
|
|
105
|
+
| `typography-{0-950}` | Text colors | 0-950 |
|
|
106
|
+
| `outline-{0-950}` | Border colors | 0-950 |
|
|
107
|
+
| `background-{0-950}` | Background colors | 0-950 |
|
|
108
|
+
|
|
109
|
+
### Special Background Tokens
|
|
110
|
+
|
|
111
|
+
Use state-based background tokens:
|
|
112
|
+
|
|
113
|
+
- `bg-background-error` - Error state backgrounds
|
|
114
|
+
- `bg-background-warning` - Warning state backgrounds
|
|
115
|
+
- `bg-background-success` - Success state backgrounds
|
|
116
|
+
- `bg-background-muted` - Muted/disabled backgrounds
|
|
117
|
+
- `bg-background-info` - Informational backgrounds
|
|
118
|
+
|
|
119
|
+
### Correct Pattern
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<Box className="bg-error-500">
|
|
123
|
+
<Text className="text-typography-0">Error message</Text>
|
|
124
|
+
</Box>
|
|
125
|
+
|
|
126
|
+
<Box className="border border-outline-300 bg-background-50">
|
|
127
|
+
<Text className="text-success-600">Success!</Text>
|
|
128
|
+
</Box>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Incorrect Pattern
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
<Box className="bg-red-500">
|
|
135
|
+
<Text className="text-white">Error message</Text>
|
|
136
|
+
</Box>
|
|
137
|
+
|
|
138
|
+
<Box style={{ backgroundColor: '#DC2626' }}>
|
|
139
|
+
<Text style={{ color: 'green' }}>Success!</Text>
|
|
140
|
+
</Box>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For complete token reference, see `references/color-tokens.md`.
|
|
144
|
+
|
|
145
|
+
## Rule 3: No Inline Styles
|
|
146
|
+
|
|
147
|
+
Avoid inline `style` props when className can achieve the same result.
|
|
148
|
+
|
|
149
|
+
### Resolution Hierarchy (in order of preference)
|
|
150
|
+
|
|
151
|
+
1. **className utilities** - Use existing Tailwind/NativeWind classes
|
|
152
|
+
2. **Gluestack component variants** - Use built-in component variants
|
|
153
|
+
3. **tva (Tailwind Variant Authority)** - Create reusable variant patterns
|
|
154
|
+
4. **NativeWind interop** - Enable className on third-party components
|
|
155
|
+
5. **Inline styles** - Only as absolute last resort with documented justification
|
|
156
|
+
|
|
157
|
+
### Correct Pattern
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
<Box className="w-20 h-20 rounded-full bg-background-100" />
|
|
161
|
+
|
|
162
|
+
<Text className="text-lg font-bold text-typography-900" />
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Incorrect Pattern
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<Box
|
|
169
|
+
style={{
|
|
170
|
+
width: 80,
|
|
171
|
+
height: 80,
|
|
172
|
+
borderRadius: 40,
|
|
173
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
174
|
+
}}
|
|
175
|
+
/>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Acceptable Exceptions
|
|
179
|
+
|
|
180
|
+
Inline styles are acceptable for:
|
|
181
|
+
|
|
182
|
+
1. **Dynamic values** - Values computed at runtime (e.g., animation values, safe area insets)
|
|
183
|
+
2. **Third-party component requirements** - Components that don't support className
|
|
184
|
+
3. **Platform-specific overrides** - When Platform.select is needed
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
// Acceptable: dynamic value from hook
|
|
188
|
+
<Box style={{ paddingBottom: bottomInset }} />
|
|
189
|
+
|
|
190
|
+
// Acceptable: animation value
|
|
191
|
+
<Animated.View style={{ transform: [{ translateX: animatedValue }] }} />
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Rule 4: Spacing Scale Adherence
|
|
195
|
+
|
|
196
|
+
Use only values from the standard spacing scale. Arbitrary values create maintenance burden.
|
|
197
|
+
|
|
198
|
+
### Allowed Spacing Values
|
|
199
|
+
|
|
200
|
+
| Class | Size |
|
|
201
|
+
| ----- | ----- |
|
|
202
|
+
| `0` | 0px |
|
|
203
|
+
| `0.5` | 2px |
|
|
204
|
+
| `1` | 4px |
|
|
205
|
+
| `1.5` | 6px |
|
|
206
|
+
| `2` | 8px |
|
|
207
|
+
| `2.5` | 10px |
|
|
208
|
+
| `3` | 12px |
|
|
209
|
+
| `3.5` | 14px |
|
|
210
|
+
| `4` | 16px |
|
|
211
|
+
| `5` | 20px |
|
|
212
|
+
| `6` | 24px |
|
|
213
|
+
| `7` | 28px |
|
|
214
|
+
| `8` | 32px |
|
|
215
|
+
| `9` | 36px |
|
|
216
|
+
| `10` | 40px |
|
|
217
|
+
| `11` | 44px |
|
|
218
|
+
| `12` | 48px |
|
|
219
|
+
| `14` | 56px |
|
|
220
|
+
| `16` | 64px |
|
|
221
|
+
| `20` | 80px |
|
|
222
|
+
| `24` | 96px |
|
|
223
|
+
| `28` | 112px |
|
|
224
|
+
| `32` | 128px |
|
|
225
|
+
| `36` | 144px |
|
|
226
|
+
| `40` | 160px |
|
|
227
|
+
| `44` | 176px |
|
|
228
|
+
| `48` | 192px |
|
|
229
|
+
| `52` | 208px |
|
|
230
|
+
| `56` | 224px |
|
|
231
|
+
| `60` | 240px |
|
|
232
|
+
| `64` | 256px |
|
|
233
|
+
| `72` | 288px |
|
|
234
|
+
| `80` | 320px |
|
|
235
|
+
| `96` | 384px |
|
|
236
|
+
|
|
237
|
+
### Prohibited Patterns
|
|
238
|
+
|
|
239
|
+
- Arbitrary values: `p-[13px]`, `m-[27px]`, `gap-[15px]`
|
|
240
|
+
- Non-scale decimals: `p-2.7`, `m-4.3`
|
|
241
|
+
|
|
242
|
+
### Correct Pattern
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
<Box className="p-4 m-2 gap-3" />
|
|
246
|
+
<Box className="px-6 py-4 mt-8" />
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Incorrect Pattern
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
<Box className="p-[13px] m-[27px]" />
|
|
253
|
+
<Box style={{ padding: 13, margin: 27 }} />
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
For complete spacing reference, see `references/spacing-scale.md`.
|
|
257
|
+
|
|
258
|
+
## Rule 5: Dark Mode Using CSS Variables
|
|
259
|
+
|
|
260
|
+
Use the CSS variables approach with `dark:` prefix for dark mode support.
|
|
261
|
+
|
|
262
|
+
### Correct Pattern
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
<Box className="bg-background-0 dark:bg-background-950" />
|
|
266
|
+
<Text className="text-typography-900 dark:text-typography-0" />
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Component-Level Dark Mode
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
const CardView = ({ isDark }: { readonly isDark: boolean }) => (
|
|
273
|
+
<Box className={isDark ? "bg-background-950" : "bg-background-0"}>
|
|
274
|
+
<Text className={isDark ? "text-typography-0" : "text-typography-900"}>
|
|
275
|
+
Content
|
|
276
|
+
</Text>
|
|
277
|
+
</Box>
|
|
278
|
+
);
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Rule 6: Gluestack Sub-Component Pattern
|
|
282
|
+
|
|
283
|
+
Use Gluestack's composable sub-component pattern for complex components.
|
|
284
|
+
|
|
285
|
+
### Correct Pattern
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
<Button action="primary" size="md">
|
|
289
|
+
<ButtonText>Click Me</ButtonText>
|
|
290
|
+
<ButtonIcon as={ChevronRightIcon} />
|
|
291
|
+
</Button>
|
|
292
|
+
|
|
293
|
+
<Input variant="outline" size="md">
|
|
294
|
+
<InputField placeholder="Enter text" />
|
|
295
|
+
<InputSlot>
|
|
296
|
+
<InputIcon as={SearchIcon} />
|
|
297
|
+
</InputSlot>
|
|
298
|
+
</Input>
|
|
299
|
+
|
|
300
|
+
<Select>
|
|
301
|
+
<SelectTrigger>
|
|
302
|
+
<SelectInput placeholder="Select option" />
|
|
303
|
+
<SelectIcon as={ChevronDownIcon} />
|
|
304
|
+
</SelectTrigger>
|
|
305
|
+
<SelectPortal>
|
|
306
|
+
<SelectBackdrop />
|
|
307
|
+
<SelectContent>
|
|
308
|
+
<SelectItem label="Option 1" value="1" />
|
|
309
|
+
<SelectItem label="Option 2" value="2" />
|
|
310
|
+
</SelectContent>
|
|
311
|
+
</SelectPortal>
|
|
312
|
+
</Select>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Incorrect Pattern
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
// Missing sub-components
|
|
319
|
+
<Button>Click Me</Button>
|
|
320
|
+
|
|
321
|
+
// Text must be wrapped in ButtonText
|
|
322
|
+
<Button>
|
|
323
|
+
Click Me {/* Will not render correctly */}
|
|
324
|
+
</Button>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Rule 7: Variant-Based Styling with tva
|
|
328
|
+
|
|
329
|
+
For components with multiple style variants, use `tva` (Tailwind Variant Authority).
|
|
330
|
+
|
|
331
|
+
### Correct Pattern
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
import { tva } from "@gluestack-ui/nativewind-utils/tva";
|
|
335
|
+
|
|
336
|
+
const cardStyles = tva({
|
|
337
|
+
base: "rounded-lg p-4",
|
|
338
|
+
variants: {
|
|
339
|
+
variant: {
|
|
340
|
+
elevated: "bg-background-0 shadow-hard-2",
|
|
341
|
+
outlined: "bg-transparent border border-outline-200",
|
|
342
|
+
filled: "bg-background-50",
|
|
343
|
+
},
|
|
344
|
+
size: {
|
|
345
|
+
sm: "p-2",
|
|
346
|
+
md: "p-4",
|
|
347
|
+
lg: "p-6",
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
defaultVariants: {
|
|
351
|
+
variant: "elevated",
|
|
352
|
+
size: "md",
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const Card = ({ variant, size, className }: CardProps) => (
|
|
357
|
+
<Box className={cardStyles({ variant, size, className })} />
|
|
358
|
+
);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Rule 8: className Merging for Custom Components
|
|
362
|
+
|
|
363
|
+
Allow className override in custom components using string concatenation.
|
|
364
|
+
|
|
365
|
+
### Correct Pattern
|
|
366
|
+
|
|
367
|
+
```tsx
|
|
368
|
+
interface BoxCardProps {
|
|
369
|
+
readonly className?: string;
|
|
370
|
+
readonly children: React.ReactNode;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const BoxCard = ({ className, children }: BoxCardProps) => (
|
|
374
|
+
<Box className={`rounded-lg bg-background-0 p-4 ${className ?? ""}`}>
|
|
375
|
+
{children}
|
|
376
|
+
</Box>
|
|
377
|
+
);
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Validation
|
|
381
|
+
|
|
382
|
+
To validate styling compliance, run:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
python3 .claude/skills/gluestack-nativewind/scripts/validate_styling.py [path]
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
The script detects:
|
|
389
|
+
|
|
390
|
+
1. Direct React Native component imports with Gluestack equivalents
|
|
391
|
+
2. Raw color values without semantic tokens
|
|
392
|
+
3. Inline style objects where className could be used
|
|
393
|
+
4. Arbitrary bracket notation values
|
|
394
|
+
5. Non-scale spacing values
|
|
395
|
+
|
|
396
|
+
## Escalation Guidance
|
|
397
|
+
|
|
398
|
+
When a design request cannot be satisfied with existing patterns:
|
|
399
|
+
|
|
400
|
+
1. **Push back early** - Explain performance and maintenance implications
|
|
401
|
+
2. **Propose alternatives** - Map to existing tokens or suggest new semantic tokens
|
|
402
|
+
3. **Add to design system** - If truly needed, add token to tailwind.config.js
|
|
403
|
+
4. **Document exception** - If inline style is unavoidable, add JSDoc explaining why
|
|
404
|
+
|
|
405
|
+
## Reference Documentation
|
|
406
|
+
|
|
407
|
+
For detailed mappings and complete token lists:
|
|
408
|
+
|
|
409
|
+
- `references/component-mapping.md` - Gluestack equivalents for React Native primitives
|
|
410
|
+
- `references/color-tokens.md` - Complete semantic color token reference
|
|
411
|
+
- `references/spacing-scale.md` - Allowed spacing values with pixel equivalents
|