@miljodirektoratet/md-css 4.3.1 → 5.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miljodirektoratet/md-css",
3
- "version": "4.3.1",
3
+ "version": "5.0.0",
4
4
  "description": "CSS for Miljødirektoratet",
5
5
  "author": "Miljødirektoratet",
6
6
  "main": "./src/index.css",
@@ -6,7 +6,7 @@
6
6
  font-weight: 400;
7
7
  font-family: 'Open sans';
8
8
  font-size: 1rem;
9
- padding: 0.75rem 1.5rem;
9
+ padding: 0.75rem 1rem;
10
10
  width: fit-content;
11
11
  border: none;
12
12
  }
@@ -23,8 +23,8 @@
23
23
  }
24
24
 
25
25
  .md-button--small {
26
- padding: 0.4rem 0.8rem;
27
- border-radius: 0.43rem;
26
+ padding: 0.5rem 0.75rem;
27
+ border-radius: 0.5rem;
28
28
  }
29
29
 
30
30
  .md-button__topIcon {
@@ -41,7 +41,7 @@
41
41
  height: 1.25rem;
42
42
  width: 1.25rem;
43
43
  flex-shrink: 0;
44
- margin-right: 1rem;
44
+ margin-right: 0.5rem;
45
45
  }
46
46
 
47
47
  .md-button--small > .md-button__leftIcon {
@@ -52,7 +52,7 @@
52
52
  height: 1.25rem;
53
53
  width: 1.25rem;
54
54
  flex-shrink: 0;
55
- margin-left: 1rem;
55
+ margin-left: 0.5rem;
56
56
  }
57
57
  .md-button__rightIcon .md-loading-spinner {
58
58
  width: 1rem;
@@ -90,7 +90,7 @@
90
90
  background-color: #ffffff;
91
91
  border: 2px solid var(--mdPrimaryColor);
92
92
  color: var(--mdPrimaryColor);
93
- padding: calc(0.75rem - 2px) calc(1.5rem - 2px);
93
+ padding: calc(0.75rem - 2px) calc(1rem - 2px);
94
94
  }
95
95
 
96
96
  .md-button--small.md-button--secondary {
@@ -111,7 +111,7 @@
111
111
 
112
112
  .md-button--secondary:disabled {
113
113
  background-color: #fff;
114
- color: var(--mdGreyColor20);
114
+ color: var(--mdGreyColor60);
115
115
  border-color: var(--mdGreyColor20);
116
116
  }
117
117
 
@@ -120,7 +120,7 @@
120
120
  }
121
121
 
122
122
  .md-button--secondary:disabled > .md-button__rightIcon {
123
- color: var(--mdGreyColor20);
123
+ color: var(--mdGreyColor60);
124
124
  }
125
125
 
126
126
  .md-button--tertiary {
@@ -128,7 +128,7 @@
128
128
  border: none;
129
129
  border-radius: 0.43rem;
130
130
  color: var(--mdPrimaryColor);
131
- padding: 0.75rem 1.5rem;
131
+ padding: 0.75rem 1rem;
132
132
  }
133
133
 
134
134
  .md-button--small.md-button--tertiary {
@@ -178,3 +178,42 @@
178
178
  .md-button--danger:hover:enabled {
179
179
  background-color: var(--mdErrorColor120);
180
180
  }
181
+
182
+ /* Danger secondary */
183
+ .md-button--danger-secondary {
184
+ background-color: #ffffff;
185
+ border: 2px solid var(--mdErrorColor);
186
+ color: var(--mdErrorColor);
187
+ padding: calc(0.75rem - 2px) calc(1rem - 2px);
188
+ }
189
+
190
+ .md-button--small.md-button--danger-secondary {
191
+ padding: 0.5rem 0.75rem;
192
+ }
193
+
194
+ .md-button--danger-secondary:hover:enabled {
195
+ background-color: var(--mdErrorBackgroundColor);
196
+ border-color: var(--mdErrorColor);
197
+ }
198
+
199
+ .md-button--danger-secondary:focus:enabled {
200
+ background-color: #ffffff;
201
+ border-color: var(--mdErrorColor);
202
+ color: var(--mdErrorColor);
203
+ outline: 2px var(--mdErrorColor) solid;
204
+ outline-offset: -6px;
205
+ }
206
+
207
+ .md-button--danger-secondary:disabled {
208
+ background-color: #fff;
209
+ color: var(--mdGreyColor60);
210
+ border-color: var(--mdGreyColor20);
211
+ }
212
+
213
+ .md-button--danger-secondary > .md-button__rightIcon {
214
+ color: var(--mdErrorColor);
215
+ }
216
+
217
+ .md-button--danger-secondary:disabled > .md-button__rightIcon {
218
+ color: var(--mdGreyColor60);
219
+ }
@@ -44,18 +44,18 @@
44
44
  background-size: 1.125rem;
45
45
  }
46
46
 
47
- .md-checkbox--disabled .md-checkbox__input:checked + .md-checkbox__label::before {
48
- filter: grayscale(100%);
49
- }
50
-
51
47
  .md-checkbox--disabled .md-checkbox__label::before,
52
48
  .md-checkbox--disabled:focus-within .md-checkbox__label::before,
53
49
  .md-checkbox--disabled:hover .md-checkbox__label::before {
54
50
  background-color: var(--mdGreyColor20);
55
- border-color: var(--mdGreyColor80);
51
+ border-color: var(--mdGreyColor60);
56
52
  cursor: default;
57
53
  }
58
54
 
55
+ .md-checkbox--disabled .md-checkbox__input:checked + .md-checkbox__label::before {
56
+ background-image: url(data:image/svg+xml;base64,PHN2ZyBpZD0iZTk2NWRkN2EtN2NlNS00MTc0LThjMjEtY2UwNjIzYmFmNTJhIiBkYXRhLW5hbWU9ImNoZWNrbWFyay1ncmVlbiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTMgMTAuMDIiPjx0aXRsZT5jaGVja21hcmstZ3JlZW48L3RpdGxlPjxwYXRoIGQ9Ik0xMS4xNCwwLDQuODMsNi4zMWwtMy0zTDAsNS4xOSw0LjgzLDEwLDEzLDEuODZaIiBmaWxsPSIjODA4MDgwIiAvPjwvc3ZnPg==);
57
+ }
58
+
59
59
  .md-checkbox--disabled .md-checkbox__labelText,
60
60
  .md-checkbox--disabled .md-checkbox__label {
61
61
  cursor: default;
@@ -1,55 +1,71 @@
1
1
  # Structure
2
2
 
3
- To use the `Select` css in `@miljodirektoratet/md-css` as a standalone, without the accompanying React component, please use the following HTML structure.
3
+ To use the `MdSelect` css in `@miljodirektoratet/md-css` as a standalone, without the accompanying React component, please use the following HTML structure. Note that this component is built on [Ariakit select](https://ariakit.org/components/select), so implementing it outside React may be challenging due to the complex accessibility behavior it provides.
4
4
 
5
5
  Class names in brackets [] are optional-/togglable-/decorator- or state dependant classes.
6
6
 
7
7
  See [Storybook](https://miljodir.github.io/md-components) for examples and more info.
8
8
 
9
9
  ```html
10
- <div class="md-select [md-select--open, md-select--disabled, md-select--medium, md-select--small]">
11
- <div class="md-select__label">
12
- <div>{label}</div>
13
- <div class="md-select__help-button">
14
- {button to trigger help text}
10
+ <div class="md-select md-select--[large|medium|small] [md-select--has-error]">
11
+ <!-- Label section with optional help button -->
12
+ <div class="md-select__label-wrapper">
13
+ <div class="md-select__label">
14
+ <Ariakit.SelectLabel>{label}</Ariakit.SelectLabel>
15
+ <div class="md-select__help-button">
16
+ <!-- Help button component -->
17
+ </div>
15
18
  </div>
16
- </div>
17
19
 
18
- <div class="md-select__help-text [md-select__help-text--open]">
19
- {helpText}
20
+ <div class="md-select__help-text [md-select__help-text--open]">
21
+ <!-- Help text component -->
22
+ </div>
20
23
  </div>
21
24
 
22
- <MdClickOutsideWrapper> <- optional wrapper to close selectbox when clicking outside
23
- <button
24
- class="md-select__button [md-select__button--open]"
25
- tabIndex={0}
26
- onClick={function to toggle expand|collapse}
27
- >
28
- <div class="md-select__button-text">{displayValue}</div>
29
- <div class="md-select__button-icon">
30
- <!-- Use MdIconChevronForward or icon from Material Symbols here -->
31
- <MdIconChevronForwward />
32
- </div>
33
- </button>
34
-
35
- <div class="md-select__dropdown">
36
- <button
37
- tabIndex={open ? 0: -1}
38
- class="md-select__dropdown-item [md-select__dropdown-item--selected]"
39
- onClick={function to handle select|deselect option}
40
- >
41
- <div class="md-select__dropdown-item-text">{option.text}</div>
42
-
43
- {if seleceted option
44
- <div class="md-select__dropdown-item-clear" title="Klikk for å fjerne valg">
45
- <!-- Use MdIconClose or icon from Material Symbols here -->
46
- <MdIconClose />
25
+ <!-- Button wrapper -->
26
+ <div class="md-select__button-wrapper">
27
+ <Ariakit.Select class="md-select__button">
28
+ Selected value text
29
+ <div class="md-select__button-right">
30
+ <div>
31
+ <!-- Counter for multi-select: +{count} -->
47
32
  </div>
48
- }
33
+ <!-- Reset button - displayed when allowReset is true and there's a value -->
34
+ <button class="md-select__reset" aria-label="Nullstill">
35
+ <!-- Close/clear icon -->
36
+ </button>
37
+ <!-- Dropdown arrow button -->
38
+ <button class="md-select__button-icon">
39
+ <!-- Chevron down icon -->
40
+ </button>
41
+ </div>
42
+ </Ariakit.Select>
43
+ </div>
49
44
 
50
- </button>
51
- </div>
52
- </MdClickOutsideWrapper>
45
+ <!-- Dropdown/popover -->
46
+ <Ariakit.SelectPopover class="md-select__popover">
47
+ <!-- For regular options -->
48
+ <Ariakit.SelectItem class="md-select__item">
49
+ <!-- For single select: just text -->
50
+ Option text
51
+
52
+ <!-- For multi-select: checkbox -->
53
+ <MdCheckbox label="Option text" />
54
+ </Ariakit.SelectItem>
55
+ </Ariakit.SelectPopover>
56
+
57
+ <!-- Error text -->
53
58
  <div class="md-select__error">{errorText}</div>
54
59
  </div>
55
60
  ```
61
+
62
+ ## Accessibility Notes
63
+
64
+ The MdSelect component uses Ariakit's Select component which handles numerous accessibility attributes including:
65
+
66
+ - Proper ARIA roles and attributes
67
+ - Keyboard navigation
68
+ - Focus management
69
+ - Screen reader announcements
70
+
71
+ When implementing this outside of React, you'll need to handle these accessibility concerns manually. The library automatically manages attributes like `aria-controls`, `aria-expanded`, `aria-pressed`, etc.
@@ -3,195 +3,171 @@
3
3
  width: 100%;
4
4
  }
5
5
 
6
- .md-select--medium {
7
- max-width: 440px;
8
- }
9
-
10
- .md-select--small {
11
- max-width: 260px;
12
- }
13
-
14
- .md-select__container {
15
- position: relative;
6
+ /* Label */
7
+ .md-select__label-wrapper {
8
+ margin-bottom: 0.5rem;
16
9
  }
17
10
 
18
11
  .md-select__label {
19
12
  display: flex;
20
- align-items: flex-end;
21
- font-weight: 600;
13
+ align-items: center;
14
+ gap: 0.5rem;
22
15
  }
23
-
24
- .md-select__label-wrapper {
25
- margin-bottom: 0.5rem;
16
+ .md-select__label label {
17
+ font-weight: 600;
26
18
  }
27
19
 
28
- .md-select__label > * + * {
29
- margin-left: 1rem;
20
+ .md-select__button-wrapper:focus-visible {
21
+ outline: 0;
30
22
  }
31
-
32
23
  .md-select__button {
33
- font-family: 'Open sans';
34
- font-size: 1rem;
35
- width: 100%;
36
24
  display: flex;
37
25
  align-items: center;
38
26
  justify-content: space-between;
27
+ width: 100%;
28
+ font-size: 1rem;
29
+ line-height: 150%;
30
+ border: 1px solid var(--mdPrimaryColor);
31
+ padding: 0.6875rem 1rem;
39
32
  background-color: #fff;
40
- padding: 1rem;
41
- border: 1px solid var(--mdGreyColor60);
42
- color: var(--mdGreyColor);
43
- text-align: left;
44
- cursor: pointer;
45
- }
46
-
47
- .md-select__button.md-select__button--error {
48
- border-color: var(--mdErrorColor);
33
+ position: relative;
34
+ outline-width: 0;
35
+ outline-style: solid;
36
+ outline-offset: -2px;
37
+ outline-color: var(--mdPrimaryColor);
38
+ transition: outline-width 0.1s ease-in;
49
39
  }
50
-
51
- .md-select__button.md-select__button--small {
52
- padding: 0.75rem;
40
+ .md-select--large .md-select__button {
41
+ padding: 0.9375rem 1rem;
53
42
  }
54
-
55
- .md-select__button:not(.md-select__button--open):focus.md-select__button--small {
56
- padding: calc(0.75rem - 1px);
43
+ .md-select--small .md-select__button {
44
+ padding: 0.4375rem 1rem;
57
45
  }
58
- .md-select__button.md-select__button--open.md-select__button--small {
59
- padding: calc(0.75rem - 1px);
60
- padding-bottom: 0.75rem;
46
+ .md-select__button[data-focus-visible],
47
+ .md-select__button[aria-expanded='true'] {
48
+ outline-width: 2px;
49
+ transition: outline-width 0.1s ease-in;
61
50
  }
62
-
63
- .md-select--disabled .md-select__button {
51
+ .md-select__button:disabled {
64
52
  background-color: var(--mdGreyColor20);
65
- color: var(--mdGreyColor60);
66
- cursor: not-allowed;
67
- }
68
-
69
- .md-select__button:focus,
70
- .md-select__button:focus-within {
71
- outline: none;
53
+ border-color: var(--mdGreyColor60);
72
54
  }
55
+ .md-select__button .md-select__button-icon {
56
+ width: 1.5rem;
57
+ height: 1.5rem;
58
+ cursor: pointer;
59
+ pointer-events: auto;
60
+ padding: 0;
61
+ margin: 0;
62
+ background: transparent;
63
+ border: 0;
64
+ border-radius: 0;
65
+ line-height: 150%;
73
66
 
74
- .md-select__button:not(.md-select__button--open):focus,
75
- .md-select__button:not(.md-select__button--open):focus-within {
76
- padding: calc(1rem - 1px);
77
- border: 2px solid var(--mdPrimaryColor);
67
+ &:focus-visible {
68
+ outline: 2px solid var(--mdPrimaryColor);
69
+ outline-offset: -2px;
70
+ }
78
71
  }
79
-
80
- .md-select--error.md-select__button:not(.md-select__button--open):focus,
81
- .md-select--error.md-select__button:not(.md-select__button--open):focus-within {
82
- border-color: var(--mdErrorColor);
72
+ .md-select__button[aria-expanded='false'] .md-select__button-icon svg {
73
+ rotate: 0deg;
74
+ transition: rotate 0.2s ease-in;
83
75
  }
84
-
85
- .md-select__button-text {
86
- display: flex;
87
- flex-grow: 1;
88
- padding-right: 1rem;
89
- min-height: 1.375rem;
76
+ .md-select__button[aria-expanded='true'] .md-select__button-icon svg {
77
+ rotate: 180deg;
78
+ transition: rotate 0.2s ease-in;
90
79
  }
91
-
92
- .md-select__button-icon {
80
+ .md-select__button-right {
93
81
  display: flex;
94
- flex-shrink: 0;
95
- width: 1.25rem;
96
- height: 1.25rem;
97
- rotate: 90deg;
98
- color: var(--mdGreyColor);
82
+ align-items: center;
83
+ gap: 0.5rem;
99
84
  }
85
+ .md-select__reset {
86
+ padding: 0;
87
+ margin: 0;
88
+ background: transparent;
89
+ border: 0;
90
+ border-radius: 0;
91
+ margin-right: 0.3rem;
92
+ width: 1.5rem;
93
+ height: 1.5rem;
94
+ cursor: pointer;
95
+ line-height: 150%;
100
96
 
101
- .md-select__help-text {
102
- max-height: 0;
103
- overflow: hidden;
104
- transition: max-height 0.15s ease-out;
97
+ &:focus-visible {
98
+ outline: 2px solid var(--mdPrimaryColor);
99
+ outline-offset: -2px;
100
+ }
105
101
  }
106
102
 
107
- .md-select__help-text--open {
108
- padding-top: 0.5rem;
109
- max-height: 2000px;
110
- transition: max-height 0.5s ease-in;
111
- }
112
-
113
- .md-select__dropdown {
114
- position: absolute;
115
- max-height: 0;
116
- overflow: hidden;
117
- z-index: -1;
103
+ /* popover */
104
+ .md-select__popover {
105
+ background-color: #fff;
106
+ max-height: min(var(--popover-available-height, 300px), 300px);
107
+ overflow: auto;
108
+ overscroll-behavior: contain;
109
+ border: 2px solid var(--mdPrimaryColor);
110
+ border-top: 0;
118
111
  opacity: 0;
119
- transition: max-height 0.5s ease-in-out;
120
- width: 100%;
112
+ transition-duration: 200ms;
113
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
114
+ animation-duration: 200ms;
115
+ animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
116
+ transform: translateY(-5%);
117
+ z-index: 3;
118
+ }
119
+ .md-select__popover[data-enter] {
120
+ opacity: 1;
121
+ transform: translateY(0%);
122
+ outline: 0;
121
123
  }
122
124
 
123
- .md-select__dropdown-item {
124
- display: flex;
125
- align-items: center;
126
- font-family: 'Open sans';
127
- border: 0;
128
- background-color: #fff;
129
- font-size: 1rem;
130
- width: 100%;
131
- text-align: left;
132
- padding: 0.9rem;
133
- transition: background-color 0.15s ease-in-out;
125
+ /* Select item */
126
+ .md-select__item {
127
+ padding: 0.75rem;
134
128
  cursor: pointer;
135
129
  }
136
-
137
- .md-select__dropdown-item:hover,
138
- .md-select__dropdown-item:focus {
139
- outline: none;
140
- background-color: var(--mdPrimaryColor20);
141
- transition: background-color 0.15s ease-in-out;
130
+ .md-select__item--no-result {
131
+ font-style: italic;
142
132
  }
143
-
144
- .md-select__dropdown-item--selected {
145
- background-color: var(--mdPrimaryColor10);
133
+ .md-select--large .md-select__item {
134
+ padding: 1rem 0.75rem;
146
135
  }
147
-
148
- .md-select__dropdown-item-text {
149
- display: flex;
150
- flex-grow: 1;
136
+ .md-select--small .md-select__item {
137
+ padding: 0.5rem 0.75rem;
151
138
  }
152
-
153
- .md-select__dropdown-item-clear {
154
- display: flex;
155
- flex-shrink: 0;
156
- height: 1.25rem;
157
- width: 1.25rem;
158
- color: var(--mdPrimaryColor);
159
- }
160
-
161
- /* Open state */
162
- .md-select--open .md-select__button {
163
- border-top: 2px solid var(--mdPrimaryColor);
164
- border-right: 2px solid var(--mdPrimaryColor);
165
- border-left: 2px solid var(--mdPrimaryColor);
166
- }
167
-
168
- .md-select__button--open {
169
- padding: calc(1rem - 1px);
170
- padding-bottom: 1rem;
139
+ .md-select__item[aria-selected='true'] {
140
+ background-color: var(--mdPrimaryColor20);
171
141
  }
142
+ .md-select__item[data-focus-visible],
143
+ .md-select__item[data-active-item] {
144
+ background-color: var(--mdPrimaryColor40);
172
145
 
173
- .md-select--open .md-select__dropdown {
174
- max-height: 350px;
175
- overflow-y: auto;
176
- opacity: 1;
177
- transition: max-height 0.5s ease-in-out;
178
- border: 2px solid var(--mdPrimaryColor);
179
- box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.25);
180
- border-top: 0;
181
- z-index: 2;
146
+ .md-checkbox__label::before {
147
+ background-color: #fff;
148
+ }
182
149
  }
183
150
 
184
- /* open + error */
185
- .md-select--open.md-select--error .md-select__button {
186
- border-color: var(--mdErrorColor);
151
+ /* Help text */
152
+ .md-select__help-text {
153
+ max-height: 0;
154
+ overflow: hidden;
155
+ transition: max-height 0.15s ease-out;
187
156
  }
188
- .md-select--open.md-select--error .md-select__dropdown {
189
- border-color: var(--mdErrorColor);
157
+ .md-select__help-text--open {
158
+ padding-top: 0.5rem;
159
+ max-height: 2000px;
160
+ transition: max-height 0.5s ease-in;
190
161
  }
191
162
 
192
- /* Error text */
163
+ /* Error */
193
164
  .md-select__error {
194
- color: var(--mdErrorColor);
195
- font-size: 0.88rem;
196
165
  margin-top: 0.5rem;
166
+ color: var(--mdErrorColor);
167
+ font-size: 0.88em;
168
+ }
169
+ .md-select--has-error .md-select__button,
170
+ .md-select--has-error .md-select__popover {
171
+ outline-color: var(--mdErrorColor);
172
+ border-color: var(--mdErrorColor);
197
173
  }