From 9fd2c51561aa62dbc22191d71601ef380366dcdc Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Fri, 15 May 2026 09:08:19 -0500 Subject: [PATCH 1/3] feat(motion): add Pine-internal motion token scaffold Add libs/core/src/global/styles/_motion.scss exposing duration and easing CSS custom properties (--pine-motion-duration-{fast,base,slow} and --pine-motion-easing-{out,in,in-out}). Wired into app.scss so the tokens land in the global stylesheet alongside fonts. Durations collapse to 0ms under prefers-reduced-motion so consumer components inherit the override without per-component media queries. Update the Guides/Motion doc to remove the no-tokens disclaimer, document the new tokens with usage tables, and call out the upstream follow-up to consolidate into @kajabi-ui/styles. --- libs/core/src/global/styles/_motion.scss | 36 ++++++++++++++++++++ libs/core/src/global/styles/app.scss | 1 + libs/core/src/stories/guides/motion.docs.mdx | 30 ++++++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 libs/core/src/global/styles/_motion.scss diff --git a/libs/core/src/global/styles/_motion.scss b/libs/core/src/global/styles/_motion.scss new file mode 100644 index 000000000..c9b4f2e2c --- /dev/null +++ b/libs/core/src/global/styles/_motion.scss @@ -0,0 +1,36 @@ +//// +/// Motion tokens (Pine-internal) +/// +/// Named duration and easing values for component transitions. Until +/// motion tokens land in the shared @kajabi-ui/styles package these are +/// Pine-local — keep usage inside libs/core/ so consumer apps stay on +/// the shared token surface. +/// +/// Component SCSS should reference the CSS custom properties (via +/// `var(--pine-motion-...)`) so that future consolidation upstream is +/// a token-swap, not a search-and-replace across every component. +/// +/// @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..a39b25af4 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,30 @@ 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 components that use them inherit the system-level override automatically. No additional media-query wrapping is required at the component level for the duration values. + +### 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`. From a12e17ca9c1830b1eba2cffcc4fe050fe76a0047 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Fri, 15 May 2026 09:22:25 -0500 Subject: [PATCH 2/3] feat(motion): strengthen contract comment, migrate pds-modal backdrop Address review feedback on the motion-tokens PR: - Strengthen the namespace contract comment in _motion.scss to make clear Pine is claiming the upstream-canonical names and that the file is to be removed when @kajabi-ui/styles publishes motion. - Migrate pds-modal __backdrop transition from raw 0.2s ease to var(--pine-motion-duration-base) var(--pine-motion-easing-out) so the new tokens have at least one production consumer. - Document the reduced-motion limitation (override applies to duration only; JS-driven animations need their own matchMedia check). --- .../src/components/pds-modal/pds-modal.scss | 2 +- libs/core/src/global/styles/_motion.scss | 19 +++++++++++-------- libs/core/src/stories/guides/motion.docs.mdx | 7 ++++++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libs/core/src/components/pds-modal/pds-modal.scss b/libs/core/src/components/pds-modal/pds-modal.scss index 0908909b5..c3a002a44 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-out), visibility var(--pine-motion-duration-base) var(--pine-motion-easing-out); visibility: hidden; width: 100%; z-index: var(--pine-z-index-modal); diff --git a/libs/core/src/global/styles/_motion.scss b/libs/core/src/global/styles/_motion.scss index c9b4f2e2c..8a5d62302 100644 --- a/libs/core/src/global/styles/_motion.scss +++ b/libs/core/src/global/styles/_motion.scss @@ -1,14 +1,17 @@ //// -/// Motion tokens (Pine-internal) +/// Motion tokens (Pine-internal until upstream consolidation) /// -/// Named duration and easing values for component transitions. Until -/// motion tokens land in the shared @kajabi-ui/styles package these are -/// Pine-local — keep usage inside libs/core/ so consumer apps stay on -/// the shared token surface. +/// Named duration and easing values for component transitions. /// -/// Component SCSS should reference the CSS custom properties (via -/// `var(--pine-motion-...)`) so that future consolidation upstream is -/// a token-swap, not a search-and-replace across every component. +/// 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 //// diff --git a/libs/core/src/stories/guides/motion.docs.mdx b/libs/core/src/stories/guides/motion.docs.mdx index a39b25af4..28c861091 100644 --- a/libs/core/src/stories/guides/motion.docs.mdx +++ b/libs/core/src/stories/guides/motion.docs.mdx @@ -42,7 +42,12 @@ Pine ships a Pine-internal motion token set in `libs/core/src/global/styles/_mot ### Reduced motion -The duration tokens collapse to `0ms` under `prefers-reduced-motion: reduce`, so components that use them inherit the system-level override automatically. No additional media-query wrapping is required at the component level for the duration values. +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 From de76005b1c7a4798ef10968cf832ecfadebba766 Mon Sep 17 00:00:00 2001 From: Quinton Jason Date: Fri, 29 May 2026 09:44:38 -0500 Subject: [PATCH 3/3] style(pds-modal): use ease-in on backdrop exit, ease-out on enter --- libs/core/src/components/pds-modal/pds-modal.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/core/src/components/pds-modal/pds-modal.scss b/libs/core/src/components/pds-modal/pds-modal.scss index c3a002a44..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 var(--pine-motion-duration-base) var(--pine-motion-easing-out), visibility var(--pine-motion-duration-base) var(--pine-motion-easing-out); + 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; } }