npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@orioncactuscorp/ui

v1.14.0

Published

orioncactus UI foundations and core primitives

Readme

@orioncactuscorp/ui

orioncactus 디자인 시스템의 React 19+ UI package입니다.

Resources

  • Storybook — 최신 컴포넌트와 사용 예시
  • Changelog — 이 패키지 버전까지의 전체 변경 내역
  • Documentation — 이 패키지 버전에 고정된 상세 가이드

요구사항

  • React 19+, React DOM 19+
  • Node 22+
  • 브라우저: color-mix()를 지원하는 evergreen 브라우저 — Chrome/Edge 111+, Safari 16.2+, Firefox 113+
  • CSS Modules와 CSS @layer를 처리하는 bundler
  • package manager: npm-compatible package manager

공개 계약의 범위와 breaking change 기준은 Stability Policy를 참조하세요.

설치

bun
bun add @orioncactuscorp/ui @orioncactuscorp/icons
npm
npm install @orioncactuscorp/ui @orioncactuscorp/icons
yarn
yarn add @orioncactuscorp/ui @orioncactuscorp/icons
pnpm
pnpm add @orioncactuscorp/ui @orioncactuscorp/icons

앱 코드에서 아이콘을 직접 import한다면 @orioncactuscorp/icons를 consumer repository의 direct dependency로 함께 설치하세요. @orioncactuscorp/ui 컴포넌트 내부 indicator만 사용한다면 별도 작업은 필요 없습니다.

사용

앱 root에서 foundations.css(토큰 + reset)를 한 번 import합니다. 컴포넌트 스타일은 컴포넌트를 import하면 사용한 컴포넌트만 자동으로 함께 로드됩니다.

import '@orioncactuscorp/ui/foundations.css';
import { IconDefault } from '@orioncactuscorp/icons';
import { Button, IconButton } from '@orioncactuscorp/ui';

export default function Example() {
  return (
    <>
      <Button>확인</Button>
      <IconButton aria-label='기본 아이콘'>
        <IconDefault />
      </IconButton>
    </>
  );
}
  • foundations.css는 항상 필요합니다. 컴포넌트 CSS에는 토큰 정의가 없어, 이 import를 빠뜨리면 모든 컴포넌트의 색·여백·타이포가 깨집니다.
  • 컴포넌트 CSS 자동 로드는 CSS Modules를 처리하는 번들러(Next.js, Vite 등)를 전제로 합니다. 번들러가 없거나 CSS Modules를 처리하지 못하는 환경에서는 아래 CSS-only 환경 절의 styles.css를 사용합니다.

Documentation

이 패키지는 상세 가이드를 docs/로 함께 배포합니다. 설치 후 node_modules/@orioncactuscorp/ui/docs/에서 설치 버전과 일치하는 문서를 바로 읽을 수 있고, 웹에서는 https://cdn.jsdelivr.net/npm/@orioncactuscorp/[email protected]/docs/<파일명>으로 볼 수 있습니다.

| 문서 | 내용 | | -------------------------------------------------------------- | ------------------------------------------------------------------------ | | API Naming Conventions | variant, appearance, size prop의 역할과 명명 규칙 | | Selector Contract | data-oc-* 기반 커스터마이즈 계약 — 컴포넌트별 selector/slot/state 표 | | Semantic Colors | 57개 semantic color의 역할, light/dark 기본값, pairing 규칙 | | Typography | 19개 variant의 용도, responsive stop, line-height, weight | | SCSS Helpers | oc-border, oc-radius, oc-alpha, typo, respond-to, fluidClamp | | Semantic Motion | intent/phase/pace 기반 motion 계약과 reduced-motion 정책 | | Spring Motion | iOS perceptual duration 기반 spring transition | | Responsive Foundation Profile | typo/space responsive 출력 mode 컴파일 설정 | | Token Reference | --oc-* foundation 토큰 전체 목록 | | Stability Policy | 공개 계약 범위, SemVer 기준, deprecation 절차 | | Editor Setup | VS Code CSS 변수 자동완성 설정 |

Components

  • SectionHeader
  • Button, TextButton, IconButton, BackgroundIconButton
  • ActionArea, ActionAreaButton, ActionAreaLayout
  • Badge, Background, Divider, Loading, Skeleton, Cell, CellItem
  • CheckMark
  • Field, FieldLabel, FieldControl, FieldMessage, FieldErrorMessage (vertical/horizontal orientation)
  • Fieldset, FieldLegend, FieldsetContent, FieldGroup
  • Checkbox, Radio, Switch
    • 단순 상태 관리에는 onCheckedChange(checked), form 통합에는 native onChange를 사용하세요 (발화 순서: onChangeonCheckedChange). CheckMark 동일.
  • TextInput, TextInputContent
  • TextArea, TextAreaContent
  • Select, SelectContent
  • MenuRoot, MenuTrigger, MenuContent, MenuItem, MenuSeparator
  • Alert, AlertRoot, AlertContent, AlertHeading, AlertDescription, AlertActionArea, AlertAction
  • Accordion, AccordionItem, AccordionSummary, AccordionDetails, AccordionDescription, AccordionContent
  • TabsRoot, TabsList, TabsTab, TabsPanel
  • Modal, ModalRoot, ModalTrigger, ModalContent, ModalHeader, ModalNavigationSection, ModalBody, ModalFooter, ModalClose
  • FloatingWindow, FloatingWindowManager, FloatingWindowRoot, ModalWindowRoot, FloatingWindowTrigger, FloatingWindowContent, FloatingWindowDragHandle, FloatingWindowHeader, FloatingWindowNavigationSection, FloatingWindowBody, FloatingWindowFooter, FloatingWindowTitle, FloatingWindowDescription, FloatingWindowClose
  • TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent
  • ScrollArea, ScrollAreaContainer
  • SvgIcon, Interaction

Modal initial focus

Modal은 DOM 순서의 첫 control을 기계적으로 선택하지 않습니다. 기본 initialFocus="auto"ModalHeader의 title을 tabIndex={-1}인 정적 문맥 시작점으로 포커스하고, title이 없을 때만 첫 tabbable 요소로 fallback합니다. modeless surface는 현재 작업 포커스를 유지합니다.

  • 일반 Modal과 ModalWindowRoot는 같은 초기 포커스 정책을 공유합니다.
  • form은 ref/function으로 첫 입력을, 단순 진행 dialog는 주요 action을 명시할 수 있습니다.
  • 되돌리기 어려운 확인 dialog는 취소처럼 가장 덜 파괴적인 action을 ref로 지정하세요.
  • initialFocus="first-interactive"는 첫 tabbable 요소, initialFocus="title"은 등록된 title을 명시합니다.
  • initialFocus="content"는 dialog container를 포커스하는 호환용 escape hatch입니다. 신규 사용은 title 또는 구체적인 ref/function을 우선하세요.

FloatingWindow

FloatingWindowRoot는 trigger 또는 명시적 anchor를 기준으로 collision-aware 배치되는 modeless dialog가 기본입니다. ModalWindowRoot는 같은 geometry에 focus trap, 배경 입력을 차단하는 backdrop, Modal popup scale/fade motion을 적용합니다. 필요한 경우에만 FloatingWindowContent backdrop="hidden"으로 dimmer를 숨길 수 있으며 modal focus와 배경 inert 정책은 유지됩니다. Header, Body, Footer, NavigationSection은 Modal 기본 presentation을 공유합니다.

import {
  FloatingWindowBody,
  FloatingWindowContent,
  FloatingWindowFooter,
  FloatingWindowHeader,
  FloatingWindowManager,
  FloatingWindowRoot,
  FloatingWindowTrigger,
  ActionArea,
  ActionAreaButton,
} from '@orioncactuscorp/ui';

<FloatingWindowManager>
  <FloatingWindowRoot windowId='notes'>
    <FloatingWindowTrigger>메모 열기</FloatingWindowTrigger>
    <FloatingWindowContent placement='rightTop' resize='fixed'>
      <FloatingWindowHeader title='프로젝트 메모' />
      <FloatingWindowBody>임의 콘텐츠</FloatingWindowBody>
      <FloatingWindowFooter>
        <ActionArea variant='neutral'>
          <ActionAreaButton priority='alternative'>취소</ActionAreaButton>
          <ActionAreaButton priority='main'>저장</ActionAreaButton>
        </ActionArea>
      </FloatingWindowFooter>
    </FloatingWindowContent>
  </FloatingWindowRoot>
</FloatingWindowManager>;
  • modeless 창은 외부 pointer 작업으로 닫히지 않으며 Escape와 명시적 close로 닫습니다.
  • placement 또는 side + alignment는 trigger 기준 배치를 정합니다. placement를 지정하면 sidealignment보다 우선합니다.
  • 기본 collision 정책은 주축 flip, 정렬축 shift입니다. 따라서 오른쪽 공간이 부족한 right 창은 왼쪽으로 전환되고, 아래 공간이 부족한 bottom 창은 위쪽으로 전환됩니다.
  • anchor로 trigger 대신 element, ref, resolver 함수를 기준점으로 사용할 수 있습니다. 열려 있는 anchored window는 anchor가 크기 변화 없이 layout에서 이동해도 좌표를 다시 맞춥니다.
  • 창을 drag하면 anchor에서 분리되어 free window가 됩니다. position은 controlled 자유 좌표, defaultPosition은 처음부터 분리된 초기 좌표입니다.
  • onPositionChange는 anchor 재배치, drag, viewport 보정 중 좌표 변경을 알리고, onPositionCommit은 drag 종료 좌표를 저장할 때 사용합니다.
  • collisionBoundary는 기본 viewport이며 특정 element를 전달하면 해당 element의 화면상 rect를 배치·이동 경계로 사용합니다.
  • 기본 dragHandleVisibility={48}은 viewport 높이가 줄어도 drag handle의 48px을 남겨 창을 복구할 수 있게 합니다.
  • resize="fixed"는 Modal popup과 같은 고정 높이 surface를 사용합니다. Body가 넘치면 내부만 스크롤되고 Header와 Footer의 경계 상태가 자동 갱신됩니다.
  • Footer의 기본 action 조합은 Modal과 동일하게 ActionAreaActionAreaButton을 사용합니다.
  • ModalWindowRoot는 배경을 inert 처리하고 focus를 가두는 application modal입니다. 배경 pointer 작업만 허용하고 focus는 창에 유지해야 하면 FloatingWindowRoot modal='trap-focus'를 사용합니다.
  • modeless FloatingWindowRoot는 기본적으로 현재 focus를 유지하며, ModalWindowRoot는 Modal과 동일하게 등록된 title을 초기 focus로 사용합니다. initialFocus를 명시하면 두 root 모두 해당 정책을 우선합니다.
  • FloatingWindowClose의 접근성 이름은 명시한 aria-label을 우선하고, 없으면 label(기본값 닫기)을 사용합니다.
  • FloatingWindowHeaderFloatingWindowNavigationSection은 surface 최상단을 소유하는 대체형 chrome입니다. Navigation을 사용할 때는 title이 기본적으로 dialog 접근성 이름을 제공합니다.
  • Header와 명시적인 FloatingWindowDragHandle에서 drag를 시작할 수 있습니다. 내부 interactive element는 자동 제외되며 custom interactive target은 data-oc-window-no-drag를 선언할 수 있습니다.
  • FloatingWindowManager는 열린 창을 등록하고 open, pointer, focus 활성화 순서에 따라 stack level을 정규화합니다. Manager 안의 각 root에는 고유한 windowId가 필요합니다.
  • Escape와 outside dismissal은 활성 창 하나에만 적용됩니다. 활성 창의 종료 모션이 끝나면 바로 아래 창이 활성화되며, 개별 창의 geometry나 position 저장은 Manager가 소유하지 않습니다.
  • 비활성 modeless 창의 명시적 Close는 창을 활성화하거나 최상단으로 올리지 않고 현재 stack 위치에서 종료합니다.
  • modeless 창의 활성화는 stacking만 변경하며 포커스를 강제로 이동하지 않습니다. 닫힐 때의 포커스 복원은 각 Dialog trigger 계약을 따릅니다.
  • modal과 trap-focus 창은 focus isolation을 보호하기 위해 modeless 창보다 위에 유지됩니다. 같은 modality tier 안에서는 최근 활성화한 창이 위로 이동합니다.
  • focus-owning 창이 여러 개 열리면 활성 창 하나만 실제 modal/inert owner가 됩니다. 아래 modal은 요청한 modality와 stack tier를 유지한 채 대기하고, 위 창 종료 후 focus isolation을 승계합니다.
  • Manager 밖에서는 기존 단일 창 동작을 유지합니다. onActivate, stackLevel은 외부 coordinator를 위한 unmanaged escape hatch이며 Manager 안에서는 자동 stack level이 우선합니다.

Customization

컴포넌트 커스터마이즈는 CSS Module 해시가 아니라 안정 data attribute와 component contract 변수를 사용합니다.

  • [data-oc-component='<name>'] — 컴포넌트 루트
  • [data-oc-part='<slot>'] — 안정 내부 slot
  • [data-oc-variant], [data-oc-size], [data-oc-state] 등 — 시각/상태 selector
  • --oc-{component}-* — component contract 변수 override
[data-oc-component='cell-item'][data-oc-interactive='true']
  [data-oc-part='label'] {
  font-weight: 600;
}

이 selector들은 버전 관리되는 계약입니다. 컴포넌트별 전체 표는 Selector Contract를 참조하세요.

Exports

| Subpath | 내용 | | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | @orioncactuscorp/ui | 컴포넌트 root barrel | | @orioncactuscorp/ui/foundations.css | foundation 토큰 + reset 번들 | | @orioncactuscorp/ui/foundations/*.css | foundation별 부분 CSS. @layer 래핑과 reset이 없으므로 일반 사용은 foundations.css 권장 | | @orioncactuscorp/ui/reset.css | reset 단독 (SCSS source compile 시 사용) | | @orioncactuscorp/ui/styles.css | 전 컴포넌트 스타일 단일 파일 (파운데이션 내장). CSS Modules 번들러가 없는 환경용 대안 | | @orioncactuscorp/ui/scss/* | SCSS source (foundations, mixins) | | @orioncactuscorp/ui/scss/index.scss | SCSS source compile용 통합 entry (foundation CSS를 방출하므로 foundations.css와 함께 쓰지 않음) | | @orioncactuscorp/ui/scss/foundations/responsive.config | responsive 출력 mode 설정 | | @orioncactuscorp/ui/utils/breakpoints | getBreakpoint/getBreakpoints — runtime breakpoint 값 조회 | | @orioncactuscorp/ui/utils/spring | ocSpring, createSpringAnimator | | @orioncactuscorp/ui/utils/motion | motion intent/phase/pace vocabulary와 resolve 유틸 | | @orioncactuscorp/ui/react/spring | useSpringTarget, useSpringValue | | @orioncactuscorp/ui/react/motion | MotionExpand |

React Server Components

@orioncactuscorp/ui는 root barrel 전체를 client boundary로 승격하지 않고, 실제 client-only component/module entry에만 'use client' directive를 보존합니다. Next App Router Server Component에서 root barrel로 Button 같은 interactive component를 import해도 leaf boundary가 유지되도록 package build에서 검증합니다.

Client Component에 전달하는 prop은 React Server Components의 serializable prop 제약을 따릅니다. Server Component에서 onClick 같은 function prop을 직접 넘겨야 하는 경우에는 해당 사용 지점을 Client Component로 분리하세요.

Foundation

일반적인 사용은 prebuilt foundations.css(토큰 + reset)를 앱 root에서 한 번 import합니다. 컴포넌트 스타일은 컴포넌트를 import할 때 자동으로 로드되므로 별도 import가 필요 없습니다.

import '@orioncactuscorp/ui/foundations.css';

CSS-only 환경 (styles.css)

CSS Modules를 처리하는 번들러가 없는 환경(플레인 <script type="module">, CSS만 다루는 파이프라인 등)에서는 전 컴포넌트 스타일을 담은 단일 파일 styles.css를 사용합니다.

import '@orioncactuscorp/ui/styles.css';
  • styles.css는 파운데이션(토큰 + reset)을 이미 내장합니다. 이 파일을 쓸 때는 foundations.css를 함께 import하지 않습니다 — 함께 쓰면 파운데이션이 이중 로드됩니다.
  • 모든 컴포넌트 CSS를 포함하므로 사용하지 않는 컴포넌트 스타일도 로드됩니다(tree-shaking 없음). 번들러 환경에서는 위 컴포넌트 자동 로드 방식을 권장합니다.

Token Override

브랜드 색처럼 CSS token 값만 바꾸는 경우에는 import 이후 로드되는 CSS에서 필요한 theme selector의 --oc-* 값을 override합니다.

:root,
[data-theme='light'],
[data-theme='dark'] {
  --oc-color-theme-primary-normal: #ff5800;
}

Theming

prebuilt foundations.css의 theme 동작은 다음과 같습니다.

  • 기본은 light theme이고, OS가 dark를 선호하면 prefers-color-scheme: dark로 자동 전환됩니다.
  • data-theme='light' 또는 data-theme='dark' attribute를 지정하면 system preference와 무관하게 해당 theme으로 고정됩니다. <html>에 지정하면 전체, 하위 요소에 지정하면 해당 서브트리만 적용됩니다.
  • 각 theme selector는 같은 scope에 color-scheme: light 또는 color-scheme: dark를 선언해 네이티브 form control, scrollbar 등 브라우저 UI도 theme과 일치시킵니다. 이 동작을 원하지 않으면 package CSS import 이후 원하는 scope에서 color-scheme을 override하세요. 문서 전체의 <meta name='color-scheme'>theme-color 설정은 소비자 앱이 담당합니다.
  • next-themes처럼 color-scheme을 inline style로 관리하는 도구를 함께 사용하면 inline 선언이 foundation CSS보다 우선합니다. foundation에 제어를 위임하려면 해당 도구의 중복 제어를 끄고, 직접 관리한다면 data-theme과 같은 값으로 유지하세요.
  • 위 brand override 예시가 :root와 두 [data-theme] selector를 모두 덮는 이유는 이 세 가지 적용 경로를 전부 커버하기 위해서입니다. theme별로 다른 값이 필요하면 selector를 나눠 지정하세요.

theme 출력 자체를 바꾸려면(예: light 전용 출력, system preference 자동 전환 제거) SCSS foundation source를 compile하면서 color.config를 설정합니다.

@use '@orioncactuscorp/ui/scss/foundations/color.config' with (
  $oc-color-themes: (
    light,
  ),
  $oc-color-system-preference: false
);
  • $oc-color-themes: 출력할 theme 목록 (light, dark). 하나만 두면 그 theme이 :root 기본값이 됩니다.
  • $oc-color-system-preference: prefers-color-scheme 자동 전환 media 출력 여부입니다.

Foundation별 커스텀 방식은 아래 기준으로 나눕니다.

| 대상 | 기본 방식 | SCSS source compile 필요 여부 | | ------ | --------------------------------------------------------- | ------------------------------------------------ | | color | --oc-color-theme-* override | theme 출력 범위나 system preference 설정 변경 시 | | typo | $oc-typo-size-overrides, $oc-typo-height-overrides | 필요 | | space | $oc-space-overrides | 필요 | | atomic | radius, width, blur, shadow 같은 --oc-atomic-* override | 보통 불필요 |

--oc-typo-size-factor은 특정 요소나 section 안의 typography를 함께 키우거나 줄일 때 쓰는 runtime multiplier입니다. 예를 들어 article 영역의 읽기 크기를 전반적으로 키워야 할 때 해당 scope에 --oc-typo-size-factor: 1.1처럼 지정할 수 있습니다. html { font-size } 조정과는 영향 범위가 다릅니다 — root font-size는 rem 기반 typography·spacing·radius 전체를 움직이고, --oc-typo-size-factor는 typo mixin이 출력한 font-size/line-height에만 적용됩니다.

--oc-atomic-radius-factor는 atomic radius와 radius helper를 거친 component-local radius를 함께 키우거나 줄이는 runtime multiplier입니다. 0으로 지정하면 --oc-atomic-radius-max를 포함한 radius token이 모두 각진 형태가 되며, 기존 --oc-atomic-radius-* token 이름은 그대로 유지됩니다.

Focus Ring

키보드 포커스(:focus-visible) ring은 reset 레이어의 전역 기본값으로 제공됩니다. button, a[href], summary, [tabindex] 요소에 자동 적용되며, ring은 요소의 border-radius를 그대로 따라갑니다. text-entry 컨트롤(input/textarea/select)은 제외되고 Field 계열의 :focus-within stroke가 포커스를 표현합니다.

  • --oc-focus-ring-width, --oc-focus-ring-offset — 두께/offset 토큰
  • --oc-color-theme-focus-ring — ring 색 (기본: --oc-color-theme-primary-normal alias, theme별 override 가능)
  • 컴포넌트/커스텀 요소에 직접 적용할 때는 @include oc-focus-ring 믹스인을 사용합니다.
  • opt-out: 전역 규칙은 :where()라 specificity 0입니다. 해당 요소에 outline: none을 선언하면 덮어집니다 (프로그램 포커스 표면 등).

Typography나 spacing token의 responsive 출력 방식까지 바꿔야 하는 경우에는 foundations.css 대신 SCSS foundation source를 직접 compile할 수 있습니다. 이때 foundations.css를 대체하므로 reset은 별도로 import합니다. 컴포넌트 스타일은 이 경우에도 컴포넌트를 import할 때 자동으로 로드됩니다.

import '@orioncactuscorp/ui/reset.css';
import './styles/foundations.scss';

SCSS Profile

전체 설정 옵션과 동작은 Responsive Foundation Profile을 참조하세요. responsive.configtypospace의 responsive 출력 mode를 정합니다. $oc-responsive-mode는 공통으로 적용하고, active stop range는 foundation별로 따로 지정할 수 있습니다. space는 stepped mode에서 base/media point별 target stop도 지정할 수 있습니다.

$oc-responsive-mode는 아래 값을 사용합니다.

  • fluid: 기본값. stop 사이를 clamp() 기반 fluid value로 보간합니다.
  • stepped: stop 값을 breakpoint에서 계단식으로 전환합니다.
  • static: 선택한 stop 하나를 전체 viewport에 고정합니다.
@use '@orioncactuscorp/ui/scss/foundations/responsive.config' with (
  $oc-responsive-mode: stepped,
  $oc-responsive-typo-stops: (
    sm,
  ),
  $oc-responsive-space-stops: (
    md,
    lg,
    xl,
  ),
  $oc-responsive-space-profile: (
    type: stepped-points,
    points: (
      base: md,
      min-md: max-active-defined,
    ),
  )
);

@use '@orioncactuscorp/ui/scss/foundations/color.global' as *;
@use '@orioncactuscorp/ui/scss/foundations/color.theme.light' as *;
@use '@orioncactuscorp/ui/scss/foundations/color.theme.dark' as *;
@use '@orioncactuscorp/ui/scss/foundations/breakpoint' as *;
@use '@orioncactuscorp/ui/scss/foundations/typo' as * with (
  $oc-typo-size-overrides: (
    title1: (
      sm: 36,
    ),
  ),
  $oc-typo-height-overrides: (
    title1: (
      sm: 48,
    ),
  )
);
@use '@orioncactuscorp/ui/scss/foundations/space' as * with (
  $oc-space-overrides: (
    section-padding-viewport-x: (
      md: 20,
      xl: 32,
    ),
  )
);
@use '@orioncactuscorp/ui/scss/foundations/atomic' as *;
@use '@orioncactuscorp/ui/scss/foundations/motion' as *;
@use '@orioncactuscorp/ui/scss/foundations/zindex' as *;

:root,
[data-theme='light'],
[data-theme='dark'] {
  --oc-color-theme-primary-normal: #ff5800;
}

SCSS foundation profile은 compile-time 설정입니다. Prebuilt foundations.css 또는 styles.css import에는 적용되지 않습니다.

SCSS Helpers

SCSS mixin/function 전체 시그니처와 예시는 SCSS Helpers 가이드를 참조하세요. 아래는 대표 helper 요약입니다.

| Helper | 모듈 | 용도 | | ---------------------------------- | ------------------------ | ----------------------------------------------------------------------- | | oc-border(...) | scss/mixins/element | layout에 영향 없는 box-shadow surface stroke (side/placement 지정 가능) | | oc-radius($radius) | scss/mixins/radius | 컴포넌트 로컬 radius를 전역 radius factor에 연결 | | oc-alpha($color, $opacity) | scss/mixins/color | CSS 변수 색상에도 동작하는 color-mix 기반 알파 | | @include typo($variant, $weight) | scss/mixins/typo | typo 토큰 조합 출력 (--oc-typo-size-factor 반영) | | @include respond-to(...) | scss/mixins/breakpoint | breakpoint media query (named/직접 값/구간) | | fluidClamp(...), toRem($px) | scss/mixins/utils | 커스텀 fluid 값 생성 |

@orioncactuscorp/ui/scss/mixins/element는 요소 표면을 구성할 때 쓰는 SCSS helper를 제공합니다.

oc-border는 실제 CSS border 대신 inset box-shadow로 안쪽 border를 그립니다. 요소의 content, padding, layout 크기를 바꾸지 않는 surface stroke가 필요할 때 사용합니다.

@use '@orioncactuscorp/ui/scss/mixins/element' as *;

.surface {
  @include oc-border;
}

.surfaceAccent {
  @include oc-border(var(--oc-color-theme-primary-normal));
}

.surfaceInvalid {
  @include oc-border(1.5px, var(--oc-color-theme-status-negative));
}
  • @include oc-border1px currentColor inset border를 출력합니다.
  • @include oc-border(black)처럼 색상만 넘기면 1px black inset border를 출력합니다.
  • @include oc-border(1.5px, var(--color))처럼 width와 color를 함께 넘길 수 있습니다.
  • 1.5px, 2.5px, 3.5px 같은 half-pixel px width는 WebKit/DPR 보정을 함께 출력합니다.

oc-radius($radius, $factor-token: var(--oc-atomic-radius-factor))rem, em, px, clamp(...) 기반 radius 값을 전역 radius factor에 연결합니다. 컴포넌트 로컬 radius contract가 typography-relative em 값을 유지하면서도 전역 radius 정책을 따라야 할 때 사용합니다.

@use '@orioncactuscorp/ui/scss/mixins/radius' as *;

.badge {
  --oc-badge-radius: #{oc-radius(0.4em)};
}

Icons

@orioncactuscorp/ui@orioncactuscorp/icons를 dependency로 사용합니다. Checkbox, Radio, Select, Accordion, ModalClose 같은 컴포넌트 내부 indicator를 별도 설정 없이 렌더링합니다.

앱 코드에서 아이콘을 직접 사용할 때는 @orioncactuscorp/icons에서 import합니다.

import { IconClose, IconDefault } from '@orioncactuscorp/icons';

@orioncactuscorp/ui는 앱 코드용 icon export를 제공하지 않습니다.

아이콘 세트를 나중에 교체할 계획이 있으면, 컴포넌트마다 직접 import하지 말고 앱 내부 icon registry를 거쳐 import하세요.

Motion

intent별 정책과 reduced-motion 동작 전체는 Semantic Motion 가이드를 참조하세요. Motion은 duration/easing 숫자를 직접 고르는 대신 feedback, fade, disclosure, surface, sheet, expand 같은 intent 기준으로 작성합니다. oc-motion은 intent, phase, pace를 기반으로 duration token, spring profile, reduced-motion 정책을 함께 적용합니다.

@include oc-motion(
  $properties,
  $intent,
  $phase: change,
  $pace: normal,
  $duration-factor: 1,
  $reduced: auto,
  $duration-token: null,
  $extra-bounce: null
);
@use '@orioncactuscorp/ui/scss/mixins/motion' as *;

.button {
  @include oc-motion((background-color, color), feedback);
}

.notice {
  @include oc-motion(opacity, fade);
}

.popover {
  @include oc-motion((opacity, transform), disclosure);
}

.accordionPanel {
  @include oc-motion(block-size, expand, $phase: enter);
}

일반 컴포넌트와 consumer SCSS에서는 oc-motion을 우선 사용하고, 직접 spring parameter를 설계해야 하는 고급 케이스에서만 oc-spring을 사용합니다.

spring-backed motion의 반동만 국소 조정해야 할 때는 $extra-bounce를 사용할 수 있습니다. non-spring motion에서는 사용할 수 없고, transform entrance처럼 overshoot가 의미 있는 property에 제한적으로 사용합니다.

Motion Factor

Motion factor는 transform scale, 이동 거리, duration의 전역 강도를 조정하는 runtime token입니다. 기본값보다 작으면 효과가 약해지거나 짧아지고, 크면 효과가 강해지거나 길어집니다. 전체 tone은 parent token으로 먼저 맞추고, 특정 intent만 달라야 할 때 child token을 override합니다.

spatial factor는 intent가 아니라 scale/translate amplitude group입니다. disclosure, surface, sheet, expand, move처럼 UI의 공간 관계를 설명하는 motion에 적용됩니다.

| Token | 기본값 | 비고 | | -------------------------------------- | ---------------------------------- | ---------------------------------------- | | --oc-motion-scale-factor | 1 | 전체 transform scale amplitude | | --oc-motion-scale-factor-feedback | var(--oc-motion-scale-factor) | press, hover, selected | | --oc-motion-scale-factor-spatial | var(--oc-motion-scale-factor) | disclosure, surface, sheet, expand, move | | --oc-motion-distance-factor | 1 | 전체 translate/reject 거리 | | --oc-motion-distance-factor-reject | var(--oc-motion-distance-factor) | reject shake | | --oc-motion-distance-factor-spatial | var(--oc-motion-distance-factor) | disclosure, surface, sheet, expand, move | | --oc-motion-duration-factor | 1 | 전체 duration. 작으면 빠르고 크면 느림 | | --oc-motion-duration-factor-reduced | 0.75 | reduced-motion fade/feedback | | --oc-motion-duration-factor-preserve | 1 | reduced-motion preserve | | --oc-motion-pace-quick | 0.75 | quick pace duration multiplier | | --oc-motion-pace-normal | 1 | normal pace duration multiplier | | --oc-motion-pace-slow | 1.35 | slow pace duration multiplier |

Runtime Motion

React에서 height expand처럼 CSS transition만으로 안정적으로 다루기 어려운 motion은 @orioncactuscorp/ui/react/motion subpath를 사용합니다. MotionExpand는 같은 intent, phase, pace, extraBounce, reduced vocabulary로 layout size를 JS spring animation에 연결합니다.

import { MotionExpand } from '@orioncactuscorp/ui/react/motion';

export function Panel({ open, children }) {
  return (
    <MotionExpand open={open} forceMount intent='expand' pace='normal'>
      {children}
    </MotionExpand>
  );
}

Spring

preset·physical spring·고급 옵션 전체는 Spring Motion 가이드를 참조하세요. SCSS에서는 iOS spring의 perceptual duration 기준으로 low-level transition을 작성할 수 있습니다. helper는 실제 CSS duration을 감쇠 settling duration으로 출력합니다.

transition: oc-spring($property, $duration, $preset: smooth, $extra-bounce: 0);
.box {
  transition: oc-spring(transform, 0.5s, snappy);
}

.custom {
  transition: oc-spring(transform, 0.5s, snappy, 0.1);
}

.menu {
  transition: oc-spring(
    (
      opacity: (
        0.3s,
        snappy,
      ),
      transform: (
        0.3s,
        snappy,
        0.1,
      ),
    )
  );
}

property별 tuple은 (duration, preset, extra-bounce, delay, samples) 순서입니다. physical spring과 고급 옵션은 named map을 사용합니다.

TS 런타임에서는 subpath util을 사용합니다.

import {
  createSpringAnimator,
  ocSpring,
} from '@orioncactuscorp/ui/utils/spring';

const spring = ocSpring.snappy({ duration: 0.5, extraBounce: 0.1 });

spring.settlingDuration; // 실제 CSS transition duration
spring.timingFunction; // linear(...) easing

const animator = createSpringAnimator({
  value: { x: 0, y: 0 },
  target: { x: 120, y: 80 },
  spring,
  onUpdate: value => {
    element.style.transform = `translate(${value.x}px, ${value.y}px)`;
  },
});

animator.setTarget({ x: 240, y: 120 }); // 현재 velocity를 이어받아 retarget

React component에서 spring 값을 렌더링해야 하면 hook subpath를 사용합니다. 일반적인 controlled target UI는 useSpringTarget으로 시작하고, 직접 retarget setter가 필요하면 useSpringValue를 사용합니다.

import { useState } from 'react';
import { useSpringTarget } from '@orioncactuscorp/ui/react/spring';
import { ocSpring } from '@orioncactuscorp/ui/utils/spring';

export function Follower() {
  const [target, setTarget] = useState({ x: 120, y: 80 });
  const position = useSpringTarget(target, {
    value: { x: 0, y: 0 },
    spring: ocSpring.snappy({ duration: 0.5 }),
  });

  return (
    <button
      type='button'
      style={{
        transform: `translate3d(${position.value.x}px, ${position.value.y}px, 0)`,
      }}
      onClick={() => setTarget({ x: 240, y: 120 })}
    >
      이동
    </button>
  );
}

VS Code CSS Variable Autocomplete

package는 VS Code CSS variable autocomplete 확장(phoenisx.cssvar)이 읽을 수 있는 foundation token index(dist/vscode/oc-ui-vars.css)를 함께 배포합니다. 설정 방법과 트러블슈팅은 Editor Setup을 참조하세요.

참고

라이선스

MIT

의견 나누기

GitHub 리포지터리 공개를 준비하고 있습니다. 그동안 의견이나 해결이 필요한 경우 [email protected]으로 편히 알려주세요.