mtrl 0.2.1 → 0.2.3

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 (98) hide show
  1. package/.typedocignore +11 -0
  2. package/DOCS.md +153 -0
  3. package/index.ts +18 -3
  4. package/package.json +7 -2
  5. package/src/components/badge/_styles.scss +174 -0
  6. package/src/components/badge/api.ts +292 -0
  7. package/src/components/badge/badge.ts +52 -0
  8. package/src/components/badge/config.ts +68 -0
  9. package/src/components/badge/constants.ts +30 -0
  10. package/src/components/badge/features.ts +185 -0
  11. package/src/components/badge/index.ts +4 -0
  12. package/src/components/badge/types.ts +105 -0
  13. package/src/components/button/types.ts +174 -29
  14. package/src/components/card/constants.ts +14 -0
  15. package/src/components/carousel/_styles.scss +645 -0
  16. package/src/components/carousel/api.ts +147 -0
  17. package/src/components/carousel/carousel.ts +178 -0
  18. package/src/components/carousel/config.ts +91 -0
  19. package/src/components/carousel/constants.ts +95 -0
  20. package/src/components/carousel/features/drag.ts +388 -0
  21. package/src/components/carousel/features/index.ts +8 -0
  22. package/src/components/carousel/features/slides.ts +682 -0
  23. package/src/components/carousel/index.ts +38 -0
  24. package/src/components/carousel/types.ts +327 -0
  25. package/src/components/chip/_styles.scss +83 -140
  26. package/src/components/chip/api.ts +231 -102
  27. package/src/components/chip/chip.ts +356 -44
  28. package/src/components/chip/constants.ts +3 -3
  29. package/src/components/chip/index.ts +3 -3
  30. package/src/components/dialog/_styles.scss +213 -0
  31. package/src/components/dialog/api.ts +283 -0
  32. package/src/components/dialog/config.ts +113 -0
  33. package/src/components/dialog/constants.ts +32 -0
  34. package/src/components/dialog/dialog.ts +56 -0
  35. package/src/components/dialog/features.ts +713 -0
  36. package/src/components/dialog/index.ts +15 -0
  37. package/src/components/dialog/types.ts +221 -0
  38. package/src/components/progress/_styles.scss +13 -1
  39. package/src/components/progress/api.ts +2 -2
  40. package/src/components/progress/progress.ts +2 -2
  41. package/src/components/progress/types.ts +3 -0
  42. package/src/components/radios/_styles.scss +232 -0
  43. package/src/components/radios/api.ts +100 -0
  44. package/src/components/radios/config.ts +60 -0
  45. package/src/components/radios/constants.ts +28 -0
  46. package/src/components/radios/index.ts +4 -0
  47. package/src/components/radios/radio.ts +269 -0
  48. package/src/components/radios/radios.ts +42 -0
  49. package/src/components/radios/types.ts +232 -0
  50. package/src/components/sheet/_styles.scss +236 -0
  51. package/src/components/sheet/api.ts +96 -0
  52. package/src/components/sheet/config.ts +66 -0
  53. package/src/components/sheet/constants.ts +20 -0
  54. package/src/components/sheet/features/content.ts +51 -0
  55. package/src/components/sheet/features/gestures.ts +177 -0
  56. package/src/components/sheet/features/index.ts +6 -0
  57. package/src/components/sheet/features/position.ts +42 -0
  58. package/src/components/sheet/features/state.ts +116 -0
  59. package/src/components/sheet/features/title.ts +86 -0
  60. package/src/components/sheet/index.ts +4 -0
  61. package/src/components/sheet/sheet.ts +57 -0
  62. package/src/components/sheet/types.ts +266 -0
  63. package/src/components/slider/_styles.scss +518 -0
  64. package/src/components/slider/api.ts +336 -0
  65. package/src/components/slider/config.ts +145 -0
  66. package/src/components/slider/constants.ts +28 -0
  67. package/src/components/slider/features/appearance.ts +140 -0
  68. package/src/components/slider/features/disabled.ts +43 -0
  69. package/src/components/slider/features/events.ts +164 -0
  70. package/src/components/slider/features/index.ts +5 -0
  71. package/src/components/slider/features/interactions.ts +256 -0
  72. package/src/components/slider/features/keyboard.ts +114 -0
  73. package/src/components/slider/features/slider.ts +336 -0
  74. package/src/components/slider/features/structure.ts +264 -0
  75. package/src/components/slider/features/ui.ts +518 -0
  76. package/src/components/slider/index.ts +9 -0
  77. package/src/components/slider/slider.ts +58 -0
  78. package/src/components/slider/types.ts +166 -0
  79. package/src/components/tabs/_styles.scss +224 -0
  80. package/src/components/tabs/api.ts +443 -0
  81. package/src/components/tabs/config.ts +80 -0
  82. package/src/components/tabs/constants.ts +12 -0
  83. package/src/components/tabs/index.ts +4 -0
  84. package/src/components/tabs/tabs.ts +52 -0
  85. package/src/components/tabs/types.ts +247 -0
  86. package/src/components/textfield/_styles.scss +97 -4
  87. package/src/components/tooltip/_styles.scss +241 -0
  88. package/src/components/tooltip/api.ts +411 -0
  89. package/src/components/tooltip/config.ts +78 -0
  90. package/src/components/tooltip/constants.ts +27 -0
  91. package/src/components/tooltip/index.ts +4 -0
  92. package/src/components/tooltip/tooltip.ts +60 -0
  93. package/src/components/tooltip/types.ts +178 -0
  94. package/src/index.ts +9 -1
  95. package/src/styles/abstract/_variables.scss +24 -0
  96. package/tsconfig.json +22 -0
  97. package/typedoc.json +28 -0
  98. package/typedoc.simple.json +14 -0
@@ -1,6 +1,7 @@
1
- // src/components/chip/chip.ts
2
- import { pipe } from '../../core/compose';
3
- import { createBase, withElement } from '../../core/compose/component';
1
+ // src/components/chip/chip.js
2
+ import { PREFIX } from '../../core/config'
3
+ import { pipe } from '../../core/compose'
4
+ import { createBase, withElement } from '../../core/compose/component'
4
5
  import {
5
6
  withEvents,
6
7
  withText,
@@ -10,72 +11,383 @@ import {
10
11
  withRipple,
11
12
  withDisabled,
12
13
  withLifecycle
13
- } from '../../core/compose/features';
14
- import { withAPI } from './api';
15
- import { ChipConfig, ChipComponent, BaseComponent } from './types';
16
- import { createBaseConfig, getElementConfig, getApiConfig } from './config';
14
+ } from '../../core/compose/features'
15
+ import { withAPI } from './api'
16
+ import { CHIP_VARIANTS, CHIP_SIZES } from './constants'
17
17
 
18
18
  /**
19
19
  * Creates a new Chip component
20
- * @param {ChipConfig} config - Chip configuration object
21
- * @returns {ChipComponent} Chip component instance
20
+ * @param {Object} config - Chip configuration
21
+ * @param {string} [config.variant='filled'] - Chip variant
22
+ * @param {string} [config.size='medium'] - Chip size
23
+ * @param {boolean} [config.selected=false] - Whether the chip is initially selected
24
+ * @param {boolean} [config.disabled=false] - Whether the chip is initially disabled
25
+ * @param {string} [config.text] - Chip text content
26
+ * @param {string} [config.leadingIcon] - Leading icon HTML content
27
+ * @param {string} [config.trailingIcon] - Trailing icon HTML content
28
+ * @param {string} [config.class] - Additional CSS classes
29
+ * @param {string} [config.value] - Chip value
30
+ * @param {boolean} [config.ripple=true] - Whether to enable ripple effect
31
+ * @param {Function} [config.onTrailingIconClick] - Callback when trailing icon is clicked
32
+ * @param {Function} [config.onSelect] - Callback when chip is selected
33
+ * @param {Function} [config.onChange] - Callback when chip selection changes
34
+ * @returns {Object} Chip component instance
22
35
  */
23
- const createChip = (config: ChipConfig = {}): ChipComponent => {
24
- const baseConfig = createBaseConfig(config);
36
+ const createChip = (config = {}) => {
37
+ const baseConfig = {
38
+ ...config,
39
+ variant: config.variant || CHIP_VARIANTS.FILLED,
40
+ size: config.size || CHIP_SIZES.MEDIUM,
41
+ componentName: 'chip',
42
+ prefix: PREFIX,
43
+ ripple: config.ripple !== false
44
+ }
25
45
 
26
46
  try {
47
+ // Create base component with core features
27
48
  const chip = pipe(
28
49
  createBase,
29
50
  withEvents(),
30
- withElement(getElementConfig(baseConfig)),
31
- withVariant(baseConfig),
32
- withSize(baseConfig),
33
- withText(baseConfig),
34
- withIcon({
35
- ...baseConfig,
36
- position: 'start',
37
- iconContent: config.leadingIcon || config.icon
51
+ withElement({
52
+ tag: 'div',
53
+ componentName: 'chip',
54
+ attrs: {
55
+ role: 'button',
56
+ tabindex: '0',
57
+ 'aria-disabled': config.disabled ? 'true' : 'false',
58
+ 'aria-selected': config.selected ? 'true' : 'false',
59
+ 'data-value': config.value || ''
60
+ },
61
+ className: config.class,
62
+ forwardEvents: {
63
+ click: (component) => component.element.getAttribute('aria-disabled') !== 'true',
64
+ focus: true,
65
+ blur: true
66
+ }
38
67
  }),
39
- withDisabled(baseConfig),
40
- withRipple(baseConfig),
41
- withLifecycle(),
42
- comp => withAPI(getApiConfig(comp))(comp)
43
- )(baseConfig);
68
+ withLifecycle()
69
+ )(baseConfig)
70
+
71
+ // Track selected state
72
+ let isSelectedState = !!config.selected;
73
+
74
+ // Manually add the variant class
75
+ if (config.variant) {
76
+ chip.element.classList.add(`${chip.getClass('chip')}--${config.variant}`)
77
+ }
78
+
79
+ // Manually add the size class
80
+ if (config.size) {
81
+ chip.element.classList.add(`${chip.getClass('chip')}--${config.size}`)
82
+ }
83
+
84
+ // Add ripple if enabled
85
+ if (config.ripple) {
86
+ withRipple(baseConfig)(chip)
87
+ }
88
+
89
+ // Add disabled state if needed
90
+ if (config.disabled) {
91
+ withDisabled(baseConfig)(chip)
92
+ }
93
+
94
+ // Add selected class if needed
95
+ if (config.selected) {
96
+ chip.element.classList.add(`${chip.getClass('chip')}--selected`)
97
+ }
98
+
99
+ // Create a container for the chip content to ensure proper ordering
100
+ const contentContainer = document.createElement('div')
101
+ contentContainer.className = `${chip.getClass('chip')}-content`
102
+ contentContainer.style.display = 'flex'
103
+ contentContainer.style.alignItems = 'center'
104
+ contentContainer.style.justifyContent = 'center'
105
+ contentContainer.style.width = '100%'
106
+ chip.element.appendChild(contentContainer)
107
+
108
+ // Add leading icon if provided
109
+ if (config.leadingIcon) {
110
+ const leadingIconElement = document.createElement('span')
111
+ leadingIconElement.className = `${chip.getClass('chip')}-leading-icon`
112
+ leadingIconElement.innerHTML = config.leadingIcon
113
+ contentContainer.appendChild(leadingIconElement)
114
+ }
115
+
116
+ // Add text element if provided
117
+ if (config.text) {
118
+ const textElement = document.createElement('span')
119
+ textElement.className = `${chip.getClass('chip')}-text`
120
+ textElement.textContent = config.text
121
+ contentContainer.appendChild(textElement)
122
+ }
44
123
 
45
124
  // Add trailing icon if provided
46
125
  if (config.trailingIcon) {
47
- const trailingIconElement = document.createElement('span');
48
- trailingIconElement.className = `${baseConfig.prefix}-chip-trailing-icon`;
49
- trailingIconElement.innerHTML = config.trailingIcon;
50
- chip.element.appendChild(trailingIconElement);
51
-
52
- // Add event listener for remove/close action if needed
126
+ const trailingIconElement = document.createElement('span')
127
+ trailingIconElement.className = `${chip.getClass('chip')}-trailing-icon`
128
+ trailingIconElement.innerHTML = config.trailingIcon
129
+
130
+ // Add click handler for trailing icon
53
131
  if (config.onTrailingIconClick) {
54
132
  trailingIconElement.addEventListener('click', (e) => {
55
- e.stopPropagation();
56
- config.onTrailingIconClick!(chip as ChipComponent);
57
- });
133
+ e.stopPropagation() // Prevent chip click event
134
+ config.onTrailingIconClick(enhancedChip)
135
+ })
58
136
  }
137
+
138
+ contentContainer.appendChild(trailingIconElement)
59
139
  }
60
140
 
61
- // Initialize selected state if needed
62
- if (config.selected) {
63
- (chip as ChipComponent).setSelected(true);
64
- }
141
+ // Create enhanced component with API
142
+ const enhancedChip = {
143
+ ...chip,
144
+
145
+ /**
146
+ * Checks if the chip is disabled
147
+ * @returns {boolean} True if the chip is disabled
148
+ */
149
+ isDisabled() {
150
+ return chip.element.getAttribute('aria-disabled') === 'true';
151
+ },
152
+
153
+ /**
154
+ * Checks if the chip is selected
155
+ * @returns {boolean} True if the chip is selected
156
+ */
157
+ isSelected() {
158
+ return isSelectedState;
159
+ },
160
+
161
+ /**
162
+ * Sets the chip's selected state
163
+ * @param {boolean} selected - Whether the chip should be selected
164
+ * @returns {Object} The chip instance for chaining
165
+ */
166
+ setSelected(selected) {
167
+ isSelectedState = !!selected;
168
+
169
+ if (selected) {
170
+ chip.element.classList.add(`${chip.getClass('chip')}--selected`);
171
+ chip.element.setAttribute('aria-selected', 'true');
172
+ } else {
173
+ chip.element.classList.remove(`${chip.getClass('chip')}--selected`);
174
+ chip.element.setAttribute('aria-selected', 'false');
175
+ }
176
+
177
+ return this;
178
+ },
179
+
180
+ /**
181
+ * Toggles the chip's selected state
182
+ * @returns {Object} The chip instance for chaining
183
+ */
184
+ toggleSelected() {
185
+ return this.setSelected(!isSelectedState);
186
+ },
187
+
188
+ /**
189
+ * Gets the chip's value
190
+ * @returns {string} The chip's value
191
+ */
192
+ getValue() {
193
+ return chip.element.getAttribute('data-value');
194
+ },
195
+
196
+ /**
197
+ * Sets the chip's value
198
+ * @param {string} value - Value to set
199
+ * @returns {Object} The chip instance for chaining
200
+ */
201
+ setValue(value) {
202
+ chip.element.setAttribute('data-value', value);
203
+ return this;
204
+ },
205
+
206
+ /**
207
+ * Enables the chip
208
+ * @returns {Object} The chip instance for chaining
209
+ */
210
+ enable() {
211
+ chip.element.classList.remove(`${chip.getClass('chip')}--disabled`);
212
+ chip.element.setAttribute('aria-disabled', 'false');
213
+ chip.element.setAttribute('tabindex', '0');
214
+ return this;
215
+ },
216
+
217
+ /**
218
+ * Disables the chip
219
+ * @returns {Object} The chip instance for chaining
220
+ */
221
+ disable() {
222
+ chip.element.classList.add(`${chip.getClass('chip')}--disabled`);
223
+ chip.element.setAttribute('aria-disabled', 'true');
224
+ chip.element.setAttribute('tabindex', '-1');
225
+ return this;
226
+ },
227
+
228
+ /**
229
+ * Sets the chip's text content
230
+ * @param {string} content - Text content
231
+ * @returns {Object} The chip instance for chaining
232
+ */
233
+ setText(content) {
234
+ const textElement = chip.element.querySelector(`.${chip.getClass('chip')}-text`);
235
+
236
+ if (textElement) {
237
+ textElement.textContent = content;
238
+ } else if (content) {
239
+ const newTextElement = document.createElement('span');
240
+ newTextElement.className = `${chip.getClass('chip')}-text`;
241
+ newTextElement.textContent = content;
242
+ contentContainer.appendChild(newTextElement);
243
+ }
244
+
245
+ return this;
246
+ },
247
+
248
+ /**
249
+ * Gets the chip's text content
250
+ * @returns {string} The chip's text content
251
+ */
252
+ getText() {
253
+ const textElement = chip.element.querySelector(`.${chip.getClass('chip')}-text`);
254
+ return textElement ? textElement.textContent : '';
255
+ },
256
+
257
+ /**
258
+ * Sets the chip's icon
259
+ * @param {string} icon - Icon HTML content
260
+ * @returns {Object} The chip instance for chaining
261
+ */
262
+ setIcon(icon) {
263
+ return this.setLeadingIcon(icon);
264
+ },
265
+
266
+ /**
267
+ * Gets the chip's icon
268
+ * @returns {string} The chip's icon HTML
269
+ */
270
+ getIcon() {
271
+ const iconElement = chip.element.querySelector(`.${chip.getClass('chip')}-leading-icon`);
272
+ return iconElement ? iconElement.innerHTML : '';
273
+ },
274
+
275
+ /**
276
+ * Sets the chip's leading icon
277
+ * @param {string} icon - Icon HTML content
278
+ * @returns {Object} The chip instance for chaining
279
+ */
280
+ setLeadingIcon(icon) {
281
+ const leadingIconSelector = `.${chip.getClass('chip')}-leading-icon`;
282
+ let leadingIconElement = chip.element.querySelector(leadingIconSelector);
283
+
284
+ if (!leadingIconElement && icon) {
285
+ leadingIconElement = document.createElement('span');
286
+ leadingIconElement.className = `${chip.getClass('chip')}-leading-icon`;
287
+
288
+ // Insert at the beginning of the content container
289
+ contentContainer.insertBefore(leadingIconElement, contentContainer.firstChild);
290
+ }
291
+
292
+ if (leadingIconElement) {
293
+ leadingIconElement.innerHTML = icon || '';
294
+
295
+ // Remove the element if icon is empty
296
+ if (!icon && leadingIconElement.parentNode) {
297
+ leadingIconElement.parentNode.removeChild(leadingIconElement);
298
+ }
299
+ }
300
+
301
+ return this;
302
+ },
303
+
304
+ /**
305
+ * Sets the chip's trailing icon
306
+ * @param {string} icon - Icon HTML content
307
+ * @param {Function} [onClick] - Click handler for the trailing icon
308
+ * @returns {Object} The chip instance for chaining
309
+ */
310
+ setTrailingIcon(icon, onClick) {
311
+ const trailingIconSelector = `.${chip.getClass('chip')}-trailing-icon`;
312
+ let trailingIconElement = chip.element.querySelector(trailingIconSelector);
313
+
314
+ if (!trailingIconElement && icon) {
315
+ trailingIconElement = document.createElement('span');
316
+ trailingIconElement.className = `${chip.getClass('chip')}-trailing-icon`;
317
+
318
+ // Add at the end of the content container
319
+ contentContainer.appendChild(trailingIconElement);
320
+
321
+ // Add click handler if provided
322
+ if (onClick) {
323
+ trailingIconElement.addEventListener('click', (e) => {
324
+ e.stopPropagation(); // Prevent chip click event
325
+ onClick(this);
326
+ });
327
+ }
328
+ }
329
+
330
+ if (trailingIconElement) {
331
+ trailingIconElement.innerHTML = icon || '';
332
+
333
+ // Remove the element if icon is empty
334
+ if (!icon && trailingIconElement.parentNode) {
335
+ trailingIconElement.parentNode.removeChild(trailingIconElement);
336
+ }
337
+ }
338
+
339
+ return this;
340
+ },
341
+
342
+ /**
343
+ * Destroys the chip component and cleans up resources
344
+ */
345
+ destroy() {
346
+ chip.lifecycle && chip.lifecycle.destroy && chip.lifecycle.destroy();
347
+ chip.element.remove();
348
+ },
349
+
350
+ // Forward event methods from the original chip
351
+ on: chip.on,
352
+ off: chip.off,
353
+
354
+ /**
355
+ * Add CSS classes to the chip element
356
+ * @param {...string} classes - CSS classes to add
357
+ * @returns {Object} The chip instance for chaining
358
+ */
359
+ addClass(...classes) {
360
+ chip.element.classList.add(...classes);
361
+ return this;
362
+ }
363
+ };
65
364
 
66
- // Handle selection callback
67
- if (config.onSelect) {
365
+ // Add click handler for selection toggle
366
+ if (config.variant === CHIP_VARIANTS.FILTER ||
367
+ config.variant === CHIP_VARIANTS.ASSIST ||
368
+ config.selectable) {
369
+
68
370
  chip.element.addEventListener('click', () => {
69
- if (chip.element.getAttribute('aria-disabled') !== 'true') {
70
- config.onSelect!(chip as ChipComponent);
371
+ if (enhancedChip.isDisabled()) return;
372
+
373
+ enhancedChip.toggleSelected();
374
+
375
+ // Call onChange callback if provided
376
+ if (config.onChange) {
377
+ config.onChange(enhancedChip);
378
+ }
379
+
380
+ // Call onSelect callback if provided
381
+ if (config.onSelect) {
382
+ config.onSelect(enhancedChip);
71
383
  }
72
384
  });
73
385
  }
74
386
 
75
- return chip as ChipComponent;
387
+ return enhancedChip;
76
388
  } catch (error) {
77
- console.error('Chip creation error:', error instanceof Error ? error.message : String(error));
78
- throw new Error(`Failed to create chip: ${error instanceof Error ? error.message : String(error)}`);
389
+ console.error('Chip creation error:', error);
390
+ throw new Error(`Failed to create chip: ${error.message}`);
79
391
  }
80
392
  };
81
393
 
@@ -1,4 +1,4 @@
1
- // src/components/chip/constants.ts
1
+ // src/components/chip/constants.js
2
2
 
3
3
  /**
4
4
  * Available variants for the Chip component
@@ -25,7 +25,7 @@ export const CHIP_VARIANTS = {
25
25
 
26
26
  /** Suggestion chip for presenting options */
27
27
  SUGGESTION: 'suggestion'
28
- } as const;
28
+ };
29
29
 
30
30
  /**
31
31
  * Available sizes for the Chip component
@@ -35,4 +35,4 @@ export const CHIP_SIZES = {
35
35
  SMALL: 'small',
36
36
  MEDIUM: 'medium',
37
37
  LARGE: 'large'
38
- } as const;
38
+ };
@@ -1,4 +1,4 @@
1
- // src/components/chip/index.ts
1
+ // src/components/chip/index.js
2
2
  export { default } from './chip'
3
- export { CHIP_VARIANTS, CHIP_SIZES } from './constants'
4
- export { ChipConfig, ChipComponent } from './types'
3
+ export { default as createChipSet } from './chip-set'
4
+ export { CHIP_VARIANTS, CHIP_SIZES } from './constants'
@@ -0,0 +1,213 @@
1
+ // src/components/dialog/_styles.scss
2
+ @use '../../styles/abstract/base' as base;
3
+ @use '../../styles/abstract/variables' as v;
4
+ @use '../../styles/abstract/functions' as f;
5
+ @use '../../styles/abstract/mixins' as m;
6
+ @use '../../styles/abstract/theme' as t;
7
+
8
+ $component: '#{base.$prefix}-dialog';
9
+
10
+ // Dialog overlay - covers the entire screen
11
+ .#{$component}-overlay {
12
+ position: fixed;
13
+ top: 0;
14
+ left: 0;
15
+ right: 0;
16
+ bottom: 0;
17
+ background-color: t.alpha('scrim', 0.32);
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ z-index: 1000;
22
+ padding: 24px;
23
+ opacity: 0;
24
+ visibility: hidden;
25
+ transition: opacity 0.15s ease, visibility 0s linear 0.15s;
26
+ overflow-y: auto;
27
+
28
+ &--visible {
29
+ opacity: 1;
30
+ visibility: visible;
31
+ transition: opacity 0.15s ease, visibility 0s linear;
32
+ }
33
+ }
34
+
35
+ // Dialog container
36
+ .#{$component} {
37
+ 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
+ background-color: t.color('surface-container-high');
46
+ color: t.color('on-surface');
47
+ overflow: hidden;
48
+ box-sizing: border-box;
49
+ @include m.elevation(3);
50
+ transform: scale(0.8);
51
+ opacity: 0;
52
+ transition: transform 0.15s ease, opacity 0.15s ease;
53
+
54
+ &--visible {
55
+ transform: scale(1);
56
+ opacity: 1;
57
+ }
58
+
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;
67
+ }
68
+
69
+ // Fullwidth variant
70
+ &--fullwidth {
71
+ width: 100%;
72
+ max-width: 560px;
73
+ }
74
+
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
+ }
85
+
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;
93
+ }
94
+
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;
102
+ }
103
+
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
+ }
128
+ }
129
+ }
130
+
131
+ // Dialog content
132
+ &-content {
133
+ flex: 1 1 auto;
134
+ padding: 0 24px;
135
+ overflow-y: auto;
136
+ -webkit-overflow-scrolling: touch;
137
+ @include m.typography('body-medium');
138
+ 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
+ }
148
+
149
+ // Dialog footer
150
+ &-footer {
151
+ display: flex;
152
+ flex-wrap: wrap;
153
+ align-items: center;
154
+ justify-content: flex-end;
155
+ padding: 16px 24px 24px;
156
+ gap: 8px;
157
+
158
+ &--left {
159
+ justify-content: flex-start;
160
+ }
161
+
162
+ &--center {
163
+ justify-content: center;
164
+ }
165
+
166
+ &--space-between {
167
+ justify-content: space-between;
168
+ }
169
+
170
+ button {
171
+ margin: 0;
172
+ }
173
+ }
174
+
175
+ // Size variants
176
+ &--small {
177
+ max-width: 400px;
178
+ }
179
+
180
+ &--medium {
181
+ max-width: 560px;
182
+ }
183
+
184
+ &--large {
185
+ max-width: 90vw;
186
+ width: 800px;
187
+ }
188
+
189
+ // Animation variants
190
+ &--slide-up {
191
+ transform: translateY(20px) scale(1);
192
+
193
+ &.#{$component}--visible {
194
+ transform: translateY(0) scale(1);
195
+ }
196
+ }
197
+
198
+ &--slide-down {
199
+ transform: translateY(-20px) scale(1);
200
+
201
+ &.#{$component}--visible {
202
+ transform: translateY(0) scale(1);
203
+ }
204
+ }
205
+
206
+ &--fade {
207
+ transform: scale(1);
208
+
209
+ &.#{$component}--visible {
210
+ transform: scale(1);
211
+ }
212
+ }
213
+ }