diff --git a/libs/core/src/components/pds-modal/pds-modal.scss b/libs/core/src/components/pds-modal/pds-modal.scss index 0908909b5..d87ebb091 100644 --- a/libs/core/src/components/pds-modal/pds-modal.scss +++ b/libs/core/src/components/pds-modal/pds-modal.scss @@ -13,7 +13,7 @@ opacity: 0; padding: 0; position: fixed; - transition: opacity 0.2s ease, visibility 0.2s ease; + transition: opacity var(--pine-motion-duration-base) var(--pine-motion-easing-in), visibility var(--pine-motion-duration-base) var(--pine-motion-easing-in); visibility: hidden; width: 100%; z-index: var(--pine-z-index-modal); @@ -33,6 +33,7 @@ &.open { opacity: 1; + transition-timing-function: var(--pine-motion-easing-out); visibility: visible; } } diff --git a/libs/core/src/global/styles/_motion.scss b/libs/core/src/global/styles/_motion.scss new file mode 100644 index 000000000..8a5d62302 --- /dev/null +++ b/libs/core/src/global/styles/_motion.scss @@ -0,0 +1,39 @@ +//// +/// Motion tokens (Pine-internal until upstream consolidation) +/// +/// Named duration and easing values for component transitions. +/// +/// Namespace contract: these CSS custom properties use the canonical +/// `--pine-motion-*` namespace that `@kajabi-ui/styles` will own once +/// motion is published upstream. Pine defines them here so component +/// SCSS can adopt the names today; when upstream lands a motion token +/// release, this file is removed in the same PR that bumps the +/// `@kajabi-ui/styles` version. Component SCSS does not change. +/// +/// If upstream ever publishes different values under the same names, +/// remove these fallbacks immediately to avoid divergent definitions. +/// +/// @group pine +//// + +:root { + // Durations + --pine-motion-duration-fast: 120ms; + --pine-motion-duration-base: 200ms; + --pine-motion-duration-slow: 300ms; + + // Easing curves (match the bands documented in Guides/Motion) + --pine-motion-easing-out: cubic-bezier(0, 0, 0.2, 1); + --pine-motion-easing-in: cubic-bezier(0.4, 0, 1, 1); + --pine-motion-easing-in-out: cubic-bezier(0.4, 0, 0.2, 1); +} + +// Honor user preference for reduced motion. Components that opt-in to +// the tokens above inherit the override automatically. +@media (prefers-reduced-motion: reduce) { + :root { + --pine-motion-duration-fast: 0ms; + --pine-motion-duration-base: 0ms; + --pine-motion-duration-slow: 0ms; + } +} diff --git a/libs/core/src/global/styles/app.scss b/libs/core/src/global/styles/app.scss index ea2e870a8..7b3e4b2ff 100644 --- a/libs/core/src/global/styles/app.scss +++ b/libs/core/src/global/styles/app.scss @@ -1,5 +1,6 @@ @use '~@kajabi-ui/styles/dist/pine/pine'; @use 'fonts'; +@use 'motion'; @use '../../components/pds-combobox/pds-combobox-dropdown-panel.scss' as *; // Body-portaled combobox listbox (outside shadow roots; see `dropdown-mount="body"` on pds-combobox) diff --git a/libs/core/src/stories/guides/motion.docs.mdx b/libs/core/src/stories/guides/motion.docs.mdx index eac412a0b..28c861091 100644 --- a/libs/core/src/stories/guides/motion.docs.mdx +++ b/libs/core/src/stories/guides/motion.docs.mdx @@ -4,7 +4,7 @@ import { Meta } from '@storybook/addon-docs/blocks'; # Motion -Motion should reinforce hierarchy and feedback without slowing tasks or causing vestibular discomfort. Pine does not yet expose a dedicated **motion token** scale in documentation; until those tokens land in the shared design language, follow the practices below. +Motion should reinforce hierarchy and feedback without slowing tasks or causing vestibular discomfort. Pine exposes a small **Pine-internal** motion token set covering durations and easing curves; full publication into the shared design language is a follow-up (see Tokens below). ## Principles @@ -20,6 +20,35 @@ Motion should reinforce hierarchy and feedback without slowing tasks or causing - Keep **focus management** paired with motion: if a dialog animates open, focus should move predictably when the animation completes (or immediately when reduced motion applies). - Coordinate with **design** on shared curves and durations so Stencil, React host apps, and marketing pages do not fight each other. -## Tokens and docs +## Tokens -When semantic motion tokens are published in the Kajabi design token set, this page should link to their Storybook entries alongside color, spacing, and typography. Until then, treat motion as **component-local** (scoped SCSS) plus the principles above. +Pine ships a Pine-internal motion token set in `libs/core/src/global/styles/_motion.scss`. Component SCSS should reference the CSS custom properties (not the raw values), so that consolidating these tokens upstream into `@kajabi-ui/styles` is a future token-swap and not a search-and-replace across every component. + +### Durations + +| Token | Default | Use for | +| --- | --- | --- | +| `--pine-motion-duration-fast` | `120ms` | Micro-interactions (hover, focus, small toggles). | +| `--pine-motion-duration-base` | `200ms` | Default for most state changes; the safe pick. | +| `--pine-motion-duration-slow` | `300ms` | Overlays entering or leaving (modal, popover, drawer). | + +### Easing + +| Token | Curve | Use for | +| --- | --- | --- | +| `--pine-motion-easing-out` | `cubic-bezier(0, 0, 0.2, 1)` | Elements **entering** the view or gaining focus. | +| `--pine-motion-easing-in` | `cubic-bezier(0.4, 0, 1, 1)` | Elements **exiting** the view. | +| `--pine-motion-easing-in-out` | `cubic-bezier(0.4, 0, 0.2, 1)` | Properties that move both ways (for example expanding height). | + +### Reduced motion + +The duration tokens collapse to `0ms` under `prefers-reduced-motion: reduce`, so CSS transitions that reference `var(--pine-motion-duration-*)` inherit the system-level override automatically — no extra media-query wrapping is required at the component level. + +**Limitations:** + +- The override only affects duration. Easing tokens still resolve to their normal curves, which is fine for 0ms transitions but worth knowing if you compose tokens elsewhere. +- JavaScript-driven animations (`element.animate`, `requestAnimationFrame` loops) do not read CSS custom properties; you have to check `window.matchMedia('(prefers-reduced-motion: reduce)')` yourself. + +### Roadmap + +When motion tokens are published in `@kajabi-ui/styles` alongside color, spacing, and typography, the CSS variable names above stay the same — the source of truth moves upstream. Track that work in `#ds-support`.