@designbasekorea/ui-contracts 0.1.2

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/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @designbasekorea/ui-contracts
3
+ *
4
+ * 웹(ui-wc)과 React Native(ui-native)가 공유하는 컴포넌트 API 계약.
5
+ *
6
+ * 소스는 하나도 공유하지 않는다 — 웹은 커스텀 엘리먼트 + CSS, RN 은 View/StyleSheet 라
7
+ * 구현을 공유할 방법이 없다. 대신 "무엇을 받아들이는가"는 공유한다.
8
+ * 그래야 디자이너가 말하는 variant 이름이 양쪽에서 같은 것을 가리킨다.
9
+ *
10
+ * 사용법:
11
+ * 웹 — `import { BUTTON_VARIANTS } from '@designbasekorea/ui-contracts'`
12
+ * attribute 문자열 검증에 배열을 그대로 쓴다.
13
+ * RN — `import type { ButtonVariant } from '@designbasekorea/ui-contracts'`
14
+ * prop 타입으로 쓴다.
15
+ */
16
+
17
+ export * from './primitives.js';
18
+ export * from './components.js';
@@ -0,0 +1,64 @@
1
+ /**
2
+ * 여러 컴포넌트가 공유하는 기본 스케일.
3
+ *
4
+ * 개별 컴포넌트가 자기만의 s/m/l 을 따로 선언하면 한쪽에서 값이 추가될 때
5
+ * 다른 쪽이 조용히 뒤처진다. 스케일은 여기서만 정의한다.
6
+ */
7
+
8
+ /** 표준 3단계 스케일 — 대부분의 컨트롤(Button, Input, Checkbox 등)이 사용한다 */
9
+ export const SIZE_SML = ['s', 'm', 'l'] as const;
10
+ export type SizeSML = (typeof SIZE_SML)[number];
11
+
12
+ /** 확장 5단계 스케일 — Spinner, Skeleton 등 시각 요소가 사용한다 */
13
+ export const SIZE_XS_XL = ['xs', 's', 'm', 'l', 'xl'] as const;
14
+ export type SizeXsXl = (typeof SIZE_XS_XL)[number];
15
+
16
+ /** Avatar 전용 6단계 스케일 */
17
+ export const SIZE_XS_2XL = ['xs', 's', 'm', 'l', 'xl', '2xl'] as const;
18
+ export type SizeXs2Xl = (typeof SIZE_XS_2XL)[number];
19
+
20
+ /**
21
+ * 피드백 톤.
22
+ *
23
+ * ⚠️ `error` 가 아니라 `danger` 다. 디자인 토큰은 내부적으로 `feedback.error` 라는
24
+ * 키를 쓰지만, 컴포넌트 공개 API 는 danger 로 통일한다. 토큰 키와 API 이름이
25
+ * 다른 것은 의도된 것이며, 매핑은 각 구현체가 담당한다.
26
+ */
27
+ export const FEEDBACK_TONES = ['info', 'success', 'warning', 'danger'] as const;
28
+ export type FeedbackTone = (typeof FEEDBACK_TONES)[number];
29
+
30
+ /** 둥글기 스케일 */
31
+ export const RADIUS_SCALE = ['none', 's', 'm', 'l', 'pill'] as const;
32
+ export type RadiusScale = (typeof RADIUS_SCALE)[number];
33
+
34
+ /**
35
+ * 계약 위반을 런타임에 잡기 위한 헬퍼.
36
+ *
37
+ * 웹 커스텀 엘리먼트는 attribute 로 임의의 문자열을 받으므로, 계약에 없는 값이
38
+ * 들어오면 기본값으로 되돌린다. RN 은 타입으로 막히니 이 헬퍼가 필요 없다.
39
+ */
40
+ export function coerceToContract<T extends readonly string[]>(
41
+ value: string | null | undefined,
42
+ allowed: T,
43
+ fallback: T[number],
44
+ ): T[number] {
45
+ return value && (allowed as readonly string[]).includes(value)
46
+ ? (value as T[number])
47
+ : fallback;
48
+ }
49
+
50
+ /**
51
+ * `coerceToContract` 와 같지만, 계약에서 빠진 구 이름을 별칭표로 한 번 접는다.
52
+ * 이름을 바꾼 뒤에도 이미 배포된 마크업이 계속 동작하게 하는 용도다.
53
+ */
54
+ export function coerceWithAliases<T extends readonly string[]>(
55
+ value: string | null | undefined,
56
+ allowed: T,
57
+ aliases: Readonly<Record<string, T[number]>>,
58
+ fallback: T[number],
59
+ ): T[number] {
60
+ if (value && !(allowed as readonly string[]).includes(value) && value in aliases) {
61
+ return aliases[value];
62
+ }
63
+ return coerceToContract(value, allowed, fallback);
64
+ }