@petnow/ui 5.3.0 → 5.4.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.4.0
4
+
5
+ ### Added
6
+
7
+ - **React Native `Chip`**: Expo apps import it from the same path, `@petnow/ui/chip`. The export has a
8
+ `react-native` condition, which the React Native and Expo Metro default config (`getDefaultConfig`)
9
+ asserts for iOS and Android, so Metro resolves `dist/native/chip.js`
10
+ (`Pressable` + `Text`, styled by the app's Uniwind) while Next.js and Vite keep the web file. Its props
11
+ match the web Chip (`label`, `icon`, `selected`, `disabled`, `onPress`, `className`) plus `Pressable`
12
+ props. `icon` also receives `color`, `width` and `height` resolved from the icon token, so
13
+ `react-native-svg` icons drawn with `currentColor` follow the theme. Checked in petify-app (Expo 54,
14
+ React Native 0.81, Uniwind 1.13) on the iOS simulator and Android emulator.
15
+ - **`@petnow/ui/petnow-design-system-v1.uniwind.css`**: the v1 tokens as a Uniwind theme for Expo apps,
16
+ generated from `petnow-design-system-v1.css` by `pnpm generate:native-theme`. It defines the Uniwind
17
+ themes `light` (Petnow), `dark` (same values as light) and `petify` (switch with
18
+ `Uniwind.setTheme("petify")`; `extraThemes: ["petify"]` in `withUniwindConfig` is required, or the CSS
19
+ fails to compile), the
20
+ typography utilities with a Pretendard face per weight (`Pretendard-Regular`, `-Medium`, `-Bold`) and
21
+ without `line-height: normal`, and registers `dist/native` as a Tailwind source. Setup is in the README
22
+ (Expo 앱에서 사용).
23
+ - `react-native` (>= 0.81) and `uniwind` (^1.13) are optional peer dependencies.
24
+
25
+ ### Changes
26
+
27
+ - `tailwind.css` skips `dist/native` (`@source not`), so web builds do not generate classes used only by
28
+ the native components.
29
+ - `Chip` keeps its web output (classes, snapshot). Its props are now `ChipBaseProps` (`Chip.types.ts`)
30
+ plus button attributes, with the classes shared with the native file in `Chip.variants.ts`.
31
+
32
+ ### Fixes
33
+
34
+ - `bg-surface-base-neutral-1-alpha-1` now has a value: white at 60% (`#ffffff99`) in both themes, the
35
+ value petify-app already uses. `petnow-design-system-v1.css` mapped it in `@theme inline` but never
36
+ declared `--surface-base-neutral-1-alpha-1`, so the class drew nothing on the web and the Uniwind theme
37
+ left it out.
38
+
39
+ ## 5.3.1
40
+
41
+ ### Fixes
42
+
43
+ - `dist/index.css` declares Tailwind's `properties` layer first, before `theme, base, components, utilities`.
44
+ It declared only the last four, so when it loaded before the consumer's Tailwind CSS (a JS import in a
45
+ layout), `properties` came after `utilities`. In browsers that use Tailwind's `@supports` fallback
46
+ (Safari < 16.4, Firefox < 128), the initial `--tw-translate-*`, `--tw-shadow`, `--tw-ring-*` and
47
+ `--tw-border-style` values then overrode utilities: centered elements moved, and shadows, rings and dashed
48
+ borders were lost. Current browsers were not affected.
49
+
3
50
  ## 5.3.0
4
51
 
5
52
  ### Added
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # @petnow/ui
2
2
 
3
- 사내 웹 프로젝트에서 쓰는 공용 컴포넌트 라이브러리다. React 19와 Tailwind CSS v4를 쓰는 소비 레포를 전제로 한다.
3
+ 사내 웹 프로젝트와 Expo 앱에서 쓰는 공용 컴포넌트 라이브러리다. 웹은 React 19와 Tailwind CSS v4, Expo 앱은
4
+ Uniwind 1.x(Tailwind CSS v4)를 쓰는 소비 레포를 전제로 한다.
4
5
 
5
6
  - Storybook: https://components.petnow.co/
6
7
  - 변경 내역: [CHANGELOG.md](CHANGELOG.md)
@@ -46,18 +47,93 @@
46
47
 
47
48
  Petify 테마는 상위 요소에 `petify` 클래스를 붙이면 v1 시맨틱 컬러가 바뀐다.
48
49
 
50
+ ## Expo 앱에서 사용
51
+
52
+ 네이티브 구현(`<Component>.native.tsx`)이 있는 컴포넌트는 웹과 같은 경로로 import한다. 지금은 `Chip`
53
+ (`@petnow/ui/chip`)이다. Expo·React Native의 Metro 기본 설정(`getDefaultConfig`)은 iOS·Android 번들에서
54
+ `package.json` `exports`의 `react-native` 조건을 쓰므로 `dist/native/`의 네이티브 구현을 가져오고, Next.js·Vite는
55
+ 이 조건을 쓰지 않아 웹 구현을 가져온다. 루트 경로(`@petnow/ui`)와 deprecated `@petnow/ui/v1/*` 경로는 웹 전용이다.
56
+ Expo web 번들은 확인하지 않았다. petify-app(Expo 54, React Native 0.81, Uniwind 1.13)의 iOS 시뮬레이터와
57
+ Android 에뮬레이터에서 확인했다.
58
+
59
+ 1. 설치. `react-native`(0.81 이상)와 `uniwind`(1.13 이상)는 optional peer dependency다.
60
+
61
+ ```sh
62
+ bun add @petnow/ui
63
+ ```
64
+
65
+ 2. Metro를 Uniwind로 감싼다. 패키지 테마 CSS가 `@variant petify`를 정의하므로 `extraThemes: ["petify"]`는
66
+ 필수다. 빠지면 CSS 컴파일이 `Cannot use @variant with unknown variant: petify`로 실패한다.
67
+
68
+ ```js
69
+ // metro.config.js
70
+ const { getDefaultConfig } = require("expo/metro-config");
71
+ const { withUniwindConfig } = require("uniwind/metro");
72
+
73
+ module.exports = withUniwindConfig(getDefaultConfig(__dirname), {
74
+ cssEntryFile: "./global.css",
75
+ extraThemes: ["petify"],
76
+ });
77
+ ```
78
+
79
+ 3. Uniwind CSS 엔트리에서 Tailwind와 Uniwind 다음에 패키지 테마를 import한다.
80
+
81
+ ```css
82
+ /* global.css */
83
+ @import "tailwindcss";
84
+ @import "uniwind";
85
+ @import "@petnow/ui/petnow-design-system-v1.uniwind.css";
86
+ ```
87
+
88
+ `petnow-design-system-v1.uniwind.css`는 `petnow-design-system-v1.css`에서 생성한 파일이다. v1 참조색·시맨틱
89
+ 컬러·타이포그래피 유틸리티와 Uniwind 테마 `light`(Petnow), `dark`(아직 light와 같은 값), `petify`를 정의하고,
90
+ 패키지의 `dist/native`를 `@source`로 등록한다. 웹과 같이 `red`·`green` 등 Tailwind 기본 팔레트와 이름이 겹치는
91
+ 참조색은 `--color-*`로 매핑하지 않는다. 네이티브에서는 `.petify` 클래스가 동작하지 않는다.
92
+
93
+ 4. 테마는 앱 전체에 적용된다. Petify 테마로 바꾼다.
94
+
95
+ ```ts
96
+ import { Uniwind } from "uniwind";
97
+
98
+ Uniwind.setTheme("petify");
99
+ ```
100
+
101
+ 5. 타이포그래피 유틸리티(`text-body-14-medium` 등)는 굵기별로 `font-family: Pretendard-Regular`,
102
+ `Pretendard-Medium`, `Pretendard-Bold`를 지정한다. 앱이 Pretendard를 이 이름으로 로드해야 한다.
103
+
104
+ ```ts
105
+ const [fontsLoaded] = useFonts({
106
+ "Pretendard-Regular": require("./assets/fonts/Pretendard-Regular.otf"),
107
+ "Pretendard-Medium": require("./assets/fonts/Pretendard-Medium.otf"),
108
+ "Pretendard-Bold": require("./assets/fonts/Pretendard-Bold.otf"),
109
+ });
110
+ ```
111
+
112
+ 6. 컴포넌트를 쓴다. 타입은 `expo/tsconfig.base`의 `customConditions: ["react-native"]`로 네이티브 선언
113
+ 파일에서 풀린다.
114
+
115
+ ```tsx
116
+ import { Chip } from "@petnow/ui/chip";
117
+
118
+ <Chip label="전체" selected={selected} onPress={() => setSelected(true)} icon={FilterIcon} />;
119
+ ```
120
+
121
+ 네이티브 `Chip`의 `icon`은 `className`과 함께 토큰에서 풀어 낸 `color`·`width`·`height`를 받는다.
122
+ `react-native-svg`의 `SvgProps`를 받는 아이콘(`fill="currentColor"`)이면 그대로 동작한다.
123
+
49
124
  ## 구조
50
125
 
51
126
  ```
52
127
  @petnow/ui
53
128
  ├── tailwind.css - 소비 레포가 import하는 Tailwind 엔트리 (v0 토큰은 deprecated)
54
129
  ├── petnow-design-system-v1.css - v1 토큰(ref·시맨틱 컬러, 타이포그래피)
130
+ ├── petnow-design-system-v1.uniwind.css - Expo 앱용 Uniwind 테마 (생성 파일, `pnpm generate:native-theme`)
55
131
  ├── index.ts - 패키지 엔트리
56
132
  ├── src
57
133
  │ ├── components
58
134
  │ │ ├── ui - 내부 전용 primitive (export하지 않음)
59
135
  │ │ ├── icons - 아이콘 (action, static)
60
- │ │ └── <컴포넌트> - 컴포넌트와 스토리 (badge, checkbox, cta-button, …)
136
+ │ │ └── <컴포넌트> - 컴포넌트와 스토리 (badge, checkbox, cta-button, …), 네이티브 구현은 *.native.tsx
61
137
  │ ├── styles/components.css - dist/index.css로 복사되는 일반 CSS
62
138
  │ ├── index.css - Storybook 엔트리
63
139
  │ └── utils
@@ -76,9 +152,12 @@ Node 버전은 `mise.toml`로 고정한다. pnpm은 `package.json`의 `packageMa
76
152
  ```sh
77
153
  mise install
78
154
  pnpm i
79
- pnpm storybook # http://localhost:6006
155
+ pnpm storybook:native # http://localhost:6007, 네이티브 컴포넌트(react-native-web). 6006보다 먼저 띄운다
156
+ pnpm storybook # http://localhost:6006, 6007이 떠 있으면 "React Native"로 합성
80
157
  pnpm jest
81
- pnpm build # tsc + vite 라이브러리 빌드 + dist/index.css 복사
158
+ pnpm build # tsc + vite 라이브러리 빌드(웹, dist/native) + dist/index.css 복사
159
+ pnpm check:dist && pnpm check:dist:native
160
+ pnpm generate:native-theme # petnow-design-system-v1.css를 바꾼 뒤 Uniwind 테마 재생성
82
161
  ```
83
162
 
84
163
  ## 배포
@@ -88,5 +167,6 @@ npm Trusted Publishing(OIDC)으로 배포한다. GitHub Actions가 발급하는
88
167
 
89
168
  1. PR을 만들어 main에 merge한다. PR에서는 테스트, 포맷 검사, 빌드, Storybook 빌드가 돈다.
90
169
  2. semver에 맞춰 `v*` 태그를 push한다(예: `v5.0.0`). `.github/workflows/publish-npm.yaml`이 태그 버전으로
91
- `package.json`을 맞춰 npm에 배포하고, 버전 커밋을 main에 남긴다.
170
+ `package.json`을 맞춰 npm에 배포하고, 버전 커밋을 main에 남긴 뒤 GitHub Release(본문은 CHANGELOG의
171
+ 해당 버전 절과 PR 목록)를 만든다. 태그를 push하기 전에 CHANGELOG에 `## <버전>` 절을 적는다.
92
172
  3. 하위 호환을 깨는 변경은 [CHANGELOG.md](CHANGELOG.md)와 `docs/migration/`에 적는다.
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { t as e } from "./TailwindUtil-DiNvXuNl.js";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
+ import "react";
5
+ import { cva as r } from "class-variance-authority";
6
+ //#region src/components/chip/Chip.variants.ts
7
+ var i = "items-center justify-center gap-1 rounded-full border px-[11px] py-[7px]", a = {
8
+ true: "bg-surface-base-accent-1 border-border-prominent-accent",
9
+ false: "bg-surface-base-neutral-1 border-border-base-neutral-2"
10
+ }, o = "opacity-40", s = r("text-body-14-medium", {
11
+ variants: { selected: {
12
+ true: "text-text-prominent-accent-1",
13
+ false: "text-text-base-neutral-3"
14
+ } },
15
+ defaultVariants: { selected: !1 }
16
+ }), c = r("size-[18px] shrink-0", {
17
+ variants: { selected: {
18
+ true: "text-icon-prominent-accent-1",
19
+ false: "text-icon-base-neutral-3"
20
+ } },
21
+ defaultVariants: { selected: !1 }
22
+ }), l = r(`inline-flex ${i} transition-colors duration-200`, {
23
+ variants: {
24
+ selected: a,
25
+ disabled: {
26
+ true: `${o} pointer-events-none`,
27
+ false: ""
28
+ }
29
+ },
30
+ defaultVariants: {
31
+ selected: !1,
32
+ disabled: !1
33
+ }
34
+ }), u = ({ className: r, label: i, icon: a, selected: o = !1, disabled: u = !1, onPress: d, onClick: f, type: p = "button", ...m }) => /* @__PURE__ */ n("button", {
35
+ type: p,
36
+ className: e(l({
37
+ selected: o,
38
+ disabled: u
39
+ }), r),
40
+ onClick: (e) => {
41
+ f?.(e), e.defaultPrevented || d?.();
42
+ },
43
+ disabled: u,
44
+ ...m,
45
+ children: [a && /* @__PURE__ */ t(a, { className: c({ selected: o }) }), /* @__PURE__ */ t("span", {
46
+ className: s({ selected: o }),
47
+ children: i
48
+ })]
49
+ });
50
+ //#endregion
51
+ export { u as t };
52
+
53
+ //# sourceMappingURL=Chip-Bu5q0mhe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chip-Bu5q0mhe.js","names":[],"sources":["../src/components/chip/Chip.variants.ts","../src/components/chip/Chip.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\n// 웹·네이티브 공통 클래스. Uniwind(React Native)에서도 동작하는 유틸리티만 둔다.\n// 플랫폼 전용 클래스(inline-flex, transition, pointer-events 등)는 각 구현 파일에서 더한다.\nexport const chipBaseClassName = \"items-center justify-center gap-1 rounded-full border px-[11px] py-[7px]\";\n\nexport const chipSelectedClassNames = {\n true: \"bg-surface-base-accent-1 border-border-prominent-accent\",\n false: \"bg-surface-base-neutral-1 border-border-base-neutral-2\",\n};\n\nexport const chipDisabledClassName = \"opacity-40\";\n\nexport const chipTextVariants = cva(\"text-body-14-medium\", {\n variants: {\n selected: {\n true: \"text-text-prominent-accent-1\",\n false: \"text-text-base-neutral-3\",\n },\n },\n defaultVariants: {\n selected: false,\n },\n});\n\nexport const chipIconVariants = cva(\"size-[18px] shrink-0\", {\n variants: {\n selected: {\n true: \"text-icon-prominent-accent-1\",\n false: \"text-icon-base-neutral-3\",\n },\n },\n defaultVariants: {\n selected: false,\n },\n});\n","\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport * as React from \"react\";\n\nimport {\n chipBaseClassName,\n chipDisabledClassName,\n chipIconVariants,\n chipSelectedClassNames,\n chipTextVariants,\n} from \"./Chip.variants\";\nimport { cn } from \"../../utils/TailwindUtil\";\n\nimport type { ChipBaseProps } from \"./Chip.types\";\n\nexport interface ChipProps\n extends ChipBaseProps,\n Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"children\" | keyof ChipBaseProps> {}\n\nconst chipVariants = cva(`inline-flex ${chipBaseClassName} transition-colors duration-200`, {\n variants: {\n selected: chipSelectedClassNames,\n disabled: {\n true: `${chipDisabledClassName} pointer-events-none`,\n false: \"\",\n },\n },\n defaultVariants: {\n selected: false,\n disabled: false,\n },\n});\n\nconst Chip = ({\n className,\n label,\n icon: Icon,\n selected = false,\n disabled = false,\n onPress,\n onClick,\n type = \"button\",\n ...props\n}: ChipProps) => {\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.defaultPrevented) {\n onPress?.();\n }\n };\n\n return (\n <button\n type={type}\n className={cn(chipVariants({ selected, disabled }), className)}\n onClick={handleClick}\n disabled={disabled}\n {...props}\n >\n {Icon && <Icon className={chipIconVariants({ selected })} />}\n <span className={chipTextVariants({ selected })}>{label}</span>\n </button>\n );\n};\n\nexport { Chip };\n"],"mappings":";;;;;;AAIA,IAAa,IAAoB,4EAEpB,IAAyB;CACpC,MAAM;CACN,OAAO;AACT,GAEa,IAAwB,cAExB,IAAmB,EAAI,uBAAuB;CACzD,UAAU,EACR,UAAU;EACR,MAAM;EACN,OAAO;CACT,EACF;CACA,iBAAiB,EACf,UAAU,GACZ;AACF,CAAC,GAEY,IAAmB,EAAI,wBAAwB;CAC1D,UAAU,EACR,UAAU;EACR,MAAM;EACN,OAAO;CACT,EACF;CACA,iBAAiB,EACf,UAAU,GACZ;AACF,CAAC,GCfK,IAAe,EAAI,eAAe,EAAkB,kCAAkC;CAC1F,UAAU;EACR,UAAU;EACV,UAAU;GACR,MAAM,GAAG,EAAsB;GAC/B,OAAO;EACT;CACF;CACA,iBAAiB;EACf,UAAU;EACV,UAAU;CACZ;AACF,CAAC,GAEK,KAAQ,EACZ,cACA,UACA,MAAM,GACN,cAAW,IACX,cAAW,IACX,YACA,YACA,UAAO,UACP,GAAG,QAWD,kBAAC,UAAD;CACQ;CACN,WAAW,EAAG,EAAa;EAAE;EAAU;CAAS,CAAC,GAAG,CAAS;CAC7D,UAZiB,MAA+C;EAGlE,AAFA,IAAU,CAAK,GAEV,EAAM,oBACT,IAAU;CAEd;CAOc;CACV,GAAI;WALN,CAOG,KAAQ,kBAAC,GAAD,EAAM,WAAW,EAAiB,EAAE,YAAS,CAAC,EAAI,CAAA,GAC3D,kBAAC,QAAD;EAAM,WAAW,EAAiB,EAAE,YAAS,CAAC;YAAI;CAAY,CAAA,CACxD"}
package/dist/chip.js CHANGED
@@ -1,53 +1,3 @@
1
1
  "use client";
2
- import { t as e } from "./TailwindUtil-DiNvXuNl.js";
3
- import { jsx as t, jsxs as n } from "react/jsx-runtime";
4
- import "react";
5
- import { cva as r } from "class-variance-authority";
6
- //#region src/components/chip/Chip.tsx
7
- var i = r("inline-flex items-center justify-center gap-1 rounded-full border px-[11px] py-[7px] transition-colors duration-200", {
8
- variants: {
9
- selected: {
10
- true: "bg-surface-base-accent-1 border-border-prominent-accent",
11
- false: "bg-surface-base-neutral-1 border-border-base-neutral-2"
12
- },
13
- disabled: {
14
- true: "opacity-40 pointer-events-none",
15
- false: ""
16
- }
17
- },
18
- defaultVariants: {
19
- selected: !1,
20
- disabled: !1
21
- }
22
- }), a = r("text-body-14-medium", {
23
- variants: { selected: {
24
- true: "text-text-prominent-accent-1",
25
- false: "text-text-base-neutral-3"
26
- } },
27
- defaultVariants: { selected: !1 }
28
- }), o = r("size-[18px] shrink-0", {
29
- variants: { selected: {
30
- true: "text-icon-prominent-accent-1",
31
- false: "text-icon-base-neutral-3"
32
- } },
33
- defaultVariants: { selected: !1 }
34
- }), s = ({ className: r, label: s, icon: c, selected: l = !1, disabled: u = !1, onPress: d, onClick: f, type: p = "button", ...m }) => /* @__PURE__ */ n("button", {
35
- type: p,
36
- className: e(i({
37
- selected: l,
38
- disabled: u
39
- }), r),
40
- onClick: (e) => {
41
- f?.(e), e.defaultPrevented || d?.();
42
- },
43
- disabled: u,
44
- ...m,
45
- children: [c && /* @__PURE__ */ t(c, { className: o({ selected: l }) }), /* @__PURE__ */ t("span", {
46
- className: a({ selected: l }),
47
- children: s
48
- })]
49
- });
50
- //#endregion
51
- export { s as Chip };
52
-
53
- //# sourceMappingURL=chip.js.map
2
+ import { t as e } from "./Chip-Bu5q0mhe.js";
3
+ export { e as Chip };
package/dist/index.css CHANGED
@@ -6,10 +6,13 @@
6
6
  The rules sit in Tailwind's `components` layer so consumer utilities can
7
7
  override them. The order statement comes first because this file may load
8
8
  before the consumer's Tailwind CSS (e.g. a JS import in a layout); without it,
9
- `components` would be declared first and lose to Tailwind's preflight.
9
+ `components` would be declared first and lose to Tailwind's preflight. It
10
+ lists every layer Tailwind declares, in Tailwind's order: a missing
11
+ `properties` would be declared after `utilities` and win over it in browsers
12
+ that use Tailwind's `@supports` fallback (Safari < 16.4, Firefox < 128).
10
13
  */
11
14
 
12
- @layer theme, base, components, utilities;
15
+ @layer properties, theme, base, components, utilities;
13
16
 
14
17
  @layer components {
15
18
  /* Scrollbar CSS */
package/dist/index.es.js CHANGED
@@ -3,7 +3,7 @@ import t from "./tabs.js";
3
3
  import n from "./checkbox.js";
4
4
  import r from "./toggle.js";
5
5
  import { Badge as i } from "./badge.js";
6
- import { Chip as a } from "./chip.js";
6
+ import { t as a } from "./Chip-Bu5q0mhe.js";
7
7
  import { CTAButton as o } from "./cta-button.js";
8
8
  import { t as s } from "./Popup-DRf-ERpL.js";
9
9
  import { CancelFilledIcon as c } from "./icons/action/cancel-filled.js";
@@ -0,0 +1,134 @@
1
+ import { cva as e } from "class-variance-authority";
2
+ import { Pressable as t, Text as n } from "react-native";
3
+ import { useResolveClassNames as r } from "uniwind";
4
+ import { clsx as i } from "clsx";
5
+ import { extendTailwindMerge as a } from "tailwind-merge";
6
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ //#region src/components/chip/Chip.variants.ts
8
+ var c = "items-center justify-center gap-1 rounded-full border px-[11px] py-[7px]", l = {
9
+ true: "bg-surface-base-accent-1 border-border-prominent-accent",
10
+ false: "bg-surface-base-neutral-1 border-border-base-neutral-2"
11
+ }, u = "opacity-40", d = e("text-body-14-medium", {
12
+ variants: { selected: {
13
+ true: "text-text-prominent-accent-1",
14
+ false: "text-text-base-neutral-3"
15
+ } },
16
+ defaultVariants: { selected: !1 }
17
+ }), f = e("size-[18px] shrink-0", {
18
+ variants: { selected: {
19
+ true: "text-icon-prominent-accent-1",
20
+ false: "text-icon-base-neutral-3"
21
+ } },
22
+ defaultVariants: { selected: !1 }
23
+ }), p = a({ extend: {
24
+ classGroups: { "font-style": [
25
+ "text-display-96-bold",
26
+ "text-display-96-medium",
27
+ "text-display-72-bold",
28
+ "text-display-72-medium",
29
+ "text-display-60-bold",
30
+ "text-display-60-medium",
31
+ "text-headline-48-bold",
32
+ "text-headline-48-medium",
33
+ "text-headline-48-regular",
34
+ "text-headline-42-bold",
35
+ "text-headline-42-medium",
36
+ "text-headline-42-regular",
37
+ "text-headline-36-bold",
38
+ "text-headline-36-medium",
39
+ "text-headline-36-regular",
40
+ "text-title-28-bold",
41
+ "text-title-28-medium",
42
+ "text-title-28-regular",
43
+ "text-title-24-bold",
44
+ "text-title-24-medium",
45
+ "text-title-24-regular",
46
+ "text-title-20-bold",
47
+ "text-title-20-medium",
48
+ "text-title-20-regular",
49
+ "text-title-18-bold",
50
+ "text-title-18-medium",
51
+ "text-title-18-regular",
52
+ "text-title-16-bold",
53
+ "text-title-14-bold",
54
+ "text-body-16-medium",
55
+ "text-body-16-regular",
56
+ "text-body-14-medium",
57
+ "text-body-14-regular",
58
+ "text-body-12-bold",
59
+ "text-caption-12-bold",
60
+ "text-caption-12-medium",
61
+ "text-caption-12-regular",
62
+ "text-caption-11-medium",
63
+ "text-caption-10-bold",
64
+ { text: [
65
+ "display-large",
66
+ "display-medium",
67
+ "title-large",
68
+ "title-medium",
69
+ "title-small",
70
+ "label-large",
71
+ "label-medium",
72
+ "label-small",
73
+ "body-large",
74
+ "body-medium",
75
+ "body-small",
76
+ "caption-large",
77
+ "caption-medium",
78
+ "caption-small",
79
+ "badge"
80
+ ] }
81
+ ] },
82
+ conflictingClassGroups: { "font-style": ["font-size", "font-weight"] }
83
+ } });
84
+ function m(...e) {
85
+ return p(i(e));
86
+ }
87
+ //#endregion
88
+ //#region src/components/chip/Chip.native.tsx
89
+ var h = (e) => {
90
+ if (typeof e == "number") return e;
91
+ if (typeof e == "string" && /^\d+(\.\d+)?px$/.test(e)) return parseFloat(e);
92
+ }, g = e(`flex-row self-start ${c}`, {
93
+ variants: {
94
+ selected: l,
95
+ disabled: {
96
+ true: u,
97
+ false: ""
98
+ }
99
+ },
100
+ defaultVariants: {
101
+ selected: !1,
102
+ disabled: !1
103
+ }
104
+ }), _ = ({ className: e, label: i, icon: a, selected: c = !1, disabled: l = !1, onPress: u, accessibilityState: p, ..._ }) => {
105
+ let v = f({ selected: c }), y = r(v);
106
+ return /* @__PURE__ */ s(t, {
107
+ accessibilityRole: "button",
108
+ accessibilityState: {
109
+ ...p,
110
+ selected: c,
111
+ disabled: l
112
+ },
113
+ className: m(g({
114
+ selected: c,
115
+ disabled: l
116
+ }), e),
117
+ onPress: u,
118
+ disabled: l,
119
+ ..._,
120
+ children: [a && /* @__PURE__ */ o(a, {
121
+ className: v,
122
+ color: y.color,
123
+ width: h(y.width),
124
+ height: h(y.height)
125
+ }), /* @__PURE__ */ o(n, {
126
+ className: d({ selected: c }),
127
+ children: i
128
+ })]
129
+ });
130
+ };
131
+ //#endregion
132
+ export { _ as Chip };
133
+
134
+ //# sourceMappingURL=chip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chip.js","names":[],"sources":["../../src/components/chip/Chip.variants.ts","../../src/utils/TailwindUtil.ts","../../src/components/chip/Chip.native.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\n\n// 웹·네이티브 공통 클래스. Uniwind(React Native)에서도 동작하는 유틸리티만 둔다.\n// 플랫폼 전용 클래스(inline-flex, transition, pointer-events 등)는 각 구현 파일에서 더한다.\nexport const chipBaseClassName = \"items-center justify-center gap-1 rounded-full border px-[11px] py-[7px]\";\n\nexport const chipSelectedClassNames = {\n true: \"bg-surface-base-accent-1 border-border-prominent-accent\",\n false: \"bg-surface-base-neutral-1 border-border-base-neutral-2\",\n};\n\nexport const chipDisabledClassName = \"opacity-40\";\n\nexport const chipTextVariants = cva(\"text-body-14-medium\", {\n variants: {\n selected: {\n true: \"text-text-prominent-accent-1\",\n false: \"text-text-base-neutral-3\",\n },\n },\n defaultVariants: {\n selected: false,\n },\n});\n\nexport const chipIconVariants = cva(\"size-[18px] shrink-0\", {\n variants: {\n selected: {\n true: \"text-icon-prominent-accent-1\",\n false: \"text-icon-base-neutral-3\",\n },\n },\n defaultVariants: {\n selected: false,\n },\n});\n","import { type ClassValue, clsx } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\nconst customTwMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n \"font-style\": [\n // Display\n \"text-display-96-bold\",\n \"text-display-96-medium\",\n \"text-display-72-bold\",\n \"text-display-72-medium\",\n \"text-display-60-bold\",\n \"text-display-60-medium\",\n // Headline\n \"text-headline-48-bold\",\n \"text-headline-48-medium\",\n \"text-headline-48-regular\",\n \"text-headline-42-bold\",\n \"text-headline-42-medium\",\n \"text-headline-42-regular\",\n \"text-headline-36-bold\",\n \"text-headline-36-medium\",\n \"text-headline-36-regular\",\n // Title\n \"text-title-28-bold\",\n \"text-title-28-medium\",\n \"text-title-28-regular\",\n \"text-title-24-bold\",\n \"text-title-24-medium\",\n \"text-title-24-regular\",\n \"text-title-20-bold\",\n \"text-title-20-medium\",\n \"text-title-20-regular\",\n \"text-title-18-bold\",\n \"text-title-18-medium\",\n \"text-title-18-regular\",\n \"text-title-16-bold\",\n \"text-title-14-bold\",\n // Body\n \"text-body-16-medium\",\n \"text-body-16-regular\",\n \"text-body-14-medium\",\n \"text-body-14-regular\",\n \"text-body-12-bold\",\n // Caption\n \"text-caption-12-bold\",\n \"text-caption-12-medium\",\n \"text-caption-12-regular\",\n \"text-caption-11-medium\",\n \"text-caption-10-bold\",\n {\n text: [\n \"display-large\",\n \"display-medium\",\n \"title-large\",\n \"title-medium\",\n \"title-small\",\n \"label-large\",\n \"label-medium\",\n \"label-small\",\n \"body-large\",\n \"body-medium\",\n \"body-small\",\n \"caption-large\",\n \"caption-medium\",\n \"caption-small\",\n \"badge\",\n ],\n },\n ],\n },\n conflictingClassGroups: {\n \"font-style\": [\"font-size\", \"font-weight\"], // 예시: 폰트 크기, 굵기와 충돌 가능성 명시\n // 기존 색상 관련 그룹과의 충돌을 피하기 위해 textColor 그룹을 명시적으로 선언하거나,\n // text-label-large가 색상과 관련 없음을 tailwind-merge에 알려야 합니다.\n // 만약 text-label-large가 특정 색상을 포함하지 않는다면,\n // textColor 그룹과의 충돌을 정의할 필요는 없을 수 있습니다.\n // 하지만, 만약 text-red-500과 같은 클래스와 충돌한다면,\n // textColor 그룹과의 관계를 명확히 해야 합니다.\n // 가장 간단한 방법은 text-label-large를 textColor 그룹에서 제외하는 것입니다.\n // 또는, text-label-large가 독립적인 그룹임을 명시합니다.\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return customTwMerge(clsx(inputs));\n}\n","import { cva } from \"class-variance-authority\";\nimport { type ColorValue, Pressable, type PressableProps, Text } from \"react-native\";\nimport { useResolveClassNames } from \"uniwind\";\n\nimport {\n chipBaseClassName,\n chipDisabledClassName,\n chipIconVariants,\n chipSelectedClassNames,\n chipTextVariants,\n} from \"./Chip.variants\";\nimport { cn } from \"../../utils/TailwindUtil\";\n\nimport type { ChipBaseProps } from \"./Chip.types\";\nimport type { ComponentType } from \"react\";\n\n// react-native-svg 아이콘은 className으로 색·크기를 받지 못하므로 해석한 값을 color·width·height로도 넘긴다.\n// SvgProps를 받는 아이콘(react-native-svg, lucide-react-native)이 이 형태를 만족한다.\nexport interface ChipIconProps {\n className?: string;\n color?: ColorValue;\n width?: number;\n height?: number;\n}\n\n// 네이티브는 숫자, react-native-web은 \"18px\" 같은 문자열로 풀린다.\nconst toNumber = (value: unknown) => {\n if (typeof value === \"number\") return value;\n if (typeof value === \"string\" && /^\\d+(\\.\\d+)?px$/.test(value)) return parseFloat(value);\n return undefined;\n};\n\nexport interface ChipProps\n extends Omit<ChipBaseProps, \"icon\">,\n Omit<PressableProps, \"children\" | \"style\" | keyof ChipBaseProps> {\n icon?: ComponentType<ChipIconProps>;\n}\n\n// self-start: 세로 방향 부모(RN 기본 flex-column)에서 칩이 가로로 늘어나지 않게 한다.\nconst chipVariants = cva(`flex-row self-start ${chipBaseClassName}`, {\n variants: {\n selected: chipSelectedClassNames,\n disabled: {\n true: chipDisabledClassName,\n false: \"\",\n },\n },\n defaultVariants: {\n selected: false,\n disabled: false,\n },\n});\n\nconst Chip = ({\n className,\n label,\n icon: Icon,\n selected = false,\n disabled = false,\n onPress,\n accessibilityState,\n ...props\n}: ChipProps) => {\n const iconClassName = chipIconVariants({ selected });\n // 테마(Uniwind.setTheme)가 바뀌면 다시 해석된다.\n const iconStyle = useResolveClassNames(iconClassName);\n\n return (\n <Pressable\n accessibilityRole=\"button\"\n accessibilityState={{ ...accessibilityState, selected, disabled }}\n className={cn(chipVariants({ selected, disabled }), className)}\n onPress={onPress}\n disabled={disabled}\n {...props}\n >\n {Icon && (\n <Icon\n className={iconClassName}\n color={iconStyle.color}\n width={toNumber(iconStyle.width)}\n height={toNumber(iconStyle.height)}\n />\n )}\n <Text className={chipTextVariants({ selected })}>{label}</Text>\n </Pressable>\n );\n};\n\nexport { Chip };\n"],"mappings":";;;;;;;AAIA,IAAa,IAAoB,4EAEpB,IAAyB;CACpC,MAAM;CACN,OAAO;AACT,GAEa,IAAwB,cAExB,IAAmB,EAAI,uBAAuB;CACzD,UAAU,EACR,UAAU;EACR,MAAM;EACN,OAAO;CACT,EACF;CACA,iBAAiB,EACf,UAAU,GACZ;AACF,CAAC,GAEY,IAAmB,EAAI,wBAAwB;CAC1D,UAAU,EACR,UAAU;EACR,MAAM;EACN,OAAO;CACT,EACF;CACA,iBAAiB,EACf,UAAU,GACZ;AACF,CAAC,GChCK,IAAgB,EAAoB,EACxC,QAAQ;CACN,aAAa,EACX,cAAc;EAEZ;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA;EACA;EACA;EACA;EACA,EACE,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,EACF;CACF,EACF;CACA,wBAAwB,EACtB,cAAc,CAAC,aAAa,aAAa,EAS3C;AACF,EACF,CAAC;AAED,SAAgB,EAAG,GAAG,GAAsB;CAC1C,OAAO,EAAc,EAAK,CAAM,CAAC;AACnC;;;AC9DA,IAAM,KAAY,MAAmB;CACnC,IAAI,OAAO,KAAU,UAAU,OAAO;CACtC,IAAI,OAAO,KAAU,YAAY,kBAAkB,KAAK,CAAK,GAAG,OAAO,WAAW,CAAK;AAEzF,GASM,IAAe,EAAI,uBAAuB,KAAqB;CACnE,UAAU;EACR,UAAU;EACV,UAAU;GACR,MAAM;GACN,OAAO;EACT;CACF;CACA,iBAAiB;EACf,UAAU;EACV,UAAU;CACZ;AACF,CAAC,GAEK,KAAQ,EACZ,cACA,UACA,MAAM,GACN,cAAW,IACX,cAAW,IACX,YACA,uBACA,GAAG,QACY;CACf,IAAM,IAAgB,EAAiB,EAAE,YAAS,CAAC,GAE7C,IAAY,EAAqB,CAAa;CAEpD,OACE,kBAAC,GAAD;EACE,mBAAkB;EAClB,oBAAoB;GAAE,GAAG;GAAoB;GAAU;EAAS;EAChE,WAAW,EAAG,EAAa;GAAE;GAAU;EAAS,CAAC,GAAG,CAAS;EACpD;EACC;EACV,GAAI;YANN,CAQG,KACC,kBAAC,GAAD;GACE,WAAW;GACX,OAAO,EAAU;GACjB,OAAO,EAAS,EAAU,KAAK;GAC/B,QAAQ,EAAS,EAAU,MAAM;EAClC,CAAA,GAEH,kBAAC,GAAD;GAAM,WAAW,EAAiB,EAAE,YAAS,CAAC;aAAI;EAAY,CAAA,CACrD;;AAEf"}
@@ -0,0 +1,14 @@
1
+ import { ColorValue, PressableProps } from 'react-native';
2
+ import { ChipBaseProps } from './Chip.types';
3
+ import { ComponentType } from 'react';
4
+ export interface ChipIconProps {
5
+ className?: string;
6
+ color?: ColorValue;
7
+ width?: number;
8
+ height?: number;
9
+ }
10
+ export interface ChipProps extends Omit<ChipBaseProps, "icon">, Omit<PressableProps, "children" | "style" | keyof ChipBaseProps> {
11
+ icon?: ComponentType<ChipIconProps>;
12
+ }
13
+ declare const Chip: ({ className, label, icon: Icon, selected, disabled, onPress, accessibilityState, ...props }: ChipProps) => import("react").JSX.Element;
14
+ export { Chip };
@@ -0,0 +1,11 @@
1
+ import { ComponentType } from 'react';
2
+ export interface ChipBaseProps {
3
+ label: string;
4
+ icon?: ComponentType<{
5
+ className?: string;
6
+ }>;
7
+ selected?: boolean;
8
+ disabled?: boolean;
9
+ onPress?: () => void;
10
+ className?: string;
11
+ }
@@ -0,0 +1,12 @@
1
+ export declare const chipBaseClassName = "items-center justify-center gap-1 rounded-full border px-[11px] py-[7px]";
2
+ export declare const chipSelectedClassNames: {
3
+ true: string;
4
+ false: string;
5
+ };
6
+ export declare const chipDisabledClassName = "opacity-40";
7
+ export declare const chipTextVariants: (props?: ({
8
+ selected?: boolean | null | undefined;
9
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
10
+ export declare const chipIconVariants: (props?: ({
11
+ selected?: boolean | null | undefined;
12
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
@@ -0,0 +1,2 @@
1
+ import { ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,2 @@
1
+ import { Ref, RefCallback } from 'react';
2
+ export declare const mergeRefs: <T>(...refs: (Ref<T> | undefined)[]) => RefCallback<T>;
@@ -1,11 +1,6 @@
1
+ import { ChipBaseProps } from './Chip.types';
1
2
  import * as React from "react";
2
- export interface ChipProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
3
- label: string;
4
- icon?: React.ComponentType<{
5
- className?: string;
6
- }>;
7
- selected?: boolean;
8
- onPress?: () => void;
3
+ export interface ChipProps extends ChipBaseProps, Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children" | keyof ChipBaseProps> {
9
4
  }
10
5
  declare const Chip: ({ className, label, icon: Icon, selected, disabled, onPress, onClick, type, ...props }: ChipProps) => React.JSX.Element;
11
6
  export { Chip };
@@ -0,0 +1,11 @@
1
+ import { ComponentType } from 'react';
2
+ export interface ChipBaseProps {
3
+ label: string;
4
+ icon?: ComponentType<{
5
+ className?: string;
6
+ }>;
7
+ selected?: boolean;
8
+ disabled?: boolean;
9
+ onPress?: () => void;
10
+ className?: string;
11
+ }
@@ -0,0 +1,12 @@
1
+ export declare const chipBaseClassName = "items-center justify-center gap-1 rounded-full border px-[11px] py-[7px]";
2
+ export declare const chipSelectedClassNames: {
3
+ true: string;
4
+ false: string;
5
+ };
6
+ export declare const chipDisabledClassName = "opacity-40";
7
+ export declare const chipTextVariants: (props?: ({
8
+ selected?: boolean | null | undefined;
9
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
10
+ export declare const chipIconVariants: (props?: ({
11
+ selected?: boolean | null | undefined;
12
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;