@hjmds/design-contracts 1.27.2 → 1.28.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/activity-chip.d.ts +1 -1
- package/dist/activity-chip.js +1 -1
- package/dist/activity-chip.js.map +1 -1
- package/dist/auth-screen.d.ts +71 -5
- package/dist/auth-screen.d.ts.map +1 -1
- package/dist/auth-screen.js +60 -2
- package/dist/auth-screen.js.map +1 -1
- package/dist/base-recipes.d.ts +1 -1
- package/dist/base-recipes.js +1 -1
- package/dist/base-recipes.js.map +1 -1
- package/dist/behaviors.d.ts +1 -1
- package/dist/breadcrumb.d.ts +1 -1
- package/dist/breadcrumb.js +1 -1
- package/dist/breadcrumb.js.map +1 -1
- package/dist/calendar.d.ts +1 -1
- package/dist/calendar.js +2 -2
- package/dist/calendar.js.map +1 -1
- package/dist/catalog.d.ts +131 -87
- package/dist/catalog.d.ts.map +1 -1
- package/dist/component-contracts.d.ts +1 -1
- package/dist/component-contracts.js +1 -1
- package/dist/component-contracts.js.map +1 -1
- package/dist/component-recipes.d.ts +85 -57
- package/dist/component-recipes.d.ts.map +1 -1
- package/dist/component-recipes.js +95 -60
- package/dist/component-recipes.js.map +1 -1
- package/dist/conversation-row.d.ts +2 -2
- package/dist/conversation-row.d.ts.map +1 -1
- package/dist/conversation-row.js +6 -4
- package/dist/conversation-row.js.map +1 -1
- package/dist/counter-badge-recipe.d.ts +1 -1
- package/dist/counter-badge-recipe.js +1 -1
- package/dist/counter-badge-recipe.js.map +1 -1
- package/dist/data-table.d.ts +4 -4
- package/dist/data-table.js +4 -4
- package/dist/data-table.js.map +1 -1
- package/dist/date-picker.d.ts +1 -1
- package/dist/design-profile.d.ts.map +1 -1
- package/dist/design-profile.js +19 -16
- package/dist/design-profile.js.map +1 -1
- package/dist/file-picker.d.ts +1 -1
- package/dist/file-picker.js +1 -1
- package/dist/file-picker.js.map +1 -1
- package/dist/foundations.d.ts +18 -14
- package/dist/foundations.d.ts.map +1 -1
- package/dist/foundations.js +18 -13
- package/dist/foundations.js.map +1 -1
- package/dist/heading.d.ts +13 -13
- package/dist/heading.js.map +1 -1
- package/dist/number-field.d.ts +1 -1
- package/dist/otp-field.d.ts +1 -1
- package/dist/password-field.d.ts +1 -1
- package/dist/result.d.ts +1 -1
- package/dist/result.js +2 -2
- package/dist/result.js.map +1 -1
- package/dist/semantic-colors.d.ts +10 -0
- package/dist/semantic-colors.d.ts.map +1 -1
- package/dist/semantic-colors.js +6 -0
- package/dist/semantic-colors.js.map +1 -1
- package/dist/sheet.d.ts +7 -4
- package/dist/sheet.d.ts.map +1 -1
- package/dist/sheet.js +8 -5
- package/dist/sheet.js.map +1 -1
- package/dist/side-panel.d.ts +1 -1
- package/dist/side-panel.js +2 -2
- package/dist/side-panel.js.map +1 -1
- package/dist/steps.d.ts +1 -1
- package/dist/steps.js +1 -1
- package/dist/steps.js.map +1 -1
- package/dist/tag.d.ts +1 -1
- package/dist/tag.js +1 -1
- package/dist/tag.js.map +1 -1
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/timeline.js.map +1 -1
- package/dist/top.d.ts +4 -4
- package/dist/top.d.ts.map +1 -1
- package/dist/top.js +3 -1
- package/dist/top.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/activity-chip.md +5 -1
- package/docs/auth-screen.md +2 -0
- package/docs/design-profile.md +14 -10
- package/docs/generated/component-maturity.md +1 -1
- package/docs/generated/renderer-evidence.json +9 -5
- package/docs/generated/renderer-evidence.md +1 -1
- package/docs/generated/showcase-manifest.json +1 -1
- package/docs/heading.md +14 -9
- package/docs/sheet.md +2 -0
- package/docs/top.md +4 -3
- package/docs/usage/README.md +1 -1
- package/docs/usage/components/auth-screen-layout.md +26 -9
- package/docs/usage/components/bottom-cta.md +6 -2
- package/docs/usage/components/breadcrumb.md +5 -1
- package/docs/usage/components/checkbox-group.md +5 -1
- package/docs/usage/components/collapsible.md +1 -0
- package/docs/usage/components/effect-surface.md +2 -2
- package/docs/usage/components/heading.md +14 -12
- package/docs/usage/components/list-row.md +7 -3
- package/docs/usage/components/list.md +5 -4
- package/docs/usage/components/notification-item.md +5 -1
- package/docs/usage/components/photo-source-sheet.md +1 -1
- package/docs/usage/components/screen-layout.md +7 -3
- package/docs/usage/components/search-screen.md +1 -1
- package/docs/usage/components/section.md +5 -1
- package/docs/usage/components/segmented-control.md +1 -1
- package/docs/usage/components/sheet.md +17 -13
- package/docs/usage/components/skeleton.md +41 -15
- package/docs/usage/components/statistic.md +5 -1
- package/docs/usage/components/switch.md +3 -2
- package/docs/usage/components/tag.md +5 -1
- package/docs/usage/components/text.md +6 -4
- package/docs/usage/components/top.md +1 -1
- package/docs/usage/compositions/adaptive-content.md +5 -1
- package/docs/usage/compositions/compound-controls.md +2 -1
- package/docs/usage/compositions/design-profile-comparison.md +1 -1
- package/docs/usage/compositions/family-drawer.md +5 -3
- package/docs/usage/compositions/input-sheet.md +1 -1
- package/docs/usage/compositions/interaction-flow-apply.md +3 -3
- package/docs/usage/compositions/photo-source.md +3 -3
- package/docs/usage/compositions/selection-motion.md +5 -1
- package/docs/usage/compositions/visual-foundations.md +5 -4
- package/docs/usage/screens/common-login.md +9 -7
- package/docs/usage/screens/landing.md +15 -14
- package/docs/usage/screens/notification-settings.md +4 -2
- package/docs/usage/tokens/typography.md +21 -13
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { collectionItemContract, fieldFrameContract, floatingSurfaceContract, focusIndicatorContract, formSupportContract, } from "./component-contracts.js";
|
|
2
|
-
import { backdrop, breakpoint, control, glyph, layer, largeTextThreshold, layout, fontWeight, motion, motionPreset, opacity, radius, spacing, stroke, } from "./foundations.js";
|
|
2
|
+
import { backdrop, breakpoint, control, glyph, layer, largeTextThreshold, layout, fontWeight, motion, motionPreset, opacity, radius, spacing, stroke, typography, } from "./foundations.js";
|
|
3
3
|
import { semanticColors } from "./semantic-colors.js";
|
|
4
4
|
import { tooltipDescriptorDefaults } from "./tooltip.js";
|
|
5
5
|
import { bottomNavigationRecipeDefaults } from "./bottom-navigation-defaults.js";
|
|
@@ -19,14 +19,18 @@ export const textRecipe = {
|
|
|
19
19
|
danger: semanticColors.content.danger,
|
|
20
20
|
inverse: semanticColors.content.inverse,
|
|
21
21
|
},
|
|
22
|
+
// 2026-10-17 user decisions: the strongest inline emphasis matches the title weight. strong=700 made unread
|
|
23
|
+
// notification titles and labels heavier than every title after titles moved to 600 ("왜 폰트가 진해"), so
|
|
24
|
+
// strong became 600; the second round ("굵기 좀더 줄여") moved titles 600→500 and display headings 700→600,
|
|
25
|
+
// so strong follows the title role (500) and equals `medium`. Semibold 600 is the key-number/selected step.
|
|
22
26
|
emphasis: {
|
|
23
27
|
regular: fontWeight.regular,
|
|
24
|
-
medium: fontWeight.
|
|
25
|
-
strong: fontWeight
|
|
28
|
+
medium: fontWeight.medium,
|
|
29
|
+
strong: typography.title.fontWeight,
|
|
26
30
|
},
|
|
27
31
|
/**
|
|
28
32
|
* Variants whose omitted `emphasis` renders the variant's typography weight even without a design profile.
|
|
29
|
-
* Label's 500
|
|
33
|
+
* Label's 500 equals the `medium` emphasis step, but the shared `regular` default drew form labels at
|
|
30
34
|
* body weight (2026-10-17 user decision: label 500 on Web and Native). Other variants keep `regular`.
|
|
31
35
|
*/
|
|
32
36
|
variantWeight: ["label"],
|
|
@@ -86,7 +90,7 @@ export const linkRecipe = {
|
|
|
86
90
|
variants: {
|
|
87
91
|
inline: {
|
|
88
92
|
textVariant: "body",
|
|
89
|
-
fontWeight: fontWeight.
|
|
93
|
+
fontWeight: fontWeight.medium,
|
|
90
94
|
underline: "always",
|
|
91
95
|
minHeight: null,
|
|
92
96
|
minWidth: null,
|
|
@@ -94,7 +98,7 @@ export const linkRecipe = {
|
|
|
94
98
|
/** 그 자체가 동작이므로 두 축 모두 최소 터치 타깃. 높이만 잡으면 짧은 라벨이 좁아진다. */
|
|
95
99
|
standalone: {
|
|
96
100
|
textVariant: "body",
|
|
97
|
-
fontWeight: fontWeight.
|
|
101
|
+
fontWeight: fontWeight.medium,
|
|
98
102
|
underline: "hover",
|
|
99
103
|
minHeight: control.minTouchTarget,
|
|
100
104
|
minWidth: control.minTouchTarget,
|
|
@@ -218,7 +222,7 @@ export const badgeRecipe = {
|
|
|
218
222
|
},
|
|
219
223
|
radius: "full",
|
|
220
224
|
borderWidth: stroke.default,
|
|
221
|
-
fontWeight: fontWeight.
|
|
225
|
+
fontWeight: fontWeight.medium,
|
|
222
226
|
};
|
|
223
227
|
/** Search is a field specialization with stable affordance and clear targets. */
|
|
224
228
|
export const searchFieldRecipe = {
|
|
@@ -320,7 +324,8 @@ export const chipRecipe = {
|
|
|
320
324
|
},
|
|
321
325
|
radius: "full",
|
|
322
326
|
borderWidth: stroke.default,
|
|
323
|
-
|
|
327
|
+
// Selected keeps one step above idle (500 → 600) so the state still carries a weight cue on the lighter scale.
|
|
328
|
+
label: { fontWeight: fontWeight.medium, selectedFontWeight: fontWeight.semibold },
|
|
324
329
|
selectionIndicator: {
|
|
325
330
|
color: semanticColors.content.brand,
|
|
326
331
|
glyph: "xs",
|
|
@@ -346,15 +351,24 @@ export const dividerRecipe = {
|
|
|
346
351
|
* VirtualList) keep exactly this much inline room so the bleed is never cut.
|
|
347
352
|
*/
|
|
348
353
|
const listRowSurfaceBleed = spacing.xs;
|
|
354
|
+
/** ListRow leading frame and the gap before its text column; the indented separator reuses both. */
|
|
355
|
+
const listRowLeadingSize = 40;
|
|
356
|
+
const listRowGap = spacing.sm;
|
|
349
357
|
export const listRecipe = {
|
|
350
358
|
slots: ["root", "item", "separator"],
|
|
351
359
|
defaults: { separator: "indented" },
|
|
360
|
+
/**
|
|
361
|
+
* Separators are measured from the list's content edge, where the row text sits, and each one belongs to the row
|
|
362
|
+
* above it (iOS cell separator). "full" spans the row surface (content edge ± bleed). "indented" follows that row's
|
|
363
|
+
* text column: it starts at the text — `leadingInsetStart` (leading 40 + gap 12) when the row has a leading
|
|
364
|
+
* element, `insetStart` 0 when it has none — and ends on the row's trailing content edge (0).
|
|
365
|
+
* 2026-10-17 user report: a fixed 52 start cut the line off midway under rows without leading (text at 16, line
|
|
366
|
+
* from 68), and the −8 end ran past the trailing content.
|
|
367
|
+
*/
|
|
352
368
|
separators: {
|
|
353
369
|
none: null,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
full: { insetStart: -listRowSurfaceBleed, insetEnd: -listRowSurfaceBleed },
|
|
357
|
-
indented: { insetStart: 40 + spacing.sm, insetEnd: -listRowSurfaceBleed },
|
|
370
|
+
full: { insetStart: -listRowSurfaceBleed, leadingInsetStart: -listRowSurfaceBleed, insetEnd: -listRowSurfaceBleed },
|
|
371
|
+
indented: { insetStart: 0, leadingInsetStart: listRowLeadingSize + listRowGap, insetEnd: 0 },
|
|
358
372
|
},
|
|
359
373
|
// A grouped list paints its own rounded surface and clips to it, so it leaves the row bleed as inline padding:
|
|
360
374
|
// rows keep their full surface inside the radius and the text stays 8 inside the group edge as before.
|
|
@@ -406,15 +420,15 @@ export const listRowRecipe = {
|
|
|
406
420
|
* the same negative inline margin, so pressed/selected fills keep 8 of room beyond the text.
|
|
407
421
|
*/
|
|
408
422
|
surfaceBleed: listRowSurfaceBleed,
|
|
409
|
-
gap:
|
|
410
|
-
leadingSize:
|
|
423
|
+
gap: listRowGap,
|
|
424
|
+
leadingSize: listRowLeadingSize,
|
|
411
425
|
/**
|
|
412
426
|
* Frame geometry for the leading slot. The size was already declared here but
|
|
413
427
|
* no renderer bound it, so every consumer re-derived the avatar box (radius,
|
|
414
428
|
* clipping, centering) in product styles.
|
|
415
429
|
*/
|
|
416
430
|
leadingShapes: { square: null, circle: "full" },
|
|
417
|
-
title: { color: semanticColors.content.body, textVariant: "bodyLarge", fontWeight: fontWeight
|
|
431
|
+
title: { color: semanticColors.content.body, textVariant: "bodyLarge", fontWeight: typography.title.fontWeight },
|
|
418
432
|
description: { color: semanticColors.content.secondary, textVariant: "body" },
|
|
419
433
|
trailing: {
|
|
420
434
|
textColor: semanticColors.content.secondary,
|
|
@@ -437,7 +451,7 @@ export const accordionRecipe = {
|
|
|
437
451
|
},
|
|
438
452
|
paddingHorizontal: spacing.xs,
|
|
439
453
|
gap: spacing.sm,
|
|
440
|
-
title: { color: semanticColors.content.body, textVariant: "bodyLarge", fontWeight: fontWeight
|
|
454
|
+
title: { color: semanticColors.content.body, textVariant: "bodyLarge", fontWeight: typography.title.fontWeight },
|
|
441
455
|
indicator: { color: semanticColors.content.secondary, glyph: "sm" },
|
|
442
456
|
panel: {
|
|
443
457
|
color: semanticColors.content.body,
|
|
@@ -577,7 +591,7 @@ export const selectRecipe = {
|
|
|
577
591
|
paddingVertical: spacing.xs,
|
|
578
592
|
},
|
|
579
593
|
optionLeading: { color: semanticColors.content.secondary, glyph: "sm" },
|
|
580
|
-
optionLabel: { fontWeight: fontWeight.
|
|
594
|
+
optionLabel: { fontWeight: fontWeight.medium, selectedFontWeight: fontWeight.semibold },
|
|
581
595
|
selectionIndicator: { color: semanticColors.border.focus, glyph: "sm" },
|
|
582
596
|
stateMessage: {
|
|
583
597
|
color: semanticColors.content.secondary,
|
|
@@ -648,6 +662,8 @@ export const comboboxRecipe = {
|
|
|
648
662
|
states: selectRecipe.states,
|
|
649
663
|
transition: selectRecipe.transition,
|
|
650
664
|
};
|
|
665
|
+
/** Block-side inset of the connected track: `container.padding` + `container.borderWidth`. */
|
|
666
|
+
const segmentedTrackInset = spacing.xxs + stroke.subtle;
|
|
651
667
|
export const segmentedControlRecipe = {
|
|
652
668
|
// Text navigation reuses radio selection, without cloning a product-only tab engine.
|
|
653
669
|
text: { gap: spacing.md, indicatorWidth: 16, indicatorHeight: 2, indicatorRadius: radius.full,
|
|
@@ -684,16 +700,25 @@ export const segmentedControlRecipe = {
|
|
|
684
700
|
padding: spacing.xxs,
|
|
685
701
|
gap: spacing.xxs,
|
|
686
702
|
},
|
|
703
|
+
/**
|
|
704
|
+
* `height` is the connected control's outer height (track border + padding included) and matches the Button /
|
|
705
|
+
* IconButton / Chip height of the same size step, so a segmented control and a chip in one row line up.
|
|
706
|
+
* `minHeight` is the option inside the track (height − 2 × (`container.padding` + `container.borderWidth`)) and `hitSlop` extends each
|
|
707
|
+
* option vertically to the 44 touch target. Before 2026-10-17 `minHeight` was the option itself, so the track
|
|
708
|
+
* drew 46/54 next to 36/44 chips and buttons (DiscoveryGallery sort row, user request "높이 맞춰").
|
|
709
|
+
*/
|
|
687
710
|
sizes: {
|
|
688
711
|
small: {
|
|
689
|
-
|
|
690
|
-
|
|
712
|
+
height: control.buttonHeight.small,
|
|
713
|
+
minHeight: control.buttonHeight.small - 2 * segmentedTrackInset,
|
|
714
|
+
hitSlop: (control.minTouchTarget - (control.buttonHeight.small - 2 * segmentedTrackInset)) / 2,
|
|
691
715
|
paddingHorizontal: spacing.sm,
|
|
692
716
|
textVariant: "label",
|
|
693
717
|
},
|
|
694
718
|
medium: {
|
|
695
|
-
|
|
696
|
-
|
|
719
|
+
height: control.buttonHeight.medium,
|
|
720
|
+
minHeight: control.buttonHeight.medium - 2 * segmentedTrackInset,
|
|
721
|
+
hitSlop: (control.minTouchTarget - (control.buttonHeight.medium - 2 * segmentedTrackInset)) / 2,
|
|
697
722
|
paddingHorizontal: spacing.md,
|
|
698
723
|
textVariant: "body",
|
|
699
724
|
},
|
|
@@ -702,7 +727,7 @@ export const segmentedControlRecipe = {
|
|
|
702
727
|
radius: "md",
|
|
703
728
|
gap: spacing.xxs,
|
|
704
729
|
idleContent: semanticColors.content.secondary,
|
|
705
|
-
fontWeight: fontWeight.
|
|
730
|
+
fontWeight: fontWeight.medium,
|
|
706
731
|
selectedBackground: semanticColors.canvas,
|
|
707
732
|
selectedContent: semanticColors.content.brand,
|
|
708
733
|
/**
|
|
@@ -712,7 +737,7 @@ export const segmentedControlRecipe = {
|
|
|
712
737
|
*/
|
|
713
738
|
selectedBorder: semanticColors.border.focus,
|
|
714
739
|
selectedBorderWidth: stroke.strong,
|
|
715
|
-
selectedFontWeight: fontWeight.
|
|
740
|
+
selectedFontWeight: fontWeight.semibold,
|
|
716
741
|
focusRing: semanticColors.border.focus,
|
|
717
742
|
pressedOpacity: opacity.pressed,
|
|
718
743
|
disabledOpacity: opacity.disabled,
|
|
@@ -773,11 +798,16 @@ export const switchRecipe = {
|
|
|
773
798
|
pressedOpacity: opacity.pressed,
|
|
774
799
|
},
|
|
775
800
|
rowMinHeight: control.minTouchTarget,
|
|
776
|
-
// A switch
|
|
777
|
-
//
|
|
778
|
-
//
|
|
779
|
-
//
|
|
780
|
-
|
|
801
|
+
// A described switch is a two-line row: the copy (body 20 + gap 4 + caption 16 = 40) with the
|
|
802
|
+
// comfortable list-row vertical padding (8) on both sides. The padding is drawn by the row itself
|
|
803
|
+
// so it survives larger text, and the minimum keeps neighbouring rows equal (a product author found
|
|
804
|
+
// content-only height gave them different heights). It used to borrow ListRow's 68, which is sized
|
|
805
|
+
// for a bodyLarge title + body description; on the smaller switch copy that left 14 above and below,
|
|
806
|
+
// and stacked rows read as widely spaced (2026-10-17 user report, notification settings: 84 pitch
|
|
807
|
+
// for 40 of copy, together with a Stack gap the rows must not have).
|
|
808
|
+
rowPaddingVertical: listRowRecipe.density.comfortable.paddingVertical,
|
|
809
|
+
rowTwoLineMinHeight: typography.body.lineHeight + spacing.xxs + typography.caption.lineHeight
|
|
810
|
+
+ 2 * listRowRecipe.density.comfortable.paddingVertical,
|
|
781
811
|
};
|
|
782
812
|
export const selectionControlRecipe = {
|
|
783
813
|
slots: [
|
|
@@ -853,8 +883,8 @@ export const selectionControlRecipe = {
|
|
|
853
883
|
},
|
|
854
884
|
label: {
|
|
855
885
|
color: semanticColors.content.body,
|
|
856
|
-
fontWeight: fontWeight.
|
|
857
|
-
checkedFontWeight: fontWeight.
|
|
886
|
+
fontWeight: fontWeight.medium,
|
|
887
|
+
checkedFontWeight: fontWeight.semibold,
|
|
858
888
|
},
|
|
859
889
|
leading: { size: "md", color: semanticColors.content.secondary },
|
|
860
890
|
description: { color: semanticColors.content.secondary },
|
|
@@ -1018,8 +1048,8 @@ export const bottomNavigationRecipe = {
|
|
|
1018
1048
|
},
|
|
1019
1049
|
},
|
|
1020
1050
|
label: {
|
|
1021
|
-
fontWeight: fontWeight.
|
|
1022
|
-
selectedFontWeight: fontWeight.
|
|
1051
|
+
fontWeight: fontWeight.medium,
|
|
1052
|
+
selectedFontWeight: fontWeight.semibold,
|
|
1023
1053
|
textAlign: "center",
|
|
1024
1054
|
wrap: true,
|
|
1025
1055
|
fixedLines: null,
|
|
@@ -1090,7 +1120,7 @@ export const tabsRecipe = {
|
|
|
1090
1120
|
},
|
|
1091
1121
|
gap: spacing.xs,
|
|
1092
1122
|
icon: { glyph: "xs" },
|
|
1093
|
-
label: { fontWeight: fontWeight.
|
|
1123
|
+
label: { fontWeight: fontWeight.medium, selectedFontWeight: fontWeight.semibold },
|
|
1094
1124
|
layouts: {
|
|
1095
1125
|
content: { fitted: false },
|
|
1096
1126
|
fitted: { fitted: true },
|
|
@@ -1129,21 +1159,28 @@ export const noticeRecipe = {
|
|
|
1129
1159
|
contentGap: spacing.xxs,
|
|
1130
1160
|
iconSize: "sm",
|
|
1131
1161
|
borderWidth: stroke.default,
|
|
1132
|
-
title: { textVariant: "body", fontWeight: fontWeight
|
|
1162
|
+
title: { textVariant: "body", fontWeight: typography.title.fontWeight },
|
|
1133
1163
|
description: { color: semanticColors.content.body, textVariant: "body" },
|
|
1134
1164
|
};
|
|
1135
1165
|
export const skeletonRecipe = {
|
|
1136
|
-
slots: ["root"],
|
|
1166
|
+
slots: ["root", "line"],
|
|
1137
1167
|
// animated는 0.9.12까지 false였다. 정지한 블록은 로딩이 아니라 깨진 화면으로
|
|
1138
1168
|
// 읽힌다. 전환 근거와 소비 측 migration은
|
|
1139
1169
|
// .changeset/skeleton-pulse-by-default.md에 있다.
|
|
1140
|
-
defaults: { shape: "block", animated: true },
|
|
1141
|
-
|
|
1170
|
+
defaults: { shape: "block", animated: true, lines: 1 },
|
|
1171
|
+
// 2026-10-17 사용자 요청: canvas 채움 + 1px 테두리는 흰 배경에서 거의 보이지 않아 로딩 모양을 알 수 없었다.
|
|
1172
|
+
// 2026-09-29 "넓은 회색 면은 canvas" 방향의 예외로, 자리표시는 채운 면이어야 모양이 읽힌다(skeleton.md 근거).
|
|
1173
|
+
background: semanticColors.surface.placeholder,
|
|
1174
|
+
// `aspectRatio`가 있으면 높이 대신 폭에 비례한다(media). `button`은 medium 버튼 높이·모서리와 같다.
|
|
1142
1175
|
shapes: {
|
|
1143
|
-
block: { radius: "md", defaultHeight: spacing.xxl },
|
|
1144
|
-
text: { radius: "sm", defaultHeight: spacing.md },
|
|
1145
|
-
circle: { radius: "full", defaultHeight: glyph.xxl },
|
|
1146
|
-
|
|
1176
|
+
block: { radius: "md", defaultHeight: spacing.xxl, aspectRatio: null },
|
|
1177
|
+
text: { radius: "sm", defaultHeight: spacing.md, aspectRatio: null },
|
|
1178
|
+
circle: { radius: "full", defaultHeight: glyph.xxl, aspectRatio: null },
|
|
1179
|
+
media: { radius: "md", defaultHeight: null, aspectRatio: 16 / 9 },
|
|
1180
|
+
button: { radius: "md", defaultHeight: control.buttonHeight.medium, aspectRatio: null },
|
|
1181
|
+
},
|
|
1182
|
+
// `lines` > 1 (text 전용): 줄 사이 간격과 짧게 끝나는 마지막 줄. 16 막대 + 8 간격 = 본문 큰 글자 줄 높이 24.
|
|
1183
|
+
lines: { gap: spacing.xs, lastLineWidthPercent: 60 },
|
|
1147
1184
|
animation: {
|
|
1148
1185
|
duration: motion.slow * 4,
|
|
1149
1186
|
easing: "standard",
|
|
@@ -1162,7 +1199,7 @@ export const emptyStateRecipe = {
|
|
|
1162
1199
|
paddingHorizontal: spacing.xl,
|
|
1163
1200
|
gap: spacing.xs,
|
|
1164
1201
|
icon: { size: "lg", color: semanticColors.content.decorative },
|
|
1165
|
-
title: { textVariant: "body", color: semanticColors.content.primary, fontWeight: fontWeight
|
|
1202
|
+
title: { textVariant: "body", color: semanticColors.content.primary, fontWeight: typography.title.fontWeight },
|
|
1166
1203
|
description: { textVariant: "label", color: semanticColors.content.secondary },
|
|
1167
1204
|
};
|
|
1168
1205
|
export const spinnerRecipe = {
|
|
@@ -1214,7 +1251,7 @@ export const loadMoreRecipe = {
|
|
|
1214
1251
|
radius: "md",
|
|
1215
1252
|
color: semanticColors.content.brand,
|
|
1216
1253
|
textVariant: "label",
|
|
1217
|
-
fontWeight: fontWeight.
|
|
1254
|
+
fontWeight: fontWeight.medium,
|
|
1218
1255
|
},
|
|
1219
1256
|
spinner: { size: "small", tone: "brand" },
|
|
1220
1257
|
states: {
|
|
@@ -1236,7 +1273,7 @@ export const avatarRecipe = {
|
|
|
1236
1273
|
background: semanticColors.canvas,
|
|
1237
1274
|
content: semanticColors.content.secondary,
|
|
1238
1275
|
border: semanticColors.border.default,
|
|
1239
|
-
/** Initials
|
|
1276
|
+
/** Initials use the strong emphasis step; their size follows the avatar (Web `.hjm-avatar[data-size]` steps). */
|
|
1240
1277
|
initialsWeight: "strong",
|
|
1241
1278
|
};
|
|
1242
1279
|
/**
|
|
@@ -1294,18 +1331,20 @@ export const statisticRecipe = {
|
|
|
1294
1331
|
},
|
|
1295
1332
|
label: {
|
|
1296
1333
|
color: semanticColors.content.secondary,
|
|
1297
|
-
fontWeight: fontWeight.
|
|
1334
|
+
fontWeight: fontWeight.medium,
|
|
1298
1335
|
},
|
|
1299
1336
|
value: {
|
|
1300
1337
|
color: semanticColors.content.primary,
|
|
1301
|
-
|
|
1338
|
+
// The key number keeps the semibold emphasis step (600, 2026-10-17 lighter scale) at the `heading` size.
|
|
1339
|
+
// It used to borrow the display heading weight, which was removed with the display tier the same day.
|
|
1340
|
+
fontWeight: fontWeight.semibold,
|
|
1302
1341
|
numericVariant: "tabular",
|
|
1303
1342
|
maxLines: null,
|
|
1304
1343
|
},
|
|
1305
1344
|
affix: {
|
|
1306
1345
|
color: semanticColors.content.body,
|
|
1307
1346
|
textVariant: "body",
|
|
1308
|
-
fontWeight: fontWeight.
|
|
1347
|
+
fontWeight: fontWeight.medium,
|
|
1309
1348
|
},
|
|
1310
1349
|
hint: {
|
|
1311
1350
|
color: semanticColors.content.secondary,
|
|
@@ -1313,7 +1352,7 @@ export const statisticRecipe = {
|
|
|
1313
1352
|
},
|
|
1314
1353
|
trend: {
|
|
1315
1354
|
textVariant: "caption",
|
|
1316
|
-
fontWeight: fontWeight.
|
|
1355
|
+
fontWeight: fontWeight.medium,
|
|
1317
1356
|
gap: spacing.xxs,
|
|
1318
1357
|
marks: {
|
|
1319
1358
|
up: "trendUp",
|
|
@@ -1378,12 +1417,8 @@ export const sheetRecipe = {
|
|
|
1378
1417
|
showWhen: "swipe-dismiss-enabled",
|
|
1379
1418
|
},
|
|
1380
1419
|
header: { minHeight: control.minTouchTarget, gap: spacing.sm },
|
|
1381
|
-
title:
|
|
1382
|
-
|
|
1383
|
-
textVariant: "title",
|
|
1384
|
-
fontWeight: fontWeight.bold,
|
|
1385
|
-
gap: spacing.xxs,
|
|
1386
|
-
},
|
|
1420
|
+
// No visual `title` region: sheets render the title only as the accessible name (2026-10-17 user decision).
|
|
1421
|
+
// The "title" slot stays because the title is still the dialog's name.
|
|
1387
1422
|
body: {
|
|
1388
1423
|
color: semanticColors.content.body,
|
|
1389
1424
|
textVariant: "body",
|
|
@@ -1467,7 +1502,7 @@ export const alertDialogRecipe = {
|
|
|
1467
1502
|
title: {
|
|
1468
1503
|
color: semanticColors.content.primary,
|
|
1469
1504
|
textVariant: "title",
|
|
1470
|
-
fontWeight: fontWeight
|
|
1505
|
+
fontWeight: typography.title.fontWeight,
|
|
1471
1506
|
},
|
|
1472
1507
|
description: {
|
|
1473
1508
|
color: semanticColors.content.secondary,
|
|
@@ -1586,7 +1621,7 @@ export const toastRecipe = {
|
|
|
1586
1621
|
title: {
|
|
1587
1622
|
color: semanticColors.content.primary,
|
|
1588
1623
|
textVariant: "body",
|
|
1589
|
-
fontWeight: fontWeight
|
|
1624
|
+
fontWeight: typography.title.fontWeight,
|
|
1590
1625
|
},
|
|
1591
1626
|
// Secondary copy so the title leads; body-on-body read as one grey block.
|
|
1592
1627
|
description: {
|
|
@@ -1594,7 +1629,7 @@ export const toastRecipe = {
|
|
|
1594
1629
|
textVariant: "body",
|
|
1595
1630
|
},
|
|
1596
1631
|
// Step dots of a running task: done and current are brand, upcoming is the divider colour; the current
|
|
1597
|
-
// label is
|
|
1632
|
+
// label is emphasized. Labels sit beside each dot so the row reads without colour alone (WCAG 1.4.1).
|
|
1598
1633
|
progress: {
|
|
1599
1634
|
gap: spacing.sm,
|
|
1600
1635
|
dotSize: 6,
|
|
@@ -1614,7 +1649,7 @@ export const toastRecipe = {
|
|
|
1614
1649
|
radius: "full",
|
|
1615
1650
|
align: "start",
|
|
1616
1651
|
textVariant: "body",
|
|
1617
|
-
fontWeight: fontWeight.
|
|
1652
|
+
fontWeight: fontWeight.medium,
|
|
1618
1653
|
minHeight: control.minTouchTarget,
|
|
1619
1654
|
paddingHorizontal: spacing.md,
|
|
1620
1655
|
},
|
|
@@ -1683,7 +1718,7 @@ export const topBarRecipe = {
|
|
|
1683
1718
|
paddingHorizontal: spacing.md,
|
|
1684
1719
|
gap: spacing.xs,
|
|
1685
1720
|
largeTextThreshold,
|
|
1686
|
-
title: { textVariant: "bodyLarge", color: semanticColors.content.primary, fontWeight: fontWeight
|
|
1721
|
+
title: { textVariant: "bodyLarge", color: semanticColors.content.primary, fontWeight: typography.title.fontWeight },
|
|
1687
1722
|
titleAction: {
|
|
1688
1723
|
minHeight: control.minTouchTarget,
|
|
1689
1724
|
minWidth: control.minTouchTarget,
|
|
@@ -1744,7 +1779,7 @@ export const sectionRecipe = {
|
|
|
1744
1779
|
gap: spacing.xs,
|
|
1745
1780
|
headerGap: spacing.sm,
|
|
1746
1781
|
copyGap: spacing.xxs,
|
|
1747
|
-
title: { textVariant: "title", color: semanticColors.content.body, fontWeight: fontWeight
|
|
1782
|
+
title: { textVariant: "title", color: semanticColors.content.body, fontWeight: typography.title.fontWeight },
|
|
1748
1783
|
description: { textVariant: "caption", color: semanticColors.content.secondary },
|
|
1749
1784
|
};
|
|
1750
1785
|
//# sourceMappingURL=component-recipes.js.map
|