@maggioli-design-system/mds-modal 5.2.1 → 5.4.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 (85) hide show
  1. package/dist/cjs/{index-7b5471f5.js → index-6f236cfa.js} +164 -69
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/mds-modal.cjs.entry.js +47 -7
  4. package/dist/cjs/mds-modal.cjs.js +3 -3
  5. package/dist/collection/collection-manifest.json +1 -1
  6. package/dist/collection/common/floating-controller.js +180 -0
  7. package/dist/collection/common/slot.js +19 -4
  8. package/dist/collection/common/string.js +30 -0
  9. package/dist/collection/components/mds-modal/mds-modal.css +124 -0
  10. package/dist/collection/components/mds-modal/mds-modal.js +77 -5
  11. package/dist/collection/components/mds-modal/meta/dictionary.js +5 -1
  12. package/dist/collection/components/mds-modal/test/mds-modal.stories.js +20 -2
  13. package/dist/collection/dictionary/keyboard.js +84 -0
  14. package/dist/collection/dictionary/tree.js +13 -0
  15. package/dist/collection/type/keyboard.js +1 -0
  16. package/dist/collection/type/tree.js +1 -0
  17. package/dist/components/mds-modal.js +48 -7
  18. package/dist/documentation.d.ts +8 -0
  19. package/dist/documentation.json +56 -5
  20. package/dist/esm/{index-1c34ac95.js → index-f8d2dee4.js} +164 -69
  21. package/dist/esm/loader.js +3 -3
  22. package/dist/esm/mds-modal.entry.js +47 -7
  23. package/dist/esm/mds-modal.js +4 -4
  24. package/dist/esm-es5/index-f8d2dee4.js +1 -0
  25. package/dist/esm-es5/loader.js +1 -1
  26. package/dist/esm-es5/mds-modal.entry.js +1 -1
  27. package/dist/esm-es5/mds-modal.js +1 -1
  28. package/dist/mds-modal/mds-modal.esm.js +1 -1
  29. package/dist/mds-modal/mds-modal.js +1 -1
  30. package/dist/mds-modal/p-2c91cf1f.entry.js +1 -0
  31. package/dist/mds-modal/p-69576bb4.system.entry.js +1 -0
  32. package/dist/mds-modal/p-bc1fa4e4.system.js +2 -0
  33. package/dist/mds-modal/{p-67c6f337.system.js → p-c6899cb0.system.js} +1 -1
  34. package/dist/mds-modal/p-ee90f86a.js +2 -0
  35. package/dist/stats.json +128 -38
  36. package/dist/types/common/floating-controller.d.ts +46 -0
  37. package/dist/types/common/slot.d.ts +3 -1
  38. package/dist/types/common/string.d.ts +4 -0
  39. package/dist/types/components/mds-modal/mds-modal.d.ts +8 -1
  40. package/dist/types/components/mds-modal/meta/dictionary.d.ts +2 -1
  41. package/dist/types/components/mds-modal/meta/types.d.ts +1 -0
  42. package/dist/types/components/mds-modal/test/mds-modal.stories.d.ts +11 -0
  43. package/dist/types/components.d.ts +10 -2
  44. package/dist/types/dictionary/keyboard.d.ts +2 -0
  45. package/dist/types/dictionary/tree.d.ts +4 -0
  46. package/dist/types/type/keyboard.d.ts +12 -0
  47. package/dist/types/type/tree.d.ts +3 -0
  48. package/documentation.json +96 -10
  49. package/package.json +4 -4
  50. package/readme.md +18 -16
  51. package/src/common/floating-controller.ts +263 -0
  52. package/src/common/slot.ts +23 -3
  53. package/src/common/string.ts +42 -0
  54. package/src/components/mds-modal/mds-modal.css +7 -1
  55. package/src/components/mds-modal/mds-modal.tsx +36 -1
  56. package/src/components/mds-modal/meta/dictionary.ts +6 -0
  57. package/src/components/mds-modal/meta/types.ts +4 -0
  58. package/src/components/mds-modal/readme.md +18 -16
  59. package/src/components/mds-modal/test/mds-modal.stories.tsx +57 -3
  60. package/src/components.d.ts +10 -2
  61. package/src/dictionary/keyboard.ts +87 -0
  62. package/src/dictionary/tree.ts +21 -0
  63. package/src/fixtures/icons.json +38 -1
  64. package/src/fixtures/iconsauce.json +6 -0
  65. package/src/meta/keyboard/keys.json +83 -0
  66. package/src/tailwind/components.css +11 -0
  67. package/src/tailwind/fouc.css +118 -0
  68. package/src/type/keyboard.ts +93 -0
  69. package/src/type/tree.ts +12 -0
  70. package/www/build/mds-modal.esm.js +1 -1
  71. package/www/build/mds-modal.js +1 -1
  72. package/www/build/p-2c91cf1f.entry.js +1 -0
  73. package/www/build/p-69576bb4.system.entry.js +1 -0
  74. package/www/build/p-bc1fa4e4.system.js +2 -0
  75. package/www/build/{p-67c6f337.system.js → p-c6899cb0.system.js} +1 -1
  76. package/www/build/p-ee90f86a.js +2 -0
  77. package/dist/esm-es5/index-1c34ac95.js +0 -1
  78. package/dist/mds-modal/p-08a99956.entry.js +0 -1
  79. package/dist/mds-modal/p-0d78ea55.system.entry.js +0 -1
  80. package/dist/mds-modal/p-0ed6e0c8.js +0 -2
  81. package/dist/mds-modal/p-423dac35.system.js +0 -2
  82. package/www/build/p-08a99956.entry.js +0 -1
  83. package/www/build/p-0d78ea55.system.entry.js +0 -1
  84. package/www/build/p-0ed6e0c8.js +0 -2
  85. package/www/build/p-423dac35.system.js +0 -2
@@ -0,0 +1,4 @@
1
+ declare const treeActionsDictionary: string[];
2
+ declare const treeAppearanceDictionary: string[];
3
+ declare const treeIconDictionary: string[];
4
+ export { treeActionsDictionary, treeAppearanceDictionary, treeIconDictionary, };
@@ -0,0 +1,12 @@
1
+ export type KeyboardKeyData = {
2
+ alias: string;
3
+ description: string;
4
+ group: string;
5
+ keyCodes: string[];
6
+ keyboardPosition?: {
7
+ left?: boolean;
8
+ right?: boolean;
9
+ };
10
+ };
11
+ export type KeyboardKeyName = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'a' | 'alt' | 'altleft' | 'altright' | 'arrowdown' | 'arrowleft' | 'arrowright' | 'arrowup' | 'b' | 'backspace' | 'c' | 'capslock' | 'command' | 'commandleft' | 'commandright' | 'control' | 'controlleft' | 'controlright' | 'd' | 'delete' | 'e' | 'end' | 'enter' | 'escape' | 'f' | 'f1' | 'f10' | 'f11' | 'f12' | 'f2' | 'f3' | 'f4' | 'f5' | 'f6' | 'f7' | 'f8' | 'f9' | 'g' | 'h' | 'home' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'option' | 'optionleft' | 'optionright' | 'p' | 'pagedown' | 'pageup' | 'q' | 'r' | 's' | 'shift' | 'shiftleft' | 'shiftright' | 'space' | 't' | 'tab' | 'u' | 'v' | 'w' | 'windows' | 'windowsleft' | 'windowsright' | 'x' | 'y' | 'z';
12
+ export type KeyboardKeyMap = Record<KeyboardKeyName, KeyboardKeyData>;
@@ -0,0 +1,3 @@
1
+ export type TreeAppearance = 'none' | 'depth';
2
+ export type TreeIcon = 'folder' | 'chevron';
3
+ export type TreeActions = 'auto' | 'visible';
@@ -1,8 +1,8 @@
1
1
  {
2
- "timestamp": "2024-12-19T14:37:09",
2
+ "timestamp": "2025-02-25T13:09:05",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
- "version": "4.22.2",
5
+ "version": "4.25.1",
6
6
  "typescriptVersion": "5.5.4"
7
7
  },
8
8
  "components": [
@@ -70,7 +70,9 @@
70
70
  }
71
71
  ],
72
72
  "optional": true,
73
- "required": false
73
+ "required": false,
74
+ "getter": false,
75
+ "setter": false
74
76
  },
75
77
  {
76
78
  "name": "opened",
@@ -92,7 +94,44 @@
92
94
  }
93
95
  ],
94
96
  "optional": false,
95
- "required": false
97
+ "required": false,
98
+ "getter": false,
99
+ "setter": false
100
+ },
101
+ {
102
+ "name": "overflow",
103
+ "type": "\"auto\" | \"manual\"",
104
+ "complexType": {
105
+ "original": "ModalOverflowType",
106
+ "resolved": "\"auto\" | \"manual\"",
107
+ "references": {
108
+ "ModalOverflowType": {
109
+ "location": "import",
110
+ "path": "./meta/types",
111
+ "id": "src/components/mds-modal/meta/types.ts::ModalOverflowType"
112
+ }
113
+ }
114
+ },
115
+ "mutable": false,
116
+ "attr": "overflow",
117
+ "reflectToAttr": true,
118
+ "docs": "Specifies if the component prevents the body from scrolling when modal window is opened",
119
+ "docsTags": [],
120
+ "default": "'auto'",
121
+ "values": [
122
+ {
123
+ "value": "auto",
124
+ "type": "string"
125
+ },
126
+ {
127
+ "value": "manual",
128
+ "type": "string"
129
+ }
130
+ ],
131
+ "optional": false,
132
+ "required": false,
133
+ "getter": false,
134
+ "setter": false
96
135
  },
97
136
  {
98
137
  "name": "position",
@@ -156,7 +195,9 @@
156
195
  }
157
196
  ],
158
197
  "optional": true,
159
- "required": false
198
+ "required": false,
199
+ "getter": false,
200
+ "setter": false
160
201
  }
161
202
  ],
162
203
  "methods": [],
@@ -210,6 +251,11 @@
210
251
  "annotation": "prop",
211
252
  "docs": "Set the color of the close icon button to the top left."
212
253
  },
254
+ {
255
+ "name": "--mds-modal-custom-window-distance",
256
+ "annotation": "prop",
257
+ "docs": "Set the distance between the slotted modal window and the screen bounds"
258
+ },
213
259
  {
214
260
  "name": "--mds-modal-overlay-color",
215
261
  "annotation": "prop",
@@ -417,6 +463,11 @@
417
463
  "docstring": "",
418
464
  "path": "src/type/button.ts"
419
465
  },
466
+ "src/type/text.ts::TypographyTruncateType": {
467
+ "declaration": "export type TypographyTruncateType =\n | 'all'\n | 'none'\n | 'word'",
468
+ "docstring": "",
469
+ "path": "src/type/text.ts"
470
+ },
420
471
  "src/type/variant.ts::ChipVariantType": {
421
472
  "declaration": "export type ChipVariantType =\n | 'primary'\n | 'secondary'\n | 'dark'\n | 'error'\n | 'info'\n | 'success'\n | 'warning'",
422
473
  "docstring": "",
@@ -457,11 +508,6 @@
457
508
  "docstring": "",
458
509
  "path": "src/components/mds-file/meta/event-detail.ts"
459
510
  },
460
- "src/type/text.ts::TypographyTruncateType": {
461
- "declaration": "export type TypographyTruncateType =\n | 'all'\n | 'none'\n | 'word'",
462
- "docstring": "",
463
- "path": "src/type/text.ts"
464
- },
465
511
  "src/components/mds-file-preview/meta/event-detail.ts::MdsFilePreviewEventDetail": {
466
512
  "declaration": "export interface MdsFilePreviewEventDetail {\n extension: string\n filename: string\n target: HTMLMdsFilePreviewElement\n}",
467
513
  "docstring": "",
@@ -492,6 +538,11 @@
492
538
  "docstring": "",
493
539
  "path": "src/components/mds-header/meta/event-detail.ts"
494
540
  },
541
+ "src/components/mds-header/meta/event-detail.ts::MdsHeaderVisibilityEventDetail": {
542
+ "declaration": "export interface MdsHeaderVisibilityEventDetail {\n visibility: boolean\n}",
543
+ "docstring": "",
544
+ "path": "src/components/mds-header/meta/event-detail.ts"
545
+ },
495
546
  "src/components/mds-horizontal-scroll/meta/types.ts::ViewportType": {
496
547
  "declaration": "export type ViewportType =\n | 'all'\n | 'tv'\n | 'xlarge'\n | 'large'\n | 'wide'\n | 'desktop'\n | 'tablet'\n | 'none'",
497
548
  "docstring": "",
@@ -607,6 +658,16 @@
607
658
  "docstring": "",
608
659
  "path": "src/components/mds-input-upload/meta/types.ts"
609
660
  },
661
+ "src/components/mds-keyboard/meta/type.ts::KeyboardTest": {
662
+ "declaration": "export type KeyboardTest =\n | 'pass'\n | 'fail'",
663
+ "docstring": "",
664
+ "path": "src/components/mds-keyboard/meta/type.ts"
665
+ },
666
+ "src/type/keyboard.ts::KeyboardKeyName": {
667
+ "declaration": "export type KeyboardKeyName =\n | '0'\n | '1'\n | '2'\n | '3'\n | '4'\n | '5'\n | '6'\n | '7'\n | '8'\n | '9'\n | 'a'\n | 'alt'\n | 'altleft'\n | 'altright'\n | 'arrowdown'\n | 'arrowleft'\n | 'arrowright'\n | 'arrowup'\n | 'b'\n | 'backspace'\n | 'c'\n | 'capslock'\n | 'command'\n | 'commandleft'\n | 'commandright'\n | 'control'\n | 'controlleft'\n | 'controlright'\n | 'd'\n | 'delete'\n | 'e'\n | 'end'\n | 'enter'\n | 'escape'\n | 'f'\n | 'f1'\n | 'f10'\n | 'f11'\n | 'f12'\n | 'f2'\n | 'f3'\n | 'f4'\n | 'f5'\n | 'f6'\n | 'f7'\n | 'f8'\n | 'f9'\n | 'g'\n | 'h'\n | 'home'\n | 'i'\n | 'j'\n | 'k'\n | 'l'\n | 'm'\n | 'n'\n | 'o'\n | 'option'\n | 'optionleft'\n | 'optionright'\n | 'p'\n | 'pagedown'\n | 'pageup'\n | 'q'\n | 'r'\n | 's'\n | 'shift'\n | 'shiftleft'\n | 'shiftright'\n | 'space'\n | 't'\n | 'tab'\n | 'u'\n | 'v'\n | 'w'\n | 'windows'\n | 'windowsleft'\n | 'windowsright'\n | 'x'\n | 'y'\n | 'z'",
668
+ "docstring": "",
669
+ "path": "src/type/keyboard.ts"
670
+ },
610
671
  "src/type/typography.ts::TypographyType": {
611
672
  "declaration": "export type TypographyType =\n | 'action'\n | 'caption'\n | 'snippet'\n | 'detail'\n | 'h1'\n | 'h2'\n | 'h3'\n | 'h4'\n | 'h5'\n | 'h6'\n | 'hack'\n | 'label'\n | 'option'\n | 'paragraph'\n | 'tip'",
612
673
  "docstring": "",
@@ -627,6 +688,11 @@
627
688
  "docstring": "",
628
689
  "path": "src/components/mds-modal/meta/types.ts"
629
690
  },
691
+ "src/components/mds-modal/meta/types.ts::ModalOverflowType": {
692
+ "declaration": "export type ModalOverflowType =\n | 'auto'\n | 'manual'",
693
+ "docstring": "",
694
+ "path": "src/components/mds-modal/meta/types.ts"
695
+ },
630
696
  "src/type/variant.ts::LabelVariantType": {
631
697
  "declaration": "export type LabelVariantType =\n | 'amaranth'\n | 'aqua'\n | 'blue'\n | 'green'\n | 'lime'\n | 'orange'\n | 'orchid'\n | 'sky'\n | 'violet'\n | 'yellow'",
632
698
  "docstring": "",
@@ -782,6 +848,26 @@
782
848
  "docstring": "",
783
849
  "path": "src/type/typography.ts"
784
850
  },
851
+ "src/type/tree.ts::TreeAppearance": {
852
+ "declaration": "export type TreeAppearance =\n | 'none'\n | 'depth'",
853
+ "docstring": "",
854
+ "path": "src/type/tree.ts"
855
+ },
856
+ "src/type/tree.ts::TreeIcon": {
857
+ "declaration": "export type TreeIcon =\n | 'folder'\n | 'chevron'",
858
+ "docstring": "",
859
+ "path": "src/type/tree.ts"
860
+ },
861
+ "src/type/tree.ts::TreeActions": {
862
+ "declaration": "export type TreeActions =\n | 'auto'\n | 'visible'",
863
+ "docstring": "",
864
+ "path": "src/type/tree.ts"
865
+ },
866
+ "src/components/mds-tree-item/meta/event-detail.ts::MdsTreeItemEventDetail": {
867
+ "declaration": "export interface MdsTreeItemEventDetail {\n element: HTMLMdsTreeItemElement\n}",
868
+ "docstring": "",
869
+ "path": "src/components/mds-tree-item/meta/event-detail.ts"
870
+ },
785
871
  "src/components/mds-usage/meta/types.ts::UsageType": {
786
872
  "declaration": "export type UsageType =\n | 'do'\n | 'dont'\n | 'info'\n | 'warn'",
787
873
  "docstring": "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maggioli-design-system/mds-modal",
3
- "version": "5.2.1",
3
+ "version": "5.4.0",
4
4
  "description": "mds-modal is a web-component from Magma Design System, built with StencilJS, TypeScript, Storybook. It's based on the web-component standard and it's designed to be agnostic from the JavaScript framework you are using.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.js",
@@ -24,9 +24,9 @@
24
24
  "test": "stencil test --spec --e2e"
25
25
  },
26
26
  "dependencies": {
27
- "@maggioli-design-system/mds-button": "6.1.3",
28
- "@maggioli-design-system/styles": "15.5.0",
29
- "@stencil/core": "4.22.2",
27
+ "@maggioli-design-system/mds-button": "6.3.0",
28
+ "@maggioli-design-system/styles": "15.8.0",
29
+ "@stencil/core": "4.25.1",
30
30
  "clsx": "2.1.0"
31
31
  },
32
32
  "license": "MIT",
package/readme.md CHANGED
@@ -9,11 +9,12 @@ This is a web-component from Maggioli Design System [Magma](https://magma.maggio
9
9
 
10
10
  ## Properties
11
11
 
12
- | Property | Attribute | Description | Type | Default |
13
- | ----------- | ----------- | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
- | `animating` | `animating` | Specifies if the component is animating itself or not | `"intro" \| "none" \| "outro" \| undefined` | `'none'` |
15
- | `opened` | `opened` | Specifies if the modal is opened or not | `boolean` | `false` |
16
- | `position` | `position` | Specifies the animation position of the modal window | `"bottom" \| "bottom-left" \| "bottom-right" \| "center" \| "left" \| "right" \| "top" \| "top-left" \| "top-right" \| undefined` | `'center'` |
12
+ | Property | Attribute | Description | Type | Default |
13
+ | ----------- | ----------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------- |
14
+ | `animating` | `animating` | Specifies if the component is animating itself or not | `"intro" \| "none" \| "outro" \| undefined` | `'none'` |
15
+ | `opened` | `opened` | Specifies if the modal is opened or not | `boolean` | `false` |
16
+ | `overflow` | `overflow` | Specifies if the component prevents the body from scrolling when modal window is opened | `"auto" \| "manual"` | `'auto'` |
17
+ | `position` | `position` | Specifies the animation position of the modal window | `"bottom" \| "bottom-left" \| "bottom-right" \| "center" \| "left" \| "right" \| "top" \| "top-left" \| "top-right" \| undefined` | `'center'` |
17
18
 
18
19
 
19
20
  ## Events
@@ -43,17 +44,18 @@ This is a web-component from Maggioli Design System [Magma](https://magma.maggio
43
44
 
44
45
  ## CSS Custom Properties
45
46
 
46
- | Name | Description |
47
- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
48
- | `--mds-modal-close-icon-color` | Set the color of the close icon button to the top left. |
49
- | `--mds-modal-overlay-color` | Set the overlay color of the background when the component is opened, this property can be inherited from `globals.css` in `styles^8.0.0`. |
50
- | `--mds-modal-overlay-opacity` | Set the overlay color opacity of the background when the component is opened, this property can be inherited from `globals.css` in `styles^8.0.0`. |
51
- | `--mds-modal-window-background` | Set the background color of the window |
52
- | `--mds-modal-window-distance` | Set the distance between the modal window and the screen bounds |
53
- | `--mds-modal-window-overflow` | Set the overflow of the window |
54
- | `--mds-modal-window-radius` | Set the border radius of the window |
55
- | `--mds-modal-window-shadow` | Set the box shadow of the window |
56
- | `--mds-modal-z-index` | Set the z-index of the window when the component is opened |
47
+ | Name | Description |
48
+ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
49
+ | `--mds-modal-close-icon-color` | Set the color of the close icon button to the top left. |
50
+ | `--mds-modal-custom-window-distance` | Set the distance between the slotted modal window and the screen bounds |
51
+ | `--mds-modal-overlay-color` | Set the overlay color of the background when the component is opened, this property can be inherited from `globals.css` in `styles^8.0.0`. |
52
+ | `--mds-modal-overlay-opacity` | Set the overlay color opacity of the background when the component is opened, this property can be inherited from `globals.css` in `styles^8.0.0`. |
53
+ | `--mds-modal-window-background` | Set the background color of the window |
54
+ | `--mds-modal-window-distance` | Set the distance between the modal window and the screen bounds |
55
+ | `--mds-modal-window-overflow` | Set the overflow of the window |
56
+ | `--mds-modal-window-radius` | Set the border radius of the window |
57
+ | `--mds-modal-window-shadow` | Set the box shadow of the window |
58
+ | `--mds-modal-z-index` | Set the z-index of the window when the component is opened |
57
59
 
58
60
 
59
61
  ## Dependencies
@@ -0,0 +1,263 @@
1
+ import {
2
+ arrow,
3
+ autoPlacement,
4
+ autoUpdate,
5
+ computePosition,
6
+ flip,
7
+ Middleware,
8
+ MiddlewareData,
9
+ offset,
10
+ shift,
11
+ } from '@floating-ui/dom'
12
+ import { FloatingUIPlacement, FloatingUIStrategy } from '@type/floating-ui'
13
+ import { cssDurationToMilliseconds } from './unit'
14
+ import { setAttributeIfEmpty } from './aria'
15
+ import { HTMLStencilElement } from '@stencil/core/internal'
16
+
17
+ export interface FloatingElement extends PositionOptions {
18
+ host: HTMLFloatingElement,
19
+ }
20
+
21
+ export interface HTMLFloatingElement extends HTMLStencilElement, PositionOptions {
22
+ visible: boolean,
23
+ }
24
+
25
+ export interface PositionOptions {
26
+ arrow: boolean;
27
+ arrowPadding: number;
28
+ autoPlacement: boolean;
29
+ flip: boolean;
30
+ offset: number;
31
+ placement: FloatingUIPlacement;
32
+ shift: boolean;
33
+ shiftPadding: number;
34
+ strategy: FloatingUIStrategy;
35
+ }
36
+
37
+ export class FloatingController {
38
+ private _caller: HTMLElement
39
+ private readonly _host: HTMLFloatingElement
40
+ arrowEl: HTMLElement | undefined
41
+
42
+ private cleanupAutoUpdate: () => void
43
+
44
+ constructor (host: HTMLFloatingElement, arrowEl?: HTMLElement) {
45
+ this._host = host
46
+ this.arrowEl = arrowEl
47
+ }
48
+
49
+ updateCaller (target: string): HTMLElement {
50
+ // search caller in document or rootNode of host (if target is in shadowDOM)
51
+ const caller = (this._host.parentElement?.shadowRoot?.querySelector(target) as HTMLElement) ??
52
+ ((this._host.getRootNode() as HTMLElement).querySelector(target) as HTMLElement)
53
+
54
+ if (!caller) {
55
+ throw Error(`Target not found: ${target}`)
56
+ }
57
+
58
+ this._caller = caller
59
+
60
+ setAttributeIfEmpty(this._caller, 'aria-haspopup', 'true')
61
+ setAttributeIfEmpty(this._caller, 'aria-controls', target)
62
+ setAttributeIfEmpty(this._host, 'role', 'menu')
63
+ setAttributeIfEmpty(this._host, 'aria-labelledby', target)
64
+ return caller
65
+ }
66
+
67
+ private readonly arrowInset = (
68
+ middleware: MiddlewareData,
69
+ arrowPosition: string,
70
+ ): { bottom?: string; left?: string; right?: string; top?: string } => {
71
+ const { arrow } = middleware
72
+ const inset = { bottom: '', left: '', right: '', top: '' }
73
+
74
+ if (arrow === undefined) {
75
+ return {}
76
+ }
77
+
78
+ switch (arrowPosition) {
79
+ case 'bottom':
80
+ inset.left = arrow.x !== null ? `${arrow.x}px` : ''
81
+ inset.top = '100%'
82
+ break
83
+ case 'left':
84
+ inset.right = '100%'
85
+ inset.top = arrow.y !== null ? `${arrow.y}px` : ''
86
+ break
87
+ case 'right':
88
+ inset.left = '100%'
89
+ inset.top = arrow.y !== null ? `${arrow.y}px` : ''
90
+ break
91
+ case 'top':
92
+ inset.left = arrow.x !== null ? `${arrow.x}px` : ''
93
+ inset.top = ''
94
+ break
95
+ default:
96
+ break
97
+ }
98
+ return inset
99
+ }
100
+
101
+ private readonly arrowTransform = (
102
+ arrowPosition: string,
103
+ ): { transform: string } => {
104
+ let transformProps = this._host.arrow && this._host.visible ? 'scale(1)' : 'scale(0)'
105
+ switch (arrowPosition) {
106
+ case 'bottom':
107
+ transformProps = `rotate(180deg) ${transformProps} translate(0, -100%)`
108
+ break
109
+ case 'left':
110
+ transformProps = `rotate(-90deg) ${transformProps} translate(50%, -50%)`
111
+ break
112
+ case 'right':
113
+ transformProps = `rotate(90deg) ${transformProps} translate(-50%, -50%)`
114
+ break
115
+ case 'top':
116
+ transformProps = `rotate(0deg) ${transformProps} translate(0, 0)`
117
+ break
118
+ default:
119
+ break
120
+ }
121
+ return { transform: transformProps }
122
+ }
123
+
124
+ private readonly arrowTransformOrigin = (
125
+ arrowPosition: string,
126
+ ): { transformOrigin: string } => {
127
+ switch (arrowPosition) {
128
+ case 'bottom':
129
+ return { transformOrigin: 'center top' }
130
+ case 'left':
131
+ return { transformOrigin: 'right center' }
132
+ case 'right':
133
+ return { transformOrigin: 'left center' }
134
+ case 'top':
135
+ return { transformOrigin: 'center bottom' }
136
+ default:
137
+ return { transformOrigin: 'center top' }
138
+ }
139
+ }
140
+
141
+ private readonly calculatePosition = (): void => {
142
+ if (!this._caller) return
143
+
144
+ const middleware: Middleware[] = new Array<Middleware>()
145
+ const config: { padding?: number } = {}
146
+
147
+ if (this._host.shiftPadding) {
148
+ config.padding = this._host.shiftPadding
149
+ }
150
+
151
+ if (this._host.autoPlacement) {
152
+ middleware.push(autoPlacement())
153
+ }
154
+
155
+ if (this._host.offset) {
156
+ middleware.push(offset(this._host.offset))
157
+ }
158
+
159
+ if (!this._host.autoPlacement && this._host.flip) {
160
+ middleware.push(flip(config))
161
+ }
162
+
163
+ if (this._host.shift) {
164
+ middleware.push(shift(config))
165
+ }
166
+
167
+ if (this.arrowEl && this._host.arrow) {
168
+ middleware.push(
169
+ arrow({
170
+ element: this.arrowEl,
171
+ padding: this._host.arrowPadding,
172
+ }),
173
+ )
174
+ }
175
+
176
+ computePosition(this._caller, this._host, {
177
+ middleware,
178
+ placement: this._host.placement,
179
+ strategy: this._host.strategy,
180
+ }).then(({ x, y, placement, middlewareData }) => {
181
+ Object.assign(this._host.style, {
182
+ left: `${x}px`,
183
+ top: `${y}px`,
184
+ })
185
+
186
+ const arrowStyle = {}
187
+ const arrowPosition = {
188
+ top: 'bottom',
189
+ right: 'left',
190
+ bottom: 'top',
191
+ left: 'right',
192
+ }[placement.split('-')[0]]
193
+
194
+ if (arrowPosition && this.arrowEl) {
195
+ Object.assign(arrowStyle, this.arrowTransform(arrowPosition))
196
+ Object.assign(
197
+ arrowStyle,
198
+ this.arrowInset(middlewareData, arrowPosition),
199
+ )
200
+ Object.assign(arrowStyle, this.arrowTransformOrigin(arrowPosition))
201
+ Object.assign(this.arrowEl.style, arrowStyle)
202
+ }
203
+ })
204
+ }
205
+
206
+ updatePosition (): void {
207
+ if (this.cleanupAutoUpdate) this.cleanupAutoUpdate()
208
+ this.cleanupAutoUpdate = autoUpdate(this._caller, this._host, this.calculatePosition)
209
+ }
210
+
211
+ dismiss (): void {
212
+ this.cleanupAutoUpdate()
213
+ }
214
+ }
215
+
216
+ export class Backdrop {
217
+ private readonly defaultBackdropId = 'magma-backdrop'
218
+ private readonly backdropBackgroundVisible = 'rgba(var(--magma-backdrop-color, 0 0 0) / var(--magma-backdrop-opacity, 0.1))'
219
+ private readonly backdropBackgroundHidden = 'rgba(var(--magma-backdrop-color, 0 0 0) / 0)'
220
+
221
+ private readonly backdropId: string
222
+ private readonly cssBackdropZIndex: string
223
+ private readonly cssBackdropDuration: string
224
+
225
+ private backdropEl: HTMLElement
226
+ private backdropTimer: NodeJS.Timeout
227
+
228
+ constructor (backdropId?: string) {
229
+ this.backdropId = backdropId ?? this.defaultBackdropId
230
+ this.cssBackdropZIndex = `var(--${this.backdropId}-z-index, 4000)`
231
+ this.cssBackdropDuration = `var(--${this.backdropId}-animation-duration, 300ms)`
232
+ }
233
+
234
+ attachBackdrop (): void {
235
+ if (!this.backdropEl) {
236
+ this.backdropEl = document.createElement('div')
237
+ this.backdropEl.className = this.backdropId
238
+ this.backdropEl.style.inset = '0'
239
+ this.backdropEl.style.pointerEvents = 'none'
240
+ this.backdropEl.style.position = 'fixed'
241
+ this.backdropEl.style.transition = `background-color ${this.cssBackdropDuration} ease-out`
242
+ this.backdropEl.style.zIndex = this.cssBackdropZIndex
243
+ }
244
+ this.backdropEl.style.backgroundColor = this.backdropBackgroundHidden
245
+ document.body.appendChild(this.backdropEl)
246
+
247
+ clearTimeout(this.backdropTimer)
248
+ this.backdropTimer = setTimeout(() => {
249
+ this.backdropEl.style.backgroundColor = this.backdropBackgroundVisible
250
+ }, 1)
251
+ }
252
+
253
+ detachBackdrop (): void {
254
+ if (!this.backdropEl) {
255
+ return
256
+ }
257
+ this.backdropEl.style.backgroundColor = 'transparent'
258
+ clearTimeout(this.backdropTimer)
259
+ this.backdropTimer = setTimeout(() => {
260
+ this.backdropEl.remove()
261
+ }, cssDurationToMilliseconds(this.cssBackdropDuration))
262
+ }
263
+ }
@@ -1,8 +1,16 @@
1
1
  const hasSlottedElements = (el: HTMLElement, name?: string): boolean => {
2
- let query = 'slot'
3
- if (name) {
4
- query = `slot[name=${name}]`
2
+ const query = name ? `slot[name="${name}"]` : 'slot:not([name])'
3
+
4
+ const slot: HTMLSlotElement = el.shadowRoot?.querySelector(query) as HTMLSlotElement
5
+ if (slot) {
6
+ return slot.assignedElements({ flatten: true }).length > 0
5
7
  }
8
+ return false
9
+ }
10
+
11
+ const hasSlottedNodes = (el: HTMLElement, name?: string): boolean => {
12
+ const query = name ? `slot[name="${name}"]` : 'slot:not([name])'
13
+
6
14
  const slot: HTMLSlotElement = el.shadowRoot?.querySelector(query) as HTMLSlotElement
7
15
  if (slot) {
8
16
  return slot.assignedNodes().length > 0
@@ -10,6 +18,18 @@ const hasSlottedElements = (el: HTMLElement, name?: string): boolean => {
10
18
  return false
11
19
  }
12
20
 
21
+ const hasSlotted = (el: HTMLElement, name?: string): boolean => {
22
+ const query = name ? `slot[name="${name}"]` : 'slot:not([name])'
23
+
24
+ const slot: HTMLSlotElement = el.shadowRoot?.querySelector(query) as HTMLSlotElement
25
+ if (slot) {
26
+ return slot.assignedNodes().length > 0 || slot.assignedElements().length > 0
27
+ }
28
+ return false
29
+ }
30
+
13
31
  export {
14
32
  hasSlottedElements,
33
+ hasSlottedNodes,
34
+ hasSlotted,
15
35
  }
@@ -0,0 +1,42 @@
1
+ const levenshteinDistance = (a: string, b: string): number => {
2
+ const dp: number[][] = Array.from({ length: a.length + 1 }, (_, i) =>
3
+ // eslint-disable-next-line no-nested-ternary
4
+ Array.from({ length: b.length + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
5
+ )
6
+
7
+ for (let i = 1; i <= a.length; i++) {
8
+ for (let j = 1; j <= b.length; j++) {
9
+ if (a[i - 1] === b[j - 1]) {
10
+ dp[i][j] = dp[i - 1][j - 1]
11
+ } else {
12
+ dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1])
13
+ }
14
+ }
15
+ }
16
+
17
+ return dp[a.length][b.length]
18
+ }
19
+
20
+
21
+ const closest = (input: string, validCodes: string[]): string => {
22
+ let [closest] = validCodes
23
+ let minDistance = levenshteinDistance(input, closest)
24
+
25
+ for (const code of validCodes) {
26
+ const distance = levenshteinDistance(input, code)
27
+ if (distance < minDistance) {
28
+ minDistance = distance
29
+ closest = code
30
+ }
31
+ }
32
+
33
+ return closest
34
+ }
35
+
36
+ const firstLetterUppercase = (str: string): string => str.charAt(0).toUpperCase() + str.slice(1)
37
+
38
+ export {
39
+ closest,
40
+ firstLetterUppercase,
41
+ levenshteinDistance,
42
+ }
@@ -12,6 +12,7 @@
12
12
  * @prop --mds-modal-window-overflow: Set the overflow of the window
13
13
  * @prop --mds-modal-window-radius: Set the border radius of the window
14
14
  * @prop --mds-modal-window-distance: Set the distance between the modal window and the screen bounds
15
+ * @prop --mds-modal-custom-window-distance: Set the distance between the slotted modal window and the screen bounds
15
16
  * @prop --mds-modal-window-shadow: Set the box shadow of the window
16
17
  * @prop --mds-modal-z-index: Set the z-index of the window when the component is opened
17
18
  */
@@ -28,6 +29,7 @@
28
29
  --mds-modal-window-radius: 0;
29
30
  --mds-modal-window-shadow: theme('boxShadow.2xl');
30
31
  --mds-modal-window-distance: 0;
32
+ --mds-modal-custom-window-distance: theme('spacing.600');
31
33
  --mds-modal-z-index: var(--magma-modal-z-index);
32
34
 
33
35
  @apply ease-in-out-expo;
@@ -46,6 +48,10 @@
46
48
  z-index: var(--mds-modal-z-index, 1000);
47
49
  }
48
50
 
51
+ :host ::slotted([slot="window"]) {
52
+ margin: var(--mds-modal-custom-window-distance);
53
+ }
54
+
49
55
  :host( [position="top"] ) {
50
56
  align-items: flex-start;
51
57
  justify-content: center;
@@ -113,4 +119,4 @@
113
119
  @import './css/mds-modal-pref-animation.css';
114
120
  @import './css/mds-modal-pref-contrast.css';
115
121
  @import './css/mds-modal-pref-theme.css';
116
-
122
+ @import '../../tailwind/fouc.css';