@orioncactuscorp/ui 1.11.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -19
- package/dist/components/Accordion/Accordion.css +1 -1
- package/dist/components/BackgroundIconButton/BackgroundIconButton.css +1 -1
- package/dist/components/Button/Button.css +1 -1
- package/dist/components/Cell/Cell.css +1 -1
- package/dist/components/ScrollArea/ScrollArea.css +1 -1
- package/dist/components/Tooltip/Tooltip.css +1 -1
- package/dist/foundations/color.theme.dark.css +1 -1
- package/dist/foundations/color.theme.light.css +1 -1
- package/dist/foundations.css +2 -2
- package/dist/styles.css +8 -8
- package/docs/api-conventions.md +90 -0
- package/docs/colors.md +241 -0
- package/docs/scss-helpers.md +2 -2
- package/docs/tokens.md +4 -2
- package/docs/typography.md +115 -0
- package/package.json +1 -1
- package/src/scss/foundations/color-theme.test.ts +23 -8
- package/src/scss/foundations/color.theme.dark.scss +3 -1
- package/src/scss/foundations/color.theme.light.scss +2 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Component API Naming Conventions
|
|
2
|
+
|
|
3
|
+
`@orioncactuscorp/ui`는 컴포넌트의 시각적 선택지를 `variant`,
|
|
4
|
+
`appearance`, `size`로 일관되게 표현합니다. 이 규칙은 처음 사용하는
|
|
5
|
+
컴포넌트에서도 prop의 역할을 예측할 수 있게 하는 공개 API 계약입니다.
|
|
6
|
+
|
|
7
|
+
## 역할은 계약, 시각 값은 기본값
|
|
8
|
+
|
|
9
|
+
prop 이름과 TypeScript에 선언된 선택지는 버전 관리되는 계약입니다. 반면 각
|
|
10
|
+
선택지가 사용하는 색, 간격, 크기 같은 구체적인 시각 값은 디자인 시스템의
|
|
11
|
+
기본값입니다. 지원되는 token, component contract 변수, selector 계약을 통해
|
|
12
|
+
consumer가 조정할 수 있으며, 디자인 시스템 정책에 따라 변경될 수 있습니다.
|
|
13
|
+
|
|
14
|
+
지원되는 선택지의 정확한 목록은 각 컴포넌트의 TypeScript 선언을 기준으로
|
|
15
|
+
확인하세요. 모든 컴포넌트가 아래 축을 전부 제공하지는 않습니다.
|
|
16
|
+
|
|
17
|
+
## `variant`: 하나의 시각·표현 축
|
|
18
|
+
|
|
19
|
+
컴포넌트에 열거형 시각 또는 표현 축이 하나라면 `variant`를 사용합니다.
|
|
20
|
+
`variant`가 나타내는 구체적인 역할은 컴포넌트에 따라 의미·색, 강조 강도,
|
|
21
|
+
형태, surface 표현, layout 표현, slot content 종류 등이 될 수 있습니다.
|
|
22
|
+
|
|
23
|
+
상태, 간격, 동작처럼 독립된 개념은 `variant`에 합치지 않고 별도 prop으로
|
|
24
|
+
표현합니다.
|
|
25
|
+
|
|
26
|
+
## `appearance` + `variant`: 독립된 두 축
|
|
27
|
+
|
|
28
|
+
형태 또는 surface와 의미 또는 색을 각각 선택해야 하는 컴포넌트는 두 축을
|
|
29
|
+
분리합니다.
|
|
30
|
+
|
|
31
|
+
- `appearance`: 형태 또는 surface 처리
|
|
32
|
+
- `variant`: 의미 또는 색 의도
|
|
33
|
+
|
|
34
|
+
`Button`이 대표적인 예입니다. `appearance`는 `solid | outlined`, `variant`는
|
|
35
|
+
`default | primary | secondary | assistive`를 제공합니다.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<Button appearance='solid' variant='primary'>
|
|
39
|
+
저장
|
|
40
|
+
</Button>
|
|
41
|
+
|
|
42
|
+
<Button appearance='outlined' variant='assistive'>
|
|
43
|
+
도움말
|
|
44
|
+
</Button>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
이 분리는 형태와 의미를 하나의 조합 이름으로 합치지 않고 각 역할을 독립적으로
|
|
48
|
+
읽고 선택할 수 있게 합니다.
|
|
49
|
+
|
|
50
|
+
## `size`: 표준 크기 순서의 부분집합
|
|
51
|
+
|
|
52
|
+
named size의 표준 순서는 다음과 같습니다.
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
xsmall < small < medium < large
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
각 컴포넌트는 실제로 지원하는 크기만 부분집합으로 제공합니다. 예를 들어 어떤
|
|
59
|
+
컴포넌트가 `small | medium`만 제공하더라도 사용하지 않는 `xsmall`이나 `large`를
|
|
60
|
+
대칭성을 위해 추가하지 않습니다. TypeScript union의 선언 순서는 별도 계약이
|
|
61
|
+
아니며, 크기 비교에는 위 순서를 사용합니다.
|
|
62
|
+
|
|
63
|
+
### Named size 밖의 예외
|
|
64
|
+
|
|
65
|
+
named preset이 아니라 외부 문맥이나 직접 지정한 치수로 크기를 정해야 할 때만
|
|
66
|
+
다음과 같은 값을 허용합니다.
|
|
67
|
+
|
|
68
|
+
- `inherit`: owner의 typography·크기를 상속
|
|
69
|
+
- `custom`: component CSS가 치수를 결정
|
|
70
|
+
- 숫자 또는 자유 형식 값: primitive나 icon-sized control에 직접 치수를 전달
|
|
71
|
+
|
|
72
|
+
`TextButton`은 owner 안에서 자연스럽게 조합할 수 있도록 `size='inherit'`을
|
|
73
|
+
제공합니다. 색을 상속하는 `variant='inherit'`은 size가 아닌 variant 축의
|
|
74
|
+
선택지입니다.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
<TextButton variant='inherit' size='inherit'>
|
|
78
|
+
자세히 보기
|
|
79
|
+
</TextButton>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
새 named size가 필요할 때 `tiny`, `mini` 같은 별도 척도를 만들지 않습니다.
|
|
83
|
+
직접·custom·상속 크기가 필요한 경우에는 해당 예외의 목적을 컴포넌트 API에
|
|
84
|
+
문서화합니다.
|
|
85
|
+
|
|
86
|
+
## 현재 호환성 예외: Badge `tiny`
|
|
87
|
+
|
|
88
|
+
`Badge`의 `size='tiny'`는 표준 named size 밖에 있는 현행 호환성 예외입니다.
|
|
89
|
+
현재 public API는 유지하며, 다음 major 릴리스에서 `xsmall`로 정규화할
|
|
90
|
+
예정입니다. 변경 시 migration note로 안내합니다.
|
package/docs/colors.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Semantic Colors
|
|
2
|
+
|
|
3
|
+
oc-ui 색상 foundation은 `Global primitive → Theme semantic → Component contract`의 3단계로 사용합니다. Global primitive는 색상 램프와 opacity 숫자를 제공하고, Theme semantic은 light/dark 맥락에서 의미가 유지되는 역할 이름을 제공합니다. 컴포넌트에서는 primitive를 직접 고르기보다 semantic token을 우선하고, 컴포넌트별 상태·variant가 필요할 때 `--oc-{component}-*` contract로 한 번 더 연결합니다.
|
|
4
|
+
|
|
5
|
+
**역할 이름은 계약이고 값은 customizable 기본값입니다.** 아래 표는 패키지가 제공하는 기본 light/dark theme를 설명합니다. 제품 theme는 같은 역할 이름을 유지한 채 CSS variable 또는 SCSS theme config로 값을 바꿀 수 있습니다.
|
|
6
|
+
|
|
7
|
+
## 역할 가이드
|
|
8
|
+
|
|
9
|
+
### Static
|
|
10
|
+
|
|
11
|
+
`static-white`, `static-black`, `static-transparent`는 theme 전환과 무관하게 같은 물리 색을 유지해야 하는 경우에만 사용합니다. 로고 원색, 이미지 위의 고정 contrast icon처럼 의도가 명확한 표면이 대상입니다. 일반 본문이나 surface에 static 색을 쓰면 dark theme에서 역할이 뒤집히지 않으므로 피합니다.
|
|
12
|
+
|
|
13
|
+
### Primary
|
|
14
|
+
|
|
15
|
+
`primary-normal`은 브랜드의 주 행동, 선택 상태, 핵심 강조에 사용합니다. 페이지 전체의 장식색으로 넓게 칠하기보다 사용자가 다음 행동이나 현재 선택을 식별해야 하는 지점에 제한합니다.
|
|
16
|
+
|
|
17
|
+
### Focus ring
|
|
18
|
+
|
|
19
|
+
`focus-ring`은 `primary-normal`을 기본 alias로 삼지만 별도 리테마 지점입니다. 키보드 포커스 대비가 브랜드 primary로 충분하지 않은 제품은 이 token만 override할 수 있습니다. 컴포넌트와 커스텀 focusable 요소에서는 직접 outline을 조립하기보다 `@include oc-focus-ring`을 사용합니다.
|
|
20
|
+
|
|
21
|
+
### Label
|
|
22
|
+
|
|
23
|
+
label 단계는 콘텐츠 중요도와 상호작용 가능성을 나타냅니다. `strong`은 가장 강한 제목·핵심 값, `normal`은 기본 본문, `neutral`은 한 단계 낮은 본문, `alternative`는 부가 설명, `assistive`는 placeholder·hint, `disable`은 비활성 텍스트에 사용합니다. 단순히 더 연한 색이 필요하다는 이유로 단계를 건너뛰지 말고 정보 위계와 상태를 먼저 정합니다.
|
|
24
|
+
|
|
25
|
+
### Background
|
|
26
|
+
|
|
27
|
+
`background-normal-*`은 페이지 흐름의 기본 surface, `background-elevated-*`는 modal처럼 떠 있는 surface의 배경 짝입니다. 층위 구분의 기본 신호는 그림자와 dimmer이며 이는 light/dark 공통입니다 — elevated 색은 이를 대체하는 것이 아니라 **dark theme에서 추가되는 분리 신호**입니다. 어두운 배경에서는 그림자가 잘 드러나지 않으므로 떠 있는 표면을 base보다 밝은 단계로 올려 층위를 확실히 하고(iOS system background의 base/elevated 개념과 같은 접근), light 기본 theme에서는 base와 같은 값을 유지합니다(기본값 표 참조). 현행 컴포넌트의 대표 사용처는 Modal surface입니다. `normal`과 `alternative`는 인접 영역을 분리할 때 짝으로 사용합니다.
|
|
28
|
+
|
|
29
|
+
### Interaction
|
|
30
|
+
|
|
31
|
+
`interaction-inactive`는 아직 활성화되지 않은 control 면이나 indicator에, `interaction-disable`은 조작할 수 없는 control 면에 사용합니다. 비활성 control의 글자는 `label-disable`, 면은 `interaction-disable`로 구분합니다. 두 역할을 하나의 token으로 대체하면 theme별 대비가 쉽게 무너집니다.
|
|
32
|
+
|
|
33
|
+
### Line
|
|
34
|
+
|
|
35
|
+
`line-normal-*`은 alpha가 포함된 선으로 단일 surface 위의 구분선과 stroke에 사용합니다. 반투명 선을 중첩하면 예상보다 진해지므로 같은 위치에 여러 번 겹치지 않습니다. 중첩 가능성이 있거나 정확한 단색 경계가 필요한 layout에서는 대응하는 `line-solid-*`을 사용합니다. `strong → normal → neutral → alternative` 순서로 시각적 강도가 낮아집니다.
|
|
36
|
+
|
|
37
|
+
### Fill
|
|
38
|
+
|
|
39
|
+
`fill-normal`은 중립 control·선택 전 surface, `fill-strong`은 더 뚜렷한 중립 강조, `fill-alternative`는 가장 약한 보조 면에 사용합니다. 텍스트 역할을 fill로 대체하거나, primary 행동을 중립 fill만으로 표현하지 않습니다.
|
|
40
|
+
|
|
41
|
+
### Accent background
|
|
42
|
+
|
|
43
|
+
`accent-background-*`은 badge, status dot, chart mark처럼 색 자체가 면을 이루고 **텍스트 명도대비를 확보할 필요가 없는** 곳에 사용합니다. 같은 hue라도 명도대비가 필요한 텍스트·icon에는 `accent-foreground-*`을 사용합니다. 색상만으로 의미를 전달하지 말고 label, icon shape 또는 접근 가능한 이름을 함께 제공합니다.
|
|
44
|
+
|
|
45
|
+
### Accent foreground
|
|
46
|
+
|
|
47
|
+
`accent-foreground-*`은 **텍스트 명도대비를 준수하도록 조정된** 전경색입니다. 색상 텍스트·아이콘처럼 명도 확보가 필요한 곳에 사용하고, 명도대비가 필요 없는 단순 면에는 `accent-background-*`을 사용합니다. background token을 텍스트에 쓰면 대비 준수가 보장되지 않으므로 피합니다.
|
|
48
|
+
|
|
49
|
+
### Status
|
|
50
|
+
|
|
51
|
+
`status-positive`, `status-cautionary`, `status-negative`는 성공·주의·오류의 의미 역할이며 기본값은 대응 accent background의 alias입니다. 제품이 status palette를 별도로 운영할 때 alias 대상만 바꿀 수 있습니다. 단순 장식색에는 status token 대신 accent token을 사용합니다.
|
|
52
|
+
|
|
53
|
+
### Inverse
|
|
54
|
+
|
|
55
|
+
inverse trio는 tooltip처럼 기본 페이지와 명암이 반전된 surface를 하나의 묶음으로 구성합니다. `inverse-background` 위에 `inverse-label`을 놓고, 행동 강조가 필요하면 `inverse-primary`를 사용합니다. 일반 dark theme surface를 inverse로 대신 만들지 않습니다.
|
|
56
|
+
|
|
57
|
+
### Material
|
|
58
|
+
|
|
59
|
+
`material-dimmer`는 modal scrim처럼 아래 맥락을 낮추는 overlay material입니다. 콘텐츠 배경이나 disabled 면에 재사용하지 않습니다.
|
|
60
|
+
|
|
61
|
+
## 기본 사용 규칙
|
|
62
|
+
|
|
63
|
+
페이지의 기본 상속값은 `@include typo(body1)`, `--oc-color-theme-label-normal`, `--oc-color-theme-background-normal-normal`의 trio로 시작합니다. 하위 요소는 역할이 달라질 때만 delta를 선언합니다.
|
|
64
|
+
|
|
65
|
+
```scss
|
|
66
|
+
@use '@orioncactuscorp/ui/scss/mixins/typo' as *;
|
|
67
|
+
|
|
68
|
+
.page {
|
|
69
|
+
@include typo(body1);
|
|
70
|
+
|
|
71
|
+
background: var(--oc-color-theme-background-normal-normal);
|
|
72
|
+
color: var(--oc-color-theme-label-normal);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 기본값 표
|
|
77
|
+
|
|
78
|
+
<!-- prettier-ignore-start -->
|
|
79
|
+
<!-- generated:colors:start -->
|
|
80
|
+
> 아래 표는 기본 theme CSS를 기준으로 생성됩니다. 값은 고정 스펙이 아니라 기본값이며, consumer override 이후 실제 렌더 값은 달라질 수 있습니다.
|
|
81
|
+
|
|
82
|
+
### Static
|
|
83
|
+
|
|
84
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
85
|
+
| --- | --- | --- | --- |
|
|
86
|
+
| `--oc-color-theme-static-white` | `white` | `white` | `var(--oc-color-global-common-100)` |
|
|
87
|
+
| `--oc-color-theme-static-black` | `black` | `black` | `var(--oc-color-global-common-0)` |
|
|
88
|
+
| `--oc-color-theme-static-transparent` | `transparent` | `transparent` | `var(--oc-color-global-common-transparent)` |
|
|
89
|
+
|
|
90
|
+
### Primary
|
|
91
|
+
|
|
92
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
93
|
+
| --- | --- | --- | --- |
|
|
94
|
+
| `--oc-color-theme-primary-normal` | `#ff5e00` | `#ff7b2e` | `light: var(--oc-color-global-redOrange-50)`<br>`dark: var(--oc-color-global-redOrange-60)` |
|
|
95
|
+
|
|
96
|
+
### Focus ring
|
|
97
|
+
|
|
98
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
99
|
+
| --- | --- | --- | --- |
|
|
100
|
+
| `--oc-color-theme-focus-ring` | `#ff5e00` | `#ff7b2e` | `var(--oc-color-theme-primary-normal)` |
|
|
101
|
+
|
|
102
|
+
### Label
|
|
103
|
+
|
|
104
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
105
|
+
| --- | --- | --- | --- |
|
|
106
|
+
| `--oc-color-theme-label-strong` | `black` | `white` | `light: var(--oc-color-global-common-0)`<br>`dark: var(--oc-color-global-common-100)` |
|
|
107
|
+
| `--oc-color-theme-label-normal` | `#171719` | `#f7f7f8` | `light: var(--oc-color-global-coolNeutral-10)`<br>`dark: var(--oc-color-global-coolNeutral-99)` |
|
|
108
|
+
| `--oc-color-theme-label-neutral` | `rgb(46 47 51 / 88%)` | `rgb(194 196 200 / 88%)` | `light: oc-alpha(coolNeutral-22, 88)`<br>`dark: oc-alpha(coolNeutral-90, 88)` |
|
|
109
|
+
| `--oc-color-theme-label-alternative` | `rgb(55 56 60 / 61%)` | `rgb(174 176 182 / 61%)` | `light: oc-alpha(coolNeutral-25, 61)`<br>`dark: oc-alpha(coolNeutral-80, 61)` |
|
|
110
|
+
| `--oc-color-theme-label-assistive` | `rgb(55 56 60 / 28%)` | `rgb(174 176 182 / 28%)` | `light: oc-alpha(coolNeutral-25, 28)`<br>`dark: oc-alpha(coolNeutral-80, 28)` |
|
|
111
|
+
| `--oc-color-theme-label-disable` | `rgb(55 56 60 / 16%)` | `rgb(152 155 162 / 16%)` | `light: oc-alpha(coolNeutral-25, 16)`<br>`dark: oc-alpha(coolNeutral-70, 16)` |
|
|
112
|
+
|
|
113
|
+
### Background
|
|
114
|
+
|
|
115
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
116
|
+
| --- | --- | --- | --- |
|
|
117
|
+
| `--oc-color-theme-background-normal-normal` | `white` | `#1b1c1e` | `light: var(--oc-color-global-common-100)`<br>`dark: var(--oc-color-global-coolNeutral-15)` |
|
|
118
|
+
| `--oc-color-theme-background-normal-alternative` | `#f7f7f8` | `#0f0f10` | `light: var(--oc-color-global-coolNeutral-99)`<br>`dark: var(--oc-color-global-coolNeutral-5)` |
|
|
119
|
+
| `--oc-color-theme-background-elevated-normal` | `white` | `#212225` | `light: var(--oc-color-global-common-100)`<br>`dark: var(--oc-color-global-coolNeutral-17)` |
|
|
120
|
+
| `--oc-color-theme-background-elevated-alternative` | `#f7f7f8` | `#141415` | `light: var(--oc-color-global-coolNeutral-99)`<br>`dark: var(--oc-color-global-coolNeutral-7)` |
|
|
121
|
+
|
|
122
|
+
### Interaction
|
|
123
|
+
|
|
124
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
125
|
+
| --- | --- | --- | --- |
|
|
126
|
+
| `--oc-color-theme-interaction-inactive` | `#989ba2` | `#5a5c63` | `light: var(--oc-color-global-coolNeutral-70)`<br>`dark: var(--oc-color-global-coolNeutral-40)` |
|
|
127
|
+
| `--oc-color-theme-interaction-disable` | `#f4f4f5` | `#2e2f33` | `light: var(--oc-color-global-coolNeutral-98)`<br>`dark: var(--oc-color-global-coolNeutral-22)` |
|
|
128
|
+
|
|
129
|
+
### Line
|
|
130
|
+
|
|
131
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
132
|
+
| --- | --- | --- | --- |
|
|
133
|
+
| `--oc-color-theme-line-normal-strong` | `rgb(112 115 124 / 52%)` | `rgb(194 196 200 / 52%)` | `light: oc-alpha(coolNeutral-50, 52)`<br>`dark: oc-alpha(coolNeutral-90, 52)` |
|
|
134
|
+
| `--oc-color-theme-line-normal-normal` | `rgb(112 115 124 / 22%)` | `rgb(112 115 124 / 32%)` | `light: oc-alpha(coolNeutral-50, 22)`<br>`dark: oc-alpha(coolNeutral-50, 0.32)` |
|
|
135
|
+
| `--oc-color-theme-line-normal-neutral` | `rgb(112 115 124 / 16%)` | `rgb(112 115 124 / 28%)` | `light: oc-alpha(coolNeutral-50, 16)`<br>`dark: oc-alpha(coolNeutral-50, 28)` |
|
|
136
|
+
| `--oc-color-theme-line-normal-alternative` | `rgb(112 115 124 / 8%)` | `rgb(112 115 124 / 22%)` | `light: oc-alpha(coolNeutral-50, 8)`<br>`dark: oc-alpha(coolNeutral-50, 22)` |
|
|
137
|
+
| `--oc-color-theme-line-solid-strong` | `#aeb0b6` | `#70737c` | `light: var(--oc-color-global-coolNeutral-80)`<br>`dark: var(--oc-color-global-coolNeutral-50)` |
|
|
138
|
+
| `--oc-color-theme-line-solid-normal` | `#e1e2e4` | `#37383c` | `light: var(--oc-color-global-coolNeutral-96)`<br>`dark: var(--oc-color-global-coolNeutral-25)` |
|
|
139
|
+
| `--oc-color-theme-line-solid-neutral` | `#eaebec` | `#333438` | `light: var(--oc-color-global-coolNeutral-97)`<br>`dark: var(--oc-color-global-coolNeutral-23)` |
|
|
140
|
+
| `--oc-color-theme-line-solid-alternative` | `#f4f4f5` | `#2e2f33` | `light: var(--oc-color-global-coolNeutral-98)`<br>`dark: var(--oc-color-global-coolNeutral-22)` |
|
|
141
|
+
|
|
142
|
+
### Fill
|
|
143
|
+
|
|
144
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
145
|
+
| --- | --- | --- | --- |
|
|
146
|
+
| `--oc-color-theme-fill-normal` | `rgb(112 115 124 / 8%)` | `rgb(112 115 124 / 22%)` | `light: oc-alpha(coolNeutral-50, 8)`<br>`dark: oc-alpha(coolNeutral-50, 22)` |
|
|
147
|
+
| `--oc-color-theme-fill-strong` | `rgb(112 115 124 / 16%)` | `rgb(112 115 124 / 28%)` | `light: oc-alpha(coolNeutral-50, 16)`<br>`dark: oc-alpha(coolNeutral-50, 28)` |
|
|
148
|
+
| `--oc-color-theme-fill-alternative` | `rgb(112 115 124 / 5%)` | `rgb(112 115 124 / 12%)` | `light: oc-alpha(coolNeutral-50, 5)`<br>`dark: oc-alpha(coolNeutral-50, 12)` |
|
|
149
|
+
|
|
150
|
+
### Accent background
|
|
151
|
+
|
|
152
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
153
|
+
| --- | --- | --- | --- |
|
|
154
|
+
| `--oc-color-theme-accent-background-red` | `#ff4242` | `#ff6363` | `light: var(--oc-color-global-red-50)`<br>`dark: var(--oc-color-global-red-60)` |
|
|
155
|
+
| `--oc-color-theme-accent-background-orange` | `#ff9200` | `#ffa938` | `light: var(--oc-color-global-orange-50)`<br>`dark: var(--oc-color-global-orange-60)` |
|
|
156
|
+
| `--oc-color-theme-accent-background-lime` | `#58cf04` | `#6be016` | `light: var(--oc-color-global-lime-50)`<br>`dark: var(--oc-color-global-lime-60)` |
|
|
157
|
+
| `--oc-color-theme-accent-background-green` | `#00bf40` | `#1ed45a` | `light: var(--oc-color-global-green-50)`<br>`dark: var(--oc-color-global-green-60)` |
|
|
158
|
+
| `--oc-color-theme-accent-background-cyan` | `#00bdde` | `#28d0ed` | `light: var(--oc-color-global-cyan-50)`<br>`dark: var(--oc-color-global-cyan-60)` |
|
|
159
|
+
| `--oc-color-theme-accent-background-lightBlue` | `#00aeff` | `#3dc2ff` | `light: var(--oc-color-global-lightBlue-50)`<br>`dark: var(--oc-color-global-lightBlue-60)` |
|
|
160
|
+
| `--oc-color-theme-accent-background-blue` | `#0066ff` | `#3385ff` | `light: var(--oc-color-global-blue-50)`<br>`dark: var(--oc-color-global-blue-60)` |
|
|
161
|
+
| `--oc-color-theme-accent-background-violet` | `#6541f2` | `#7d5ef7` | `light: var(--oc-color-global-violet-50)`<br>`dark: var(--oc-color-global-violet-60)` |
|
|
162
|
+
| `--oc-color-theme-accent-background-purple` | `#cb59ff` | `#d478ff` | `light: var(--oc-color-global-purple-50)`<br>`dark: var(--oc-color-global-purple-60)` |
|
|
163
|
+
| `--oc-color-theme-accent-background-pink` | `#f553da` | `#fa73e3` | `light: var(--oc-color-global-pink-50)`<br>`dark: var(--oc-color-global-pink-60)` |
|
|
164
|
+
| `--oc-color-theme-accent-background-redOrange` | `#ff5e00` | `#ff7b2e` | `light: var(--oc-color-global-redOrange-50)`<br>`dark: var(--oc-color-global-redOrange-60)` |
|
|
165
|
+
|
|
166
|
+
### Accent foreground
|
|
167
|
+
|
|
168
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
169
|
+
| --- | --- | --- | --- |
|
|
170
|
+
| `--oc-color-theme-accent-foreground-red` | `#e52222` | `#ff6363` | `light: var(--oc-color-global-red-40)`<br>`dark: var(--oc-color-global-red-60)` |
|
|
171
|
+
| `--oc-color-theme-accent-foreground-redOrange` | `#f55a00` | `#ff7b2e` | `light: var(--oc-color-global-redOrange-48)`<br>`dark: var(--oc-color-global-redOrange-60)` |
|
|
172
|
+
| `--oc-color-theme-accent-foreground-orange` | `#d17600` | `#ff9200` | `light: var(--oc-color-global-orange-39)`<br>`dark: var(--oc-color-global-orange-50)` |
|
|
173
|
+
| `--oc-color-theme-accent-foreground-lime` | `#429e00` | `#58cf04` | `light: var(--oc-color-global-lime-37)`<br>`dark: var(--oc-color-global-lime-50)` |
|
|
174
|
+
| `--oc-color-theme-accent-foreground-green` | `#009632` | `#1ed45a` | `light: var(--oc-color-global-green-40)`<br>`dark: var(--oc-color-global-green-60)` |
|
|
175
|
+
| `--oc-color-theme-accent-foreground-cyan` | `#0098b2` | `#00bdde` | `light: var(--oc-color-global-cyan-40)`<br>`dark: var(--oc-color-global-cyan-50)` |
|
|
176
|
+
| `--oc-color-theme-accent-foreground-lightBlue` | `#008dcf` | `#00aeff` | `light: var(--oc-color-global-lightBlue-40)`<br>`dark: var(--oc-color-global-lightBlue-50)` |
|
|
177
|
+
| `--oc-color-theme-accent-foreground-blue` | `#005eeb` | `#4f95ff` | `light: var(--oc-color-global-blue-45)`<br>`dark: var(--oc-color-global-blue-65)` |
|
|
178
|
+
| `--oc-color-theme-accent-foreground-violet` | `#5b37ed` | `#9e86fc` | `light: var(--oc-color-global-violet-45)`<br>`dark: var(--oc-color-global-violet-70)` |
|
|
179
|
+
| `--oc-color-theme-accent-foreground-purple` | `#ad36e3` | `#d478ff` | `light: var(--oc-color-global-purple-40)`<br>`dark: var(--oc-color-global-purple-60)` |
|
|
180
|
+
| `--oc-color-theme-accent-foreground-pink` | `#e846cd` | `#fa73e3` | `light: var(--oc-color-global-pink-46)`<br>`dark: var(--oc-color-global-pink-60)` |
|
|
181
|
+
|
|
182
|
+
### Status
|
|
183
|
+
|
|
184
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
185
|
+
| --- | --- | --- | --- |
|
|
186
|
+
| `--oc-color-theme-status-positive` | `#00bf40` | `#1ed45a` | `var(--oc-color-theme-accent-background-green)` |
|
|
187
|
+
| `--oc-color-theme-status-cautionary` | `#ff9200` | `#ffa938` | `var(--oc-color-theme-accent-background-orange)` |
|
|
188
|
+
| `--oc-color-theme-status-negative` | `#ff4242` | `#ff6363` | `var(--oc-color-theme-accent-background-red)` |
|
|
189
|
+
|
|
190
|
+
### Inverse
|
|
191
|
+
|
|
192
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
193
|
+
| --- | --- | --- | --- |
|
|
194
|
+
| `--oc-color-theme-inverse-primary` | `#ff7b2e` | `#ff5e00` | `light: var(--oc-color-global-redOrange-60)`<br>`dark: var(--oc-color-global-redOrange-50)` |
|
|
195
|
+
| `--oc-color-theme-inverse-background` | `#1b1c1e` | `white` | `light: var(--oc-color-global-coolNeutral-15)`<br>`dark: var(--oc-color-global-common-100)` |
|
|
196
|
+
| `--oc-color-theme-inverse-label` | `#f7f7f8` | `#171719` | `light: var(--oc-color-global-coolNeutral-99)`<br>`dark: var(--oc-color-global-coolNeutral-10)` |
|
|
197
|
+
|
|
198
|
+
### Material
|
|
199
|
+
|
|
200
|
+
| Token | Light 기본값 | Dark 기본값 | Primitive 유도식 |
|
|
201
|
+
| --- | --- | --- | --- |
|
|
202
|
+
| `--oc-color-theme-material-dimmer` | `rgb(23 23 25 / 52%)` | `rgb(23 23 25 / 74%)` | `light: oc-alpha(coolNeutral-10, 52)`<br>`dark: oc-alpha(coolNeutral-10, 74)` |
|
|
203
|
+
<!-- generated:colors:end -->
|
|
204
|
+
<!-- prettier-ignore-end -->
|
|
205
|
+
|
|
206
|
+
## Customize
|
|
207
|
+
|
|
208
|
+
### Runtime CSS variable
|
|
209
|
+
|
|
210
|
+
theme selector와 같은 scope에서 semantic token을 override합니다. Global primitive를 바꾸는 대신 역할 token을 바꾸면 컴포넌트 의미가 유지됩니다.
|
|
211
|
+
|
|
212
|
+
```css
|
|
213
|
+
:root,
|
|
214
|
+
[data-theme='light'] {
|
|
215
|
+
--oc-color-theme-primary-normal: #0066ff;
|
|
216
|
+
--oc-color-theme-focus-ring: #0054d1;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
[data-theme='dark'] {
|
|
220
|
+
--oc-color-theme-primary-normal: #69a5ff;
|
|
221
|
+
--oc-color-theme-focus-ring: #9ec5ff;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Storybook의 semantic swatch는 `var(--oc-color-theme-*)`를 직접 읽으므로 consumer foundation profile이나 runtime override를 적용한 환경에서는 현재 실값으로 렌더됩니다.
|
|
226
|
+
|
|
227
|
+
### SCSS theme config
|
|
228
|
+
|
|
229
|
+
필요한 theme만 출력하거나 OS theme preference 연동을 끄려면 foundation을 직접 compile하면서 `color.config`를 먼저 설정합니다.
|
|
230
|
+
|
|
231
|
+
```scss
|
|
232
|
+
@use '@orioncactuscorp/ui/scss/foundations/color.config' with (
|
|
233
|
+
$oc-color-themes: (
|
|
234
|
+
light,
|
|
235
|
+
dark,
|
|
236
|
+
),
|
|
237
|
+
$oc-color-system-preference: false
|
|
238
|
+
);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
전체 import 순서와 theme scope 예시는 [README Theming](../README.md#theming), responsive compile 설정은 [Responsive Foundation Profile](./responsive-foundation-profile.md)을 참조하세요.
|
package/docs/scss-helpers.md
CHANGED
|
@@ -126,10 +126,10 @@ oc-alpha($color, $opacity)
|
|
|
126
126
|
|
|
127
127
|
`font-size`, `line-height`, `letter-spacing`, `font-weight`를 `--oc-typo-*` 토큰에서 한 번에 출력합니다. raw `var(--oc-typo-size-*)` 직접 참조 대신 이 mixin을 사용하세요 — `--oc-typo-size-factor` runtime multiplier가 자동 반영됩니다.
|
|
128
128
|
|
|
129
|
-
- `$variant`: foundation typo variant 이름 (`title1`, `body1` 등 —
|
|
129
|
+
- `$variant`: foundation typo variant 이름 (`title1`, `body1` 등 — 역할과 기본값은 [Typography](./typography.md))
|
|
130
130
|
- `$weight`: `normal` | `medium` | `bold`
|
|
131
131
|
|
|
132
|
-
variant
|
|
132
|
+
19개 variant는 모두 `normal | medium | bold`를 제공하며, 의미상 같은 weight라도 작은 계층에서 숫자가 단계적으로 낮아집니다. 전체 weight·responsive stop 표는 [Typography](./typography.md)를 참조하세요.
|
|
133
133
|
|
|
134
134
|
```scss
|
|
135
135
|
@use '@orioncactuscorp/ui/scss/mixins/typo' as *;
|
package/docs/tokens.md
CHANGED
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
|
|
9
9
|
값 커스터마이즈 방법은 README의 Foundation 섹션과 [Responsive Foundation Profile](./responsive-foundation-profile.md)을 참조하세요.
|
|
10
10
|
|
|
11
|
+
색상과 타이포는 이름 목록보다 역할 가이드를 먼저 확인하세요: [Semantic Colors](./colors.md), [Typography](./typography.md).
|
|
12
|
+
|
|
11
13
|
## Color — theme semantic
|
|
12
14
|
|
|
13
|
-
`:root`, `[data-theme="light"]`, `[data-theme="dark"]`에서 theme별 값으로 선언됩니다. consumer override는 theme selector 스코프에서 수행합니다.
|
|
15
|
+
`:root`, `[data-theme="light"]`, `[data-theme="dark"]`에서 theme별 값으로 선언됩니다. consumer override는 theme selector 스코프에서 수행합니다. 역할별 용도와 light/dark 기본값은 [Semantic Colors](./colors.md)를 참조하세요.
|
|
14
16
|
|
|
15
17
|
- `--oc-color-theme-accent-background-blue`
|
|
16
18
|
- `--oc-color-theme-accent-background-cyan`
|
|
@@ -285,7 +287,7 @@ theme와 무관한 primitive 값입니다. 컴포넌트에서는 theme semantic
|
|
|
285
287
|
|
|
286
288
|
## Typography
|
|
287
289
|
|
|
288
|
-
size/height/spacing/weight는 `@include typo($variant, $weight)` 경유가 기본입니다. raw size 토큰 직접 참조는 피하세요.
|
|
290
|
+
size/height/spacing/weight는 `@include typo($variant, $weight)` 경유가 기본입니다. raw size 토큰 직접 참조는 피하세요. 19개 variant의 용도와 기본값은 [Typography](./typography.md)를 참조하세요.
|
|
289
291
|
|
|
290
292
|
- `--oc-typo-font-family`
|
|
291
293
|
- `--oc-typo-height-body1`
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Typography
|
|
2
|
+
|
|
3
|
+
oc-ui typography foundation은 19개 variant와 `normal | medium | bold` weight 조합을 제공합니다. variant 이름은 정보 위계와 읽기 맥락의 계약이고, size·line-height 값은 responsive profile과 consumer override에 따라 달라질 수 있는 기본값입니다.
|
|
4
|
+
|
|
5
|
+
## Variant hierarchy
|
|
6
|
+
|
|
7
|
+
- `display1`~`display3`: 캠페인 hero나 대형 숫자처럼 짧고 가장 강한 표현
|
|
8
|
+
- `title1`~`title3`: 페이지 표제
|
|
9
|
+
- `heading1`~`heading2`: 큰 section의 제목
|
|
10
|
+
- `headline1`~`headline2`: 내비게이션과 소섹션(sub-section)의 제목
|
|
11
|
+
- `body1`~`body2`: 일반 본문과 UI 설명. `body1`이 기본 페이지 typography
|
|
12
|
+
- `label1`~`label2`: 대상을 지칭하는 '라벨' 텍스트 — form field label, 항목명, button·menu 같은 control의 라벨
|
|
13
|
+
- `caption1`~`caption2`: metadata, timestamp, 짧은 보조 정보
|
|
14
|
+
|
|
15
|
+
variant 숫자가 작을수록 같은 계층 안에서 더 큽니다. 계층을 오직 크기 선택 도구로 사용하지 말고 문서 구조와 UI 역할에 맞춰 선택합니다.
|
|
16
|
+
|
|
17
|
+
## Reading variants
|
|
18
|
+
|
|
19
|
+
`body1reading`, `body2reading`, `label1reading`은 대응 기본 variant와 font-size·letter-spacing·weight가 같고 line-height만 더 넓습니다. 여러 줄로 이어지는 본문, 안내문, 조밀한 label 묶음처럼 읽기 호흡이 필요한 경우에 사용합니다. 한 줄 control label이나 짧은 badge에는 기본 variant를 유지합니다.
|
|
20
|
+
|
|
21
|
+
## Responsive stops
|
|
22
|
+
|
|
23
|
+
기본 profile은 `sm / md / lg / xl` 4개 stop을 사용합니다.
|
|
24
|
+
|
|
25
|
+
- `body*`, `label*`, `caption*`은 `md` stop을 포함합니다.
|
|
26
|
+
- `heading*`, `headline*`, `body*`, `label*`, `caption*`은 `xl` stop을 포함합니다.
|
|
27
|
+
- `display*`, `title*`은 `sm / lg`, `heading*`과 `headline*`은 `sm / lg / xl` 기본값을 가집니다.
|
|
28
|
+
- 정의되지 않은 stop은 responsive segment에서 인접한 유효 stop을 기준으로 보간·유지됩니다. 표의 `—`는 token이 없다는 뜻이 아니라 해당 variant map에 별도 stop 값이 없다는 뜻입니다.
|
|
29
|
+
|
|
30
|
+
## Weight policy
|
|
31
|
+
|
|
32
|
+
모든 variant는 `normal`, `medium`, `bold` 세 이름을 제공하지만 `bold`의 숫자는 계층에 따라 낮아집니다. display·title은 700, heading·headline·body는 600, label은 550, caption1은 540, caption2는 530입니다. 작은 글자에서 지나치게 뭉치는 것을 피하면서 의미상 같은 `bold` 역할을 유지하기 위한 정책입니다.
|
|
33
|
+
|
|
34
|
+
## 기본값 표
|
|
35
|
+
|
|
36
|
+
<!-- prettier-ignore-start -->
|
|
37
|
+
<!-- generated:typography:start -->
|
|
38
|
+
> 아래 표는 기본 responsive profile의 SCSS map에서 생성됩니다. 값은 고정 스펙이 아니라 기본값입니다. line-height 괄호 안 숫자는 `line-height / font-size` 비율입니다.
|
|
39
|
+
|
|
40
|
+
| Variant | Size sm | Size md | Size lg | Size xl | Line-height sm | Line-height md | Line-height lg | Line-height xl | Letter spacing | Normal | Medium | Bold |
|
|
41
|
+
| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
|
|
42
|
+
| `display1` | 48px | — | 64px | — | 62px (1.29) | — | 82px (1.28) | — | 0em | 400 | 500 | 700 |
|
|
43
|
+
| `display2` | 40px | — | 48px | — | 52px (1.30) | — | 62px (1.29) | — | 0em | 400 | 500 | 700 |
|
|
44
|
+
| `display3` | 36px | — | 40px | — | 48px (1.33) | — | 52px (1.30) | — | 0em | 400 | 500 | 700 |
|
|
45
|
+
| `title1` | 32px | — | 36px | — | 44px (1.38) | — | 48px (1.33) | — | 0em | 400 | 500 | 700 |
|
|
46
|
+
| `title2` | 28px | — | 32px | — | 38px (1.36) | — | 42px (1.31) | — | 0em | 400 | 500 | 700 |
|
|
47
|
+
| `title3` | 24px | — | 28px | — | 32px (1.33) | — | 36px (1.29) | — | 0em | 400 | 500 | 700 |
|
|
48
|
+
| `heading1` | 22px | — | 24px | 26px | 30px (1.36) | — | 32px (1.33) | 34px (1.31) | 0em | 400 | 500 | 600 |
|
|
49
|
+
| `heading2` | 20px | — | 22px | 24px | 28px (1.40) | — | 30px (1.36) | 32px (1.33) | 0em | 400 | 500 | 600 |
|
|
50
|
+
| `headline1` | 18px | — | 20px | 22px | 26px (1.44) | — | 28px (1.40) | 30px (1.36) | 0em | 400 | 500 | 600 |
|
|
51
|
+
| `headline2` | 17px | — | 18px | 20px | 24px (1.41) | — | 26px (1.44) | 28px (1.40) | 0em | 400 | 500 | 600 |
|
|
52
|
+
| `body1` | 16px | 17px | 18px | 20px | 24px (1.50) | 26px (1.53) | 28px (1.56) | 30px (1.50) | 0em | 400 | 500 | 600 |
|
|
53
|
+
| `body1reading` | 16px | 17px | 18px | 20px | 26px (1.63) | 28px (1.65) | 30px (1.67) | 32px (1.60) | 0em | 400 | 500 | 600 |
|
|
54
|
+
| `body2` | 15px | 16px | 17px | 18px | 22px (1.47) | 24px (1.50) | 26px (1.53) | 28px (1.56) | 0em | 400 | 500 | 600 |
|
|
55
|
+
| `body2reading` | 15px | 16px | 17px | 18px | 24px (1.60) | 26px (1.63) | 28px (1.65) | 30px (1.67) | 0em | 400 | 500 | 600 |
|
|
56
|
+
| `label1` | 14px | 15px | 16px | 17px | 20px (1.43) | 22px (1.47) | 24px (1.50) | 26px (1.53) | 0.01em | 400 | 500 | 550 |
|
|
57
|
+
| `label1reading` | 14px | 15px | 16px | 17px | 22px (1.57) | 24px (1.60) | 26px (1.63) | 28px (1.65) | 0.01em | 400 | 500 | 550 |
|
|
58
|
+
| `label2` | 13px | 14px | 15px | 16px | 18px (1.38) | 20px (1.43) | 22px (1.47) | 24px (1.50) | 0.01em | 400 | 500 | 550 |
|
|
59
|
+
| `caption1` | 12px | 13px | 14px | 15px | 16px (1.33) | 18px (1.38) | 20px (1.43) | 22px (1.47) | 0.01em | 400 | 500 | 540 |
|
|
60
|
+
| `caption2` | 11px | 12px | 13px | 14px | 14px (1.27) | 16px (1.33) | 18px (1.38) | 20px (1.43) | 0.01em | 400 | 500 | 530 |
|
|
61
|
+
<!-- generated:typography:end -->
|
|
62
|
+
<!-- prettier-ignore-end -->
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
raw `--oc-typo-size-*`, `--oc-typo-height-*`, `--oc-typo-spacing-*`, `--oc-typo-weight-*`를 직접 조합하지 말고 반드시 `typo()` mixin을 사용합니다. mixin은 네 속성을 같은 variant contract에서 출력하고 runtime `--oc-typo-size-factor`도 반영합니다.
|
|
67
|
+
|
|
68
|
+
```scss
|
|
69
|
+
@use '@orioncactuscorp/ui/scss/mixins/typo' as *;
|
|
70
|
+
|
|
71
|
+
.pageTitle {
|
|
72
|
+
@include typo(title1, bold);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.articleBody {
|
|
76
|
+
@include typo(body1reading, normal);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.fieldLabel {
|
|
80
|
+
@include typo(label1, medium);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Customize
|
|
85
|
+
|
|
86
|
+
### Size and line-height maps
|
|
87
|
+
|
|
88
|
+
foundation을 직접 compile할 때 `$oc-typo-size-overrides`와 `$oc-typo-height-overrides`로 필요한 variant·stop만 덮습니다. 역할 이름은 유지하고 제품에 필요한 기본값만 조정합니다.
|
|
89
|
+
|
|
90
|
+
```scss
|
|
91
|
+
@use '@orioncactuscorp/ui/scss/foundations/typo' as * with (
|
|
92
|
+
$oc-typo-size-overrides: (
|
|
93
|
+
title1: (
|
|
94
|
+
sm: 36,
|
|
95
|
+
),
|
|
96
|
+
),
|
|
97
|
+
$oc-typo-height-overrides: (
|
|
98
|
+
title1: (
|
|
99
|
+
sm: 48,
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Runtime size factor
|
|
106
|
+
|
|
107
|
+
`--oc-typo-size-factor`는 size와 line-height에 함께 적용되는 runtime multiplier입니다. 특정 subtree의 접근성 확대나 preview에 사용할 수 있지만, variant 간 위계를 다시 설계하는 용도로 남용하지 않습니다.
|
|
108
|
+
|
|
109
|
+
```css
|
|
110
|
+
.largeTypeScope {
|
|
111
|
+
--oc-typo-size-factor: 1.125;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
fluid·stepped·static 출력과 active stop 범위는 [Responsive Foundation Profile](./responsive-foundation-profile.md), mixin signature는 [SCSS Helpers](./scss-helpers.md)를 참조하세요. Storybook typography matrix는 현재 foundation profile의 CSS variable을 사용하므로 override 환경의 실값을 그대로 보여줍니다.
|
package/package.json
CHANGED
|
@@ -30,11 +30,23 @@ describe('color theme foundations', () => {
|
|
|
30
30
|
`);
|
|
31
31
|
|
|
32
32
|
expect(css).toMatch(
|
|
33
|
-
/:root\{[^}]*--oc-color-theme-background-normal-normal:var\(--oc-color-global-common-100\)/,
|
|
33
|
+
/:root\{color-scheme:light;[^}]*--oc-color-theme-background-normal-normal:var\(--oc-color-global-common-100\)/,
|
|
34
34
|
);
|
|
35
|
-
expect(css).toContain('[data-theme=light]');
|
|
36
|
-
expect(css).toContain(
|
|
37
|
-
|
|
35
|
+
expect(css).toContain('[data-theme=light]{color-scheme:light;');
|
|
36
|
+
expect(css).toContain(
|
|
37
|
+
'@media(prefers-color-scheme:dark){:root:where(:not([data-theme=light])){color-scheme:dark;',
|
|
38
|
+
);
|
|
39
|
+
expect(css).toContain('[data-theme=dark]{color-scheme:dark;');
|
|
40
|
+
|
|
41
|
+
const lightAttributeIndex = css.indexOf('[data-theme=light]');
|
|
42
|
+
const systemPreferenceIndex = css.indexOf(
|
|
43
|
+
'@media(prefers-color-scheme:dark)',
|
|
44
|
+
);
|
|
45
|
+
const darkAttributeIndex = css.indexOf('[data-theme=dark]');
|
|
46
|
+
|
|
47
|
+
expect(lightAttributeIndex).toBeLessThan(systemPreferenceIndex);
|
|
48
|
+
expect(systemPreferenceIndex).toBeLessThan(darkAttributeIndex);
|
|
49
|
+
expect(css).not.toContain('@media(prefers-color-scheme:dark){:root{');
|
|
38
50
|
});
|
|
39
51
|
|
|
40
52
|
it('aliases the focus ring color to the primary semantic in both themes', () => {
|
|
@@ -58,7 +70,8 @@ describe('color theme foundations', () => {
|
|
|
58
70
|
@use 'foundations/color.theme.dark' as dark;
|
|
59
71
|
`);
|
|
60
72
|
|
|
61
|
-
expect(css).toContain('
|
|
73
|
+
expect(css).toContain(':root{color-scheme:light;');
|
|
74
|
+
expect(css).toContain('[data-theme=light]{color-scheme:light;');
|
|
62
75
|
expect(css).not.toContain('@media(prefers-color-scheme:dark)');
|
|
63
76
|
expect(css).not.toContain('[data-theme=dark]');
|
|
64
77
|
expect(css).not.toContain(
|
|
@@ -75,7 +88,8 @@ describe('color theme foundations', () => {
|
|
|
75
88
|
|
|
76
89
|
expect(css).not.toContain('@media(prefers-color-scheme:dark)');
|
|
77
90
|
expect(css).not.toContain('[data-theme=light]');
|
|
78
|
-
expect(css).toContain('
|
|
91
|
+
expect(css).toContain(':root{color-scheme:dark;');
|
|
92
|
+
expect(css).toContain('[data-theme=dark]{color-scheme:dark;');
|
|
79
93
|
expect(css).toMatch(
|
|
80
94
|
/:root\{[^}]*--oc-color-theme-background-normal-normal:var\(--oc-color-global-coolNeutral-15\)/,
|
|
81
95
|
);
|
|
@@ -89,8 +103,9 @@ describe('color theme foundations', () => {
|
|
|
89
103
|
`);
|
|
90
104
|
|
|
91
105
|
expect(css).not.toContain('@media(prefers-color-scheme:dark)');
|
|
92
|
-
expect(css).toContain('
|
|
93
|
-
expect(css).toContain('[data-theme=
|
|
106
|
+
expect(css).toContain(':root{color-scheme:light;');
|
|
107
|
+
expect(css).toContain('[data-theme=light]{color-scheme:light;');
|
|
108
|
+
expect(css).toContain('[data-theme=dark]{color-scheme:dark;');
|
|
94
109
|
});
|
|
95
110
|
|
|
96
111
|
it('throws when $oc-color-themes is empty', () => {
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
@use '../mixins/color' as *;
|
|
4
4
|
|
|
5
5
|
@mixin color-theme-dark {
|
|
6
|
+
color-scheme: dark;
|
|
7
|
+
|
|
6
8
|
--oc-color-theme-static-white: var(--oc-color-global-common-100);
|
|
7
9
|
--oc-color-theme-static-black: var(--oc-color-global-common-0);
|
|
8
10
|
--oc-color-theme-static-transparent: var(--oc-color-global-common-transparent);
|
|
@@ -68,7 +70,7 @@
|
|
|
68
70
|
@include color-theme-dark;
|
|
69
71
|
}
|
|
70
72
|
} @else if config.$oc-color-system-preference {
|
|
71
|
-
:root {
|
|
73
|
+
:root:where(:not([data-theme='light'])) {
|
|
72
74
|
@media (prefers-color-scheme: dark) {
|
|
73
75
|
@include color-theme-dark;
|
|
74
76
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
@use '../mixins/color' as *;
|
|
4
4
|
|
|
5
5
|
@mixin color-theme-light {
|
|
6
|
+
color-scheme: light;
|
|
7
|
+
|
|
6
8
|
--oc-color-theme-static-white: var(--oc-color-global-common-100);
|
|
7
9
|
--oc-color-theme-static-black: var(--oc-color-global-common-0);
|
|
8
10
|
--oc-color-theme-static-transparent: var(--oc-color-global-common-transparent);
|