@orioncactuscorp/ui
v1.6.0
Published
orioncactus UI foundations and core primitives
Maintainers
Readme
@orioncactuscorp/ui
orioncactus 디자인 시스템의 React 19+ UI package입니다.
요구사항
- React 19+, React DOM 19+
- Node 22+
- CSS Modules와 CSS
@layer를 처리하는 bundler - package manager: npm-compatible package manager
설치
bun
bun add @orioncactuscorp/ui @orioncactuscorp/iconsnpm
npm install @orioncactuscorp/ui @orioncactuscorp/iconsyarn
yarn add @orioncactuscorp/ui @orioncactuscorp/iconspnpm
pnpm add @orioncactuscorp/ui @orioncactuscorp/icons앱 코드에서 아이콘을 직접 import한다면 @orioncactuscorp/icons를 consumer repository의 direct dependency로 함께 설치하세요. @orioncactuscorp/ui 컴포넌트 내부 indicator만 사용한다면 별도 작업은 필요 없습니다.
사용
import '@orioncactuscorp/ui/foundations.css';
import '@orioncactuscorp/ui/styles.css';
import { IconDefault } from '@orioncactuscorp/icons';
import { Button, IconButton } from '@orioncactuscorp/ui';
export default function Example() {
return (
<>
<Button>확인</Button>
<IconButton aria-label='기본 아이콘'>
<IconDefault />
</IconButton>
</>
);
}Components
SectionHeaderButton,TextButton,IconButton,BackgroundIconButtonActionArea,ActionAreaButton,ActionAreaLayoutBadge,Background,Divider,Loading,Cell,CellItemCheckMarkField,FieldLabel,FieldControl,FieldMessage,FieldErrorMessage(vertical/horizontalorientation)Fieldset,FieldLegend,FieldsetContent,FieldGroupCheckbox,Radio,SwitchTextInput,TextInputContentTextArea,TextAreaContentSelect,SelectContentMenuRoot,MenuTrigger,MenuContent,MenuItem,MenuSeparatorAlert,AlertRoot,AlertContent,AlertHeading,AlertDescription,AlertActionArea,AlertActionAccordion,AccordionItem,AccordionSummary,AccordionDetails,AccordionDescription,AccordionContentModal,ModalRoot,ModalTrigger,ModalContent,ModalHeader,ModalBody,ModalFooter,ModalCloseTooltipProvider,TooltipRoot,TooltipTrigger,TooltipContentScrollArea,ScrollAreaContainerSvgIcon,Interaction
Exports
@orioncactuscorp/ui@orioncactuscorp/ui/foundations.css@orioncactuscorp/ui/reset.css@orioncactuscorp/ui/styles.css@orioncactuscorp/ui/scss/*@orioncactuscorp/ui/scss/foundations/responsive.config@orioncactuscorp/ui/utils/spring@orioncactuscorp/ui/utils/motion@orioncactuscorp/ui/react/spring@orioncactuscorp/ui/react/motion
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 CSS를 앱 root에서 한 번 import합니다.
import '@orioncactuscorp/ui/foundations.css';
import '@orioncactuscorp/ui/styles.css';브랜드 색처럼 CSS token 값만 바꾸는 경우에는 import 이후 로드되는 CSS에서 필요한 theme selector의 --oc-* 값을 override합니다.
:root,
[data-theme='light'],
[data-theme='dark'] {
--oc-color-theme-primary-normal: #ff5800;
}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처럼 지정할 수 있습니다.
--oc-atomic-radius-factor는 atomic radius와 radius helper를 거친 component-local radius를 함께 키우거나 줄이는 runtime multiplier입니다. 0으로 지정하면 --oc-atomic-radius-max를 포함한 radius token이 모두 각진 형태가 되며, 기존 --oc-atomic-radius-* token 이름은 그대로 유지됩니다.
Typography나 spacing token의 responsive 출력 방식까지 바꿔야 하는 경우에는 foundations.css 대신 SCSS foundation source를 직접 compile할 수 있습니다. 이때 foundations.css를 대체하므로 reset은 별도로 import합니다.
import '@orioncactuscorp/ui/reset.css';
import './styles/foundations.scss';
import '@orioncactuscorp/ui/styles.css';SCSS Profile
responsive.config는 typo와 space의 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
@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-border는1px currentColorinset border를 출력합니다.@include oc-border(black)처럼 색상만 넘기면1px blackinset 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
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
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를 이어받아 retargetReact 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 확장이 읽을 수 있는 foundation token index를 함께 배포합니다.
node_modules/@orioncactuscorp/ui/dist/vscode/oc-ui-vars.cssconsumer repository에서 phoenisx.cssvar 확장을 사용할 경우 .vscode/settings.json에 아래 설정을 추가합니다.
{
"cssvar.files": [
"./node_modules/@orioncactuscorp/ui/dist/vscode/oc-ui-vars.css"
]
}이 파일은 foundations.css에서 생성되므로 설치된 @orioncactuscorp/ui package 버전의 --oc-* foundation token과 자동완성 목록이 함께 움직입니다. 자동완성 전용 index이므로 runtime stylesheet로 import하지 않습니다.
참고
- wanteddev/montage-web: foundation, component state, slot, accessibility, interaction 설계 참고
라이선스
MIT
