@olives/devos 2.1.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/.agents/AGENTS.md +316 -0
- package/.agents/README.md +55 -0
- package/.agents/agents/architect.md +18 -0
- package/.agents/agents/dba.md +25 -0
- package/.agents/agents/developer.md +40 -0
- package/.agents/agents/devops.md +18 -0
- package/.agents/agents/memory-manager.md +38 -0
- package/.agents/agents/orchestrator.md +92 -0
- package/.agents/agents/qa.md +53 -0
- package/.agents/agents/release-manager.md +41 -0
- package/.agents/agents/researcher.md +19 -0
- package/.agents/agents/security.md +27 -0
- package/.agents/agents/tester.md +21 -0
- package/.agents/commands/README.md +42 -0
- package/.agents/commands/architect.md +16 -0
- package/.agents/commands/commit.md +15 -0
- package/.agents/commands/deploy.md +18 -0
- package/.agents/commands/fix.md +19 -0
- package/.agents/commands/refactor.md +19 -0
- package/.agents/commands/research.md +19 -0
- package/.agents/commands/review.md +21 -0
- package/.agents/commands/secure.md +23 -0
- package/.agents/commands/status.md +16 -0
- package/.agents/commands/test.md +16 -0
- package/.agents/scripts/commit.sh +73 -0
- package/.agents/scripts/install-hooks.sh +72 -0
- package/.agents/skills/agent-browser/SKILL.md +50 -0
- package/.agents/skills/agent-development/SKILL.md +415 -0
- package/.agents/skills/agent-development/examples/agent-creation-prompt.md +238 -0
- package/.agents/skills/agent-development/examples/complete-agent-examples.md +427 -0
- package/.agents/skills/agent-development/references/agent-creation-system-prompt.md +207 -0
- package/.agents/skills/agent-development/references/system-prompt-design.md +411 -0
- package/.agents/skills/agent-development/references/triggering-examples.md +491 -0
- package/.agents/skills/agent-development/scripts/validate-agent.sh +217 -0
- package/.agents/skills/backend-dev-guidelines/SKILL.md +352 -0
- package/.agents/skills/backend-dev-guidelines/resources/architecture-overview.md +451 -0
- package/.agents/skills/backend-dev-guidelines/resources/async-and-errors.md +307 -0
- package/.agents/skills/backend-dev-guidelines/resources/complete-examples.md +638 -0
- package/.agents/skills/backend-dev-guidelines/resources/configuration.md +275 -0
- package/.agents/skills/backend-dev-guidelines/resources/database-patterns.md +224 -0
- package/.agents/skills/backend-dev-guidelines/resources/middleware-guide.md +213 -0
- package/.agents/skills/backend-dev-guidelines/resources/routing-and-controllers.md +756 -0
- package/.agents/skills/backend-dev-guidelines/resources/sentry-and-monitoring.md +336 -0
- package/.agents/skills/backend-dev-guidelines/resources/services-and-repositories.md +789 -0
- package/.agents/skills/backend-dev-guidelines/resources/testing-guide.md +235 -0
- package/.agents/skills/backend-dev-guidelines/resources/validation-patterns.md +754 -0
- package/.agents/skills/backend-development/SKILL.md +156 -0
- package/.agents/skills/backend-patterns/SKILL.md +562 -0
- package/.agents/skills/brainstorming/SKILL.md +159 -0
- package/.agents/skills/brainstorming/scripts/frame-template.html +213 -0
- package/.agents/skills/brainstorming/scripts/helper.js +167 -0
- package/.agents/skills/brainstorming/scripts/server.cjs +723 -0
- package/.agents/skills/brainstorming/scripts/start-server.sh +209 -0
- package/.agents/skills/brainstorming/scripts/stop-server.sh +120 -0
- package/.agents/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/.agents/skills/brainstorming/visual-companion.md +291 -0
- package/.agents/skills/code-reviewer/SKILL.md +65 -0
- package/.agents/skills/content-strategy/SKILL.md +365 -0
- package/.agents/skills/content-strategy/evals/evals.json +90 -0
- package/.agents/skills/content-strategy/references/headless-cms.md +194 -0
- package/.agents/skills/deploy-to-vercel/SKILL.md +296 -0
- package/.agents/skills/deploy-to-vercel/resources/deploy-codex.sh +301 -0
- package/.agents/skills/deploy-to-vercel/resources/deploy.sh +301 -0
- package/.agents/skills/deployment-checklist/SKILL.md +119 -0
- package/.agents/skills/design/SKILL.md +170 -0
- package/.agents/skills/design-an-interface/SKILL.md +94 -0
- package/.agents/skills/expose-localhost/SKILL.md +211 -0
- package/.agents/skills/expose-localhost/references/TROUBLESHOOTING.md +27 -0
- package/.agents/skills/find-skills/SKILL.md +142 -0
- package/.agents/skills/frontend-ui-engineering/SKILL.md +328 -0
- package/.agents/skills/git-commit/SKILL.md +124 -0
- package/.agents/skills/git-ops/SKILL.md +53 -0
- package/.agents/skills/git-workflow/SKILL.md +167 -0
- package/.agents/skills/google-agents-cli-adk-code/SKILL.md +72 -0
- package/.agents/skills/google-agents-cli-adk-code/references/adk-python.md +937 -0
- package/.agents/skills/google-agents-cli-adk-code/references/adk-workflows.md +507 -0
- package/.agents/skills/google-agents-cli-workflow/SKILL.md +310 -0
- package/.agents/skills/google-agents-cli-workflow/references/commands.md +12 -0
- package/.agents/skills/google-agents-cli-workflow/references/internals.md +24 -0
- package/.agents/skills/google-agents-cli-workflow/references/samples.md +59 -0
- package/.agents/skills/google-agents-cli-workflow/references/spec-template.md +25 -0
- package/.agents/skills/google-agents-cli-workflow/references/terminology.md +11 -0
- package/.agents/skills/grill-me/SKILL.md +47 -0
- package/.agents/skills/grill-with-docs/SKILL.md +7 -0
- package/.agents/skills/human-checkpoint/SKILL.md +21 -0
- package/.agents/skills/image/SKILL.md +340 -0
- package/.agents/skills/image/evals/evals.json +89 -0
- package/.agents/skills/image/references/ai-image-prompting.md +229 -0
- package/.agents/skills/image-generation/SKILL.md +374 -0
- package/.agents/skills/imagegen/LICENSE.txt +201 -0
- package/.agents/skills/imagegen/SKILL.md +279 -0
- package/.agents/skills/imagegen/agents/openai.yaml +6 -0
- package/.agents/skills/imagegen/assets/imagegen-small.svg +5 -0
- package/.agents/skills/imagegen/assets/imagegen.png +0 -0
- package/.agents/skills/imagegen/references/cli.md +160 -0
- package/.agents/skills/imagegen/references/codex-network.md +33 -0
- package/.agents/skills/imagegen/references/image-api.md +49 -0
- package/.agents/skills/imagegen/references/prompting.md +98 -0
- package/.agents/skills/imagegen/references/sample-prompts.md +376 -0
- package/.agents/skills/imagegen/scripts/image_gen.py +926 -0
- package/.agents/skills/imagegen-frontend-web/SKILL.md +987 -0
- package/.agents/skills/laravel-security/SKILL.md +948 -0
- package/.agents/skills/laravel-specialist/SKILL.md +264 -0
- package/.agents/skills/laravel-specialist/references/eloquent.md +351 -0
- package/.agents/skills/laravel-specialist/references/livewire.md +512 -0
- package/.agents/skills/laravel-specialist/references/queues.md +423 -0
- package/.agents/skills/laravel-specialist/references/routing.md +362 -0
- package/.agents/skills/laravel-specialist/references/testing.md +522 -0
- package/.agents/skills/laravel-tdd/SKILL.md +675 -0
- package/.agents/skills/laravel-verification/SKILL.md +180 -0
- package/.agents/skills/modern-web-guidance/SKILL.md +114 -0
- package/.agents/skills/modern-web-guidance/guides/accessibility/accessibility.md +463 -0
- package/.agents/skills/modern-web-guidance/guides/accessibility/accessible-error-announcement.md +207 -0
- package/.agents/skills/modern-web-guidance/guides/built-in-ai/language-detection.md +89 -0
- package/.agents/skills/modern-web-guidance/guides/built-in-ai/language-model.md +189 -0
- package/.agents/skills/modern-web-guidance/guides/built-in-ai/prompt-api.md +189 -0
- package/.agents/skills/modern-web-guidance/guides/built-in-ai/summarizer.md +154 -0
- package/.agents/skills/modern-web-guidance/guides/built-in-ai/translator.md +162 -0
- package/.agents/skills/modern-web-guidance/guides/css/css.md +527 -0
- package/.agents/skills/modern-web-guidance/guides/css/highlight-text-ranges.md +128 -0
- package/.agents/skills/modern-web-guidance/guides/css-layout/css-layout.md +305 -0
- package/.agents/skills/modern-web-guidance/guides/forms/animated-select-picker.md +178 -0
- package/.agents/skills/modern-web-guidance/guides/forms/autofill-address-form.md +75 -0
- package/.agents/skills/modern-web-guidance/guides/forms/autofill-highlight-inputs.md +45 -0
- package/.agents/skills/modern-web-guidance/guides/forms/autofill-payment-form.md +125 -0
- package/.agents/skills/modern-web-guidance/guides/forms/autofill-sign-in-form.md +135 -0
- package/.agents/skills/modern-web-guidance/guides/forms/autofill-sign-up-form.md +145 -0
- package/.agents/skills/modern-web-guidance/guides/forms/brand-consistent-forms.md +255 -0
- package/.agents/skills/modern-web-guidance/guides/forms/branded-select-styling.md +114 -0
- package/.agents/skills/modern-web-guidance/guides/forms/custom-select-picker-layouts.md +103 -0
- package/.agents/skills/modern-web-guidance/guides/forms/form-fields-automatically-fit-contents.md +121 -0
- package/.agents/skills/modern-web-guidance/guides/forms/forms.md +372 -0
- package/.agents/skills/modern-web-guidance/guides/forms/required-field-feedback.md +214 -0
- package/.agents/skills/modern-web-guidance/guides/forms/rich-media-picker.md +132 -0
- package/.agents/skills/modern-web-guidance/guides/forms/select-menu-interaction.md +180 -0
- package/.agents/skills/modern-web-guidance/guides/forms/validate-input-after-interaction.md +258 -0
- package/.agents/skills/modern-web-guidance/guides/html/html.md +407 -0
- package/.agents/skills/modern-web-guidance/guides/passkeys/passkey-authentication.md +205 -0
- package/.agents/skills/modern-web-guidance/guides/passkeys/passkey-conditional-create.md +134 -0
- package/.agents/skills/modern-web-guidance/guides/passkeys/passkey-management.md +211 -0
- package/.agents/skills/modern-web-guidance/guides/passkeys/passkey-reauthentication.md +128 -0
- package/.agents/skills/modern-web-guidance/guides/passkeys/passkey-registration.md +181 -0
- package/.agents/skills/modern-web-guidance/guides/passkeys/passkeys.md +38 -0
- package/.agents/skills/modern-web-guidance/guides/performance/batch-analytics-events.md +154 -0
- package/.agents/skills/modern-web-guidance/guides/performance/break-up-long-tasks.md +60 -0
- package/.agents/skills/modern-web-guidance/guides/performance/calculate-total-foreground-time.md +69 -0
- package/.agents/skills/modern-web-guidance/guides/performance/conditional-async-dependencies.md +71 -0
- package/.agents/skills/modern-web-guidance/guides/performance/defer-rendering-heavy-content.md +106 -0
- package/.agents/skills/modern-web-guidance/guides/performance/defer-work-until-scroll-ends.md +78 -0
- package/.agents/skills/modern-web-guidance/guides/performance/deprioritize-background-fetches.md +37 -0
- package/.agents/skills/modern-web-guidance/guides/performance/detect-initial-visibility-state.md +99 -0
- package/.agents/skills/modern-web-guidance/guides/performance/efficient-background-processing.md +117 -0
- package/.agents/skills/modern-web-guidance/guides/performance/faster-spa-view-transitions.md +79 -0
- package/.agents/skills/modern-web-guidance/guides/performance/full-session-analytics.md +135 -0
- package/.agents/skills/modern-web-guidance/guides/performance/identify-heavy-scripts.md +69 -0
- package/.agents/skills/modern-web-guidance/guides/performance/identify-inp-causes.md +73 -0
- package/.agents/skills/modern-web-guidance/guides/performance/improve-next-page-load-performance.md +119 -0
- package/.agents/skills/modern-web-guidance/guides/performance/interactions-in-complex-layouts.md +78 -0
- package/.agents/skills/modern-web-guidance/guides/performance/optimize-image-priority.md +61 -0
- package/.agents/skills/modern-web-guidance/guides/performance/optimize-preload-priority.md +41 -0
- package/.agents/skills/modern-web-guidance/guides/performance/optimize-script-priority.md +38 -0
- package/.agents/skills/modern-web-guidance/guides/performance/performance.md +366 -0
- package/.agents/skills/modern-web-guidance/guides/performance/resolution-optimized-pseudo-elements.md +47 -0
- package/.agents/skills/modern-web-guidance/guides/performance/schedule-tasks-by-priority.md +59 -0
- package/.agents/skills/modern-web-guidance/guides/performance/sequence-distributed-events.md +76 -0
- package/.agents/skills/modern-web-guidance/guides/privacy/privacy.md +247 -0
- package/.agents/skills/modern-web-guidance/guides/security/security.md +350 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/adapt-scrollbar-to-contrast-preferences.md +74 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/anchor-positioning-tab-underline.md +95 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/animate-element-entry-exit.md +131 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/animate-to-from-top-layer.md +140 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/animate-to-intrinsic-sizes.md +127 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/apply-webgl-shaders.md +239 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/calculate-event-differentials.md +85 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/calculate-with-intrinsic-sizes.md +196 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/capture-location-agnostic-data.md +63 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/carousel-slide-effects.md +187 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/carousel-snap-highlights.md +136 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/child-state-based-styling.md +101 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/complex-shapes.md +73 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/component-specific-light-dark-theme.md +179 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/consistent-cross-document-transitions.md +226 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/content-based-styling.md +118 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/coordinate-global-events.md +79 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/cross-document-transitions.md +127 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/custom-button-actions.md +173 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/customize-scrollbar-color-and-thickness.md +59 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/dark-mode.md +295 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/declarative-dialog-popover-control.md +238 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/deliver-optimized-decorative-images.md +49 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/design-token-reactivity.md +174 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/directional-navigation-transitions.md +125 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/dynamic-sibling-animations.md +54 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/dynamic-sibling-styling.md +98 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/export-html-media-from-canvas.md +256 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/expose-canvas-content-to-browser-features.md +401 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/flicker-free-client-side-ab-testing.md +168 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/fluid-scaling.md +78 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/format-human-readable-durations.md +87 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/group-element-transitions.md +124 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/improve-text-layout-and-legibility.md +76 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/individual-transform-properties.md +92 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/interactive-content-in-3d-scenes.md +383 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/interactive-content-reveal.md +118 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/interest-triggered-action-previews.md +79 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/interest-triggered-tooltips.md +132 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/light-dismiss-a-dialog.md +84 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/manage-recurring-intervals.md +73 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/model-partial-time-concepts.md +96 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/move-dom-element-without-losing-state.md +57 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/navigation-drawer.md +357 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/overflow-clipping-control.md +180 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/parallax-scroll-effects.md +230 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/persistent-app-tours.md +112 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/persistent-toast-notifications.md +30 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/persistent-top-layer-ui.md +48 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/physics-based-easing.md +118 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/platform-controls-dismiss-dialog.md +38 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/position-aware-tooltips.md +154 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/precise-text-alignment.md +99 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/prevent-text-wrapping.md +62 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/pull-to-reveal.md +83 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/reduce-style-repetition.md +87 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/resilient-context-menus-and-nested-dropdowns.md +102 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/same-document-transitions.md +177 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scroll-entry-exit-effects.md +173 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scroll-position-aware-elements.md +128 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scroll-progress-indicator.md +133 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scroll-snap-realtime-feedback.md +153 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scroll-snap-state-sync.md +93 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scroll-target-on-load.md +56 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scrollability-affordance-hints.md +124 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/scrollytelling.md +181 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/search-hidden-content.md +136 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/shaped-cutouts.md +146 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/shrinking-header-on-scroll.md +126 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/size-aware-styling.md +104 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/soft-edge-content-fade.md +62 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/stabilize-reactive-state.md +72 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/stack-drill-down.md +680 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/style-parent-with-has.md +199 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/support-global-calendar-systems.md +107 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/swipe-to-remove.md +527 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/visually-stable-font-fallbacks.md +49 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/visually-stable-mixed-fonts.md +61 -0
- package/.agents/skills/modern-web-guidance/guides/user-experience/visually-texture-content.md +76 -0
- package/.agents/skills/modern-web-guidance/guides/webmcp/agentic-forms.md +116 -0
- package/.agents/skills/modern-web-guidance/guides/webmcp/agentic-javascript-tools.md +116 -0
- package/.agents/skills/modern-web-guidance/guides/webmcp/webmcp.md +43 -0
- package/.agents/skills/nextjs-app-router-patterns/SKILL.md +114 -0
- package/.agents/skills/nextjs-app-router-patterns/references/details.md +428 -0
- package/.agents/skills/nextjs-developer/SKILL.md +145 -0
- package/.agents/skills/nextjs-developer/references/app-router.md +311 -0
- package/.agents/skills/nextjs-developer/references/data-fetching.md +482 -0
- package/.agents/skills/nextjs-developer/references/deployment.md +545 -0
- package/.agents/skills/nextjs-developer/references/server-actions.md +462 -0
- package/.agents/skills/nextjs-developer/references/server-components.md +384 -0
- package/.agents/skills/nextjs-supabase-auth/SKILL.md +313 -0
- package/.agents/skills/nodejs-backend-patterns/SKILL.md +45 -0
- package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
- package/.agents/skills/nodejs-backend-patterns/references/details.md +599 -0
- package/.agents/skills/performance-engineer/SKILL.md +181 -0
- package/.agents/skills/project-requirements/SKILL.md +43 -0
- package/.agents/skills/qa/SKILL.md +130 -0
- package/.agents/skills/security-review/LICENSE +22 -0
- package/.agents/skills/security-review/SKILL.md +312 -0
- package/.agents/skills/security-review/infrastructure/docker.md +432 -0
- package/.agents/skills/security-review/languages/javascript.md +387 -0
- package/.agents/skills/security-review/languages/python.md +363 -0
- package/.agents/skills/security-review/references/api-security.md +519 -0
- package/.agents/skills/security-review/references/authentication.md +353 -0
- package/.agents/skills/security-review/references/authorization.md +372 -0
- package/.agents/skills/security-review/references/business-logic.md +443 -0
- package/.agents/skills/security-review/references/cryptography.md +329 -0
- package/.agents/skills/security-review/references/csrf.md +398 -0
- package/.agents/skills/security-review/references/data-protection.md +378 -0
- package/.agents/skills/security-review/references/deserialization.md +410 -0
- package/.agents/skills/security-review/references/error-handling.md +436 -0
- package/.agents/skills/security-review/references/file-security.md +457 -0
- package/.agents/skills/security-review/references/injection.md +259 -0
- package/.agents/skills/security-review/references/logging.md +433 -0
- package/.agents/skills/security-review/references/misconfiguration.md +435 -0
- package/.agents/skills/security-review/references/modern-threats.md +475 -0
- package/.agents/skills/security-review/references/ssrf.md +413 -0
- package/.agents/skills/security-review/references/supply-chain.md +405 -0
- package/.agents/skills/security-review/references/xss.md +336 -0
- package/.agents/skills/seo-aeo-best-practices/SKILL.md +37 -0
- package/.agents/skills/seo-aeo-best-practices/references/aeo-considerations.md +159 -0
- package/.agents/skills/seo-aeo-best-practices/references/eeat-principles.md +127 -0
- package/.agents/skills/seo-aeo-best-practices/references/structured-data.md +183 -0
- package/.agents/skills/seo-aeo-best-practices/references/technical-seo.md +188 -0
- package/.agents/skills/seo-geo/.claude-plugin/plugin.json +29 -0
- package/.agents/skills/seo-geo/SKILL.md +250 -0
- package/.agents/skills/seo-geo/examples/opc-skills-case-study.md +330 -0
- package/.agents/skills/seo-geo/references/geo-research.md +319 -0
- package/.agents/skills/seo-geo/references/google-docs-summary.md +65 -0
- package/.agents/skills/seo-geo/references/platform-algorithms.md +354 -0
- package/.agents/skills/seo-geo/references/schema-templates.md +517 -0
- package/.agents/skills/seo-geo/references/seo-checklist.md +249 -0
- package/.agents/skills/seo-geo/references/tools-and-apis.md +313 -0
- package/.agents/skills/seo-geo/scripts/autocomplete_ideas.py +74 -0
- package/.agents/skills/seo-geo/scripts/backlinks.py +37 -0
- package/.agents/skills/seo-geo/scripts/competitor_gap.py +80 -0
- package/.agents/skills/seo-geo/scripts/credential.py +12 -0
- package/.agents/skills/seo-geo/scripts/dataforseo_api.py +104 -0
- package/.agents/skills/seo-geo/scripts/domain_overview.py +44 -0
- package/.agents/skills/seo-geo/scripts/keyword_research.py +38 -0
- package/.agents/skills/seo-geo/scripts/related_keywords.py +84 -0
- package/.agents/skills/seo-geo/scripts/seo_audit.py +151 -0
- package/.agents/skills/seo-geo/scripts/serp_analysis.py +41 -0
- package/.agents/skills/shadcn-ui/README.md +248 -0
- package/.agents/skills/shadcn-ui/SKILL.md +326 -0
- package/.agents/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
- package/.agents/skills/shadcn-ui/examples/data-table.tsx +313 -0
- package/.agents/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
- package/.agents/skills/shadcn-ui/resources/component-catalog.md +481 -0
- package/.agents/skills/shadcn-ui/resources/customization-guide.md +516 -0
- package/.agents/skills/shadcn-ui/resources/migration-guide.md +463 -0
- package/.agents/skills/shadcn-ui/resources/setup-guide.md +412 -0
- package/.agents/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
- package/.agents/skills/skill-creator/LICENSE.txt +202 -0
- package/.agents/skills/skill-creator/SKILL.md +485 -0
- package/.agents/skills/skill-creator/agents/analyzer.md +274 -0
- package/.agents/skills/skill-creator/agents/comparator.md +202 -0
- package/.agents/skills/skill-creator/agents/grader.md +223 -0
- package/.agents/skills/skill-creator/assets/eval_review.html +146 -0
- package/.agents/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/.agents/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/.agents/skills/skill-creator/references/schemas.md +430 -0
- package/.agents/skills/skill-creator/scripts/__init__.py +0 -0
- package/.agents/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/.agents/skills/skill-creator/scripts/generate_report.py +326 -0
- package/.agents/skills/skill-creator/scripts/improve_description.py +247 -0
- package/.agents/skills/skill-creator/scripts/package_skill.py +136 -0
- package/.agents/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/.agents/skills/skill-creator/scripts/run_eval.py +310 -0
- package/.agents/skills/skill-creator/scripts/run_loop.py +328 -0
- package/.agents/skills/skill-creator/scripts/utils.py +47 -0
- package/.agents/skills/stacks/SKILL.md +21 -0
- package/.agents/skills/stacks/django.md +187 -0
- package/.agents/skills/stacks/express.md +16 -0
- package/.agents/skills/stacks/fastapi.md +17 -0
- package/.agents/skills/stacks/laravel.md +18 -0
- package/.agents/skills/stacks/nextjs.md +20 -0
- package/.agents/skills/stacks/react-native.md +170 -0
- package/.agents/skills/supabase/CHANGELOG.md +35 -0
- package/.agents/skills/supabase/SKILL.md +135 -0
- package/.agents/skills/supabase/assets/feedback-issue-template.md +17 -0
- package/.agents/skills/supabase/references/skill-feedback.md +17 -0
- package/.agents/skills/supabase-postgres-best-practices/CHANGELOG.md +29 -0
- package/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/.agents/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
- package/.agents/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
- package/.agents/skills/supabase-postgres-best-practices/references/_template.md +34 -0
- package/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
- package/.agents/skills/task-contract/SKILL.md +29 -0
- package/.agents/skills/token-optimization/SKILL.md +40 -0
- package/.agents/skills/ui-designer/SKILL.md +76 -0
- package/.agents/skills/ui-ux-pro-max/SKILL.md +704 -0
- package/.agents/skills/ui-ux-pro-max/data/_sync_all.py +414 -0
- package/.agents/skills/ui-ux-pro-max/data/app-interface.csv +31 -0
- package/.agents/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.agents/skills/ui-ux-pro-max/data/colors.csv +162 -0
- package/.agents/skills/ui-ux-pro-max/data/design.csv +1776 -0
- package/.agents/skills/ui-ux-pro-max/data/draft.csv +1779 -0
- package/.agents/skills/ui-ux-pro-max/data/google-fonts.csv +1924 -0
- package/.agents/skills/ui-ux-pro-max/data/icons.csv +106 -0
- package/.agents/skills/ui-ux-pro-max/data/landing.csv +35 -0
- package/.agents/skills/ui-ux-pro-max/data/motion.csv +17 -0
- package/.agents/skills/ui-ux-pro-max/data/products.csv +162 -0
- package/.agents/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/angular.csv +51 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/laravel.csv +51 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/threejs.csv +54 -0
- package/.agents/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.agents/skills/ui-ux-pro-max/data/styles.csv +85 -0
- package/.agents/skills/ui-ux-pro-max/data/typography.csv +74 -0
- package/.agents/skills/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
- package/.agents/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.agents/skills/ui-ux-pro-max/scripts/core.py +274 -0
- package/.agents/skills/ui-ux-pro-max/scripts/design_system.py +1329 -0
- package/.agents/skills/ui-ux-pro-max/scripts/search.py +127 -0
- package/.agents/skills/vercel-cli-with-tokens/SKILL.md +353 -0
- package/.agents/skills/vercel-composition-patterns/AGENTS.md +946 -0
- package/.agents/skills/vercel-composition-patterns/README.md +60 -0
- package/.agents/skills/vercel-composition-patterns/SKILL.md +89 -0
- package/.agents/skills/vercel-composition-patterns/metadata.json +11 -0
- package/.agents/skills/vercel-composition-patterns/rules/_sections.md +29 -0
- package/.agents/skills/vercel-composition-patterns/rules/_template.md +24 -0
- package/.agents/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/.agents/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/.agents/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/.agents/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/.agents/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/.agents/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/.agents/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/.agents/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/.agents/skills/vercel-optimize/AGENTS.md +48 -0
- package/.agents/skills/vercel-optimize/CONTRIBUTING.md +41 -0
- package/.agents/skills/vercel-optimize/README.md +91 -0
- package/.agents/skills/vercel-optimize/SKILL.md +322 -0
- package/.agents/skills/vercel-optimize/lib/auth-route.mjs +23 -0
- package/.agents/skills/vercel-optimize/lib/budget-summary.mjs +182 -0
- package/.agents/skills/vercel-optimize/lib/citations.mjs +139 -0
- package/.agents/skills/vercel-optimize/lib/cost-coverage.mjs +143 -0
- package/.agents/skills/vercel-optimize/lib/dedup-recs.mjs +325 -0
- package/.agents/skills/vercel-optimize/lib/deep-dive.mjs +350 -0
- package/.agents/skills/vercel-optimize/lib/display-labels.mjs +185 -0
- package/.agents/skills/vercel-optimize/lib/extract-claims.mjs +550 -0
- package/.agents/skills/vercel-optimize/lib/framework-support.mjs +67 -0
- package/.agents/skills/vercel-optimize/lib/gates/build-minutes-fanout.mjs +69 -0
- package/.agents/skills/vercel-optimize/lib/gates/cold-start.mjs +66 -0
- package/.agents/skills/vercel-optimize/lib/gates/contract.mjs +79 -0
- package/.agents/skills/vercel-optimize/lib/gates/cwv-poor.mjs +87 -0
- package/.agents/skills/vercel-optimize/lib/gates/external-api-slow.mjs +55 -0
- package/.agents/skills/vercel-optimize/lib/gates/hard-gates.mjs +73 -0
- package/.agents/skills/vercel-optimize/lib/gates/index.mjs +45 -0
- package/.agents/skills/vercel-optimize/lib/gates/isr-overrevalidation.mjs +62 -0
- package/.agents/skills/vercel-optimize/lib/gates/middleware-heavy.mjs +51 -0
- package/.agents/skills/vercel-optimize/lib/gates/observability-events-attribution.mjs +56 -0
- package/.agents/skills/vercel-optimize/lib/gates/platform-bot-protection.mjs +115 -0
- package/.agents/skills/vercel-optimize/lib/gates/platform-fluid-compute.mjs +83 -0
- package/.agents/skills/vercel-optimize/lib/gates/region-misconfig.mjs +64 -0
- package/.agents/skills/vercel-optimize/lib/gates/route-errors.mjs +80 -0
- package/.agents/skills/vercel-optimize/lib/gates/scanner-driven.mjs +122 -0
- package/.agents/skills/vercel-optimize/lib/gates/select-candidates.mjs +134 -0
- package/.agents/skills/vercel-optimize/lib/gates/slow-route.mjs +88 -0
- package/.agents/skills/vercel-optimize/lib/gates/types.d.ts +38 -0
- package/.agents/skills/vercel-optimize/lib/gates/uncached-route.mjs +93 -0
- package/.agents/skills/vercel-optimize/lib/gates/usage-spike-triage.mjs +121 -0
- package/.agents/skills/vercel-optimize/lib/grade-recommendation.mjs +155 -0
- package/.agents/skills/vercel-optimize/lib/impact-label.mjs +126 -0
- package/.agents/skills/vercel-optimize/lib/impact-magnitude.mjs +60 -0
- package/.agents/skills/vercel-optimize/lib/investigation-brief.mjs +610 -0
- package/.agents/skills/vercel-optimize/lib/observation-safety.mjs +174 -0
- package/.agents/skills/vercel-optimize/lib/project-facts.mjs +99 -0
- package/.agents/skills/vercel-optimize/lib/queries.mjs +315 -0
- package/.agents/skills/vercel-optimize/lib/reconcile-candidates.mjs +372 -0
- package/.agents/skills/vercel-optimize/lib/render-report.mjs +955 -0
- package/.agents/skills/vercel-optimize/lib/repo-root.mjs +86 -0
- package/.agents/skills/vercel-optimize/lib/route-normalize.mjs +220 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/bot-protection-certainty.mjs +38 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/cache-tag-invalidation-certainty.mjs +30 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/count-correct.mjs +52 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/function-duration-invocations.mjs +38 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/index.mjs +79 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/middleware-conflict.mjs +36 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/missing-citation.mjs +16 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/pre-release.mjs +74 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/rate-limit.mjs +67 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/rendering-mode-mislabel.mjs +38 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/undeclared-dep.mjs +78 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/vercel-directive-strip.mjs +37 -0
- package/.agents/skills/vercel-optimize/lib/sanitizers/window-units.mjs +32 -0
- package/.agents/skills/vercel-optimize/lib/scanners/cache-components-suspense-dedupe.mjs +109 -0
- package/.agents/skills/vercel-optimize/lib/scanners/edge-heavy-import.mjs +94 -0
- package/.agents/skills/vercel-optimize/lib/scanners/force-dynamic.mjs +42 -0
- package/.agents/skills/vercel-optimize/lib/scanners/headers-in-page.mjs +44 -0
- package/.agents/skills/vercel-optimize/lib/scanners/index.mjs +35 -0
- package/.agents/skills/vercel-optimize/lib/scanners/large-static-asset.mjs +92 -0
- package/.agents/skills/vercel-optimize/lib/scanners/max-age-without-s-maxage.mjs +42 -0
- package/.agents/skills/vercel-optimize/lib/scanners/middleware-broad-matcher.mjs +55 -0
- package/.agents/skills/vercel-optimize/lib/scanners/missing-cache-headers.mjs +90 -0
- package/.agents/skills/vercel-optimize/lib/scanners/prisma-include-tree.mjs +42 -0
- package/.agents/skills/vercel-optimize/lib/scanners/region-pin-in-config.mjs +88 -0
- package/.agents/skills/vercel-optimize/lib/scanners/source-maps-production.mjs +36 -0
- package/.agents/skills/vercel-optimize/lib/scanners/sveltekit-prerender-missing.mjs +43 -0
- package/.agents/skills/vercel-optimize/lib/scanners/turbo-force-bypass.mjs +129 -0
- package/.agents/skills/vercel-optimize/lib/scanners/unoptimized-image.mjs +113 -0
- package/.agents/skills/vercel-optimize/lib/scanners/use-cache-date-stamp.mjs +106 -0
- package/.agents/skills/vercel-optimize/lib/support-topics.mjs +355 -0
- package/.agents/skills/vercel-optimize/lib/throttle.mjs +273 -0
- package/.agents/skills/vercel-optimize/lib/util.mjs +17 -0
- package/.agents/skills/vercel-optimize/lib/vercel.mjs +864 -0
- package/.agents/skills/vercel-optimize/lib/verify-claim.mjs +1296 -0
- package/.agents/skills/vercel-optimize/lib/workspace-resolver.mjs +521 -0
- package/.agents/skills/vercel-optimize/metadata.json +14 -0
- package/.agents/skills/vercel-optimize/references/candidates.md +176 -0
- package/.agents/skills/vercel-optimize/references/data-collection.md +218 -0
- package/.agents/skills/vercel-optimize/references/docs-library.json +683 -0
- package/.agents/skills/vercel-optimize/references/doctrine.md +105 -0
- package/.agents/skills/vercel-optimize/references/observability-plus.md +108 -0
- package/.agents/skills/vercel-optimize/references/playbooks/README.md +53 -0
- package/.agents/skills/vercel-optimize/references/playbooks/ai-application.md +32 -0
- package/.agents/skills/vercel-optimize/references/playbooks/api-service.md +30 -0
- package/.agents/skills/vercel-optimize/references/playbooks/content-site.md +30 -0
- package/.agents/skills/vercel-optimize/references/playbooks/ecommerce.md +30 -0
- package/.agents/skills/vercel-optimize/references/playbooks/marketing.md +30 -0
- package/.agents/skills/vercel-optimize/references/playbooks/saas.md +31 -0
- package/.agents/skills/vercel-optimize/references/playbooks/sveltekit.md +75 -0
- package/.agents/skills/vercel-optimize/references/recommendations.md +203 -0
- package/.agents/skills/vercel-optimize/references/scanner-patterns.md +251 -0
- package/.agents/skills/vercel-optimize/references/scoring.md +205 -0
- package/.agents/skills/vercel-optimize/references/support-topics/README.md +46 -0
- package/.agents/skills/vercel-optimize/references/support-topics/astro-edge-middleware-scope.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/astro-output-mode-and-isr.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/auth-preserving-parallelization.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/bot-protection-product-guardrails.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/build-minutes-monorepo-fanout.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/cache-components-static-shell-boundaries.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/cache-components-suspense-dedupe-pitfall.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/cdn-cache-auth-safety.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/cold-start-initialization-bundle.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/core-web-vitals-client-bottlenecks.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/database-egress-pooling-region.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/dynamic-rendering-traps.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/external-api-critical-path-platform.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/external-api-critical-path.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/fast-data-transfer-payloads.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/fluid-compute-caveats.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/function-duration-io-and-after.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/function-invocation-reduction.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/function-region-misconfiguration-ttfb.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/image-optimization-cost-control.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/isr-revalidation-static-generation.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/middleware-proxy-edge-cost.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/next-fetch-revalidate-floor.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/next-font-cls-self-hosting.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/next-heavy-ui-lazy-load-boundaries.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/next-image-lcp-preload-sizes.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/next-route-handler-get-cache-defaults.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/next-script-third-party-strategy.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/nextjs-version-cache-semantics.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/not-found-catchall-request-waste.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/nuxt-route-rules-cache-isr.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/observability-events-cost-attribution.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/post-response-work-waituntil.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/route-error-durable-offload.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/route-error-runtime-limits.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/runtime-cache-reusable-data.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/sveltekit-isr-prerender-safety.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/sveltekit-split-cold-start-tradeoff.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/usage-spike-triage.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/use-cache-date-stamp-isr-write-amplifier.md +23 -0
- package/.agents/skills/vercel-optimize/references/support-topics/use-cache-remote-shared-origin-data.md +22 -0
- package/.agents/skills/vercel-optimize/references/support-topics/workflow-resumable-stream-routes.md +23 -0
- package/.agents/skills/vercel-optimize/references/verification.md +102 -0
- package/.agents/skills/vercel-optimize/references/voice.md +76 -0
- package/.agents/skills/vercel-optimize/scripts/budget-summary.mjs +56 -0
- package/.agents/skills/vercel-optimize/scripts/build-docs.mjs +74 -0
- package/.agents/skills/vercel-optimize/scripts/check-citations.mjs +81 -0
- package/.agents/skills/vercel-optimize/scripts/check-docs-fresh.mjs +93 -0
- package/.agents/skills/vercel-optimize/scripts/collect-signals.mjs +576 -0
- package/.agents/skills/vercel-optimize/scripts/collect-sub-agent-outputs.mjs +296 -0
- package/.agents/skills/vercel-optimize/scripts/deep-dive.mjs +319 -0
- package/.agents/skills/vercel-optimize/scripts/gate-investigations.mjs +166 -0
- package/.agents/skills/vercel-optimize/scripts/merge-signals.mjs +192 -0
- package/.agents/skills/vercel-optimize/scripts/prepare-investigation-brief.mjs +231 -0
- package/.agents/skills/vercel-optimize/scripts/reconcile-candidates.mjs +62 -0
- package/.agents/skills/vercel-optimize/scripts/render-report.mjs +437 -0
- package/.agents/skills/vercel-optimize/scripts/scan-codebase.mjs +313 -0
- package/.agents/skills/vercel-optimize/scripts/verify-and-regen.mjs +346 -0
- package/.agents/skills/vercel-optimize/scripts/verify-finding.mjs +19 -0
- package/.agents/skills/vercel-react-best-practices/AGENTS.md +3810 -0
- package/.agents/skills/vercel-react-best-practices/README.md +123 -0
- package/.agents/skills/vercel-react-best-practices/SKILL.md +149 -0
- package/.agents/skills/vercel-react-best-practices/metadata.json +15 -0
- package/.agents/skills/vercel-react-best-practices/rules/_sections.md +46 -0
- package/.agents/skills/vercel-react-best-practices/rules/_template.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/.agents/skills/vercel-react-native-skills/AGENTS.md +2897 -0
- package/.agents/skills/vercel-react-native-skills/README.md +165 -0
- package/.agents/skills/vercel-react-native-skills/SKILL.md +121 -0
- package/.agents/skills/vercel-react-native-skills/metadata.json +16 -0
- package/.agents/skills/vercel-react-native-skills/rules/_sections.md +86 -0
- package/.agents/skills/vercel-react-native-skills/rules/_template.md +28 -0
- package/.agents/skills/vercel-react-native-skills/rules/animation-derived-value.md +53 -0
- package/.agents/skills/vercel-react-native-skills/rules/animation-gesture-detector-press.md +95 -0
- package/.agents/skills/vercel-react-native-skills/rules/animation-gpu-properties.md +65 -0
- package/.agents/skills/vercel-react-native-skills/rules/design-system-compound-components.md +66 -0
- package/.agents/skills/vercel-react-native-skills/rules/fonts-config-plugin.md +71 -0
- package/.agents/skills/vercel-react-native-skills/rules/imports-design-system-folder.md +68 -0
- package/.agents/skills/vercel-react-native-skills/rules/js-hoist-intl.md +61 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-callbacks.md +44 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-function-references.md +132 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-images.md +53 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-inline-objects.md +97 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-item-expensive.md +94 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-item-memo.md +82 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-item-types.md +104 -0
- package/.agents/skills/vercel-react-native-skills/rules/list-performance-virtualize.md +67 -0
- package/.agents/skills/vercel-react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
- package/.agents/skills/vercel-react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
- package/.agents/skills/vercel-react-native-skills/rules/navigation-native-navigators.md +188 -0
- package/.agents/skills/vercel-react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
- package/.agents/skills/vercel-react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
- package/.agents/skills/vercel-react-native-skills/rules/react-state-dispatcher.md +91 -0
- package/.agents/skills/vercel-react-native-skills/rules/react-state-fallback.md +56 -0
- package/.agents/skills/vercel-react-native-skills/rules/react-state-minimize.md +65 -0
- package/.agents/skills/vercel-react-native-skills/rules/rendering-no-falsy-and.md +74 -0
- package/.agents/skills/vercel-react-native-skills/rules/rendering-text-in-text-component.md +36 -0
- package/.agents/skills/vercel-react-native-skills/rules/scroll-position-no-state.md +82 -0
- package/.agents/skills/vercel-react-native-skills/rules/state-ground-truth.md +80 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-expo-image.md +66 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-image-gallery.md +104 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-measure-views.md +78 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-menus.md +174 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-native-modals.md +77 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-pressable.md +61 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-safe-area-scroll.md +65 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
- package/.agents/skills/vercel-react-native-skills/rules/ui-styling.md +87 -0
- package/.agents/skills/vercel-react-view-transitions/AGENTS.md +955 -0
- package/.agents/skills/vercel-react-view-transitions/README.md +42 -0
- package/.agents/skills/vercel-react-view-transitions/SKILL.md +320 -0
- package/.agents/skills/vercel-react-view-transitions/metadata.json +12 -0
- package/.agents/skills/vercel-react-view-transitions/references/css-recipes.md +242 -0
- package/.agents/skills/vercel-react-view-transitions/references/implementation.md +182 -0
- package/.agents/skills/vercel-react-view-transitions/references/nextjs.md +176 -0
- package/.agents/skills/vercel-react-view-transitions/references/patterns.md +262 -0
- package/.agents/skills/web-design-guidelines/SKILL.md +39 -0
- package/.agents/skills/workflow-metrics/SKILL.md +18 -0
- package/.agents/skills/writing-guidelines/SKILL.md +39 -0
- package/CODING_STANDARDS.md +49 -0
- package/LICENSE +21 -0
- package/README.md +556 -0
- package/VERSION +1 -0
- package/bin/devos.js +893 -0
- package/docs/.gitkeep +0 -0
- package/docs/ARCHITECTURE.md +114 -0
- package/docs/CHANGELOG.md +61 -0
- package/docs/CURRENT_STATE.md +39 -0
- package/docs/FIELD_REPORT_2026-08-20.md +130 -0
- package/docs/GETTING_STARTED.md +130 -0
- package/docs/LESSONS.md +24 -0
- package/docs/PRE_COMMIT_HOOK.md +152 -0
- package/docs/SLASH_COMMANDS.md +116 -0
- package/docs/TUTORIAL.md +75 -0
- package/package.json +54 -0
- package/scripts/smoke-test.js +167 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
# Swipe to remove
|
|
2
|
+
|
|
3
|
+
Swipe-to-remove patterns are common in mobile applications but can be challenging to implement cleanly on the web. By using CSS Scroll Snap, you can create a smooth, native-feeling swipe interaction that hooks directly into the browser's scrolling engine. This ensures high performance and physics-based momentum without needing a complex JavaScript gesture library.
|
|
4
|
+
|
|
5
|
+
The same pattern works for any single-action swipe (remove, archive, mark as read, snooze). The action visuals change; the mechanics do not.
|
|
6
|
+
|
|
7
|
+
## How to implement
|
|
8
|
+
|
|
9
|
+
The component has two layers: a **list** (the `<ul>`) and the **items** inside it. Each item is structured as an outer `<li>`, an inner scroll **track** (the scroll container with the snap points), and a **content** element (the visible row). The action's revealed UI (trash icon, archive label, etc.) lives on either side of the content. The list owns shared wiring (lazy item setup, picking up newly added items); each item owns its own swipe detection.
|
|
10
|
+
|
|
11
|
+
### Step 1: Mark up the list with track and content
|
|
12
|
+
|
|
13
|
+
```html
|
|
14
|
+
<ul class="SwipeableList">
|
|
15
|
+
<li id="list-item-1" class="SwipeableList-item">
|
|
16
|
+
<div class="SwipeableList-track">
|
|
17
|
+
<div class="SwipeableList-content">Item One</div>
|
|
18
|
+
</div>
|
|
19
|
+
</li>
|
|
20
|
+
<li id="list-item-2" class="SwipeableList-item">
|
|
21
|
+
<div class="SwipeableList-track">
|
|
22
|
+
<div class="SwipeableList-content">Item Two</div>
|
|
23
|
+
</div>
|
|
24
|
+
</li>
|
|
25
|
+
<!-- ...more items... -->
|
|
26
|
+
</ul>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Step 2: Configure the track as a horizontal snap container with three snap points
|
|
30
|
+
|
|
31
|
+
The track has three full-width columns: a left spacer (`::before`), the content, and a right spacer (`::after`). Snapping to a spacer means the content is fully off-screen, which is the rest position after a committed swipe.
|
|
32
|
+
|
|
33
|
+
The track configuration is gated behind an `.is-initialized` class on the list item. Before JS upgrades the row, the item just renders as plain content with no horizontal scroller. The class is added in Step 4 once the JavaScript that detects swipes has been wired up. This ensures the user cannot swipe before the functionality is ready.
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
.SwipeableList {
|
|
37
|
+
list-style: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.SwipeableList-item {
|
|
41
|
+
/* Establishes a containing block for the absolutely positioned action
|
|
42
|
+
icons (Step 3) and clips overflow during the row's removal
|
|
43
|
+
animation (Step 4). */
|
|
44
|
+
contain: content;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* The track only becomes a scroll snap container after JS upgrades
|
|
48
|
+
the row by adding `.is-initialized` (see Step 4). */
|
|
49
|
+
.SwipeableList-item.is-initialized .SwipeableList-track {
|
|
50
|
+
/* Three full-width columns: left spacer | content | right spacer.
|
|
51
|
+
Width is 100% of the track, so each column fills the viewport row. */
|
|
52
|
+
display: grid;
|
|
53
|
+
grid-template-columns: 100% 100% 100%;
|
|
54
|
+
|
|
55
|
+
/* Horizontal scroll only; vertical overflow is clipped so the
|
|
56
|
+
reveal stays inside the row. */
|
|
57
|
+
overflow: scroll clip;
|
|
58
|
+
|
|
59
|
+
/* Prevent the swipe from chaining into the page scroll or browser
|
|
60
|
+
back-gesture on iOS/Android. */
|
|
61
|
+
overscroll-behavior-x: none;
|
|
62
|
+
|
|
63
|
+
/* Hide the scrollbar; the gesture is the affordance. */
|
|
64
|
+
scrollbar-width: none;
|
|
65
|
+
|
|
66
|
+
/* `mandatory` ensures the track always rests on a snap point
|
|
67
|
+
(spacer or content), never partially scrolled. */
|
|
68
|
+
scroll-snap-type: x mandatory;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Spacers act as the left and right snap targets, AND carry the action's
|
|
72
|
+
reveal color. As the user swipes, the colored spacer slides into view,
|
|
73
|
+
which is what the user sees behind the content. */
|
|
74
|
+
.SwipeableList-item.is-initialized .SwipeableList-track::before,
|
|
75
|
+
.SwipeableList-item.is-initialized .SwipeableList-track::after {
|
|
76
|
+
content: '';
|
|
77
|
+
|
|
78
|
+
/* `scroll-snap-align` is required to make this a valid snap target,
|
|
79
|
+
but the specific value (`start`/`center`/`end`) doesn't matter here
|
|
80
|
+
because each snap point spans the full width of the scroll
|
|
81
|
+
container, so all alignments resolve to the same resting position. */
|
|
82
|
+
scroll-snap-align: start;
|
|
83
|
+
|
|
84
|
+
/* `hsl(0 65% 50%)` is an example value; pick whatever fits your
|
|
85
|
+
design (red here signals "delete"; use a different color for
|
|
86
|
+
archive, mark-as-read, etc.). */
|
|
87
|
+
background-color: hsl(0 65% 50%);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.SwipeableList-content {
|
|
91
|
+
/* The content sits above the action icons (Step 3), so it covers
|
|
92
|
+
them until the user swipes. */
|
|
93
|
+
position: relative;
|
|
94
|
+
z-index: 2;
|
|
95
|
+
|
|
96
|
+
/* Required to make the content a valid snap target (its resting
|
|
97
|
+
position). As with the spacers above, the specific value doesn't
|
|
98
|
+
matter because the snap points are full-width. */
|
|
99
|
+
scroll-snap-align: start;
|
|
100
|
+
|
|
101
|
+
/* The content must paint over the revealed spacer color. */
|
|
102
|
+
background: Canvas;
|
|
103
|
+
|
|
104
|
+
/* Row separator (example value; customize to taste). */
|
|
105
|
+
border-bottom: 1px solid #eee;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Gate `scroll-initial-target` behind `.is-initialized` so it only
|
|
109
|
+
applies once the track is actually a scroll container. Setting it on
|
|
110
|
+
the content before then would let the property walk up to the nearest
|
|
111
|
+
scrollable ancestor (typically the document) and shift the page's
|
|
112
|
+
initial scroll position to bring this row's content into view. With
|
|
113
|
+
the gate, the rule is only live when the row's own track can satisfy
|
|
114
|
+
it, so the initial scroll happens inside the track as intended. */
|
|
115
|
+
.SwipeableList-item.is-initialized .SwipeableList-content {
|
|
116
|
+
scroll-initial-target: nearest;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* The track is the focusable scroll container, but its overflow is clipped
|
|
120
|
+
so a default focus ring on the track itself would be invisible. Project
|
|
121
|
+
the focus affordance onto the content element (which paints above the
|
|
122
|
+
track) using `:focus-visible` on the track. */
|
|
123
|
+
.SwipeableList-track:focus-visible .SwipeableList-content {
|
|
124
|
+
outline: auto;
|
|
125
|
+
outline-offset: -2px;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Step 3: Add the action icons to the list item
|
|
130
|
+
|
|
131
|
+
The action color lives on the spacers (Step 2). The action **icon** lives on the list item itself, anchored to the row's left and right edges.
|
|
132
|
+
|
|
133
|
+
> **Note:** Throughout this guide, "left" refers to the *left side of the row* (which is revealed by swiping right), and "right" refers to the *right side of the row* (revealed by swiping left).
|
|
134
|
+
|
|
135
|
+
The placement, sizing, and motion below are a **starting suggestion**, not a requirement. Adjust the icon size, edge insets, threshold-pop scale, transition duration, and even the choice of pseudo-elements vs. real DOM nodes to match your design. The only mechanical requirement is that the icon sits behind the content (so the content can cover it pre-swipe) and inside the list item (so it doesn't scroll with the spacer). Everything else is taste.
|
|
136
|
+
|
|
137
|
+
```css
|
|
138
|
+
/* Action icons painted on the list item. They're absolutely positioned
|
|
139
|
+
inside the row (which is a containing block thanks to `contain: content`
|
|
140
|
+
on `.SwipeableList-item` from Step 2) and sit at z-index 1, so the
|
|
141
|
+
content element (z-index 2) covers them until the user swipes far
|
|
142
|
+
enough. */
|
|
143
|
+
.SwipeableList-item.is-initialized::before,
|
|
144
|
+
.SwipeableList-item.is-initialized::after {
|
|
145
|
+
/* Inline an SVG as the action icon. Replace this with whatever icon
|
|
146
|
+
fits the action (archive, checkmark, clock, etc.). The `fill='white'`
|
|
147
|
+
is baked into the SVG so it contrasts with the red spacer background;
|
|
148
|
+
adjust if your background color is light. */
|
|
149
|
+
--action-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'><path d='M9 3v1H4v2h1v13a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V6h1V4h-5V3H9zm0 5h2v9H9V8zm4 0h2v9h-2V8z'/></svg>");
|
|
150
|
+
|
|
151
|
+
content: '';
|
|
152
|
+
position: absolute;
|
|
153
|
+
z-index: 1;
|
|
154
|
+
|
|
155
|
+
/* The size (`width`) and insets (`left`/`right` below) are example
|
|
156
|
+
values, tune them to match your row height and visual weight.
|
|
157
|
+
The icon fills its box via `background-size: contain`, so changing
|
|
158
|
+
`width` resizes it. */
|
|
159
|
+
width: 1.5em; /* example value, adjust to taste */
|
|
160
|
+
aspect-ratio: 1;
|
|
161
|
+
top: 50%;
|
|
162
|
+
translate: 0 -50%;
|
|
163
|
+
|
|
164
|
+
/* Smooth transitions for the icon's visual states: the activate-point
|
|
165
|
+
pop (`scale`, see `.is-activating` below) and the removal fade
|
|
166
|
+
(`scale` + `opacity`, see `.is-removing` below). 0.2s is an example
|
|
167
|
+
duration. */
|
|
168
|
+
transition: scale 0.2s ease, opacity 0.2s ease;
|
|
169
|
+
|
|
170
|
+
background: var(--action-icon) center / contain no-repeat;
|
|
171
|
+
}
|
|
172
|
+
/* Inset from the row edge (example values; adjust to match your layout). */
|
|
173
|
+
.SwipeableList-item.is-initialized::before { left: 1.5em; }
|
|
174
|
+
.SwipeableList-item.is-initialized::after { right: 1.5em; }
|
|
175
|
+
|
|
176
|
+
/* Activating pop: scale the icon up when the user is past the visual
|
|
177
|
+
activate point, so the row's affordance feels reactive. Toggled by JS
|
|
178
|
+
in Step 4. */
|
|
179
|
+
.SwipeableList-item.is-activating::before,
|
|
180
|
+
.SwipeableList-item.is-activating::after {
|
|
181
|
+
scale: 1.333;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* Removal affordance: fade and shrink the icons as the row collapses.
|
|
185
|
+
Driven by the `is-removing` class added in Step 4 at commit time;
|
|
186
|
+
the existing `transition` on the icons animates the change. */
|
|
187
|
+
.SwipeableList-item.is-removing::before,
|
|
188
|
+
.SwipeableList-item.is-removing::after {
|
|
189
|
+
scale: 0.5;
|
|
190
|
+
opacity: 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* Only show the icon on the *leading* side of the swipe; hide the
|
|
194
|
+
trailing-side one. `data-swipe-direction` is set by JS in Step 4. */
|
|
195
|
+
.SwipeableList-item.is-activating[data-swipe-direction="left"]::after,
|
|
196
|
+
.SwipeableList-item.is-activating[data-swipe-direction="right"]::before {
|
|
197
|
+
visibility: hidden;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Step 4: Detect the commit gesture with `IntersectionObserver`
|
|
202
|
+
|
|
203
|
+
Use `IntersectionObserver` rooted at the track, observing the content. As the user swipes, the content's intersection ratio with the track drops; we use **two thresholds**:
|
|
204
|
+
|
|
205
|
+
- `activateThreshold`: a high ratio (e.g., 0.8). When the visible portion of the content drops below this, the user is past the visual activate point. Toggle the icon-pop affordance.
|
|
206
|
+
- `commitThreshold`: a low ratio (e.g., 0.2). When the visible portion drops below this, the user has committed. Start the remove animation **immediately**, without waiting for the snap gesture to fully settle. The collapsing row blends into the user's continuing swipe momentum, which feels more responsive than waiting for the snap to land before reacting.
|
|
207
|
+
|
|
208
|
+
Two more concerns are handled here:
|
|
209
|
+
|
|
210
|
+
- **Lazy per-item setup**: a single outer `IntersectionObserver` rooted at the viewport drives setup and the start/stop of the inner swipe observers. Items only get wired up the first time they scroll into view, and items that scroll off-screen have their swipe observer paused. This keeps the active observer count bounded and avoids reading layout-dependent values (like `clientWidth`) before the item has been rendered.
|
|
211
|
+
- **Dynamic items**: real lists grow over time (initial render, infinite scroll, server push). A `MutationObserver` on the `<ul>` registers any newly added items with the outer observer.
|
|
212
|
+
|
|
213
|
+
```js
|
|
214
|
+
// Per-item handles. Populated when an item is first lazily wired up; read by
|
|
215
|
+
// the outer viewport observer to start/stop the inner observer as items enter
|
|
216
|
+
// and leave the viewport.
|
|
217
|
+
const swipeObservers = new WeakMap();
|
|
218
|
+
|
|
219
|
+
// Outer observer: drives the entire swipe lifecycle off viewport visibility.
|
|
220
|
+
// On first entry, lazily wires the item up (`setupItem` reads layout-dependent
|
|
221
|
+
// values like `clientWidth`, which return 0 until the item is rendered). After
|
|
222
|
+
// setup, starts the inner observer. On exit, stops the inner observer so
|
|
223
|
+
// offscreen items don't track scroll positions.
|
|
224
|
+
const viewportObserver = new IntersectionObserver((entries) => {
|
|
225
|
+
for (const entry of entries) {
|
|
226
|
+
const item = entry.target;
|
|
227
|
+
if (entry.isIntersecting) {
|
|
228
|
+
const handle = swipeObservers.get(item) ?? setupItem(item);
|
|
229
|
+
handle.observer.observe(handle.content);
|
|
230
|
+
} else {
|
|
231
|
+
const handle = swipeObservers.get(item);
|
|
232
|
+
if (handle) handle.observer.unobserve(handle.content);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
function setupItem(item) {
|
|
238
|
+
const track = item.querySelector('.SwipeableList-track');
|
|
239
|
+
const content = track.querySelector('.SwipeableList-content');
|
|
240
|
+
|
|
241
|
+
// Upgrade the row into "swipeable" mode. This is the gate for all the CSS
|
|
242
|
+
// from Steps 2 and 3 (the track becomes a snap container, the action icons
|
|
243
|
+
// appear). Done *before* the inner observer is attached so the snap
|
|
244
|
+
// container exists by the time intersection callbacks can fire.
|
|
245
|
+
item.classList.add('is-initialized');
|
|
246
|
+
|
|
247
|
+
// Tunable thresholds. `activateThreshold` is the visual feedback point
|
|
248
|
+
// (icon pops). `commitThreshold` is the point of no return: once the
|
|
249
|
+
// content is past this point of being off-screen, we commit even if the
|
|
250
|
+
// user releases mid-gesture and the track snaps back. A low value (~0.2)
|
|
251
|
+
// commits before the snap settles, so the remove animation can start
|
|
252
|
+
// during the swipe.
|
|
253
|
+
const activateThreshold = 0.8;
|
|
254
|
+
const commitThreshold = 0.2;
|
|
255
|
+
|
|
256
|
+
// One inner observer per item, rooted at the track. Vertical scrolling of
|
|
257
|
+
// the outer list moves root and target together, so the callback only fires
|
|
258
|
+
// for the horizontal swipe.
|
|
259
|
+
const observer = new IntersectionObserver((entries, observer) => {
|
|
260
|
+
const entry = entries.at(-1);
|
|
261
|
+
const ratio = entry.intersectionRatio;
|
|
262
|
+
|
|
263
|
+
// Direction the user is swiping toward. A positive offset from the
|
|
264
|
+
// track's left edge means the content has been pulled right (left
|
|
265
|
+
// spacer revealed), so the leading icon is on the left.
|
|
266
|
+
const direction = (entry.boundingClientRect.x - entry.rootBounds.x) > 0
|
|
267
|
+
? 'left'
|
|
268
|
+
: 'right';
|
|
269
|
+
|
|
270
|
+
if (ratio < commitThreshold) {
|
|
271
|
+
// The IO entry's boundingClientRect is the last reliable measurement
|
|
272
|
+
// before the animation starts; reuse it for both the pre-collapse
|
|
273
|
+
// height and the slide-off translate distance.
|
|
274
|
+
removeItem(item, content, direction, entry);
|
|
275
|
+
viewportObserver.unobserve(item);
|
|
276
|
+
observer.disconnect();
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Scale up the leading icon while the content is past the activate
|
|
281
|
+
// point; restore it at rest.
|
|
282
|
+
item.classList.toggle('is-activating', ratio < activateThreshold);
|
|
283
|
+
|
|
284
|
+
// Hold the previous direction at rest so the icon's exit animation
|
|
285
|
+
// finishes on the side the user was swiping toward.
|
|
286
|
+
if (entry.boundingClientRect.x !== entry.rootBounds.x) {
|
|
287
|
+
item.dataset.swipeDirection = direction;
|
|
288
|
+
}
|
|
289
|
+
}, {
|
|
290
|
+
root: track,
|
|
291
|
+
threshold: [commitThreshold, activateThreshold],
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// Return the handle without starting observation; the outer viewport observer
|
|
295
|
+
// calls `observer.observe(content)` once the item is in view.
|
|
296
|
+
const handle = {observer, content};
|
|
297
|
+
swipeObservers.set(item, handle);
|
|
298
|
+
return handle;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async function removeItem(item, content, direction, entry) {
|
|
302
|
+
const opts = { duration: 300, easing: 'ease', fill: 'forwards' };
|
|
303
|
+
|
|
304
|
+
const rect = entry.boundingClientRect;
|
|
305
|
+
// Content's pixel offset from the track's left edge.
|
|
306
|
+
const x = rect.x - entry.rootBounds.x;
|
|
307
|
+
// Pixel distance the content needs to travel to be fully out of view.
|
|
308
|
+
const translate = direction === 'left'
|
|
309
|
+
? rect.width - x
|
|
310
|
+
: -(x + rect.width);
|
|
311
|
+
|
|
312
|
+
// Use a combination of CSS transitions (for declarative styles) and
|
|
313
|
+
// WAAPI animations (for computed values) to remove the element,
|
|
314
|
+
// then await the completion of all of them.
|
|
315
|
+
// Note: the content translate animation is important because the
|
|
316
|
+
// height-collapse animation can otherwise finish before the browser's
|
|
317
|
+
// smooth scroll-snap has scrolled the content fully off-screen.
|
|
318
|
+
item.classList.add('is-removing');
|
|
319
|
+
item.animate([{ height: `${rect.height}px` }, { height: '0px' }], opts);
|
|
320
|
+
content.animate([{ translate: `${translate}px` }], opts);
|
|
321
|
+
await Promise.allSettled(
|
|
322
|
+
item.getAnimations({ subtree: true }).map((a) => a.finished),
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// Safari has a scroll-latching bug: removing the node while the swipe
|
|
326
|
+
// gesture's momentum is still resolving causes the next item (which
|
|
327
|
+
// slides up into this one's place) to inherit the scroll and
|
|
328
|
+
// immediately scroll itself off-screen. Detect Safari via
|
|
329
|
+
// `GestureEvent` (a Safari-only API) and defer the actual DOM removal
|
|
330
|
+
// until the gesture has fully settled. The 5s delay is conservative;
|
|
331
|
+
// anything longer than the momentum tail is fine. Mark the row inert
|
|
332
|
+
// so it can't be interacted with during the delay.
|
|
333
|
+
if (globalThis.GestureEvent) {
|
|
334
|
+
item.inert = true;
|
|
335
|
+
setTimeout(() => item.remove(), 5000);
|
|
336
|
+
} else {
|
|
337
|
+
item.remove();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function setupList(list) {
|
|
342
|
+
// Observe items already in the list.
|
|
343
|
+
for (const item of list.children) {
|
|
344
|
+
if (item.matches('.SwipeableList-item')) {
|
|
345
|
+
viewportObserver.observe(item);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Pick up items added later (initial render after data loads, infinite
|
|
350
|
+
// scroll, server push). Removals don't need MutationObserver handling —
|
|
351
|
+
// the commit branch above already unobserves the item before removing it
|
|
352
|
+
// from the DOM.
|
|
353
|
+
new MutationObserver((mutations) => {
|
|
354
|
+
for (const mutation of mutations) {
|
|
355
|
+
for (const node of mutation.addedNodes) {
|
|
356
|
+
if (node.nodeType === Node.ELEMENT_NODE &&
|
|
357
|
+
node.matches('.SwipeableList-item')) {
|
|
358
|
+
viewportObserver.observe(node);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}).observe(list, { childList: true });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
document.querySelectorAll('.SwipeableList').forEach(setupList);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### Step 5: Use the action and label that fits your use case
|
|
369
|
+
|
|
370
|
+
For variants other than removal, only the visuals and the body of the commit handler change:
|
|
371
|
+
|
|
372
|
+
- **Archive**: green/blue background, archive icon, move the item to an archive list rather than removing it.
|
|
373
|
+
- **Mark as read**: subdued background, checkmark icon, update item state and re-render (or just remove a `.unread` class).
|
|
374
|
+
- **Snooze**: blue background, clock icon, hide until a chosen time.
|
|
375
|
+
|
|
376
|
+
The scroll/snap/observation mechanics are unchanged.
|
|
377
|
+
|
|
378
|
+
#### Different actions per swipe direction
|
|
379
|
+
|
|
380
|
+
A single row can also expose **two different actions**: one for a left swipe and one for a right swipe (e.g., "archive" on right, "delete" on left), the way many native mail apps do it. The scroll, snap, and commit-detection mechanics don't change at all — the only thing that changes is what happens at commit time.
|
|
381
|
+
|
|
382
|
+
In Step 4, the commit branch always calls `removeItem(...)`. To support two actions, pick the handler based on `direction`:
|
|
383
|
+
|
|
384
|
+
```js
|
|
385
|
+
if (ratio < commitThreshold) {
|
|
386
|
+
const handler = direction === 'left' ? archiveItem : removeItem;
|
|
387
|
+
handler(item, content, direction, entry);
|
|
388
|
+
viewportObserver.unobserve(item);
|
|
389
|
+
observer.disconnect();
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
A note on naming: `removeItem` is named for the destructive case, but the function it runs (collapse the row's height, slide the content off-screen, then drop the node) is really a generic "this row is done, animate it away" routine. It works just as well for archive, mark-as-read, or snooze — the row goes away from *this* list either way. If your handlers don't actually remove anything (e.g., both move the item elsewhere), rename it to something neutral like `dismissItem` so the code reads correctly.
|
|
395
|
+
|
|
396
|
+
To make the two actions visually distinct, hoist a color and icon for each direction onto the list item, then paint the track with a split gradient and the two pseudo-element icons from the same variables.
|
|
397
|
+
|
|
398
|
+
```css
|
|
399
|
+
.SwipeableList-item {
|
|
400
|
+
/* Action color + icon per swipe direction. `--left-*` is revealed
|
|
401
|
+
when the user swipes RIGHT (e.g., archive); `--right-*` is revealed
|
|
402
|
+
when the user swipes LEFT (e.g., delete). */
|
|
403
|
+
--left-action-color: hsl(140 50% 40%);
|
|
404
|
+
--left-action-icon: url("…archive svg…");
|
|
405
|
+
--right-action-color: hsl(0 65% 50%);
|
|
406
|
+
--right-action-icon: url("…trash svg…");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.SwipeableList-item.is-initialized .SwipeableList-track {
|
|
410
|
+
/* Split reveal: left half of the scrollable area gets the left-action
|
|
411
|
+
color, right half gets the right-action color. `background-attachment:
|
|
412
|
+
local` makes the gradient's positioning area the scrollable area
|
|
413
|
+
(3x the visible width), so the default size fills it and the 50% hard
|
|
414
|
+
stop lines up exactly with the midpoint of the resting content column.
|
|
415
|
+
The track's color also stays continuous behind the content as it
|
|
416
|
+
translates off, so the leading-direction color shows the whole way. */
|
|
417
|
+
background-image: linear-gradient(
|
|
418
|
+
to right,
|
|
419
|
+
var(--left-action-color) 50%,
|
|
420
|
+
var(--right-action-color) 50%
|
|
421
|
+
);
|
|
422
|
+
background-attachment: local;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/* Per-side icons read from the same variables. */
|
|
426
|
+
.SwipeableList-item.is-initialized::before { background-image: var(--left-action-icon); }
|
|
427
|
+
.SwipeableList-item.is-initialized::after { background-image: var(--right-action-icon); }
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
With this setup, the spacers no longer need their own background-color (the track's gradient handles the reveal), so you can drop the `background-color` rule on `.SwipeableList-track::before, ::after` from Step 2 if you're using this dual-action variant.
|
|
431
|
+
|
|
432
|
+
## Best practices and pitfalls
|
|
433
|
+
|
|
434
|
+
- **DO** use `mandatory` snap, not `proximity`. With `proximity`, the row can rest partially scrolled, leaving the action background half-visible.
|
|
435
|
+
- **DO** set `overscroll-behavior-x: none` on the track. Without it, an over-swipe can trigger the browser's back-navigation gesture on iOS/Android.
|
|
436
|
+
- **DO** commit at a threshold *before* the snap settles (e.g., `commitThreshold ≈ 0.2`) rather than waiting for the content to be fully off-screen. This lets the remove animation start during the gesture, which feels significantly more responsive than waiting for the snap to land.
|
|
437
|
+
- **DO** drive per-item setup from an outer viewport `IntersectionObserver` rather than wiring every item up at page load. This avoids reading layout-dependent values (`clientWidth`, etc.) before items have been rendered, and keeps the active observer count proportional to what the user can actually see.
|
|
438
|
+
- **DO** use a `MutationObserver` on the list when items are added dynamically (initial render after data loads, infinite scroll, server push). Without it, items appended after page load won't get wired up.
|
|
439
|
+
- **DO NOT** rely on `pointerdown`/`pointermove`/`pointerup` to drive a manual transform. You'll lose momentum, snap-back, keyboard accessibility, and reduced-motion handling that the browser gives you for free.
|
|
440
|
+
- **DO** confirm destructive actions when appropriate. For "remove", consider showing an undo toast after the swipe completes; the gesture is fast and easy to trigger by accident.
|
|
441
|
+
- **DO** ensure the scroll track is focusable, keyboard accessible, and that there is a visual focus affordance.
|
|
442
|
+
- **DO** provide accessible alternatives for any relevant actions triggered by the swipe (e.g., a visible button, context menu, or edit mode).
|
|
443
|
+
|
|
444
|
+
## Fallback strategies
|
|
445
|
+
|
|
446
|
+
The scroll-snap mechanics that underpin this pattern (`scroll-snap-type`, `scroll-snap-align`), `IntersectionObserver`, `MutationObserver`, `ResizeObserver`, and the Web Animations API are all Baseline Widely Available, so the gesture, commit detection, lifecycle management, and removal animation work broadly. All newer features that are used are either not core to the experience or have robust fallbacks that can be reliably used now.
|
|
447
|
+
|
|
448
|
+
### Fallback for `overscroll-behavior`
|
|
449
|
+
|
|
450
|
+
overscroll-behavior has limited availability.
|
|
451
|
+
Supported by: Chrome 144 (Jan 2026), Edge 144 (Jan 2026), and Firefox 150 (Apr 2026).
|
|
452
|
+
Unsupported in: Safari.
|
|
453
|
+
|
|
454
|
+
No fallback is needed for this use case. `overscroll-behavior` was Baseline Widely Available but no longer is due to an interop issue that only manifests on containers without scrollable overflow. But the track here is always horizontally scrollable (three full-width columns inside a 100%-width container), so the property behaves consistently across browsers and the swipe gesture is reliably contained.
|
|
455
|
+
|
|
456
|
+
### Fallback for `scrollbar-width`
|
|
457
|
+
|
|
458
|
+
Baseline status for scrollbar-width: Newly available. It's been Baseline since 2024-12-11.
|
|
459
|
+
Supported by: Chrome 121 (Jan 2024), Edge 121 (Jan 2024), Firefox 64 (Dec 2018), and Safari 18.2 (Dec 2024).
|
|
460
|
+
|
|
461
|
+
Hidden scrollbars are a visual enhancement, not the mechanism that makes swipe-to-remove work. If your Baseline target does not include `scrollbar-width`, the row still scrolls, snaps, detects commit, and removes correctly; the unsupported experience may simply show a horizontal scrollbar. If your product requires hidden scrollbars in older WebKit-derived browsers, you can add a narrowly scoped `::-webkit-scrollbar { display: none; }` rule for the swipe track.
|
|
462
|
+
|
|
463
|
+
### Fallback for `scroll-initial-target`
|
|
464
|
+
|
|
465
|
+
scroll-initial-target has limited availability.
|
|
466
|
+
Supported by: Chrome 133 (Feb 2025) and Edge 133 (Feb 2025).
|
|
467
|
+
Unsupported in: Firefox and Safari.
|
|
468
|
+
|
|
469
|
+
If your Baseline target does not include `scroll-initial-target`, scroll the track to the content programmatically inside `setupItem`. Detect with `CSS.supports`:
|
|
470
|
+
|
|
471
|
+
```js
|
|
472
|
+
// Hoist the feature detect so the conditional `ResizeObserver` below can be
|
|
473
|
+
// skipped entirely when the property is supported.
|
|
474
|
+
const needsScrollWorkaround = !CSS.supports('scroll-initial-target', 'nearest');
|
|
475
|
+
|
|
476
|
+
function setupItem(item) {
|
|
477
|
+
// ...existing setup from Step 4...
|
|
478
|
+
|
|
479
|
+
if (needsScrollWorkaround) {
|
|
480
|
+
track.scrollLeft = track.clientWidth;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// ...attach the inner IntersectionObserver, etc.
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
**Call ordering matters.** The programmatic scroll MUST run:
|
|
488
|
+
|
|
489
|
+
1. **AFTER** `.is-initialized` is added to the list item (the class is what turns the track into a scroll container; setting `scrollLeft` on a non-scrollable element is a no-op).
|
|
490
|
+
2. **BEFORE** the inner `IntersectionObserver` from Step 4 is attached. Otherwise the initial programmatic scroll past the left spacer will be observed as a "swipe" and immediately fire the commit handler.
|
|
491
|
+
|
|
492
|
+
Driving setup from the outer viewport observer (Step 4) is what makes this reliable: `setupItem` runs after the item is rendered, so `track.clientWidth` returns a real value rather than `0`.
|
|
493
|
+
|
|
494
|
+
Some browsers (notably Safari) also reset the snap-container scroll position whenever the track resizes (URL-bar show/hide, viewport resize, container queries, etc.). Use a `ResizeObserver` on each track to re-apply the scroll. Gate it behind the same `CSS.supports` check — when `scroll-initial-target` is supported, the browser handles resize-time scroll restoration itself.
|
|
495
|
+
|
|
496
|
+
```js
|
|
497
|
+
const trackResizeObserver = needsScrollWorkaround
|
|
498
|
+
? new ResizeObserver((entries) => {
|
|
499
|
+
for (const entry of entries) {
|
|
500
|
+
entry.target.scrollLeft = entry.target.clientWidth;
|
|
501
|
+
}
|
|
502
|
+
})
|
|
503
|
+
: null;
|
|
504
|
+
|
|
505
|
+
function setupItem(item) {
|
|
506
|
+
// ...existing setup...
|
|
507
|
+
|
|
508
|
+
if (needsScrollWorkaround) {
|
|
509
|
+
track.scrollLeft = track.clientWidth;
|
|
510
|
+
trackResizeObserver.observe(track);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// ...attach the inner IntersectionObserver, etc.
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Unobserve the track before the row's height animation runs in `removeItem`, otherwise the height change re-triggers the resize callback during removal. Add this alongside the existing `viewportObserver.unobserve(item)` in the commit branch:
|
|
518
|
+
|
|
519
|
+
```js
|
|
520
|
+
if (ratio < commitThreshold) {
|
|
521
|
+
removeItem(item, content, direction, entry);
|
|
522
|
+
viewportObserver.unobserve(item);
|
|
523
|
+
if (needsScrollWorkaround) trackResizeObserver.unobserve(track);
|
|
524
|
+
observer.disconnect();
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
```
|
package/.agents/skills/modern-web-guidance/guides/user-experience/visually-stable-font-fallbacks.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
When web fonts load, they often replace a fallback font that has different dimensions, even if both are set to the same `font-size`. This causes "layout shift" (Cumulative Layout Shift) and can make text illegible if the fallback's lowercase letters (x-height) are significantly different than the preferred font.
|
|
2
|
+
|
|
3
|
+
The `font-size-adjust` property solves this by normalizing the size of the font based on a specific metric (usually the x-height), ensuring that text occupies the same visual space regardless of which font is currently active.
|
|
4
|
+
|
|
5
|
+
## Implementation steps
|
|
6
|
+
|
|
7
|
+
### 1. Identify the aspect ratio of your preferred font
|
|
8
|
+
To normalize fallbacks, you need the "aspect value" (the ratio of lowercase letters to the font size) of your primary font.
|
|
9
|
+
|
|
10
|
+
* **Automatic discovery (Recommended):** Use the `from-font` keyword to let the browser extract the ratio from your primary web font.
|
|
11
|
+
* **Manual calculation:** If you know the specific value (e.g., 0.545 for Verdana), you can provide it directly for more precise control.
|
|
12
|
+
|
|
13
|
+
### 2. Apply font-size-adjust to the text container
|
|
14
|
+
Apply the property to the element or a parent container. This ensures that if the primary font fails to load or is in the process of loading, the fallback font is scaled to match the visual size of the primary font.
|
|
15
|
+
|
|
16
|
+
```css
|
|
17
|
+
.text-content {
|
|
18
|
+
/* Define your font stack as usual */
|
|
19
|
+
font-family: "MyWebFont", "Arial", sans-serif;
|
|
20
|
+
font-size: 1rem;
|
|
21
|
+
|
|
22
|
+
/* MANDATORY: Normalize the font size based on the primary font's x-height.
|
|
23
|
+
This ensures that if 'Arial' is used as a fallback, it is scaled
|
|
24
|
+
to match the x-height of 'MyWebFont'. */
|
|
25
|
+
font-size-adjust: from-font;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 3. (Optional) Adjust for specific metrics
|
|
30
|
+
While x-height is the default and most common, you can normalize by other metrics like `cap-height` (useful for all-caps headers) or `ch-width` (useful for monospaced fonts).
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
h1 {
|
|
34
|
+
/* Normalize based on the height of capital letters */
|
|
35
|
+
font-size-adjust: cap-height from-font;
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 4. Verify visual stability
|
|
40
|
+
Ensure that the `font-size-adjust` value correctly aligns the fallback. You can test this by temporarily blocking the web font or adjusting the `font-family` declaration in your browser's DevTools and verifying that the text layout remains stable.
|
|
41
|
+
|
|
42
|
+
## Fallback strategies
|
|
43
|
+
|
|
44
|
+
Baseline status for font-size-adjust: Newly available. It's been Baseline since 2024-07-25.
|
|
45
|
+
Supported by: Chrome 127 (Jul 2024), Edge 127 (Jul 2024), Firefox 118 (Sep 2023), and Safari 17 (Sep 2023).
|
|
46
|
+
|
|
47
|
+
In browsers that do not support `font-size-adjust`, the font will be rendered at its default scale. This may result in layout shifts or changes in readability during font swaps.
|
|
48
|
+
|
|
49
|
+
To mitigate this without `font-size-adjust`, you can use the `@font-face` descriptors `size-adjust`, `ascent-override`, and `descent-override` to manually tune fallback fonts, though these are more complex to calculate than a single `font-size-adjust` value.
|
package/.agents/skills/modern-web-guidance/guides/user-experience/visually-stable-mixed-fonts.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
When mixing different font families, for instance when inserting inline code snippets, or switching out font families for different themes, differences in "x-height" (the height of lowercase letters) can make one font appear much smaller or larger than the other font. This can lead to poor legibility and layout shifts.
|
|
2
|
+
|
|
3
|
+
The `font-size-adjust` property allows you to normalize the visual size of text by adjusting the font size based on a specific font metric (usually the x-height).
|
|
4
|
+
|
|
5
|
+
### Implementation Steps
|
|
6
|
+
|
|
7
|
+
1. **MANDATORY**: Apply `font-size-adjust` to elements where font consistency is critical, such as containers using web fonts or blocks with mixed font families.
|
|
8
|
+
2. **MANDATORY**: Use the `from-font` keyword on elements to automatically match font size in nested elements to the proportions of the primary font.
|
|
9
|
+
3. **MANDATORY**: Use a specific numeric aspect-ratio override value for `font-size-adjust` (e.g., `font-size-adjust: 0.5`) to normalize proportions independently when the font proportions to base on are from different themes.
|
|
10
|
+
|
|
11
|
+
### Example: Normalizing x-height automatically
|
|
12
|
+
|
|
13
|
+
Using `from-font` is the most robust approach. It extracts the aspect ratio of the x-height from the first available font and applies it to fonts in child elements.
|
|
14
|
+
|
|
15
|
+
```css
|
|
16
|
+
.content-area {
|
|
17
|
+
font-family: "MyCustomWebFont";
|
|
18
|
+
/* Automatically extract and apply x-height ratio from MyCustomWebFont */
|
|
19
|
+
font-size-adjust: from-font;
|
|
20
|
+
}
|
|
21
|
+
.content-area span{
|
|
22
|
+
font-family: "MyOtherCustomWebFont"
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Example: Specifying a specific x-height
|
|
27
|
+
|
|
28
|
+
When the font to adjust is not a child of the font to base the size on, specify a value to adjust the x-height by.
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
.theme{
|
|
32
|
+
font-family: Verdana, sans-serif;
|
|
33
|
+
}
|
|
34
|
+
.theme.alternate{
|
|
35
|
+
font-family: Times;
|
|
36
|
+
/* Set to the aspect ratio (x-height / font-size) of the primary font */
|
|
37
|
+
font-size-adjust: 0.51;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Fallback strategies
|
|
42
|
+
|
|
43
|
+
Baseline status for font-size-adjust: Newly available. It's been Baseline since 2024-07-25.
|
|
44
|
+
Supported by: Chrome 127 (Jul 2024), Edge 127 (Jul 2024), Firefox 118 (Sep 2023), and Safari 17 (Sep 2023).
|
|
45
|
+
|
|
46
|
+
**MANDATORY**: In browsers that do not support `font-size-adjust`, fonts will render at their natural `font-size` value. You must provide a valid fallback strategy for non-supporting browsers using a `@supports` block to mitigate this:
|
|
47
|
+
|
|
48
|
+
- Use `@supports not (font-size-adjust: from-font)` to detect `font-size-adjust` support and provide fallback styles (e.g. adjusted line-height or font-size).
|
|
49
|
+
- Choose fonts with similar x-heights to your primary font.
|
|
50
|
+
- Apply specific `font-size` and `line-height` overrides for alternate and nested font families.
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
/* Feature detection for font-size-adjust */
|
|
54
|
+
@supports not (font-size-adjust: from-font) {
|
|
55
|
+
.content-area {
|
|
56
|
+
/* Manual adjustment for browsers without support (if needed) */
|
|
57
|
+
line-height: 1.6;
|
|
58
|
+
font-size: 1.2rem;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|