@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
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Apollo Client Mutation Patterns
|
|
2
|
+
|
|
3
|
+
This reference provides comprehensive examples of mutation patterns for Apollo Client 3.10.
|
|
4
|
+
|
|
5
|
+
## Complete Mutation Hook Pattern
|
|
6
|
+
|
|
7
|
+
Every custom mutation hook should follow this structure:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { useCallback } from "react";
|
|
11
|
+
import {
|
|
12
|
+
useUpdateKanbanCardMutation,
|
|
13
|
+
KanbanCardFragment,
|
|
14
|
+
KanbanCardFragmentDoc,
|
|
15
|
+
} from "@/generated/graphql";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook for updating kanban card with optimistic UI
|
|
19
|
+
* @param boardId - The board ID for context
|
|
20
|
+
* @returns Object containing update function and loading state
|
|
21
|
+
*/
|
|
22
|
+
export const useUpdateCard = (boardId: string) => {
|
|
23
|
+
const [updateCardMutation, { loading }] = useUpdateKanbanCardMutation({
|
|
24
|
+
// 1. OPTIMISTIC RESPONSE - Provides instant UI feedback
|
|
25
|
+
optimisticResponse: variables => ({
|
|
26
|
+
__typename: "Mutation",
|
|
27
|
+
updateKanbanCard: {
|
|
28
|
+
__typename: "KanbanCard",
|
|
29
|
+
id: variables.id,
|
|
30
|
+
notes: variables.input.notes ?? null,
|
|
31
|
+
position: variables.input.position ?? 0,
|
|
32
|
+
kanbanPhaseId: variables.input.kanbanPhaseId ?? "",
|
|
33
|
+
kanbanPhase: {
|
|
34
|
+
__typename: "KanbanPhase",
|
|
35
|
+
id: variables.input.kanbanPhaseId ?? "",
|
|
36
|
+
name: "", // Will be updated by server response
|
|
37
|
+
},
|
|
38
|
+
createdAt: new Date().toISOString(),
|
|
39
|
+
updatedAt: new Date().toISOString(),
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
|
|
43
|
+
// 2. CACHE UPDATE - Ensures UI stays in sync
|
|
44
|
+
update(cache, { data }) {
|
|
45
|
+
if (!data?.updateKanbanCard) return;
|
|
46
|
+
|
|
47
|
+
// For simple field updates, Apollo handles automatically
|
|
48
|
+
// For complex scenarios, use cache.modify:
|
|
49
|
+
cache.modify({
|
|
50
|
+
id: cache.identify({
|
|
51
|
+
__typename: "KanbanCard",
|
|
52
|
+
id: data.updateKanbanCard.id,
|
|
53
|
+
}),
|
|
54
|
+
fields: {
|
|
55
|
+
notes: () => data.updateKanbanCard.notes,
|
|
56
|
+
position: () => data.updateKanbanCard.position,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// 3. ERROR HANDLING - Never pollutes console
|
|
62
|
+
onError: () => {
|
|
63
|
+
// Set error state in UI, don't console.log
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// 4. WRAPPED CALLBACK - Proper memoization
|
|
68
|
+
const updateCard = useCallback(
|
|
69
|
+
async (cardId: string, notes: string) => {
|
|
70
|
+
await updateCardMutation({
|
|
71
|
+
variables: {
|
|
72
|
+
id: cardId,
|
|
73
|
+
input: { notes },
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
},
|
|
77
|
+
[updateCardMutation]
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return { updateCard, isUpdating: loading };
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Adding Items to a List
|
|
85
|
+
|
|
86
|
+
When creating new items that need to appear in a list:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const [addPlayerMutation] = useAddPlayerToKanbanMutation({
|
|
90
|
+
optimisticResponse: variables => ({
|
|
91
|
+
__typename: "Mutation",
|
|
92
|
+
addPlayerToKanban: {
|
|
93
|
+
__typename: "KanbanCard",
|
|
94
|
+
id: crypto.randomUUID(), // Temporary ID for new items
|
|
95
|
+
position: 0,
|
|
96
|
+
notes: variables.input.notes ?? null,
|
|
97
|
+
kanbanPhaseId: variables.input.kanbanPhaseId,
|
|
98
|
+
kanbanPhase: {
|
|
99
|
+
__typename: "KanbanPhase",
|
|
100
|
+
id: variables.input.kanbanPhaseId,
|
|
101
|
+
name: "", // Will be replaced by server
|
|
102
|
+
},
|
|
103
|
+
createdAt: new Date().toISOString(),
|
|
104
|
+
updatedAt: new Date().toISOString(),
|
|
105
|
+
},
|
|
106
|
+
}),
|
|
107
|
+
|
|
108
|
+
update(cache, { data }) {
|
|
109
|
+
if (!data?.addPlayerToKanban) return;
|
|
110
|
+
|
|
111
|
+
cache.modify({
|
|
112
|
+
fields: {
|
|
113
|
+
listKanbanCards(existingCards = { edges: [] }) {
|
|
114
|
+
const newCardRef = cache.writeFragment({
|
|
115
|
+
data: data.addPlayerToKanban,
|
|
116
|
+
fragment: KanbanCardFragmentDoc,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...existingCards,
|
|
121
|
+
edges: [
|
|
122
|
+
...existingCards.edges,
|
|
123
|
+
{
|
|
124
|
+
__typename: "KanbanCardEdge",
|
|
125
|
+
cursor: "",
|
|
126
|
+
node: { __ref: newCardRef.__ref },
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
onError: () => {
|
|
136
|
+
// Handle error in UI state
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Removing Items from a List
|
|
142
|
+
|
|
143
|
+
When deleting items that should disappear from a list:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const [removePlayerMutation] = useRemovePlayerFromKanbanMutation({
|
|
147
|
+
optimisticResponse: variables => ({
|
|
148
|
+
__typename: "Mutation",
|
|
149
|
+
removePlayerFromKanban: {
|
|
150
|
+
__typename: "KanbanCard",
|
|
151
|
+
id: variables.cardId,
|
|
152
|
+
position: 0,
|
|
153
|
+
notes: null,
|
|
154
|
+
kanbanPhaseId: "",
|
|
155
|
+
kanbanPhase: {
|
|
156
|
+
__typename: "KanbanPhase",
|
|
157
|
+
id: "",
|
|
158
|
+
name: "",
|
|
159
|
+
},
|
|
160
|
+
createdAt: new Date().toISOString(),
|
|
161
|
+
updatedAt: new Date().toISOString(),
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
164
|
+
|
|
165
|
+
update(cache, { data }) {
|
|
166
|
+
if (!data?.removePlayerFromKanban) return;
|
|
167
|
+
|
|
168
|
+
const removedId = data.removePlayerFromKanban.id;
|
|
169
|
+
|
|
170
|
+
cache.modify({
|
|
171
|
+
fields: {
|
|
172
|
+
listKanbanCards(existingCards = { edges: [] }, { readField }) {
|
|
173
|
+
return {
|
|
174
|
+
...existingCards,
|
|
175
|
+
edges: existingCards.edges.filter(
|
|
176
|
+
(edge: { node: { __ref: string } }) => {
|
|
177
|
+
const cardRef = edge.node.__ref;
|
|
178
|
+
return readField("id", { __ref: cardRef }) !== removedId;
|
|
179
|
+
}
|
|
180
|
+
),
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Evict the removed item from cache entirely
|
|
187
|
+
cache.evict({
|
|
188
|
+
id: cache.identify({
|
|
189
|
+
__typename: "KanbanCard",
|
|
190
|
+
id: removedId,
|
|
191
|
+
}),
|
|
192
|
+
});
|
|
193
|
+
cache.gc();
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
onError: () => {
|
|
197
|
+
// Handle error in UI state
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Moving Items Between Lists
|
|
203
|
+
|
|
204
|
+
When an item moves from one parent to another:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const [moveCardMutation] = useMoveKanbanCardMutation({
|
|
208
|
+
optimisticResponse: variables => ({
|
|
209
|
+
__typename: "Mutation",
|
|
210
|
+
moveKanbanCard: {
|
|
211
|
+
__typename: "KanbanCard",
|
|
212
|
+
id: variables.input.cardId,
|
|
213
|
+
position: variables.input.targetPosition,
|
|
214
|
+
notes: null, // Preserve from existing cache
|
|
215
|
+
kanbanPhaseId: variables.input.targetPhaseId,
|
|
216
|
+
kanbanPhase: {
|
|
217
|
+
__typename: "KanbanPhase",
|
|
218
|
+
id: variables.input.targetPhaseId,
|
|
219
|
+
name: "", // Will be updated by server
|
|
220
|
+
},
|
|
221
|
+
createdAt: new Date().toISOString(),
|
|
222
|
+
updatedAt: new Date().toISOString(),
|
|
223
|
+
},
|
|
224
|
+
}),
|
|
225
|
+
|
|
226
|
+
// For moves, refetchQueries is often cleaner than manual cache updates
|
|
227
|
+
refetchQueries: ["ListKanbanCards"],
|
|
228
|
+
awaitRefetchQueries: false, // Don't block UI
|
|
229
|
+
|
|
230
|
+
onError: () => {
|
|
231
|
+
// Handle error in UI state
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Batch Updates with Reordering
|
|
237
|
+
|
|
238
|
+
When updating positions of multiple items:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
const [updatePositionsMutation] = useUpdateKanbanPhasePositionsMutation({
|
|
242
|
+
optimisticResponse: variables => ({
|
|
243
|
+
__typename: "Mutation",
|
|
244
|
+
updateKanbanPhasePositions: variables.input.phasePositions.map(pp => ({
|
|
245
|
+
__typename: "KanbanPhase",
|
|
246
|
+
id: pp.phaseId,
|
|
247
|
+
position: pp.position,
|
|
248
|
+
name: "", // Preserve from cache
|
|
249
|
+
kanbanBoardId: variables.input.kanbanBoardId,
|
|
250
|
+
createdAt: new Date().toISOString(),
|
|
251
|
+
updatedAt: new Date().toISOString(),
|
|
252
|
+
})),
|
|
253
|
+
}),
|
|
254
|
+
|
|
255
|
+
refetchQueries: ["ListKanbanPhases"],
|
|
256
|
+
awaitRefetchQueries: false,
|
|
257
|
+
|
|
258
|
+
onError: () => {
|
|
259
|
+
// Handle error in UI state
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Conditional Optimistic Updates
|
|
265
|
+
|
|
266
|
+
Skip optimistic updates when conditions aren't met:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
const [updateMutation] = useUpdateMutation({
|
|
270
|
+
optimisticResponse: (variables, { IGNORE }) => {
|
|
271
|
+
// Skip optimistic update if we don't have enough data
|
|
272
|
+
if (!variables.input.name) {
|
|
273
|
+
return IGNORE;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
__typename: "Mutation",
|
|
278
|
+
update: {
|
|
279
|
+
__typename: "Entity",
|
|
280
|
+
id: variables.id,
|
|
281
|
+
name: variables.input.name,
|
|
282
|
+
updatedAt: new Date().toISOString(),
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Cache Update with cache.identify
|
|
290
|
+
|
|
291
|
+
Use `cache.identify` to get the correct cache key:
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
update(cache, { data }) {
|
|
295
|
+
if (!data?.updatePlayer) return;
|
|
296
|
+
|
|
297
|
+
const cacheId = cache.identify({
|
|
298
|
+
__typename: "Player",
|
|
299
|
+
id: data.updatePlayer.id,
|
|
300
|
+
});
|
|
301
|
+
// cacheId = "Player:abc-123"
|
|
302
|
+
|
|
303
|
+
cache.modify({
|
|
304
|
+
id: cacheId,
|
|
305
|
+
fields: {
|
|
306
|
+
isActive: () => true,
|
|
307
|
+
updatedAt: () => new Date().toISOString(),
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Using readonly Types for Cache Modifiers
|
|
314
|
+
|
|
315
|
+
Apollo cache data is readonly. Use proper typing:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
cache.modify({
|
|
319
|
+
fields: {
|
|
320
|
+
players(existingPlayers: readonly { __ref: string }[] = [], { readField }) {
|
|
321
|
+
return existingPlayers.filter(ref => readField("id", ref) !== removedId);
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Decision Tree: Cache Update Strategy
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
Mutation creates/updates/deletes entity
|
|
331
|
+
│
|
|
332
|
+
▼
|
|
333
|
+
┌───────────────────────────────┐
|
|
334
|
+
│ Does mutation return entity │
|
|
335
|
+
│ with id and __typename? │
|
|
336
|
+
└───────────────────────────────┘
|
|
337
|
+
│
|
|
338
|
+
┌──────┴──────┐
|
|
339
|
+
│ YES │ NO
|
|
340
|
+
▼ ▼
|
|
341
|
+
┌─────────┐ ┌─────────────────┐
|
|
342
|
+
│Automatic│ │ Use │
|
|
343
|
+
│ Update │ │ refetchQueries │
|
|
344
|
+
└─────────┘ └─────────────────┘
|
|
345
|
+
│
|
|
346
|
+
▼
|
|
347
|
+
┌───────────────────────────────┐
|
|
348
|
+
│ Does entity need to appear │
|
|
349
|
+
│ in or disappear from a list? │
|
|
350
|
+
└───────────────────────────────┘
|
|
351
|
+
│
|
|
352
|
+
┌──────┴──────┐
|
|
353
|
+
│ YES │ NO
|
|
354
|
+
▼ ▼
|
|
355
|
+
┌─────────────┐ ┌─────────────┐
|
|
356
|
+
│cache.modify │ │ Automatic │
|
|
357
|
+
│ with list │ │ is enough │
|
|
358
|
+
│ manipulation│ │ │
|
|
359
|
+
└─────────────┘ └─────────────┘
|
|
360
|
+
```
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: atomic-design-gluestack
|
|
3
|
+
description: |
|
|
4
|
+
Enforces atomic design methodology (atoms, molecules, organisms, templates, pages) for React Native/Expo projects using Gluestack UI. This skill should be used when creating new components, validating existing component organization, reviewing component placement decisions, or planning component architecture. Use this skill to ensure components are properly categorized, placed in correct directories, and follow composition patterns appropriate to their atomic level.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Atomic Design with Gluestack UI
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This skill enforces Brad Frost's atomic design methodology adapted for React Native/Expo projects using Gluestack UI v3 + NativeWind v4. It provides clear guidelines for component categorization, directory structure, composition patterns, and testing strategies for each atomic level.
|
|
12
|
+
|
|
13
|
+
## Core Principles
|
|
14
|
+
|
|
15
|
+
### The Atomic Hierarchy
|
|
16
|
+
|
|
17
|
+
Components are organized into five levels, from simplest to most complex:
|
|
18
|
+
|
|
19
|
+
| Level | Definition | State | Examples |
|
|
20
|
+
|-------|------------|-------|----------|
|
|
21
|
+
| **Atoms** | Foundational building blocks that cannot be broken down further while remaining functional | Stateless (purely presentational) | Button, Text, Icon, Input, Badge |
|
|
22
|
+
| **Molecules** | Simple groups of UI elements functioning together as a unit | Isolated state (form validation, toggles) | SearchField, FormField, AvatarWithName |
|
|
23
|
+
| **Organisms** | Complex components composed of molecules and atoms forming distinct interface sections | Feature state, coordinates children | Header, ProductCard, NavigationDrawer |
|
|
24
|
+
| **Templates** | Page-level layouts that place components into a structure (skeleton without real content) | Layout state only | MainLayout, AuthLayout, DashboardLayout |
|
|
25
|
+
| **Pages** | Specific instances of templates with real content and data | Connected to global state | HomeScreen, ProfileScreen, SettingsScreen |
|
|
26
|
+
|
|
27
|
+
### Design Tokens Foundation
|
|
28
|
+
|
|
29
|
+
Design tokens sit **below atoms** as the foundational layer. In this project, tokens are defined in:
|
|
30
|
+
- `components/ui/gluestack-ui-provider/config.ts` - Color tokens (primary, secondary, error, success, etc.)
|
|
31
|
+
- `tailwind.config.js` - Spacing, typography, and other design tokens via NativeWind
|
|
32
|
+
|
|
33
|
+
## Directory Structure
|
|
34
|
+
|
|
35
|
+
### Required Structure
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
components/
|
|
39
|
+
├── ui/ # Gluestack UI library components (DO NOT MODIFY unless extending)
|
|
40
|
+
├── atoms/ # Project-specific atoms
|
|
41
|
+
│ ├── AppIcon/
|
|
42
|
+
│ │ ├── index.tsx
|
|
43
|
+
│ │ ├── AppIcon.test.tsx
|
|
44
|
+
│ │ └── types.ts
|
|
45
|
+
│ └── index.ts # Barrel export for atoms
|
|
46
|
+
├── molecules/ # Composite simple components
|
|
47
|
+
│ ├── SearchField/
|
|
48
|
+
│ │ ├── index.tsx
|
|
49
|
+
│ │ ├── SearchFieldView.tsx
|
|
50
|
+
│ │ ├── SearchField.test.tsx
|
|
51
|
+
│ │ └── types.ts
|
|
52
|
+
│ └── index.ts
|
|
53
|
+
├── organisms/ # Complex feature components
|
|
54
|
+
│ ├── Header/
|
|
55
|
+
│ │ ├── index.tsx
|
|
56
|
+
│ │ ├── HeaderView.tsx
|
|
57
|
+
│ │ ├── Header.test.tsx
|
|
58
|
+
│ │ └── types.ts
|
|
59
|
+
│ └── index.ts
|
|
60
|
+
└── templates/ # Page layouts
|
|
61
|
+
├── MainLayout/
|
|
62
|
+
│ ├── index.tsx
|
|
63
|
+
│ ├── MainLayoutView.tsx
|
|
64
|
+
│ └── types.ts
|
|
65
|
+
└── index.ts
|
|
66
|
+
|
|
67
|
+
features/
|
|
68
|
+
└── [feature-name]/
|
|
69
|
+
├── components/ # Feature-specific components (follow atomic naming)
|
|
70
|
+
│ ├── atoms/
|
|
71
|
+
│ ├── molecules/
|
|
72
|
+
│ └── organisms/
|
|
73
|
+
└── screens/ # Pages (specific to this feature)
|
|
74
|
+
|
|
75
|
+
app/ # Expo Router pages (connect templates with data)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Gluestack UI Components Location
|
|
79
|
+
|
|
80
|
+
The 40+ Gluestack UI components in `components/ui/` serve as the **foundation atom library**. When building custom components:
|
|
81
|
+
|
|
82
|
+
1. **Use Gluestack components as atoms** - Import from `@/components/ui/`
|
|
83
|
+
2. **Extend when needed** - Create project-specific atoms in `components/atoms/`
|
|
84
|
+
3. **Never modify `components/ui/`** - Except for theme customization in `config.ts`
|
|
85
|
+
|
|
86
|
+
## Component Classification Rules
|
|
87
|
+
|
|
88
|
+
### Rule 1: Atoms (Building Blocks)
|
|
89
|
+
|
|
90
|
+
**Definition**: Smallest functional UI elements that cannot be broken down further.
|
|
91
|
+
|
|
92
|
+
**Characteristics**:
|
|
93
|
+
- Stateless and purely presentational
|
|
94
|
+
- Accept props for customization
|
|
95
|
+
- No business logic
|
|
96
|
+
- Highly reusable across the entire app
|
|
97
|
+
|
|
98
|
+
**Gluestack Atoms** (use directly from `@/components/ui/`):
|
|
99
|
+
- Box, Center, HStack, VStack, ScrollView
|
|
100
|
+
- Text, Heading
|
|
101
|
+
- Button, ButtonText, ButtonIcon
|
|
102
|
+
- Input, InputField, InputSlot
|
|
103
|
+
- Icon, Image, Avatar
|
|
104
|
+
- Badge, Divider, Spinner
|
|
105
|
+
|
|
106
|
+
**When to create custom atoms**:
|
|
107
|
+
- Project-specific iconography
|
|
108
|
+
- Branded text variants
|
|
109
|
+
- Wrapper components with default styling
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
/**
|
|
113
|
+
* AppLogo atom - Branded logo component
|
|
114
|
+
* @description Displays the application logo with consistent sizing
|
|
115
|
+
*/
|
|
116
|
+
const AppLogo = memo(function AppLogo({ size = "md" }: AppLogoProps) {
|
|
117
|
+
return (
|
|
118
|
+
<Image
|
|
119
|
+
source={logoSource}
|
|
120
|
+
className={logoSizes[size]}
|
|
121
|
+
alt="App Logo"
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Rule 2: Molecules (Simple Compositions)
|
|
128
|
+
|
|
129
|
+
**Definition**: Simple groups of atoms functioning together as a unit.
|
|
130
|
+
|
|
131
|
+
**Characteristics**:
|
|
132
|
+
- Combines 2-5 atoms
|
|
133
|
+
- Single responsibility (does one thing well)
|
|
134
|
+
- May have isolated UI state (toggle, validation)
|
|
135
|
+
- No external data fetching
|
|
136
|
+
|
|
137
|
+
**Examples**:
|
|
138
|
+
```typescript
|
|
139
|
+
/**
|
|
140
|
+
* SearchField molecule - Search input with button
|
|
141
|
+
* @description Combines Input and Button atoms for search functionality
|
|
142
|
+
*/
|
|
143
|
+
const SearchField = memo(function SearchField({
|
|
144
|
+
onSearch,
|
|
145
|
+
placeholder
|
|
146
|
+
}: SearchFieldProps) {
|
|
147
|
+
const [value, setValue] = useState("");
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<HStack space="sm" className="items-center">
|
|
151
|
+
<Input className="flex-1">
|
|
152
|
+
<InputField
|
|
153
|
+
value={value}
|
|
154
|
+
onChangeText={setValue}
|
|
155
|
+
placeholder={placeholder}
|
|
156
|
+
/>
|
|
157
|
+
</Input>
|
|
158
|
+
<Button onPress={() => onSearch(value)}>
|
|
159
|
+
<ButtonIcon as={SearchIcon} />
|
|
160
|
+
</Button>
|
|
161
|
+
</HStack>
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Molecule Checklist**:
|
|
167
|
+
- [ ] Uses only atoms (Gluestack or custom)
|
|
168
|
+
- [ ] Has a single, clear purpose
|
|
169
|
+
- [ ] State is UI-only (no business logic)
|
|
170
|
+
- [ ] Reusable in multiple contexts
|
|
171
|
+
|
|
172
|
+
### Rule 3: Organisms (Complex Sections)
|
|
173
|
+
|
|
174
|
+
**Definition**: Relatively complex components forming distinct interface sections.
|
|
175
|
+
|
|
176
|
+
**Characteristics**:
|
|
177
|
+
- Combines molecules and atoms
|
|
178
|
+
- May have feature-specific state
|
|
179
|
+
- Can coordinate child component behavior
|
|
180
|
+
- Represents a standalone section of UI
|
|
181
|
+
|
|
182
|
+
**Examples**:
|
|
183
|
+
```typescript
|
|
184
|
+
/**
|
|
185
|
+
* ProductCard organism - Complete product display
|
|
186
|
+
* @description Displays product information with actions
|
|
187
|
+
*/
|
|
188
|
+
const ProductCard = memo(function ProductCard({
|
|
189
|
+
product,
|
|
190
|
+
onAddToCart
|
|
191
|
+
}: ProductCardProps) {
|
|
192
|
+
return (
|
|
193
|
+
<Card variant="elevated" size="md">
|
|
194
|
+
<ProductImage source={product.image} /> {/* Atom */}
|
|
195
|
+
<VStack space="sm" className="p-4">
|
|
196
|
+
<Heading size="md">{product.name}</Heading> {/* Atom */}
|
|
197
|
+
<PriceDisplay price={product.price} /> {/* Molecule */}
|
|
198
|
+
<RatingStars rating={product.rating} /> {/* Molecule */}
|
|
199
|
+
<AddToCartButton onPress={onAddToCart} /> {/* Molecule */}
|
|
200
|
+
</VStack>
|
|
201
|
+
</Card>
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Organism Checklist**:
|
|
207
|
+
- [ ] Forms a distinct interface section
|
|
208
|
+
- [ ] Combines molecules and/or atoms
|
|
209
|
+
- [ ] Has clear boundaries
|
|
210
|
+
- [ ] May receive data as props (but doesn't fetch)
|
|
211
|
+
|
|
212
|
+
### Rule 4: Templates (Page Layouts)
|
|
213
|
+
|
|
214
|
+
**Definition**: Page-level layouts that place components into a structure.
|
|
215
|
+
|
|
216
|
+
**Characteristics**:
|
|
217
|
+
- Defines layout skeleton with slots
|
|
218
|
+
- No real content (uses placeholder or children)
|
|
219
|
+
- Handles responsive behavior
|
|
220
|
+
- Manages layout-specific state only
|
|
221
|
+
|
|
222
|
+
**Example**:
|
|
223
|
+
```typescript
|
|
224
|
+
/**
|
|
225
|
+
* MainLayout template - Primary app layout
|
|
226
|
+
* @description Provides consistent header, content, and footer structure
|
|
227
|
+
*/
|
|
228
|
+
const MainLayout = memo(function MainLayout({
|
|
229
|
+
children,
|
|
230
|
+
showHeader = true,
|
|
231
|
+
showFooter = true
|
|
232
|
+
}: MainLayoutProps) {
|
|
233
|
+
return (
|
|
234
|
+
<SafeAreaView className="flex-1 bg-background-0">
|
|
235
|
+
{showHeader && <Header />}
|
|
236
|
+
<ScrollView className="flex-1">
|
|
237
|
+
{children}
|
|
238
|
+
</ScrollView>
|
|
239
|
+
{showFooter && <Footer />}
|
|
240
|
+
</SafeAreaView>
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Rule 5: Pages (Screens)
|
|
246
|
+
|
|
247
|
+
**Definition**: Specific instances of templates with real content and data.
|
|
248
|
+
|
|
249
|
+
**Characteristics**:
|
|
250
|
+
- Connects to global state (Apollo, Context)
|
|
251
|
+
- Handles data fetching
|
|
252
|
+
- Passes data to organisms/molecules
|
|
253
|
+
- Lives in `app/` (Expo Router) or `features/*/screens/`
|
|
254
|
+
|
|
255
|
+
**Example**:
|
|
256
|
+
```typescript
|
|
257
|
+
/**
|
|
258
|
+
* HomeScreen page - Main home page
|
|
259
|
+
* @description Renders home content with fetched data
|
|
260
|
+
*/
|
|
261
|
+
export default function HomeScreen() {
|
|
262
|
+
const { data, loading } = useHomeDataQuery();
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<MainLayout>
|
|
266
|
+
{loading ? (
|
|
267
|
+
<LoadingSpinner />
|
|
268
|
+
) : (
|
|
269
|
+
<VStack space="lg">
|
|
270
|
+
<FeaturedProducts products={data.featured} />
|
|
271
|
+
<RecentActivity items={data.activity} />
|
|
272
|
+
</VStack>
|
|
273
|
+
)}
|
|
274
|
+
</MainLayout>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Validation Rules
|
|
280
|
+
|
|
281
|
+
### Enforcement Checklist
|
|
282
|
+
|
|
283
|
+
When creating or reviewing components, verify:
|
|
284
|
+
|
|
285
|
+
1. **Correct Directory Placement**
|
|
286
|
+
- Atoms in `components/atoms/` or `features/*/components/atoms/`
|
|
287
|
+
- Molecules in `components/molecules/` or `features/*/components/molecules/`
|
|
288
|
+
- Organisms in `components/organisms/` or `features/*/components/organisms/`
|
|
289
|
+
- Templates in `components/templates/`
|
|
290
|
+
- Pages in `app/` or `features/*/screens/`
|
|
291
|
+
|
|
292
|
+
2. **State Appropriateness**
|
|
293
|
+
- Atoms: No state
|
|
294
|
+
- Molecules: UI state only (useState for toggles, form values)
|
|
295
|
+
- Organisms: Feature state, may use custom hooks
|
|
296
|
+
- Templates: Layout state only
|
|
297
|
+
- Pages: Connected to global state, data fetching
|
|
298
|
+
|
|
299
|
+
3. **Import Direction** (dependencies flow upward only)
|
|
300
|
+
```
|
|
301
|
+
Pages → Templates → Organisms → Molecules → Atoms → Design Tokens
|
|
302
|
+
```
|
|
303
|
+
- Atoms MUST NOT import from molecules, organisms, templates, or pages
|
|
304
|
+
- Molecules MUST NOT import from organisms, templates, or pages
|
|
305
|
+
- Organisms MUST NOT import from templates or pages
|
|
306
|
+
|
|
307
|
+
4. **Composition Appropriateness**
|
|
308
|
+
- Molecules combine 2-5 atoms
|
|
309
|
+
- Organisms can be complex but should represent a single interface section
|
|
310
|
+
- If an organism becomes too large, extract sub-organisms
|
|
311
|
+
|
|
312
|
+
### Common Mistakes to Avoid
|
|
313
|
+
|
|
314
|
+
| Mistake | Problem | Solution |
|
|
315
|
+
|---------|---------|----------|
|
|
316
|
+
| Atom with useState | Atoms should be stateless | Move state to parent molecule |
|
|
317
|
+
| Molecule fetching data | Data fetching belongs in pages | Accept data as props |
|
|
318
|
+
| Organism in atoms folder | Misclassification | Move to organisms folder |
|
|
319
|
+
| Template with business logic | Templates handle layout only | Move logic to page |
|
|
320
|
+
| Importing organism in atom | Wrong dependency direction | Restructure component hierarchy |
|
|
321
|
+
|
|
322
|
+
## Testing by Atomic Level
|
|
323
|
+
|
|
324
|
+
| Level | Test Type | Focus |
|
|
325
|
+
|-------|-----------|-------|
|
|
326
|
+
| Atoms | Unit + Snapshot | Props rendering, accessibility |
|
|
327
|
+
| Molecules | Unit + Interaction | Composition, isolated state |
|
|
328
|
+
| Organisms | Integration | Data flow, child coordination |
|
|
329
|
+
| Templates | Layout | Slot rendering, responsiveness |
|
|
330
|
+
| Pages | E2E | Full user flows |
|
|
331
|
+
|
|
332
|
+
## Quick Reference
|
|
333
|
+
|
|
334
|
+
### Decision Tree: Which Level?
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
Is it a single, indivisible UI element?
|
|
338
|
+
├─ YES → ATOM
|
|
339
|
+
└─ NO → Does it combine 2-5 atoms for a single purpose?
|
|
340
|
+
├─ YES → MOLECULE
|
|
341
|
+
└─ NO → Does it form a distinct interface section?
|
|
342
|
+
├─ YES → ORGANISM
|
|
343
|
+
└─ NO → Is it a layout skeleton?
|
|
344
|
+
├─ YES → TEMPLATE
|
|
345
|
+
└─ NO → PAGE
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Gluestack Component Level Map
|
|
349
|
+
|
|
350
|
+
Reference `references/gluestack-mapping.md` for the complete mapping of all 40 Gluestack UI components to their atomic levels.
|
|
351
|
+
|
|
352
|
+
## Resources
|
|
353
|
+
|
|
354
|
+
### references/
|
|
355
|
+
- `atomic-levels.md` - Detailed definitions with comprehensive examples
|
|
356
|
+
- `gluestack-mapping.md` - Complete Gluestack UI component classification
|
|
357
|
+
- `folder-structure.md` - Detailed directory structure requirements
|
|
358
|
+
|
|
359
|
+
### scripts/
|
|
360
|
+
- `validate_atomic_structure.py` - Validates component placement and imports
|