Skip to content

feat(flex): support responsive prop values - #284

Merged
KYBee merged 6 commits into
devfrom
feature/flex-responsive-contract-kybee-dev
Jul 23, 2026
Merged

feat(flex): support responsive prop values#284
KYBee merged 6 commits into
devfrom
feature/flex-responsive-contract-kybee-dev

Conversation

@KYBee

@KYBee KYBee commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Changes

  • Flex의 기존 단일 값 prop 계약을 유지하면서 { sm, md, lg } responsive 값을 추가로 받을 수 있도록 확장했습니다.
  • direction, align, justify, wrap, gap에서 단일 값과 breakpoint 객체 값을 모두 지원합니다.
  • responsive class와 media query는 현재 Flex 패키지 내부 계약으로 처리합니다.
  • 추후 @sipe-team/tokens에 정식 breakpoint token이 정의되면, 외부 사용 방식은 유지하고 내부 구현만 token 기반으로 교체할 수 있습니다.
  • @sipe-team/flex minor / @sipe-team/side patch changeset을 추가했습니다.

Visuals

  • Storybook Flex/Responsive 예시를 추가했습니다.

Checklist

  • Have you written the functional specifications?
  • Have you written the test code?

Additional Discussion Points

  • 기존 사용 방식은 계속 호환됩니다.
  • sipe.team 마이그레이션은 이 PR 배포 이후 별도 PR에서 진행할 수 있습니다.

Validation

  • mise exec -- pnpm --filter @sipe-team/flex test -- run src/Flex.test.tsx
  • mise exec -- pnpm --filter @sipe-team/flex typecheck
  • mise exec -- pnpm --filter @sipe-team/flex lint
  • mise exec -- pnpm --filter @sipe-team/flex build
  • mise exec -- pnpm --filter @sipe-team/side typecheck
  • mise exec -- pnpm --filter @sipe-team/side build
  • git diff --check origin/dev..HEAD

@changeset-bot

changeset-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ad3a563

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@sipe-team/flex Minor
@sipe-team/side Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • main
  • release/v1

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2211af33-9197-4ab8-81e1-8b56593f610a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/flex-responsive-contract-kybee-dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
packages/flex/src/Flex.css.ts 100.00% <ø> (ø)
packages/flex/src/Flex.test.tsx 100.00% <100.00%> (ø)
packages/flex/src/Flex.tsx 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@KYBee
KYBee marked this pull request as ready for review June 30, 2026 06:30
@KYBee
KYBee marked this pull request as draft June 30, 2026 06:31
@KYBee
KYBee force-pushed the feature/flex-responsive-contract-kybee-dev branch from fa78aeb to 594a33d Compare June 30, 2026 06:44
@KYBee
KYBee marked this pull request as ready for review June 30, 2026 07:00
Comment thread packages/flex/src/Flex.tsx Outdated
Comment on lines +10 to +12
type FlexBreakpoint = 'sm' | 'md' | 'lg';
type ResponsiveValue<T> = T | Partial<Record<FlexBreakpoint, T>>;
type ResponsiveStyleVariants<T extends string> = Record<FlexBreakpoint, Record<T, string>>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

export 하지 않으면 사용부에서 한번 더 정의해야해서 export를 해야할꺼 같습니다~

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 감사합니다. 반영하겠습니다!

Comment on lines +10 to +11
md: 'screen and (min-width: 780px)',
lg: 'screen and (min-width: 1060px)',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

780, 1060으로 잡은 이유는 몬가요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

780/1060은 기존 @sipe-team/tokens layout breakpoint(md/lg) 값과 맞춘 값입니다. 해당 token export가 deprecated 상태라 Flex 내부에 로컬 상수로 두고, 그 맥락을 코드 주석에 추가했습니다.

@osohyun0224 osohyun0224 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생많으셨습니다 bb

getResponsiveClassNames(direction, 'row', styles.direction),
getResponsiveClassNames(align, 'normal', styles.align),
getResponsiveClassNames(justify, 'normal', styles.justify),
getResponsiveClassNames(wrap, 'nowrap', styles.wrap),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 gap 은 없는데 혹시 의도하신 걸까요...?

gap={{ md: '16px', lg: '24px' }}처럼 sm을 생략하면
780px 미만 화면에서 --side-flex-gap-sm이 설정 안 되서
폴백 없이 무효화되고 gap이 0이 되는 것 같은데.

이게 다른 prop들과 동작이 다른데, 의도하신 걸까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

문의 주신 부분을 확인해보았습니다. sm을 생략한 구간에서는 Flex의 기본 gap인 normal(flex 레이아웃에서는 0)을 사용하는 동작을 의도했습니다. 다른 responsive prop도 값이 없는 기본 구간에서는 각 prop의 기본값을 사용하고 있어 같은 기준으로 보았습니다. 이번 수정에서는 이 계약이 명확하게 드러나도록 sm 기본값을 명시하고 관련 테스트를 추가했습니다. (e9034fd)

[mediaQuery.lg]: style,
},
})),
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

responsiveGap 처럼 하나의 style() 호출 안에서
@media 우선순위를 명시하는 방식으로 바꾸는 게 더 안전할 것 같습니다.

나중에 이 함수 근처에 다른 mediaQuery.lg 참조가 먼저 추가되거나
객체 프로퍼티 순서가 바뀌면,
lg 값이 적용돼야 할 1060px 이상 화면에서 md 값이 대신 적용되는 일이 생길 수도 있을 것 같습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀해주신 것처럼 1060px 이상에서는 mdlg 조건이 함께 적용되므로 최종 CSS 선언 순서가 중요하다고 보았습니다. 실제 빌드 결과를 확인한 결과, 현재 responsiveGap의 단일 style()에 선언된 md → lg 순서가 같은 파일의 미디어 규칙 정렬에 반영되어 md 블록 다음에 lg 블록이 생성되고 있었습니다. 이번 변경 후에도 해당 순서가 유지되는 것을 다시 확인했으며, 현재 구조에서는 lg 값이 정상적으로 우선 적용되고 있어 이 부분은 기존 구현을 유지했습니다.

@G-hoon

G-hoon commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

@KYBee 질문이 있습니다.

<Flex gap={{ sm: '8px' }}>
  <div>부모 아이템 1</div>
  <div>부모 아이템 2</div>

  <Flex gap={{ lg: '2px' }}>   {/* sm 생략 */}
    <div>자식 아이템 1</div>
    <div>자식 아이템 2</div>
  </Flex>
</Flex>

의 케이스에 대해서,
자식 엘리먼트에 sm 이 없을 경우 부모로 올라가서, sm 값을 찾아서 사용하는데.
이 경우엔 자식 요소가 sm: 8px 을 상속받아서 사용하는데 의도된 동작이 맞을까요?

코드를 작성하는 입장에서는, 자식 요소의 Flex gap 속성 값이
sm: 0px 로 생각하고 이렇게 작성할 수도 있을 것 같은데.
의도치 않게 부모에 있는 Flex의 요소를 상속 받아서 쓰게 되지 않나 생각이 들어서요.

나중에 Flex 를 매우 복잡하게 사용해야 할 때는, 의도치 못한 이슈가 발생할 수도 있을 것 같은데.
다른 디자인 컴포넌트나 라이브러리 참고한 게 있으면 같이 공유해주시면 좋을 것 같습니다.

@KYBee

KYBee commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

@G-hoon 문의 주신 중첩 케이스를 확인해보았습니다. 이번 responsive API는 별도로 참고한 특정 컴포넌트나 라이브러리 구현은 없으며, 기존 sipe.teamsm, md, lg breakpoint와 현재 Flex prop 계약을 기준으로 설계했습니다.

확인 과정에서 CSS custom property가 상속되면서 자식 Flex가 생략한 breakpoint에서 부모의 gap 값을 가져오는 문제가 있었습니다. 의도한 동작은 아니어서, 자식 Flex가 각 breakpoint 값을 자체 기본값과 직전 breakpoint 값으로 해석하도록 수정했습니다. 예시의 자식 gap={{ lg: "2px" }}은 이제 sm/md에서 기본값 normal(flex 레이아웃에서는 0), lg에서 2px을 사용합니다. 중첩 시 부모 값을 상속하지 않는 테스트도 함께 추가했습니다. (e9034fd)

@KYBee
KYBee merged commit 7cf28a0 into dev Jul 23, 2026
6 checks passed
@KYBee
KYBee deleted the feature/flex-responsive-contract-kybee-dev branch July 23, 2026 09:05
KYBee added a commit that referenced this pull request Jul 27, 2026
* chore: upgrade pnpm to 10.33.0 (#211)

* fix(ci): add --if-present flag to pnpm filter commands (#238)

* chore(commitlint): simplify config to conventional preset only (#237)

* chore(husky): update branch naming rules (#239)

* docs: sync convention sections with new rules (#240)

* docs(#218): v1 token usage audit              (#243)

* fix(build): preserve css imports in sideEffects (#228)

* fix(build): preserve css imports in sideEffects

* fix(build): preserve css side effects in template

* chore(changeset): add css sideEffects fix note

* chore(changeset): fix package list and description

* docs: sync README badges, license year, and CLAUDE.md pnpm version (#242)

* docs: token architecture and naming convention (#246)

* test(flex): strengthen contract coverage (#241)

* refactor(flex): align story options with constants

- replace hardcoded story options with Flex constants
- keep Storybook controls aligned with the current contract values
- reduce the risk of drift between implementation and story definitions

* test(flex): strengthen contract coverage

- align tests with the current Flex contract in side
- use constants as the source of truth for direction, align, justify, and wrap cases
- add coverage for normal values, asChild behavior, style overrides, ref forwarding, and common consumer usage patterns
- verify the Flex test suite passes at the package level

* test(flex): translate test descriptions to english

---------

Co-authored-by: KYBee <kybee@KYBeeui-Macmini.local>

* chore: remove unused eslint type declarations (#249)

* chore: add build, typecheck, test:coverage scripts to root

* chore: add missing scripts to packages

* chore: sort scripts order across all packages

* chore: remove plugin-figma-codegen package (#251)

* feat(Button): 버튼 컴포넌트의 최소 WAI-ARIA 기본 접근성 개선 (#244)

* chore: remove per-package .storybook configs (#250)

* feat(tokens): define primitive token foundations (#248)

* feat: primitive token

* fix: ci error

* docs: update spacing primitive token

* docs: update radius primitive token

* fix(Tooltip): 접근성(a11y) 개선 및 스타일 코드 개선 (#245)

* fix(tooltip): add aria-label for screen readers

* refactor(tooltip): migrate styles to vanilla-extract recipe

* test(tooltip): improve accessibility test coverage

* refactor(tooltip): use enum instead of string literal

* fix(tooltip): resolve type import error

* test(tooltip): translate test descriptions to English

* chore(tooltip): remove export and add changeset

* chore: enforce package.json consistency across the workspace (#252)

* chore(chip): normalize package.json structure

* chore(packages): align package.json across workspace

* chore(tooling): add package.json consistency checker

* chore(packages): add clean script to template and accordion

* docs(claude): document package consistency policy

* fix(tooling): tighten allowlist fieldPath matching

* fix(tooling): harden policy allowlist validation

* feat(tooling): police sideEffects field in package policy

* fix(ci): mark consistency install step as non-blocking

* chore: drop per-package storybook scripts

* chore(tooling): promote test to hard rule, drop optionalScripts

* fix(tooling): allow publishConfig hard rules to be allowlisted

* docs(claude): sync package policy with enforced rules

* chore(deps): sync lockfile with workspace catalogs

* chore(tooling): namespace lint scripts (lint:biome, lint:package)

* feat(tokens): introduce semantic token foundation and brand color alias strategy (#258)

* feat(tokens): update primitive token JSON with extended scale

Add missing color shades (gray.950, status colors), expanded radius,
spacing, and typography scales to align with semantic token requirements.

Confidence: high
Scope-risk: narrow

* feat(tokens): add semantic token JSON draft in DTCG format

Introduce dark-mode semantic tokens for color, spacing, radius, and
typography. All values reference primitive aliases only — no raw hex or
px values. Each token includes two usage-scenario descriptions.
Light-mode tokens are deferred (tokens/semantic/light/ has .gitkeep only).

Confidence: high
Scope-risk: narrow

* feat(tokens): redesign CSS contract to match semantic token structure

Rewrite vars contract to reflect semantic layers (color.background.*,
color.foreground.*, color.accent.*, spacing.component.*, spacing.layout.*,
radius.component.*, radius.layout.*). Extract darkBaseColor shared object
and define four brand theme variants (default, 1st–4th).

Constraint: dark mode is the default; light mode is deferred
Rejected: per-theme contract files | increases maintenance surface
Confidence: high
Scope-risk: broad

* feat(button): migrate styles to new semantic vars paths

Update all token references to match the redesigned CSS contract:
color.primary → color.accent.default, spacing.sm/lg → spacing.component.*,
radius.md → radius.component.md, focus ring wired to color.border.focus.

Confidence: high
Scope-risk: narrow

* chore(tokens): mark unused TS primitive exports as deprecated

Add @deprecated JSDoc to opacity, zIndex, borderWidth/borderStyle,
shadows, spacing, breakpoints, grid, and responsiveStyle. These TS
source files will be removed alongside all other TS primitives once
the JSON token pipeline is complete and components have migrated to vars.*.

Directive: do not add new consumers of these exports
Confidence: high
Scope-risk: narrow

* chore: changeset

* feat(tokens): add brand primitive and update accent semantic alias

- Add color.brand.{default,hover,subtle} to primitive/color.json
  with current cohort values (#ffb24d, #d9963f, #3b2005)
- Update semantic accent.* to reference {color.brand.*} instead of
  blue to reflect actual brand color

brand primitive acts as the single update point per cohort;
semantic tokens and components require no changes on rebranding.

* feat(tokens): add brandColor and update defaultTheme accent to orange

- Export brandColor const from colors.ts (mirrors primitive brand.*)
- Import brandColor in themes.css.ts and apply to defaultTheme accent
  replacing hardcoded blue values

Note: colors.ts and themes.css.ts are deprecated and will be removed
once the Style Dictionary pipeline is in place.

* fix(theme): correct assignInlineVars contract mapping in ThemeProvider

assignInlineVars(vars.color, theme) was passing ThemeColor
{ primary, secondary, background, text, gradient } to a contract
that expects { accent, foreground, border, status, ... },
causing a TypeScript error and no-op CSS variable assignment.

Fix by scoping to vars.color.accent and mapping ThemeColor fields:
- primary   → accent.default
- secondary → accent.hover
- background → accent.subtle

* docs(tokens): add semantic token proposal with rebrand strategy

- Document semantic token structure (color, spacing, radius, typography)
- Add rebranding flow section explaining brand primitive alias pattern:
  update color.brand.* in primitive/color.json only on cohort change
- Note W3C Design Token format compatibility with Token Studio v2
  and Style Dictionary v4 for upcoming Figma pipeline integration

* fix(tokens): remove duplicate named exports from themes.css.ts

theme1st–theme4th were exported from both colors.ts (ThemeColor objects)
and themes.css.ts (createGlobalTheme return values), causing TS2308
ambiguous re-export errors in src/index.ts.

createGlobalTheme calls are CSS side effects; their return values are
not consumed by any external code, so export keywords are removed.

* Release (#256)

Co-authored-by: KYBee <kybee@KYBeeui-Macmini.local>
Co-authored-by: Jinho Yeom <81306489+Yeom-JinHo@users.noreply.github.com>
Co-authored-by: 이원주 <101818687+3o14@users.noreply.github.com>
Co-authored-by: YOUNGBEEN, KIM <62539910+KYBee@users.noreply.github.com>
Co-authored-by: 오소현 <53892427+osohyun0224@users.noreply.github.com>
Co-authored-by: Minji Jeon <105787441+minji0214@users.noreply.github.com>

* chore: update changeset BC

* docs: update semantic-proposal docs

* docs: modify semantic proposal muted token

* fix: modify spacing, radius themes

* chore: update deprecated annotation

---------

Co-authored-by: Evan <clcl6084@gmail.com>
Co-authored-by: KYBee <kybee@KYBeeui-Macmini.local>
Co-authored-by: Jinho Yeom <81306489+Yeom-JinHo@users.noreply.github.com>
Co-authored-by: YOUNGBEEN, KIM <62539910+KYBee@users.noreply.github.com>
Co-authored-by: 오소현 <53892427+osohyun0224@users.noreply.github.com>
Co-authored-by: Minji Jeon <105787441+minji0214@users.noreply.github.com>

* feat(tokens): add Style Dictionary v5 pipeline with W3C DTCG primitive tokens (#261)

* feat: style dictionary pipeline

* fix(tokens): adopt W3C DTCG format for primitives and fix token-names publish export

* fix: restore broken pnpm-lock.yaml after merge conflict resolution

* docs(md): unify ai context document (#257)

* feat(Card): add ghost variant with transparent background and no border (#265)

* feat(tokens): setup design token transformation pipeline and CI automation (#270)

* chore: formatting

* feat(tokens): setup design token transformation pipeline and CI automation

* ci: commit transformed tokens

* fix(accordion): add single/multiple open mode support(#255) (#254)

* feat(accordion): add single/multiple open mode support

* chore(accordion): add changeset for single/multiple mode feature

* fix(accordian): improve controlled state handling and add initialValue prop

* refactor(tooltip): replace trigger prop and improve WCAG compliance (#259)

* refactor(tooltip): rename useTooltip.tsx to useTooltip.ts

* perf(tooltip): throttle scroll/resize position update with rAF

* feat(tooltip): support keyboard focus for hover trigger

* refactor(tooltip): replace trigger prop with MUI-style listener controls

* fix(tooltip): remove redundant isVisible condition in portal className

* refactor(tooltip): remove redundant code and improve WCAG compliance

- Remove always-true visible class from portal (portal only renders when isVisible=true)
- Remove associated CSS opacity/transform/transition/pointerEvents overrides
- Remove redundant position:fixed from inline styles (already in CSS base)
- Remove redundant --tooltip-bg-color JS fallback (CSS already has var fallback)
- Conditionally apply tabIndex=0 only when focus listener is active (WCAG 2.4.7)
- Apply styles.button class only when asChild=false (WCAG 1.4.3)

* chore: downgrade esbuild to ~0.24.0 to fix Storybook manager build

esbuild 0.27 changed its behavior to refuse transforming syntax for
old browser targets (es2020, chrome87). Storybook 8.5 manager build
uses these hardcoded targets and breaks with 0.27. Downgrade to 0.24
as a temporary fix until Storybook is upgraded to support esbuild 0.27.

* Revert "chore: downgrade esbuild to ~0.24.0 to fix Storybook manager build"

This reverts commit e3e8a95.

* refactor(tooltip): remove disableFocusListener prop

Focus listener is always required for keyboard accessibility (WCAG 2.1.1).
Removing this prop enforces accessible defaults and simplifies the API.

* feat(tooltip): add fade-in animation on mount

Uses @Keyframes instead of CSS transition to correctly animate on DOM
insertion. Respects prefers-reduced-motion for accessibility (WCAG 2.3.3).

* fix(tooltip): prevent focus event from interfering with click-controlled open state

On first click, the browser fires focus before click, causing onFocus→requestOpen
to set open=true before the onClick toggle sets it back to false. Fixed by tracking
mousedown state so focus triggered by mouse click is ignored (keyboard focus still works).

* chore: add changeset for tooltip API refactor

* refactor(tooltip): restore disableFocusListener, remove hardcoded tabIndex, spread rest props

- Restore disableFocusListener prop for click-only controlled mode support
- Remove hardcoded tabIndex={0} to respect consumer element focusability
- Spread ...rest onto wrapper so consumers can pass tabIndex, role, aria-* etc.
- Merge className from rest with internal styles via clsx

* test(tooltip): add missing coverage for mouseUp, scroll/resize, invalid placement

* refactor(tooltip): apply PR review feedback

- Change changeset from minor to major (trigger prop removal is breaking change)
- Compose user event handlers with internal handlers via composeHandlers helper
- Make placement and gap optional in useTooltip with default values

* fix(tooltip): guard setInternalOpen with isControlled check in controlled mode

Co-Authored-By: MinjiJeon <jinnyjeon@sweetspot.co.kr>

---------

Co-authored-by: MinjiJeon <jinnyjeon@sweetspot.co.kr>

* chore(biome): remove unsafe flag from claude hooks (#267)

* chore: remove .github/decisions directory (#269)

* chore(storybook): upgrade to v10.3.5 (#276)

* fix(husky): update pre-push branch regex for dev (#278)

* chore: add title option to release workflow (#277)

* chore(templates): simplify component template to minimal pattern (#268)

* chore(tokens): token JSON file integration (#274)

* chore: .claudeingore file (#279)

* feat(button): Redesign Button component based on 5th generation design system (#263)

* feat(button): 5세대 디자인 시스템 기반 버튼 컴포넌트 전면 개편

* feat(button): add to changeset docs

* fix(Button): use Slottable for multi-child asChild compatibility

* fix(Button): apply to typecheck CI

* refactor(theme): replace brand-color ThemeProvider with light/dark mode toggle (#282)

* chore: replace existing data-theme

* chore: update theme provider render and themes.css.ts

* chore: claude allow reading tokens/dist

* chore: update theme packages

* chore: update themes css

* chore: changeset

* chore: theme utils test

* chore: update changeset

* chore: delete optional

* chore: modify changeset

* chore: add TODO comments for pending light mode

* chore: widen tokens dist read permission scope

* chore: resolve conflicts from main into dev (#286)

* Release (#256)

Co-authored-by: KYBee <kybee@KYBeeui-Macmini.local>
Co-authored-by: Jinho Yeom <81306489+Yeom-JinHo@users.noreply.github.com>
Co-authored-by: 이원주 <101818687+3o14@users.noreply.github.com>
Co-authored-by: YOUNGBEEN, KIM <62539910+KYBee@users.noreply.github.com>
Co-authored-by: 오소현 <53892427+osohyun0224@users.noreply.github.com>
Co-authored-by: Minji Jeon <105787441+minji0214@users.noreply.github.com>

* Version Packages (#260)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* chore: add title option to release workflow (#266)

---------

Co-authored-by: Evan <clcl6084@gmail.com>
Co-authored-by: KYBee <kybee@KYBeeui-Macmini.local>
Co-authored-by: Jinho Yeom <81306489+Yeom-JinHo@users.noreply.github.com>
Co-authored-by: YOUNGBEEN, KIM <62539910+KYBee@users.noreply.github.com>
Co-authored-by: 오소현 <53892427+osohyun0224@users.noreply.github.com>
Co-authored-by: Minji Jeon <105787441+minji0214@users.noreply.github.com>
Co-authored-by: y09n <euihyun.yang.9x@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix(tokens): restore token CSS chain and add ./styles.css entrypoint (#291)

packages/tokens/tsup.config.ts was the only package that redefined the
root tsup config instead of inheriting it, and it omitted the
vanilla-extract esbuild plugin. Two failures followed:

- contract.css.ts was bundled as plain TS, so importing dist threw at
  runtime ("Styles were unable to be assigned to a file"). This also
  broke @sipe-team/side, which re-exports @sipe-team/tokens.
- The --side-* bridge CSS was never emitted, and no CSS entrypoint
  existed to load the token values. Button — the only component
  consuming vars.* — rendered with padding, border-radius, font-size,
  font-weight, font-family and gap all collapsed to initial values.

Inherit the root tsup config, and ship a single ./styles.css that
concatenates the Style Dictionary value layer with the vanilla-extract
bridge — splitting them would let a consumer load half the chain and
break silently.

sideEffects moves from false to ["**/*.css"] for a separate reason: it
is what stops a downstream bundler from dropping the consumer's
`import '@sipe-team/tokens/styles.css'`. It was not the cause of the
missing bridge CSS (verified: the bridge emits fine under
sideEffects:false once the plugin is present). 17 of 21 packages
already use this value.

tokens.yaml called `build:tokens` standalone, which no longer works now
that the Style Dictionary step concatenates the tsup-emitted bridge —
point it at `build` (tsup && build:tokens).

Verified: dangling var() references in the built Storybook bundle go
from 11 to 0; importing tokens/dist no longer throws; a clean checkout
running the Tokens workflow's commands exits 0.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(release): gate publish behind export map validation (#289)

* fix(accordion,grid): compile vanilla-extract styles into dist

Both packages declared a local tsup config without the vanilla-extract plugin,
so their `.css.ts` styles were never compiled and the `dist/index.css` behind
`./styles.css` never made it into the tarball. Reuse the shared root config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(reset): point reset.css export at the emitted stylesheet

The export referenced `./dist/reset.css`, but the build emits `./dist/index.css`,
so `@sipe-team/reset/reset.css` failed to resolve for consumers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(tokens): emit resolvable token-names barrel declarations

The generated barrel re-exported `./primitive` and `./semantic` without runtime
extensions, so `@sipe-team/tokens/token-names` failed to resolve under node16 ESM.
Declaration files need the extension; the types-only semantic layer needs no
runtime module, since TypeScript resolves `./semantic.js` to `semantic.d.ts` by
extension substitution.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(release): gate publish behind publint and attw

Packages point `exports` at `src/` and swap it for `dist/` via
`publishConfig.exports`, a pnpm-only behaviour. The published export map is
therefore never exercised by a local build, typecheck, or test run — which is how
accordion, grid, reset and tokens all shipped export maps that do not resolve.

Pack every package with pnpm and validate the resulting tarball, the same bytes
the registry receives. `npm pack` cannot be used: it ignores the publishConfig
swap, so every entrypoint reports as unresolvable. CSS subpaths are excluded from
attw only, since stylesheets never carry type declarations; publint still proves
they are in the tarball. `changeset publish` now runs behind this check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: run the publishability gate on pull requests

Gating only at publish time would surface a broken export map after the version
PR is already merged. As a parallel job it costs no extra wall-clock, and it
gates the changesets version PR itself. The work is skipped when the diff cannot
affect a tarball, while the job still runs so it stays usable as a required check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: serialize releases with a concurrency group

Two merges landing while a release is in flight would run `changeset publish`
concurrently against the registry. Cancellation stays off: interrupting a publish
mid-flight is how packages end up half-released.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: drop the paths filter from the publishability gate

Skipping the gate when the diff could not affect a tarball took an eleven-line
diff step, two step-level conditions, and a full-depth checkout. It bought only
runner time on docs-only pull requests — the job runs alongside CI, so it never
cost wall-clock to begin with. Not worth the machinery.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: run the publishability check as its own release step

The `release` script existed only because changesets/action does not run its
`publish` input through a shell, so the check could not be chained onto it. A
step before the action gates the publish just as well — a failure there fails the
job, so the action never runs. That drops the script, and with it the footgun of
a `pnpm release` that looks like a dry run and is not.

`pnpm lint:publish` stays, so the gate is still runnable locally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(www): render workspace components in Docusaurus and document Accordion

The docs site had no path for rendering a workspace component: www declared no
@sipe-team dependency, and workspace `exports` resolves to raw `src/*.ts`, which
webpack cannot consume. Add the vanilla-extract webpack plugin so Docusaurus
compiles the packages' `.css.ts` from source — docs pages import @sipe-team/*
directly, with no prebuilt dist, alias table, CSS injection, or build ordering.
Adding a component is then just a www dependency plus its MDX page.

- add Preview: renders children server-side with a "Show code" toggle. No
  react-live, no BrowserOnly — an example that only appeared after hydration
  would not prove the component server-renders
- accordion.mdx with hand-written prop tables read off the source. No prop
  extraction, so packages/ stays untouched
- _TEMPLATE.md fixes the five core sections; Accessibility and Known
  limitations are optional trailing sections a component adds when warranted

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(www): give Preview a dark stage and tighten its frame

Dark-only components landed as a dark card floating on a light neutral frame,
which read as a broken render. Add an opt-in `theme="dark"` to Preview that
swaps the stage to a dark canvas, so the example reads as deliberate; the
Accordion examples use it. Also compact the stage padding and fold the
"Show code" toggle into the card as a left-aligned footer instead of a
floating right-aligned button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(www): document Button, the first vars-consuming component (#298)

* docs(www): document Button and make the token chain survive production

Button is the only component that reads `vars`, so it's the first to need the
Style Dictionary value layer — and it exposed a production-only break: every
`var(--side-*)` resolved to nothing while dev worked and hid it.

Root cause: under source compilation the token bridge was emitted twice — once
by the injected `@sipe-team/tokens/styles.css`, and again by vanilla-extract
recompiling tokens' `themes.css.ts` through Button's `vars` import. Docusaurus's
advanced cssnano collapses the duplicated `@layer theme { … }` to a bare
`@layer theme;`, stripping the whole bridge.

Fix:
- alias `@sipe-team/tokens` to its built dist so its theme is compiled once
  (via `build:tokens`); the bridge now has a single copy and full CSS
  minification stays on. Components still compile from source
- inject `@sipe-team/tokens/styles.css` for the Style Dictionary value layer
  (`--color-*` etc.), which is not vanilla-extract and can't come from source

button.mdx documents variant/size/leftIcon/rightIcon/asChild from source, with
hand-written prop tables. packages/ is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(www): sharpen Button captions, fix Back arrow, clarify disabled example

- Variant/Size captions now say when to reach for each option instead of just
  restating the names, matching the accordion pilot's teaching tone
- the "With icons" example pointed a right chevron at "Back"; split the inline
  icon into ArrowLeft/ArrowRight so Back points left and Next points right
- the Disabled example showed two identical unlabelled buttons; label them
  Fill/Outline and note that disabled styling is uniform across variants, so the
  sameness reads as an intentional demonstration rather than a mistake

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Merge pull request #299 from sipe-team/docs/avatar-docs-jinho

docs(www): document Avatar (+ fix onError loop and asChild sizing)

* docs(www): document Checkbox (+ fix inline SVG assets and defaultChecked warning) (#301)

* fix(checkbox): inline SVG marks and consume defaultChecked

- inline the check/indeterminate marks as data: URIs instead of
  url("public/*.svg"); esbuild resolved those paths but source-compiling
  consumers (webpack + vanilla-extract plugin, e.g. the docs site) could not,
  breaking their production build
- destructure defaultChecked in Root so it seeds the uncontrolled initial state
  only and no longer leaks through context onto the input alongside the
  always-set checked, which triggered React's checked+defaultChecked warning

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(www): document Checkbox

Add the Checkbox component docs page (Preview-based MDX) covering the
Root/Input/Label parts, controlled/uncontrolled usage, indeterminate and
disabled states, and the API reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(checkbox): keep the inlined mark SVGs readable

Store the check/indeterminate marks as plain SVG markup and encode them with
encodeURIComponent at build time (via a small svgToDataUri helper) instead of a
hand-encoded data-URI blob. Same portable data-URI output, but the source stays
readable and editable. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(www): document Typography (#300)

Add the Typography component docs page (Preview-based MDX) covering usage,
size/weight/color examples, the asChild semantic-element note, anatomy, and
the API reference. Also refresh _TEMPLATE.md to describe the source-compilation
setup instead of the stale dist-alias note.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(flex): support responsive prop values (#284)

* feat(flex): support responsive prop values

* test(flex): cover responsive prop contract

* docs(flex): add responsive story

* fix(flex): export responsive helper types

* fix(flex): isolate responsive gap values

---------

Co-authored-by: Jinho Yeom <81306489+Yeom-JinHo@users.noreply.github.com>
Co-authored-by: Evan <clcl6084@gmail.com>
Co-authored-by: 이원주 <101818687+3o14@users.noreply.github.com>
Co-authored-by: KYBee <kybee@KYBeeui-Macmini.local>
Co-authored-by: 오소현 <53892427+osohyun0224@users.noreply.github.com>
Co-authored-by: Minji Jeon <105787441+minji0214@users.noreply.github.com>
Co-authored-by: MinjiJeon <jinnyjeon@sweetspot.co.kr>
Co-authored-by: y09n <euihyun.yang.9x@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinho Yeom <pwlsghq@naver.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants