@hjmds/design-contracts 1.46.1 → 1.47.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.
Files changed (89) hide show
  1. package/dist/behaviors.d.ts +2 -1
  2. package/dist/behaviors.d.ts.map +1 -1
  3. package/dist/bottom-navigation.d.ts +4 -0
  4. package/dist/bottom-navigation.d.ts.map +1 -1
  5. package/dist/bottom-navigation.js +12 -0
  6. package/dist/bottom-navigation.js.map +1 -1
  7. package/dist/card.d.ts +2 -2
  8. package/dist/card.d.ts.map +1 -1
  9. package/dist/card.js +3 -2
  10. package/dist/card.js.map +1 -1
  11. package/dist/carousel.d.ts +1 -0
  12. package/dist/carousel.d.ts.map +1 -1
  13. package/dist/carousel.js +1 -0
  14. package/dist/carousel.js.map +1 -1
  15. package/dist/catalog.d.ts +130 -14
  16. package/dist/catalog.d.ts.map +1 -1
  17. package/dist/catalog.js +4 -3
  18. package/dist/catalog.js.map +1 -1
  19. package/dist/color-picker.d.ts +51 -1
  20. package/dist/color-picker.d.ts.map +1 -1
  21. package/dist/color-picker.js +56 -2
  22. package/dist/color-picker.js.map +1 -1
  23. package/dist/component-recipes.d.ts +23 -9
  24. package/dist/component-recipes.d.ts.map +1 -1
  25. package/dist/component-recipes.js +24 -18
  26. package/dist/component-recipes.js.map +1 -1
  27. package/dist/conversation-row.d.ts +1 -1
  28. package/dist/conversation-row.d.ts.map +1 -1
  29. package/dist/conversation-row.js +2 -1
  30. package/dist/conversation-row.js.map +1 -1
  31. package/dist/date-range.d.ts +122 -3
  32. package/dist/date-range.d.ts.map +1 -1
  33. package/dist/date-range.js +139 -5
  34. package/dist/date-range.js.map +1 -1
  35. package/dist/icon.d.ts +2 -1
  36. package/dist/icon.d.ts.map +1 -1
  37. package/dist/icon.js +2 -0
  38. package/dist/icon.js.map +1 -1
  39. package/dist/recipes.d.ts +1 -0
  40. package/dist/recipes.d.ts.map +1 -1
  41. package/dist/recipes.js +1 -0
  42. package/dist/recipes.js.map +1 -1
  43. package/dist/screen-patterns.d.ts +33 -2
  44. package/dist/screen-patterns.d.ts.map +1 -1
  45. package/dist/screen-patterns.js +27 -2
  46. package/dist/screen-patterns.js.map +1 -1
  47. package/dist/version.d.ts +1 -1
  48. package/dist/version.js +1 -1
  49. package/dist/version.js.map +1 -1
  50. package/docs/bottom-navigation.md +16 -0
  51. package/docs/color-picker.md +24 -19
  52. package/docs/generated/component-maturity.md +3 -3
  53. package/docs/generated/renderer-evidence.json +59 -7
  54. package/docs/generated/renderer-evidence.md +3 -2
  55. package/docs/generated/showcase-manifest.json +18 -4
  56. package/docs/usage/README.md +5 -2
  57. package/docs/usage/SELECTION.md +109 -0
  58. package/docs/usage/components/avatar.md +31 -6
  59. package/docs/usage/components/bottom-navigation.md +16 -0
  60. package/docs/usage/components/button.md +11 -0
  61. package/docs/usage/components/card.md +6 -0
  62. package/docs/usage/components/chat-message.md +9 -1
  63. package/docs/usage/components/chat-room-members.md +4 -0
  64. package/docs/usage/components/chat-screen.md +10 -1
  65. package/docs/usage/components/color-picker.md +65 -28
  66. package/docs/usage/components/comment-thread-screen.md +16 -1
  67. package/docs/usage/components/conversation-list-screen.md +81 -0
  68. package/docs/usage/components/conversation-row.md +5 -1
  69. package/docs/usage/components/date-range-picker.md +15 -5
  70. package/docs/usage/components/event-attendance-card.md +4 -0
  71. package/docs/usage/components/follow-list-screen.md +109 -0
  72. package/docs/usage/components/follow-profile-card.md +4 -0
  73. package/docs/usage/components/list-row.md +6 -0
  74. package/docs/usage/components/menu.md +12 -0
  75. package/docs/usage/components/notice.md +8 -3
  76. package/docs/usage/components/notification-inbox-screen.md +10 -0
  77. package/docs/usage/components/notification-row.md +4 -0
  78. package/docs/usage/components/page-indicator.md +1 -0
  79. package/docs/usage/components/profile-summary.md +32 -3
  80. package/docs/usage/components/section.md +2 -2
  81. package/docs/usage/components/settings-screen.md +1 -1
  82. package/docs/usage/components/sheet.md +1 -0
  83. package/docs/usage/components/statistic.md +1 -1
  84. package/docs/usage/compositions/web-additions.md +5 -5
  85. package/docs/usage/screens/common-comments.md +1 -0
  86. package/docs/usage/screens/common-conversation-list.md +22 -1
  87. package/docs/usage/screens/common-follow-list.md +87 -0
  88. package/docs/usage/screens/common-settings.md +23 -0
  89. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  /** Conversation previews reserve metadata and unread status while truncating the message. */
2
2
  export declare const conversationRowRecipe: {
3
- readonly avatarSize: 56;
3
+ readonly avatarSize: 48;
4
4
  readonly unreadSize: 10;
5
5
  readonly gap: 12;
6
6
  readonly paddingInline: 16;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-row.d.ts","sourceRoot":"","sources":["../src/conversation-row.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB;;;;;;;;;;CAYxB,CAAC"}
1
+ {"version":3,"file":"conversation-row.d.ts","sourceRoot":"","sources":["../src/conversation-row.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB;;;;;;;;;;CAaxB,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { fontWeight, spacing, typography } from "./foundations.js";
2
2
  /** Conversation previews reserve metadata and unread status while truncating the message. */
3
3
  export const conversationRowRecipe = {
4
- avatarSize: 56,
4
+ // Standard member portrait (2026-10-25); message bubbles retain their compact avatar recipe.
5
+ avatarSize: 48,
5
6
  unreadSize: 10,
6
7
  gap: spacing.sm,
7
8
  paddingInline: spacing.md,
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-row.js","sourceRoot":"","sources":["../src/conversation-row.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnE,6FAA6F;AAC7F,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,GAAG,EAAE,OAAO,CAAC,EAAE;IACf,aAAa,EAAE,OAAO,CAAC,EAAE;IACzB,YAAY,EAAE,EAAE;IAChB,UAAU,EAAE,CAAC;IACb,mGAAmG;IACnG,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC,UAAU;IACxC,iBAAiB,EAAE,UAAU,CAAC,QAAQ;IACtC,mBAAmB,EAAE,UAAU,CAAC,QAAQ;CAChC,CAAC","sourcesContent":["import { fontWeight, spacing, typography } from \"./foundations.js\";\n\n/** Conversation previews reserve metadata and unread status while truncating the message. */\nexport const conversationRowRecipe = {\n avatarSize: 56,\n unreadSize: 10,\n gap: spacing.sm,\n paddingInline: spacing.md,\n paddingBlock: 10,\n contentGap: 2,\n // Read rows use the title weight; unread rows step up to semibold, the heaviest non-display weight\n // (800/700 before the 2026-10-17 lighter scale, \"굵기 좀더 줄여\").\n titleWeight: typography.title.fontWeight,\n unreadTitleWeight: fontWeight.semibold,\n unreadPreviewWeight: fontWeight.semibold,\n} as const;\n"]}
1
+ {"version":3,"file":"conversation-row.js","sourceRoot":"","sources":["../src/conversation-row.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnE,6FAA6F;AAC7F,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,6FAA6F;IAC7F,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,GAAG,EAAE,OAAO,CAAC,EAAE;IACf,aAAa,EAAE,OAAO,CAAC,EAAE;IACzB,YAAY,EAAE,EAAE;IAChB,UAAU,EAAE,CAAC;IACb,mGAAmG;IACnG,6DAA6D;IAC7D,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC,UAAU;IACxC,iBAAiB,EAAE,UAAU,CAAC,QAAQ;IACtC,mBAAmB,EAAE,UAAU,CAAC,QAAQ;CAChC,CAAC","sourcesContent":["import { fontWeight, spacing, typography } from \"./foundations.js\";\n\n/** Conversation previews reserve metadata and unread status while truncating the message. */\nexport const conversationRowRecipe = {\n // Standard member portrait (2026-10-25); message bubbles retain their compact avatar recipe.\n avatarSize: 48,\n unreadSize: 10,\n gap: spacing.sm,\n paddingInline: spacing.md,\n paddingBlock: 10,\n contentGap: 2,\n // Read rows use the title weight; unread rows step up to semibold, the heaviest non-display weight\n // (800/700 before the 2026-10-17 lighter scale, \"굵기 좀더 줄여\").\n titleWeight: typography.title.fontWeight,\n unreadTitleWeight: fontWeight.semibold,\n unreadPreviewWeight: fontWeight.semibold,\n} as const;\n"]}
@@ -15,7 +15,28 @@ export type DateRangeValue = Readonly<{
15
15
  end: string | null;
16
16
  }>;
17
17
  export declare const emptyDateRange: DateRangeValue;
18
- export declare function validateDateRange(value: DateRangeValue): void;
18
+ /**
19
+ * 구간이 덮을 수 있는 최대 길이. 일수가 아니라 달력 단위로 센다 — "1년"을 365일로 두면 윤년을 낀
20
+ * 1월 1일~12월 31일이 막힌다. 끝은 포함이라 `{ years: 1 }`은 2026-01-01부터 2026-12-31까지다.
21
+ * 2026-10-25 사용자 요청으로 DateRangePicker 기본값은 1년이고, `null`이면 제한하지 않는다.
22
+ */
23
+ export type DateRangeLimit = Readonly<{
24
+ years?: number;
25
+ months?: number;
26
+ days?: number;
27
+ }>;
28
+ export declare const defaultDateRangeLimit: DateRangeLimit;
29
+ /** `start`를 한쪽 끝으로 둘 때 다른 끝이 올 수 있는 가장 이른·늦은 날(둘 다 포함). */
30
+ export declare function resolveDateRangeLimitBounds(start: string, limit: DateRangeLimit): Readonly<{
31
+ earliest: string;
32
+ latest: string;
33
+ }>;
34
+ export declare function validateDateRange(value: DateRangeValue, limit?: DateRangeLimit | null): void;
35
+ /**
36
+ * 고르는 중에 이 날짜를 끝으로 고를 수 있는지. 비었거나 완성된 구간에서는 누르면 새로 시작하므로
37
+ * 언제나 고를 수 있다. 막힌 날은 renderer가 비활성으로 그린다 — 눌렀다가 거절하면 이유를 알 수 없다.
38
+ */
39
+ export declare function isDateWithinRangeLimit(value: DateRangeValue, date: string, limit: DateRangeLimit | null): boolean;
19
40
  /**
20
41
  * 날짜 하나를 눌렀을 때의 다음 값.
21
42
  *
@@ -25,13 +46,110 @@ export declare function validateDateRange(value: DateRangeValue): void;
25
46
  * - 고르는 중이면 **끝**을 정한다. 시작보다 앞선 날짜를 누르면 두 값을 바꿔 담는다 —
26
47
  * 거절하면 사용자가 왜 안 되는지 알 수 없다.
27
48
  */
28
- export declare function resolveDateRangeSelection(current: DateRangeValue, date: string): DateRangeValue;
49
+ export declare function resolveDateRangeSelection(current: DateRangeValue, date: string, limit?: DateRangeLimit | null): DateRangeValue;
29
50
  export type DateRangeCellState = "start" | "end" | "between" | "none";
30
51
  /**
31
52
  * 한 칸이 구간 안에서 어떤 자리인지. 미리보기(`hoveredDate`)는 아직 확정되지 않은 끝을
32
53
  * 가리키므로 같은 함수가 처리한다 — renderer가 두 벌의 칠하기 규칙을 만들지 않게 한다.
33
54
  */
34
55
  export declare function resolveDateRangeCellState(value: DateRangeValue, date: string, hoveredDate?: string | null): DateRangeCellState;
56
+ /**
57
+ * 칸 하나를 어떻게 칠하는지. `edge`는 채운 원(시작·끝), `band`는 시작과 끝을 잇는 띠의 모양이다.
58
+ * 띠는 시작 칸에서 끝 쪽 절반(`toEnd`), 끝 칸에서 시작 쪽 절반(`toStart`), 사이 칸 전체(`full`)를 덮는다.
59
+ * 시작과 끝이 같은 날(하루 구간)이거나 끝이 아직 없으면 띠가 없다.
60
+ *
61
+ * 2026-10-25 개편(Spint 기간 시트 사용자 지적): 점 표시는 구간이 이어져 보이지 않았고, 점 줄 때문에 행이
62
+ * 라벨 한 줄만큼 높아졌다. Material 3·Airbnb처럼 띠로 잇고 두 끝을 같은 채운 원으로 그린다.
63
+ */
64
+ export type DateRangeCellPaint = Readonly<{
65
+ edge: boolean;
66
+ band: "none" | "full" | "toEnd" | "toStart";
67
+ }>;
68
+ export declare function resolveDateRangeCellPaint(value: DateRangeValue, date: string, hoveredDate?: string | null): DateRangeCellPaint;
69
+ /**
70
+ * 요약 칸에서 강조할 끝. 비었으면 시작, 고르는 중이면 끝을 강조한다. 완성된 구간은 아무것도 강조하지 않는다 —
71
+ * 다음 탭이 새 시작이 되긴 하지만, 완성 직후 시작 칸이 강조되면 시작일을 고치는 중으로 읽혔다(2026-10-25 실화면).
72
+ */
73
+ export declare function resolveDateRangeActiveEdge(value: DateRangeValue): "start" | "end" | null;
74
+ /** 프리셋 길이. `days`는 오늘 포함 n일, `months`는 n개월 전 다음 날부터 오늘까지다. */
75
+ export type DateRangePresetLength = Readonly<{
76
+ days: number;
77
+ } | {
78
+ months: number;
79
+ }>;
80
+ /**
81
+ * 오늘로 끝나는 프리셋 구간(최근 7일·1개월 등). 날짜 계산은 UTC 달력 날짜로만 해 서머타임·시간대에 흔들리지 않는다.
82
+ * 달 길이가 다르면 그 달의 마지막 날로 맞춘다(3/31의 1개월 전 = 2/28, 구간은 3/1부터).
83
+ */
84
+ export declare function resolveDateRangePreset(today: string, length: DateRangePresetLength): DateRangeValue;
85
+ export declare const dateRangeRecipe: {
86
+ readonly slots: readonly ["root", "summary", "summaryField", "summaryLabel", "summaryValue", "presets", "band", "edge"];
87
+ readonly band: {
88
+ readonly background: Readonly<{
89
+ source: "theme";
90
+ key: "primary";
91
+ alpha?: number;
92
+ }>;
93
+ };
94
+ readonly edge: {
95
+ readonly background: Readonly<{
96
+ source: "theme";
97
+ key: "primary";
98
+ alpha?: number;
99
+ }>;
100
+ readonly content: Readonly<{
101
+ source: "theme";
102
+ key: "onPrimary";
103
+ alpha?: number;
104
+ }>;
105
+ };
106
+ readonly summary: {
107
+ readonly gap: 8;
108
+ readonly field: {
109
+ readonly paddingVertical: 8;
110
+ readonly paddingHorizontal: 12;
111
+ readonly radius: "md";
112
+ readonly gap: 4;
113
+ readonly background: Readonly<{
114
+ source: "theme";
115
+ key: "surfaceAlt";
116
+ alpha?: number;
117
+ }>;
118
+ readonly activeBorder: Readonly<{
119
+ source: "theme";
120
+ key: "primary";
121
+ alpha?: number;
122
+ }>;
123
+ readonly activeBorderWidth: 2;
124
+ };
125
+ readonly label: {
126
+ readonly textVariant: "label";
127
+ readonly color: Readonly<{
128
+ source: "theme";
129
+ key: "textMuted";
130
+ alpha?: number;
131
+ }>;
132
+ };
133
+ readonly value: {
134
+ readonly textVariant: "body";
135
+ readonly color: Readonly<{
136
+ source: "theme";
137
+ key: "text";
138
+ alpha?: number;
139
+ }>;
140
+ readonly placeholderColor: Readonly<{
141
+ source: "theme";
142
+ key: "textSub";
143
+ alpha?: number;
144
+ }>;
145
+ };
146
+ };
147
+ readonly presets: {
148
+ readonly gap: 8;
149
+ readonly chipSize: "small";
150
+ };
151
+ readonly gap: 16;
152
+ };
35
153
  /** 구간이 실제로 쓸 수 있는 값인지. 제품의 제출 버튼이 읽는다. */
36
154
  export declare function isCompleteDateRange(value: DateRangeValue): boolean;
37
155
  export declare const dateRangeBehavior: {
@@ -51,6 +169,7 @@ export declare const dateRangeBehavior: {
51
169
  readonly states: readonly ["selected", "disabled"];
52
170
  readonly actions: readonly ["select"];
53
171
  };
54
- readonly scenarios: readonly ["a-click-on-a-complete-range-starts-a-new-one-instead-of-guessing-which-end-to-move", "picking-an-earlier-date-while-selecting-swaps-the-two-instead-of-rejecting-it", "the-selecting-state-is-start-without-end-not-a-separate-flag", "a-hovered-date-previews-the-end-through-the-same-cell-state-function", "an-end-without-a-start-is-rejected-by-validation-not-rendered-as-something", "calendar-keeps-single-selection-this-module-never-adds-a-mode-axis-to-it"];
172
+ readonly scenarios: readonly ["a-click-on-a-complete-range-starts-a-new-one-instead-of-guessing-which-end-to-move", "picking-an-earlier-date-while-selecting-swaps-the-two-instead-of-rejecting-it", "the-selecting-state-is-start-without-end-not-a-separate-flag", "a-hovered-date-previews-the-end-through-the-same-cell-state-function", "an-end-without-a-start-is-rejected-by-validation-not-rendered-as-something", "calendar-keeps-single-selection-this-module-never-adds-a-mode-axis-to-it", "the-range-is-one-band-between-two-filled-edges-and-a-one-day-range-has-no-band", "the-summary-marks-the-edge-being-picked-and-nothing-once-complete", "a-preset-ends-today-and-is-selected-only-while-the-value-equals-it"];
55
173
  };
174
+ export declare function dateRangeSpans(value: DateRangeValue, hoveredDate?: string | null): boolean;
56
175
  //# sourceMappingURL=date-range.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"date-range.d.ts","sourceRoot":"","sources":["../src/date-range.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,cAAc,EAAE,cAA2C,CAAC;AAEzE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAS7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,GACX,cAAc,CAShB;AAED,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,kBAAkB,CASpB;AAED,0CAA0C;AAC1C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAGlE;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;CAqBO,CAAC"}
1
+ {"version":3,"file":"date-range.d.ts","sourceRoot":"","sources":["../src/date-range.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB,CAAC,CAAC;AAEH,eAAO,MAAM,cAAc,EAAE,cAA2C,CAAC;AAEzE;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1F,eAAO,MAAM,qBAAqB,EAAE,cAA6B,CAAC;AA6BlE,2DAA2D;AAC3D,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAQhI;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,GAAE,cAAc,GAAG,IAAW,GAAG,IAAI,CAalG;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,OAAO,CAMjH;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,cAAc,GAAG,IAAW,GAClC,cAAc,CAUhB;AAED,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAEtE;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,kBAAkB,CASpB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;CAAE,CAAC,CAAC;AAI1G,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,kBAAkB,CASpB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,GAAG,KAAK,GAAG,IAAI,CAIxF;AAED,8DAA8D;AAC9D,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAIpF;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,cAAc,CAUnG;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BlB,CAAC;AAEX,0CAA0C;AAC1C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAGlE;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;CAwBO,CAAC;AAEtC,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAK1F"}
@@ -1,6 +1,44 @@
1
- import { assertIsoCalendarDate } from "./calendar.js";
1
+ import { assertIsoCalendarDate, calendarRecipe } from "./calendar.js";
2
+ import { semanticColors } from "./semantic-colors.js";
3
+ import { accentTint } from "./colors.js";
4
+ import { themeColor } from "./color-references.js";
5
+ import { spacing, stroke } from "./foundations.js";
2
6
  export const emptyDateRange = { start: null, end: null };
3
- export function validateDateRange(value) {
7
+ export const defaultDateRangeLimit = { years: 1 };
8
+ function assertDateRangeLimit(limit) {
9
+ const parts = [limit.years ?? 0, limit.months ?? 0, limit.days ?? 0];
10
+ if (parts.some((part) => !Number.isInteger(part) || part < 0) || parts.every((part) => part === 0)) {
11
+ throw new RangeError("Date range limit must be non-negative whole years/months/days and not empty");
12
+ }
13
+ }
14
+ function toUtc(date) {
15
+ return new Date(Date.UTC(Number(date.slice(0, 4)), Number(date.slice(5, 7)) - 1, Number(date.slice(8, 10))));
16
+ }
17
+ function toIso(date) {
18
+ return date.toISOString().slice(0, 10);
19
+ }
20
+ /** 달을 옮기면 그 달에 없는 날(1월 31일 + 1개월)은 말일로 맞춘다. 넘겨서 다음 달로 새지 않게 한다. */
21
+ function shiftIsoDate(date, limit, sign) {
22
+ const base = toUtc(date);
23
+ const months = base.getUTCFullYear() * 12 + base.getUTCMonth() + sign * ((limit.years ?? 0) * 12 + (limit.months ?? 0));
24
+ const year = Math.floor(months / 12);
25
+ const month = months - year * 12;
26
+ const lastDay = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
27
+ const shifted = new Date(Date.UTC(year, month, Math.min(base.getUTCDate(), lastDay)));
28
+ shifted.setUTCDate(shifted.getUTCDate() + sign * (limit.days ?? 0));
29
+ return toIso(shifted);
30
+ }
31
+ /** `start`를 한쪽 끝으로 둘 때 다른 끝이 올 수 있는 가장 이른·늦은 날(둘 다 포함). */
32
+ export function resolveDateRangeLimitBounds(start, limit) {
33
+ assertIsoCalendarDate(start, "range start");
34
+ assertDateRangeLimit(limit);
35
+ const latest = toUtc(shiftIsoDate(start, limit, 1));
36
+ latest.setUTCDate(latest.getUTCDate() - 1);
37
+ const earliest = toUtc(shiftIsoDate(start, limit, -1));
38
+ earliest.setUTCDate(earliest.getUTCDate() + 1);
39
+ return { earliest: toIso(earliest), latest: toIso(latest) };
40
+ }
41
+ export function validateDateRange(value, limit = null) {
4
42
  if (value.start !== null)
5
43
  assertIsoCalendarDate(value.start, "range start");
6
44
  if (value.end !== null)
@@ -11,6 +49,22 @@ export function validateDateRange(value) {
11
49
  if (value.start !== null && value.end !== null && value.end < value.start) {
12
50
  throw new RangeError("Date range end must not precede start");
13
51
  }
52
+ if (limit !== null && value.start !== null && value.end !== null
53
+ && value.end > resolveDateRangeLimitBounds(value.start, limit).latest) {
54
+ throw new RangeError("Date range exceeds its maximum length");
55
+ }
56
+ }
57
+ /**
58
+ * 고르는 중에 이 날짜를 끝으로 고를 수 있는지. 비었거나 완성된 구간에서는 누르면 새로 시작하므로
59
+ * 언제나 고를 수 있다. 막힌 날은 renderer가 비활성으로 그린다 — 눌렀다가 거절하면 이유를 알 수 없다.
60
+ */
61
+ export function isDateWithinRangeLimit(value, date, limit) {
62
+ assertIsoCalendarDate(date, "date");
63
+ validateDateRange(value, limit);
64
+ if (limit === null || value.start === null || value.end !== null)
65
+ return true;
66
+ const { earliest, latest } = resolveDateRangeLimitBounds(value.start, limit);
67
+ return date >= earliest && date <= latest;
14
68
  }
15
69
  /**
16
70
  * 날짜 하나를 눌렀을 때의 다음 값.
@@ -21,10 +75,11 @@ export function validateDateRange(value) {
21
75
  * - 고르는 중이면 **끝**을 정한다. 시작보다 앞선 날짜를 누르면 두 값을 바꿔 담는다 —
22
76
  * 거절하면 사용자가 왜 안 되는지 알 수 없다.
23
77
  */
24
- export function resolveDateRangeSelection(current, date) {
78
+ export function resolveDateRangeSelection(current, date, limit = null) {
25
79
  assertIsoCalendarDate(date, "selected date");
26
- validateDateRange(current);
27
- if (current.start === null || current.end !== null) {
80
+ validateDateRange(current, limit);
81
+ // 최대 길이를 넘는 날은 renderer가 막지만, 그래도 들어오면 넘는 구간을 만들지 않고 거기서 새로 시작한다.
82
+ if (current.start === null || current.end !== null || !isDateWithinRangeLimit(current, date, limit)) {
28
83
  return { start: date, end: null };
29
84
  }
30
85
  return date < current.start
@@ -49,6 +104,75 @@ export function resolveDateRangeCellState(value, date, hoveredDate) {
49
104
  return "between";
50
105
  return "none";
51
106
  }
107
+ const unpainted = { edge: false, band: "none" };
108
+ export function resolveDateRangeCellPaint(value, date, hoveredDate) {
109
+ const state = resolveDateRangeCellState(value, date, hoveredDate);
110
+ if (state === "none")
111
+ return unpainted;
112
+ if (state === "between")
113
+ return { edge: false, band: "full" };
114
+ const provisionalEnd = value.end
115
+ ?? (hoveredDate != null && value.start !== null && hoveredDate >= value.start ? hoveredDate : null);
116
+ const spans = provisionalEnd !== null && provisionalEnd !== value.start;
117
+ if (state === "start")
118
+ return { edge: true, band: spans ? "toEnd" : "none" };
119
+ return { edge: true, band: spans ? "toStart" : "none" };
120
+ }
121
+ /**
122
+ * 요약 칸에서 강조할 끝. 비었으면 시작, 고르는 중이면 끝을 강조한다. 완성된 구간은 아무것도 강조하지 않는다 —
123
+ * 다음 탭이 새 시작이 되긴 하지만, 완성 직후 시작 칸이 강조되면 시작일을 고치는 중으로 읽혔다(2026-10-25 실화면).
124
+ */
125
+ export function resolveDateRangeActiveEdge(value) {
126
+ validateDateRange(value);
127
+ if (value.start === null)
128
+ return "start";
129
+ return value.end === null ? "end" : null;
130
+ }
131
+ const isoOf = (date) => date.toISOString().slice(0, 10);
132
+ /**
133
+ * 오늘로 끝나는 프리셋 구간(최근 7일·1개월 등). 날짜 계산은 UTC 달력 날짜로만 해 서머타임·시간대에 흔들리지 않는다.
134
+ * 달 길이가 다르면 그 달의 마지막 날로 맞춘다(3/31의 1개월 전 = 2/28, 구간은 3/1부터).
135
+ */
136
+ export function resolveDateRangePreset(today, length) {
137
+ assertIsoCalendarDate(today, "preset today");
138
+ const [year, month, day] = today.split("-").map(Number);
139
+ const count = "days" in length ? length.days : length.months;
140
+ if (!Number.isInteger(count) || count < 1)
141
+ throw new RangeError("Date range preset length must be a positive integer");
142
+ if ("days" in length)
143
+ return { start: isoOf(new Date(Date.UTC(year, month - 1, day - (count - 1)))), end: today };
144
+ const lastDay = new Date(Date.UTC(year, month - 1 - count + 1, 0)).getUTCDate();
145
+ const anchor = new Date(Date.UTC(year, month - 1 - count, Math.min(day, lastDay)));
146
+ anchor.setUTCDate(anchor.getUTCDate() + 1);
147
+ return { start: isoOf(anchor), end: today };
148
+ }
149
+ export const dateRangeRecipe = {
150
+ slots: ["root", "summary", "summaryField", "summaryLabel", "summaryValue", "presets", "band", "edge"],
151
+ // 띠는 두 끝 원과 같은 브랜드색의 tint다. 처음 쓴 `interaction.selected`(surfaceSelected)는 기본 팔레트에서
152
+ // #f0f1f3 회색이라 시트 바탕 위에서 구간이 거의 보이지 않았다(2026-10-25 Spint 실화면). 높이는 날짜 원과 같다.
153
+ band: { background: themeColor("primary", accentTint.base) },
154
+ edge: calendarRecipe.day.selected,
155
+ // 시작일·종료일 요약. 안내 문장 대신 "다음에 고를 쪽"을 강조해 지금 무엇을 누르는지 보여 준다
156
+ // (Material 3 기간 선택 머리·Airbnb 체크인/체크아웃 칸 모티브). 값이 없으면 제품 placeholder를 쓴다.
157
+ summary: {
158
+ gap: spacing.xs,
159
+ field: {
160
+ paddingVertical: spacing.xs,
161
+ paddingHorizontal: spacing.sm,
162
+ radius: "md",
163
+ gap: spacing.xxs,
164
+ background: semanticColors.surface.sunken,
165
+ activeBorder: semanticColors.action.brand.background,
166
+ activeBorderWidth: stroke.strong,
167
+ },
168
+ label: { textVariant: "label", color: semanticColors.content.secondary },
169
+ value: { textVariant: "body", color: semanticColors.content.primary, placeholderColor: semanticColors.content.tertiary },
170
+ },
171
+ // 프리셋 칩 줄(Chip 단일 선택, 작은 크기). 요약 아래·달력 위에서 줄바꿈한다.
172
+ presets: { gap: spacing.xs, chipSize: "small" },
173
+ // 요약·프리셋·달력 사이.
174
+ gap: spacing.md,
175
+ };
52
176
  /** 구간이 실제로 쓸 수 있는 값인지. 제품의 제출 버튼이 읽는다. */
53
177
  export function isCompleteDateRange(value) {
54
178
  validateDateRange(value);
@@ -74,6 +198,16 @@ export const dateRangeBehavior = {
74
198
  "a-hovered-date-previews-the-end-through-the-same-cell-state-function",
75
199
  "an-end-without-a-start-is-rejected-by-validation-not-rendered-as-something",
76
200
  "calendar-keeps-single-selection-this-module-never-adds-a-mode-axis-to-it",
201
+ "the-range-is-one-band-between-two-filled-edges-and-a-one-day-range-has-no-band",
202
+ "the-summary-marks-the-edge-being-picked-and-nothing-once-complete",
203
+ "a-preset-ends-today-and-is-selected-only-while-the-value-equals-it",
77
204
  ],
78
205
  };
206
+ export function dateRangeSpans(value, hoveredDate) {
207
+ validateDateRange(value);
208
+ if (value.start === null)
209
+ return false;
210
+ const end = value.end ?? (hoveredDate != null && hoveredDate >= value.start ? hoveredDate : null);
211
+ return end !== null && end !== value.start;
212
+ }
79
213
  //# sourceMappingURL=date-range.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"date-range.js","sourceRoot":"","sources":["../src/date-range.ts"],"names":[],"mappings":"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","sourcesContent":["import { assertIsoCalendarDate } from \"./calendar.js\";\nimport type { BehaviorContract } from \"./behaviors.js\";\n\n/**\n * 날짜 **구간** 선택. Calendar의 단일 선택과 같은 격자를 쓰되, \"지금 무엇을 고르는\n * 중인가\"라는 축이 하나 더 있다.\n *\n * Calendar에 `mode: \"single\" | \"range\"`를 넣지 않은 이유: 단일 선택의 값은\n * `string | null`이고 구간의 값은 `{start, end}`다. 한 컴포넌트가 두 값 모양을 가지면\n * 모든 소비자가 매번 좁히기(narrowing)를 해야 하고, \"range 모드인데 selectedDate를 준\"\n * 조합이 타입에 남는다. 대신 이 모듈이 **구간 판정만** 갖고 격자는 그대로 재사용한다.\n *\n * 값은 제품이 저장한다 — 이 모듈은 다음 클릭이 시작을 바꾸는지 끝을 정하는지만 답한다.\n */\nexport type DateRangeValue = Readonly<{\n start: string | null;\n /** `start`만 있고 `end`가 없는 상태가 \"고르는 중\"이다. 별도 플래그를 두지 않는다. */\n end: string | null;\n}>;\n\nexport const emptyDateRange: DateRangeValue = { start: null, end: null };\n\nexport function validateDateRange(value: DateRangeValue): void {\n if (value.start !== null) assertIsoCalendarDate(value.start, \"range start\");\n if (value.end !== null) assertIsoCalendarDate(value.end, \"range end\");\n if (value.start === null && value.end !== null) {\n throw new TypeError(\"Date range cannot have an end without a start\");\n }\n if (value.start !== null && value.end !== null && value.end < value.start) {\n throw new RangeError(\"Date range end must not precede start\");\n }\n}\n\n/**\n * 날짜 하나를 눌렀을 때의 다음 값.\n *\n * - 비어 있거나 이미 완성된 구간이면 새 구간을 **시작**한다. (완성된 구간을 다시 눌렀을\n * 때 끝을 옮기는 동작은 \"어느 쪽 끝인가\"를 추측해야 해서 넣지 않았다 — 다시 시작하는\n * 쪽이 예측 가능하다.)\n * - 고르는 중이면 **끝**을 정한다. 시작보다 앞선 날짜를 누르면 두 값을 바꿔 담는다 —\n * 거절하면 사용자가 왜 안 되는지 알 수 없다.\n */\nexport function resolveDateRangeSelection(\n current: DateRangeValue,\n date: string,\n): DateRangeValue {\n assertIsoCalendarDate(date, \"selected date\");\n validateDateRange(current);\n if (current.start === null || current.end !== null) {\n return { start: date, end: null };\n }\n return date < current.start\n ? { start: date, end: current.start }\n : { start: current.start, end: date };\n}\n\nexport type DateRangeCellState = \"start\" | \"end\" | \"between\" | \"none\";\n\n/**\n * 한 칸이 구간 안에서 어떤 자리인지. 미리보기(`hoveredDate`)는 아직 확정되지 않은 끝을\n * 가리키므로 같은 함수가 처리한다 — renderer가 두 벌의 칠하기 규칙을 만들지 않게 한다.\n */\nexport function resolveDateRangeCellState(\n value: DateRangeValue,\n date: string,\n hoveredDate?: string | null,\n): DateRangeCellState {\n validateDateRange(value);\n if (value.start === null) return \"none\";\n const provisionalEnd = value.end\n ?? (hoveredDate != null && hoveredDate >= value.start ? hoveredDate : null);\n if (date === value.start && (provisionalEnd === null || date !== provisionalEnd)) return \"start\";\n if (provisionalEnd !== null && date === provisionalEnd) return \"end\";\n if (provisionalEnd !== null && date > value.start && date < provisionalEnd) return \"between\";\n return \"none\";\n}\n\n/** 구간이 실제로 쓸 수 있는 값인지. 제품의 제출 버튼이 읽는다. */\nexport function isCompleteDateRange(value: DateRangeValue): boolean {\n validateDateRange(value);\n return value.start !== null && value.end !== null;\n}\n\nexport const dateRangeBehavior = {\n controlled: [\"value\", \"defaultValue\", \"onValueChange\"],\n inputs: [\"grid\", \"monthLabel\", \"hoveredDate\"],\n stateAxes: {\n value: [\"empty\", \"selecting\", \"complete\"],\n availability: [\"enabled\", \"disabled\"],\n },\n web: {\n roles: [\"grid\", \"gridcell\"],\n keyboard: [\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\", \"Enter\", \"Space\"],\n focus: \"roving\",\n },\n native: { roles: [], states: [\"selected\", \"disabled\"], actions: [\"select\"] },\n scenarios: [\n \"a-click-on-a-complete-range-starts-a-new-one-instead-of-guessing-which-end-to-move\",\n \"picking-an-earlier-date-while-selecting-swaps-the-two-instead-of-rejecting-it\",\n \"the-selecting-state-is-start-without-end-not-a-separate-flag\",\n \"a-hovered-date-previews-the-end-through-the-same-cell-state-function\",\n \"an-end-without-a-start-is-rejected-by-validation-not-rendered-as-something\",\n \"calendar-keeps-single-selection-this-module-never-adds-a-mode-axis-to-it\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"date-range.js","sourceRoot":"","sources":["../src/date-range.ts"],"names":[],"mappings":"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","sourcesContent":["import { assertIsoCalendarDate, calendarRecipe } from \"./calendar.js\";\nimport type { BehaviorContract } from \"./behaviors.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport { accentTint } from \"./colors.js\";\nimport { themeColor } from \"./color-references.js\";\nimport { spacing, stroke } from \"./foundations.js\";\n\n/**\n * 날짜 **구간** 선택. Calendar의 단일 선택과 같은 격자를 쓰되, \"지금 무엇을 고르는\n * 중인가\"라는 축이 하나 더 있다.\n *\n * Calendar에 `mode: \"single\" | \"range\"`를 넣지 않은 이유: 단일 선택의 값은\n * `string | null`이고 구간의 값은 `{start, end}`다. 한 컴포넌트가 두 값 모양을 가지면\n * 모든 소비자가 매번 좁히기(narrowing)를 해야 하고, \"range 모드인데 selectedDate를 준\"\n * 조합이 타입에 남는다. 대신 이 모듈이 **구간 판정만** 갖고 격자는 그대로 재사용한다.\n *\n * 값은 제품이 저장한다 — 이 모듈은 다음 클릭이 시작을 바꾸는지 끝을 정하는지만 답한다.\n */\nexport type DateRangeValue = Readonly<{\n start: string | null;\n /** `start`만 있고 `end`가 없는 상태가 \"고르는 중\"이다. 별도 플래그를 두지 않는다. */\n end: string | null;\n}>;\n\nexport const emptyDateRange: DateRangeValue = { start: null, end: null };\n\n/**\n * 구간이 덮을 수 있는 최대 길이. 일수가 아니라 달력 단위로 센다 — \"1년\"을 365일로 두면 윤년을 낀\n * 1월 1일~12월 31일이 막힌다. 끝은 포함이라 `{ years: 1 }`은 2026-01-01부터 2026-12-31까지다.\n * 2026-10-25 사용자 요청으로 DateRangePicker 기본값은 1년이고, `null`이면 제한하지 않는다.\n */\nexport type DateRangeLimit = Readonly<{ years?: number; months?: number; days?: number }>;\n\nexport const defaultDateRangeLimit: DateRangeLimit = { years: 1 };\n\nfunction assertDateRangeLimit(limit: DateRangeLimit): void {\n const parts = [limit.years ?? 0, limit.months ?? 0, limit.days ?? 0];\n if (parts.some((part) => !Number.isInteger(part) || part < 0) || parts.every((part) => part === 0)) {\n throw new RangeError(\"Date range limit must be non-negative whole years/months/days and not empty\");\n }\n}\n\nfunction toUtc(date: string): Date {\n return new Date(Date.UTC(Number(date.slice(0, 4)), Number(date.slice(5, 7)) - 1, Number(date.slice(8, 10))));\n}\n\nfunction toIso(date: Date): string {\n return date.toISOString().slice(0, 10);\n}\n\n/** 달을 옮기면 그 달에 없는 날(1월 31일 + 1개월)은 말일로 맞춘다. 넘겨서 다음 달로 새지 않게 한다. */\nfunction shiftIsoDate(date: string, limit: DateRangeLimit, sign: 1 | -1): string {\n const base = toUtc(date);\n const months = base.getUTCFullYear() * 12 + base.getUTCMonth() + sign * ((limit.years ?? 0) * 12 + (limit.months ?? 0));\n const year = Math.floor(months / 12);\n const month = months - year * 12;\n const lastDay = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();\n const shifted = new Date(Date.UTC(year, month, Math.min(base.getUTCDate(), lastDay)));\n shifted.setUTCDate(shifted.getUTCDate() + sign * (limit.days ?? 0));\n return toIso(shifted);\n}\n\n/** `start`를 한쪽 끝으로 둘 때 다른 끝이 올 수 있는 가장 이른·늦은 날(둘 다 포함). */\nexport function resolveDateRangeLimitBounds(start: string, limit: DateRangeLimit): Readonly<{ earliest: string; latest: string }> {\n assertIsoCalendarDate(start, \"range start\");\n assertDateRangeLimit(limit);\n const latest = toUtc(shiftIsoDate(start, limit, 1));\n latest.setUTCDate(latest.getUTCDate() - 1);\n const earliest = toUtc(shiftIsoDate(start, limit, -1));\n earliest.setUTCDate(earliest.getUTCDate() + 1);\n return { earliest: toIso(earliest), latest: toIso(latest) };\n}\n\nexport function validateDateRange(value: DateRangeValue, limit: DateRangeLimit | null = null): void {\n if (value.start !== null) assertIsoCalendarDate(value.start, \"range start\");\n if (value.end !== null) assertIsoCalendarDate(value.end, \"range end\");\n if (value.start === null && value.end !== null) {\n throw new TypeError(\"Date range cannot have an end without a start\");\n }\n if (value.start !== null && value.end !== null && value.end < value.start) {\n throw new RangeError(\"Date range end must not precede start\");\n }\n if (limit !== null && value.start !== null && value.end !== null\n && value.end > resolveDateRangeLimitBounds(value.start, limit).latest) {\n throw new RangeError(\"Date range exceeds its maximum length\");\n }\n}\n\n/**\n * 고르는 중에 이 날짜를 끝으로 고를 수 있는지. 비었거나 완성된 구간에서는 누르면 새로 시작하므로\n * 언제나 고를 수 있다. 막힌 날은 renderer가 비활성으로 그린다 — 눌렀다가 거절하면 이유를 알 수 없다.\n */\nexport function isDateWithinRangeLimit(value: DateRangeValue, date: string, limit: DateRangeLimit | null): boolean {\n assertIsoCalendarDate(date, \"date\");\n validateDateRange(value, limit);\n if (limit === null || value.start === null || value.end !== null) return true;\n const { earliest, latest } = resolveDateRangeLimitBounds(value.start, limit);\n return date >= earliest && date <= latest;\n}\n\n/**\n * 날짜 하나를 눌렀을 때의 다음 값.\n *\n * - 비어 있거나 이미 완성된 구간이면 새 구간을 **시작**한다. (완성된 구간을 다시 눌렀을\n * 때 끝을 옮기는 동작은 \"어느 쪽 끝인가\"를 추측해야 해서 넣지 않았다 — 다시 시작하는\n * 쪽이 예측 가능하다.)\n * - 고르는 중이면 **끝**을 정한다. 시작보다 앞선 날짜를 누르면 두 값을 바꿔 담는다 —\n * 거절하면 사용자가 왜 안 되는지 알 수 없다.\n */\nexport function resolveDateRangeSelection(\n current: DateRangeValue,\n date: string,\n limit: DateRangeLimit | null = null,\n): DateRangeValue {\n assertIsoCalendarDate(date, \"selected date\");\n validateDateRange(current, limit);\n // 최대 길이를 넘는 날은 renderer가 막지만, 그래도 들어오면 넘는 구간을 만들지 않고 거기서 새로 시작한다.\n if (current.start === null || current.end !== null || !isDateWithinRangeLimit(current, date, limit)) {\n return { start: date, end: null };\n }\n return date < current.start\n ? { start: date, end: current.start }\n : { start: current.start, end: date };\n}\n\nexport type DateRangeCellState = \"start\" | \"end\" | \"between\" | \"none\";\n\n/**\n * 한 칸이 구간 안에서 어떤 자리인지. 미리보기(`hoveredDate`)는 아직 확정되지 않은 끝을\n * 가리키므로 같은 함수가 처리한다 — renderer가 두 벌의 칠하기 규칙을 만들지 않게 한다.\n */\nexport function resolveDateRangeCellState(\n value: DateRangeValue,\n date: string,\n hoveredDate?: string | null,\n): DateRangeCellState {\n validateDateRange(value);\n if (value.start === null) return \"none\";\n const provisionalEnd = value.end\n ?? (hoveredDate != null && hoveredDate >= value.start ? hoveredDate : null);\n if (date === value.start && (provisionalEnd === null || date !== provisionalEnd)) return \"start\";\n if (provisionalEnd !== null && date === provisionalEnd) return \"end\";\n if (provisionalEnd !== null && date > value.start && date < provisionalEnd) return \"between\";\n return \"none\";\n}\n\n/**\n * 칸 하나를 어떻게 칠하는지. `edge`는 채운 원(시작·끝), `band`는 시작과 끝을 잇는 띠의 모양이다.\n * 띠는 시작 칸에서 끝 쪽 절반(`toEnd`), 끝 칸에서 시작 쪽 절반(`toStart`), 사이 칸 전체(`full`)를 덮는다.\n * 시작과 끝이 같은 날(하루 구간)이거나 끝이 아직 없으면 띠가 없다.\n *\n * 2026-10-25 개편(Spint 기간 시트 사용자 지적): 점 표시는 구간이 이어져 보이지 않았고, 점 줄 때문에 행이\n * 라벨 한 줄만큼 높아졌다. Material 3·Airbnb처럼 띠로 잇고 두 끝을 같은 채운 원으로 그린다.\n */\nexport type DateRangeCellPaint = Readonly<{ edge: boolean; band: \"none\" | \"full\" | \"toEnd\" | \"toStart\" }>;\n\nconst unpainted: DateRangeCellPaint = { edge: false, band: \"none\" };\n\nexport function resolveDateRangeCellPaint(\n value: DateRangeValue,\n date: string,\n hoveredDate?: string | null,\n): DateRangeCellPaint {\n const state = resolveDateRangeCellState(value, date, hoveredDate);\n if (state === \"none\") return unpainted;\n if (state === \"between\") return { edge: false, band: \"full\" };\n const provisionalEnd = value.end\n ?? (hoveredDate != null && value.start !== null && hoveredDate >= value.start ? hoveredDate : null);\n const spans = provisionalEnd !== null && provisionalEnd !== value.start;\n if (state === \"start\") return { edge: true, band: spans ? \"toEnd\" : \"none\" };\n return { edge: true, band: spans ? \"toStart\" : \"none\" };\n}\n\n/**\n * 요약 칸에서 강조할 끝. 비었으면 시작, 고르는 중이면 끝을 강조한다. 완성된 구간은 아무것도 강조하지 않는다 —\n * 다음 탭이 새 시작이 되긴 하지만, 완성 직후 시작 칸이 강조되면 시작일을 고치는 중으로 읽혔다(2026-10-25 실화면).\n */\nexport function resolveDateRangeActiveEdge(value: DateRangeValue): \"start\" | \"end\" | null {\n validateDateRange(value);\n if (value.start === null) return \"start\";\n return value.end === null ? \"end\" : null;\n}\n\n/** 프리셋 길이. `days`는 오늘 포함 n일, `months`는 n개월 전 다음 날부터 오늘까지다. */\nexport type DateRangePresetLength = Readonly<{ days: number } | { months: number }>;\n\nconst isoOf = (date: Date) => date.toISOString().slice(0, 10);\n\n/**\n * 오늘로 끝나는 프리셋 구간(최근 7일·1개월 등). 날짜 계산은 UTC 달력 날짜로만 해 서머타임·시간대에 흔들리지 않는다.\n * 달 길이가 다르면 그 달의 마지막 날로 맞춘다(3/31의 1개월 전 = 2/28, 구간은 3/1부터).\n */\nexport function resolveDateRangePreset(today: string, length: DateRangePresetLength): DateRangeValue {\n assertIsoCalendarDate(today, \"preset today\");\n const [year, month, day] = today.split(\"-\").map(Number) as [number, number, number];\n const count = \"days\" in length ? length.days : length.months;\n if (!Number.isInteger(count) || count < 1) throw new RangeError(\"Date range preset length must be a positive integer\");\n if (\"days\" in length) return { start: isoOf(new Date(Date.UTC(year, month - 1, day - (count - 1)))), end: today };\n const lastDay = new Date(Date.UTC(year, month - 1 - count + 1, 0)).getUTCDate();\n const anchor = new Date(Date.UTC(year, month - 1 - count, Math.min(day, lastDay)));\n anchor.setUTCDate(anchor.getUTCDate() + 1);\n return { start: isoOf(anchor), end: today };\n}\n\nexport const dateRangeRecipe = {\n slots: [\"root\", \"summary\", \"summaryField\", \"summaryLabel\", \"summaryValue\", \"presets\", \"band\", \"edge\"] as const,\n // 띠는 두 끝 원과 같은 브랜드색의 tint다. 처음 쓴 `interaction.selected`(surfaceSelected)는 기본 팔레트에서\n // #f0f1f3 회색이라 시트 바탕 위에서 구간이 거의 보이지 않았다(2026-10-25 Spint 실화면). 높이는 날짜 원과 같다.\n band: { background: themeColor(\"primary\", accentTint.base) },\n edge: calendarRecipe.day.selected,\n // 시작일·종료일 요약. 안내 문장 대신 \"다음에 고를 쪽\"을 강조해 지금 무엇을 누르는지 보여 준다\n // (Material 3 기간 선택 머리·Airbnb 체크인/체크아웃 칸 모티브). 값이 없으면 제품 placeholder를 쓴다.\n summary: {\n gap: spacing.xs,\n field: {\n paddingVertical: spacing.xs,\n paddingHorizontal: spacing.sm,\n radius: \"md\" as const,\n gap: spacing.xxs,\n background: semanticColors.surface.sunken,\n activeBorder: semanticColors.action.brand.background,\n activeBorderWidth: stroke.strong,\n },\n label: { textVariant: \"label\" as const, color: semanticColors.content.secondary },\n value: { textVariant: \"body\" as const, color: semanticColors.content.primary, placeholderColor: semanticColors.content.tertiary },\n },\n // 프리셋 칩 줄(Chip 단일 선택, 작은 크기). 요약 아래·달력 위에서 줄바꿈한다.\n presets: { gap: spacing.xs, chipSize: \"small\" as const },\n // 요약·프리셋·달력 사이.\n gap: spacing.md,\n} as const;\n\n/** 구간이 실제로 쓸 수 있는 값인지. 제품의 제출 버튼이 읽는다. */\nexport function isCompleteDateRange(value: DateRangeValue): boolean {\n validateDateRange(value);\n return value.start !== null && value.end !== null;\n}\n\nexport const dateRangeBehavior = {\n controlled: [\"value\", \"defaultValue\", \"onValueChange\"],\n inputs: [\"grid\", \"monthLabel\", \"hoveredDate\"],\n stateAxes: {\n value: [\"empty\", \"selecting\", \"complete\"],\n availability: [\"enabled\", \"disabled\"],\n },\n web: {\n roles: [\"grid\", \"gridcell\"],\n keyboard: [\"ArrowUp\", \"ArrowDown\", \"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\", \"Enter\", \"Space\"],\n focus: \"roving\",\n },\n native: { roles: [], states: [\"selected\", \"disabled\"], actions: [\"select\"] },\n scenarios: [\n \"a-click-on-a-complete-range-starts-a-new-one-instead-of-guessing-which-end-to-move\",\n \"picking-an-earlier-date-while-selecting-swaps-the-two-instead-of-rejecting-it\",\n \"the-selecting-state-is-start-without-end-not-a-separate-flag\",\n \"a-hovered-date-previews-the-end-through-the-same-cell-state-function\",\n \"an-end-without-a-start-is-rejected-by-validation-not-rendered-as-something\",\n \"calendar-keeps-single-selection-this-module-never-adds-a-mode-axis-to-it\",\n \"the-range-is-one-band-between-two-filled-edges-and-a-one-day-range-has-no-band\",\n \"the-summary-marks-the-edge-being-picked-and-nothing-once-complete\",\n \"a-preset-ends-today-and-is-selected-only-while-the-value-equals-it\",\n ],\n} as const satisfies BehaviorContract;\n\nexport function dateRangeSpans(value: DateRangeValue, hoveredDate?: string | null): boolean {\n validateDateRange(value);\n if (value.start === null) return false;\n const end = value.end ?? (hoveredDate != null && hoveredDate >= value.start ? hoveredDate : null);\n return end !== null && end !== value.start;\n}\n"]}
package/dist/icon.d.ts CHANGED
@@ -6,7 +6,7 @@ import type { DesignSystemDirection } from "./design-system-provider.js";
6
6
  * or native glyph component instead of leaking a third-party icon name into a
7
7
  * product screen.
8
8
  */
9
- export declare const semanticIconNames: readonly ["add", "ai", "alert", "arrowDown", "arrowUp", "back", "calendar", "check", "chevronDown", "chevronEnd", "chevronStart", "chevronUp", "close", "compare", "copy", "delete", "download", "edit", "error", "favorite", "filter", "forward", "help", "home", "info", "lock", "menu", "more", "notifications", "pause", "play", "refresh", "rotate", "search", "settings", "share", "success", "trendDown", "trendFlat", "trendUp", "unblock", "upload", "user", "users", "visibility", "visibilityOff", "warning"];
9
+ export declare const semanticIconNames: readonly ["add", "ai", "alert", "arrowDown", "arrowUp", "back", "calendar", "check", "chevronDown", "chevronEnd", "chevronStart", "chevronUp", "close", "compare", "copy", "delete", "download", "edit", "error", "favorite", "filter", "forward", "help", "home", "info", "lock", "menu", "more", "moreVertical", "notifications", "pause", "play", "refresh", "rotate", "search", "settings", "share", "success", "trendDown", "trendFlat", "trendUp", "unblock", "upload", "user", "users", "visibility", "visibilityOff", "warning"];
10
10
  export type SemanticIconName = (typeof semanticIconNames)[number];
11
11
  /**
12
12
  * Geometry of every semantic mark on one 24-unit stroke grid (round caps/joins, no fill). It lived privately in the
@@ -43,6 +43,7 @@ export declare const semanticIconPaths: {
43
43
  readonly lock: "M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 6 0v3";
44
44
  readonly menu: "M4 6h16M4 12h16M4 18h16";
45
45
  readonly more: "M5 12h.01M12 12h.01M19 12h.01";
46
+ readonly moreVertical: "M12 5h.01M12 12h.01M12 19h.01";
46
47
  readonly notifications: "M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Zm-8 12h4";
47
48
  readonly pause: "M8 5v14m8-14v14";
48
49
  readonly play: "m8 5 11 7-11 7V5Z";
@@ -1 +1 @@
1
- {"version":3,"file":"icon.d.ts","sourceRoot":"","sources":["../src/icon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,0fAgDpB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDuB,CAAC;AAItD,iHAAiH;AACjH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,gBAAgB,CAEzE;AACD,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAClD,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,eAAe,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,eAAe,CAAC;AASrD,KAAK,cAAc,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,MAAM,wBAAwB,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IACzE,cAAc,GACZ,QAAQ,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,kBAAkB,CAAC,EAAE,KAAK,CAAC;CAC5B,CAAC,CAAC;AAEP,MAAM,MAAM,yBAAyB,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IAC1E,cAAc,GACZ,QAAQ,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,oFAAoF;IACpF,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACvC,UAAU,EAAE,KAAK,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC,CAAC;AAEP,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IAC7D,wBAAwB,CAAC,IAAI,CAAC,GAC9B,yBAAyB,CAAC,IAAI,CAAC,CAAC;AAEpC,MAAM,MAAM,sBAAsB,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IACrE,CAAC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC,CAAC,GACnE,QAAQ,CAAC;IAAE,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,GAC3C,QAAQ,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC;AAE9C,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAEtE;AAED,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,kBAAkB,EAClC,SAAS,EAAE,aAAa,GACvB,aAAa,CAUf;AAgBD,wBAAgB,sBAAsB,CAAC,IAAI,SAAS,MAAM,EACxD,UAAU,EAAE,cAAc,CAAC,IAAI,CAAC,GAC/B,IAAI,CAkDN;AAED,wBAAgB,qBAAqB,CAAC,IAAI,SAAS,MAAM,EACvD,UAAU,EAAE,cAAc,CAAC,IAAI,CAAC,GAC/B,sBAAsB,CAAC,IAAI,CAAC,CAqB9B"}
1
+ {"version":3,"file":"icon.d.ts","sourceRoot":"","sources":["../src/icon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,0gBAiDpB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDuB,CAAC;AAItD,iHAAiH;AACjH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,gBAAgB,CAEzE;AACD,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAClD,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,eAAe,CAAC;AAC3D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,eAAe,CAAC;AASrD,KAAK,cAAc,GAAG,QAAQ,CAAC;IAC7B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,cAAc,CAAC,EAAE,kBAAkB,CAAC;CACrC,CAAC,CAAC;AAEH,MAAM,MAAM,wBAAwB,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IACzE,cAAc,GACZ,QAAQ,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,kBAAkB,CAAC,EAAE,KAAK,CAAC;CAC5B,CAAC,CAAC;AAEP,MAAM,MAAM,yBAAyB,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IAC1E,cAAc,GACZ,QAAQ,CAAC;IACP,IAAI,EAAE,IAAI,CAAC;IACX,oFAAoF;IACpF,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACvC,UAAU,EAAE,KAAK,CAAC;IAClB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC,CAAC;AAEP,MAAM,MAAM,cAAc,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IAC7D,wBAAwB,CAAC,IAAI,CAAC,GAC9B,yBAAyB,CAAC,IAAI,CAAC,CAAC;AAEpC,MAAM,MAAM,sBAAsB,CAAC,IAAI,SAAS,MAAM,GAAG,gBAAgB,IACrE,CAAC,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC,CAAC,GACnE,QAAQ,CAAC;IAAE,kBAAkB,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC,GAC3C,QAAQ,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC;AAE9C,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAEtE;AAED,wBAAgB,gBAAgB,CAC9B,cAAc,EAAE,kBAAkB,EAClC,SAAS,EAAE,aAAa,GACvB,aAAa,CAUf;AAgBD,wBAAgB,sBAAsB,CAAC,IAAI,SAAS,MAAM,EACxD,UAAU,EAAE,cAAc,CAAC,IAAI,CAAC,GAC/B,IAAI,CAkDN;AAED,wBAAgB,qBAAqB,CAAC,IAAI,SAAS,MAAM,EACvD,UAAU,EAAE,cAAc,CAAC,IAAI,CAAC,GAC/B,sBAAsB,CAAC,IAAI,CAAC,CAqB9B"}
package/dist/icon.js CHANGED
@@ -32,6 +32,7 @@ export const semanticIconNames = [
32
32
  "lock",
33
33
  "menu",
34
34
  "more",
35
+ "moreVertical",
35
36
  "notifications",
36
37
  "pause",
37
38
  "play",
@@ -88,6 +89,7 @@ export const semanticIconPaths = {
88
89
  lock: "M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 6 0v3",
89
90
  menu: "M4 6h16M4 12h16M4 18h16",
90
91
  more: "M5 12h.01M12 12h.01M19 12h.01",
92
+ moreVertical: "M12 5h.01M12 12h.01M12 19h.01",
91
93
  notifications: "M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Zm-8 12h4",
92
94
  pause: "M8 5v14m8-14v14",
93
95
  play: "m8 5 11 7-11 7V5Z",
package/dist/icon.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"icon.js","sourceRoot":"","sources":["../src/icon.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GlyphSize } from \"./foundations.js\";\nimport type { IconTone, IconWeight } from \"./component-recipes.js\";\nimport type { DesignSystemDirection } from \"./design-system-provider.js\";\n\n/**\n * Shared semantic names. Renderers map these roles to their tree-shakeable SVG\n * or native glyph component instead of leaking a third-party icon name into a\n * product screen.\n */\nexport const semanticIconNames = [\n \"add\",\n \"ai\",\n \"alert\",\n \"arrowDown\",\n \"arrowUp\",\n \"back\",\n \"calendar\",\n \"check\",\n \"chevronDown\",\n \"chevronEnd\",\n \"chevronStart\",\n \"chevronUp\",\n \"close\",\n \"compare\",\n \"copy\",\n \"delete\",\n \"download\",\n \"edit\",\n \"error\",\n \"favorite\",\n \"filter\",\n \"forward\",\n \"help\",\n \"home\",\n \"info\",\n \"lock\",\n \"menu\",\n \"more\",\n \"notifications\",\n \"pause\",\n \"play\",\n \"refresh\",\n \"rotate\",\n \"search\",\n \"settings\",\n \"share\",\n \"success\",\n \"trendDown\",\n \"trendFlat\",\n \"trendUp\",\n \"unblock\",\n \"upload\",\n \"user\",\n \"users\",\n \"visibility\",\n \"visibilityOff\",\n \"warning\",\n] as const;\n\nexport type SemanticIconName = (typeof semanticIconNames)[number];\n\n/**\n * Geometry of every semantic mark on one 24-unit stroke grid (round caps/joins, no fill). It lived privately in the\n * Web renderer, so Native products redrew the same marks in their own adapters (utilverse UiGlyph arrowUp/arrowDown/\n * rotate, 2026-10-18). As shared appearance data it belongs here: Web draws it, Native draws it through the optional\n * `@hjmds/react-native/icon-svg` adapter, and products without react-native-svg can still read the same path.\n */\nexport const semanticIconPaths = {\n add: \"M12 5v14M5 12h14\",\n ai: \"M12 2l1.2 4.1L17 8l-3.8 1.9L12 14l-1.2-4.1L7 8l3.8-1.9L12 2ZM19 14l.7 2.3L22 17.5l-2.3 1.2L19 21l-.7-2.3-2.3-1.2 2.3-1.2L19 14Z\",\n alert: \"M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01\",\n // Reorder pair: a shaft with the head on the travel end. Fixed in RTL because up/down is physical.\n arrowDown: \"M12 5v14m-6-6 6 6 6-6\",\n arrowUp: \"M12 19V5m-6 6 6-6 6 6\",\n back: \"M15 18 9 12l6-6M9 12h10\",\n calendar: \"M5 4h14a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Zm2-2v4m10-4v4M3 9h18\",\n check: \"m5 12 4 4L19 6\",\n chevronDown: \"m6 9 6 6 6-6\",\n chevronEnd: \"m9 6 6 6-6 6\",\n chevronStart: \"m15 6-6 6 6 6\",\n chevronUp: \"m6 15 6-6 6 6\",\n close: \"M6 6l12 12M18 6 6 18\",\n compare: \"M8 7h11m0 0-3-3m3 3-3 3M16 17H5m0 0 3-3m-3 3 3 3\",\n copy: \"M8 8h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2V8Zm8 0V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3\",\n delete: \"M4 7h16M9 7V4h6v3m3 0-1 14H7L6 7m4 4v6m4-6v6\",\n download: \"M12 3v12m0 0 5-5m-5 5-5-5M4 19v2h16v-2\",\n edit: \"m4 16-1 5 5-1L19 9l-4-4L4 16Zm9-9 4 4\",\n error: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-14v5m0 3h.01\",\n favorite: \"M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8L12 21l8.8-8.6a5.5 5.5 0 0 0 0-7.8Z\",\n filter: \"M3 5h18l-7 8v6l-4 2v-8L3 5Z\",\n forward: \"m9 6 6 6-6 6m6-6H5\",\n help: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-3-13a3 3 0 1 1 4.7 2.5c-1 .7-1.7 1.2-1.7 2.5m0 3h.01\",\n home: \"m3 11 9-8 9 8v10h-6v-6H9v6H3V11Z\",\n info: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-11v6m0-10h.01\",\n lock: \"M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 6 0v3\",\n menu: \"M4 6h16M4 12h16M4 18h16\",\n more: \"M5 12h.01M12 12h.01M19 12h.01\",\n notifications: \"M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Zm-8 12h4\",\n pause: \"M8 5v14m8-14v14\",\n play: \"m8 5 11 7-11 7V5Z\",\n refresh: \"M20 7v5h-5M4 17v-5h5m10.5-3A8 8 0 0 0 6 6l-2 2m.5 7A8 8 0 0 0 18 18l2-2\",\n // Clockwise quarter-turn (the arc runs clockwise into the corner at the upper end), matching the +90deg step image\n // and page tools apply. Fixed in RTL: rotation direction is physical, not reading order.\n rotate: \"M20 12a8 8 0 1 1-2.3-5.6L20 9m0-5v5h-5\",\n search: \"m21 21-4.4-4.4M19 11a8 8 0 1 1-16 0 8 8 0 0 1 16 0Z\",\n settings: \"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Zm7.4-3.5 2-1.5-2-3.5-2.4 1a8 8 0 0 0-2-1.2L14.7 4h-4l-.4 2.8A8 8 0 0 0 8 8L5.6 7l-2 3.5 2 1.5a8 8 0 0 0 0 2l-2 1.5 2 3.5L8 18a8 8 0 0 0 2.3 1.2l.4 2.8h4l.3-2.8A8 8 0 0 0 17 18l2.4 1 2-3.5-2-1.5a8 8 0 0 0 0-2Z\",\n // Keep all three nodes and their stroke inside the 24-unit viewport; the former lower node ended at y=24 and clipped.\n share: \"M18 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm12 7a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM8.6 13.5l6.8 4M15.4 6.5l-6.8 4\",\n success: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-5-10 3 3 7-7\",\n trendDown: \"M3 7l7 7 4-4 7 7m0 0v-6m0 6h-6\",\n trendFlat: \"M4 12h16m0 0-4-4m4 4-4 4\",\n trendUp: \"M3 17l7-7 4 4 7-7m0 0v6m0-6h-6\",\n // Release a block (blocked account, locked item): the `lock` body with its shackle swung open, so it reads as the\n // undo of `lock` in the same family instead of a new pictogram.\n unblock: \"M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 5.8-1.1\",\n upload: \"M12 21V9m0 0-5 5m5-5 5 5M4 5V3h16v2\",\n user: \"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-8 9a8 8 0 0 1 16 0\",\n users: \"M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-7 10a7 7 0 0 1 14 0m1-16a4 4 0 0 1 0 7m0 3a6 6 0 0 1 5 6\",\n visibility: \"M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12Zm10 3a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\",\n visibilityOff: \"m3 3 18 18M10.6 5.2A9 9 0 0 1 12 5c6 0 10 7 10 7a17 17 0 0 1-2.1 3M6.6 6.6C3.8 8.5 2 12 2 12s4 7 10 7a9 9 0 0 0 3.4-.7M9.9 9.9a3 3 0 0 0 4.2 4.2\",\n warning: \"M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01\",\n} as const satisfies Record<SemanticIconName, string>;\n\nconst semanticIconNameSet = new Set<string>(semanticIconNames);\n\n/** Narrows a product glyph name to the shared set, so adapters can draw HJM marks and fall back to their own. */\nexport function isSemanticIconName(name: string): name is SemanticIconName {\n return semanticIconNameSet.has(name);\n}\nexport type IconDirection = DesignSystemDirection;\nexport type IconDirectionality = \"fixed\" | \"mirror-in-rtl\";\nexport type IconTransform = \"none\" | \"mirror-inline\";\n\nconst logicalIconNames = new Set<string>([\n \"back\",\n \"chevronEnd\",\n \"chevronStart\",\n \"forward\",\n]);\n\ntype IconAppearance = Readonly<{\n size?: GlyphSize;\n weight?: IconWeight;\n directionality?: IconDirectionality;\n}>;\n\nexport type DecorativeIconDescriptor<Name extends string = SemanticIconName> =\n IconAppearance &\n Readonly<{\n name: Name;\n tone?: IconTone;\n decorative?: true;\n accessibilityLabel?: never;\n }>;\n\nexport type InformativeIconDescriptor<Name extends string = SemanticIconName> =\n IconAppearance &\n Readonly<{\n name: Name;\n /** Decorative is intentionally excluded because informative marks need contrast. */\n tone?: Exclude<IconTone, \"decorative\">;\n decorative: false;\n accessibilityLabel: string;\n }>;\n\nexport type IconDescriptor<Name extends string = SemanticIconName> =\n | DecorativeIconDescriptor<Name>\n | InformativeIconDescriptor<Name>;\n\nexport type ResolvedIconDescriptor<Name extends string = SemanticIconName> =\n | (Required<Omit<DecorativeIconDescriptor<Name>, \"accessibilityLabel\">> &\n Readonly<{ accessibilityLabel?: never }>)\n | Required<InformativeIconDescriptor<Name>>;\n\nexport function getIconDirectionality(name: string): IconDirectionality {\n return logicalIconNames.has(name) ? \"mirror-in-rtl\" : \"fixed\";\n}\n\nexport function getIconTransform(\n directionality: IconDirectionality,\n direction: IconDirection,\n): IconTransform {\n if (directionality !== \"fixed\" && directionality !== \"mirror-in-rtl\") {\n throw new TypeError(`Unsupported Icon directionality: ${String(directionality)}`);\n }\n if (direction !== \"ltr\" && direction !== \"rtl\") {\n throw new TypeError(`Unsupported Icon direction: ${String(direction)}`);\n }\n return directionality === \"mirror-in-rtl\" && direction === \"rtl\"\n ? \"mirror-inline\"\n : \"none\";\n}\n\nconst sizes = new Set<GlyphSize>([\"xs\", \"sm\", \"md\", \"lg\", \"xl\", \"xxl\", \"xxxl\"]);\nconst tones = new Set<IconTone>([\n \"primary\",\n \"secondary\",\n \"decorative\",\n \"brand\",\n \"info\",\n \"success\",\n \"warning\",\n \"danger\",\n \"inverse\",\n]);\nconst weights = new Set<IconWeight>([\"regular\", \"strong\"]);\n\nexport function validateIconDescriptor<Name extends string>(\n descriptor: IconDescriptor<Name>,\n): void {\n const runtimeName = (descriptor as Readonly<{ name?: unknown }>).name;\n const runtimeTone = (descriptor as Readonly<{ tone?: unknown }>).tone;\n const runtimeDecorative = (\n descriptor as Readonly<{ decorative?: unknown }>\n ).decorative;\n const runtimeLabel = (\n descriptor as Readonly<{ accessibilityLabel?: unknown }>\n ).accessibilityLabel;\n if (typeof runtimeName !== \"string\" || runtimeName.trim().length === 0) {\n throw new TypeError(\"Icon name must not be empty\");\n }\n if (runtimeName !== runtimeName.trim()) {\n throw new TypeError(\"Icon name must not start or end with whitespace\");\n }\n if (descriptor.size !== undefined && !sizes.has(descriptor.size)) {\n throw new TypeError(`Unsupported Icon size: ${String(descriptor.size)}`);\n }\n if (runtimeTone !== undefined && !tones.has(runtimeTone as IconTone)) {\n throw new TypeError(`Unsupported Icon tone: ${String(runtimeTone)}`);\n }\n if (descriptor.weight !== undefined && !weights.has(descriptor.weight)) {\n throw new TypeError(`Unsupported Icon weight: ${String(descriptor.weight)}`);\n }\n if (\n descriptor.directionality !== undefined &&\n descriptor.directionality !== \"fixed\" &&\n descriptor.directionality !== \"mirror-in-rtl\"\n ) {\n throw new TypeError(\n `Unsupported Icon directionality: ${String(descriptor.directionality)}`,\n );\n }\n if (\n runtimeDecorative !== undefined &&\n runtimeDecorative !== true &&\n runtimeDecorative !== false\n ) {\n throw new TypeError(\"Icon decorative must be a boolean when provided\");\n }\n if (runtimeDecorative === false) {\n if (typeof runtimeLabel !== \"string\" || runtimeLabel.trim().length === 0) {\n throw new TypeError(\"Informative Icon accessibilityLabel must not be empty\");\n }\n if (runtimeTone === \"decorative\") {\n throw new TypeError(\"Informative Icon cannot use the decorative tone\");\n }\n } else if (runtimeLabel !== undefined) {\n throw new TypeError(\"Decorative Icon must not provide accessibilityLabel\");\n }\n}\n\nexport function resolveIconDescriptor<Name extends string>(\n descriptor: IconDescriptor<Name>,\n): ResolvedIconDescriptor<Name> {\n validateIconDescriptor(descriptor);\n const common = {\n name: descriptor.name,\n size: descriptor.size ?? \"md\",\n tone: descriptor.tone ?? \"secondary\",\n weight: descriptor.weight ?? \"regular\",\n directionality:\n descriptor.directionality ?? getIconDirectionality(descriptor.name),\n } as const;\n if (descriptor.decorative === false) {\n return {\n ...common,\n decorative: false,\n accessibilityLabel: descriptor.accessibilityLabel,\n } as ResolvedIconDescriptor<Name>;\n }\n return {\n ...common,\n decorative: true,\n } as ResolvedIconDescriptor<Name>;\n}\n"]}
1
+ {"version":3,"file":"icon.js","sourceRoot":"","sources":["../src/icon.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GlyphSize } from \"./foundations.js\";\nimport type { IconTone, IconWeight } from \"./component-recipes.js\";\nimport type { DesignSystemDirection } from \"./design-system-provider.js\";\n\n/**\n * Shared semantic names. Renderers map these roles to their tree-shakeable SVG\n * or native glyph component instead of leaking a third-party icon name into a\n * product screen.\n */\nexport const semanticIconNames = [\n \"add\",\n \"ai\",\n \"alert\",\n \"arrowDown\",\n \"arrowUp\",\n \"back\",\n \"calendar\",\n \"check\",\n \"chevronDown\",\n \"chevronEnd\",\n \"chevronStart\",\n \"chevronUp\",\n \"close\",\n \"compare\",\n \"copy\",\n \"delete\",\n \"download\",\n \"edit\",\n \"error\",\n \"favorite\",\n \"filter\",\n \"forward\",\n \"help\",\n \"home\",\n \"info\",\n \"lock\",\n \"menu\",\n \"more\",\n \"moreVertical\",\n \"notifications\",\n \"pause\",\n \"play\",\n \"refresh\",\n \"rotate\",\n \"search\",\n \"settings\",\n \"share\",\n \"success\",\n \"trendDown\",\n \"trendFlat\",\n \"trendUp\",\n \"unblock\",\n \"upload\",\n \"user\",\n \"users\",\n \"visibility\",\n \"visibilityOff\",\n \"warning\",\n] as const;\n\nexport type SemanticIconName = (typeof semanticIconNames)[number];\n\n/**\n * Geometry of every semantic mark on one 24-unit stroke grid (round caps/joins, no fill). It lived privately in the\n * Web renderer, so Native products redrew the same marks in their own adapters (utilverse UiGlyph arrowUp/arrowDown/\n * rotate, 2026-10-18). As shared appearance data it belongs here: Web draws it, Native draws it through the optional\n * `@hjmds/react-native/icon-svg` adapter, and products without react-native-svg can still read the same path.\n */\nexport const semanticIconPaths = {\n add: \"M12 5v14M5 12h14\",\n ai: \"M12 2l1.2 4.1L17 8l-3.8 1.9L12 14l-1.2-4.1L7 8l3.8-1.9L12 2ZM19 14l.7 2.3L22 17.5l-2.3 1.2L19 21l-.7-2.3-2.3-1.2 2.3-1.2L19 14Z\",\n alert: \"M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01\",\n // Reorder pair: a shaft with the head on the travel end. Fixed in RTL because up/down is physical.\n arrowDown: \"M12 5v14m-6-6 6 6 6-6\",\n arrowUp: \"M12 19V5m-6 6 6-6 6 6\",\n back: \"M15 18 9 12l6-6M9 12h10\",\n calendar: \"M5 4h14a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Zm2-2v4m10-4v4M3 9h18\",\n check: \"m5 12 4 4L19 6\",\n chevronDown: \"m6 9 6 6 6-6\",\n chevronEnd: \"m9 6 6 6-6 6\",\n chevronStart: \"m15 6-6 6 6 6\",\n chevronUp: \"m6 15 6-6 6 6\",\n close: \"M6 6l12 12M18 6 6 18\",\n compare: \"M8 7h11m0 0-3-3m3 3-3 3M16 17H5m0 0 3-3m-3 3 3 3\",\n copy: \"M8 8h11a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H10a2 2 0 0 1-2-2V8Zm8 0V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h3\",\n delete: \"M4 7h16M9 7V4h6v3m3 0-1 14H7L6 7m4 4v6m4-6v6\",\n download: \"M12 3v12m0 0 5-5m-5 5-5-5M4 19v2h16v-2\",\n edit: \"m4 16-1 5 5-1L19 9l-4-4L4 16Zm9-9 4 4\",\n error: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-14v5m0 3h.01\",\n favorite: \"M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8L12 21l8.8-8.6a5.5 5.5 0 0 0 0-7.8Z\",\n filter: \"M3 5h18l-7 8v6l-4 2v-8L3 5Z\",\n forward: \"m9 6 6 6-6 6m6-6H5\",\n help: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-3-13a3 3 0 1 1 4.7 2.5c-1 .7-1.7 1.2-1.7 2.5m0 3h.01\",\n home: \"m3 11 9-8 9 8v10h-6v-6H9v6H3V11Z\",\n info: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm0-11v6m0-10h.01\",\n lock: \"M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 6 0v3\",\n menu: \"M4 6h16M4 12h16M4 18h16\",\n more: \"M5 12h.01M12 12h.01M19 12h.01\",\n moreVertical: \"M12 5h.01M12 12h.01M12 19h.01\",\n notifications: \"M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9Zm-8 12h4\",\n pause: \"M8 5v14m8-14v14\",\n play: \"m8 5 11 7-11 7V5Z\",\n refresh: \"M20 7v5h-5M4 17v-5h5m10.5-3A8 8 0 0 0 6 6l-2 2m.5 7A8 8 0 0 0 18 18l2-2\",\n // Clockwise quarter-turn (the arc runs clockwise into the corner at the upper end), matching the +90deg step image\n // and page tools apply. Fixed in RTL: rotation direction is physical, not reading order.\n rotate: \"M20 12a8 8 0 1 1-2.3-5.6L20 9m0-5v5h-5\",\n search: \"m21 21-4.4-4.4M19 11a8 8 0 1 1-16 0 8 8 0 0 1 16 0Z\",\n settings: \"M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Zm7.4-3.5 2-1.5-2-3.5-2.4 1a8 8 0 0 0-2-1.2L14.7 4h-4l-.4 2.8A8 8 0 0 0 8 8L5.6 7l-2 3.5 2 1.5a8 8 0 0 0 0 2l-2 1.5 2 3.5L8 18a8 8 0 0 0 2.3 1.2l.4 2.8h4l.3-2.8A8 8 0 0 0 17 18l2.4 1 2-3.5-2-1.5a8 8 0 0 0 0-2Z\",\n // Keep all three nodes and their stroke inside the 24-unit viewport; the former lower node ended at y=24 and clipped.\n share: \"M18 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM6 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm12 7a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM8.6 13.5l6.8 4M15.4 6.5l-6.8 4\",\n success: \"M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20Zm-5-10 3 3 7-7\",\n trendDown: \"M3 7l7 7 4-4 7 7m0 0v-6m0 6h-6\",\n trendFlat: \"M4 12h16m0 0-4-4m4 4-4 4\",\n trendUp: \"M3 17l7-7 4 4 7-7m0 0v6m0-6h-6\",\n // Release a block (blocked account, locked item): the `lock` body with its shackle swung open, so it reads as the\n // undo of `lock` in the same family instead of a new pictogram.\n unblock: \"M6 10h12v11H6V10Zm3 0V7a3 3 0 0 1 5.8-1.1\",\n upload: \"M12 21V9m0 0-5 5m5-5 5 5M4 5V3h16v2\",\n user: \"M12 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-8 9a8 8 0 0 1 16 0\",\n users: \"M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-7 10a7 7 0 0 1 14 0m1-16a4 4 0 0 1 0 7m0 3a6 6 0 0 1 5 6\",\n visibility: \"M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12Zm10 3a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\",\n visibilityOff: \"m3 3 18 18M10.6 5.2A9 9 0 0 1 12 5c6 0 10 7 10 7a17 17 0 0 1-2.1 3M6.6 6.6C3.8 8.5 2 12 2 12s4 7 10 7a9 9 0 0 0 3.4-.7M9.9 9.9a3 3 0 0 0 4.2 4.2\",\n warning: \"M12 3 2.7 20h18.6L12 3Zm0 6v4m0 3h.01\",\n} as const satisfies Record<SemanticIconName, string>;\n\nconst semanticIconNameSet = new Set<string>(semanticIconNames);\n\n/** Narrows a product glyph name to the shared set, so adapters can draw HJM marks and fall back to their own. */\nexport function isSemanticIconName(name: string): name is SemanticIconName {\n return semanticIconNameSet.has(name);\n}\nexport type IconDirection = DesignSystemDirection;\nexport type IconDirectionality = \"fixed\" | \"mirror-in-rtl\";\nexport type IconTransform = \"none\" | \"mirror-inline\";\n\nconst logicalIconNames = new Set<string>([\n \"back\",\n \"chevronEnd\",\n \"chevronStart\",\n \"forward\",\n]);\n\ntype IconAppearance = Readonly<{\n size?: GlyphSize;\n weight?: IconWeight;\n directionality?: IconDirectionality;\n}>;\n\nexport type DecorativeIconDescriptor<Name extends string = SemanticIconName> =\n IconAppearance &\n Readonly<{\n name: Name;\n tone?: IconTone;\n decorative?: true;\n accessibilityLabel?: never;\n }>;\n\nexport type InformativeIconDescriptor<Name extends string = SemanticIconName> =\n IconAppearance &\n Readonly<{\n name: Name;\n /** Decorative is intentionally excluded because informative marks need contrast. */\n tone?: Exclude<IconTone, \"decorative\">;\n decorative: false;\n accessibilityLabel: string;\n }>;\n\nexport type IconDescriptor<Name extends string = SemanticIconName> =\n | DecorativeIconDescriptor<Name>\n | InformativeIconDescriptor<Name>;\n\nexport type ResolvedIconDescriptor<Name extends string = SemanticIconName> =\n | (Required<Omit<DecorativeIconDescriptor<Name>, \"accessibilityLabel\">> &\n Readonly<{ accessibilityLabel?: never }>)\n | Required<InformativeIconDescriptor<Name>>;\n\nexport function getIconDirectionality(name: string): IconDirectionality {\n return logicalIconNames.has(name) ? \"mirror-in-rtl\" : \"fixed\";\n}\n\nexport function getIconTransform(\n directionality: IconDirectionality,\n direction: IconDirection,\n): IconTransform {\n if (directionality !== \"fixed\" && directionality !== \"mirror-in-rtl\") {\n throw new TypeError(`Unsupported Icon directionality: ${String(directionality)}`);\n }\n if (direction !== \"ltr\" && direction !== \"rtl\") {\n throw new TypeError(`Unsupported Icon direction: ${String(direction)}`);\n }\n return directionality === \"mirror-in-rtl\" && direction === \"rtl\"\n ? \"mirror-inline\"\n : \"none\";\n}\n\nconst sizes = new Set<GlyphSize>([\"xs\", \"sm\", \"md\", \"lg\", \"xl\", \"xxl\", \"xxxl\"]);\nconst tones = new Set<IconTone>([\n \"primary\",\n \"secondary\",\n \"decorative\",\n \"brand\",\n \"info\",\n \"success\",\n \"warning\",\n \"danger\",\n \"inverse\",\n]);\nconst weights = new Set<IconWeight>([\"regular\", \"strong\"]);\n\nexport function validateIconDescriptor<Name extends string>(\n descriptor: IconDescriptor<Name>,\n): void {\n const runtimeName = (descriptor as Readonly<{ name?: unknown }>).name;\n const runtimeTone = (descriptor as Readonly<{ tone?: unknown }>).tone;\n const runtimeDecorative = (\n descriptor as Readonly<{ decorative?: unknown }>\n ).decorative;\n const runtimeLabel = (\n descriptor as Readonly<{ accessibilityLabel?: unknown }>\n ).accessibilityLabel;\n if (typeof runtimeName !== \"string\" || runtimeName.trim().length === 0) {\n throw new TypeError(\"Icon name must not be empty\");\n }\n if (runtimeName !== runtimeName.trim()) {\n throw new TypeError(\"Icon name must not start or end with whitespace\");\n }\n if (descriptor.size !== undefined && !sizes.has(descriptor.size)) {\n throw new TypeError(`Unsupported Icon size: ${String(descriptor.size)}`);\n }\n if (runtimeTone !== undefined && !tones.has(runtimeTone as IconTone)) {\n throw new TypeError(`Unsupported Icon tone: ${String(runtimeTone)}`);\n }\n if (descriptor.weight !== undefined && !weights.has(descriptor.weight)) {\n throw new TypeError(`Unsupported Icon weight: ${String(descriptor.weight)}`);\n }\n if (\n descriptor.directionality !== undefined &&\n descriptor.directionality !== \"fixed\" &&\n descriptor.directionality !== \"mirror-in-rtl\"\n ) {\n throw new TypeError(\n `Unsupported Icon directionality: ${String(descriptor.directionality)}`,\n );\n }\n if (\n runtimeDecorative !== undefined &&\n runtimeDecorative !== true &&\n runtimeDecorative !== false\n ) {\n throw new TypeError(\"Icon decorative must be a boolean when provided\");\n }\n if (runtimeDecorative === false) {\n if (typeof runtimeLabel !== \"string\" || runtimeLabel.trim().length === 0) {\n throw new TypeError(\"Informative Icon accessibilityLabel must not be empty\");\n }\n if (runtimeTone === \"decorative\") {\n throw new TypeError(\"Informative Icon cannot use the decorative tone\");\n }\n } else if (runtimeLabel !== undefined) {\n throw new TypeError(\"Decorative Icon must not provide accessibilityLabel\");\n }\n}\n\nexport function resolveIconDescriptor<Name extends string>(\n descriptor: IconDescriptor<Name>,\n): ResolvedIconDescriptor<Name> {\n validateIconDescriptor(descriptor);\n const common = {\n name: descriptor.name,\n size: descriptor.size ?? \"md\",\n tone: descriptor.tone ?? \"secondary\",\n weight: descriptor.weight ?? \"regular\",\n directionality:\n descriptor.directionality ?? getIconDirectionality(descriptor.name),\n } as const;\n if (descriptor.decorative === false) {\n return {\n ...common,\n decorative: false,\n accessibilityLabel: descriptor.accessibilityLabel,\n } as ResolvedIconDescriptor<Name>;\n }\n return {\n ...common,\n decorative: true,\n } as ResolvedIconDescriptor<Name>;\n}\n"]}
package/dist/recipes.d.ts CHANGED
@@ -5,6 +5,7 @@ export { aspectRatioRecipe } from "./aspect-ratio.js";
5
5
  export { containerRecipe } from "./container.js";
6
6
  export { cardRecipe, type CardHeadingLevel } from "./card.js";
7
7
  export { calendarRecipe } from "./calendar.js";
8
+ export { dateRangeRecipe } from "./date-range.js";
8
9
  export { carouselRecipe } from "./carousel.js";
9
10
  export { commandPaletteRecipe } from "./command-palette.js";
10
11
  export { dataTableRecipe } from "./data-table.js";
@@ -1 +1 @@
1
- {"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../src/recipes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../src/recipes.ts"],"names":[],"mappings":"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"}