@surflane/ui 0.10.0 → 0.11.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/dist/css/rules/date-picker.css +10 -3
- package/dist/css/rules/field-control.css +7 -0
- package/dist/css/rules/fieldset.css +3 -1
- package/dist/css/rules/input-group.css +15 -0
- package/dist/css/rules/otp-field.css +7 -4
- package/dist/css/rules/skeleton.css +9 -2
- package/dist/css/rules/slider.css +4 -2
- package/dist/file-upload.js +3 -1
- package/package.json +3 -3
|
@@ -50,13 +50,20 @@
|
|
|
50
50
|
.surf-date-group:hover {
|
|
51
51
|
border-color: var(--surf-status-danger-fg);
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
53
|
+
/* Disabled fades the field, as in every other field: the label and the reason
|
|
54
|
+
beside it stay readable. */
|
|
56
55
|
:is(.surf-date-picker, .surf-time-field)[data-disabled] .surf-date-group {
|
|
56
|
+
opacity: var(--surf-control-disabled-opacity);
|
|
57
57
|
cursor: not-allowed;
|
|
58
58
|
background: var(--surf-control-disabled-background);
|
|
59
59
|
}
|
|
60
|
+
/* Read-only shows a value, not a box to type in: it sits on the surface plane
|
|
61
|
+
without the field's border, as text fields do. */
|
|
62
|
+
:is(.surf-date-picker, .surf-time-field)[data-readonly]:not([data-invalid])
|
|
63
|
+
.surf-date-group:not([data-focus-within], :focus-within) {
|
|
64
|
+
border-color: transparent;
|
|
65
|
+
background: var(--surf-surface);
|
|
66
|
+
}
|
|
60
67
|
.surf-date-input {
|
|
61
68
|
display: flex;
|
|
62
69
|
align-items: center;
|
|
@@ -62,6 +62,13 @@
|
|
|
62
62
|
cursor: not-allowed;
|
|
63
63
|
background: var(--surf-control-disabled-background);
|
|
64
64
|
}
|
|
65
|
+
/* Read-only shows a value, not a box to type in: the value sits on the surface
|
|
66
|
+
plane without the field's border. Its text stays at full ink, apart from a
|
|
67
|
+
disabled field, and focus still rings it, so the value stays copyable. */
|
|
68
|
+
.surf-input[readonly]:not(:focus, [aria-invalid='true']) {
|
|
69
|
+
border-color: transparent;
|
|
70
|
+
background: var(--surf-surface);
|
|
71
|
+
}
|
|
65
72
|
/* An invalid field keeps its edge while hovered; hover still tints the fill. */
|
|
66
73
|
.surf-input[aria-invalid='true'],
|
|
67
74
|
.surf-input[aria-invalid='true']:hover,
|
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
flex-direction: column;
|
|
13
13
|
gap: var(--surf-space-4);
|
|
14
14
|
}
|
|
15
|
+
/* Base UI renders the legend as a div, a flex item, so the fieldset's gap alone
|
|
16
|
+
spaces it from the first field. A margin added to that gap and left the legend
|
|
17
|
+
closer to the group above it than to its own fields. */
|
|
15
18
|
.surf-fieldset-legend {
|
|
16
19
|
padding: 0;
|
|
17
|
-
margin-bottom: var(--surf-space-4);
|
|
18
20
|
color: var(--surf-ink);
|
|
19
21
|
font: var(--surf-weight-medium)
|
|
20
22
|
var(--surf-type-subsection-size)/var(--surf-type-subsection-leading)
|
|
@@ -24,6 +24,15 @@
|
|
|
24
24
|
border-color: var(--surf-control-hover-border);
|
|
25
25
|
background: var(--surf-control-hover-background);
|
|
26
26
|
}
|
|
27
|
+
/* Read-only shows a value on the surface plane, without the field's border, as
|
|
28
|
+
text fields do. */
|
|
29
|
+
:is(.surf-combobox-group, .surf-number-group)[data-readonly]:not(
|
|
30
|
+
:focus-within,
|
|
31
|
+
[data-invalid]
|
|
32
|
+
) {
|
|
33
|
+
border-color: transparent;
|
|
34
|
+
background: var(--surf-surface);
|
|
35
|
+
}
|
|
27
36
|
.surf-combobox-group:focus-within,
|
|
28
37
|
.surf-number-group:focus-within {
|
|
29
38
|
border-color: var(--surf-control-focus);
|
|
@@ -63,6 +72,12 @@
|
|
|
63
72
|
opacity: var(--surf-control-disabled-opacity);
|
|
64
73
|
cursor: not-allowed;
|
|
65
74
|
}
|
|
75
|
+
/* A read-only field keeps its value readable and copyable, but its steppers do
|
|
76
|
+
nothing, so they fade like a disabled one's. */
|
|
77
|
+
.surf-number-step[data-readonly] {
|
|
78
|
+
opacity: var(--surf-control-disabled-opacity);
|
|
79
|
+
cursor: default;
|
|
80
|
+
}
|
|
66
81
|
.surf-combobox-group[data-invalid],
|
|
67
82
|
.surf-number-group[data-invalid] {
|
|
68
83
|
border-color: var(--surf-status-danger-fg);
|
|
@@ -29,12 +29,15 @@
|
|
|
29
29
|
font-variant-numeric: tabular-nums;
|
|
30
30
|
caret-color: var(--surf-control-focus);
|
|
31
31
|
}
|
|
32
|
+
/* A short dash, as a code is written elsewhere (481-920): muted ink, weaker than
|
|
33
|
+
the digits and the boxes but plainly there. */
|
|
32
34
|
.surf-otp-separator {
|
|
33
35
|
flex: none;
|
|
34
|
-
width: var(--surf-space-
|
|
35
|
-
height:
|
|
36
|
+
width: var(--surf-space-3);
|
|
37
|
+
height: 2px;
|
|
36
38
|
border: 0;
|
|
37
|
-
border-
|
|
39
|
+
border-radius: var(--surf-radius-full);
|
|
40
|
+
background: var(--surf-ink-muted);
|
|
38
41
|
}
|
|
39
42
|
@media (max-width: 760px) {
|
|
40
43
|
.surf-otp-field,
|
|
@@ -56,7 +59,7 @@
|
|
|
56
59
|
border-color: LinkText;
|
|
57
60
|
}
|
|
58
61
|
.surf-otp-separator {
|
|
59
|
-
|
|
62
|
+
background: CanvasText;
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
}
|
|
@@ -9,8 +9,15 @@
|
|
|
9
9
|
width: 100%;
|
|
10
10
|
height: 1em;
|
|
11
11
|
border-radius: var(--surf-radius-sm);
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/* Its own tokens: --surf-surface is about 1.07:1 on a light canvas, and a pulse
|
|
13
|
+
through opacity faded it further. The pulse moves between the two shades. */
|
|
14
|
+
background: var(--surf-skeleton-base);
|
|
15
|
+
animation: surf-skeleton-pulse 1.4s ease-in-out infinite;
|
|
16
|
+
}
|
|
17
|
+
@keyframes surf-skeleton-pulse {
|
|
18
|
+
50% {
|
|
19
|
+
background-color: var(--surf-skeleton-highlight);
|
|
20
|
+
}
|
|
14
21
|
}
|
|
15
22
|
.surf-skeleton[data-shape='block'] {
|
|
16
23
|
height: 96px;
|
|
@@ -38,12 +38,14 @@
|
|
|
38
38
|
}
|
|
39
39
|
.surf-slider-track {
|
|
40
40
|
width: 100%;
|
|
41
|
-
height:
|
|
41
|
+
height: var(--surf-size-slider-track-default);
|
|
42
42
|
border-radius: var(--surf-radius-full);
|
|
43
43
|
background: var(--surf-slider-track);
|
|
44
44
|
}
|
|
45
|
+
/* The pair Progress uses: a brand-mark fill on the surface track, 3:1 against both
|
|
46
|
+
the track and the sheet in either theme. */
|
|
45
47
|
.surf-slider-indicator {
|
|
46
|
-
background: var(--surf-brand);
|
|
48
|
+
background: var(--surf-brand-mark);
|
|
47
49
|
border-radius: inherit;
|
|
48
50
|
}
|
|
49
51
|
.surf-slider-thumb {
|
package/dist/file-upload.js
CHANGED
|
@@ -55,6 +55,8 @@ function accepts(file, accept) {
|
|
|
55
55
|
export const FileUpload = function FileUpload({ label, description, name, form, accept = '', capture, multiple = false, required = false, maxFiles = Infinity, maxFileSize = Infinity, files: controlled, defaultFiles = [], onFilesChange, onReject, transport, getUploadError, labels: customLabels, disabled = false, className, onDragEnter, onDragLeave, onDragOver, onDrop, ref: forwardedRef, ...props }) {
|
|
56
56
|
const labels = {
|
|
57
57
|
...labelsDefault,
|
|
58
|
+
// A field that takes one file says so.
|
|
59
|
+
...(!multiple && { choose: 'Choose file', drop: 'or drop a file here' }),
|
|
58
60
|
...customLabels,
|
|
59
61
|
status: { ...labelsDefault.status, ...customLabels?.status },
|
|
60
62
|
};
|
|
@@ -271,7 +273,7 @@ export const FileUpload = function FileUpload({ label, description, name, form,
|
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
const hasFiles = (event) => Array.from(event.dataTransfer.types).includes('Files');
|
|
274
|
-
return (_jsxs(Field.Root, { ...props, ref: ref, name: name, disabled: disabled, className: skin('surf-
|
|
276
|
+
return (_jsxs(Field.Root, { ...props, ref: ref, name: name, disabled: disabled, className: skin('surf-file-upload', className), "data-dragging": dragging || undefined, children: [_jsx(Field.Label, { children: label }), description != null && description !== false && (_jsx(Field.Description, { children: description })), _jsxs("div", { className: 'surf-file-dropzone', onDragEnter: (event) => {
|
|
275
277
|
onDragEnter?.(event);
|
|
276
278
|
if (!event.defaultPrevented && hasFiles(event) && !disabled) {
|
|
277
279
|
event.preventDefault();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@surflane/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Surflane React components built on Base UI, with data, chart, code and Markdown components.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-system",
|
|
@@ -406,8 +406,8 @@
|
|
|
406
406
|
"@base-ui/react": "^1.9.0",
|
|
407
407
|
"@headless-tree/core": "^1.8.0",
|
|
408
408
|
"@headless-tree/react": "^1.8.0",
|
|
409
|
-
"@surflane/css": "^0.
|
|
410
|
-
"@surflane/design-tokens": "^0.
|
|
409
|
+
"@surflane/css": "^0.11.0",
|
|
410
|
+
"@surflane/design-tokens": "^0.11.0",
|
|
411
411
|
"@tanstack/react-virtual": "^3.14.21",
|
|
412
412
|
"react": "^19.0.0",
|
|
413
413
|
"react-aria-components": "^1.22.1",
|