From d65e6d4e06119421d03b54e1c7712ce6a5597238 Mon Sep 17 00:00:00 2001 From: HerbertJulio Date: Thu, 25 Jun 2026 20:13:14 -0300 Subject: [PATCH 1/4] [ENG-46312] feat(webkit): add Divider (layout) --- .specs/divider.md | 115 +++++++++++++++++ .../components/layout/Divider.stories.js | 121 ++++++++++++++++++ packages/webkit/package.json | 1 + .../src/components/layout/divider/divider.vue | 53 ++++++++ .../components/layout/divider/package.json | 11 ++ 5 files changed, 301 insertions(+) create mode 100644 .specs/divider.md create mode 100644 apps/storybook/src/stories/components/layout/Divider.stories.js create mode 100644 packages/webkit/src/components/layout/divider/divider.vue create mode 100644 packages/webkit/src/components/layout/divider/package.json diff --git a/.specs/divider.md b/.specs/divider.md new file mode 100644 index 00000000..87b96825 --- /dev/null +++ b/.specs/divider.md @@ -0,0 +1,115 @@ +--- +name: divider +category: layout +structure: monolithic +status: approved +spec_version: 1 +figma: + url: https://www.figma.com/design/t97pXRs7xME3SJDs5iZ5RF/Webkit?node-id=479-886 + node_id: 479:886 +checksum: ac9f15a30e669c779403cb474d6759bd8b8f5bd108a29680cd772532ed2991a2 +created: 2026-06-25 +last_updated: 2026-06-25 +--- + +# Divider — Component Spec + +## Purpose + +Thin separator line that visually splits content into groups. Renders as a full-width hairline (`horizontal`) or full-height hairline (`vertical`), and can carry centered content (an "Or"-style label) when the default slot or `label` prop is set. Unlike `ScrollArea` it adds no scrolling behaviour; it is a purely decorative-yet-semantic boundary exposing `role="separator"`. + +## Usage + +```vue + + + +``` + +## Props + +| Prop | Type | Default | Required | JSDoc | +|---|---|---|---|---| +| `orientation` | `'horizontal' | 'vertical'` | `'horizontal'` | no | Layout axis of the separator line. | +| `label` | `string` | `''` | no | Fallback centered text shown when the default slot is empty. | + +## Events + +| _none_ | — | — | + +## Slots + +| Slot | Scope | Notes | +|---|---|---| +| `default` | — | Centered content; overrides `label` when provided. | + +## States + +- Visual states: `default` +- `data-orientation` mirrors the `orientation` prop: `horizontal` | `vertical` + +## Motion & Animations + +_none_ + +## Tokens + +| Region | Token (DESIGN.md) | +|---|---| +| line | `var(--border-default)` | +| typography (label) | `.text-label-sm` | +| text (label) | `var(--text-muted)` | +| spacing (gap around label) | `var(--spacing-sm)` | + +## Theme gaps + +| Figma variable | Temporary primitive | Follow-up | +|---|---|---| +| _none_ | — | — | + +## Accessibility (WCAG 2.1 AA) + +- Visible focus: not applicable — the separator is non-interactive and not in the tab order. +- Keyboard map: not applicable — no interactive controls. +- ARIA: root carries `role="separator"` and `aria-orientation="{orientation}"`. A labelled divider keeps the `separator` role; the label is exposed as the separator's accessible content. +- Contrast ≥4.5:1 (text) / ≥3:1 (large + icons), including the disabled state — the muted label text meets the body-text ratio against canvas/surface. +- `motion-reduce:transition-none motion-reduce:transform-none` on animated states — not applicable; the component declares no motion. +- Touch target ≥40×40 px — not applicable; the component is non-interactive. + +## Stories (Storybook) + +Canonical layout — matches `apps/storybook/src/stories/components/layout/ScrollArea.stories.js`. + +- Default — the horizontal hairline at its most representative state. +- Orientations — composite story rendering `horizontal` and `vertical` side by side in a single frame; the two values are the component's only variant axis, so they are shown together rather than one story per value. +- WithLabel — demonstrates the centered `label` (and, by extension, the default slot) splitting the line, which neither Default nor Orientations exercises. + +## Constraints — DO NOT + + + +- Do not add props beyond the Props table above. If you need a prop that is not listed, emit `BLOCKED: missing prop ` and stop — do not invent. +- Do not add events beyond the Events table above. Same rule for slots and sub-components. +- Do not invent imports. Every `@aziontech/webkit/*` path must exist in `packages/webkit/package.json#exports`. Every relative import must resolve to a real file. Every npm package must be installed. +- Do not use HEX/RGB/HSL colors, Tailwind palette names (e.g. `bg-blue-500`), raw typography classes (e.g. `text-sm`), `any`, `@ts-ignore`, or `class` inside `defineProps`. +- Do not install or import positioning/animation libraries (`@floating-ui/*`, `popper.js`, `tippy.js`, `gsap`, `framer-motion`, `motion`, `@vueuse/motion`, `@formkit/auto-animate`, drag-drop runtimes, scroll virtualization libs). Use CSS + Vue primitives (``, ``). See `.claude/rules/dependencies.md`. +- Do not improvise animations. Every `animate-*` / `transition-*` class must come from `packages/theme/src/tokens/semantic/animations.js`; every motion-bearing class pairs with `motion-reduce:*` on the same class string; no component-local `@keyframes`. +- Do not create class presets in JavaScript (`const kindClasses = {...}`, `const sharedClasses = [...]`, `const sizeClasses = {...}`, `const rootClasses = computed(...)`). Variants live on `data-*` attributes consumed by Tailwind `data-[attr=value]:`. All utilities live inline on the root element's `class` attribute. No `