@natachah/vanilla-frontend 0.1.22 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/pages/components/drawer.html +4 -2
- package/docs/pages/components/grid.html +42 -76
- package/docs/pages/javascript/trap.html +89 -0
- package/docs/pages/quick-start/customization.html +74 -73
- package/docs/src/js/doc-layout.js +7 -3
- package/docs/src/scss/layout.scss +2 -2
- package/docs/src/scss/style.scss +1 -1
- package/js/_drawer.js +42 -28
- package/js/tests/drawer.test.js +0 -1
- package/js/tests/trap.test.js +119 -0
- package/js/utilities/_trap.js +155 -0
- package/natachah-vanilla-frontend-0.2.1.tgz +0 -0
- package/package.json +1 -1
- package/scss/base/_reset.scss +7 -7
- package/scss/components/_grid.scss +6 -5
- package/natachah-vanilla-frontend-0.1.22.tgz +0 -0
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<rect width="100" height="10" x="0" y="80" rx="0"></rect>
|
|
32
32
|
</svg>
|
|
33
33
|
</button>
|
|
34
|
-
<div id="drawer" class="drawer"
|
|
34
|
+
<div id="drawer" class="drawer" hidden>
|
|
35
35
|
My awsome drawer !
|
|
36
36
|
</div>
|
|
37
37
|
</doc-code>
|
|
@@ -63,6 +63,8 @@
|
|
|
63
63
|
|
|
64
64
|
<blockquote class="note">The <code>#backdrop</code> must be a child of the <code><body></code> ! <br> And the default CSS breakpoint to view the backdrop is 960px</blockquote>
|
|
65
65
|
|
|
66
|
+
<blockquote class="warning"> You should add a toggle button inside the drawer to avoid some Focus Trap !</blockquote>
|
|
67
|
+
|
|
66
68
|
<h2>Javascript</h2>
|
|
67
69
|
<p>This component is mostly in javascript, to use it you must import the javascript file and create a new Drawer object.</p>
|
|
68
70
|
<p>You can have a <b>Backdrop</b> if you want to make it more like a drawer opening on the front of the content, you juste need a <code>#backdrop</code> somewhere on your page.</p>
|
|
@@ -106,7 +108,7 @@
|
|
|
106
108
|
<doc-code data-type="js">
|
|
107
109
|
import Drawer from '@natachah/vanilla-frontend/js/utilities/_drawer.js'
|
|
108
110
|
const drawer = document.getElementById('drawer')
|
|
109
|
-
if (drawer) new Drawer(drawer, { breakpoint : 960,
|
|
111
|
+
if (drawer) new Drawer(drawer, { breakpoint : 960, cookie: '_drawer-cookie' })
|
|
110
112
|
</doc-code>
|
|
111
113
|
|
|
112
114
|
<blockquote>
|
|
@@ -26,10 +26,8 @@
|
|
|
26
26
|
|
|
27
27
|
<p>You can create a basic grid via the <code>.grid</code> class.</p>
|
|
28
28
|
|
|
29
|
-
<p>This method is perfect for <b>fixed</b> and/or <b>complex</b> layout.</p>
|
|
30
|
-
|
|
31
29
|
<doc-demo>
|
|
32
|
-
<div class="grid">
|
|
30
|
+
<div class="grid" style="--grid-columns:8">
|
|
33
31
|
<div>1</div>
|
|
34
32
|
<div>2</div>
|
|
35
33
|
<div>3</div>
|
|
@@ -46,29 +44,20 @@
|
|
|
46
44
|
</doc-demo>
|
|
47
45
|
|
|
48
46
|
<doc-code>
|
|
49
|
-
<div class="grid">
|
|
47
|
+
<div class="grid" style="--grid-columns:8">
|
|
50
48
|
<div>Col 1</div>
|
|
51
49
|
<div>Col 2</div>
|
|
52
50
|
<div>Col 3</div>
|
|
53
|
-
<div
|
|
54
|
-
<div>Col 5</div>
|
|
55
|
-
<div>Col 6</div>
|
|
56
|
-
<div>Col 7</div>
|
|
57
|
-
<div>Col 8</div>
|
|
58
|
-
<div>Col 9</div>
|
|
59
|
-
<div>Col 10</div>
|
|
60
|
-
<div>Col 11</div>
|
|
61
|
-
<div>Col 12</div>
|
|
51
|
+
<div>...</div>
|
|
62
52
|
</div>
|
|
63
53
|
</doc-code>
|
|
64
54
|
|
|
65
55
|
<h2 id="flex-grid">Flex grid</h2>
|
|
66
56
|
|
|
67
57
|
<p>You can create a flexible grid via the <code>.flex-grid</code> class.</p>
|
|
68
|
-
<p>This method is more for <b>flexible</b> layout with a random number of items to display.</p>
|
|
69
58
|
|
|
70
59
|
<doc-demo>
|
|
71
|
-
<div class="flex-grid">
|
|
60
|
+
<div class="flex-grid" style="--grid-columns:8; --grid-grow:0">
|
|
72
61
|
<div>1</div>
|
|
73
62
|
<div>2</div>
|
|
74
63
|
<div>3</div>
|
|
@@ -85,7 +74,39 @@
|
|
|
85
74
|
</doc-demo>
|
|
86
75
|
|
|
87
76
|
<doc-code>
|
|
88
|
-
<div class="flex-grid">
|
|
77
|
+
<div class="flex-grid" style="--grid-columns:8; --grid-grow:0">
|
|
78
|
+
<div>1</div>
|
|
79
|
+
<div>2</div>
|
|
80
|
+
<div>3</div>
|
|
81
|
+
<div>...</div>
|
|
82
|
+
</div>
|
|
83
|
+
</doc-code>
|
|
84
|
+
|
|
85
|
+
<h2>Customization</h2>
|
|
86
|
+
|
|
87
|
+
<p>Both of them can be customize by changing the CSS custom properties.</p>
|
|
88
|
+
|
|
89
|
+
<doc-code data-type="scss">
|
|
90
|
+
--grid-columns: 12;
|
|
91
|
+
--grid-gap-inline: 1rem;
|
|
92
|
+
--grid-gap-block: 1rem;
|
|
93
|
+
--grid-min-column-size: 0%;
|
|
94
|
+
--grid-min-columns: auto-fit;
|
|
95
|
+
</doc-code>
|
|
96
|
+
|
|
97
|
+
<p>But <code>.flex-grid</code> as also the property <code>--grid-grow</code> !</p>
|
|
98
|
+
|
|
99
|
+
<h3>Responsive</h3>
|
|
100
|
+
|
|
101
|
+
<p>There is multiple way to make them responsive, but a simple one is to change the CSS custom properties as:</p>
|
|
102
|
+
|
|
103
|
+
<doc-code data-type="scss">
|
|
104
|
+
--grid-columns: 6; // The maximum number of columns
|
|
105
|
+
--grid-min-column-size: 120px; // The minimum width of a column
|
|
106
|
+
</doc-code>
|
|
107
|
+
|
|
108
|
+
<doc-demo>
|
|
109
|
+
<div class="grid" style="--grid-columns: 6;--grid-min-column-size: 120px;">
|
|
89
110
|
<div>1</div>
|
|
90
111
|
<div>2</div>
|
|
91
112
|
<div>3</div>
|
|
@@ -94,23 +115,13 @@
|
|
|
94
115
|
<div>6</div>
|
|
95
116
|
<div>7</div>
|
|
96
117
|
<div>8</div>
|
|
97
|
-
<div>9</div>
|
|
98
|
-
<div>10</div>
|
|
99
|
-
<div>11</div>
|
|
100
|
-
<div>12</div>
|
|
101
118
|
</div>
|
|
102
|
-
</doc-
|
|
103
|
-
|
|
104
|
-
<h2>Responsive</h2>
|
|
105
|
-
|
|
106
|
-
<p>Both of them can be responsive by changing the CSS custom property <code>--grid-columns</code> inside a <code>@media</code> or a <code>@container</code>.</p>
|
|
107
|
-
|
|
108
|
-
<h3>Auto-fill</h3>
|
|
119
|
+
</doc-demo>
|
|
109
120
|
|
|
110
|
-
<p>
|
|
121
|
+
<p>Same thing for the Flex grid:</p>
|
|
111
122
|
|
|
112
123
|
<doc-demo>
|
|
113
|
-
<div class="grid" style="--grid-columns:
|
|
124
|
+
<div class="flex-grid" style="--grid-columns: 6;--grid-min-column-size: 120px;">
|
|
114
125
|
<div>1</div>
|
|
115
126
|
<div>2</div>
|
|
116
127
|
<div>3</div>
|
|
@@ -119,10 +130,6 @@
|
|
|
119
130
|
<div>6</div>
|
|
120
131
|
<div>7</div>
|
|
121
132
|
<div>8</div>
|
|
122
|
-
<div>9</div>
|
|
123
|
-
<div>10</div>
|
|
124
|
-
<div>11</div>
|
|
125
|
-
<div>12</div>
|
|
126
133
|
</div>
|
|
127
134
|
</doc-demo>
|
|
128
135
|
|
|
@@ -130,10 +137,10 @@
|
|
|
130
137
|
|
|
131
138
|
<h3>Offset</h3>
|
|
132
139
|
|
|
133
|
-
<p>To make a column ossfet with <code>.grid</code>, change the properties <code>grid-column-start</code> and <code>grid-column-end</code>
|
|
140
|
+
<p>To make a column ossfet with <code>.grid</code>, change the properties <code>--grid-min-columns</code> to a fixed number, and add the properties <code>grid-column-start</code> and <code>grid-column-end</code> into the column.</p>
|
|
134
141
|
|
|
135
142
|
<doc-demo>
|
|
136
|
-
<div class="grid" style="--grid-columns:4">
|
|
143
|
+
<div class="grid" style="--grid-min-columns:4">
|
|
137
144
|
<div>Grid 1</div>
|
|
138
145
|
<div>Grid 2</div>
|
|
139
146
|
<div style="grid-column-start: 4;grid-column-end: 5;">Offset</div>
|
|
@@ -171,47 +178,6 @@
|
|
|
171
178
|
<div id="flexGridDemoWider">Wider</div>
|
|
172
179
|
</div>
|
|
173
180
|
</doc-demo>
|
|
174
|
-
|
|
175
|
-
<h3>Auto</h3>
|
|
176
|
-
|
|
177
|
-
<p>Both grids support auto column but are triggered by different CSS custom properties.</p>
|
|
178
|
-
|
|
179
|
-
<p>For <code>.grid</code> use the property <code>--grid-columns:auto-fit</code>.</p>
|
|
180
|
-
|
|
181
|
-
<doc-demo>
|
|
182
|
-
<div class="grid" style="--grid-columns:auto-fit">
|
|
183
|
-
<div>Grid 1</div>
|
|
184
|
-
<div>Grid 2</div>
|
|
185
|
-
<div>Grid 3</div>
|
|
186
|
-
<div>Grid 4</div>
|
|
187
|
-
</div>
|
|
188
|
-
</doc-demo>
|
|
189
|
-
|
|
190
|
-
<p>And for the <code>.flex-grid</code> use the property <code>--grid-grow:1</code>.</p>
|
|
191
|
-
|
|
192
|
-
<doc-demo>
|
|
193
|
-
<div class="flex-grid" style="--grid-grow:1">
|
|
194
|
-
<div>Flex 1</div>
|
|
195
|
-
<div>Flex 2</div>
|
|
196
|
-
<div>Flex 3</div>
|
|
197
|
-
<div>Flex 4</div>
|
|
198
|
-
</div>
|
|
199
|
-
</doc-demo>
|
|
200
|
-
|
|
201
|
-
<h2>Customization</h2>
|
|
202
|
-
|
|
203
|
-
<p>Both grid can be customize via CSS custom property.</p>
|
|
204
|
-
|
|
205
|
-
<doc-code data-type="css">
|
|
206
|
-
--grid-gap-block
|
|
207
|
-
--grid-gap-inline
|
|
208
|
-
--grid-justify
|
|
209
|
-
--grid-align
|
|
210
|
-
--grid-columns
|
|
211
|
-
--grid-grow /* only for .flex-grid */
|
|
212
|
-
--grid-column-size /* only for .grid */
|
|
213
|
-
</doc-code>
|
|
214
|
-
|
|
215
181
|
</doc-layout>
|
|
216
182
|
<script type="module" src="/main.js"></script>
|
|
217
183
|
</body>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Documentations: Javascript > Trap</title>
|
|
8
|
+
</head>
|
|
9
|
+
|
|
10
|
+
<body data-preload>
|
|
11
|
+
<doc-layout>
|
|
12
|
+
|
|
13
|
+
<h1>Trap</h1>
|
|
14
|
+
<p>The trap component make you able to create a focus trap on an element.</p>
|
|
15
|
+
|
|
16
|
+
<h2>Javascript</h2>
|
|
17
|
+
<p>This component is only in javascript, to use it you must import the javascript file and create a new Trap object.</p>
|
|
18
|
+
<p>You can pass the element and an array of exclusions when initiate the component.</p>
|
|
19
|
+
|
|
20
|
+
<doc-code data-type="js">
|
|
21
|
+
import Trap from "@natachah/vanilla-frontend/js/utilities/_trap"
|
|
22
|
+
new Trap(document.getElementById('drawer'), ['#backdrop'])
|
|
23
|
+
</doc-code>
|
|
24
|
+
|
|
25
|
+
<h3>Methods</h3>
|
|
26
|
+
<table>
|
|
27
|
+
<thead>
|
|
28
|
+
<tr>
|
|
29
|
+
<th>Method</th>
|
|
30
|
+
<th>Description</th>
|
|
31
|
+
</tr>
|
|
32
|
+
</thead>
|
|
33
|
+
<tbody>
|
|
34
|
+
<tr>
|
|
35
|
+
<td data-label="Method">
|
|
36
|
+
<p>focusOnFirst()</p>
|
|
37
|
+
</td>
|
|
38
|
+
<td data-label="Description">
|
|
39
|
+
<p>This will focus on the first focusable element</p>
|
|
40
|
+
</td>
|
|
41
|
+
</tr>
|
|
42
|
+
<tr>
|
|
43
|
+
<td data-label="Method">
|
|
44
|
+
<p>activate()</p>
|
|
45
|
+
</td>
|
|
46
|
+
<td data-label="Description">
|
|
47
|
+
<p>This method will activate the trap, it will also set <code>inert</code> and <code>aria-hidden</code> attributes on other HTMLElements</p>
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
<tr>
|
|
51
|
+
<td data-label="Method">
|
|
52
|
+
<p>desactivate()</p>
|
|
53
|
+
</td>
|
|
54
|
+
<td data-label="Description">
|
|
55
|
+
<p>This method will desactivate the trap and remove related attributes</p>
|
|
56
|
+
</td>
|
|
57
|
+
</tr>
|
|
58
|
+
<tr>
|
|
59
|
+
<td data-label="Method">
|
|
60
|
+
<p>handleKeydown(e)</p>
|
|
61
|
+
</td>
|
|
62
|
+
<td data-label="Description">
|
|
63
|
+
<p>This method will keep the <kbd>TAB</kbd> focus inside the element</p>
|
|
64
|
+
</td>
|
|
65
|
+
</tr>
|
|
66
|
+
<tr>
|
|
67
|
+
<td data-label="Method">
|
|
68
|
+
<p>getFocusableElements()</p>
|
|
69
|
+
</td>
|
|
70
|
+
<td data-label="Description">
|
|
71
|
+
<p>This method will return an array of focusable items inside the element</p>
|
|
72
|
+
</td>
|
|
73
|
+
</tr>
|
|
74
|
+
<tr>
|
|
75
|
+
<td data-label="Method">
|
|
76
|
+
<p>getSiblingsOutside()</p>
|
|
77
|
+
</td>
|
|
78
|
+
<td data-label="Description">
|
|
79
|
+
<p>This method will return an array of HTMLElements outside of the element</p>
|
|
80
|
+
</td>
|
|
81
|
+
</tr>
|
|
82
|
+
</tbody>
|
|
83
|
+
</table>
|
|
84
|
+
|
|
85
|
+
</doc-layout>
|
|
86
|
+
<script type="module" src="/main.js"></script>
|
|
87
|
+
</body>
|
|
88
|
+
|
|
89
|
+
</html>
|
|
@@ -28,69 +28,70 @@
|
|
|
28
28
|
<doc-code data-type="css">
|
|
29
29
|
:root {
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
31
|
+
// Typography
|
|
32
|
+
--font-size: 16px;
|
|
33
|
+
--line-height: 1.5;
|
|
34
|
+
--font-family: Arial;
|
|
35
|
+
--font-weight: normal;
|
|
36
|
+
|
|
37
|
+
--font-size-h1: 2.25em; // 36px
|
|
38
|
+
--font-size-h2: 2.00em; // 32px
|
|
39
|
+
--font-size-h3: 1.75em; // 28px
|
|
40
|
+
--font-size-h4: 1.50em; // 24px
|
|
41
|
+
--font-size-h5: 1.25em; // 20px
|
|
42
|
+
--font-size-h6: 1.125em; // 18px
|
|
43
|
+
--font-size-large: 1.125em; // 18px
|
|
44
|
+
--font-size-small: .875em; // 14px
|
|
45
|
+
|
|
46
|
+
// Anchor
|
|
47
|
+
--decoration: none;
|
|
48
|
+
|
|
49
|
+
// Layouts
|
|
50
|
+
--padding-inline: .75em;
|
|
51
|
+
--padding-block: .5em;
|
|
52
|
+
|
|
53
|
+
// Border
|
|
54
|
+
--border-size: 1px;
|
|
55
|
+
--border-style: solid;
|
|
56
|
+
--border-radius: .25rem;
|
|
57
|
+
|
|
58
|
+
// Outline (:focus)
|
|
59
|
+
--outline-size: 3px;
|
|
60
|
+
--outline-style: solid;
|
|
61
|
+
--outline-offset: 0;
|
|
62
|
+
--outline-opacity: 50%;
|
|
63
|
+
|
|
64
|
+
// Hover (color-mix)
|
|
65
|
+
--hover-color: black;
|
|
66
|
+
--hover-percent: 5%;
|
|
67
|
+
|
|
68
|
+
// Active (color-mix)
|
|
69
|
+
--active-color: black;
|
|
70
|
+
--active-percent: 10%;
|
|
71
|
+
|
|
72
|
+
// Disabled
|
|
73
|
+
--disabled-opacity: 50%;
|
|
74
|
+
|
|
75
|
+
// Colors
|
|
76
|
+
--color-body: white;
|
|
77
|
+
--color-font: black;
|
|
78
|
+
--color-primary: #B790E5;
|
|
79
|
+
--color-error: #DC3030;
|
|
80
|
+
--color-success: #008A00;
|
|
81
|
+
--color-warning: #FFA500;
|
|
82
|
+
|
|
83
|
+
// Contrasts
|
|
84
|
+
--color-warning-contrast: black;
|
|
85
|
+
|
|
86
|
+
// Icons
|
|
87
|
+
--icon-external: url('data:image/svg+xml,...');
|
|
88
|
+
--icon-date: url('data:image/svg+xml,...');
|
|
89
|
+
--icon-time: url('data:image/svg+xml,...');
|
|
90
|
+
--icon-file: url('data:image/svg+xml,...');
|
|
91
|
+
--icon-select: url('data:image/svg+xml,...');
|
|
92
|
+
--icon-radio: url('data:image/svg+xml,...');
|
|
93
|
+
--icon-check: url('data:image/svg+xml,...');
|
|
94
|
+
--icon-switch: var(--icon-radio);
|
|
94
95
|
|
|
95
96
|
}
|
|
96
97
|
</doc-code>
|
|
@@ -102,20 +103,20 @@
|
|
|
102
103
|
// This is the light theme (or if there is none)
|
|
103
104
|
html[data-theme=light],
|
|
104
105
|
html:not([data-theme]) {
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
--color-body: white;
|
|
107
|
+
--color-font: black;
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
// This is for the dark theme
|
|
110
111
|
html[data-theme=dark] {
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
--color-body: black;
|
|
113
|
+
--color-font: white;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// This is for the dark theme
|
|
116
117
|
html[data-theme=my-custom-theme] {
|
|
117
|
-
|
|
118
|
-
|
|
118
|
+
--color-body: white;
|
|
119
|
+
--color-font: orange;
|
|
119
120
|
}
|
|
120
121
|
</doc-code>
|
|
121
122
|
|
|
@@ -137,10 +138,10 @@
|
|
|
137
138
|
|
|
138
139
|
<doc-code data-type="scss">
|
|
139
140
|
@use '@natachah/vanilla-frontend/scss/abstracts/_options' with (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
$colors: (
|
|
142
|
+
primary,
|
|
143
|
+
danger
|
|
144
|
+
)
|
|
144
145
|
);
|
|
145
146
|
@use "@natachah/vanilla-frontend/scss/base";
|
|
146
147
|
</doc-code>
|
|
@@ -18,7 +18,7 @@ class DocLayout extends HTMLElement {
|
|
|
18
18
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-angle" viewBox="0 0 16 16">
|
|
19
19
|
<path d="M9.828.722a.5.5 0 0 1 .354.146l4.95 4.95a.5.5 0 0 1 0 .707c-.48.48-1.072.588-1.503.588-.177 0-.335-.018-.46-.039l-3.134 3.134a6 6 0 0 1 .16 1.013c.046.702-.032 1.687-.72 2.375a.5.5 0 0 1-.707 0l-2.829-2.828-3.182 3.182c-.195.195-1.219.902-1.414.707s.512-1.22.707-1.414l3.182-3.182-2.828-2.829a.5.5 0 0 1 0-.707c.688-.688 1.673-.767 2.375-.72a6 6 0 0 1 1.013.16l3.134-3.133a3 3 0 0 1-.04-.461c0-.43.108-1.022.589-1.503a.5.5 0 0 1 .353-.146m.122 2.112v-.002zm0-.002v.002a.5.5 0 0 1-.122.51L6.293 6.878a.5.5 0 0 1-.511.12H5.78l-.014-.004a5 5 0 0 0-.288-.076 5 5 0 0 0-.765-.116c-.422-.028-.836.008-1.175.15l5.51 5.509c.141-.34.177-.753.149-1.175a5 5 0 0 0-.192-1.054l-.004-.013v-.001a.5.5 0 0 1 .12-.512l3.536-3.535a.5.5 0 0 1 .532-.115l.096.022c.087.017.208.034.344.034q.172.002.343-.04L9.927 2.028q-.042.172-.04.343a1.8 1.8 0 0 0 .062.46z"/>
|
|
20
20
|
</svg>
|
|
21
|
-
0.1
|
|
21
|
+
0.2.1
|
|
22
22
|
</span>
|
|
23
23
|
</li>
|
|
24
24
|
<li>
|
|
@@ -36,7 +36,7 @@ class DocLayout extends HTMLElement {
|
|
|
36
36
|
</ul>
|
|
37
37
|
</nav>
|
|
38
38
|
</header>
|
|
39
|
-
<
|
|
39
|
+
<div id="sidebar" class="drawer" hidden>
|
|
40
40
|
<header>
|
|
41
41
|
<a href="/index.html">
|
|
42
42
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-rocket" viewBox="0 0 16 16">
|
|
@@ -91,14 +91,18 @@ class DocLayout extends HTMLElement {
|
|
|
91
91
|
<li><a href="/pages/javascript/sortable.html">Sortable</a></li>
|
|
92
92
|
<li><a href="/pages/javascript/tabpanel.html">Tabpanel</a></li>
|
|
93
93
|
<li><a href="/pages/javascript/toggle.html">Toggle</a></li>
|
|
94
|
+
<li><a href="/pages/javascript/trap.html">Trap</a></li>
|
|
94
95
|
<li><a href="/pages/javascript/tree.html">Tree</a></li>
|
|
95
96
|
</ul>
|
|
96
97
|
<div id="copyright">
|
|
97
98
|
Released under the MIT License.<br>
|
|
98
99
|
Copyright © 2024-present <a href="https://natachaherth.ch">Natacha Herth</a>
|
|
99
100
|
</div>
|
|
101
|
+
<button aria-expanded="false" aria-pressed="false" aria-controls="sidebar" aria-label="Close the sidebar navigation">
|
|
102
|
+
Close
|
|
103
|
+
</button>
|
|
100
104
|
</nav>
|
|
101
|
-
</
|
|
105
|
+
</div>
|
|
102
106
|
<main>
|
|
103
107
|
${this.innerHTML}
|
|
104
108
|
</main>
|
|
@@ -40,7 +40,7 @@ doc-layout {
|
|
|
40
40
|
overflow-y: auto;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
#sidebar {
|
|
44
44
|
|
|
45
45
|
--drawer-display: grid;
|
|
46
46
|
--drawer-transform: translatex(-100%);
|
|
@@ -75,7 +75,7 @@ doc-layout {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
@media (min-width: 960px) {
|
|
78
|
-
&:has(
|
|
78
|
+
&:has(#sidebar:not([hidden])) {
|
|
79
79
|
grid-template-columns: 320px 1fr;
|
|
80
80
|
}
|
|
81
81
|
}
|
package/docs/src/scss/style.scss
CHANGED
package/js/_drawer.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import BaseComponent from './utilities/_base-component'
|
|
14
14
|
import ErrorMessage from "./utilities/_error"
|
|
15
15
|
import Cookie from "./utilities/_cookie"
|
|
16
|
+
import Trap from "./utilities/_trap"
|
|
16
17
|
|
|
17
18
|
export default class Drawer extends BaseComponent {
|
|
18
19
|
|
|
@@ -45,13 +46,12 @@ export default class Drawer extends BaseComponent {
|
|
|
45
46
|
|
|
46
47
|
this._isOpen = !this._element.hidden
|
|
47
48
|
|
|
48
|
-
this._focus = this._element.getAttribute('tabindex') === '0' ? this._element : this._element.querySelector('[tabindex="0"]') ?? this._element.querySelector('button, a, input')
|
|
49
|
-
|
|
50
49
|
this._cookie = this._options.cookie ? new Cookie(this._options.cookie) : null
|
|
51
50
|
|
|
51
|
+
this._trap = new Trap(this._element, ['#backdrop'])
|
|
52
|
+
|
|
52
53
|
// Init the event listener
|
|
53
54
|
this.#init()
|
|
54
|
-
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
@@ -64,29 +64,15 @@ export default class Drawer extends BaseComponent {
|
|
|
64
64
|
// Set the cookie by default
|
|
65
65
|
if (this._cookie && !this._cookie.has('drawer-is-open')) this._cookie.set({ ...this._cookie.value, 'drawer-is-open': this._isOpen })
|
|
66
66
|
|
|
67
|
-
// Define the default
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// Window is bigger than breakpoint
|
|
71
|
-
// -> Show/Hide the drawer by the cookie
|
|
72
|
-
if (window.innerWidth > this._options.breakpoint) this.toggle(shouldBeOpen)
|
|
73
|
-
|
|
74
|
-
// Window is smaller than breakpoint
|
|
75
|
-
// -> Hide the drawer
|
|
76
|
-
if (window.innerWidth <= this._options.breakpoint) this.toggle(false)
|
|
67
|
+
// Define the default status of the drawer by breakpoint
|
|
68
|
+
this.defineDrawerByBreakpoint()
|
|
77
69
|
|
|
78
70
|
// On window resize
|
|
79
71
|
// -> Toggle the drawer
|
|
80
72
|
window.onresize = () => {
|
|
81
73
|
clearTimeout(this._timeout)
|
|
82
74
|
this._timeout = setTimeout(() => {
|
|
83
|
-
|
|
84
|
-
// Bigger than breakpoint
|
|
85
|
-
if (window.innerWidth > this._options.breakpoint && (!this._isOpen && shouldBeOpen)) this.toggle(true)
|
|
86
|
-
|
|
87
|
-
// Smaller than breakpoint -> Invisible
|
|
88
|
-
if (window.innerWidth <= this._options.breakpoint && this._isOpen) this.toggle(false)
|
|
89
|
-
|
|
75
|
+
this.defineDrawerByBreakpoint()
|
|
90
76
|
}, 250)
|
|
91
77
|
}
|
|
92
78
|
|
|
@@ -98,6 +84,34 @@ export default class Drawer extends BaseComponent {
|
|
|
98
84
|
|
|
99
85
|
}
|
|
100
86
|
|
|
87
|
+
defineDrawerByBreakpoint() {
|
|
88
|
+
|
|
89
|
+
let drawerStatus
|
|
90
|
+
|
|
91
|
+
// On mobil, the drawer become a Dialog and it is hidden per default
|
|
92
|
+
if (window.innerWidth <= this._options.breakpoint) {
|
|
93
|
+
// Add Dialog role
|
|
94
|
+
this._element.setAttribute('role', 'dialog')
|
|
95
|
+
this._element.setAttribute('aria-modal', true)
|
|
96
|
+
|
|
97
|
+
// The drawer should be closed
|
|
98
|
+
drawerStatus = false
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// On breakpoint, the drawer become by default "this._options.default"
|
|
102
|
+
if (window.innerWidth > this._options.breakpoint) {
|
|
103
|
+
// Remove Dialog role
|
|
104
|
+
this._element.removeAttribute('role')
|
|
105
|
+
this._element.removeAttribute('aria-modal')
|
|
106
|
+
|
|
107
|
+
// The drawer should be cookie or open
|
|
108
|
+
drawerStatus = this._cookie ? this._cookie.get('drawer-is-open') : true
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (drawerStatus != this._isOpen) this.toggle(drawerStatus)
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
101
115
|
/**
|
|
102
116
|
* Toggle the drawer
|
|
103
117
|
*
|
|
@@ -122,15 +136,15 @@ export default class Drawer extends BaseComponent {
|
|
|
122
136
|
this._cookie.set({ ...this._cookie.value, 'drawer-is-open': this._isOpen })
|
|
123
137
|
}
|
|
124
138
|
|
|
125
|
-
// Add the focus
|
|
139
|
+
// Add the Trap focus
|
|
126
140
|
// * Need to wait the transition before make it focused
|
|
127
|
-
|
|
128
|
-
this._element.
|
|
129
|
-
this.
|
|
130
|
-
}
|
|
131
|
-
|
|
141
|
+
this._element.addEventListener('transitionend', () => {
|
|
142
|
+
if (this._element.getAttribute('role') === 'dialog') {
|
|
143
|
+
this._isOpen ? this._trap.activate() : this._trap.desactivate()
|
|
144
|
+
} else if (this._isOpen) {
|
|
145
|
+
this._trap.focusOnFirst()
|
|
146
|
+
}
|
|
147
|
+
}, { once: true })
|
|
132
148
|
|
|
133
149
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
150
|
}
|
package/js/tests/drawer.test.js
CHANGED
|
@@ -44,7 +44,6 @@ describe('Structure of the class', () => {
|
|
|
44
44
|
expect(fakeDrawer._buttons).toStrictEqual(document.querySelectorAll('button[aria-controls="drawer"]'))
|
|
45
45
|
expect(fakeDrawer._backdrop).toStrictEqual(document.getElementById('backdrop'))
|
|
46
46
|
expect(fakeDrawer._isOpen).toBeTruthy()
|
|
47
|
-
expect(fakeDrawer._focus).toStrictEqual(document.getElementById('focus'))
|
|
48
47
|
})
|
|
49
48
|
|
|
50
49
|
})
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ------------------------------------------------------------------
|
|
3
|
+
* TEST for the /utilities/_trap.js
|
|
4
|
+
* ------------------------------------------------------------------
|
|
5
|
+
* The test will take care of:
|
|
6
|
+
* - Has all the public method
|
|
7
|
+
* - Constructor: Passing the correct parameters
|
|
8
|
+
* - FocusOnFirst(): Passing the correct parameters
|
|
9
|
+
* - Activate(): Save the new cookie value
|
|
10
|
+
* - Desactivate(): Passing the correct parameters
|
|
11
|
+
* - HandleKeydown(): Verify the existance of a key in the cookie value
|
|
12
|
+
* - GetFocusableElements(): Passing the correct parameters
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, test, expect, beforeAll, vi } from "vitest"
|
|
16
|
+
import { fireEvent } from "@testing-library/dom"
|
|
17
|
+
import Trap from "../utilities/_trap"
|
|
18
|
+
import ErrorMessage from "../utilities/_error"
|
|
19
|
+
|
|
20
|
+
let fakeTrap, fakeBtn, fakeLink, fakeDisabledLink, fakeInput
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Before all tests
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
beforeAll(() => {
|
|
28
|
+
|
|
29
|
+
document.body.innerHTML =
|
|
30
|
+
'<div id="trap">' +
|
|
31
|
+
'<button id="button"></button>' +
|
|
32
|
+
'<a id="link" href="#"></a>' +
|
|
33
|
+
'<a id="linkDisabled"></a>' +
|
|
34
|
+
'<input id="input">' +
|
|
35
|
+
'</div>' +
|
|
36
|
+
'<div id="backdrop"></div>' +
|
|
37
|
+
'<div id="content"></div>'
|
|
38
|
+
|
|
39
|
+
fakeTrap = new Trap(document.getElementById('trap'), ['#backdrop'])
|
|
40
|
+
fakeBtn = document.getElementById('button')
|
|
41
|
+
fakeLink = document.getElementById('link')
|
|
42
|
+
fakeDisabledLink = document.getElementById('linkDisabled')
|
|
43
|
+
fakeInput = document.getElementById('input')
|
|
44
|
+
|
|
45
|
+
for (const el of [fakeBtn, fakeLink, fakeDisabledLink, fakeInput]) {
|
|
46
|
+
Object.defineProperty(el, 'offsetWidth', { configurable: true, value: 100 })
|
|
47
|
+
Object.defineProperty(el, 'offsetHeight', { configurable: true, value: 20 })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('Structure of the class', () => {
|
|
53
|
+
|
|
54
|
+
test('Has all the public method', () => {
|
|
55
|
+
expect(fakeTrap.focusOnFirst).toBeTypeOf('function')
|
|
56
|
+
expect(fakeTrap.activate).toBeTypeOf('function')
|
|
57
|
+
expect(fakeTrap.desactivate).toBeTypeOf('function')
|
|
58
|
+
expect(fakeTrap.handleKeydown).toBeTypeOf('function')
|
|
59
|
+
expect(fakeTrap.getFocusableElements).toBeTypeOf('function')
|
|
60
|
+
expect(fakeTrap.getSiblingsOutside).toBeTypeOf('function')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
test('Constructor: Passing the correct parameters', () => {
|
|
64
|
+
expect(() => new Trap()).toThrowError(ErrorMessage.instanceOf('el', 'HTMLElement'))
|
|
65
|
+
expect(() => new Trap(document.getElementById('trap'), 'error')).toThrowError(ErrorMessage.typeOf('exclusions', 'object'))
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe('FocusOnFirst()', () => {
|
|
71
|
+
|
|
72
|
+
test('Focus on first element', () => {
|
|
73
|
+
|
|
74
|
+
expect(fakeTrap._items).toStrictEqual([])
|
|
75
|
+
expect(fakeTrap._first).toStrictEqual(null)
|
|
76
|
+
|
|
77
|
+
fakeTrap.focusOnFirst()
|
|
78
|
+
|
|
79
|
+
expect(fakeTrap._items).toStrictEqual(fakeTrap.getFocusableElements())
|
|
80
|
+
expect(fakeTrap._first).toStrictEqual(fakeBtn)
|
|
81
|
+
expect(document.activeElement).toBe(fakeTrap._first)
|
|
82
|
+
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
describe('Toggle the trap', () => {
|
|
88
|
+
|
|
89
|
+
test('Activate the trap', () => {
|
|
90
|
+
const eventSpy = vi.spyOn(fakeTrap._element, 'addEventListener')
|
|
91
|
+
|
|
92
|
+
fakeTrap.activate()
|
|
93
|
+
|
|
94
|
+
expect(fakeTrap._items).toStrictEqual(fakeTrap.getFocusableElements())
|
|
95
|
+
expect(fakeTrap._items).not.toContain(fakeDisabledLink)
|
|
96
|
+
expect(fakeTrap._first).toStrictEqual(document.getElementById('button'))
|
|
97
|
+
expect(fakeTrap._last).toStrictEqual(document.getElementById('input'))
|
|
98
|
+
expect(fakeTrap._inerts).toStrictEqual(fakeTrap.getSiblingsOutside())
|
|
99
|
+
expect(fakeTrap._inerts).not.toContain(document.getElementById('backdrop'))
|
|
100
|
+
expect(document.activeElement).toBe(fakeTrap._first)
|
|
101
|
+
expect(eventSpy).toHaveBeenCalledWith('keydown', fakeTrap.handleKeydown)
|
|
102
|
+
expect(document.getElementById('backdrop').hasAttribute('inert')).toBeFalsy()
|
|
103
|
+
expect(document.getElementById('backdrop').hasAttribute('aria-hidden')).toBeFalsy()
|
|
104
|
+
expect(document.getElementById('content').hasAttribute('inert')).toBeTruthy()
|
|
105
|
+
expect(document.getElementById('content').hasAttribute('aria-hidden')).toBeTruthy()
|
|
106
|
+
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
test('Desactivate the trap', () => {
|
|
110
|
+
const eventSpy = vi.spyOn(fakeTrap._element, 'removeEventListener')
|
|
111
|
+
fakeTrap.desactivate()
|
|
112
|
+
expect(eventSpy).toHaveBeenCalledWith('keydown', fakeTrap.handleKeydown)
|
|
113
|
+
expect(document.getElementById('backdrop').hasAttribute('inert')).toBeFalsy()
|
|
114
|
+
expect(document.getElementById('backdrop').hasAttribute('aria-hidden')).toBeFalsy()
|
|
115
|
+
expect(document.getElementById('content').hasAttribute('inert')).toBeFalsy()
|
|
116
|
+
expect(document.getElementById('content').hasAttribute('aria-hidden')).toBeFalsy()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
})
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ------------------------------------------------------------------
|
|
3
|
+
* Focus Trap
|
|
4
|
+
* ------------------------------------------------------------------
|
|
5
|
+
* This class create a focus trap on an element as a drawer or a dialog.
|
|
6
|
+
*
|
|
7
|
+
* @author Natacha Herth
|
|
8
|
+
* @copyright Natacha Herth, design & web development
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import ErrorMessage from "./_error"
|
|
12
|
+
|
|
13
|
+
export default class Trap {
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates an instance
|
|
17
|
+
*
|
|
18
|
+
* @constructor
|
|
19
|
+
*/
|
|
20
|
+
constructor(el, exclusions = null) {
|
|
21
|
+
|
|
22
|
+
// Check for errors
|
|
23
|
+
if (!(el instanceof HTMLElement)) throw new Error(ErrorMessage.instanceOf('el', 'HTMLElement'))
|
|
24
|
+
if (exclusions && typeof exclusions !== 'object') throw new Error(ErrorMessage.typeOf('exclusions', 'object'))
|
|
25
|
+
|
|
26
|
+
// Define elements
|
|
27
|
+
this._element = el
|
|
28
|
+
this._items = []
|
|
29
|
+
this._first = null
|
|
30
|
+
this._last = null
|
|
31
|
+
this._inerts = []
|
|
32
|
+
this._exclusions = exclusions ?? []
|
|
33
|
+
this.handleKeydown = this.handleKeydown.bind(this)
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Focus on first element
|
|
39
|
+
*
|
|
40
|
+
*/
|
|
41
|
+
focusOnFirst() {
|
|
42
|
+
// Define the focusable items
|
|
43
|
+
this._items = this.getFocusableElements()
|
|
44
|
+
if (this._items.length === 0) return
|
|
45
|
+
|
|
46
|
+
// Define the first and last item
|
|
47
|
+
this._first = this._element.querySelector('[tabindex="0"]') ?? this._items[0]
|
|
48
|
+
|
|
49
|
+
// Focus the first element by default
|
|
50
|
+
this._first.focus()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Activate the trap
|
|
55
|
+
*
|
|
56
|
+
*/
|
|
57
|
+
activate() {
|
|
58
|
+
// Define the focusable items
|
|
59
|
+
this._items = this.getFocusableElements()
|
|
60
|
+
if (this._items.length === 0) return
|
|
61
|
+
|
|
62
|
+
// Define the first and last item
|
|
63
|
+
this._first = this._element.querySelector('[tabindex="0"]') ?? this._items[0]
|
|
64
|
+
this._last = this._items[this._items.length - 1]
|
|
65
|
+
|
|
66
|
+
// Define event listener
|
|
67
|
+
this._element.addEventListener('keydown', this.handleKeydown)
|
|
68
|
+
|
|
69
|
+
// Focus the first element by default
|
|
70
|
+
this._first.focus()
|
|
71
|
+
|
|
72
|
+
// Make the rest of the content inert for screen reader
|
|
73
|
+
this._inerts = this.getSiblingsOutside()
|
|
74
|
+
this._inerts.forEach(el => {
|
|
75
|
+
el.setAttribute('aria-hidden', 'true')
|
|
76
|
+
el.setAttribute('inert', true)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Desactivate the trap
|
|
83
|
+
*
|
|
84
|
+
*/
|
|
85
|
+
desactivate() {
|
|
86
|
+
this._element.removeEventListener('keydown', this.handleKeydown)
|
|
87
|
+
|
|
88
|
+
this._inerts.forEach(el => {
|
|
89
|
+
el.removeAttribute('aria-hidden')
|
|
90
|
+
el.removeAttribute('inert')
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Handle event on Tab
|
|
96
|
+
*
|
|
97
|
+
* @param {event} e - Event
|
|
98
|
+
*/
|
|
99
|
+
handleKeydown(e) {
|
|
100
|
+
|
|
101
|
+
// Check for the Tab event only
|
|
102
|
+
if (e.key !== 'Tab') return
|
|
103
|
+
|
|
104
|
+
const isShift = e.shiftKey
|
|
105
|
+
|
|
106
|
+
if (isShift && document.activeElement === this._first) {
|
|
107
|
+
e.preventDefault()
|
|
108
|
+
this._last.focus()
|
|
109
|
+
} else if (!isShift && document.activeElement === this._last) {
|
|
110
|
+
e.preventDefault()
|
|
111
|
+
this._first.focus()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get all focusable elements
|
|
118
|
+
*
|
|
119
|
+
*/
|
|
120
|
+
getFocusableElements() {
|
|
121
|
+
return Array.from(
|
|
122
|
+
this._element.querySelectorAll('a[href], area[href], input:not([disabled]):not([type="hidden"]), select:not([disabled]),textarea:not([disabled]), button:not([disabled]), iframe, object, embed,[contenteditable], [tabindex]:not([tabindex="-1"])')
|
|
123
|
+
).filter(el => el.offsetWidth > 0 || el.offsetHeight > 0 || el === document.activeElement)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Find elements outside of the element
|
|
128
|
+
* Generated by ChatGPT
|
|
129
|
+
*
|
|
130
|
+
* @returns {HTMLElement[]}
|
|
131
|
+
*/
|
|
132
|
+
getSiblingsOutside() {
|
|
133
|
+
const hiddenEls = new Set()
|
|
134
|
+
let current = this._element
|
|
135
|
+
|
|
136
|
+
while (current && current !== document.body) {
|
|
137
|
+
const parent = current.parentElement
|
|
138
|
+
if (!parent) break
|
|
139
|
+
|
|
140
|
+
const siblings = Array.from(parent.children).filter(el =>
|
|
141
|
+
el !== current &&
|
|
142
|
+
!current.contains(el) &&
|
|
143
|
+
!this._exclusions.some(sel => el.matches(sel))
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
siblings.forEach(el => hiddenEls.add(el))
|
|
147
|
+
|
|
148
|
+
current = parent
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return Array.from(hiddenEls)
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
}
|
|
Binary file
|
package/package.json
CHANGED
package/scss/base/_reset.scss
CHANGED
|
@@ -120,16 +120,16 @@ body {
|
|
|
120
120
|
overflow-x: hidden;
|
|
121
121
|
margin-right: calc(100% - 100vw);
|
|
122
122
|
|
|
123
|
-
// Avoid scroll when a dialog is opened
|
|
124
|
-
&[inert] {
|
|
125
|
-
overflow: hidden;
|
|
126
|
-
pointer-events: none;
|
|
127
|
-
touch-action: none;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
123
|
// Data attribute to prevent animation on first load DOM
|
|
131
124
|
&[data-preload] * {
|
|
132
125
|
transition-duration: 0s !important;
|
|
133
126
|
}
|
|
134
127
|
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Avoid scroll when a dialog is opened
|
|
131
|
+
[inert] {
|
|
132
|
+
overflow: hidden;
|
|
133
|
+
pointer-events: none;
|
|
134
|
+
touch-action: none;
|
|
135
135
|
}
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
///
|
|
12
12
|
////
|
|
13
13
|
|
|
14
|
+
$grid-column-max-calc: calc((100% - var(--grid-gap-inline, 1rem) * (var(--grid-columns, 12) - 1)) / var(--grid-columns, 12));
|
|
15
|
+
$grid-column-min-calc: min(max($grid-column-max-calc, var(--grid-min-column-size, 0%)), 100%);
|
|
16
|
+
|
|
14
17
|
.grid,
|
|
15
18
|
.flex-grid {
|
|
16
19
|
gap: var(--grid-gap-block, 1rem) var(--grid-gap-inline, 1rem);
|
|
@@ -20,7 +23,7 @@
|
|
|
20
23
|
|
|
21
24
|
.grid {
|
|
22
25
|
display: grid;
|
|
23
|
-
grid-template-columns: repeat(var(--grid-columns,
|
|
26
|
+
grid-template-columns: repeat(var(--grid-min-columns, auto-fit), minmax($grid-column-min-calc, 1fr));
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
.flex-grid {
|
|
@@ -28,9 +31,7 @@
|
|
|
28
31
|
flex-wrap: wrap;
|
|
29
32
|
|
|
30
33
|
> * {
|
|
31
|
-
|
|
32
|
-
flex-
|
|
33
|
-
flex-grow: var(--grid-grow, 0);
|
|
34
|
+
flex-basis: $grid-column-min-calc;
|
|
35
|
+
flex-grow: var(--grid-grow, 1);
|
|
34
36
|
}
|
|
35
|
-
|
|
36
37
|
}
|
|
Binary file
|