@nordcode/ui 2.0.6 → 2.1.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.
@@ -1,5 +1,5 @@
1
1
  @layer components.buttons {
2
- :where(button:not([class]), button[type]:not([class]), input[type="button"]:not([class]), input[type="submit"]:not([class]), input[type="reset"]:not([class]), input[type="file"], input[type="file"]::-webkit-file-upload-button, input[type="file"]::file-selector-button, .nc-button) {
2
+ :where(button, button, input[type="button"], input[type="submit"], input[type="reset"], input[type="file"], input[type="file"]::-webkit-file-upload-button, input[type="file"]::file-selector-button, .nc-button) {
3
3
  --_button-background: var(--button-background, var(--surface-hover));
4
4
  --_button-color: var(--button-color, var(--text-hover));
5
5
  --_button-border-color: var(--button-border-color, var(--surface-hover));
@@ -31,7 +31,6 @@
31
31
  font-size: inherit;
32
32
  cursor: pointer;
33
33
  display: inline-flex;
34
- box-sizing: border-box;
35
34
  align-items: center;
36
35
  justify-content: center;
37
36
  text-align: center;
@@ -41,13 +40,14 @@
41
40
  text-decoration: unset;
42
41
  box-shadow: var(--_button-box-shadow);
43
42
  user-select: none;
43
+ gap: var(--control-spacing-tiny, 0.25em);
44
44
  -webkit-tap-highlight-color: transparent;
45
45
  -webkit-touch-callout: none;
46
46
 
47
47
  line-height: var(--line-height-base);
48
48
  }
49
49
 
50
- :where(button:not([class]), button[type]:not([class]), input[type="button"]:not([class]), input[type="submit"]:not([class]), input[type="reset"]:not([class]), .nc-button) {
50
+ :where(button, button[type], input[type="button"], input[type="submit"], input[type="reset"], .nc-button) {
51
51
  &:hover {
52
52
  background: var(--_button-background-hover);
53
53
  color: var(--_button-color-hover);
@@ -61,6 +61,10 @@
61
61
  font-weight: var(--font-weight-active);
62
62
  }
63
63
 
64
+ & > svg {
65
+ pointer-events: none;
66
+ }
67
+
64
68
  &:is(:active, .-active) {
65
69
  background-color: var(--_button-background-hover);
66
70
  color: var(--_button-color-hover);
@@ -72,20 +76,6 @@
72
76
  backdrop-filter: contrast(2);
73
77
  }
74
78
 
75
- &[disabled] {
76
- --_button-background: none !important;
77
- --_button-background-hover: none !important;
78
- --_button-color: var(--color-text-subtle) !important;
79
- --_button-color-hover: var(--_button-color) !important;
80
- --_button-border-color: var(--color-text-subtle) !important;
81
- --_button-border-color-hover: var(--_button-border-color);
82
-
83
- box-shadow: none !important;
84
- transform: none !important;
85
- filter: contrast(0.72) opacity(0.72);
86
- cursor: not-allowed;
87
- }
88
-
89
79
  &.-outline {
90
80
  background-color: transparent;
91
81
  color: var(--text);
@@ -169,45 +159,6 @@
169
159
  }
170
160
  }
171
161
 
172
- /*
173
- * for inline icons
174
- */
175
-
176
- &:has(svg) {
177
- gap: var(--control-spacing-tiny, 0.25em);
178
- }
179
-
180
- /*
181
- * If there is no text node for the button,
182
- * it is assumed that an `aria-label` is that
183
- * and the button will be styled as an icon button.
184
- */
185
-
186
- &[aria-label],
187
- &.-icon {
188
- --_button-border-radius: var(--border-radius-round);
189
- padding: 0;
190
- aspect-ratio: 1;
191
- fill: currentColor;
192
-
193
- &:after {
194
- content: "";
195
- inline-size: max(var(--control-height-base), 100%);
196
- block-size: max(var(--control-height-base), 100%);
197
- aspect-ratio: 1;
198
- border-radius: 100%;
199
- inset-inline-start: calc(-0.5 * (var(--control-height-base) - 100%));
200
- inset-block-start: calc(-0.5 * (var(--control-height-base) - 100%));
201
- position: absolute;
202
- z-index: -1;
203
- pointer-events: all;
204
- }
205
-
206
- & > svg {
207
- pointer-events: none;
208
- }
209
- }
210
-
211
162
  &.-icon.-small {
212
163
  padding: 0;
213
164
  }
@@ -217,6 +168,45 @@
217
168
  }
218
169
  }
219
170
 
171
+ /*
172
+ * If there is no text node for the button,
173
+ * it is assumed that an `aria-label` is that
174
+ * and the button will be styled as an icon button.
175
+ */
176
+ :is([aria-label], .-icon):where(button, button[type], input[type="button"], input[type="submit"], input[type="reset"], .nc-button) {
177
+ --_button-border-radius: var(--border-radius-round);
178
+ padding: 0;
179
+ aspect-ratio: 1;
180
+ fill: currentColor;
181
+
182
+ &:after {
183
+ content: "";
184
+ inline-size: max(var(--control-height-base), 100%);
185
+ block-size: max(var(--control-height-base), 100%);
186
+ aspect-ratio: 1;
187
+ border-radius: 100%;
188
+ inset-inline-start: calc(-0.5 * (var(--control-height-base) - 100%));
189
+ inset-block-start: calc(-0.5 * (var(--control-height-base) - 100%));
190
+ position: absolute;
191
+ z-index: -1;
192
+ pointer-events: all;
193
+ }
194
+ }
195
+
196
+ [disabled]:where(button, button[type], input[type="button"], input[type="submit"], input[type="reset"], .nc-button) {
197
+ --_button-background: none !important;
198
+ --_button-background-hover: none !important;
199
+ --_button-color: var(--color-text-subtle) !important;
200
+ --_button-color-hover: var(--_button-color) !important;
201
+ --_button-border-color: var(--color-text-subtle) !important;
202
+ --_button-border-color-hover: var(--_button-border-color);
203
+
204
+ box-shadow: none !important;
205
+ transform: none !important;
206
+ filter: contrast(0.72) opacity(0.72);
207
+ cursor: not-allowed;
208
+ }
209
+
220
210
  :where(input[type="file"]) {
221
211
  color: var(--_input-color);
222
212
  background-color: var(--_input-background);
@@ -244,7 +234,7 @@
244
234
  border-end-end-radius: 0;
245
235
  }
246
236
 
247
- :where(button[type="reset"]:not([class]), .nc-button.-destructive) {
237
+ :where(button[type="reset"], .nc-button.-destructive) {
248
238
  --text: var(--color-status-danger-emphasis);
249
239
  --color: var(--color-status-danger-base);
250
240
  --surface: var(--color-status-danger-surface);
@@ -34,7 +34,7 @@
34
34
  border-radius: var(--_card-border-radius);
35
35
  box-shadow: var(--_card-shadow);
36
36
 
37
- transition: border-color var(--transition-duration-base) var(--ease-2);
37
+ transition: border-color var(--transition-duration-quick-2) var(--ease-2);
38
38
 
39
39
  @media (width >= 480px) {
40
40
  --_card-padding-inline: var(--card-padding-inline, var(--spacing-far));
@@ -5,7 +5,7 @@
5
5
  --_dialog-close-size: var(--dialog-close-size, var(--control-height-base));
6
6
  --_dialog-transition-duration: var(
7
7
  --dialog-transition-duration,
8
- var(--transition-duration-base)
8
+ var(--transition-duration-moderate-2)
9
9
  );
10
10
  --_dialog-max-block-size: var(--dialog-max-block-size, 90dvh);
11
11
  --_dialog-max-inline-size: var(--dialog-max-inline-size, 28rem);
@@ -13,8 +13,8 @@
13
13
  --_dialog-radius: 0;
14
14
  display: block;
15
15
  z-index: var(--layer-important);
16
- animation: close-dialog var(--_dialog-transition-duration) cubic-bezier(0.7, 0, 1, 1) forwards;
17
- transition: opacity var(--_dialog-transition-duration) cubic-bezier(0.7, 0, 1, 1);
16
+ animation: close-dialog var(--_dialog-transition-duration) var(--easing-exit) forwards;
17
+ transition: opacity var(--_dialog-transition-duration) var(--easing-exit);
18
18
  position: fixed;
19
19
  inset: 0;
20
20
  border: var(--border-width-thin) solid var(--color-border-base);
@@ -39,7 +39,7 @@
39
39
  }
40
40
 
41
41
  &[open] {
42
- animation: open-dialog var(--_dialog-transition-duration) cubic-bezier(0, 0.6, 0.58, 1);
42
+ animation: open-dialog var(--_dialog-transition-duration) var(--easing-entry);
43
43
  }
44
44
 
45
45
  &:not([open]) {
@@ -1,5 +1,5 @@
1
- @layer components.inputs {
2
- :where(label:not([class]), .nc-input-label) {
1
+ @layer base.inputs {
2
+ :where(label, .nc-input-label) {
3
3
  font-family: var(--font-family-default);
4
4
  letter-spacing: var(--tracking-tight);
5
5
  font-weight: var(--font-weight-active);
@@ -10,7 +10,7 @@
10
10
  align-items: center;
11
11
  }
12
12
 
13
- :where(input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="url"], input[type="search"], input[type="date"], input[type="month"], input[type="week"], input[type="text"], input[type="datetime"], input[type="datetime-local"], input[type="time"], input[type="tel"], input[type="color"], input[type="file"], input[type="checkbox"], input[type="radio"], textarea, select, .nc-input, .nc-select, .nc-textarea, .nc-input-checkbox, .nc-input-radio, .nc-input-label, .nc-input-color, .nc-input-field, .nc-input-error, .nc-checkbox-wrapper, .nc-input-switch, .nc-radio-field, .nc-checkbox-field) {
13
+ :where(input, textarea, select, .nc-input, .nc-select, .nc-textarea, .nc-input-checkbox, .nc-input-radio, .nc-input-label, .nc-input-color, .nc-input-field, .nc-input-error, .nc-checkbox-wrapper, .nc-input-switch, .nc-radio-field, .nc-checkbox-field) {
14
14
  --_input-background: var(--input-background, var(--color-surface-subtle));
15
15
  --_input-background-active: var(--input-background-active, var(--color-surface-base));
16
16
  --_input-color: var(--input-color, var(--color-text-base));
@@ -32,7 +32,7 @@
32
32
  --_input-hover-background: var(--input-hover-background, var(--color-brand-primary-hover));
33
33
  }
34
34
 
35
- :where(input[type="text"], input[type="email"], input[type="password"], input[type="number"], input[type="url"], input[type="search"], input[type="date"], input[type="month"], input[type="week"], input[type="text"], input[type="datetime"], input[type="datetime-local"], input[type="time"], input[type="tel"], input[type="color"], input[type="file"], textarea, select, .nc-input) {
35
+ :where(input, textarea, select, .nc-input) {
36
36
  font: inherit;
37
37
  letter-spacing: inherit;
38
38
  word-spacing: inherit;
@@ -73,16 +73,28 @@
73
73
  &::placeholder {
74
74
  color: var(--color-text-subtle);
75
75
  }
76
+
77
+ &.-validate:user-valid {
78
+ outline: var(--_input-outline);
79
+ outline-offset: 0;
80
+ outline-color: var(--color-status-success-base);
81
+ }
82
+
83
+ &.-validate:user-invalid {
84
+ outline: var(--_input-outline);
85
+ outline-offset: 0;
86
+ outline-color: var(--color-status-danger-base);
87
+ }
76
88
  }
77
89
 
78
- :where(select:not([class]), .nc-select) {
90
+ :where(select, .nc-select) {
79
91
  padding-inline-end: 1.75em;
80
92
  background-image: var(--triangle-down-url);
81
93
  background-position: right 0.5em top 50%;
82
94
  background-size: 1em 0.75em;
83
95
  }
84
96
 
85
- :where(textarea:not([class]), .nc-textarea) {
97
+ :where(textarea, .nc-textarea) {
86
98
  min-block-size: calc(8lh + 2 * var(--_input-padding-block));
87
99
  max-block-size: 80svh;
88
100
  min-inline-size: var(--input-inline-size, 100%);
@@ -93,7 +105,7 @@
93
105
  field-sizing: content;
94
106
  }
95
107
 
96
- :where(input[type="checkbox"]:not([class]), input[type="radio"]:not([class]), .nc-input-checkbox, .nc-input-radio, .nc-input-switch) {
108
+ :where(input[type="checkbox"], input[type="radio"], .nc-input-checkbox, .nc-input-radio, .nc-input-switch) {
97
109
  inline-size: 1lh;
98
110
  block-size: 1lh;
99
111
  padding: 0;
@@ -104,11 +116,11 @@
104
116
  border: var(--_input-border);
105
117
  --current-background: var(--_input-background);
106
118
  background: var(--current-background);
107
- transition: var(--transition-duration-short) background var(--ease-2);
119
+ transition: var(--transition-duration-quick-1) background var(--ease-2);
108
120
  box-shadow: var(--_input-box-shadow);
109
121
  }
110
122
 
111
- :where(input[type="checkbox"]:not([class]), .nc-input-checkbox) {
123
+ :where(input[type="checkbox"], .nc-input-checkbox) {
112
124
  --_transition-duration: 0ms;
113
125
  overflow: hidden;
114
126
  border-radius: var(--_input-border-radius);
@@ -122,7 +134,7 @@
122
134
  block-size: 0.75lh;
123
135
  background-color: var(--color-brand-primary-contrast);
124
136
  transform: scale(0.8) translateY(2em);
125
- transition: transform var(--ease-out-2) var(--transition-duration-short);
137
+ transition: transform var(--ease-out-2) var(--transition-duration-quick-1);
126
138
  font-family: var(--font-family-sans);
127
139
  --font-weight: var(--font-weight-active);
128
140
  line-height: 1;
@@ -151,7 +163,7 @@
151
163
  border-radius: var(--border-radius-round);
152
164
  transform: scale(0.8) translateY(2em);
153
165
  background-color: var(--color-brand-primary-contrast);
154
- transition: transform var(--ease-out-2) var(--transition-duration-short);
166
+ transition: transform var(--ease-out-2) var(--transition-duration-quick-1);
155
167
  }
156
168
 
157
169
  &:checked {
@@ -166,7 +178,7 @@
166
178
  :where(input[type="color"], .nc-input-color) {
167
179
  aspect-ratio: 1;
168
180
  inline-size: auto;
169
- padding: var(--control-spacing-minimal, 0.125em);
181
+ padding: var(--control-spacing-nearest, 0.125em);
170
182
  }
171
183
 
172
184
  :where(input[type="date"], .nc-input-date) {
@@ -25,7 +25,7 @@
25
25
  border-radius: var(--_input-border-radius);
26
26
  box-shadow: var(--shadow-near);
27
27
  transition: transform, background-color;
28
- transition-duration: var(--transition-duration-base);
28
+ transition-duration: var(--transition-duration-quick-2);
29
29
  transition-timing-function: var(--ease-2);
30
30
  }
31
31
 
@@ -26,7 +26,7 @@
26
26
  backdrop-filter: blur(3px);
27
27
  background-color: var(--_notification-center-background);
28
28
  transform: translate(100%, 0);
29
- transition: transform var(--transition-duration-base) ease-in-out;
29
+ transition: transform var(--transition-duration-moderate-2) var(--ease-in-out-2);
30
30
  }
31
31
 
32
32
  :where(.nc-notification-output, .nc-notification-center-container) {
@@ -70,7 +70,7 @@
70
70
  inline-size: 100%;
71
71
  border-radius: var(--border-radius-small);
72
72
  box-shadow: var(--shadow-far);
73
- animation: pop-in var(--transition-duration-base) cubic-bezier(0, 0.6, 0.58, 1);
73
+ animation: pop-in var(--transition-duration-moderate-2) var(--easing-entry);
74
74
  color: var(--color-text-base);
75
75
  pointer-events: all;
76
76
  }
@@ -108,7 +108,7 @@
108
108
  }
109
109
 
110
110
  :where(.nc-notification.-closing) {
111
- animation: remove-notification var(--transition-duration-base) cubic-bezier(0.7, 0, 1, 1) forwards;
111
+ animation: remove-notification var(--transition-duration-moderate-2) var(--easing-exit) forwards;
112
112
  }
113
113
 
114
114
  @keyframes pop-in {
@@ -4,3 +4,4 @@
4
4
  @import "./easings.css";
5
5
  @import "./layouts.css";
6
6
  @import "./theme.css";
7
+ @import "./conditionalRadius.css";
@@ -0,0 +1,7 @@
1
+ @layer helpers.conditionalRadius {
2
+ :where(html) {
3
+ --border-radius-cond-small: clamp(0px, calc(100vw - 100%) * 1e5, var(--border-radius-small));
4
+ --border-radius-cond-medium: clamp(0px, calc(100vw - 100%) * 1e5, var(--border-radius-medium));
5
+ --border-radius-cond-large: clamp(0px, calc(100vw - 100%) * 1e5, var(--border-radius-large));
6
+ }
7
+ }
@@ -1,17 +1,18 @@
1
1
  @layer config.easings {
2
2
  :where(html) {
3
+ /* From https://github.com/argyleink/open-props/blob/main/src/props.easing.css */
3
4
  --ease-1: cubic-bezier(0.25, 0, 0.5, 1);
4
5
  --ease-2: cubic-bezier(0.25, 0, 0.4, 1);
5
6
  --ease-3: cubic-bezier(0.25, 0, 0.3, 1);
6
7
  --ease-4: cubic-bezier(0.25, 0, 0.2, 1);
7
8
  --ease-5: cubic-bezier(0.25, 0, 0.1, 1);
8
9
  --ease-in-1: cubic-bezier(0.25, 0, 1, 1);
9
- --ease-in-2: cubic-bezier(0.5, 0, 1, 1);
10
- --ease-in-3: cubic-bezier(0.7, 0, 1, 1);
11
- --ease-in-4: cubic-bezier(0.9, 0, 1, 1);
10
+ --ease-in-2: cubic-bezier(0.50, 0, 1, 1);
11
+ --ease-in-3: cubic-bezier(0.70, 0, 1, 1);
12
+ --ease-in-4: cubic-bezier(0.90, 0, 1, 1);
12
13
  --ease-in-5: cubic-bezier(1, 0, 1, 1);
13
14
  --ease-out-1: cubic-bezier(0, 0, 0.75, 1);
14
- --ease-out-2: cubic-bezier(0, 0, 0.5, 1);
15
+ --ease-out-2: cubic-bezier(0, 0, 0.50, 1);
15
16
  --ease-out-3: cubic-bezier(0, 0, 0.3, 1);
16
17
  --ease-out-4: cubic-bezier(0, 0, 0.1, 1);
17
18
  --ease-out-5: cubic-bezier(0, 0, 0, 1);
@@ -26,9 +27,9 @@
26
27
  --ease-elastic-out-4: cubic-bezier(0.5, 1.5, 0.75, 1.25);
27
28
  --ease-elastic-out-5: cubic-bezier(0.5, 1.75, 0.75, 1.25);
28
29
  --ease-elastic-in-1: cubic-bezier(0.5, -0.25, 0.75, 1);
29
- --ease-elastic-in-2: cubic-bezier(0.5, -0.5, 0.75, 1);
30
+ --ease-elastic-in-2: cubic-bezier(0.5, -0.50, 0.75, 1);
30
31
  --ease-elastic-in-3: cubic-bezier(0.5, -0.75, 0.75, 1);
31
- --ease-elastic-in-4: cubic-bezier(0.5, -1, 0.75, 1);
32
+ --ease-elastic-in-4: cubic-bezier(0.5, -1.00, 0.75, 1);
32
33
  --ease-elastic-in-5: cubic-bezier(0.5, -1.25, 0.75, 1);
33
34
  --ease-elastic-in-out-1: cubic-bezier(0.5, -0.1, 0.1, 1.5);
34
35
  --ease-elastic-in-out-2: cubic-bezier(0.5, -0.3, 0.1, 1.5);
@@ -363,20 +364,55 @@
363
364
  1
364
365
  );
365
366
 
367
+ --easing-entry: cubic-bezier(0.1, 0, 0, 1);
368
+ --easing-exit: cubic-bezier(0.3, 0, 1.0, 0.8);
369
+
366
370
  --transition-duration-instant: 0ms;
367
- --transition-duration-short: 100ms;
368
- --transition-duration-base: 200ms;
369
- --transition-duration-long: 300ms;
371
+
372
+ /* Animation duration based on https://design.brainly.com/8adfd5f36/p/091f75-ux-motion */
373
+
374
+ --transition-duration-quick-1: 80ms; /* e.g. checkbox, radio, hover */
375
+ --transition-duration-quick-2: 120ms; /* e.g. toggle, tab, chip, color, fade */
376
+ --transition-duration-moderate-1: 180ms; /* e.g. dropdown, tooltip */
377
+ --transition-duration-moderate-2: 260ms; /* e.g. modal, toast, dialog, notification */
378
+ --transition-duration-gentle-1: 320ms; /* e.g. bottom sheet, card expand */
379
+ --transition-duration-gentle-2: 420ms; /* e.g. advanced animations */
380
+
381
+ --transition-duration-short: var(--transition-duration-quick-1);
382
+ --transition-duration-base: var(--transition-duration-moderate-1);
383
+ --transition-duration-long: var(--transition-duration-gentle-1);
370
384
  --transition-duration-entry: 0s;
371
385
  --transition-duration-exit: 0s;
372
386
 
373
387
  --transition-target-scale: 0.9;
374
388
 
389
+ /*
390
+ * Calculated animation duration based on https://design.brainly.com/8adfd5f36/p/091f75-ux-motion/t/page-091f75-75547432-5018fa-12
391
+ * Demo: https://codepen.io/T3sT3ro/pen/RNwRLWx
392
+ * unitless
393
+ */
394
+ --animated-element-distance: 0;
395
+ --animated-element-width: 0;
396
+ --animated-element-height: 0;
397
+
398
+ /* Calculated animation duration in milliseconds */
399
+ --transition-duration-calculated: calc(
400
+ (
401
+ 0.5 * var(--animated-element-distance, 0) + 0.35 * var(--animated-element-width, 0) +
402
+ 0.3 * var(--animated-element-height, 0)
403
+ ) *
404
+ 1ms
405
+ );
406
+
375
407
  @media (--motionNotOK) {
408
+ --transition-duration-quick-1: 80ms;
409
+ --transition-duration-quick-2: 120ms;
410
+ --transition-duration-moderate-1: 180ms;
411
+ --transition-duration-moderate-2: 260ms;
412
+ --transition-duration-gentle-1: 320ms;
413
+ --transition-duration-gentle-2: 420ms;
414
+ --transition-duration-calculated: 0;
376
415
  --transition-duration-instant: 0ms;
377
- --transition-duration-short: 0ms;
378
- --transition-duration-base: 0ms;
379
- --transition-duration-long: 0ms;
380
416
  --transition-duration-entry: 0s;
381
417
  --transition-duration-exit: 0s;
382
418
  }
@@ -16,14 +16,8 @@
16
16
  background-repeat: no-repeat;
17
17
  }
18
18
 
19
- @media (prefers-reduced-motion: no-preference) {
20
- :where(:focus-visible) {
21
- transition: outline-offset var(--transition-duration-short) var(--ease-2);
22
- }
23
-
24
- :where(:not(:active):focus-visible) {
25
- transition-duration: var(--transition-duration-base);
26
- }
19
+ :where(:focus-visible) {
20
+ transition: outline-offset var(--transition-duration-quick-1) var(--ease-2);
27
21
  }
28
22
 
29
23
  :where(:not(:active):focus-visible) {
package/transform.js CHANGED
@@ -3,14 +3,7 @@ import { browserslistToTargets, bundle } from 'lightningcss';
3
3
  import fs from 'node:fs';
4
4
 
5
5
  const browserlistTargtsWidelyAvailable = [
6
- 'Chrome > 0 and last 2.5 years',
7
- 'ChromeAndroid > 0 and last 2.5 years',
8
- 'Edge > 0 and last 2.5 years',
9
- 'Firefox > 0 and last 2.5 years',
10
- 'FirefoxAndroid > 0 and last 2.5 years',
11
- 'Safari > 0 and last 2.5 years',
12
- 'iOS > 0 and last 2.5 years',
13
- 'not dead',
6
+ 'extends browserslist-config-baseline',
14
7
  ];
15
8
 
16
9
  const targets = browserslistToTargets(browserslist(browserlistTargtsWidelyAvailable));