@tide-tds/foundation 0.0.0-stage → 0.2.0

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.
@@ -0,0 +1,230 @@
1
+ import { ColorFamily, PrimitiveColorName } from "./color.js";
2
+ import { BackgroundSlot, ColorSlot, familyOverrides, slotRule } from "./color-slot.js";
3
+ /** Theme 이름 */
4
+ export type ThemeName = "light" | "dark";
5
+ /** Primitive에 투명도를 더한 색. overlay와 shadow 색에만 쓰고, CSS에는 8자리 hex로 나간다. */
6
+ export interface AlphaColor {
7
+ readonly primitive: PrimitiveColorName;
8
+ /** 0~1 */
9
+ readonly alpha: number;
10
+ }
11
+ /**
12
+ * Semantic Token 하나가 가리키는 값. `transparent`는 light raised border에만 쓴다(CSS에서도 `transparent` 키워드로 나간다).
13
+ */
14
+ export type SemanticColorValue = PrimitiveColorName | AlphaColor | "transparent";
15
+ /** Theme별로 가리키는 값 */
16
+ export interface ThemedColor {
17
+ readonly light: SemanticColorValue;
18
+ readonly dark: SemanticColorValue;
19
+ }
20
+ /**
21
+ * Tide가 정한 Role 6개. 앱이 `RoleRegistry`에 더한 Role은 들어 있지 않다.
22
+ * Tide 안의 계산(Semantic Token 이름, 대비 쌍)은 이 타입을 쓴다. 앱 Role에는 Role Token이 생기지 않기 때문이다.
23
+ */
24
+ export type TideRole = "neutral" | "primary" | "success" | "warning" | "danger" | "info";
25
+ /**
26
+ * Role이 참조하는 Primitive 계열.
27
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
28
+ */
29
+ export declare const roleFamily: {
30
+ readonly neutral: "gray";
31
+ readonly primary: "blue";
32
+ readonly success: "green";
33
+ readonly warning: "amber";
34
+ readonly danger: "red";
35
+ readonly info: "cyan";
36
+ };
37
+ /**
38
+ * Role별로 계열 규칙에서 덮어쓸 값.
39
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
40
+ */
41
+ export declare const roleOverrides: {
42
+ readonly neutral: {
43
+ readonly subtle: {
44
+ readonly dark: 900;
45
+ };
46
+ readonly "subtle-hover": {
47
+ readonly dark: 800;
48
+ };
49
+ readonly "subtle-active": {
50
+ readonly dark: 700;
51
+ };
52
+ };
53
+ };
54
+ /**
55
+ * 역할 Token 대신 공통 Semantic Token을 쓰는 Role 슬롯. on-solid는 모든 Role이 `text-on-solid`를 쓴다.
56
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
57
+ */
58
+ export declare const roleSharedSlots: {
59
+ readonly neutral: {
60
+ readonly text: "text-default";
61
+ readonly border: "border-strong";
62
+ };
63
+ };
64
+ /**
65
+ * Role 목록. Tide Role 6개가 들어 있고, 앱은 module augmentation으로 자기 Role(예: `brand`)을 더한다.
66
+ * 앱 Role의 색은 `@tide-tds/foundation/color-family`의 `defineColorFamily`와 `tide-color build`로 만든다.
67
+ *
68
+ * ```ts
69
+ * declare module "@tide-tds/components" {
70
+ * interface RoleRegistry {
71
+ * brand: true;
72
+ * }
73
+ * }
74
+ * ```
75
+ */
76
+ export interface RoleRegistry extends Record<TideRole, true> {}
77
+ /**
78
+ * Role. 뜻이 있는 색이다. 행동·의미 Component의 `color`로 고르고, `data-color` 속성으로 accent 슬롯에 꽂는다.
79
+ * Tide Role 6개와 앱이 `RoleRegistry`에 더한 Role이다.
80
+ */
81
+ export type Role = keyof RoleRegistry;
82
+ /**
83
+ * 색 계열 목록. Tide 색 계열 6개가 들어 있고, 앱은 module augmentation으로 장식용 계열을 더한다.
84
+ * Tide가 Primitive 계열을 더하면 이 목록도 함께 넓어진다.
85
+ *
86
+ * ```ts
87
+ * declare module "@tide-tds/components" {
88
+ * interface ColorFamilyRegistry {
89
+ * brand: true;
90
+ * }
91
+ * }
92
+ * ```
93
+ */
94
+ export interface ColorFamilyRegistry extends Record<ColorFamily, true> {}
95
+ /**
96
+ * 색 계열 이름. 뜻이 없는 색이라 장식·분류 Component가 쓴다.
97
+ * Tide 색 계열(`ColorFamily`)과 앱이 `ColorFamilyRegistry`에 더한 계열이다.
98
+ */
99
+ export type ColorFamilyName = keyof ColorFamilyRegistry;
100
+ /** 색 이름(Color). `data-color` 속성이 받는 모든 이름이다(Role과 색 계열). */
101
+ export type Color = Role | ColorFamilyName;
102
+ type Lookup<Table, K1, K2, K3, Fallback> = K1 extends keyof Table ? K2 extends keyof Table[K1] ? K3 extends keyof Table[K1][K2] ? Table[K1][K2][K3] : Fallback : Fallback : Fallback;
103
+ type FamilyStep<Family, Slot extends ColorSlot, Theme extends ThemeName> = Lookup<typeof familyOverrides, Family, Slot, Theme, (typeof slotRule)[Slot][Theme]>;
104
+ type RoleStep<Name extends TideRole, Slot extends ColorSlot, Theme extends ThemeName> = Lookup<typeof roleOverrides, Name, Slot, Theme, FamilyStep<(typeof roleFamily)[Name], Slot, Theme>>;
105
+ type StepName<Family extends string, Step> = Step extends number ? `${Family}-${Step}` : Step;
106
+ type RoleSlotColor<Name extends TideRole, Slot extends ColorSlot> = {
107
+ readonly light: StepName<(typeof roleFamily)[Name], RoleStep<Name, Slot, "light">>;
108
+ readonly dark: StepName<(typeof roleFamily)[Name], RoleStep<Name, Slot, "dark">>;
109
+ };
110
+ /** 역할 text·border Token이 있는 Role(neutral 제외) */
111
+ type AccentRole = Exclude<TideRole, keyof typeof roleSharedSlots>;
112
+ type RoleBackgroundTokens = { readonly [Key in `${TideRole}-${BackgroundSlot}`]: Key extends `${infer Name extends TideRole}-${infer Slot extends BackgroundSlot}` ? RoleSlotColor<Name, Slot> : never; };
113
+ type RoleSlotTokens<Slot extends "text" | "border"> = { readonly [Name in AccentRole]: RoleSlotColor<Name, Slot>; };
114
+ declare const commonBackground: {
115
+ readonly canvas: {
116
+ readonly light: "white";
117
+ readonly dark: "gray-950";
118
+ };
119
+ readonly surface: {
120
+ readonly light: "white";
121
+ readonly dark: "gray-950";
122
+ };
123
+ readonly raised: {
124
+ readonly light: "white";
125
+ readonly dark: "gray-900";
126
+ };
127
+ readonly disabled: {
128
+ readonly light: "gray-100";
129
+ readonly dark: "gray-900";
130
+ };
131
+ readonly overlay: {
132
+ readonly light: {
133
+ readonly primitive: "gray-950";
134
+ readonly alpha: 0.5;
135
+ };
136
+ readonly dark: {
137
+ readonly primitive: "gray-950";
138
+ readonly alpha: 0.7;
139
+ };
140
+ };
141
+ };
142
+ declare const commonText: {
143
+ readonly default: {
144
+ readonly light: "gray-900";
145
+ readonly dark: "gray-50";
146
+ };
147
+ readonly muted: {
148
+ readonly light: "gray-600";
149
+ readonly dark: "gray-300";
150
+ };
151
+ readonly disabled: {
152
+ readonly light: "gray-400";
153
+ readonly dark: "gray-600";
154
+ };
155
+ readonly "on-solid": {
156
+ readonly light: "white";
157
+ readonly dark: "white";
158
+ };
159
+ };
160
+ declare const commonBorder: {
161
+ readonly default: {
162
+ readonly light: "gray-200";
163
+ readonly dark: "gray-800";
164
+ };
165
+ readonly strong: {
166
+ readonly light: "gray-500";
167
+ readonly dark: "gray-400";
168
+ };
169
+ readonly raised: {
170
+ readonly light: "transparent";
171
+ readonly dark: "gray-800";
172
+ };
173
+ };
174
+ declare const commonOutline: {
175
+ readonly focus: {
176
+ readonly light: "blue-600";
177
+ readonly dark: "blue-400";
178
+ };
179
+ };
180
+ export declare const semantic: {
181
+ readonly background: typeof commonBackground & RoleBackgroundTokens;
182
+ readonly text: typeof commonText & RoleSlotTokens<"text">;
183
+ readonly border: typeof commonBorder & RoleSlotTokens<"border">;
184
+ readonly outline: typeof commonOutline;
185
+ };
186
+ /** Semantic namespace와 Utility class 접두사 */
187
+ export type SemanticNamespace = "background" | "text" | "border" | "outline";
188
+ export declare const semanticPrefix: {
189
+ readonly background: "bg";
190
+ readonly text: "text";
191
+ readonly border: "border";
192
+ readonly outline: "outline";
193
+ };
194
+ /** Semantic Token의 Utility class 이름. 예: `bg-primary-solid`, `text-muted` */
195
+ export type SemanticColorName = { [Namespace in SemanticNamespace]: `${(typeof semanticPrefix)[Namespace]}-${keyof (typeof semantic)[Namespace] & string}`; }[SemanticNamespace];
196
+ /**
197
+ * Theme별 shadow 색. CSS에서는 `--tide-shadow-color`로 쓴다.
198
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
199
+ */
200
+ export declare const shadowColor: {
201
+ readonly light: {
202
+ readonly primitive: "gray-950";
203
+ readonly alpha: 0.08;
204
+ };
205
+ readonly dark: {
206
+ readonly primitive: "black";
207
+ readonly alpha: 0.3;
208
+ };
209
+ };
210
+ /**
211
+ * 모든 Semantic Token(namespace, Utility class 이름, Theme별 값).
212
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
213
+ */
214
+ export declare function semanticEntries(): {
215
+ readonly namespace: SemanticNamespace;
216
+ readonly key: string;
217
+ readonly className: SemanticColorName;
218
+ readonly value: ThemedColor;
219
+ }[];
220
+ /**
221
+ * 값을 hex로 바꾼다. alpha가 있으면 8자리 hex(`#rrggbbaa`)다. `transparent`는 `#00000000`이다.
222
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
223
+ */
224
+ export declare function colorValueHex(value: SemanticColorValue): string;
225
+ /**
226
+ * Semantic Token이 Theme에서 가리키는 hex.
227
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
228
+ */
229
+ export declare function semanticHex(name: SemanticColorName, theme: ThemeName): string;
230
+ export {};
@@ -0,0 +1,177 @@
1
+ import { primitiveHex } from "./color.js";
2
+ import { colorSlots, familyOverrides, resolveSlotSteps, slotPrimitive } from "./color-slot.js";
3
+
4
+ // src/semantic.ts
5
+ /**
6
+ * Role이 참조하는 Primitive 계열.
7
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
8
+ */
9
+ const roleFamily = {
10
+ neutral: "gray",
11
+ primary: "blue",
12
+ success: "green",
13
+ warning: "amber",
14
+ danger: "red",
15
+ info: "cyan"
16
+ };
17
+ /**
18
+ * Role별로 계열 규칙에서 덮어쓸 값.
19
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
20
+ */
21
+ const roleOverrides = { neutral: {
22
+ subtle: { dark: 900 },
23
+ "subtle-hover": { dark: 800 },
24
+ "subtle-active": { dark: 700 }
25
+ } };
26
+ /**
27
+ * 역할 Token 대신 공통 Semantic Token을 쓰는 Role 슬롯. on-solid는 모든 Role이 `text-on-solid`를 쓴다.
28
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
29
+ */
30
+ const roleSharedSlots = { neutral: {
31
+ text: "text-default",
32
+ border: "border-strong"
33
+ } };
34
+ const roles = Object.keys(roleFamily);
35
+ const backgroundSlots = colorSlots.filter((slot) => slot !== "text" && slot !== "border" && slot !== "on-solid");
36
+ const accentRoles = roles.filter((role) => !(role in roleSharedSlots));
37
+ /** Role 슬롯이 가리키는 Primitive. 계열 규칙 → 계열 덮어쓸 값 → Role 덮어쓸 값 순서로 얹는다. */
38
+ function roleSlotColor(role, slot) {
39
+ const family = roleFamily[role];
40
+ const steps = resolveSlotSteps(familyOverrides[family], roleOverrides[role])[slot];
41
+ return {
42
+ light: slotPrimitive(family, steps.light),
43
+ dark: slotPrimitive(family, steps.dark)
44
+ };
45
+ }
46
+ const commonBackground = {
47
+ canvas: {
48
+ light: "white",
49
+ dark: "gray-950"
50
+ },
51
+ surface: {
52
+ light: "white",
53
+ dark: "gray-950"
54
+ },
55
+ raised: {
56
+ light: "white",
57
+ dark: "gray-900"
58
+ },
59
+ disabled: {
60
+ light: "gray-100",
61
+ dark: "gray-900"
62
+ },
63
+ overlay: {
64
+ light: {
65
+ primitive: "gray-950",
66
+ alpha: .5
67
+ },
68
+ dark: {
69
+ primitive: "gray-950",
70
+ alpha: .7
71
+ }
72
+ }
73
+ };
74
+ const commonText = {
75
+ default: {
76
+ light: "gray-900",
77
+ dark: "gray-50"
78
+ },
79
+ muted: {
80
+ light: "gray-600",
81
+ dark: "gray-300"
82
+ },
83
+ disabled: {
84
+ light: "gray-400",
85
+ dark: "gray-600"
86
+ },
87
+ "on-solid": {
88
+ light: "white",
89
+ dark: "white"
90
+ }
91
+ };
92
+ const commonBorder = {
93
+ default: {
94
+ light: "gray-200",
95
+ dark: "gray-800"
96
+ },
97
+ strong: {
98
+ light: "gray-500",
99
+ dark: "gray-400"
100
+ },
101
+ raised: {
102
+ light: "transparent",
103
+ dark: "gray-800"
104
+ }
105
+ };
106
+ const commonOutline = { focus: {
107
+ light: "blue-600",
108
+ dark: "blue-400"
109
+ } };
110
+ const semantic = {
111
+ background: {
112
+ ...commonBackground,
113
+ ...Object.fromEntries(roles.flatMap((role) => backgroundSlots.map((slot) => [`${role}-${slot}`, roleSlotColor(role, slot)])))
114
+ },
115
+ text: {
116
+ ...commonText,
117
+ ...Object.fromEntries(accentRoles.map((role) => [role, roleSlotColor(role, "text")]))
118
+ },
119
+ border: {
120
+ ...commonBorder,
121
+ ...Object.fromEntries(accentRoles.map((role) => [role, roleSlotColor(role, "border")]))
122
+ },
123
+ outline: commonOutline
124
+ };
125
+ const semanticPrefix = {
126
+ background: "bg",
127
+ text: "text",
128
+ border: "border",
129
+ outline: "outline"
130
+ };
131
+ /**
132
+ * Theme별 shadow 색. CSS에서는 `--tide-shadow-color`로 쓴다.
133
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
134
+ */
135
+ const shadowColor = {
136
+ light: {
137
+ primitive: "gray-950",
138
+ alpha: .08
139
+ },
140
+ dark: {
141
+ primitive: "black",
142
+ alpha: .3
143
+ }
144
+ };
145
+ /**
146
+ * 모든 Semantic Token(namespace, Utility class 이름, Theme별 값).
147
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
148
+ */
149
+ function semanticEntries() {
150
+ return Object.keys(semantic).flatMap((namespace) => Object.entries(semantic[namespace]).map(([key, value]) => ({
151
+ namespace,
152
+ key,
153
+ className: `${semanticPrefix[namespace]}-${key}`,
154
+ value
155
+ })));
156
+ }
157
+ /**
158
+ * 값을 hex로 바꾼다. alpha가 있으면 8자리 hex(`#rrggbbaa`)다. `transparent`는 `#00000000`이다.
159
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
160
+ */
161
+ function colorValueHex(value) {
162
+ if (value === "transparent") return "#00000000";
163
+ if (typeof value === "string") return primitiveHex(value);
164
+ const alpha = Math.round(value.alpha * 255).toString(16).padStart(2, "0");
165
+ return `${primitiveHex(value.primitive)}${alpha}`;
166
+ }
167
+ /**
168
+ * Semantic Token이 Theme에서 가리키는 hex.
169
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
170
+ */
171
+ function semanticHex(name, theme) {
172
+ const entry = semanticEntries().find((candidate) => candidate.className === name);
173
+ if (!entry) throw new Error(`Semantic Token이 아니다: ${name}`);
174
+ return colorValueHex(entry.value[theme]);
175
+ }
176
+
177
+ export { colorValueHex, roleFamily, roleOverrides, roleSharedSlots, semantic, semanticEntries, semanticHex, semanticPrefix, shadowColor };
@@ -0,0 +1,89 @@
1
+ /**
2
+ * radius 5단계. `rounded-<이름>` class와 공개 계약 `--tide-rounded-<이름>`이 쓴다.
3
+ * - sm: 작은 표시 요소, 목록 안 항목
4
+ * - md: 조작 요소(모든 size)
5
+ * - lg: 담는 요소(Card, Alert, Popover, 목록, Toast, Accordion)
6
+ * - xl: Dialog류
7
+ * - full: 원·알약형
8
+ */
9
+ export declare const radius: {
10
+ readonly sm: "0.25rem";
11
+ readonly md: "0.375rem";
12
+ readonly lg: "0.5rem";
13
+ readonly xl: "0.75rem";
14
+ readonly full: "9999px";
15
+ };
16
+ /** radius 단계 이름 */
17
+ export type RadiusName = keyof typeof radius;
18
+ /** 그림자 레이어 하나. 길이는 px, `mix`는 `--tide-shadow-color`를 남기는 비율(%)이다. */
19
+ export interface ShadowLayer {
20
+ readonly x: number;
21
+ readonly y: number;
22
+ readonly blur: number;
23
+ readonly spread: number;
24
+ readonly mix: number;
25
+ }
26
+ /**
27
+ * Elevation 3단계. 각 단계는 [가까운 레이어, 먼 레이어]다. 값은 spec 표를 그대로 옮겼다.
28
+ * `shadow-<이름>` class와 공개 계약 `--tide-shadow-<이름>`이 쓴다. Theme에 따라 `--tide-shadow-color`만 바뀐다.
29
+ * - sm: Switch thumb
30
+ * - md: Popover, 목록, Tooltip, Toast
31
+ * - lg: Dialog류
32
+ */
33
+ export declare const shadow: {
34
+ readonly sm: readonly [{
35
+ readonly x: 0;
36
+ readonly y: 1;
37
+ readonly blur: 1;
38
+ readonly spread: 0;
39
+ readonly mix: 60;
40
+ }, {
41
+ readonly x: 0;
42
+ readonly y: 1;
43
+ readonly blur: 2;
44
+ readonly spread: 0;
45
+ readonly mix: 100;
46
+ }];
47
+ readonly md: readonly [{
48
+ readonly x: 0;
49
+ readonly y: 1;
50
+ readonly blur: 3;
51
+ readonly spread: 0;
52
+ readonly mix: 50;
53
+ }, {
54
+ readonly x: 0;
55
+ readonly y: 4;
56
+ readonly blur: 12;
57
+ readonly spread: -2;
58
+ readonly mix: 100;
59
+ }];
60
+ readonly lg: readonly [{
61
+ readonly x: 0;
62
+ readonly y: 2;
63
+ readonly blur: 6;
64
+ readonly spread: -1;
65
+ readonly mix: 50;
66
+ }, {
67
+ readonly x: 0;
68
+ readonly y: 12;
69
+ readonly blur: 24;
70
+ readonly spread: -6;
71
+ readonly mix: 100;
72
+ }];
73
+ };
74
+ /** Elevation 단계 이름 */
75
+ export type ShadowName = keyof typeof shadow;
76
+ /**
77
+ * 포커스 표시 ring의 두께와 offset. 공개 계약은 `--tide-focus-ring-width`, `--tide-focus-ring-offset`이다.
78
+ * `focus-ring` utility가 쓰고, `focus-field`의 투명 outline 두께도 같은 값을 쓴다.
79
+ */
80
+ export declare const focusRing: {
81
+ readonly width: "2px";
82
+ readonly offset: "2px";
83
+ };
84
+ /**
85
+ * Elevation 단계를 CSS `box-shadow` 값으로 만든다. 두 레이어 모두
86
+ * `color-mix(in srgb, var(--tide-shadow-color) N%, transparent)`로 색을 낮춘다(100%도 같은 형태로 쓴다).
87
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
88
+ */
89
+ export declare function shadowCss(name: ShadowName): string;
package/dist/shape.js ADDED
@@ -0,0 +1,93 @@
1
+ // src/shape.ts
2
+ /**
3
+ * radius 5단계. `rounded-<이름>` class와 공개 계약 `--tide-rounded-<이름>`이 쓴다.
4
+ * - sm: 작은 표시 요소, 목록 안 항목
5
+ * - md: 조작 요소(모든 size)
6
+ * - lg: 담는 요소(Card, Alert, Popover, 목록, Toast, Accordion)
7
+ * - xl: Dialog류
8
+ * - full: 원·알약형
9
+ */
10
+ const radius = {
11
+ sm: "0.25rem",
12
+ md: "0.375rem",
13
+ lg: "0.5rem",
14
+ xl: "0.75rem",
15
+ full: "9999px"
16
+ };
17
+ /**
18
+ * Elevation 3단계. 각 단계는 [가까운 레이어, 먼 레이어]다. 값은 spec 표를 그대로 옮겼다.
19
+ * `shadow-<이름>` class와 공개 계약 `--tide-shadow-<이름>`이 쓴다. Theme에 따라 `--tide-shadow-color`만 바뀐다.
20
+ * - sm: Switch thumb
21
+ * - md: Popover, 목록, Tooltip, Toast
22
+ * - lg: Dialog류
23
+ */
24
+ const shadow = {
25
+ sm: [{
26
+ x: 0,
27
+ y: 1,
28
+ blur: 1,
29
+ spread: 0,
30
+ mix: 60
31
+ }, {
32
+ x: 0,
33
+ y: 1,
34
+ blur: 2,
35
+ spread: 0,
36
+ mix: 100
37
+ }],
38
+ md: [{
39
+ x: 0,
40
+ y: 1,
41
+ blur: 3,
42
+ spread: 0,
43
+ mix: 50
44
+ }, {
45
+ x: 0,
46
+ y: 4,
47
+ blur: 12,
48
+ spread: -2,
49
+ mix: 100
50
+ }],
51
+ lg: [{
52
+ x: 0,
53
+ y: 2,
54
+ blur: 6,
55
+ spread: -1,
56
+ mix: 50
57
+ }, {
58
+ x: 0,
59
+ y: 12,
60
+ blur: 24,
61
+ spread: -6,
62
+ mix: 100
63
+ }]
64
+ };
65
+ /**
66
+ * 포커스 표시 ring의 두께와 offset. 공개 계약은 `--tide-focus-ring-width`, `--tide-focus-ring-offset`이다.
67
+ * `focus-ring` utility가 쓰고, `focus-field`의 투명 outline 두께도 같은 값을 쓴다.
68
+ */
69
+ const focusRing = {
70
+ width: "2px",
71
+ offset: "2px"
72
+ };
73
+ /** 길이 하나를 CSS로 쓴다. 0은 단위 없이 쓴다. */
74
+ const length = (px) => px === 0 ? "0" : `${px}px`;
75
+ /**
76
+ * Elevation 단계를 CSS `box-shadow` 값으로 만든다. 두 레이어 모두
77
+ * `color-mix(in srgb, var(--tide-shadow-color) N%, transparent)`로 색을 낮춘다(100%도 같은 형태로 쓴다).
78
+ * @internal `@tide-tds/foundation/internal` 전용. 앱 개발자용 공개 계약이 아니다(문서 앱·빌드 스크립트·테스트용).
79
+ */
80
+ function shadowCss(name) {
81
+ return shadow[name].map((layer) => {
82
+ const lengths = [
83
+ layer.x,
84
+ layer.y,
85
+ layer.blur,
86
+ ...layer.spread === 0 ? [] : [layer.spread]
87
+ ];
88
+ const color = `color-mix(in srgb, var(--tide-shadow-color) ${layer.mix}%, transparent)`;
89
+ return `${lengths.map(length).join(" ")} ${color}`;
90
+ }).join(", ");
91
+ }
92
+
93
+ export { focusRing, radius, shadow, shadowCss };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 쌓임 단계 5개. 뒤에서부터 앞 순서다. `z-<이름>` class와 공개 계약 `--tide-z-<이름>`이 쓴다.
3
+ * - sticky: 앱의 sticky 헤더·사이드바(v0 Tide Component는 쓰지 않음)
4
+ * - modal: Dialog·AlertDialog와 그 backdrop
5
+ * - popover: Popover, Menu, Select·Combobox 목록
6
+ * - toast: Toast 영역
7
+ * - tooltip: Tooltip
8
+ */
9
+ export declare const zIndex: {
10
+ readonly sticky: 100;
11
+ readonly modal: 200;
12
+ readonly popover: 300;
13
+ readonly toast: 400;
14
+ readonly tooltip: 500;
15
+ };
16
+ /** 쌓임 단계 이름 */
17
+ export type ZIndexName = keyof typeof zIndex;
@@ -0,0 +1,18 @@
1
+ // src/stacking.ts
2
+ /**
3
+ * 쌓임 단계 5개. 뒤에서부터 앞 순서다. `z-<이름>` class와 공개 계약 `--tide-z-<이름>`이 쓴다.
4
+ * - sticky: 앱의 sticky 헤더·사이드바(v0 Tide Component는 쓰지 않음)
5
+ * - modal: Dialog·AlertDialog와 그 backdrop
6
+ * - popover: Popover, Menu, Select·Combobox 목록
7
+ * - toast: Toast 영역
8
+ * - tooltip: Tooltip
9
+ */
10
+ const zIndex = {
11
+ sticky: 100,
12
+ modal: 200,
13
+ popover: 300,
14
+ toast: 400,
15
+ tooltip: 500
16
+ };
17
+
18
+ export { zIndex };
@@ -0,0 +1,5 @@
1
+ /* 이 파일은 @tide-tds/foundation 빌드 스크립트가 만든다. 직접 고치지 않는다. */
2
+ import type { ConfigExtension, DefaultClassGroupIds, DefaultThemeGroupIds } from "tailwind-merge";
3
+
4
+ /** `extendTailwindMerge`에 넘기는 Tide 설정 */
5
+ export declare const tailwindMergeConfig: ConfigExtension<DefaultClassGroupIds, DefaultThemeGroupIds>;