@ihabdevteam/core 0.9.10 → 0.10.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.
@@ -54,47 +54,79 @@ textarea {
54
54
 
55
55
  /* ── 타이포그래피 헬퍼 (전역) ────────────────────────────── */
56
56
  /* 값은 전부 tokens.css의 --text-* 변수에서 온다(반응형·글자 크기 스케일 포함).
57
- 여기서는 "어떤 변수를 쓰는지"만 정의한다 — 수치를 바꾸려면 tokens.css를 고친다. */
57
+ 여기서는 "어떤 변수를 쓰는지"만 정의한다 — 수치를 바꾸려면 tokens.css를 고친다.
58
+
59
+ **왜 전부 :where() 로 감쌌나 — 이것은 기본값이지 강제가 아니다.**
60
+ 이 번들은 소비자 앱과 섞이지 않게 모든 셀렉터에 `.ihabdevteam-core-scope` 를
61
+ 붙여 내보낸다. 그러면 `.h0` 이 `.ihabdevteam-core-scope .h0`(특이도 0-2-0)이
62
+ 되어, 앱이 `.lp-hero-sub`(0-1-0) 한 겹으로 적은 여백·크기를 **통째로 눌러
63
+ 이긴다.** 바로 아래 "margin은 0 기본, 필요 시 컴포넌트에서 override" 라고 적어
64
+ 두고도 그 override 가 성립하지 않았다.
65
+
66
+ 실측으로 확인한 피해 — 회원앱 랜딩 한 화면에서 다섯 자리가 눌렸고, 그중 셋은
67
+ **코어 자신의 컴포넌트**였다(payment-plan__quote · payment-plan__subtitle ·
68
+ site-footer__copyright). 히어로에서는 `margin-bottom: 32px` 가 0px 이 되어 제목·
69
+ 본문·단추가 맞붙었고, 모바일에서 앱이 정한 26px 제목이 h0 의 28px 로 되돌아갔다.
70
+
71
+ `:where()` 는 안에 무엇이 들어 있든 특이도가 0 이다. postcss 설정이 프리픽스도
72
+ `:where(.ihabdevteam-core-scope)` 로 감싸므로(postcss.config.cjs 참고) 최종
73
+ 특이도가 0-0-0 이 되어, 앱의 어떤 클래스 규칙이든 이 기본값을 덮을 수 있다.
74
+ 타이포 헬퍼는 **바탕**이고 화면이 그 위에 자기 판단을 얹는다 — 그것이 원래
75
+ 의도였고, 이제 실제로 그렇게 된다. */
76
+
77
+ /* Display — h0 위의 세 단. 랜딩·히어로처럼 크게 외치는 자리 전용이다.
78
+ h 단과 달리 크기가 뷰포트를 따라 연속으로 변한다(tokens.css 의 clamp) — 까닭은
79
+ 그쪽 주석에 적어 두었다. 앱 화면 제목에는 h0~h5 를 쓴다. */
80
+ :where(.display-1), :where(.display-1b) { font-size: var(--text-display-1-size); line-height: var(--text-display-1-line); letter-spacing: var(--text-display-1-spacing); margin: 0; }
81
+ :where(.display-2), :where(.display-2b) { font-size: var(--text-display-2-size); line-height: var(--text-display-2-line); letter-spacing: var(--text-display-2-spacing); margin: 0; }
82
+ :where(.display-3), :where(.display-3b) { font-size: var(--text-display-3-size); line-height: var(--text-display-3-line); letter-spacing: var(--text-display-3-spacing); margin: 0; }
83
+
84
+ :where(.display-1) { font-weight: var(--text-display-1-weight); }
85
+ :where(.display-2) { font-weight: var(--text-display-2-weight); }
86
+ :where(.display-3) { font-weight: var(--text-display-3-weight); }
87
+ :where(.display-1b) { font-weight: var(--text-display-1-weight-bold); }
88
+ :where(.display-2b) { font-weight: var(--text-display-2-weight-bold); }
89
+ :where(.display-3b) { font-weight: var(--text-display-3-weight-bold); }
58
90
 
59
91
  /* Heading — margin은 0 기본, 필요 시 컴포넌트에서 override */
60
- .h0, .h0b { font-size: var(--text-h0-size); line-height: var(--text-h0-line); letter-spacing: var(--text-h0-spacing); margin: 0; }
61
- .h1, .h1b { font-size: var(--text-h1-size); line-height: var(--text-h1-line); letter-spacing: var(--text-h1-spacing); margin: 0; }
62
- .h2, .h2b { font-size: var(--text-h2-size); line-height: var(--text-h2-line); letter-spacing: var(--text-h2-spacing); margin: 0; }
63
- .h3, .h3b { font-size: var(--text-h3-size); line-height: var(--text-h3-line); letter-spacing: var(--text-h3-spacing); margin: 0; }
64
- .h4, .h4b { font-size: var(--text-h4-size); line-height: var(--text-h4-line); letter-spacing: var(--text-h4-spacing); margin: 0; }
65
- .h5, .h5b { font-size: var(--text-h5-size); line-height: var(--text-h5-line); letter-spacing: var(--text-h5-spacing); margin: 0; }
92
+ :where(.h0), :where(.h0b) { font-size: var(--text-h0-size); line-height: var(--text-h0-line); letter-spacing: var(--text-h0-spacing); margin: 0; }
93
+ :where(.h1), :where(.h1b) { font-size: var(--text-h1-size); line-height: var(--text-h1-line); letter-spacing: var(--text-h1-spacing); margin: 0; }
94
+ :where(.h2), :where(.h2b) { font-size: var(--text-h2-size); line-height: var(--text-h2-line); letter-spacing: var(--text-h2-spacing); margin: 0; }
95
+ :where(.h3), :where(.h3b) { font-size: var(--text-h3-size); line-height: var(--text-h3-line); letter-spacing: var(--text-h3-spacing); margin: 0; }
96
+ :where(.h4), :where(.h4b) { font-size: var(--text-h4-size); line-height: var(--text-h4-line); letter-spacing: var(--text-h4-spacing); margin: 0; }
97
+ :where(.h5), :where(.h5b) { font-size: var(--text-h5-size); line-height: var(--text-h5-line); letter-spacing: var(--text-h5-spacing); margin: 0; }
66
98
 
67
99
  /* Weight */
68
- .h0 { font-weight: var(--text-h0-weight); }
69
- .h1 { font-weight: var(--text-h1-weight); }
70
- .h2 { font-weight: var(--text-h2-weight); }
71
- .h3 { font-weight: var(--text-h3-weight); }
72
- .h4 { font-weight: var(--text-h4-weight); }
73
- .h5 { font-weight: var(--text-h5-weight); }
74
- .h0b { font-weight: var(--text-h0-weight-bold); }
75
- .h1b { font-weight: var(--text-h1-weight-bold); }
76
- .h2b { font-weight: var(--text-h2-weight-bold); }
77
- .h3b { font-weight: var(--text-h3-weight-bold); }
78
- .h4b { font-weight: var(--text-h4-weight-bold); }
79
- .h5b { font-weight: var(--text-h5-weight-bold); }
100
+ :where(.h0) { font-weight: var(--text-h0-weight); }
101
+ :where(.h1) { font-weight: var(--text-h1-weight); }
102
+ :where(.h2) { font-weight: var(--text-h2-weight); }
103
+ :where(.h3) { font-weight: var(--text-h3-weight); }
104
+ :where(.h4) { font-weight: var(--text-h4-weight); }
105
+ :where(.h5) { font-weight: var(--text-h5-weight); }
106
+ :where(.h0b) { font-weight: var(--text-h0-weight-bold); }
107
+ :where(.h1b) { font-weight: var(--text-h1-weight-bold); }
108
+ :where(.h2b) { font-weight: var(--text-h2-weight-bold); }
109
+ :where(.h3b) { font-weight: var(--text-h3-weight-bold); }
110
+ :where(.h4b) { font-weight: var(--text-h4-weight-bold); }
111
+ :where(.h5b) { font-weight: var(--text-h5-weight-bold); }
80
112
 
81
113
  /* Body — weight 명시 */
82
- .body-1, .body-1b { font-size: var(--text-body-1-size); line-height: var(--text-body-1-line); margin: 0; font-weight: var(--text-body-1-weight); }
83
- .body-2, .body-2b { font-size: var(--text-body-2-size); line-height: var(--text-body-2-line); margin: 0; font-weight: var(--text-body-2-weight); }
84
- .body-3, .body-3b { font-size: var(--text-body-3-size); line-height: var(--text-body-3-line); margin: 0; font-weight: var(--text-body-3-weight); }
114
+ :where(.body-1), :where(.body-1b) { font-size: var(--text-body-1-size); line-height: var(--text-body-1-line); margin: 0; font-weight: var(--text-body-1-weight); }
115
+ :where(.body-2), :where(.body-2b) { font-size: var(--text-body-2-size); line-height: var(--text-body-2-line); margin: 0; font-weight: var(--text-body-2-weight); }
116
+ :where(.body-3), :where(.body-3b) { font-size: var(--text-body-3-size); line-height: var(--text-body-3-line); margin: 0; font-weight: var(--text-body-3-weight); }
85
117
 
86
- .body-1b { font-weight: var(--text-body-1-weight-bold); }
87
- .body-2b { font-weight: var(--text-body-2-weight-bold); }
88
- .body-3b { font-weight: var(--text-body-3-weight-bold); }
118
+ :where(.body-1b) { font-weight: var(--text-body-1-weight-bold); }
119
+ :where(.body-2b) { font-weight: var(--text-body-2-weight-bold); }
120
+ :where(.body-3b) { font-weight: var(--text-body-3-weight-bold); }
89
121
 
90
122
  /* Button / Caption — button에 weight 추가, caption과 크기 차별화 */
91
- .button-1 { font-size: var(--text-button-1-size); line-height: var(--text-button-1-line); font-weight: var(--text-button-1-weight); margin: 0; }
92
- .button-2 { font-size: var(--text-button-2-size); line-height: var(--text-button-2-line); font-weight: var(--text-button-2-weight); margin: 0; }
93
- .caption-1, .caption-1b { font-size: var(--text-caption-1-size); line-height: var(--text-caption-1-line); font-weight: var(--text-caption-1-weight); margin: 0; }
94
- .caption-2, .caption-2b { font-size: var(--text-caption-2-size); line-height: var(--text-caption-2-line); font-weight: var(--text-caption-2-weight); margin: 0; }
123
+ :where(.button-1) { font-size: var(--text-button-1-size); line-height: var(--text-button-1-line); font-weight: var(--text-button-1-weight); margin: 0; }
124
+ :where(.button-2) { font-size: var(--text-button-2-size); line-height: var(--text-button-2-line); font-weight: var(--text-button-2-weight); margin: 0; }
125
+ :where(.caption-1), :where(.caption-1b) { font-size: var(--text-caption-1-size); line-height: var(--text-caption-1-line); font-weight: var(--text-caption-1-weight); margin: 0; }
126
+ :where(.caption-2), :where(.caption-2b) { font-size: var(--text-caption-2-size); line-height: var(--text-caption-2-line); font-weight: var(--text-caption-2-weight); margin: 0; }
95
127
  /* b 계열 — 크기·행간은 같고 굵기만 다르다(body-*b와 동일한 규칙) */
96
- .caption-1b { font-weight: var(--text-caption-1-weight-bold); }
97
- .caption-2b { font-weight: var(--text-caption-2-weight-bold); }
128
+ :where(.caption-1b) { font-weight: var(--text-caption-1-weight-bold); }
129
+ :where(.caption-2b) { font-weight: var(--text-caption-2-weight-bold); }
98
130
 
99
131
  /* ── 전역 스크롤바 ──────────────────────────────────────── */
100
132
  ::-webkit-scrollbar { width: 6px; height: 6px; }
@@ -133,10 +133,34 @@
133
133
  --font-family: 'Pretendard Variable', 'Pretendard', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
134
134
 
135
135
  /* ── 타입 스케일 ──────────────────────────────────────────
136
- 클래스(.h0~.h5 / .body-* / .button-* / .caption-*)는 styles.css에 있고 값은 전부
136
+ 클래스(.display-1~3 / .h0~.h5 / .body-* / .button-* / .caption-*)는 styles.css에 있고 값은 전부
137
137
  여기서 온다. 아래 반응형·글자 크기 스케일 블록이 같은 변수를 재정의하므로,
138
138
  다른 프레임워크(Tailwind @theme 등)에서도 이 변수만 읽으면 동일한 스케일을 얻는다.
139
139
  `-weight`는 기본, `-weight-bold`는 클래스명에 b가 붙은 변형(.h0b, .body-1b …)이다. */
140
+ /* ── 디스플레이 단 (display-1~3) ─────────────────────────
141
+ h0 **위**의 세 단. 앱 화면 제목이 아니라 **랜딩·히어로처럼 크게 외치는 자리** 전용이다.
142
+ 그래서 아래 h0~h5 와 규약이 셋 다르다 —
143
+
144
+ · **크기는 clamp(뷰포트 연속 보간)** 이다. h 단은 미디어쿼리로 세 계단을 뛰는데,
145
+ 히어로 글자가 계단으로 뛰면 그 폭 근처에서 줄바꿈이 툭툭 달라진다. 아래
146
+ 반응형 블록에 display 를 **다시 적지 않는 것은 그 때문**이다(적으면 계단이
147
+ 되살아난다).
148
+ · **행간은 배수, 자간은 em** 이다. 크기가 연속으로 변하는데 px 로 박으면 큰 화면
149
+ 에서 행간이 붙고 작은 화면에서 벌어진다.
150
+ · **글자 크기 스케일([data-font-scale])에서 뺀다.** h0~h3 도 같은 이유로 빠져
151
+ 있다 — 이미 충분히 크고, 키우면 히어로 한 줄이 화면을 넘긴다.
152
+
153
+ h0(40px) 과 겹치지 않게 잡았다. 어느 폭에서도 h0 < display-3 < display-2 < display-1:
154
+ 375px h0 28 · d3 34 · d2 38 · d1 44
155
+ 768px h0 32 · d3 34 · d2 40 · d1 51
156
+ 1024px h0 40 · d3 42 · d2 53 · d1 68
157
+ 1440px h0 40 · d3 44 · d2 56 · d1 72 (셋 다 최댓값 도달)
158
+ 특히 1024px 은 h0 가 32→40 으로 뛰는 지점이라, display-3 의 vw 계수(4.1)는
159
+ 그 자리에서 40 을 넘도록 잡은 값이다. 낮추면 그 폭에서만 h0 보다 작아진다. */
160
+ --text-display-1-size: clamp(44px, 6.6vw, 72px); --text-display-1-line: 1.05; --text-display-1-spacing: -0.04em; --text-display-1-weight: 800; --text-display-1-weight-bold: 900;
161
+ --text-display-2-size: clamp(38px, 5.2vw, 56px); --text-display-2-line: 1.12; --text-display-2-spacing: -0.03em; --text-display-2-weight: 700; --text-display-2-weight-bold: 800;
162
+ --text-display-3-size: clamp(34px, 4.1vw, 44px); --text-display-3-line: 1.2; --text-display-3-spacing: -0.02em; --text-display-3-weight: 700; --text-display-3-weight-bold: 800;
163
+
140
164
  --text-h0-size: 40px; --text-h0-line: 52px; --text-h0-spacing: -1px; --text-h0-weight: 700; --text-h0-weight-bold: 800;
141
165
  --text-h1-size: 32px; --text-h1-line: 44px; --text-h1-spacing: -0.5px; --text-h1-weight: 700; --text-h1-weight-bold: 800;
142
166
  --text-h2-size: 24px; --text-h2-line: 34px; --text-h2-spacing: -0.25px; --text-h2-weight: 500; --text-h2-weight-bold: 600;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ihabdevteam/core",
3
- "version": "0.9.10",
3
+ "version": "0.10.0",
4
4
  "private": false,
5
5
  "main": "dist/ihabdevteam-core.cjs.js",
6
6
  "module": "dist/ihabdevteam-core.esm.js",
@@ -81,7 +81,8 @@
81
81
  },
82
82
  "./i18n/locales/*": "./dist/packages/core/src/i18n/locales/*",
83
83
  "./styles.css": "./dist/ihabdevteam-core.css",
84
- "./tokens.css": "./dist/ihabdevteam-core-tokens.css"
84
+ "./tokens.css": "./dist/ihabdevteam-core-tokens.css",
85
+ "./fonts.css": "./dist/ihabdevteam-core-fonts.css"
85
86
  },
86
87
  "publishConfig": {
87
88
  "access": "public"
@@ -100,13 +101,13 @@
100
101
  "dist/**/*.css"
101
102
  ],
102
103
  "scripts": {
103
- "build": "(rm -rf dist node_modules/.tmp/tsconfig.core.tsbuildinfo 2>/dev/null || true) && tsc -p tsconfig.json && postcss src/styles.css -o dist/ihabdevteam-core.css && CORE_CSS_NO_PREFIX=1 postcss src/tokens.css -o dist/ihabdevteam-core-tokens.css && mkdir -p dist/packages/core/src && find src -type f \\( -name '*.css' -o -name '*.svg' -o -name '*.mp3' -o -name '*.png' \\) | while IFS= read -r f; do d=$(dirname \"$f\"); mkdir -p \"dist/packages/core/$d\"; cp \"$f\" \"dist/packages/core/$d/\"; done && mkdir -p dist/logo && if [ -d src/logo ]; then cp -r src/logo/. dist/logo/; elif [ -d ../../logo ]; then cp -r ../../logo/. dist/logo/; elif [ -d ../../public/logo ]; then cp -r ../../public/logo/. dist/logo/; fi && node scripts/check-build-outputs.mjs && rollup -c && cp dist/packages/core/src/index.d.ts dist/ihabdevteam-core.d.ts",
104
+ "build": "(rm -rf dist node_modules/.tmp/tsconfig.core.tsbuildinfo 2>/dev/null || true) && tsc -p tsconfig.json && postcss src/styles.css -o dist/ihabdevteam-core.css && CORE_CSS_NO_PREFIX=1 postcss src/tokens.css -o dist/ihabdevteam-core-tokens.css && cp src/fonts.css dist/ihabdevteam-core-fonts.css && mkdir -p dist/packages/core/src && find src -type f \\( -name '*.css' -o -name '*.svg' -o -name '*.mp3' -o -name '*.png' \\) | while IFS= read -r f; do d=$(dirname \"$f\"); mkdir -p \"dist/packages/core/$d\"; cp \"$f\" \"dist/packages/core/$d/\"; done && mkdir -p dist/logo && if [ -d src/logo ]; then cp -r src/logo/. dist/logo/; elif [ -d ../../logo ]; then cp -r ../../logo/. dist/logo/; elif [ -d ../../public/logo ]; then cp -r ../../public/logo/. dist/logo/; fi && node scripts/check-build-outputs.mjs && rollup -c && cp dist/packages/core/src/index.d.ts dist/ihabdevteam-core.d.ts",
104
105
  "extract-api": "api-extractor run --local --verbose",
105
106
  "postbuild": "npm run extract-api",
106
107
  "prepare": "npm run build",
107
108
  "prepublishOnly": "npm run build && npm run audit:exports && npm pack --dry-run > /dev/null",
108
109
  "dev": "vite serve playground --config playground/vite.config.ts",
109
- "typecheck:playground": "tsc -p playground/tsconfig.json --noEmit",
110
+ "typecheck:playground": "npm run build --silent && tsc -p playground/tsconfig.json --noEmit",
110
111
  "build-playground": "vite build playground --config playground/vite.config.js",
111
112
  "preview-playground": "vite preview --outDir playground/dist",
112
113
  "smoke-test": "node ./scripts/smoke-test.js",
@@ -126,7 +127,8 @@
126
127
  },
127
128
  "peerDependencies": {
128
129
  "react": "^16.8 || ^17 || ^18 || ^19",
129
- "react-dom": "^16.8 || ^17 || ^18 || ^19"
130
+ "react-dom": "^16.8 || ^17 || ^18 || ^19",
131
+ "pretendard": "^1.3.9"
130
132
  },
131
133
  "engines": {
132
134
  "node": ">=16"
@@ -177,5 +179,10 @@
177
179
  "path": "dist/ihabdevteam-core.esm.js",
178
180
  "limit": "800 KB"
179
181
  }
180
- ]
182
+ ],
183
+ "peerDependenciesMeta": {
184
+ "pretendard": {
185
+ "optional": true
186
+ }
187
+ }
181
188
  }