mtrl 0.2.6 → 0.2.7

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 (147) hide show
  1. package/index.ts +18 -0
  2. package/package.json +1 -1
  3. package/src/components/badge/_styles.scss +117 -109
  4. package/src/components/badge/api.ts +57 -59
  5. package/src/components/badge/badge.ts +16 -2
  6. package/src/components/badge/config.ts +65 -11
  7. package/src/components/badge/constants.ts +22 -12
  8. package/src/components/badge/features.ts +44 -40
  9. package/src/components/badge/types.ts +42 -30
  10. package/src/components/bottom-app-bar/_styles.scss +103 -0
  11. package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
  12. package/src/components/bottom-app-bar/config.ts +73 -0
  13. package/src/components/bottom-app-bar/index.ts +11 -0
  14. package/src/components/bottom-app-bar/types.ts +108 -0
  15. package/src/components/button/_styles.scss +0 -10
  16. package/src/components/button/api.ts +5 -0
  17. package/src/components/button/config.ts +5 -0
  18. package/src/components/button/types.ts +6 -0
  19. package/src/components/card/card.ts +13 -25
  20. package/src/components/card/config.ts +67 -22
  21. package/src/components/card/features.ts +3 -0
  22. package/src/components/card/types.ts +28 -0
  23. package/src/components/checkbox/_styles.scss +0 -2
  24. package/src/components/datepicker/_styles.scss +358 -0
  25. package/src/components/datepicker/api.ts +272 -0
  26. package/src/components/datepicker/config.ts +144 -0
  27. package/src/components/datepicker/constants.ts +98 -0
  28. package/src/components/datepicker/datepicker.ts +346 -0
  29. package/src/components/datepicker/index.ts +9 -0
  30. package/src/components/datepicker/render.ts +452 -0
  31. package/src/components/datepicker/types.ts +268 -0
  32. package/src/components/datepicker/utils.ts +290 -0
  33. package/src/components/dialog/_styles.scss +174 -128
  34. package/src/components/dialog/api.ts +48 -13
  35. package/src/components/dialog/config.ts +9 -5
  36. package/src/components/dialog/dialog.ts +6 -3
  37. package/src/components/dialog/features.ts +290 -130
  38. package/src/components/dialog/types.ts +7 -4
  39. package/src/components/divider/_styles.scss +57 -0
  40. package/src/components/divider/config.ts +81 -0
  41. package/src/components/divider/divider.ts +37 -0
  42. package/src/components/divider/features.ts +207 -0
  43. package/src/components/divider/index.ts +5 -0
  44. package/src/components/divider/types.ts +55 -0
  45. package/src/components/extended-fab/_styles.scss +267 -0
  46. package/src/components/extended-fab/api.ts +141 -0
  47. package/src/components/extended-fab/config.ts +108 -0
  48. package/src/components/extended-fab/constants.ts +36 -0
  49. package/src/components/extended-fab/extended-fab.ts +125 -0
  50. package/src/components/extended-fab/index.ts +4 -0
  51. package/src/components/extended-fab/types.ts +287 -0
  52. package/src/components/fab/_styles.scss +225 -0
  53. package/src/components/fab/api.ts +97 -0
  54. package/src/components/fab/config.ts +94 -0
  55. package/src/components/fab/constants.ts +41 -0
  56. package/src/components/fab/fab.ts +67 -0
  57. package/src/components/fab/index.ts +4 -0
  58. package/src/components/fab/types.ts +234 -0
  59. package/src/components/navigation/_styles.scss +1 -0
  60. package/src/components/navigation/api.ts +78 -50
  61. package/src/components/navigation/features/items.ts +280 -0
  62. package/src/components/navigation/nav-item.ts +72 -23
  63. package/src/components/navigation/navigation.ts +54 -2
  64. package/src/components/navigation/types.ts +210 -188
  65. package/src/components/search/_styles.scss +306 -0
  66. package/src/components/search/api.ts +203 -0
  67. package/src/components/search/config.ts +87 -0
  68. package/src/components/search/constants.ts +21 -0
  69. package/src/components/search/features/index.ts +4 -0
  70. package/src/components/search/features/search.ts +718 -0
  71. package/src/components/search/features/states.ts +165 -0
  72. package/src/components/search/features/structure.ts +198 -0
  73. package/src/components/search/index.ts +10 -0
  74. package/src/components/search/search.ts +52 -0
  75. package/src/components/search/types.ts +163 -0
  76. package/src/components/segmented-button/_styles.scss +117 -0
  77. package/src/components/segmented-button/config.ts +67 -0
  78. package/src/components/segmented-button/constants.ts +42 -0
  79. package/src/components/segmented-button/index.ts +4 -0
  80. package/src/components/segmented-button/segment.ts +155 -0
  81. package/src/components/segmented-button/segmented-button.ts +250 -0
  82. package/src/components/segmented-button/types.ts +219 -0
  83. package/src/components/slider/_styles.scss +83 -24
  84. package/src/components/slider/accessibility.md +5 -5
  85. package/src/components/slider/api.ts +41 -120
  86. package/src/components/slider/config.ts +51 -47
  87. package/src/components/slider/features/handlers.ts +495 -0
  88. package/src/components/slider/features/index.ts +1 -2
  89. package/src/components/slider/features/slider.ts +66 -84
  90. package/src/components/slider/features/states.ts +195 -0
  91. package/src/components/slider/features/structure.ts +136 -206
  92. package/src/components/slider/features/ui.ts +145 -206
  93. package/src/components/slider/index.ts +2 -11
  94. package/src/components/slider/slider.ts +9 -12
  95. package/src/components/slider/types.ts +39 -24
  96. package/src/components/switch/_styles.scss +0 -2
  97. package/src/components/tabs/_styles.scss +94 -32
  98. package/src/components/tabs/features.ts +4 -2
  99. package/src/components/tabs/indicator.ts +73 -13
  100. package/src/components/tabs/types.ts +10 -2
  101. package/src/components/timepicker/README.md +277 -0
  102. package/src/components/timepicker/_styles.scss +451 -0
  103. package/src/components/timepicker/api.ts +632 -0
  104. package/src/components/timepicker/clockdial.ts +482 -0
  105. package/src/components/timepicker/config.ts +130 -0
  106. package/src/components/timepicker/constants.ts +138 -0
  107. package/src/components/timepicker/index.ts +8 -0
  108. package/src/components/timepicker/render.ts +613 -0
  109. package/src/components/timepicker/timepicker.ts +117 -0
  110. package/src/components/timepicker/types.ts +336 -0
  111. package/src/components/timepicker/utils.ts +241 -0
  112. package/src/components/top-app-bar/_styles.scss +225 -0
  113. package/src/components/top-app-bar/config.ts +83 -0
  114. package/src/components/top-app-bar/index.ts +11 -0
  115. package/src/components/top-app-bar/top-app-bar.ts +316 -0
  116. package/src/components/top-app-bar/types.ts +140 -0
  117. package/src/core/build/_ripple.scss +6 -6
  118. package/src/core/build/ripple.ts +72 -95
  119. package/src/core/compose/features/icon.ts +3 -1
  120. package/src/core/compose/features/ripple.ts +4 -1
  121. package/src/core/compose/features/textlabel.ts +26 -2
  122. package/src/core/dom/create.ts +5 -0
  123. package/src/index.ts +9 -0
  124. package/src/styles/abstract/_theme.scss +9 -1
  125. package/src/styles/themes/_autumn.scss +21 -0
  126. package/src/styles/themes/_base-theme.scss +61 -0
  127. package/src/styles/themes/_baseline.scss +58 -0
  128. package/src/styles/themes/_bluekhaki.scss +125 -0
  129. package/src/styles/themes/_brownbeige.scss +125 -0
  130. package/src/styles/themes/_browngreen.scss +125 -0
  131. package/src/styles/themes/_forest.scss +6 -0
  132. package/src/styles/themes/_greenbeige.scss +125 -0
  133. package/src/styles/themes/_material.scss +125 -0
  134. package/src/styles/themes/_ocean.scss +6 -0
  135. package/src/styles/themes/_sageivory.scss +125 -0
  136. package/src/styles/themes/_spring.scss +6 -0
  137. package/src/styles/themes/_summer.scss +5 -0
  138. package/src/styles/themes/_sunset.scss +5 -0
  139. package/src/styles/themes/_tealcaramel.scss +125 -0
  140. package/src/styles/themes/_winter.scss +6 -0
  141. package/src/components/navigation/features/items.js +0 -192
  142. package/src/components/slider/features/appearance.ts +0 -94
  143. package/src/components/slider/features/disabled.ts +0 -68
  144. package/src/components/slider/features/events.ts +0 -164
  145. package/src/components/slider/features/interactions.ts +0 -396
  146. package/src/components/slider/features/keyboard.ts +0 -233
  147. package/src/core/collection/adapters/mongodb.js +0 -232
@@ -0,0 +1,290 @@
1
+ // src/components/datepicker/utils.ts
2
+ import { CalendarDate } from './types';
3
+ import { MONTH_NAMES, MONTH_NAMES_SHORT } from './constants';
4
+
5
+ /**
6
+ * Parses a date from various input types
7
+ * @param date - Date string, Date object, or null
8
+ * @returns Valid Date object or null if invalid
9
+ */
10
+ export const parseDate = (date: Date | string | null): Date | null => {
11
+ if (!date) return null;
12
+
13
+ // Already a Date object
14
+ if (date instanceof Date) {
15
+ return isNaN(date.getTime()) ? null : date;
16
+ }
17
+
18
+ // String date
19
+ if (typeof date === 'string') {
20
+ // Try to parse the string
21
+ const parsedDate = new Date(date);
22
+ return isNaN(parsedDate.getTime()) ? null : parsedDate;
23
+ }
24
+
25
+ return null;
26
+ };
27
+
28
+ /**
29
+ * Formats a date according to the specified format using a parser-based approach
30
+ * This avoids string replacement issues by building the output string from scratch
31
+ *
32
+ * @param date - Date to format
33
+ * @param format - Format string (MM/DD/YYYY, etc.)
34
+ * @returns Formatted date string
35
+ */
36
+ export const formatDate = (date: Date | null, format: string = 'MM/DD/YYYY'): string => {
37
+ if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
38
+ return '';
39
+ }
40
+
41
+ let result = '';
42
+ let i = 0;
43
+
44
+ while (i < format.length) {
45
+ // Check for month name patterns
46
+ if (format.substring(i, i+4) === 'MMMM') {
47
+ // Full month name
48
+ result += MONTH_NAMES[date.getMonth()];
49
+ i += 4;
50
+ }
51
+ else if (format.substring(i, i+3) === 'MMM') {
52
+ // Abbreviated month name
53
+ result += MONTH_NAMES_SHORT[date.getMonth()];
54
+ i += 3;
55
+ }
56
+ else if (format.substring(i, i+2) === 'MM') {
57
+ // Two-digit month
58
+ result += (date.getMonth() + 1).toString().padStart(2, '0');
59
+ i += 2;
60
+ }
61
+ else if (format.substring(i, i+1) === 'M') {
62
+ // Single-digit month
63
+ result += (date.getMonth() + 1);
64
+ i += 1;
65
+ }
66
+ else if (format.substring(i, i+4) === 'YYYY') {
67
+ // 4-digit year
68
+ result += date.getFullYear();
69
+ i += 4;
70
+ }
71
+ else if (format.substring(i, i+2) === 'YY') {
72
+ // 2-digit year
73
+ result += date.getFullYear().toString().slice(-2);
74
+ i += 2;
75
+ }
76
+ else if (format.substring(i, i+2) === 'DD') {
77
+ // Two-digit day
78
+ result += date.getDate().toString().padStart(2, '0');
79
+ i += 2;
80
+ }
81
+ else if (format.substring(i, i+1) === 'D') {
82
+ // Single-digit day
83
+ result += date.getDate();
84
+ i += 1;
85
+ }
86
+ else {
87
+ // Any other character is copied as-is
88
+ result += format[i];
89
+ i += 1;
90
+ }
91
+ }
92
+
93
+ return result;
94
+ };
95
+
96
+ /**
97
+ * Gets the days in a month
98
+ * @param year - Year
99
+ * @param month - Month (0-11)
100
+ * @returns Number of days in the month
101
+ */
102
+ export const getDaysInMonth = (year: number, month: number): number => {
103
+ return new Date(year, month + 1, 0).getDate();
104
+ };
105
+
106
+ /**
107
+ * Gets the first day of the month
108
+ * @param year - Year
109
+ * @param month - Month (0-11)
110
+ * @returns Day of the week (0-6, where 0 is Sunday)
111
+ */
112
+ export const getFirstDayOfMonth = (year: number, month: number): number => {
113
+ return new Date(year, month, 1).getDay();
114
+ };
115
+
116
+ /**
117
+ * Checks if two dates are the same day
118
+ * @param date1 - First date
119
+ * @param date2 - Second date
120
+ * @returns True if same day, false otherwise
121
+ */
122
+ export const isSameDay = (date1: Date, date2: Date): boolean => {
123
+ return (
124
+ date1.getDate() === date2.getDate() &&
125
+ date1.getMonth() === date2.getMonth() &&
126
+ date1.getFullYear() === date2.getFullYear()
127
+ );
128
+ };
129
+
130
+ /**
131
+ * Checks if a date is between two other dates (inclusive)
132
+ * @param date - Date to check
133
+ * @param startDate - Start date
134
+ * @param endDate - End date
135
+ * @returns True if date is between start and end, false otherwise
136
+ */
137
+ export const isDateInRange = (date: Date, startDate: Date, endDate: Date): boolean => {
138
+ const timestamp = date.getTime();
139
+ return timestamp >= startDate.getTime() && timestamp <= endDate.getTime();
140
+ };
141
+
142
+ /**
143
+ * Generates calendar dates for a month
144
+ * @param year - Year
145
+ * @param month - Month (0-11)
146
+ * @param selectedDate - Currently selected date
147
+ * @param rangeEndDate - End date if range selection
148
+ * @param minDate - Minimum selectable date
149
+ * @param maxDate - Maximum selectable date
150
+ * @returns Array of calendar dates
151
+ */
152
+ export const generateCalendarDates = (
153
+ year: number,
154
+ month: number,
155
+ selectedDate: Date | null = null,
156
+ rangeEndDate: Date | null = null,
157
+ minDate: Date | null = null,
158
+ maxDate: Date | null = null
159
+ ): CalendarDate[] => {
160
+ const today = new Date();
161
+ today.setHours(0, 0, 0, 0);
162
+
163
+ const result: CalendarDate[] = [];
164
+
165
+ // Calculate days needed from previous month
166
+ const firstDay = getFirstDayOfMonth(year, month);
167
+ const daysInPrevMonth = getDaysInMonth(year, month - 1);
168
+
169
+ // Add days from previous month
170
+ for (let i = firstDay - 1; i >= 0; i--) {
171
+ const date = new Date(year, month - 1, daysInPrevMonth - i);
172
+ const isDisabled =
173
+ (minDate && date < minDate) ||
174
+ (maxDate && date > maxDate);
175
+
176
+ result.push({
177
+ date,
178
+ day: date.getDate(),
179
+ isCurrentMonth: false,
180
+ isToday: isSameDay(date, today),
181
+ isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
182
+ isDisabled
183
+ });
184
+ }
185
+
186
+ // Add days from current month
187
+ const daysInMonth = getDaysInMonth(year, month);
188
+ for (let i = 1; i <= daysInMonth; i++) {
189
+ const date = new Date(year, month, i);
190
+ const isSelected = selectedDate ? isSameDay(date, selectedDate) : false;
191
+ const isDisabled =
192
+ (minDate && date < minDate) ||
193
+ (maxDate && date > maxDate);
194
+
195
+ const calendarDate: CalendarDate = {
196
+ date,
197
+ day: i,
198
+ isCurrentMonth: true,
199
+ isToday: isSameDay(date, today),
200
+ isSelected,
201
+ isDisabled
202
+ };
203
+
204
+ // Handle range selection
205
+ if (selectedDate && rangeEndDate) {
206
+ calendarDate.isRangeStart = isSameDay(date, selectedDate);
207
+ calendarDate.isRangeEnd = isSameDay(date, rangeEndDate);
208
+ calendarDate.isRangeMiddle = isDateInRange(date, selectedDate, rangeEndDate) &&
209
+ !calendarDate.isRangeStart && !calendarDate.isRangeEnd;
210
+ }
211
+
212
+ result.push(calendarDate);
213
+ }
214
+
215
+ // Add days from next month to complete the calendar grid (6 rows × 7 columns)
216
+ const totalDaysNeeded = 42; // 6 rows × 7 columns
217
+ const remainingDays = totalDaysNeeded - result.length;
218
+
219
+ for (let i = 1; i <= remainingDays; i++) {
220
+ const date = new Date(year, month + 1, i);
221
+ const isDisabled =
222
+ (minDate && date < minDate) ||
223
+ (maxDate && date > maxDate);
224
+
225
+ result.push({
226
+ date,
227
+ day: i,
228
+ isCurrentMonth: false,
229
+ isToday: isSameDay(date, today),
230
+ isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
231
+ isDisabled
232
+ });
233
+ }
234
+
235
+ return result;
236
+ };
237
+
238
+ /**
239
+ * Generates an array of years for year selection
240
+ * @param currentYear - Center year for the range
241
+ * @param range - Number of years before and after current year
242
+ * @returns Array of years
243
+ */
244
+ export const generateYearRange = (currentYear: number, range: number = 10): number[] => {
245
+ const years: number[] = [];
246
+ const startYear = currentYear - range;
247
+ const endYear = currentYear + range;
248
+
249
+ for (let year = startYear; year <= endYear; year++) {
250
+ years.push(year);
251
+ }
252
+
253
+ return years;
254
+ };
255
+
256
+ /**
257
+ * Adds days to a date
258
+ * @param date - Base date
259
+ * @param days - Number of days to add
260
+ * @returns New date with days added
261
+ */
262
+ export const addDays = (date: Date, days: number): Date => {
263
+ const result = new Date(date);
264
+ result.setDate(result.getDate() + days);
265
+ return result;
266
+ };
267
+
268
+ /**
269
+ * Adds months to a date
270
+ * @param date - Base date
271
+ * @param months - Number of months to add
272
+ * @returns New date with months added
273
+ */
274
+ export const addMonths = (date: Date, months: number): Date => {
275
+ const result = new Date(date);
276
+ result.setMonth(result.getMonth() + months);
277
+ return result;
278
+ };
279
+
280
+ /**
281
+ * Adds years to a date
282
+ * @param date - Base date
283
+ * @param years - Number of years to add
284
+ * @returns New date with years added
285
+ */
286
+ export const addYears = (date: Date, years: number): Date => {
287
+ const result = new Date(date);
288
+ result.setFullYear(result.getFullYear() + years);
289
+ return result;
290
+ };
@@ -1,4 +1,4 @@
1
- // src/components/dialog/_styles.scss
1
+ // src/components/dialog/_dialog.scss
2
2
  @use '../../styles/abstract/base' as base;
3
3
  @use '../../styles/abstract/variables' as v;
4
4
  @use '../../styles/abstract/functions' as f;
@@ -7,207 +7,253 @@
7
7
 
8
8
  $component: '#{base.$prefix}-dialog';
9
9
 
10
- // Dialog overlay - covers the entire screen
10
+ // Dialog overlay (background scrim)
11
11
  .#{$component}-overlay {
12
12
  position: fixed;
13
13
  top: 0;
14
14
  left: 0;
15
15
  right: 0;
16
16
  bottom: 0;
17
- background-color: t.alpha('scrim', 0.32);
17
+ background-color: t.alpha('scrim', 0.48);
18
+ opacity: 0;
19
+ z-index: v.z-index('modal');
18
20
  display: flex;
19
21
  align-items: center;
20
22
  justify-content: center;
21
- z-index: 1000;
23
+ overflow: auto;
22
24
  padding: 24px;
23
- opacity: 0;
24
- visibility: hidden;
25
- transition: opacity 0.15s ease, visibility 0s linear 0.15s;
26
- overflow-y: auto;
25
+ box-sizing: border-box;
26
+ // Use proper SCSS function calls for transition values
27
+ $duration: v.motion('duration-short4');
28
+ $easing: v.motion('easing-standard');
29
+ transition: opacity #{$duration} #{$easing},
30
+ visibility #{$duration} #{$easing};
27
31
 
28
32
  &--visible {
29
33
  opacity: 1;
30
34
  visibility: visible;
31
- transition: opacity 0.15s ease, visibility 0s linear;
32
35
  }
33
36
  }
34
37
 
35
38
  // Dialog container
36
39
  .#{$component} {
37
40
  position: relative;
38
- display: flex;
39
- flex-direction: column;
40
- min-width: 280px;
41
- max-width: 90vw;
42
- width: fit-content;
43
- max-height: calc(100vh - 48px);
44
- border-radius: 28px;
45
41
  background-color: t.color('surface-container-high');
46
42
  color: t.color('on-surface');
47
- overflow: hidden;
48
- box-sizing: border-box;
49
- @include m.elevation(3);
50
- transform: scale(0.8);
43
+ border-radius: v.shape('extra-large'); // 28dp corner radius
44
+ max-width: 560px;
45
+ min-width: 280px;
46
+ width: 100%;
47
+ margin: auto;
51
48
  opacity: 0;
52
- transition: transform 0.15s ease, opacity 0.15s ease;
49
+ transform: scale(0.8);
50
+ $duration: v.motion('duration-short4');
51
+ $easing: v.motion('easing-standard');
52
+ transition: transform #{$duration} #{$easing},
53
+ opacity #{$duration} #{$easing};
54
+ @include m.elevation(3);
53
55
 
54
56
  &--visible {
55
- transform: scale(1);
56
57
  opacity: 1;
58
+ transform: scale(1);
57
59
  }
58
60
 
59
- // Fullscreen variant
60
- &--fullscreen {
61
- width: 100vw;
62
- height: 100vh;
63
- max-width: 100vw;
64
- max-height: 100vh;
65
- border-radius: 0;
66
- margin: 0;
61
+ // Size variants
62
+ &--small {
63
+ width: 80%;
64
+ max-width: 360px;
65
+ }
66
+
67
+ &--medium {
68
+ width: 90%;
69
+ max-width: 560px;
70
+ }
71
+
72
+ &--large {
73
+ width: 95%;
74
+ max-width: 800px;
67
75
  }
68
76
 
69
- // Fullwidth variant
70
77
  &--fullwidth {
71
78
  width: 100%;
72
- max-width: 560px;
79
+ max-width: none;
80
+ margin: 24px;
73
81
  }
74
82
 
75
- // Dialog header
76
- &-header {
77
- display: flex;
78
- align-items: flex-start;
79
- padding: 24px 24px 16px;
80
-
81
- &-content {
82
- flex: 1;
83
- min-width: 0;
84
- }
83
+ &--fullscreen {
84
+ width: 100%;
85
+ height: 100%;
86
+ max-width: none;
87
+ max-height: none;
88
+ margin: 0;
89
+ border-radius: 0;
90
+ }
91
+
92
+ // Animation variants
93
+ &--slide-up {
94
+ transform: translateY(50px);
85
95
 
86
- &-title {
87
- @include m.typography('headline-small');
88
- color: t.color('on-surface');
89
- margin: 0;
90
- overflow: hidden;
91
- text-overflow: ellipsis;
92
- white-space: nowrap;
96
+ &.#{$component}--visible {
97
+ transform: translateY(0);
93
98
  }
99
+ }
100
+
101
+ &--slide-down {
102
+ transform: translateY(-50px);
94
103
 
95
- &-subtitle {
96
- @include m.typography('body-medium');
97
- color: t.color('on-surface-variant');
98
- margin: 4px 0 0;
99
- overflow: hidden;
100
- text-overflow: ellipsis;
101
- white-space: nowrap;
104
+ &.#{$component}--visible {
105
+ transform: translateY(0);
102
106
  }
107
+ }
108
+
109
+ &--fade {
110
+ transform: scale(1);
103
111
 
104
- &-close {
105
- margin: -8px -8px -8px 8px;
106
- padding: 8px;
107
- border: none;
108
- background: transparent;
109
- cursor: pointer;
110
- display: flex;
111
- align-items: center;
112
- justify-content: center;
113
- border-radius: 50%;
114
- color: t.color('on-surface-variant');
115
-
116
- &:hover {
117
- background-color: t.alpha('on-surface', 0.08);
118
- }
119
-
120
- &:active {
121
- background-color: t.alpha('on-surface', 0.12);
122
- }
123
-
124
- svg {
125
- width: 24px;
126
- height: 24px;
127
- }
112
+ &.#{$component}--visible {
113
+ transform: scale(1);
128
114
  }
129
115
  }
116
+ }
117
+
118
+ // Dialog header
119
+ .#{$component}-header {
120
+ display: flex;
121
+ align-items: flex-start;
122
+ justify-content: space-between;
123
+ padding: 24px 24px 16px 24px;
130
124
 
131
- // Dialog content
132
125
  &-content {
133
- flex: 1 1 auto;
134
- padding: 0 24px;
135
- overflow-y: auto;
136
- -webkit-overflow-scrolling: touch;
126
+ flex: 1;
127
+ }
128
+
129
+ &-title {
130
+ margin: 0;
131
+ font-size: 24px;
132
+ line-height: 32px;
133
+ font-weight: 400;
134
+ color: t.color('on-surface');
135
+ @include m.typography('headline-small');
136
+ }
137
+
138
+ &-subtitle {
139
+ margin: 4px 0 0 0;
137
140
  @include m.typography('body-medium');
138
141
  color: t.color('on-surface-variant');
139
-
140
- &:first-child {
141
- padding-top: 24px;
142
- }
143
-
144
- &:last-child {
145
- padding-bottom: 24px;
146
- }
147
142
  }
148
143
 
149
- // Dialog footer
150
- &-footer {
144
+ &-close {
151
145
  display: flex;
152
- flex-wrap: wrap;
153
146
  align-items: center;
154
- justify-content: flex-end;
155
- padding: 16px 24px 24px;
156
- gap: 8px;
147
+ justify-content: center;
148
+ width: 40px;
149
+ height: 40px;
150
+ margin: -8px -8px 0 0;
151
+ padding: 8px;
152
+ background: transparent;
153
+ border: none;
154
+ border-radius: 50%;
155
+ cursor: pointer;
156
+ color: t.color('on-surface-variant');
157
157
 
158
- &--left {
159
- justify-content: flex-start;
158
+ &:hover {
159
+ background-color: t.alpha('on-surface', 0.08);
160
160
  }
161
161
 
162
- &--center {
163
- justify-content: center;
162
+ &:focus {
163
+ outline: none;
164
+ background-color: t.alpha('on-surface', 0.12);
164
165
  }
165
166
 
166
- &--space-between {
167
- justify-content: space-between;
167
+ svg {
168
+ width: 24px;
169
+ height: 24px;
168
170
  }
171
+ }
172
+ }
173
+
174
+ // Dialog content
175
+ .#{$component}-content {
176
+ padding: 16px 24px;
177
+ color: t.color('on-surface');
178
+ @include m.typography('body-medium');
179
+
180
+ p {
181
+ margin: 0 0 16px 0;
169
182
 
170
- button {
171
- margin: 0;
183
+ &:last-child {
184
+ margin-bottom: 0;
172
185
  }
173
186
  }
187
+ }
188
+
189
+ // Dialog footer
190
+ .#{$component}-footer {
191
+ display: flex;
192
+ align-items: center;
193
+ justify-content: flex-end;
194
+ padding: 24px;
195
+ gap: 8px;
174
196
 
175
- // Size variants
176
- &--small {
177
- max-width: 400px;
197
+ &--left {
198
+ justify-content: flex-start;
178
199
  }
179
200
 
180
- &--medium {
181
- max-width: 560px;
201
+ &--center {
202
+ justify-content: center;
182
203
  }
183
204
 
184
- &--large {
185
- max-width: 90vw;
186
- width: 800px;
205
+ &--space-between {
206
+ justify-content: space-between;
187
207
  }
188
-
189
- // Animation variants
190
- &--slide-up {
191
- transform: translateY(20px) scale(1);
208
+ }
209
+
210
+ // Dialog divider styling
211
+ .#{$component}-header-divider {
212
+ margin: 0;
213
+ }
214
+
215
+ .#{$component}-footer-divider {
216
+ margin: 0;
217
+ }
218
+
219
+ // Accessibility
220
+ @include m.reduced-motion {
221
+ .#{$component},
222
+ .#{$component}-overlay {
223
+ transition: none;
224
+ }
225
+ }
226
+
227
+ // Mobile responsiveness
228
+ @media (max-width: v.breakpoint('sm')) {
229
+ .#{$component} {
230
+ min-width: 280px;
231
+ width: calc(100% - 32px);
232
+ max-width: 100%;
233
+ margin: 16px;
192
234
 
193
- &.#{$component}--visible {
194
- transform: translateY(0) scale(1);
235
+ &--fullscreen {
236
+ width: 100%;
237
+ height: 100%;
238
+ margin: 0;
195
239
  }
196
240
  }
197
241
 
198
- &--slide-down {
199
- transform: translateY(-20px) scale(1);
242
+ .#{$component}-overlay {
243
+ padding: 16px;
244
+ align-items: flex-end;
200
245
 
201
- &.#{$component}--visible {
202
- transform: translateY(0) scale(1);
246
+ &.#{$component}--fullscreen {
247
+ padding: 0;
203
248
  }
204
249
  }
205
250
 
206
- &--fade {
207
- transform: scale(1);
251
+ // Adjust animations for mobile
252
+ .#{$component}--slide-up {
253
+ transform: translateY(100%);
208
254
 
209
255
  &.#{$component}--visible {
210
- transform: scale(1);
256
+ transform: translateY(0);
211
257
  }
212
258
  }
213
259
  }