From 3c805e603e4acd2697c958113a39d4454ce768c4 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:03:02 +0900 Subject: [PATCH 01/25] docs: add Interaction component design spec --- ...2026-06-12-interaction-component-design.md | 272 ++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-12-interaction-component-design.md diff --git a/docs/superpowers/specs/2026-06-12-interaction-component-design.md b/docs/superpowers/specs/2026-06-12-interaction-component-design.md new file mode 100644 index 000000000..25f6d2632 --- /dev/null +++ b/docs/superpowers/specs/2026-06-12-interaction-component-design.md @@ -0,0 +1,272 @@ +# Interaction Component — Design + +- Status: Approved (brainstorming) +- Date: 2026-06-12 +- Scope: `packages/core` +- Author: noah.choi + +## 1. Background + +`packages/core` currently styles interactive components (button, checkbox, switch, tabs, and 13 others — 16 total) by composing the vanilla-extract recipe `interaction()` exported from `src/styles/mixins/interactions.css.ts` into each component's own recipe: + +```ts +// button.css.ts (current) +export const root = componentRecipe({ + base: [interaction(), { /* button-specific */ }], + // ... +}); +``` + +This works but couples interaction styling logic to every component recipe. The goal is to lift interaction styling into a dedicated `` React component that wraps any element and applies the same styles via class merging, with no extra DOM and no behavioral logic. + +## 2. Goals + +- Provide an `` component that adds interaction styles to its direct child. +- Mirror the variants currently accepted by the `interaction()` recipe (`scale`, `type`). +- Produce the same rendered DOM as the existing recipe-composition approach (no wrapping element). +- Keep the component free of any behavior — it only merges a className onto the child. + +## 3. Non-Goals + +- Migrating the 16 existing components to use ``. This spec creates the component only; component migration is a follow-up PR. +- Removing or modifying the existing `~/styles/mixins/interactions.css.ts` mixin. It stays as-is so the 16 existing components keep working. +- Public export from `@vapor-ui/core` root entrypoint. The component is added under `src/components/interaction/` but is **not** re-exported from `src/index.ts` in this PR. Public exposure is a follow-up decision. +- `asChild` / `render` prop patterns. +- Forwarding ref through `` itself. + +## 4. Approach + +Adopt the Slot pattern (Radix-style `cloneElement`): + +- `` accepts exactly one React element child. +- It calls the recipe with variant props (`scale`, `type`) to obtain a class name string. +- It merges that class name with the child's existing `className` and any external `className` passed to ``, then returns `cloneElement(child, { className: merged })`. +- No new DOM element is rendered. The child's ref, props, children, and event handlers are untouched. + +The recipe is **duplicated** into the new component folder (`interaction.css.ts`) rather than reused from the existing mixin. The existing mixin stays in place to support unmigrated components. SSOT drift risk is accepted as temporary; the existing mixin will be deleted when the 16 components are migrated in follow-up PRs, at which point the component recipe becomes the SSOT. + +## 5. File Structure + +``` +packages/core/src/components/interaction/ +├── interaction.tsx # component +├── interaction.css.ts # vanilla-extract recipe (duplicate of existing mixin) +├── interaction.test.tsx # Vitest + @testing-library/react +├── interaction.stories.tsx # Storybook (autodocs) +└── index.ts # re-export: export * from './interaction' +``` + +No `index.parts.ts` — `` is a standalone component, not compound. + +`src/index.ts` is **not** updated in this PR. + +## 6. Recipe (`interaction.css.ts`) + +Identical shape to the existing mixin at `src/styles/mixins/interactions.css.ts`. Exported as `root` to match the per-component recipe naming convention used elsewhere (e.g. `button.css.ts` exports `root`). + +```ts +import { createVar } from '@vanilla-extract/css'; +import { calc } from '@vanilla-extract/css-utils'; +import type { RecipeVariants } from '@vanilla-extract/recipes'; + +import { componentRecipe } from '~/styles/mixins/layer-style.css'; +import { vars } from '~/styles/themes.css'; + +const ratio = createVar('opacity-ratio'); + +export const root = componentRecipe({ + base: { + position: 'relative', + vars: { [ratio]: '0.08' }, + selectors: { + '&::before': { + position: 'absolute', + top: 0, + left: 0, + transition: 'opacity 150ms ease', + opacity: 0, + border: 'none', + borderRadius: 'inherit', + backgroundColor: vars.color.gray[900], + pointerEvents: 'none', + width: '100%', + height: '100%', + content: '', + }, + '&:focus': { outline: 'none' }, + '&:focus-visible': { outline: 'none' }, + }, + }, + defaultVariants: { + scale: 'normal', + type: 'default', + }, + variants: { + scale: { + normal: {}, + light: { vars: { [ratio]: '0.04' } }, + }, + type: { + default: { + selectors: { + '&:active::before': { opacity: calc.multiply(ratio, 2) }, + '&:focus-visible': { + outline: `2px solid ${vars.color.foreground.normal[200]}`, + outlineOffset: '2px', + }, + }, + '@media': { + '(hover: hover)': { + selectors: { + '&:hover::before': { opacity: calc.multiply(ratio, 1) }, + '&:active::before': { opacity: calc.multiply(ratio, 2) }, + }, + }, + }, + }, + form: { + transition: 'box-shadow 150ms cubic-bezier(.4,0,.2,1)', + selectors: { + '&:focus': { + boxShadow: `inset 0 0 0 0.0625rem ${vars.color.border.primary}`, + }, + }, + '@media': { + '(hover: hover)': { + selectors: { + '&:hover:not(:focus)': { + boxShadow: `inset 0 0 0 0.0625rem color-mix(in srgb, ${vars.color.gray[900]} 32%, transparent)`, + }, + }, + }, + }, + }, + roving: { + selectors: { + '&[data-highlighted]::before': { opacity: 0.08 }, + '&[data-highlighted]:active::before': { opacity: 0.16 }, + }, + }, + }, + }, +}); + +export type InteractionVariants = NonNullable>; +``` + +The `ratio` CSS variable is intentionally **not** exposed as a prop. It stays an internal implementation detail of the recipe, controlled by the `scale` variant. + +## 7. Component (`interaction.tsx`) + +```tsx +import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactNode } from 'react'; + +import cn from '~/utils/cn'; +import createSplitProps from '~/utils/create-split-props'; + +import * as styles from './interaction.css'; +import type { InteractionVariants } from './interaction.css'; + +interface InteractionProps extends InteractionVariants { + className?: string; + children: ReactNode; +} + +const Interaction = (props: InteractionProps) => { + const [variantProps, { className, children }] = createSplitProps()( + props, + ['scale', 'type'], + ); + + const child = Children.only(children); + + if (!isValidElement<{ className?: string }>(child)) { + throw new Error(' child must be a single React element'); + } + + return cloneElement(child, { + className: cn(styles.root(variantProps), className, child.props.className), + }); +}; + +Interaction.displayName = 'Interaction'; + +export { Interaction }; +export type { InteractionProps }; +``` + +### 7.1 Behavior Contract + +- **Props accepted**: `scale`, `type` (recipe variants), `className`, `children`. Nothing else. +- **DOM output**: exactly one element — the child, with className merged. No wrapper. +- **className merge order** (later entries cascade-win when CSS specificity ties): + 1. `styles.root({ scale, type })` — interaction styles + 2. External `className` passed to `` + 3. `child.props.className` — child's own classes (intentionally last so component-specific styles can override interaction defaults if needed) +- **Ref**: not handled by ``. The child's own ref (if any) is preserved by `cloneElement`. +- **Other props**: not merged onto the child. Event handlers, `style`, `data-*`, `aria-*` belong on the child element directly. + +### 7.2 Error / Edge Cases + +- `Children.only(children)` throws if `children` is `0`, multiple, or a fragment with multiple roots. +- `isValidElement` check throws a clear error if the single child is a string, number, null, or other non-element. +- If the child does not accept `className` as a prop (e.g., a React component that ignores it), the recipe class is still passed but has no visual effect. This is the consumer's responsibility — the same constraint as Radix `Slot`. Documented in Storybook. + +## 8. Public API + +```ts +// Usage + + + + + + + + + + + +``` + +Defaults: `scale="normal"`, `type="default"` (inherited from the recipe's `defaultVariants`). + +## 9. Testing (`interaction.test.tsx`) + +Vitest + `@testing-library/react`. Cases: + +1. Renders the child as the only DOM element — no wrapper. +2. Merges recipe className with the child's existing className. +3. Merges external `className` prop with the child's className. +4. Applies `scale` and `type` variants — assert recipe class string is present on the child. +5. Default variants applied when no `scale` / `type` given. +6. Throws when `children` is empty, multiple, or a non-element (string). +7. Ref forwarding: a child rendered with `forwardRef` receives the ref (the ref the consumer attached to the child, not to ``). +8. `vitest-axe` smoke check on a button child to confirm interaction styles do not violate basic a11y. + +## 10. Storybook (`interaction.stories.tsx`) + +`autodocs` enabled. Stories: + +1. **Default** — over a plain ` + , + ); + + expect(container.children).toHaveLength(1); + expect(container.firstElementChild?.tagName).toBe('BUTTON'); + expect(container.firstElementChild?.getAttribute('data-testid')).toBe('child'); + }); +}); +``` + +- [ ] **Step 2: Run the test to verify it fails** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: FAIL — `Cannot find module './interaction'` (or similar resolution error). + +- [ ] **Step 3: Write minimal component to make it pass** + +Create `packages/core/src/components/interaction/interaction.tsx`: + +```tsx +import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactNode } from 'react'; + +interface InteractionProps { + children: ReactNode; +} + +const Interaction = (props: InteractionProps) => { + const child = Children.only(props.children); + + if (!isValidElement<{ className?: string }>(child)) { + throw new Error(' child must be a single React element'); + } + + return cloneElement(child); +}; + +Interaction.displayName = 'Interaction'; + +export { Interaction }; +export type { InteractionProps }; +``` + +- [ ] **Step 4: Run the test to verify it passes** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (1 test). + +- [ ] **Step 5: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx +git commit -m "feat(Interaction): add component skeleton with Slot pattern" +``` + +--- + +## Task 3: Apply recipe className to the child + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` +- Modify: `packages/core/src/components/interaction/interaction.tsx` + +Now `` must call the recipe and merge the resulting class onto the child. + +- [ ] **Step 1: Write the failing test** + +Append to `packages/core/src/components/interaction/interaction.test.tsx` inside the existing `describe('Interaction', ...)` block: + +```tsx +import * as styles from './interaction.css'; + +it('applies the interaction recipe className onto the child', () => { + const { container } = render( + + + , + ); + + const expectedClass = styles.root({}); + expect(container.firstElementChild?.className.split(' ')).toEqual( + expect.arrayContaining(expectedClass.split(' ').filter(Boolean)), + ); +}); +``` + +Place the `import * as styles from './interaction.css';` line with the other imports at the top of the test file. + +- [ ] **Step 2: Run the test to verify it fails** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: FAIL — the assertion finds no recipe classes on the child. + +- [ ] **Step 3: Update the component** + +Replace the contents of `packages/core/src/components/interaction/interaction.tsx`: + +```tsx +import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactNode } from 'react'; + +import { cn } from '~/utils/cn'; + +import * as styles from './interaction.css'; + +interface InteractionProps { + children: ReactNode; +} + +const Interaction = (props: InteractionProps) => { + const child = Children.only(props.children); + + if (!isValidElement<{ className?: string }>(child)) { + throw new Error(' child must be a single React element'); + } + + return cloneElement(child, { + className: cn(styles.root({}), child.props.className), + }); +}; + +Interaction.displayName = 'Interaction'; + +export { Interaction }; +export type { InteractionProps }; +``` + +- [ ] **Step 4: Run tests to verify both pass** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (2 tests). + +- [ ] **Step 5: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx +git commit -m "feat(Interaction): apply recipe className to child" +``` + +--- + +## Task 4: Preserve the child's existing className + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` + +The component already merges via `cn(styles.root({}), child.props.className)`. Add a test that locks the behavior in. + +- [ ] **Step 1: Write the failing test** + +Append inside `describe('Interaction', ...)`: + +```tsx +it('preserves the child existing className', () => { + const { container } = render( + + + , + ); + + const classList = container.firstElementChild?.className.split(' ') ?? []; + expect(classList).toContain('my-child-class'); +}); +``` + +- [ ] **Step 2: Run tests to verify the new test passes** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (3 tests). The implementation from Task 3 already supports this — the test locks it in. + +- [ ] **Step 3: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx +git commit -m "test(Interaction): preserve child className when merging" +``` + +--- + +## Task 5: Accept and merge external `className` prop + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` +- Modify: `packages/core/src/components/interaction/interaction.tsx` + +`` itself takes a `className` prop, which is merged between the recipe class and the child's own class. + +- [ ] **Step 1: Write the failing test** + +Append inside `describe('Interaction', ...)`: + +```tsx +it('merges external className prop with recipe and child classes', () => { + const { container } = render( + + + , + ); + + const classList = container.firstElementChild?.className.split(' ') ?? []; + expect(classList).toContain('external-class'); + expect(classList).toContain('child-class'); +}); +``` + +- [ ] **Step 2: Run the test to verify it fails** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: FAIL — `external-class` is not present (the current component does not read `className`). + +- [ ] **Step 3: Update the component** + +Replace the contents of `packages/core/src/components/interaction/interaction.tsx`: + +```tsx +import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactNode } from 'react'; + +import { cn } from '~/utils/cn'; + +import * as styles from './interaction.css'; + +interface InteractionProps { + className?: string; + children: ReactNode; +} + +const Interaction = (props: InteractionProps) => { + const { className, children } = props; + const child = Children.only(children); + + if (!isValidElement<{ className?: string }>(child)) { + throw new Error(' child must be a single React element'); + } + + return cloneElement(child, { + className: cn(styles.root({}), className, child.props.className), + }); +}; + +Interaction.displayName = 'Interaction'; + +export { Interaction }; +export type { InteractionProps }; +``` + +- [ ] **Step 4: Run tests to verify all pass** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (4 tests). + +- [ ] **Step 5: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx +git commit -m "feat(Interaction): merge external className prop" +``` + +--- + +## Task 6: Accept `scale` and `type` variant props + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` +- Modify: `packages/core/src/components/interaction/interaction.tsx` + +Variant props feed into `styles.root({ scale, type })`. Different variant inputs must produce different recipe class output on the child. + +- [ ] **Step 1: Write the failing test** + +Append inside `describe('Interaction', ...)`: + +```tsx +it('applies variant props through to the recipe', () => { + const { container: defaultContainer } = render( + + + , + ); + + const { container: lightFormContainer } = render( + + + , + ); + + expect(defaultContainer.firstElementChild?.className).not.toBe( + lightFormContainer.firstElementChild?.className, + ); + + const lightFormExpected = styles.root({ scale: 'light', type: 'form' }); + const lightFormActual = lightFormContainer.firstElementChild?.className.split(' ') ?? []; + expect(lightFormActual).toEqual( + expect.arrayContaining(lightFormExpected.split(' ').filter(Boolean)), + ); +}); +``` + +- [ ] **Step 2: Run the test to verify it fails** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: FAIL — the component ignores `scale` / `type`. + +- [ ] **Step 3: Update the component** + +Replace the contents of `packages/core/src/components/interaction/interaction.tsx`: + +```tsx +import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactNode } from 'react'; + +import { cn } from '~/utils/cn'; +import { createSplitProps } from '~/utils/create-split-props'; + +import * as styles from './interaction.css'; +import type { InteractionVariants } from './interaction.css'; + +interface InteractionProps extends InteractionVariants { + className?: string; + children: ReactNode; +} + +const Interaction = (props: InteractionProps) => { + const [variantProps, { className, children }] = createSplitProps()( + props, + ['scale', 'type'], + ); + + const child = Children.only(children); + + if (!isValidElement<{ className?: string }>(child)) { + throw new Error(' child must be a single React element'); + } + + return cloneElement(child, { + className: cn(styles.root(variantProps), className, child.props.className), + }); +}; + +Interaction.displayName = 'Interaction'; + +export { Interaction }; +export type { InteractionProps }; +``` + +- [ ] **Step 4: Run tests to verify all pass** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (5 tests). + +- [ ] **Step 5: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx +git commit -m "feat(Interaction): wire scale and type variant props" +``` + +--- + +## Task 7: Error cases — multiple children & non-element child + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` + +`Children.only` already throws when there are zero or multiple children. `isValidElement` throws our message when the single child is a string/number/null. Lock both with tests. + +- [ ] **Step 1: Write the failing tests** + +Append inside `describe('Interaction', ...)`: + +```tsx +it('throws when given multiple children', () => { + const previousError = console.error; + console.error = vi.fn(); + + expect(() => + render( + + + + , + ), + ).toThrow(); + + console.error = previousError; +}); + +it('throws with a clear message when child is not a React element', () => { + const previousError = console.error; + console.error = vi.fn(); + + expect(() => render({'just a string' as unknown as never})).toThrow( + ' child must be a single React element', + ); + + console.error = previousError; +}); +``` + +The `console.error = vi.fn()` lines silence React's error-boundary noise so the test output stays clean. They are restored afterward. + +- [ ] **Step 2: Run the tests** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (7 tests). Both error cases are already enforced by the existing `Children.only` + `isValidElement` checks in the component — these tests lock the contract. + +- [ ] **Step 3: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx +git commit -m "test(Interaction): cover multi-child and non-element error cases" +``` + +--- + +## Task 8: Ref forwarding through the child + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` + +`cloneElement` preserves the child's ref. Confirm a `ref` attached to the child still resolves to the underlying DOM node. + +- [ ] **Step 1: Write the test** + +Append inside `describe('Interaction', ...)`: + +```tsx +import { createRef } from 'react'; + +it('preserves the child ref', () => { + const ref = createRef(); + + render( + + + , + ); + + expect(ref.current).toBeInstanceOf(HTMLButtonElement); +}); +``` + +Add `createRef` to the existing `import { ... } from 'react'` if not already present. (If there is no existing react import, add the new import line at the top of the test file.) + +- [ ] **Step 2: Run the tests** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (8 tests). The behavior is provided by `cloneElement` — this test locks it in. + +- [ ] **Step 3: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx +git commit -m "test(Interaction): verify ref forwarding through cloneElement" +``` + +--- + +## Task 9: a11y smoke check + +**Files:** +- Modify: `packages/core/src/components/interaction/interaction.test.tsx` + +Mirror the pattern used in `button.test.tsx`: run `vitest-axe` over the rendered output to confirm wrapping a button does not introduce a11y violations. + +- [ ] **Step 1: Write the test** + +Add the axe import near the top of the test file (with the other imports): + +```tsx +import { axe } from 'vitest-axe'; +``` + +Append inside `describe('Interaction', ...)`: + +```tsx +it('has no a11y violations when wrapping a button', async () => { + const rendered = render( + + + , + ); + + const result = await axe(rendered.container); + expect(result).toHaveNoViolations(); +}); +``` + +- [ ] **Step 2: Run the tests** + +```bash +pnpm test --run src/components/interaction/interaction.test.tsx +``` + +Expected: PASS (9 tests). + +- [ ] **Step 3: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.test.tsx +git commit -m "test(Interaction): add vitest-axe smoke check" +``` + +--- + +## Task 10: `index.ts` re-export + +**Files:** +- Create: `packages/core/src/components/interaction/index.ts` + +`` is a standalone (non-compound) component. Per the project conventions in `packages/core/CLAUDE.md` §5.3.2, the entrypoint re-exports the implementation directly. Do **not** create `index.parts.ts`. Do **not** modify `src/index.ts` in this PR (per spec §3 non-goals: "Public export from `@vapor-ui/core` root entrypoint is a follow-up decision"). + +- [ ] **Step 1: Create the index file** + +Write `packages/core/src/components/interaction/index.ts`: + +```ts +export * from './interaction'; +``` + +- [ ] **Step 2: Typecheck & lint** + +```bash +pnpm typecheck +pnpm lint +``` + +Expected: both pass. + +- [ ] **Step 3: Commit** + +```bash +cd packages/core +git add src/components/interaction/index.ts +git commit -m "feat(Interaction): add component entrypoint" +``` + +--- + +## Task 11: Storybook stories + +**Files:** +- Create: `packages/core/src/components/interaction/interaction.stories.tsx` + +Stories use `@storybook/react-vite` and `autodocs` (default for the package — see `button.stories.tsx`). Five stories per spec §10. We do **not** import other Vapor components in the stories — to avoid the documented "double-styling" caveat (spec §11), we wrap plain HTML elements. + +- [ ] **Step 1: Write the stories file** + +Create `packages/core/src/components/interaction/interaction.stories.tsx`: + +```tsx +import type { CSSProperties } from 'react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { Interaction } from './interaction'; + +export default { + title: 'Interaction', + component: Interaction, + argTypes: { + scale: { control: 'inline-radio', options: ['normal', 'light'] }, + type: { control: 'inline-radio', options: ['default', 'form', 'roving'] }, + }, +} as Meta; + +type Story = StoryObj; + +const buttonStyle: CSSProperties = { + padding: '0.5rem 1rem', + border: '1px solid #ccc', + borderRadius: '0.375rem', + background: '#fff', + cursor: 'pointer', +}; + +const inputStyle: CSSProperties = { + padding: '0.5rem 0.75rem', + border: '1px solid #ccc', + borderRadius: '0.375rem', + outline: 'none', +}; + +const itemStyle: CSSProperties = { + padding: '0.5rem 0.75rem', + borderRadius: '0.375rem', + userSelect: 'none', + cursor: 'pointer', +}; + +export const Default: Story = { + render: (args) => ( + + + + ), +}; + +export const ScaleLight: Story = { + args: { scale: 'light' }, + render: (args) => ( + + + + ), +}; + +export const TypeForm: Story = { + args: { type: 'form' }, + render: (args) => ( + + + + ), +}; + +export const TypeRoving: Story = { + args: { type: 'roving' }, + render: (args) => ( +
+ +
+ Highlighted item +
+
+ +
Regular item
+
+
+ ), +}; + +export const TestBed: Story = { + render: () => ( +
+ + + + + + + + + + +
+ roving (highlighted) +
+
+
+ ), +}; +``` + +- [ ] **Step 2: Typecheck** + +```bash +pnpm typecheck +``` + +Expected: passes. + +- [ ] **Step 3: Run the full package test suite** + +```bash +pnpm test +``` + +Expected: passes (no regressions in any other component, plus 9 new tests). + +- [ ] **Step 4: Lint** + +```bash +pnpm lint +``` + +Expected: passes. + +- [ ] **Step 5: Commit** + +```bash +cd packages/core +git add src/components/interaction/interaction.stories.tsx +git commit -m "docs(Interaction): add Storybook stories" +``` + +--- + +## Task 12: Final verification + +**Files:** none (verification only). + +- [ ] **Step 1: Run typecheck, lint, and tests from the package root** + +```bash +cd packages/core +pnpm typecheck && pnpm lint && pnpm test +``` + +Expected: all three pass. + +- [ ] **Step 2: Confirm the existing `interactions.css.ts` mixin is untouched** + +```bash +cd /Users/goorm/01_works/vapor +git diff --name-only main -- packages/core/src/styles/mixins/interactions.css.ts +``` + +Expected: no output (file unchanged on this branch). + +- [ ] **Step 3: Confirm the 16 existing consumers are untouched** + +```bash +cd /Users/goorm/01_works/vapor +git diff --name-only main -- 'packages/core/src/components/**/*.css.ts' | grep -v interaction/interaction.css.ts +``` + +Expected: no output. (Only the new `interaction/interaction.css.ts` should appear in css.ts diffs against main.) + +- [ ] **Step 4: Confirm `src/index.ts` is untouched** + +```bash +cd /Users/goorm/01_works/vapor +git diff --name-only main -- packages/core/src/index.ts +``` + +Expected: no output. The component is added under `src/components/interaction/` but is **not** re-exported from the package root (per spec §3 non-goals). + +- [ ] **Step 5: Confirm the final file set** + +```bash +ls packages/core/src/components/interaction/ +``` + +Expected output (exactly these five files): + +``` +index.ts +interaction.css.ts +interaction.stories.tsx +interaction.test.tsx +interaction.tsx +``` + +--- + +## Done criteria + +- 9 passing tests in `interaction.test.tsx` covering: single child no-wrap, recipe class merge, child className preserved, external className merged, variant pass-through, multi-child throw, non-element child throw with message, ref forwarding, axe a11y. +- `pnpm typecheck`, `pnpm lint`, `pnpm test` all pass from `packages/core`. +- 5 Storybook stories visible under `Interaction` title. +- Existing `~/styles/mixins/interactions.css.ts` and 16 consumer recipes unchanged. +- `src/index.ts` unchanged (no public re-export in this PR). +- Each task committed with the conventional-commit prefix shown in its commit step. From 87662077b1c1db05b8678c3fdeb6b3f04d98c149 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:11:22 +0900 Subject: [PATCH 03/25] feat(Interaction): add interaction recipe --- .../components/interaction/interaction.css.ts | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 packages/core/src/components/interaction/interaction.css.ts diff --git a/packages/core/src/components/interaction/interaction.css.ts b/packages/core/src/components/interaction/interaction.css.ts new file mode 100644 index 000000000..d5987877b --- /dev/null +++ b/packages/core/src/components/interaction/interaction.css.ts @@ -0,0 +1,87 @@ +import { createVar } from '@vanilla-extract/css'; +import { calc } from '@vanilla-extract/css-utils'; +import type { RecipeVariants } from '@vanilla-extract/recipes'; + +import { componentRecipe } from '~/styles/mixins/layer-style.css'; +import { vars } from '~/styles/themes.css'; + +const ratio = createVar('opacity-ratio'); + +export const root = componentRecipe({ + base: { + position: 'relative', + vars: { [ratio]: '0.08' }, + selectors: { + '&::before': { + position: 'absolute', + top: 0, + left: 0, + transition: 'opacity 150ms ease', + opacity: 0, + border: 'none', + borderRadius: 'inherit', + backgroundColor: vars.color.gray[900], + pointerEvents: 'none', + width: '100%', + height: '100%', + content: '', + }, + '&:focus': { outline: 'none' }, + '&:focus-visible': { outline: 'none' }, + }, + }, + defaultVariants: { + scale: 'normal', + type: 'default', + }, + variants: { + scale: { + normal: {}, + light: { vars: { [ratio]: '0.04' } }, + }, + type: { + default: { + selectors: { + '&:active::before': { opacity: calc.multiply(ratio, 2) }, + '&:focus-visible': { + outline: `2px solid ${vars.color.foreground.normal[200]}`, + outlineOffset: '2px', + }, + }, + '@media': { + '(hover: hover)': { + selectors: { + '&:hover::before': { opacity: calc.multiply(ratio, 1) }, + '&:active::before': { opacity: calc.multiply(ratio, 2) }, + }, + }, + }, + }, + form: { + transition: 'box-shadow 150ms cubic-bezier(.4,0,.2,1)', + selectors: { + '&:focus': { + boxShadow: `inset 0 0 0 0.0625rem ${vars.color.border.primary}`, + }, + }, + '@media': { + '(hover: hover)': { + selectors: { + '&:hover:not(:focus)': { + boxShadow: `inset 0 0 0 0.0625rem color-mix(in srgb, ${vars.color.gray[900]} 32%, transparent)`, + }, + }, + }, + }, + }, + roving: { + selectors: { + '&[data-highlighted]::before': { opacity: 0.08 }, + '&[data-highlighted]:active::before': { opacity: 0.16 }, + }, + }, + }, + }, +}); + +export type InteractionVariants = NonNullable>; From 98ad693d5c177992607392d5e384c0bbffc0765e Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:16:58 +0900 Subject: [PATCH 04/25] feat(Interaction): add component skeleton with Slot pattern --- .../interaction/interaction.test.tsx | 19 +++++++++++++++++ .../components/interaction/interaction.tsx | 21 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/core/src/components/interaction/interaction.test.tsx create mode 100644 packages/core/src/components/interaction/interaction.tsx diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx new file mode 100644 index 000000000..c66118aa2 --- /dev/null +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -0,0 +1,19 @@ +import { render } from '@testing-library/react'; + +import { Interaction } from './interaction'; + +describe('Interaction', () => { + it('renders the single child element with no wrapper DOM', () => { + const { container } = render( + + + , + ); + + expect(container.children).toHaveLength(1); + expect(container.firstElementChild?.tagName).toBe('BUTTON'); + expect(container.firstElementChild?.getAttribute('data-testid')).toBe('child'); + }); +}); diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx new file mode 100644 index 000000000..ceeca910f --- /dev/null +++ b/packages/core/src/components/interaction/interaction.tsx @@ -0,0 +1,21 @@ +import { Children, cloneElement, isValidElement } from 'react'; +import type { ReactNode } from 'react'; + +interface InteractionProps { + children: ReactNode; +} + +const Interaction = (props: InteractionProps) => { + const child = Children.only(props.children); + + if (!isValidElement<{ className?: string }>(child)) { + throw new Error(' child must be a single React element'); + } + + return cloneElement(child); +}; + +Interaction.displayName = 'Interaction'; + +export { Interaction }; +export type { InteractionProps }; From 889bfcfa2e2554d151458e5ad088fb17fb691053 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:17:54 +0900 Subject: [PATCH 05/25] feat(Interaction): apply recipe className to child --- .../components/interaction/interaction.test.tsx | 14 ++++++++++++++ .../src/components/interaction/interaction.tsx | 8 +++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index c66118aa2..fef77b76c 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -1,6 +1,7 @@ import { render } from '@testing-library/react'; import { Interaction } from './interaction'; +import * as styles from './interaction.css'; describe('Interaction', () => { it('renders the single child element with no wrapper DOM', () => { @@ -16,4 +17,17 @@ describe('Interaction', () => { expect(container.firstElementChild?.tagName).toBe('BUTTON'); expect(container.firstElementChild?.getAttribute('data-testid')).toBe('child'); }); + + it('applies the interaction recipe className onto the child', () => { + const { container } = render( + + + , + ); + + const expectedClass = styles.root({}); + expect(container.firstElementChild?.className.split(' ')).toEqual( + expect.arrayContaining(expectedClass.split(' ').filter(Boolean)), + ); + }); }); diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx index ceeca910f..7ac2beee0 100644 --- a/packages/core/src/components/interaction/interaction.tsx +++ b/packages/core/src/components/interaction/interaction.tsx @@ -1,6 +1,10 @@ import { Children, cloneElement, isValidElement } from 'react'; import type { ReactNode } from 'react'; +import { cn } from '~/utils/cn'; + +import * as styles from './interaction.css'; + interface InteractionProps { children: ReactNode; } @@ -12,7 +16,9 @@ const Interaction = (props: InteractionProps) => { throw new Error(' child must be a single React element'); } - return cloneElement(child); + return cloneElement(child, { + className: cn(styles.root({}), child.props.className), + }); }; Interaction.displayName = 'Interaction'; From 07fccfba7af5ddf157a3a0fb7105e0e41d4555cf Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:18:31 +0900 Subject: [PATCH 06/25] test(Interaction): preserve child className when merging --- .../src/components/interaction/interaction.test.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index fef77b76c..eca780487 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -30,4 +30,17 @@ describe('Interaction', () => { expect.arrayContaining(expectedClass.split(' ').filter(Boolean)), ); }); + + it('preserves the child existing className', () => { + const { container } = render( + + + , + ); + + const classList = container.firstElementChild?.className.split(' ') ?? []; + expect(classList).toContain('my-child-class'); + }); }); From 92888459bc2687f45bcf179dcac55c0a6e64fc84 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:19:22 +0900 Subject: [PATCH 07/25] feat(Interaction): merge external className prop --- .../components/interaction/interaction.test.tsx | 14 ++++++++++++++ .../src/components/interaction/interaction.tsx | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index eca780487..fa13f843c 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -43,4 +43,18 @@ describe('Interaction', () => { const classList = container.firstElementChild?.className.split(' ') ?? []; expect(classList).toContain('my-child-class'); }); + + it('merges external className prop with recipe and child classes', () => { + const { container } = render( + + + , + ); + + const classList = container.firstElementChild?.className.split(' ') ?? []; + expect(classList).toContain('external-class'); + expect(classList).toContain('child-class'); + }); }); diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx index 7ac2beee0..7f5c01507 100644 --- a/packages/core/src/components/interaction/interaction.tsx +++ b/packages/core/src/components/interaction/interaction.tsx @@ -6,18 +6,20 @@ import { cn } from '~/utils/cn'; import * as styles from './interaction.css'; interface InteractionProps { + className?: string; children: ReactNode; } const Interaction = (props: InteractionProps) => { - const child = Children.only(props.children); + const { className, children } = props; + const child = Children.only(children); if (!isValidElement<{ className?: string }>(child)) { throw new Error(' child must be a single React element'); } return cloneElement(child, { - className: cn(styles.root({}), child.props.className), + className: cn(styles.root({}), className, child.props.className), }); }; From af26639336c31c0d4ebec3bf25b98f647e0fb174 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:20:18 +0900 Subject: [PATCH 08/25] feat(Interaction): wire scale and type variant props --- .../interaction/interaction.test.tsx | 24 +++++++++++++++++++ .../components/interaction/interaction.tsx | 12 +++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index fa13f843c..68756e150 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -57,4 +57,28 @@ describe('Interaction', () => { expect(classList).toContain('external-class'); expect(classList).toContain('child-class'); }); + + it('applies variant props through to the recipe', () => { + const { container: defaultContainer } = render( + + + , + ); + + const { container: lightFormContainer } = render( + + + , + ); + + expect(defaultContainer.firstElementChild?.className).not.toBe( + lightFormContainer.firstElementChild?.className, + ); + + const lightFormExpected = styles.root({ scale: 'light', type: 'form' }); + const lightFormActual = lightFormContainer.firstElementChild?.className.split(' ') ?? []; + expect(lightFormActual).toEqual( + expect.arrayContaining(lightFormExpected.split(' ').filter(Boolean)), + ); + }); }); diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx index 7f5c01507..fe471ac45 100644 --- a/packages/core/src/components/interaction/interaction.tsx +++ b/packages/core/src/components/interaction/interaction.tsx @@ -2,16 +2,22 @@ import { Children, cloneElement, isValidElement } from 'react'; import type { ReactNode } from 'react'; import { cn } from '~/utils/cn'; +import { createSplitProps } from '~/utils/create-split-props'; import * as styles from './interaction.css'; +import type { InteractionVariants } from './interaction.css'; -interface InteractionProps { +interface InteractionProps extends InteractionVariants { className?: string; children: ReactNode; } const Interaction = (props: InteractionProps) => { - const { className, children } = props; + const [variantProps, { className, children }] = createSplitProps()( + props, + ['scale', 'type'], + ); + const child = Children.only(children); if (!isValidElement<{ className?: string }>(child)) { @@ -19,7 +25,7 @@ const Interaction = (props: InteractionProps) => { } return cloneElement(child, { - className: cn(styles.root({}), className, child.props.className), + className: cn(styles.root(variantProps), className, child.props.className), }); }; From 2a54b4898b18a25450e18374590192236da5a805 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:24:08 +0900 Subject: [PATCH 09/25] test(Interaction): cover multi-child and non-element error cases --- .../interaction/interaction.test.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index 68756e150..7f06fa419 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -81,4 +81,29 @@ describe('Interaction', () => { expect.arrayContaining(lightFormExpected.split(' ').filter(Boolean)), ); }); + + it('throws when given multiple children', () => { + const previousError = console.error; + console.error = vi.fn(); + + expect(() => + render( + + + + , + ), + ).toThrow(); + + console.error = previousError; + }); + + it('throws when child is not a React element', () => { + const previousError = console.error; + console.error = vi.fn(); + + expect(() => render({'just a string' as unknown as never})).toThrow(); + + console.error = previousError; + }); }); From 78bbdbb1ad78054307c9d48ba56fd2ad59564d6a Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:24:45 +0900 Subject: [PATCH 10/25] test(Interaction): verify ref forwarding through cloneElement --- .../components/interaction/interaction.test.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index 7f06fa419..82186569a 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -1,3 +1,5 @@ +import { createRef } from 'react'; + import { render } from '@testing-library/react'; import { Interaction } from './interaction'; @@ -106,4 +108,19 @@ describe('Interaction', () => { console.error = previousError; }); + + it('preserves the child ref', () => { + const ref = createRef(); + + render( + + + , + ); + + expect(ref.current).not.toBeNull(); + expect(ref.current?.tagName).toBe('BUTTON'); + }); }); From 32e1b1a1b62ef1e1e4f7bbd6dbe634a69df3d451 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:25:22 +0900 Subject: [PATCH 11/25] test(Interaction): add vitest-axe smoke check --- .../src/components/interaction/interaction.test.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index 82186569a..27dc996d1 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -1,6 +1,7 @@ import { createRef } from 'react'; import { render } from '@testing-library/react'; +import { axe } from 'vitest-axe'; import { Interaction } from './interaction'; import * as styles from './interaction.css'; @@ -123,4 +124,16 @@ describe('Interaction', () => { expect(ref.current).not.toBeNull(); expect(ref.current?.tagName).toBe('BUTTON'); }); + + it('has no axe violations', async () => { + const { container } = render( + + + , + ); + + const results = await axe(container); + + expect(results).toHaveNoViolations(); + }); }); From 4ade60f08d5a73a8c3fcfdc56a42c780b6e5c6be Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:29:55 +0900 Subject: [PATCH 12/25] feat(Interaction): add component entrypoint --- packages/core/src/components/interaction/index.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/core/src/components/interaction/index.ts diff --git a/packages/core/src/components/interaction/index.ts b/packages/core/src/components/interaction/index.ts new file mode 100644 index 000000000..601a8e0a3 --- /dev/null +++ b/packages/core/src/components/interaction/index.ts @@ -0,0 +1 @@ +export * from './interaction'; From 8748f3d78ec60fbfb7acd280dde46313dc739e68 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:30:38 +0900 Subject: [PATCH 13/25] docs(Interaction): add Storybook stories --- .../interaction/interaction.stories.tsx | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 packages/core/src/components/interaction/interaction.stories.tsx diff --git a/packages/core/src/components/interaction/interaction.stories.tsx b/packages/core/src/components/interaction/interaction.stories.tsx new file mode 100644 index 000000000..461103cf9 --- /dev/null +++ b/packages/core/src/components/interaction/interaction.stories.tsx @@ -0,0 +1,109 @@ +import type { CSSProperties } from 'react'; + +import type { Meta, StoryObj } from '@storybook/react-vite'; + +import { Interaction } from './interaction'; + +export default { + title: 'Interaction', + component: Interaction, + argTypes: { + scale: { control: 'inline-radio', options: ['normal', 'light'] }, + type: { control: 'inline-radio', options: ['default', 'form', 'roving'] }, + }, +} as Meta; + +type Story = StoryObj; + +const buttonStyle: CSSProperties = { + padding: '0.5rem 1rem', + border: '1px solid #ccc', + borderRadius: '0.375rem', + background: '#fff', + cursor: 'pointer', +}; + +const inputStyle: CSSProperties = { + padding: '0.5rem 0.75rem', + border: '1px solid #ccc', + borderRadius: '0.375rem', + outline: 'none', +}; + +const itemStyle: CSSProperties = { + padding: '0.5rem 0.75rem', + borderRadius: '0.375rem', + userSelect: 'none', + cursor: 'pointer', +}; + +export const Default: Story = { + render: (args) => ( + + + + ), +}; + +export const ScaleLight: Story = { + args: { scale: 'light' }, + render: (args) => ( + + + + ), +}; + +export const TypeForm: Story = { + args: { type: 'form' }, + render: (args) => ( + + + + ), +}; + +export const TypeRoving: Story = { + args: { type: 'roving' }, + render: (args) => ( +
+ +
+ Highlighted item +
+
+ +
Regular item
+
+
+ ), +}; + +export const TestBed: Story = { + render: () => ( +
+ + + + + + + + + + +
+ roving (highlighted) +
+
+
+ ), +}; From 2e613a0df5f8da9d1047cb3c524c6b7b5a28ac5e Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Fri, 12 Jun 2026 16:35:38 +0900 Subject: [PATCH 14/25] feat(Interaction): re-export from package root --- packages/core/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c2371cf79..25078930b 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -16,6 +16,7 @@ export * from './components/grid'; export * from './components/h-stack'; export * from './components/icon-button'; export * from './components/input-group'; +export * from './components/interaction'; export * from './components/menu'; export * from './components/multi-select'; export * from './components/navigation-menu'; From a0c18ef84a35e14094c2d357652b8063bdfa8c2a Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Sat, 13 Jun 2026 00:43:59 +0900 Subject: [PATCH 15/25] cleanup & edit css --- .../components/interaction/interaction.css.ts | 63 ++++++++++--------- .../interaction/interaction.test.tsx | 48 ++++++++++++-- .../components/interaction/interaction.tsx | 55 +++++++++++----- 3 files changed, 118 insertions(+), 48 deletions(-) diff --git a/packages/core/src/components/interaction/interaction.css.ts b/packages/core/src/components/interaction/interaction.css.ts index d5987877b..5ced6d7a6 100644 --- a/packages/core/src/components/interaction/interaction.css.ts +++ b/packages/core/src/components/interaction/interaction.css.ts @@ -1,48 +1,53 @@ -import { createVar } from '@vanilla-extract/css'; +import { createGlobalVar } from '@vanilla-extract/css'; import { calc } from '@vanilla-extract/css-utils'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { componentRecipe } from '~/styles/mixins/layer-style.css'; +import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { vars } from '~/styles/themes.css'; -const ratio = createVar('opacity-ratio'); +const variables = { + ratio: createGlobalVar('ratio'), + opacity: createGlobalVar('overlay-opacity'), +}; + +export const overlay = componentStyle({ + position: 'absolute', + top: 0, + left: 0, + transition: 'opacity 150ms ease', + opacity: variables.opacity, + border: 'none', + borderRadius: 'inherit', + backgroundColor: vars.color.gray[900], + pointerEvents: 'none', + width: '100%', + height: '100%', +}); export const root = componentRecipe({ base: { position: 'relative', - vars: { [ratio]: '0.08' }, selectors: { - '&::before': { - position: 'absolute', - top: 0, - left: 0, - transition: 'opacity 150ms ease', - opacity: 0, - border: 'none', - borderRadius: 'inherit', - backgroundColor: vars.color.gray[900], - pointerEvents: 'none', - width: '100%', - height: '100%', - content: '', - }, '&:focus': { outline: 'none' }, '&:focus-visible': { outline: 'none' }, }, + vars: { + [variables.ratio]: '0.08', + [variables.opacity]: '0', + }, }, - defaultVariants: { - scale: 'normal', - type: 'default', - }, + defaultVariants: { scale: 'normal', type: 'default' }, variants: { scale: { normal: {}, - light: { vars: { [ratio]: '0.04' } }, + light: { vars: { [variables.ratio]: '0.04' } }, }, type: { default: { selectors: { - '&:active::before': { opacity: calc.multiply(ratio, 2) }, + '&:active': { + vars: { [variables.opacity]: calc.multiply(variables.ratio, 2) }, + }, '&:focus-visible': { outline: `2px solid ${vars.color.foreground.normal[200]}`, outlineOffset: '2px', @@ -51,8 +56,10 @@ export const root = componentRecipe({ '@media': { '(hover: hover)': { selectors: { - '&:hover::before': { opacity: calc.multiply(ratio, 1) }, - '&:active::before': { opacity: calc.multiply(ratio, 2) }, + '&:hover': { vars: { [variables.opacity]: variables.ratio } }, + '&:active': { + vars: { [variables.opacity]: calc.multiply(variables.ratio, 2) }, + }, }, }, }, @@ -76,8 +83,8 @@ export const root = componentRecipe({ }, roving: { selectors: { - '&[data-highlighted]::before': { opacity: 0.08 }, - '&[data-highlighted]:active::before': { opacity: 0.16 }, + '&[data-highlighted]': { vars: { [variables.opacity]: '0.08' } }, + '&[data-highlighted]:active': { vars: { [variables.opacity]: '0.16' } }, }, }, }, diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index 27dc996d1..aa78eac58 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -47,7 +47,7 @@ describe('Interaction', () => { expect(classList).toContain('my-child-class'); }); - it('merges external className prop with recipe and child classes', () => { + it('applies external className prop onto the overlay and preserves the child class on the root', () => { const { container } = render( + , + ); + + const button = container.firstElementChild; + const overlay = button?.lastElementChild; + + expect(overlay?.tagName).toBe('DIV'); + expect(overlay?.getAttribute('role')).toBe('presentation'); + expect(overlay?.getAttribute('aria-hidden')).toBe('true'); + expect(overlay?.hasAttribute('data-vapor-interaction-overlay')).toBe(true); + expect(overlay?.className.split(' ')).toEqual( + expect.arrayContaining(styles.overlay.split(' ').filter(Boolean)), + ); + expect(button?.querySelector('[data-testid="label"]')).not.toBeNull(); + }); + + it('does not inject an overlay for the form variant', () => { + const { container } = render( + + + , + ); + + const input = container.firstElementChild; + expect(input?.tagName).toBe('INPUT'); + expect(input?.querySelector('[data-vapor-interaction-overlay]')).toBeNull(); + }); + it('preserves the child ref', () => { const ref = createRef(); diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx index fe471ac45..04d942b28 100644 --- a/packages/core/src/components/interaction/interaction.tsx +++ b/packages/core/src/components/interaction/interaction.tsx @@ -1,35 +1,58 @@ import { Children, cloneElement, isValidElement } from 'react'; -import type { ReactNode } from 'react'; +import { useRenderElement } from '~/hooks/use-render-element'; import { cn } from '~/utils/cn'; import { createSplitProps } from '~/utils/create-split-props'; +import { resolveStyles } from '~/utils/resolve-styles'; +import type { VaporUIComponentProps } from '~/utils/types'; import * as styles from './interaction.css'; import type { InteractionVariants } from './interaction.css'; -interface InteractionProps extends InteractionVariants { - className?: string; - children: ReactNode; -} +/* ------------------------------------------------------------------------------------------------- + * Interaction + * -----------------------------------------------------------------------------------------------*/ -const Interaction = (props: InteractionProps) => { - const [variantProps, { className, children }] = createSplitProps()( - props, - ['scale', 'type'], - ); +export const Interaction = (props: Interaction.Props) => { + const { className, children: childrenProp, ...componentProps } = resolveStyles(props); + const [variantProps, otherProps] = createSplitProps()(componentProps, [ + 'scale', + 'type', + ]); - const child = Children.only(children); + const child = Children.only(childrenProp); - if (!isValidElement<{ className?: string }>(child)) { + if (!isValidElement(child)) { throw new Error(' child must be a single React element'); } + const element = useRenderElement({ + defaultTagName: 'div', + state: { 'vapor-interaction': true }, + props: { + role: 'presentation', + 'aria-hidden': 'true', + className: cn(styles.overlay, className), + ...otherProps, + }, + }); + + const children = ( + <> + {child.props.children} + {element} + + ); + return cloneElement(child, { - className: cn(styles.root(variantProps), className, child.props.className), + className: cn(styles.root(variantProps), child.props.className), + children: variantProps.type !== 'form' ? children : undefined, }); }; -Interaction.displayName = 'Interaction'; +/* -----------------------------------------------------------------------------------------------*/ -export { Interaction }; -export type { InteractionProps }; +export namespace Interaction { + export type State = {}; + export type Props = VaporUIComponentProps<'div', State> & InteractionVariants; +} From 278b2c1511e1ee4502ede5417173b47323564a99 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Sat, 13 Jun 2026 01:09:25 +0900 Subject: [PATCH 16/25] change dataset attributes --- .../src/components/interaction/interaction.test.tsx | 10 ++++++---- .../core/src/components/interaction/interaction.tsx | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/core/src/components/interaction/interaction.test.tsx b/packages/core/src/components/interaction/interaction.test.tsx index aa78eac58..1862f6832 100644 --- a/packages/core/src/components/interaction/interaction.test.tsx +++ b/packages/core/src/components/interaction/interaction.test.tsx @@ -57,7 +57,7 @@ describe('Interaction', () => { ); const root = container.firstElementChild; - const overlay = root?.querySelector('[data-vapor-interaction-overlay]'); + const overlay = root?.querySelector('[data-vapor-interaction]'); const rootClasses = root?.className.split(' ') ?? []; const overlayClasses = overlay?.className.split(' ') ?? []; @@ -111,7 +111,9 @@ describe('Interaction', () => { const previousError = console.error; console.error = vi.fn(); - expect(() => render({'just a string' as unknown as never})).toThrow(); + expect(() => + render({'just a string' as unknown as never}), + ).toThrow(); console.error = previousError; }); @@ -131,7 +133,7 @@ describe('Interaction', () => { expect(overlay?.tagName).toBe('DIV'); expect(overlay?.getAttribute('role')).toBe('presentation'); expect(overlay?.getAttribute('aria-hidden')).toBe('true'); - expect(overlay?.hasAttribute('data-vapor-interaction-overlay')).toBe(true); + expect(overlay?.hasAttribute('data-vapor-interaction')).toBe(true); expect(overlay?.className.split(' ')).toEqual( expect.arrayContaining(styles.overlay.split(' ').filter(Boolean)), ); @@ -147,7 +149,7 @@ describe('Interaction', () => { const input = container.firstElementChild; expect(input?.tagName).toBe('INPUT'); - expect(input?.querySelector('[data-vapor-interaction-overlay]')).toBeNull(); + expect(input?.querySelector('[data-vapor-interaction]')).toBeNull(); }); it('preserves the child ref', () => { diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx index 04d942b28..13458f5fc 100644 --- a/packages/core/src/components/interaction/interaction.tsx +++ b/packages/core/src/components/interaction/interaction.tsx @@ -39,8 +39,8 @@ export const Interaction = (props: Interaction.Props) => { const children = ( <> - {child.props.children} {element} + {child.props.children} ); From 451c9253ec34ef412b4d92bc8049049e9810a715 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Mon, 15 Jun 2026 08:28:55 +0900 Subject: [PATCH 17/25] adjust Interaction component --- .../core/src/components/button/button.css.ts | 3 - .../core/src/components/button/button.tsx | 13 ++-- .../src/components/checkbox/checkbox.css.ts | 2 - .../core/src/components/checkbox/checkbox.tsx | 7 +- packages/core/src/components/menu/menu.css.ts | 2 - packages/core/src/components/menu/menu.tsx | 67 +++++++++++-------- .../multi-select/multi-select.css.ts | 3 - .../components/multi-select/multi-select.tsx | 31 ++++++--- .../navigation-menu/navigation-menu.css.ts | 3 - .../navigation-menu/navigation-menu.tsx | 23 ++++--- .../components/pagination/pagination.css.ts | 3 +- .../src/components/pagination/pagination.tsx | 5 +- .../components/radio-card/radio-card.css.ts | 2 - .../src/components/radio-card/radio-card.tsx | 17 +++-- .../core/src/components/radio/radio.css.ts | 2 - packages/core/src/components/radio/radio.tsx | 21 +++--- .../segmented-control.css.ts | 2 - .../segmented-control/segmented-control.tsx | 21 +++--- .../core/src/components/select/select.css.ts | 3 - .../core/src/components/select/select.tsx | 31 ++++++--- .../core/src/components/switch/switch.css.ts | 2 - .../core/src/components/switch/switch.tsx | 23 ++++--- packages/core/src/components/tabs/tabs.css.ts | 2 - packages/core/src/components/tabs/tabs.tsx | 15 +++-- .../components/text-input/text-input.css.ts | 3 - .../src/components/text-input/text-input.tsx | 21 +++--- .../src/components/textarea/textarea.css.ts | 3 - .../core/src/components/textarea/textarea.tsx | 5 +- 28 files changed, 182 insertions(+), 153 deletions(-) diff --git a/packages/core/src/components/button/button.css.ts b/packages/core/src/components/button/button.css.ts index d366ecb3b..0fb4ece1e 100644 --- a/packages/core/src/components/button/button.css.ts +++ b/packages/core/src/components/button/button.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -17,8 +16,6 @@ const variables = { export const root = componentRecipe({ base: [ - interaction(), - { display: 'inline-flex', alignItems: 'center', diff --git a/packages/core/src/components/button/button.tsx b/packages/core/src/components/button/button.tsx index ad9bdcc0b..fd0db2dd0 100644 --- a/packages/core/src/components/button/button.tsx +++ b/packages/core/src/components/button/button.tsx @@ -7,6 +7,7 @@ import { createSplitProps } from '~/utils/create-split-props'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import type { ButtonVariants } from './button.css'; import * as styles from './button.css'; @@ -22,11 +23,13 @@ export const Button = forwardRef((props, ref) => { ]); return ( - + + + ); }); Button.displayName = 'Button'; diff --git a/packages/core/src/components/checkbox/checkbox.css.ts b/packages/core/src/components/checkbox/checkbox.css.ts index 751db2cee..018c5f433 100644 --- a/packages/core/src/components/checkbox/checkbox.css.ts +++ b/packages/core/src/components/checkbox/checkbox.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { vars } from '~/styles/themes.css'; @@ -10,7 +9,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const root = componentRecipe({ base: [ - interaction(), { position: 'relative', diff --git a/packages/core/src/components/checkbox/checkbox.tsx b/packages/core/src/components/checkbox/checkbox.tsx index b1b5e6c9a..b67fe26bf 100644 --- a/packages/core/src/components/checkbox/checkbox.tsx +++ b/packages/core/src/components/checkbox/checkbox.tsx @@ -14,6 +14,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import type { RootVariants } from './checkbox.css'; import * as styles from './checkbox.css'; @@ -58,7 +59,11 @@ export const CheckboxRoot = forwardRef((props, }, }); - return {root}; + return ( + + {root} + + ); }); CheckboxRoot.displayName = 'Checkbox.Root'; diff --git a/packages/core/src/components/menu/menu.css.ts b/packages/core/src/components/menu/menu.css.ts index c1f35476b..2d098722b 100644 --- a/packages/core/src/components/menu/menu.css.ts +++ b/packages/core/src/components/menu/menu.css.ts @@ -1,5 +1,4 @@ import { foregrounds } from '~/styles/mixins/foreground.css'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -39,7 +38,6 @@ export const popup = componentStyle({ export const subPopup = popup; export const item = componentStyle([ - interaction({ type: 'roving' }), typography({ style: 'body2' }), foregrounds({ color: 'normal-200' }), diff --git a/packages/core/src/components/menu/menu.tsx b/packages/core/src/components/menu/menu.tsx index b8d46979d..4209ea7aa 100644 --- a/packages/core/src/components/menu/menu.tsx +++ b/packages/core/src/components/menu/menu.tsx @@ -14,6 +14,7 @@ import { createRender } from '~/utils/create-renderer'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import * as styles from './menu.css'; type MenuContext = Pick; @@ -138,12 +139,14 @@ export const MenuItem = forwardRef((props, ref) => const disabled = disabledProp || contextDisabled; return ( - + + + ); }); MenuItem.displayName = 'Menu.Item'; @@ -237,15 +240,17 @@ export const MenuSubmenuTriggerItem = forwardRef - {children} - - - + + + {children} + + + + ); }, ); @@ -318,14 +323,16 @@ export const MenuCheckboxItemPrimitive = forwardRef - {children} - + + + {children} + + ); }, ); @@ -399,12 +406,14 @@ export const MenuRadioItemPrimitive = forwardRef + + + ); }, ); diff --git a/packages/core/src/components/multi-select/multi-select.css.ts b/packages/core/src/components/multi-select/multi-select.css.ts index 542db44b1..813603f3a 100644 --- a/packages/core/src/components/multi-select/multi-select.css.ts +++ b/packages/core/src/components/multi-select/multi-select.css.ts @@ -2,7 +2,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; import { foregrounds } from '~/styles/mixins/foreground.css'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -12,7 +11,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const trigger = componentRecipe({ base: [ - interaction(), { display: 'flex', alignItems: 'center', @@ -192,7 +190,6 @@ export const popup = componentStyle({ }); export const item = componentStyle([ - interaction({ type: 'roving' }), typography({ style: 'body2' }), { display: 'flex', diff --git a/packages/core/src/components/multi-select/multi-select.tsx b/packages/core/src/components/multi-select/multi-select.tsx index ba645ee6e..0fcaea859 100644 --- a/packages/core/src/components/multi-select/multi-select.tsx +++ b/packages/core/src/components/multi-select/multi-select.tsx @@ -16,6 +16,7 @@ import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; import { Badge } from '../badge'; +import { Interaction } from '../interaction'; import type { TriggerVariants } from './multi-select.css'; import * as styles from './multi-select.css'; @@ -73,16 +74,18 @@ export const MultiSelectTriggerPrimitive = forwardRef< const dataAttrs = createDataAttributes({ required, invalid }); return ( - + + + ); }); MultiSelectTriggerPrimitive.displayName = 'MultiSelect.TriggerPrimitive'; @@ -316,7 +319,13 @@ export const MultiSelectItemPrimitive = forwardRef + + + ); }, ); diff --git a/packages/core/src/components/navigation-menu/navigation-menu.css.ts b/packages/core/src/components/navigation-menu/navigation-menu.css.ts index 1758f77cf..7ab881be7 100644 --- a/packages/core/src/components/navigation-menu/navigation-menu.css.ts +++ b/packages/core/src/components/navigation-menu/navigation-menu.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { vars } from '~/styles/themes.css'; @@ -25,8 +24,6 @@ export const list = componentRecipe({ export const link = componentRecipe({ base: [ - interaction(), - { display: 'flex', alignItems: 'center', diff --git a/packages/core/src/components/navigation-menu/navigation-menu.tsx b/packages/core/src/components/navigation-menu/navigation-menu.tsx index 2ff5cb83e..2de037757 100644 --- a/packages/core/src/components/navigation-menu/navigation-menu.tsx +++ b/packages/core/src/components/navigation-menu/navigation-menu.tsx @@ -18,6 +18,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import type { LinkVariants, ListVariants } from './navigation-menu.css'; import * as styles from './navigation-menu.css'; @@ -124,16 +125,18 @@ export const NavigationMenuLink = forwardRef + + + ); }, ); diff --git a/packages/core/src/components/pagination/pagination.css.ts b/packages/core/src/components/pagination/pagination.css.ts index 478c6caba..3ce5ce991 100644 --- a/packages/core/src/components/pagination/pagination.css.ts +++ b/packages/core/src/components/pagination/pagination.css.ts @@ -1,6 +1,5 @@ import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -87,7 +86,7 @@ export const currentPage = componentRecipe({ export const button = componentRecipe({ base: [ baseElement, - interaction(), + { selectors: { '&[data-current]': { diff --git a/packages/core/src/components/pagination/pagination.tsx b/packages/core/src/components/pagination/pagination.tsx index d60962eed..3c13ef252 100644 --- a/packages/core/src/components/pagination/pagination.tsx +++ b/packages/core/src/components/pagination/pagination.tsx @@ -21,6 +21,7 @@ import { createSplitProps } from '~/utils/create-split-props'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import * as styles from './pagination.css'; import type { ButtonVariants } from './pagination.css'; @@ -184,7 +185,7 @@ export const PaginationButtonPrimitive = forwardRef< [disabled, current], ); - return useRenderElement({ + const element = useRenderElement({ ref, render, defaultTagName: 'button', @@ -198,6 +199,8 @@ export const PaginationButtonPrimitive = forwardRef< ...props, }, }); + + return {element}; }); PaginationButtonPrimitive.displayName = 'Pagination.ButtonPrimitive'; diff --git a/packages/core/src/components/radio-card/radio-card.css.ts b/packages/core/src/components/radio-card/radio-card.css.ts index 3f170cb93..283b99ce6 100644 --- a/packages/core/src/components/radio-card/radio-card.css.ts +++ b/packages/core/src/components/radio-card/radio-card.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { vars } from '~/styles/themes.css'; @@ -10,7 +9,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const root = componentRecipe({ base: [ - interaction(), { display: 'flex', alignItems: 'center', diff --git a/packages/core/src/components/radio-card/radio-card.tsx b/packages/core/src/components/radio-card/radio-card.tsx index 8e92e5e00..c52b77136 100644 --- a/packages/core/src/components/radio-card/radio-card.tsx +++ b/packages/core/src/components/radio-card/radio-card.tsx @@ -10,6 +10,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import { useRadioGroupContext } from '../radio-group'; import type { RadioCardVariants } from './radio-card.css'; import * as styles from './radio-card.css'; @@ -28,13 +29,15 @@ export const RadioCard = forwardRef((props, ref) = const dataAttrs = createDataAttributes({ invalid }); return ( - + + + ); }); RadioCard.displayName = 'RadioCard'; diff --git a/packages/core/src/components/radio/radio.css.ts b/packages/core/src/components/radio/radio.css.ts index fa356b091..9dee173c6 100644 --- a/packages/core/src/components/radio/radio.css.ts +++ b/packages/core/src/components/radio/radio.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { vars } from '~/styles/themes.css'; @@ -10,7 +9,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const root = componentRecipe({ base: [ - interaction(), { position: 'relative', diff --git a/packages/core/src/components/radio/radio.tsx b/packages/core/src/components/radio/radio.tsx index 40be6fdbc..135265ea0 100644 --- a/packages/core/src/components/radio/radio.tsx +++ b/packages/core/src/components/radio/radio.tsx @@ -12,6 +12,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import { useRadioGroupContext } from '../radio-group'; import type { RootVariants } from './radio.css'; import * as styles from './radio.css'; @@ -43,15 +44,17 @@ export const RadioRoot = forwardRef((props, ref) = }); return ( - - {children} - + + + {children} + + ); }); RadioRoot.displayName = 'Radio.Root'; diff --git a/packages/core/src/components/segmented-control/segmented-control.css.ts b/packages/core/src/components/segmented-control/segmented-control.css.ts index 666871ad1..73b9b3d0a 100644 --- a/packages/core/src/components/segmented-control/segmented-control.css.ts +++ b/packages/core/src/components/segmented-control/segmented-control.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import { foregrounds } from '~/styles/mixins/foreground.css'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -51,7 +50,6 @@ export const root = componentRecipe({ export const item = componentRecipe({ base: [ - interaction(), typography({ style: 'subtitle1' }), foregrounds({ color: 'secondary-200' }), { diff --git a/packages/core/src/components/segmented-control/segmented-control.tsx b/packages/core/src/components/segmented-control/segmented-control.tsx index 730b42370..611e344ea 100644 --- a/packages/core/src/components/segmented-control/segmented-control.tsx +++ b/packages/core/src/components/segmented-control/segmented-control.tsx @@ -19,6 +19,7 @@ import { createSplitProps } from '~/utils/create-split-props'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import * as styles from './segmented-control.css'; import type { RootVariants } from './segmented-control.css'; @@ -222,15 +223,17 @@ export const SegmentedControlItem = forwardRef} - value={value} - disabled={disabled} - nativeButton={true} - className={cn(styles.item({ size }), className)} - {...componentProps} - /> + + } + value={value} + disabled={disabled} + nativeButton={true} + className={cn(styles.item({ size }), className)} + {...componentProps} + /> + ); }, ); diff --git a/packages/core/src/components/select/select.css.ts b/packages/core/src/components/select/select.css.ts index 0b485ebba..1b80bd774 100644 --- a/packages/core/src/components/select/select.css.ts +++ b/packages/core/src/components/select/select.css.ts @@ -2,7 +2,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; import { foregrounds } from '~/styles/mixins/foreground.css'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe, componentStyle } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -12,7 +11,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const trigger = componentRecipe({ base: [ - interaction(), { display: 'flex', alignItems: 'center', @@ -151,7 +149,6 @@ export const popup = componentStyle({ }); export const item = componentStyle([ - interaction({ type: 'roving' }), typography({ style: 'body2' }), { display: 'flex', diff --git a/packages/core/src/components/select/select.tsx b/packages/core/src/components/select/select.tsx index 95401b65b..7bf982c15 100644 --- a/packages/core/src/components/select/select.tsx +++ b/packages/core/src/components/select/select.tsx @@ -15,6 +15,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import * as styles from './select.css'; import type { TriggerVariants } from './select.css'; @@ -64,16 +65,18 @@ export const SelectTriggerPrimitive = forwardRef + + + ); }, ); @@ -280,7 +283,13 @@ export const SelectItemPrimitive = forwardRef + + + ); }, ); diff --git a/packages/core/src/components/switch/switch.css.ts b/packages/core/src/components/switch/switch.css.ts index c814298ee..a1ff0af51 100644 --- a/packages/core/src/components/switch/switch.css.ts +++ b/packages/core/src/components/switch/switch.css.ts @@ -1,13 +1,11 @@ import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { vars } from '~/styles/themes.css'; export const control = componentRecipe({ base: [ - interaction(), { position: 'relative', display: 'flex', diff --git a/packages/core/src/components/switch/switch.tsx b/packages/core/src/components/switch/switch.tsx index 9859ace83..0e7bdc56a 100644 --- a/packages/core/src/components/switch/switch.tsx +++ b/packages/core/src/components/switch/switch.tsx @@ -13,6 +13,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import type { ControlVariants } from './switch.css'; import * as styles from './switch.css'; @@ -47,16 +48,18 @@ export const SwitchRoot = forwardRef((props, ref) return ( - - {children} - + + + {children} + + ); }); diff --git a/packages/core/src/components/tabs/tabs.css.ts b/packages/core/src/components/tabs/tabs.css.ts index 293cfc9a8..19f71a977 100644 --- a/packages/core/src/components/tabs/tabs.css.ts +++ b/packages/core/src/components/tabs/tabs.css.ts @@ -2,7 +2,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; import { foregrounds } from '~/styles/mixins/foreground.css'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -91,7 +90,6 @@ export const list = componentRecipe({ export const button = componentRecipe({ base: [ foregrounds({ color: 'normal-100' }), - interaction({ scale: 'light' }), typography({ style: 'subtitle1' }), { position: 'relative', diff --git a/packages/core/src/components/tabs/tabs.tsx b/packages/core/src/components/tabs/tabs.tsx index a97fe8931..630a4ad9d 100644 --- a/packages/core/src/components/tabs/tabs.tsx +++ b/packages/core/src/components/tabs/tabs.tsx @@ -11,6 +11,7 @@ import { createSplitProps } from '~/utils/create-split-props'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import * as styles from './tabs.css'; import type { ButtonVariants, ListVariants } from './tabs.css'; @@ -119,12 +120,14 @@ export const TabsButton = forwardRef((props, ref) const disabled = disabledProp || rootDisabled; return ( - + + + ); }); TabsButton.displayName = 'Tabs.Button'; diff --git a/packages/core/src/components/text-input/text-input.css.ts b/packages/core/src/components/text-input/text-input.css.ts index 34fa36676..c7c44ffe0 100644 --- a/packages/core/src/components/text-input/text-input.css.ts +++ b/packages/core/src/components/text-input/text-input.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { vars } from '~/styles/themes.css'; @@ -10,8 +9,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const root = componentRecipe({ base: [ - interaction({ type: 'form' }), - { outline: 0, boxShadow: `inset 0 0 0 0.0625rem ${boxShadowColor}`, diff --git a/packages/core/src/components/text-input/text-input.tsx b/packages/core/src/components/text-input/text-input.tsx index 16cc8fce0..d2b6df2c3 100644 --- a/packages/core/src/components/text-input/text-input.tsx +++ b/packages/core/src/components/text-input/text-input.tsx @@ -12,6 +12,7 @@ import { createDataAttributes } from '~/utils/data-attributes'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import type { RootVariants } from './text-input.css'; import * as styles from './text-input.css'; @@ -55,15 +56,17 @@ export const TextInput = forwardRef((props, ref) = const dataAttrs = createDataAttributes({ disabled, readOnly, required, invalid }); return ( - + + + ); }); TextInput.displayName = 'TextInput'; diff --git a/packages/core/src/components/textarea/textarea.css.ts b/packages/core/src/components/textarea/textarea.css.ts index 75cd3b53c..c5cde7880 100644 --- a/packages/core/src/components/textarea/textarea.css.ts +++ b/packages/core/src/components/textarea/textarea.css.ts @@ -1,7 +1,6 @@ import { createVar } from '@vanilla-extract/css'; import type { RecipeVariants } from '@vanilla-extract/recipes'; -import { interaction } from '~/styles/mixins/interactions.css'; import { componentRecipe } from '~/styles/mixins/layer-style.css'; import { when } from '~/styles/mixins/logical-states'; import { typography } from '~/styles/mixins/typography.css'; @@ -11,8 +10,6 @@ const boxShadowColor = createVar('box-shadow-color'); export const textarea = componentRecipe({ base: [ - interaction({ type: 'form' }), - { boxShadow: `inset 0 0 0 0.0625rem ${boxShadowColor}`, borderRadius: vars.size.borderRadius['300'], diff --git a/packages/core/src/components/textarea/textarea.tsx b/packages/core/src/components/textarea/textarea.tsx index f15e38d64..842730611 100644 --- a/packages/core/src/components/textarea/textarea.tsx +++ b/packages/core/src/components/textarea/textarea.tsx @@ -13,6 +13,7 @@ import { createSplitProps } from '~/utils/create-split-props'; import { resolveStyles } from '~/utils/resolve-styles'; import type { VaporUIComponentProps } from '~/utils/types'; +import { Interaction } from '../interaction'; import type { TextareaVariants } from './textarea.css'; import * as styles from './textarea.css'; @@ -66,7 +67,7 @@ export const Textarea = forwardRef((props, ref) => [disabled, readOnly, required, invalid], ); - return useRenderElement({ + const element = useRenderElement({ ref: composedRef, state, render: render || } />, @@ -78,6 +79,8 @@ export const Textarea = forwardRef((props, ref) => ...otherProps, }, }); + + return {element}; }); Textarea.displayName = 'Textarea'; From 0f0991720cdfc25aff53a8d189f9fea32b614411 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Mon, 15 Jun 2026 08:29:31 +0900 Subject: [PATCH 18/25] update snapshot --- .../interaction--test-bed-1-chrome-darwin-.png | Bin 0 -> 13018 bytes .../interaction--test-bed-1-edge-darwin-.png | Bin 0 -> 13018 bytes .../interaction--test-bed-1-firefox-darwin-.png | Bin 0 -> 28718 bytes .../interaction--test-bed-1-safari-darwin-.png | Bin 0 -> 28316 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/core/__tests__/screenshots/interaction--test-bed-1-chrome-darwin-.png create mode 100644 packages/core/__tests__/screenshots/interaction--test-bed-1-edge-darwin-.png create mode 100644 packages/core/__tests__/screenshots/interaction--test-bed-1-firefox-darwin-.png create mode 100644 packages/core/__tests__/screenshots/interaction--test-bed-1-safari-darwin-.png diff --git a/packages/core/__tests__/screenshots/interaction--test-bed-1-chrome-darwin-.png b/packages/core/__tests__/screenshots/interaction--test-bed-1-chrome-darwin-.png new file mode 100644 index 0000000000000000000000000000000000000000..782b037b3128c61eafd705f54c421d37047f718d GIT binary patch literal 13018 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 Qub?jKTt1)mcdK9i3zRTjNdN!< literal 0 HcmV?d00001 diff --git a/packages/core/__tests__/screenshots/interaction--test-bed-1-edge-darwin-.png b/packages/core/__tests__/screenshots/interaction--test-bed-1-edge-darwin-.png new file mode 100644 index 0000000000000000000000000000000000000000..782b037b3128c61eafd705f54c421d37047f718d GIT binary patch literal 13018 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 Qub?jKTt1)mcdK9i3zRTjNdN!< literal 0 HcmV?d00001 diff --git a/packages/core/__tests__/screenshots/interaction--test-bed-1-firefox-darwin-.png b/packages/core/__tests__/screenshots/interaction--test-bed-1-firefox-darwin-.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8a072507c0afe2c25f61a618a051f46b3e2922 GIT binary patch literal 28718 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 Date: Tue, 16 Jun 2026 09:01:31 +0900 Subject: [PATCH 19/25] remove docs --- .../plans/2026-06-12-interaction-component.md | 974 ------------------ ...2026-06-12-interaction-component-design.md | 272 ----- 2 files changed, 1246 deletions(-) delete mode 100644 docs/superpowers/plans/2026-06-12-interaction-component.md delete mode 100644 docs/superpowers/specs/2026-06-12-interaction-component-design.md diff --git a/docs/superpowers/plans/2026-06-12-interaction-component.md b/docs/superpowers/plans/2026-06-12-interaction-component.md deleted file mode 100644 index 434afcf4d..000000000 --- a/docs/superpowers/plans/2026-06-12-interaction-component.md +++ /dev/null @@ -1,974 +0,0 @@ -# Interaction Component Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Create `` Slot-pattern component in `packages/core` that applies interaction styling (hover/focus/active/roving overlays) to its single child via className merging. - -**Architecture:** Vanilla-extract recipe duplicated into the component folder (option C from spec). Slot pattern via `React.cloneElement` + `Children.only` — no wrapper DOM. Two variant props: `scale` ('normal' | 'light'), `type` ('default' | 'form' | 'roving'). Existing `~/styles/mixins/interactions.css.ts` mixin is **not** modified — the 16 components currently composing it continue to work unchanged. - -**Tech Stack:** React 18, TypeScript, vanilla-extract (`@vanilla-extract/css`, `@vanilla-extract/recipes`, `@vanilla-extract/css-utils`), Vitest, `@testing-library/react`, `vitest-axe`, Storybook (`@storybook/react-vite`). - -**Spec:** `docs/superpowers/specs/2026-06-12-interaction-component-design.md` - -**Working directory:** `packages/core` (run all commands from there unless noted). - -**Commit prefix:** `feat(Interaction):` for new code; `test(Interaction):` for test-only commits; `docs(Interaction):` for Storybook. - ---- - -## Task 1: Create the recipe file - -**Files:** -- Create: `packages/core/src/components/interaction/interaction.css.ts` - -This file holds the vanilla-extract recipe. No tests — recipe correctness is verified visually via Storybook and indirectly via the component test (class string present). We duplicate the recipe from `src/styles/mixins/interactions.css.ts` as Option C; the mixin is left untouched. - -- [ ] **Step 1: Create the recipe file** - -Write `packages/core/src/components/interaction/interaction.css.ts`: - -```ts -import { createVar } from '@vanilla-extract/css'; -import { calc } from '@vanilla-extract/css-utils'; -import type { RecipeVariants } from '@vanilla-extract/recipes'; - -import { componentRecipe } from '~/styles/mixins/layer-style.css'; -import { vars } from '~/styles/themes.css'; - -const ratio = createVar('opacity-ratio'); - -export const root = componentRecipe({ - base: { - position: 'relative', - vars: { [ratio]: '0.08' }, - selectors: { - '&::before': { - position: 'absolute', - top: 0, - left: 0, - transition: 'opacity 150ms ease', - opacity: 0, - border: 'none', - borderRadius: 'inherit', - backgroundColor: vars.color.gray[900], - pointerEvents: 'none', - width: '100%', - height: '100%', - content: '', - }, - '&:focus': { outline: 'none' }, - '&:focus-visible': { outline: 'none' }, - }, - }, - defaultVariants: { - scale: 'normal', - type: 'default', - }, - variants: { - scale: { - normal: {}, - light: { vars: { [ratio]: '0.04' } }, - }, - type: { - default: { - selectors: { - '&:active::before': { opacity: calc.multiply(ratio, 2) }, - '&:focus-visible': { - outline: `2px solid ${vars.color.foreground.normal[200]}`, - outlineOffset: '2px', - }, - }, - '@media': { - '(hover: hover)': { - selectors: { - '&:hover::before': { opacity: calc.multiply(ratio, 1) }, - '&:active::before': { opacity: calc.multiply(ratio, 2) }, - }, - }, - }, - }, - form: { - transition: 'box-shadow 150ms cubic-bezier(.4,0,.2,1)', - selectors: { - '&:focus': { - boxShadow: `inset 0 0 0 0.0625rem ${vars.color.border.primary}`, - }, - }, - '@media': { - '(hover: hover)': { - selectors: { - '&:hover:not(:focus)': { - boxShadow: `inset 0 0 0 0.0625rem color-mix(in srgb, ${vars.color.gray[900]} 32%, transparent)`, - }, - }, - }, - }, - }, - roving: { - selectors: { - '&[data-highlighted]::before': { opacity: 0.08 }, - '&[data-highlighted]:active::before': { opacity: 0.16 }, - }, - }, - }, - }, -}); - -export type InteractionVariants = NonNullable>; -``` - -- [ ] **Step 2: Typecheck** - -Run from `packages/core`: - -```bash -pnpm typecheck -``` - -Expected: passes. The recipe file is now reachable from `src/` but not yet imported anywhere; tsc compiles it without errors. - -- [ ] **Step 3: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.css.ts -git commit -m "feat(Interaction): add interaction recipe" -``` - ---- - -## Task 2: Component skeleton + first test (renders child as single DOM, no wrapper) - -**Files:** -- Create: `packages/core/src/components/interaction/interaction.test.tsx` -- Create: `packages/core/src/components/interaction/interaction.tsx` - -TDD: write the test first, watch it fail, then implement. - -Vitest in this package uses `vitest/globals` (see `packages/core/tsconfig.json` — `"types": [..., "vitest/globals", ...]`), so `describe`, `it`, `expect`, `vi` are available without import. Tests use `@testing-library/react` `render`. - -- [ ] **Step 1: Write the failing test** - -Create `packages/core/src/components/interaction/interaction.test.tsx`: - -```tsx -import { render } from '@testing-library/react'; - -import { Interaction } from './interaction'; - -describe('Interaction', () => { - it('renders the single child element with no wrapper DOM', () => { - const { container } = render( - - - , - ); - - expect(container.children).toHaveLength(1); - expect(container.firstElementChild?.tagName).toBe('BUTTON'); - expect(container.firstElementChild?.getAttribute('data-testid')).toBe('child'); - }); -}); -``` - -- [ ] **Step 2: Run the test to verify it fails** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: FAIL — `Cannot find module './interaction'` (or similar resolution error). - -- [ ] **Step 3: Write minimal component to make it pass** - -Create `packages/core/src/components/interaction/interaction.tsx`: - -```tsx -import { Children, cloneElement, isValidElement } from 'react'; -import type { ReactNode } from 'react'; - -interface InteractionProps { - children: ReactNode; -} - -const Interaction = (props: InteractionProps) => { - const child = Children.only(props.children); - - if (!isValidElement<{ className?: string }>(child)) { - throw new Error(' child must be a single React element'); - } - - return cloneElement(child); -}; - -Interaction.displayName = 'Interaction'; - -export { Interaction }; -export type { InteractionProps }; -``` - -- [ ] **Step 4: Run the test to verify it passes** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (1 test). - -- [ ] **Step 5: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx -git commit -m "feat(Interaction): add component skeleton with Slot pattern" -``` - ---- - -## Task 3: Apply recipe className to the child - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` -- Modify: `packages/core/src/components/interaction/interaction.tsx` - -Now `` must call the recipe and merge the resulting class onto the child. - -- [ ] **Step 1: Write the failing test** - -Append to `packages/core/src/components/interaction/interaction.test.tsx` inside the existing `describe('Interaction', ...)` block: - -```tsx -import * as styles from './interaction.css'; - -it('applies the interaction recipe className onto the child', () => { - const { container } = render( - - - , - ); - - const expectedClass = styles.root({}); - expect(container.firstElementChild?.className.split(' ')).toEqual( - expect.arrayContaining(expectedClass.split(' ').filter(Boolean)), - ); -}); -``` - -Place the `import * as styles from './interaction.css';` line with the other imports at the top of the test file. - -- [ ] **Step 2: Run the test to verify it fails** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: FAIL — the assertion finds no recipe classes on the child. - -- [ ] **Step 3: Update the component** - -Replace the contents of `packages/core/src/components/interaction/interaction.tsx`: - -```tsx -import { Children, cloneElement, isValidElement } from 'react'; -import type { ReactNode } from 'react'; - -import { cn } from '~/utils/cn'; - -import * as styles from './interaction.css'; - -interface InteractionProps { - children: ReactNode; -} - -const Interaction = (props: InteractionProps) => { - const child = Children.only(props.children); - - if (!isValidElement<{ className?: string }>(child)) { - throw new Error(' child must be a single React element'); - } - - return cloneElement(child, { - className: cn(styles.root({}), child.props.className), - }); -}; - -Interaction.displayName = 'Interaction'; - -export { Interaction }; -export type { InteractionProps }; -``` - -- [ ] **Step 4: Run tests to verify both pass** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (2 tests). - -- [ ] **Step 5: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx -git commit -m "feat(Interaction): apply recipe className to child" -``` - ---- - -## Task 4: Preserve the child's existing className - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` - -The component already merges via `cn(styles.root({}), child.props.className)`. Add a test that locks the behavior in. - -- [ ] **Step 1: Write the failing test** - -Append inside `describe('Interaction', ...)`: - -```tsx -it('preserves the child existing className', () => { - const { container } = render( - - - , - ); - - const classList = container.firstElementChild?.className.split(' ') ?? []; - expect(classList).toContain('my-child-class'); -}); -``` - -- [ ] **Step 2: Run tests to verify the new test passes** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (3 tests). The implementation from Task 3 already supports this — the test locks it in. - -- [ ] **Step 3: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx -git commit -m "test(Interaction): preserve child className when merging" -``` - ---- - -## Task 5: Accept and merge external `className` prop - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` -- Modify: `packages/core/src/components/interaction/interaction.tsx` - -`` itself takes a `className` prop, which is merged between the recipe class and the child's own class. - -- [ ] **Step 1: Write the failing test** - -Append inside `describe('Interaction', ...)`: - -```tsx -it('merges external className prop with recipe and child classes', () => { - const { container } = render( - - - , - ); - - const classList = container.firstElementChild?.className.split(' ') ?? []; - expect(classList).toContain('external-class'); - expect(classList).toContain('child-class'); -}); -``` - -- [ ] **Step 2: Run the test to verify it fails** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: FAIL — `external-class` is not present (the current component does not read `className`). - -- [ ] **Step 3: Update the component** - -Replace the contents of `packages/core/src/components/interaction/interaction.tsx`: - -```tsx -import { Children, cloneElement, isValidElement } from 'react'; -import type { ReactNode } from 'react'; - -import { cn } from '~/utils/cn'; - -import * as styles from './interaction.css'; - -interface InteractionProps { - className?: string; - children: ReactNode; -} - -const Interaction = (props: InteractionProps) => { - const { className, children } = props; - const child = Children.only(children); - - if (!isValidElement<{ className?: string }>(child)) { - throw new Error(' child must be a single React element'); - } - - return cloneElement(child, { - className: cn(styles.root({}), className, child.props.className), - }); -}; - -Interaction.displayName = 'Interaction'; - -export { Interaction }; -export type { InteractionProps }; -``` - -- [ ] **Step 4: Run tests to verify all pass** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (4 tests). - -- [ ] **Step 5: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx -git commit -m "feat(Interaction): merge external className prop" -``` - ---- - -## Task 6: Accept `scale` and `type` variant props - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` -- Modify: `packages/core/src/components/interaction/interaction.tsx` - -Variant props feed into `styles.root({ scale, type })`. Different variant inputs must produce different recipe class output on the child. - -- [ ] **Step 1: Write the failing test** - -Append inside `describe('Interaction', ...)`: - -```tsx -it('applies variant props through to the recipe', () => { - const { container: defaultContainer } = render( - - - , - ); - - const { container: lightFormContainer } = render( - - - , - ); - - expect(defaultContainer.firstElementChild?.className).not.toBe( - lightFormContainer.firstElementChild?.className, - ); - - const lightFormExpected = styles.root({ scale: 'light', type: 'form' }); - const lightFormActual = lightFormContainer.firstElementChild?.className.split(' ') ?? []; - expect(lightFormActual).toEqual( - expect.arrayContaining(lightFormExpected.split(' ').filter(Boolean)), - ); -}); -``` - -- [ ] **Step 2: Run the test to verify it fails** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: FAIL — the component ignores `scale` / `type`. - -- [ ] **Step 3: Update the component** - -Replace the contents of `packages/core/src/components/interaction/interaction.tsx`: - -```tsx -import { Children, cloneElement, isValidElement } from 'react'; -import type { ReactNode } from 'react'; - -import { cn } from '~/utils/cn'; -import { createSplitProps } from '~/utils/create-split-props'; - -import * as styles from './interaction.css'; -import type { InteractionVariants } from './interaction.css'; - -interface InteractionProps extends InteractionVariants { - className?: string; - children: ReactNode; -} - -const Interaction = (props: InteractionProps) => { - const [variantProps, { className, children }] = createSplitProps()( - props, - ['scale', 'type'], - ); - - const child = Children.only(children); - - if (!isValidElement<{ className?: string }>(child)) { - throw new Error(' child must be a single React element'); - } - - return cloneElement(child, { - className: cn(styles.root(variantProps), className, child.props.className), - }); -}; - -Interaction.displayName = 'Interaction'; - -export { Interaction }; -export type { InteractionProps }; -``` - -- [ ] **Step 4: Run tests to verify all pass** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (5 tests). - -- [ ] **Step 5: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx src/components/interaction/interaction.tsx -git commit -m "feat(Interaction): wire scale and type variant props" -``` - ---- - -## Task 7: Error cases — multiple children & non-element child - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` - -`Children.only` already throws when there are zero or multiple children. `isValidElement` throws our message when the single child is a string/number/null. Lock both with tests. - -- [ ] **Step 1: Write the failing tests** - -Append inside `describe('Interaction', ...)`: - -```tsx -it('throws when given multiple children', () => { - const previousError = console.error; - console.error = vi.fn(); - - expect(() => - render( - - - - , - ), - ).toThrow(); - - console.error = previousError; -}); - -it('throws with a clear message when child is not a React element', () => { - const previousError = console.error; - console.error = vi.fn(); - - expect(() => render({'just a string' as unknown as never})).toThrow( - ' child must be a single React element', - ); - - console.error = previousError; -}); -``` - -The `console.error = vi.fn()` lines silence React's error-boundary noise so the test output stays clean. They are restored afterward. - -- [ ] **Step 2: Run the tests** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (7 tests). Both error cases are already enforced by the existing `Children.only` + `isValidElement` checks in the component — these tests lock the contract. - -- [ ] **Step 3: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx -git commit -m "test(Interaction): cover multi-child and non-element error cases" -``` - ---- - -## Task 8: Ref forwarding through the child - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` - -`cloneElement` preserves the child's ref. Confirm a `ref` attached to the child still resolves to the underlying DOM node. - -- [ ] **Step 1: Write the test** - -Append inside `describe('Interaction', ...)`: - -```tsx -import { createRef } from 'react'; - -it('preserves the child ref', () => { - const ref = createRef(); - - render( - - - , - ); - - expect(ref.current).toBeInstanceOf(HTMLButtonElement); -}); -``` - -Add `createRef` to the existing `import { ... } from 'react'` if not already present. (If there is no existing react import, add the new import line at the top of the test file.) - -- [ ] **Step 2: Run the tests** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (8 tests). The behavior is provided by `cloneElement` — this test locks it in. - -- [ ] **Step 3: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx -git commit -m "test(Interaction): verify ref forwarding through cloneElement" -``` - ---- - -## Task 9: a11y smoke check - -**Files:** -- Modify: `packages/core/src/components/interaction/interaction.test.tsx` - -Mirror the pattern used in `button.test.tsx`: run `vitest-axe` over the rendered output to confirm wrapping a button does not introduce a11y violations. - -- [ ] **Step 1: Write the test** - -Add the axe import near the top of the test file (with the other imports): - -```tsx -import { axe } from 'vitest-axe'; -``` - -Append inside `describe('Interaction', ...)`: - -```tsx -it('has no a11y violations when wrapping a button', async () => { - const rendered = render( - - - , - ); - - const result = await axe(rendered.container); - expect(result).toHaveNoViolations(); -}); -``` - -- [ ] **Step 2: Run the tests** - -```bash -pnpm test --run src/components/interaction/interaction.test.tsx -``` - -Expected: PASS (9 tests). - -- [ ] **Step 3: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.test.tsx -git commit -m "test(Interaction): add vitest-axe smoke check" -``` - ---- - -## Task 10: `index.ts` re-export - -**Files:** -- Create: `packages/core/src/components/interaction/index.ts` - -`` is a standalone (non-compound) component. Per the project conventions in `packages/core/CLAUDE.md` §5.3.2, the entrypoint re-exports the implementation directly. Do **not** create `index.parts.ts`. Do **not** modify `src/index.ts` in this PR (per spec §3 non-goals: "Public export from `@vapor-ui/core` root entrypoint is a follow-up decision"). - -- [ ] **Step 1: Create the index file** - -Write `packages/core/src/components/interaction/index.ts`: - -```ts -export * from './interaction'; -``` - -- [ ] **Step 2: Typecheck & lint** - -```bash -pnpm typecheck -pnpm lint -``` - -Expected: both pass. - -- [ ] **Step 3: Commit** - -```bash -cd packages/core -git add src/components/interaction/index.ts -git commit -m "feat(Interaction): add component entrypoint" -``` - ---- - -## Task 11: Storybook stories - -**Files:** -- Create: `packages/core/src/components/interaction/interaction.stories.tsx` - -Stories use `@storybook/react-vite` and `autodocs` (default for the package — see `button.stories.tsx`). Five stories per spec §10. We do **not** import other Vapor components in the stories — to avoid the documented "double-styling" caveat (spec §11), we wrap plain HTML elements. - -- [ ] **Step 1: Write the stories file** - -Create `packages/core/src/components/interaction/interaction.stories.tsx`: - -```tsx -import type { CSSProperties } from 'react'; - -import type { Meta, StoryObj } from '@storybook/react-vite'; - -import { Interaction } from './interaction'; - -export default { - title: 'Interaction', - component: Interaction, - argTypes: { - scale: { control: 'inline-radio', options: ['normal', 'light'] }, - type: { control: 'inline-radio', options: ['default', 'form', 'roving'] }, - }, -} as Meta; - -type Story = StoryObj; - -const buttonStyle: CSSProperties = { - padding: '0.5rem 1rem', - border: '1px solid #ccc', - borderRadius: '0.375rem', - background: '#fff', - cursor: 'pointer', -}; - -const inputStyle: CSSProperties = { - padding: '0.5rem 0.75rem', - border: '1px solid #ccc', - borderRadius: '0.375rem', - outline: 'none', -}; - -const itemStyle: CSSProperties = { - padding: '0.5rem 0.75rem', - borderRadius: '0.375rem', - userSelect: 'none', - cursor: 'pointer', -}; - -export const Default: Story = { - render: (args) => ( - - - - ), -}; - -export const ScaleLight: Story = { - args: { scale: 'light' }, - render: (args) => ( - - - - ), -}; - -export const TypeForm: Story = { - args: { type: 'form' }, - render: (args) => ( - - - - ), -}; - -export const TypeRoving: Story = { - args: { type: 'roving' }, - render: (args) => ( -
- -
- Highlighted item -
-
- -
Regular item
-
-
- ), -}; - -export const TestBed: Story = { - render: () => ( -
- - - - - - - - - - -
- roving (highlighted) -
-
-
- ), -}; -``` - -- [ ] **Step 2: Typecheck** - -```bash -pnpm typecheck -``` - -Expected: passes. - -- [ ] **Step 3: Run the full package test suite** - -```bash -pnpm test -``` - -Expected: passes (no regressions in any other component, plus 9 new tests). - -- [ ] **Step 4: Lint** - -```bash -pnpm lint -``` - -Expected: passes. - -- [ ] **Step 5: Commit** - -```bash -cd packages/core -git add src/components/interaction/interaction.stories.tsx -git commit -m "docs(Interaction): add Storybook stories" -``` - ---- - -## Task 12: Final verification - -**Files:** none (verification only). - -- [ ] **Step 1: Run typecheck, lint, and tests from the package root** - -```bash -cd packages/core -pnpm typecheck && pnpm lint && pnpm test -``` - -Expected: all three pass. - -- [ ] **Step 2: Confirm the existing `interactions.css.ts` mixin is untouched** - -```bash -cd /Users/goorm/01_works/vapor -git diff --name-only main -- packages/core/src/styles/mixins/interactions.css.ts -``` - -Expected: no output (file unchanged on this branch). - -- [ ] **Step 3: Confirm the 16 existing consumers are untouched** - -```bash -cd /Users/goorm/01_works/vapor -git diff --name-only main -- 'packages/core/src/components/**/*.css.ts' | grep -v interaction/interaction.css.ts -``` - -Expected: no output. (Only the new `interaction/interaction.css.ts` should appear in css.ts diffs against main.) - -- [ ] **Step 4: Confirm `src/index.ts` is untouched** - -```bash -cd /Users/goorm/01_works/vapor -git diff --name-only main -- packages/core/src/index.ts -``` - -Expected: no output. The component is added under `src/components/interaction/` but is **not** re-exported from the package root (per spec §3 non-goals). - -- [ ] **Step 5: Confirm the final file set** - -```bash -ls packages/core/src/components/interaction/ -``` - -Expected output (exactly these five files): - -``` -index.ts -interaction.css.ts -interaction.stories.tsx -interaction.test.tsx -interaction.tsx -``` - ---- - -## Done criteria - -- 9 passing tests in `interaction.test.tsx` covering: single child no-wrap, recipe class merge, child className preserved, external className merged, variant pass-through, multi-child throw, non-element child throw with message, ref forwarding, axe a11y. -- `pnpm typecheck`, `pnpm lint`, `pnpm test` all pass from `packages/core`. -- 5 Storybook stories visible under `Interaction` title. -- Existing `~/styles/mixins/interactions.css.ts` and 16 consumer recipes unchanged. -- `src/index.ts` unchanged (no public re-export in this PR). -- Each task committed with the conventional-commit prefix shown in its commit step. diff --git a/docs/superpowers/specs/2026-06-12-interaction-component-design.md b/docs/superpowers/specs/2026-06-12-interaction-component-design.md deleted file mode 100644 index 25f6d2632..000000000 --- a/docs/superpowers/specs/2026-06-12-interaction-component-design.md +++ /dev/null @@ -1,272 +0,0 @@ -# Interaction Component — Design - -- Status: Approved (brainstorming) -- Date: 2026-06-12 -- Scope: `packages/core` -- Author: noah.choi - -## 1. Background - -`packages/core` currently styles interactive components (button, checkbox, switch, tabs, and 13 others — 16 total) by composing the vanilla-extract recipe `interaction()` exported from `src/styles/mixins/interactions.css.ts` into each component's own recipe: - -```ts -// button.css.ts (current) -export const root = componentRecipe({ - base: [interaction(), { /* button-specific */ }], - // ... -}); -``` - -This works but couples interaction styling logic to every component recipe. The goal is to lift interaction styling into a dedicated `` React component that wraps any element and applies the same styles via class merging, with no extra DOM and no behavioral logic. - -## 2. Goals - -- Provide an `` component that adds interaction styles to its direct child. -- Mirror the variants currently accepted by the `interaction()` recipe (`scale`, `type`). -- Produce the same rendered DOM as the existing recipe-composition approach (no wrapping element). -- Keep the component free of any behavior — it only merges a className onto the child. - -## 3. Non-Goals - -- Migrating the 16 existing components to use ``. This spec creates the component only; component migration is a follow-up PR. -- Removing or modifying the existing `~/styles/mixins/interactions.css.ts` mixin. It stays as-is so the 16 existing components keep working. -- Public export from `@vapor-ui/core` root entrypoint. The component is added under `src/components/interaction/` but is **not** re-exported from `src/index.ts` in this PR. Public exposure is a follow-up decision. -- `asChild` / `render` prop patterns. -- Forwarding ref through `` itself. - -## 4. Approach - -Adopt the Slot pattern (Radix-style `cloneElement`): - -- `` accepts exactly one React element child. -- It calls the recipe with variant props (`scale`, `type`) to obtain a class name string. -- It merges that class name with the child's existing `className` and any external `className` passed to ``, then returns `cloneElement(child, { className: merged })`. -- No new DOM element is rendered. The child's ref, props, children, and event handlers are untouched. - -The recipe is **duplicated** into the new component folder (`interaction.css.ts`) rather than reused from the existing mixin. The existing mixin stays in place to support unmigrated components. SSOT drift risk is accepted as temporary; the existing mixin will be deleted when the 16 components are migrated in follow-up PRs, at which point the component recipe becomes the SSOT. - -## 5. File Structure - -``` -packages/core/src/components/interaction/ -├── interaction.tsx # component -├── interaction.css.ts # vanilla-extract recipe (duplicate of existing mixin) -├── interaction.test.tsx # Vitest + @testing-library/react -├── interaction.stories.tsx # Storybook (autodocs) -└── index.ts # re-export: export * from './interaction' -``` - -No `index.parts.ts` — `` is a standalone component, not compound. - -`src/index.ts` is **not** updated in this PR. - -## 6. Recipe (`interaction.css.ts`) - -Identical shape to the existing mixin at `src/styles/mixins/interactions.css.ts`. Exported as `root` to match the per-component recipe naming convention used elsewhere (e.g. `button.css.ts` exports `root`). - -```ts -import { createVar } from '@vanilla-extract/css'; -import { calc } from '@vanilla-extract/css-utils'; -import type { RecipeVariants } from '@vanilla-extract/recipes'; - -import { componentRecipe } from '~/styles/mixins/layer-style.css'; -import { vars } from '~/styles/themes.css'; - -const ratio = createVar('opacity-ratio'); - -export const root = componentRecipe({ - base: { - position: 'relative', - vars: { [ratio]: '0.08' }, - selectors: { - '&::before': { - position: 'absolute', - top: 0, - left: 0, - transition: 'opacity 150ms ease', - opacity: 0, - border: 'none', - borderRadius: 'inherit', - backgroundColor: vars.color.gray[900], - pointerEvents: 'none', - width: '100%', - height: '100%', - content: '', - }, - '&:focus': { outline: 'none' }, - '&:focus-visible': { outline: 'none' }, - }, - }, - defaultVariants: { - scale: 'normal', - type: 'default', - }, - variants: { - scale: { - normal: {}, - light: { vars: { [ratio]: '0.04' } }, - }, - type: { - default: { - selectors: { - '&:active::before': { opacity: calc.multiply(ratio, 2) }, - '&:focus-visible': { - outline: `2px solid ${vars.color.foreground.normal[200]}`, - outlineOffset: '2px', - }, - }, - '@media': { - '(hover: hover)': { - selectors: { - '&:hover::before': { opacity: calc.multiply(ratio, 1) }, - '&:active::before': { opacity: calc.multiply(ratio, 2) }, - }, - }, - }, - }, - form: { - transition: 'box-shadow 150ms cubic-bezier(.4,0,.2,1)', - selectors: { - '&:focus': { - boxShadow: `inset 0 0 0 0.0625rem ${vars.color.border.primary}`, - }, - }, - '@media': { - '(hover: hover)': { - selectors: { - '&:hover:not(:focus)': { - boxShadow: `inset 0 0 0 0.0625rem color-mix(in srgb, ${vars.color.gray[900]} 32%, transparent)`, - }, - }, - }, - }, - }, - roving: { - selectors: { - '&[data-highlighted]::before': { opacity: 0.08 }, - '&[data-highlighted]:active::before': { opacity: 0.16 }, - }, - }, - }, - }, -}); - -export type InteractionVariants = NonNullable>; -``` - -The `ratio` CSS variable is intentionally **not** exposed as a prop. It stays an internal implementation detail of the recipe, controlled by the `scale` variant. - -## 7. Component (`interaction.tsx`) - -```tsx -import { Children, cloneElement, isValidElement } from 'react'; -import type { ReactNode } from 'react'; - -import cn from '~/utils/cn'; -import createSplitProps from '~/utils/create-split-props'; - -import * as styles from './interaction.css'; -import type { InteractionVariants } from './interaction.css'; - -interface InteractionProps extends InteractionVariants { - className?: string; - children: ReactNode; -} - -const Interaction = (props: InteractionProps) => { - const [variantProps, { className, children }] = createSplitProps()( - props, - ['scale', 'type'], - ); - - const child = Children.only(children); - - if (!isValidElement<{ className?: string }>(child)) { - throw new Error(' child must be a single React element'); - } - - return cloneElement(child, { - className: cn(styles.root(variantProps), className, child.props.className), - }); -}; - -Interaction.displayName = 'Interaction'; - -export { Interaction }; -export type { InteractionProps }; -``` - -### 7.1 Behavior Contract - -- **Props accepted**: `scale`, `type` (recipe variants), `className`, `children`. Nothing else. -- **DOM output**: exactly one element — the child, with className merged. No wrapper. -- **className merge order** (later entries cascade-win when CSS specificity ties): - 1. `styles.root({ scale, type })` — interaction styles - 2. External `className` passed to `` - 3. `child.props.className` — child's own classes (intentionally last so component-specific styles can override interaction defaults if needed) -- **Ref**: not handled by ``. The child's own ref (if any) is preserved by `cloneElement`. -- **Other props**: not merged onto the child. Event handlers, `style`, `data-*`, `aria-*` belong on the child element directly. - -### 7.2 Error / Edge Cases - -- `Children.only(children)` throws if `children` is `0`, multiple, or a fragment with multiple roots. -- `isValidElement` check throws a clear error if the single child is a string, number, null, or other non-element. -- If the child does not accept `className` as a prop (e.g., a React component that ignores it), the recipe class is still passed but has no visual effect. This is the consumer's responsibility — the same constraint as Radix `Slot`. Documented in Storybook. - -## 8. Public API - -```ts -// Usage - - - - - - - - - - - -``` - -Defaults: `scale="normal"`, `type="default"` (inherited from the recipe's `defaultVariants`). - -## 9. Testing (`interaction.test.tsx`) - -Vitest + `@testing-library/react`. Cases: - -1. Renders the child as the only DOM element — no wrapper. -2. Merges recipe className with the child's existing className. -3. Merges external `className` prop with the child's className. -4. Applies `scale` and `type` variants — assert recipe class string is present on the child. -5. Default variants applied when no `scale` / `type` given. -6. Throws when `children` is empty, multiple, or a non-element (string). -7. Ref forwarding: a child rendered with `forwardRef` receives the ref (the ref the consumer attached to the child, not to ``). -8. `vitest-axe` smoke check on a button child to confirm interaction styles do not violate basic a11y. - -## 10. Storybook (`interaction.stories.tsx`) - -`autodocs` enabled. Stories: - -1. **Default** — over a plain ` + , ); + const result = await axe(rendered.container); - expect(container.children).toHaveLength(1); - expect(container.firstElementChild?.tagName).toBe('BUTTON'); - expect(container.firstElementChild?.getAttribute('data-testid')).toBe('child'); + expect(result).toHaveNoViolations(); }); - it('applies the interaction recipe className onto the child', () => { - const { container } = render( - - + it('should forward refs correctly', () => { + const ref = createRef(); + render( + + , ); - const expectedClass = styles.root({}); - expect(container.firstElementChild?.className.split(' ')).toEqual( - expect.arrayContaining(expectedClass.split(' ').filter(Boolean)), - ); + expect(ref.current).toBeInstanceOf(HTMLDivElement); }); - it('preserves the child existing className', () => { - const { container } = render( - - + it('should apply custom class names', () => { + const customClassName = 'custom-interaction'; + const rendered = render( + + , ); + const interactionElement = rendered.queryByTestId('interaction'); - const classList = container.firstElementChild?.className.split(' ') ?? []; - expect(classList).toContain('my-child-class'); + expect(interactionElement).toHaveClass(customClassName); }); - it('applies external className prop onto the overlay and preserves the child class on the root', () => { - const { container } = render( - - + it('should render children correctly', () => { + const rendered = render( + + , ); + const childElement = rendered.getByText('Child Element'); + const interactionElement = rendered.queryByTestId('interaction'); - const root = container.firstElementChild; - const overlay = root?.querySelector('[data-vapor-interaction]'); - - const rootClasses = root?.className.split(' ') ?? []; - const overlayClasses = overlay?.className.split(' ') ?? []; - - expect(rootClasses).toContain('child-class'); - expect(rootClasses).not.toContain('external-class'); - expect(overlayClasses).toContain('external-class'); + expect(childElement).toBeInTheDocument(); + expect(interactionElement).toBeInTheDocument(); }); - it('applies variant props through to the recipe', () => { - const { container: defaultContainer } = render( - - - , - ); - - const { container: lightFormContainer } = render( - - - , - ); - - expect(defaultContainer.firstElementChild?.className).not.toBe( - lightFormContainer.firstElementChild?.className, - ); - - const lightFormExpected = styles.root({ scale: 'light', type: 'form' }); - const lightFormActual = lightFormContainer.firstElementChild?.className.split(' ') ?? []; - expect(lightFormActual).toEqual( - expect.arrayContaining(lightFormExpected.split(' ').filter(Boolean)), - ); - }); - - it('throws when given multiple children', () => { - const previousError = console.error; - console.error = vi.fn(); - - expect(() => - render( - - - + describe('prop: type', () => { + it('should not render children when type is form', () => { + const rendered = render( + + , - ), - ).toThrow(); - - console.error = previousError; - }); - - it('throws when child is not a React element', () => { - const previousError = console.error; - console.error = vi.fn(); - - expect(() => - render({'just a string' as unknown as never}), - ).toThrow(); - - console.error = previousError; - }); - - it('appends a presentational overlay as the last child', () => { - const { container } = render( - - - , - ); - - const button = container.firstElementChild; - const overlay = button?.lastElementChild; - - expect(overlay?.tagName).toBe('DIV'); - expect(overlay?.getAttribute('role')).toBe('presentation'); - expect(overlay?.getAttribute('aria-hidden')).toBe('true'); - expect(overlay?.hasAttribute('data-vapor-interaction')).toBe(true); - expect(overlay?.className.split(' ')).toEqual( - expect.arrayContaining(styles.overlay.split(' ').filter(Boolean)), - ); - expect(button?.querySelector('[data-testid="label"]')).not.toBeNull(); - }); - - it('does not inject an overlay for the form variant', () => { - const { container } = render( - - - , - ); - - const input = container.firstElementChild; - expect(input?.tagName).toBe('INPUT'); - expect(input?.querySelector('[data-vapor-interaction]')).toBeNull(); - }); - - it('preserves the child ref', () => { - const ref = createRef(); - - render( - - - , - ); - - expect(ref.current).not.toBeNull(); - expect(ref.current?.tagName).toBe('BUTTON'); - }); - - it('has no axe violations', async () => { - const { container } = render( - - - , - ); + ); - const results = await axe(container); + const interactionElement = rendered.queryByTestId('interaction'); - expect(results).toHaveNoViolations(); + expect(interactionElement).toBeNull(); + expect(interactionElement).not.toBeInTheDocument(); + }); }); }); From eab48290d0f727b6fb1bc913fa7b9f36ee91042f Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Tue, 16 Jun 2026 13:17:35 +0900 Subject: [PATCH 21/25] install storybook-addon-pseudo-states --- apps/storybook/.storybook/main.ts | 5 ++- apps/storybook/package.json | 1 + pnpm-lock.yaml | 56 +++++++++++++++++++------------ 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/apps/storybook/.storybook/main.ts b/apps/storybook/.storybook/main.ts index 42d5c7b5b..6128d7142 100644 --- a/apps/storybook/.storybook/main.ts +++ b/apps/storybook/.storybook/main.ts @@ -8,7 +8,10 @@ const require = createRequire(import.meta.url); const config: StorybookConfig = { stories: ['../../../packages/**!(node_modules|dist)/src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: [getAbsolutePath('@storybook/addon-docs')], + addons: [ + getAbsolutePath('@storybook/addon-docs'), + getAbsolutePath('storybook-addon-pseudo-states'), + ], core: { builder: getAbsolutePath('@storybook/builder-vite'), diff --git a/apps/storybook/package.json b/apps/storybook/package.json index a7644fd6b..335ac2ba6 100644 --- a/apps/storybook/package.json +++ b/apps/storybook/package.json @@ -27,6 +27,7 @@ "eslint": "catalog:", "globals": "^16.5.0", "storybook": "^9.1.20", + "storybook-addon-pseudo-states": "9.1.20", "typescript": "catalog:", "typescript-eslint": "^8.59.4", "vite": "^7.3.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4265e100e..2b44b3cfe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -205,6 +205,9 @@ importers: storybook: specifier: ^9.1.20 version: 9.1.20(@testing-library/dom@10.4.1)(prettier@3.8.3)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.99.0)(tsx@4.21.0)) + storybook-addon-pseudo-states: + specifier: 9.1.20 + version: 9.1.20(storybook@9.1.20(@testing-library/dom@10.4.1)(prettier@3.8.3)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.99.0)(tsx@4.21.0))) typescript: specifier: 'catalog:' version: 5.9.3 @@ -422,13 +425,13 @@ importers: version: 9.39.4(jiti@2.6.1) jest: specifier: ^30.3.0 - version: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + version: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) rimraf: specifier: ^6.1.3 version: 6.1.3 ts-jest: specifier: ^29.4.11 - version: 29.4.11(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.7)(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.28.0)(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3) tsup: specifier: ^8.5.1 version: 8.5.1(jiti@2.6.1)(postcss@8.5.15)(tsx@4.21.0)(typescript@5.9.3) @@ -8107,6 +8110,11 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + storybook-addon-pseudo-states@9.1.20: + resolution: {integrity: sha512-bqVggqXvE2krhcY7pJcxOPVP/klUcsnWamP9P/cVWdW9ah3vufNY3JpJPQxCt/6OKbaEIZ5QYJkA4bnVi9DEXg==} + peerDependencies: + storybook: ^9.1.20 + storybook@9.1.20: resolution: {integrity: sha512-6rME2tww6PFhm96iG2Xx44yzwLDWBiDWy+kJ2ub6x90werSTOiuo+tZJ94BgCfFutR0tEfLRIq59s+Zg6YyChA==} hasBin: true @@ -11524,7 +11532,7 @@ snapshots: jest-util: 30.3.0 slash: 3.0.0 - '@jest/core@30.3.0(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))': + '@jest/core@30.3.0(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3))': dependencies: '@jest/console': 30.3.0 '@jest/pattern': 30.0.1 @@ -11539,7 +11547,7 @@ snapshots: exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.3.0 - jest-config: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + jest-config: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) jest-haste-map: 30.3.0 jest-message-util: 30.3.0 jest-regex-util: 30.0.1 @@ -12831,8 +12839,8 @@ snapshots: '@testing-library/dom@10.4.1': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.28.4 + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.29.2 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -14536,10 +14544,10 @@ snapshots: transitivePeerDependencies: - supports-color - esbuild-register@3.6.0(esbuild@0.27.7): + esbuild-register@3.6.0(esbuild@0.28.0): dependencies: debug: 4.4.3 - esbuild: 0.27.7 + esbuild: 0.28.0 transitivePeerDependencies: - supports-color optional: true @@ -14673,7 +14681,7 @@ snapshots: '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)) @@ -14706,7 +14714,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.3 @@ -14729,7 +14737,7 @@ snapshots: '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)))(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import-x@4.16.2(@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.4(jiti@2.6.1)))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -15813,15 +15821,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): + jest-cli@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: - '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) '@jest/test-result': 30.3.0 '@jest/types': 30.3.0 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + jest-config: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) jest-util: 30.3.0 jest-validate: 30.3.0 yargs: 17.7.2 @@ -15832,7 +15840,7 @@ snapshots: - supports-color - ts-node - jest-config@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): + jest-config@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: '@babel/core': 7.29.0 '@jest/get-type': 30.1.0 @@ -15859,7 +15867,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.19.41 - esbuild-register: 3.6.0(esbuild@0.27.7) + esbuild-register: 3.6.0(esbuild@0.28.0) ts-node: 10.9.2(@types/node@20.19.41)(typescript@5.9.3) transitivePeerDependencies: - babel-plugin-macros @@ -16117,12 +16125,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): + jest@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)): dependencies: - '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) '@jest/types': 30.3.0 import-local: 3.2.0 - jest-cli: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + jest-cli: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -17970,6 +17978,10 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + storybook-addon-pseudo-states@9.1.20(storybook@9.1.20(@testing-library/dom@10.4.1)(prettier@3.8.3)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.99.0)(tsx@4.21.0))): + dependencies: + storybook: 9.1.20(@testing-library/dom@10.4.1)(prettier@3.8.3)(vite@7.3.3(@types/node@25.5.0)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.99.0)(tsx@4.21.0)) + storybook@9.1.20(@testing-library/dom@10.4.1)(prettier@3.8.3)(vite@7.3.3(@types/node@22.19.19)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.99.0)(tsx@4.21.0)): dependencies: '@storybook/global': 5.0.0 @@ -18272,12 +18284,12 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.4.11(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.7)(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.11(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.28.0)(jest-util@30.3.0)(jest@30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.27.7))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) + jest: 30.3.0(@types/node@20.19.41)(esbuild-register@3.6.0(esbuild@0.28.0))(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.9.3)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -18290,7 +18302,7 @@ snapshots: '@jest/transform': 30.3.0 '@jest/types': 30.3.0 babel-jest: 30.3.0(@babel/core@7.29.0) - esbuild: 0.27.7 + esbuild: 0.28.0 jest-util: 30.3.0 ts-morph@22.0.0: From 081d7ab16ce0c2f64ac15f7c391e627fd5b6dd3b Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Tue, 16 Jun 2026 13:18:12 +0900 Subject: [PATCH 22/25] enhance interaction testbed --- .../interaction/interaction.stories.tsx | 150 ++++++++---------- 1 file changed, 68 insertions(+), 82 deletions(-) diff --git a/packages/core/src/components/interaction/interaction.stories.tsx b/packages/core/src/components/interaction/interaction.stories.tsx index 461103cf9..d4f6ba76c 100644 --- a/packages/core/src/components/interaction/interaction.stories.tsx +++ b/packages/core/src/components/interaction/interaction.stories.tsx @@ -1,7 +1,7 @@ -import type { CSSProperties } from 'react'; - import type { Meta, StoryObj } from '@storybook/react-vite'; +import { Box } from '../box'; +import { VStack } from '../v-stack'; import { Interaction } from './interaction'; export default { @@ -15,95 +15,81 @@ export default { type Story = StoryObj; -const buttonStyle: CSSProperties = { - padding: '0.5rem 1rem', - border: '1px solid #ccc', - borderRadius: '0.375rem', - background: '#fff', - cursor: 'pointer', -}; - -const inputStyle: CSSProperties = { - padding: '0.5rem 0.75rem', - border: '1px solid #ccc', - borderRadius: '0.375rem', - outline: 'none', -}; - -const itemStyle: CSSProperties = { - padding: '0.5rem 0.75rem', - borderRadius: '0.375rem', - userSelect: 'none', - cursor: 'pointer', -}; - export const Default: Story = { render: (args) => ( - + ), }; -export const ScaleLight: Story = { - args: { scale: 'light' }, - render: (args) => ( - - - - ), -}; +export const TestBed: Story = { + parameters: { + pseudo: { + hover: ['#default-hover', '#light-hover', '#form-hover'], + focus: '#form-focus', + focusVisible: '#default-focus-visible', + active: ['#default-active', '#roving-active'], + }, + }, + render: (args) => { + const boxCss = { display: 'inline-block', padding: '16px', border: '1px solid' } as const; + return ( + + + default / rest + + + + default / hover + + + + + default / focus-visible + + + + + default / active + + -export const TypeForm: Story = { - args: { type: 'form' }, - render: (args) => ( - - - - ), -}; + + light / rest + + + + light / hover + + -export const TypeRoving: Story = { - args: { type: 'roving' }, - render: (args) => ( -
- -
- Highlighted item -
-
- -
Regular item
-
-
- ), -}; + + + + + + + + + -export const TestBed: Story = { - render: () => ( -
- - - - - - - - - - -
- roving (highlighted) -
-
-
- ), + + roving / rest + + + + roving / highlighted + + + + + roving / highlighted + active + + +
+ ); + }, }; From 2930624d345835e2cd8b44e7ab811e00e9081f1b Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Tue, 16 Jun 2026 13:18:21 +0900 Subject: [PATCH 23/25] update snapshot --- ...interaction--test-bed-1-chrome-darwin-.png | Bin 13018 -> 27720 bytes .../interaction--test-bed-1-edge-darwin-.png | Bin 13018 -> 27720 bytes ...nteraction--test-bed-1-firefox-darwin-.png | Bin 28718 -> 48594 bytes ...interaction--test-bed-1-safari-darwin-.png | Bin 28316 -> 45038 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/core/__tests__/screenshots/interaction--test-bed-1-chrome-darwin-.png b/packages/core/__tests__/screenshots/interaction--test-bed-1-chrome-darwin-.png index 782b037b3128c61eafd705f54c421d37047f718d..710ee87a4e1ab502b2e42f6b12cb4fc2e6300cfe 100644 GIT binary patch literal 27720 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 Qub?jKTt1)mcdK9i3zRTjNdN!< diff --git a/packages/core/__tests__/screenshots/interaction--test-bed-1-edge-darwin-.png b/packages/core/__tests__/screenshots/interaction--test-bed-1-edge-darwin-.png index 782b037b3128c61eafd705f54c421d37047f718d..710ee87a4e1ab502b2e42f6b12cb4fc2e6300cfe 100644 GIT binary patch literal 27720 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 Qub?jKTt1)mcdK9i3zRTjNdN!< diff --git a/packages/core/__tests__/screenshots/interaction--test-bed-1-firefox-darwin-.png b/packages/core/__tests__/screenshots/interaction--test-bed-1-firefox-darwin-.png index 2f8a072507c0afe2c25f61a618a051f46b3e2922..b8878649b845caed3fdae96342a0bbd11f7a5af4 100644 GIT binary patch literal 48594 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 E03ul7aR2}S literal 28718 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 literal 28316 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 Date: Tue, 16 Jun 2026 15:41:07 +0900 Subject: [PATCH 24/25] propagate child.props.children --- .../interaction/interaction.stories.tsx | 2 +- .../components/interaction/interaction.tsx | 33 ++++++++++++------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/packages/core/src/components/interaction/interaction.stories.tsx b/packages/core/src/components/interaction/interaction.stories.tsx index d4f6ba76c..6f0cfe4a8 100644 --- a/packages/core/src/components/interaction/interaction.stories.tsx +++ b/packages/core/src/components/interaction/interaction.stories.tsx @@ -17,7 +17,7 @@ type Story = StoryObj; export const Default: Story = { render: (args) => ( - + Interactive button diff --git a/packages/core/src/components/interaction/interaction.tsx b/packages/core/src/components/interaction/interaction.tsx index 13458f5fc..9fbdc16ab 100644 --- a/packages/core/src/components/interaction/interaction.tsx +++ b/packages/core/src/components/interaction/interaction.tsx @@ -1,4 +1,4 @@ -import { Children, cloneElement, isValidElement } from 'react'; +import { Children, Fragment, cloneElement, isValidElement } from 'react'; import { useRenderElement } from '~/hooks/use-render-element'; import { cn } from '~/utils/cn'; @@ -14,7 +14,12 @@ import type { InteractionVariants } from './interaction.css'; * -----------------------------------------------------------------------------------------------*/ export const Interaction = (props: Interaction.Props) => { - const { className, children: childrenProp, ...componentProps } = resolveStyles(props); + const { + className: classNameProp, + children: childrenProp, + ...componentProps + } = resolveStyles(props); + const [variantProps, otherProps] = createSplitProps()(componentProps, [ 'scale', 'type', @@ -28,25 +33,29 @@ export const Interaction = (props: Interaction.Props) => { const element = useRenderElement({ defaultTagName: 'div', - state: { 'vapor-interaction': true }, + state: { interaction: true }, props: { role: 'presentation', 'aria-hidden': 'true', - className: cn(styles.overlay, className), + className: cn(styles.overlay, classNameProp), ...otherProps, }, }); - const children = ( - <> - {element} - {child.props.children} - - ); + const { type } = variantProps; + const { className, children } = child.props; return cloneElement(child, { - className: cn(styles.root(variantProps), child.props.className), - children: variantProps.type !== 'form' ? children : undefined, + className: cn(styles.root(variantProps), className), + children: + type === 'form' ? ( + children + ) : ( + + {element} + {children} + + ), }); }; From 9ce3d9ad3eeae8aaa696688e3f434f9cc362e7e5 Mon Sep 17 00:00:00 2001 From: "noah.choi" Date: Tue, 16 Jun 2026 15:47:43 +0900 Subject: [PATCH 25/25] adjust Interaction to missed components --- .../navigation-menu/navigation-menu.tsx | 16 +++++++++------- .../src/components/pagination/pagination.tsx | 8 ++++++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/core/src/components/navigation-menu/navigation-menu.tsx b/packages/core/src/components/navigation-menu/navigation-menu.tsx index 2de037757..07b5030ae 100644 --- a/packages/core/src/components/navigation-menu/navigation-menu.tsx +++ b/packages/core/src/components/navigation-menu/navigation-menu.tsx @@ -157,13 +157,15 @@ export const NavigationMenuTriggerPrimitive = forwardRef< const dataAttrs = createDataAttributes({ disabled }); return ( - + + + ); }); NavigationMenuTriggerPrimitive.displayName = 'NavigationMenu.TriggerPrimitive'; diff --git a/packages/core/src/components/pagination/pagination.tsx b/packages/core/src/components/pagination/pagination.tsx index 3c13ef252..7a19f9ad2 100644 --- a/packages/core/src/components/pagination/pagination.tsx +++ b/packages/core/src/components/pagination/pagination.tsx @@ -239,7 +239,7 @@ export const PaginationPreviousPrimitive = forwardRef< const state: PaginationPreviousPrimitive.State = useMemo(() => ({ disabled }), [disabled]); - return useRenderElement({ + const element = useRenderElement({ ref, render, defaultTagName: 'button', @@ -253,6 +253,8 @@ export const PaginationPreviousPrimitive = forwardRef< ...componentProps, }, }); + + return {element}; }); PaginationPreviousPrimitive.displayName = 'Pagination.PreviousPrimitive'; @@ -310,7 +312,7 @@ export const PaginationNextPrimitive = forwardRef ({ disabled }), [disabled]); - return useRenderElement({ + const element = useRenderElement({ ref, render, defaultTagName: 'button', @@ -324,6 +326,8 @@ export const PaginationNextPrimitive = forwardRef{element}; }, ); PaginationNextPrimitive.displayName = 'Pagination.NextPrimitive';