@highpixel-co/palda-design-system 0.6.0 → 0.8.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/dist/styles.css CHANGED
@@ -1091,8 +1091,6 @@
1091
1091
 
1092
1092
  /* src/NavigationButton/NavigationButton.css */
1093
1093
  .palda-navigation-button {
1094
- --palda-navigation-button-icon-color: var(--palda-color-border-strong);
1095
- --palda-navigation-button-text-color: var(--palda-color-text-disabled);
1096
1094
  align-items: center;
1097
1095
  background: var(--palda-navigation-button-background, transparent);
1098
1096
  border: 0;
@@ -1100,34 +1098,55 @@
1100
1098
  box-sizing: border-box;
1101
1099
  color: var(--palda-navigation-button-text-color);
1102
1100
  cursor: pointer;
1103
- display: flex;
1104
1101
  gap: var(--palda-space-gap-sm);
1105
- height: 48px;
1106
1102
  justify-content: flex-start;
1107
- padding: var(--palda-space-3) var(--palda-space-4);
1103
+ min-width: 0;
1108
1104
  text-align: left;
1105
+ text-decoration: none;
1109
1106
  transition: background-color var(--palda-duration-fast) var(--palda-easing-standard), color var(--palda-duration-fast) var(--palda-easing-standard);
1107
+ }
1108
+ .palda-navigation-button--md {
1109
+ --palda-navigation-button-icon-color: var(--palda-color-border-strong);
1110
+ --palda-navigation-button-text-color: var(--palda-color-text-disabled);
1111
+ display: flex;
1112
+ height: 48px;
1113
+ padding: var(--palda-space-3) var(--palda-space-4);
1110
1114
  width: 100%;
1111
1115
  }
1116
+ .palda-navigation-button--sm {
1117
+ --palda-navigation-button-icon-color: var(--palda-color-primary-default);
1118
+ --palda-navigation-button-text-color: var(--palda-color-text-primary);
1119
+ display: inline-flex;
1120
+ height: 36px;
1121
+ padding: var(--palda-space-2) var(--palda-space-3);
1122
+ }
1112
1123
  .palda-navigation-button__icon {
1113
1124
  align-items: center;
1114
1125
  color: var(--palda-navigation-button-icon-color);
1115
1126
  display: inline-flex;
1116
1127
  flex-shrink: 0;
1128
+ justify-content: center;
1129
+ }
1130
+ .palda-navigation-button--md .palda-navigation-button__icon {
1117
1131
  font-size: 24px;
1118
1132
  height: 24px;
1119
- justify-content: center;
1120
1133
  width: 24px;
1121
1134
  }
1135
+ .palda-navigation-button--sm .palda-navigation-button__icon {
1136
+ font-size: 20px;
1137
+ height: 20px;
1138
+ width: 20px;
1139
+ }
1122
1140
  .palda-navigation-button__label {
1123
1141
  overflow: hidden;
1124
1142
  text-overflow: ellipsis;
1125
1143
  white-space: nowrap;
1126
1144
  }
1127
- .palda-navigation-button:not(:disabled, .palda-navigation-button--selected):is(:hover, :active) {
1145
+ .palda-navigation-button--md:not(:disabled, .palda-navigation-button--selected):is(:hover, :active),
1146
+ .palda-navigation-button--sm:not(:disabled):is(:hover, :active) {
1128
1147
  --palda-navigation-button-background: var(--palda-color-state-hover-pressed);
1129
1148
  }
1130
- .palda-navigation-button--selected {
1149
+ .palda-navigation-button--md.palda-navigation-button--selected {
1131
1150
  --palda-navigation-button-background: var(--palda-color-accent-subtle);
1132
1151
  --palda-navigation-button-icon-color: var(--palda-color-accent-default);
1133
1152
  --palda-navigation-button-text-color: var(--palda-color-text-accent);
@@ -1245,6 +1264,49 @@
1245
1264
  }
1246
1265
  }
1247
1266
 
1267
+ /* src/Skeleton/Skeleton.css */
1268
+ .palda-skeleton {
1269
+ animation: palda-skeleton-pulse var(--palda-duration-normal) var(--palda-easing-standard) infinite alternate;
1270
+ background: var(--palda-color-surface-sunken);
1271
+ border-radius: var(--palda-radius-control-sm);
1272
+ display: block;
1273
+ }
1274
+ .palda-skeleton--body1 {
1275
+ height: var(--palda-font-size-md);
1276
+ }
1277
+ .palda-skeleton--body2 {
1278
+ height: var(--palda-font-size-sm);
1279
+ }
1280
+ .palda-skeleton--label {
1281
+ height: var(--palda-font-size-xs);
1282
+ }
1283
+ .palda-skeleton--full {
1284
+ width: 100%;
1285
+ }
1286
+ .palda-skeleton--wide {
1287
+ width: 70%;
1288
+ }
1289
+ .palda-skeleton--narrow {
1290
+ width: 40%;
1291
+ }
1292
+ .palda-skeleton--block {
1293
+ block-size: 100%;
1294
+ inline-size: 100%;
1295
+ }
1296
+ @keyframes palda-skeleton-pulse {
1297
+ from {
1298
+ opacity: 1;
1299
+ }
1300
+ to {
1301
+ opacity: 0.4;
1302
+ }
1303
+ }
1304
+ @media (prefers-reduced-motion: reduce) {
1305
+ .palda-skeleton {
1306
+ animation: none;
1307
+ }
1308
+ }
1309
+
1248
1310
  /* src/Switch/Switch.css */
1249
1311
  .palda-switch {
1250
1312
  align-items: center;
@@ -1508,6 +1570,24 @@
1508
1570
  }
1509
1571
  }
1510
1572
 
1573
+ /* src/Thumbnail/Thumbnail.css */
1574
+ .palda-thumbnail {
1575
+ background: var(--palda-color-surface-raised);
1576
+ border-radius: var(--palda-radius-control);
1577
+ box-sizing: border-box;
1578
+ display: block;
1579
+ flex-shrink: 0;
1580
+ object-fit: cover;
1581
+ }
1582
+ .palda-thumbnail--md {
1583
+ height: 40px;
1584
+ width: 40px;
1585
+ }
1586
+ .palda-thumbnail--sm {
1587
+ height: 32px;
1588
+ width: 32px;
1589
+ }
1590
+
1511
1591
  /* src/Toast/Toast.css */
1512
1592
  .palda-toast {
1513
1593
  align-items: center;
@@ -1891,7 +1971,7 @@ button.palda-card {
1891
1971
  text-align: start;
1892
1972
  width: 100%;
1893
1973
  }
1894
- button.palda-card:hover {
1974
+ button.palda-card:not(.palda-card--selected):hover {
1895
1975
  border-color: var(--palda-color-border-strong);
1896
1976
  }
1897
1977
  button.palda-card:focus-visible {
@@ -2010,6 +2090,16 @@ button.palda-card:focus-visible {
2010
2090
  gap: var(--palda-space-gap-lg);
2011
2091
  min-width: 0;
2012
2092
  }
2093
+ .palda-form-section--filled .palda-form-section__fields {
2094
+ background: var(--palda-color-surface-raised);
2095
+ border-radius: var(--palda-radius-container);
2096
+ padding: var(--palda-space-inset-md);
2097
+ --palda-list-row-filled-background: var(--palda-color-surface-base);
2098
+ }
2099
+ .palda-form-section--filled .palda-text-field--outline,
2100
+ .palda-form-section--filled .palda-text-field--accent {
2101
+ --palda-text-field-background: var(--palda-color-surface-base);
2102
+ }
2013
2103
  .palda-form-section__footer {
2014
2104
  align-items: center;
2015
2105
  display: flex;
@@ -2038,7 +2128,7 @@ button.palda-card:focus-visible {
2038
2128
  border-block-end: 0;
2039
2129
  }
2040
2130
  .palda-list-row--filled {
2041
- background: var(--palda-color-surface-raised);
2131
+ background: var(--palda-list-row-filled-background, var(--palda-color-surface-raised));
2042
2132
  border-radius: var(--palda-radius-control);
2043
2133
  padding-inline: var(--palda-space-inset-md);
2044
2134
  }
@@ -2103,42 +2193,11 @@ button.palda-list-row:focus-visible {
2103
2193
  flex-direction: column;
2104
2194
  gap: var(--palda-space-gap-xs);
2105
2195
  }
2106
- .palda-list-row__skeleton {
2107
- animation: palda-list-row-pulse var(--palda-duration-normal) var(--palda-easing-standard) infinite alternate;
2108
- background: var(--palda-color-surface-sunken);
2109
- border-radius: var(--palda-radius-control-sm);
2110
- display: block;
2111
- }
2112
- .palda-list-row__skeleton--title {
2113
- height: var(--palda-font-size-sm);
2114
- width: 40%;
2115
- }
2116
- .palda-list-row__skeleton--description {
2117
- height: var(--palda-font-size-xs);
2118
- width: 70%;
2119
- }
2120
- .palda-list-row--strong .palda-list-row__skeleton--title {
2121
- height: var(--palda-font-size-md);
2122
- }
2123
- .palda-list-row--strong .palda-list-row__skeleton--description {
2124
- height: var(--palda-font-size-sm);
2125
- }
2126
- @keyframes palda-list-row-pulse {
2127
- from {
2128
- opacity: 1;
2129
- }
2130
- to {
2131
- opacity: 0.4;
2132
- }
2133
- }
2134
2196
  @media (prefers-reduced-motion: reduce) {
2135
2197
  .palda-list-row,
2136
2198
  .palda-list-row__chevron {
2137
2199
  transition: none;
2138
2200
  }
2139
- .palda-list-row__skeleton {
2140
- animation: none;
2141
- }
2142
2201
  }
2143
2202
 
2144
2203
  /* src/LivePreview/LivePreview.css */
package/dist/ui.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, AnchorHTMLAttributes, ReactElement } from 'react';
2
+ import { HTMLAttributes, ReactNode, ButtonHTMLAttributes, InputHTMLAttributes, AnchorHTMLAttributes, ImgHTMLAttributes, ReactElement } from 'react';
3
3
 
4
4
  type AlertVariant = 'neutral' | 'accent' | 'warning' | 'danger';
5
5
  interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
@@ -141,14 +141,29 @@ interface ModalProps {
141
141
  }
142
142
  declare function Modal({ children, className, closeLabel, footer, onClose, open, showCloseButton, title, }: ModalProps): react.ReactPortal | null;
143
143
 
144
- interface NavigationButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
144
+ type NavigationButtonSize = 'md' | 'sm';
145
+ interface NavigationButtonOwnProps {
145
146
  children: ReactNode;
146
- /** 라벨 앞 아이콘. 시안 기준 24px 고정이다. */
147
+ /** 라벨 앞 아이콘. md는 24px, sm은 20px 고정이다. */
147
148
  icon?: ReactNode;
148
149
  /** 지금 보고 있는 화면. `aria-current="page"`로 함께 노출된다. */
149
150
  selected?: boolean;
151
+ /**
152
+ * `md`는 사이드바 항목(48px · 아이콘 24 · semibold · 부모 폭을 채움),
153
+ * `sm`은 상단 행 항목(36px · 아이콘 20 · medium · 내용만큼)이다.
154
+ */
155
+ size?: NavigationButtonSize;
150
156
  }
151
- declare function NavigationButton({ children, className, icon, selected, ...props }: NavigationButtonProps): react.JSX.Element;
157
+ /**
158
+ * 내비게이션은 폼 제출에 쓰지 않는다. 그래서 button일 때 `type`은 노출하지 않고 button으로
159
+ * 고정하고, anchor일 때 `href`는 이 union이 필수로 만든다.
160
+ */
161
+ type NavigationButtonProps = (NavigationButtonOwnProps & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'type'> & {
162
+ href?: undefined;
163
+ }) | (NavigationButtonOwnProps & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> & {
164
+ href: string;
165
+ });
166
+ declare function NavigationButton(props: NavigationButtonProps): react.JSX.Element;
152
167
 
153
168
  interface ProgressBarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'role'> {
154
169
  /** 0~100. 범위를 벗어난 값은 잘라서 그린다. */
@@ -164,6 +179,38 @@ interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>
164
179
  }
165
180
  declare function Radio({ children, className, disabled, ...props }: RadioProps): react.JSX.Element;
166
181
 
182
+ type SkeletonShape = 'text' | 'block';
183
+ type SkeletonText = 'body1' | 'body2' | 'label';
184
+ type SkeletonWidth = 'full' | 'wide' | 'narrow';
185
+ /**
186
+ * `children`을 받지 않는다. 뼈대 안에 든 것은 읽히지 않는데 DOM에는 남아서, 넣을 수 있게 두면
187
+ * 실제 내용이 숨겨진 채 그려진다.
188
+ */
189
+ interface SkeletonProps extends Omit<HTMLAttributes<HTMLSpanElement>, 'children'> {
190
+ shape?: SkeletonShape;
191
+ /** `shape="text"`에서만 쓴다. */
192
+ text?: SkeletonText;
193
+ /** `shape="text"`에서만 쓴다. */
194
+ width?: SkeletonWidth;
195
+ }
196
+ /**
197
+ * 값이 오기 전 자리를 잡아 두는 뼈대다.
198
+ *
199
+ * **뼈대는 자리를 잡는 것이 목적이다.** 대신할 것과 크기가 갈리면 값이 도착할 때 화면이 튀어서,
200
+ * 깜빡임을 막으려고 쓴 것이 다른 깜빡임을 만든다. 그래서 `text`의 높이는 그 텍스트 스타일의 글자
201
+ * 크기이고, `block`은 크기를 스스로 갖지 않고 놓인 자리를 채운다 — 카드도 썸네일도 크기는 그
202
+ * 자리가 정한다.
203
+ *
204
+ * **폭을 값으로 받지 않는다.** 글자 폭을 흉내 내는 자리라 정확한 값이 있을 수 없고, 자리마다 다른
205
+ * 값이 들어가면 같은 목록의 뼈대가 서로 갈린다. `full`·`wide`·`narrow` 셋으로 닫는다.
206
+ *
207
+ * **여러 줄은 화면이 조립한다.** `lines` 같은 prop을 두지 않는다 — 줄 사이 간격은 그 자리의
208
+ * 레이아웃이고, 컴포넌트가 들면 자리마다 어긋난다.
209
+ *
210
+ * 읽을 내용이 없으므로 스크린리더에서 뺀다. **진행 중이라는 사실은 이것을 놓은 자리가 알린다.**
211
+ */
212
+ declare function Skeleton({ className, shape, text, width, ...props }: SkeletonProps): react.JSX.Element;
213
+
167
214
  type SwitchSize = 'md' | 'sm';
168
215
  interface SwitchProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'type'> {
169
216
  size?: SwitchSize;
@@ -202,6 +249,21 @@ interface TextFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 're
202
249
  }
203
250
  declare function TextField({ className, defaultValue, description, disabled, error, icon, id, label, maxLength, onChange, required, size, value, variant, ...props }: TextFieldProps): react.JSX.Element;
204
251
 
252
+ type ThumbnailSize = 'md' | 'sm';
253
+ /**
254
+ * 상품·항목의 작은 사각 이미지. 원형(아바타)은 다른 것이라 여기에 넣지 않는다.
255
+ *
256
+ * `alt`를 필수로 받는다. 장식이면 빈 문자열을 **명시적으로** 넘긴다 — 빠뜨린 것과 장식인 것이
257
+ * 코드에서 갈려야 한다 (docs/ACCESSIBILITY.md).
258
+ */
259
+ interface ThumbnailProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'alt' | 'height' | 'src' | 'width'> {
260
+ src: string;
261
+ /** 장식이면 `""`를 넘긴다. 생략할 수 없다. */
262
+ alt: string;
263
+ size?: ThumbnailSize;
264
+ }
265
+ declare function Thumbnail({ alt, className, loading, size, src, ...props }: ThumbnailProps): react.JSX.Element;
266
+
205
267
  type ToastVariant = 'primary' | 'danger';
206
268
 
207
269
  type ToasterPlacement = 'bottom-center' | 'bottom-right' | 'top-center' | 'top-right';
@@ -245,4 +307,4 @@ interface TooltipProps {
245
307
  }
246
308
  declare function Tooltip({ children, className, label, placement }: TooltipProps): react.JSX.Element;
247
309
 
248
- export { Alert, type AlertProps, type AlertVariant, Badge, type BadgeProps, type BadgeSize, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipSize, type ChipVariant, DropdownButton, type DropdownButtonAlign, type DropdownButtonItem, type DropdownButtonProps, type DropdownButtonVariant, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, Link, type LinkProps, type LinkSize, type LinkVariant, Modal, ModalActions, type ModalActionsProps, type ModalProps, NavigationButton, type NavigationButtonProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, Switch, type SwitchProps, type SwitchSize, Tab, type TabProps, TextField, type TextFieldProps, type TextFieldSize, type TextFieldVariant, type ToastOptions, type ToastVariant, Toaster, type ToasterPlacement, type ToasterProps, Tooltip, type TooltipPlacement, type TooltipProps, toast };
310
+ export { Alert, type AlertProps, type AlertVariant, Badge, type BadgeProps, type BadgeSize, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Checkbox, type CheckboxProps, Chip, type ChipProps, type ChipSize, type ChipVariant, DropdownButton, type DropdownButtonAlign, type DropdownButtonItem, type DropdownButtonProps, type DropdownButtonVariant, IconButton, type IconButtonProps, type IconButtonSize, type IconButtonVariant, Link, type LinkProps, type LinkSize, type LinkVariant, Modal, ModalActions, type ModalActionsProps, type ModalProps, NavigationButton, type NavigationButtonProps, type NavigationButtonSize, ProgressBar, type ProgressBarProps, Radio, type RadioProps, Skeleton, type SkeletonProps, type SkeletonShape, type SkeletonText, type SkeletonWidth, Switch, type SwitchProps, type SwitchSize, Tab, type TabProps, TextField, type TextFieldProps, type TextFieldSize, type TextFieldVariant, Thumbnail, type ThumbnailProps, type ThumbnailSize, type ToastOptions, type ToastVariant, Toaster, type ToasterPlacement, type ToasterProps, Tooltip, type TooltipPlacement, type TooltipProps, toast };
package/dist/ui.js CHANGED
@@ -13,13 +13,15 @@ import {
13
13
  NavigationButton,
14
14
  ProgressBar,
15
15
  Radio,
16
+ Skeleton,
16
17
  Switch,
17
18
  Tab,
18
19
  TextField,
20
+ Thumbnail,
19
21
  Toaster,
20
22
  Tooltip,
21
23
  toast
22
- } from "./chunk-6JZPK2W5.js";
24
+ } from "./chunk-PWAQFOM3.js";
23
25
  import "./chunk-TWYJ2UTC.js";
24
26
  export {
25
27
  Alert,
@@ -35,9 +37,11 @@ export {
35
37
  NavigationButton,
36
38
  ProgressBar,
37
39
  Radio,
40
+ Skeleton,
38
41
  Switch,
39
42
  Tab,
40
43
  TextField,
44
+ Thumbnail,
41
45
  Toaster,
42
46
  Tooltip,
43
47
  toast
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@highpixel-co/palda-design-system",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Palda product design tokens, icons, React components, and patterns",
5
5
  "license": "MIT",
6
6
  "type": "module",