@devslab/dds-css 0.25.1 → 0.27.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/README.ko.md +3 -0
- package/README.md +3 -0
- package/dist/components/button.css +49 -3
- package/dist/components/date-picker.css +56 -0
- package/dist/components/iconbutton.css +9 -0
- package/dist/components/spinner.css +15 -1
- package/dist/dds.css +130 -4
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -20,6 +20,9 @@ EmptyState** (BottomSheet은 Dialog의 네이티브 짝 — Phase 3).
|
|
|
20
20
|
- 다크 모드는 공짜: `<html>` 또는 임의 서브트리에 `data-theme="dark"`
|
|
21
21
|
(`data-theme="light"`로 되고정). 어떤 컴포넌트에도 다크 분기가 없습니다.
|
|
22
22
|
- 개별 임포트: `@devslab/dds-css/components/button.css` 등.
|
|
23
|
+
- 진행 중인 버튼(`aria-busy="true"` + `.dds-spinner` 자식)은 크기와 이름을
|
|
24
|
+
그대로 유지합니다. 라벨은 지우지 않고 숨기고, 스피너를 그 위에 겹쳐
|
|
25
|
+
그립니다(D-043).
|
|
23
26
|
- 컴포넌트별 마크업 계약·상태·접근성 체크리스트·do/don't:
|
|
24
27
|
[`docs/components.ko.md`](../../docs/components.ko.md).
|
|
25
28
|
라이브 레퍼런스: `preview/components.html` (먼저 `pnpm build`).
|
package/README.md
CHANGED
|
@@ -21,6 +21,9 @@ the native counterpart of Dialog — Phase 3).
|
|
|
21
21
|
- Dark mode is free: `data-theme="dark"` on `<html>` or any subtree
|
|
22
22
|
(`data-theme="light"` pins back). No component has a dark branch.
|
|
23
23
|
- Per-component imports: `@devslab/dds-css/components/button.css` etc.
|
|
24
|
+
- A loading button (`aria-busy="true"` + a `.dds-spinner` child) keeps its
|
|
25
|
+
size and name: the label is hidden, not removed, and the spinner is drawn
|
|
26
|
+
over it (D-043).
|
|
24
27
|
- Markup contracts, states, accessibility checklists and do/don't per
|
|
25
28
|
component: [`docs/components.md`](../../docs/components.md).
|
|
26
29
|
Live reference: `preview/components.html` (run `pnpm build` first).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Variants: primary / secondary / ghost / danger. Sizes: sm / md(default) / lg.
|
|
3
3
|
* Control heights come from the spacing scale (32/40/48); type from the typo
|
|
4
4
|
* scale (label for sm/md, body-1 size for lg). Loading = aria-busy="true" with
|
|
5
|
-
* a .dds-spinner child. */
|
|
5
|
+
* a .dds-spinner child; the button keeps its size while loading (D-043). */
|
|
6
6
|
|
|
7
7
|
.dds-btn {
|
|
8
8
|
appearance: none;
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
-webkit-tap-highlight-color: transparent;
|
|
30
30
|
white-space: normal;
|
|
31
31
|
overflow-wrap: anywhere;
|
|
32
|
+
/* Containing block for the loading spinner, which is centred over the
|
|
33
|
+
* label rather than placed beside it. Set here, not only while loading,
|
|
34
|
+
* so a consumer's own position (a fixed action button) still wins. */
|
|
35
|
+
position: relative;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
.dds-btn:focus-visible {
|
|
@@ -37,13 +41,36 @@
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
/* opacity is allowed for disabled only (spec §4.2) */
|
|
40
|
-
.dds-btn[disabled]
|
|
41
|
-
.dds-btn[aria-busy="true"] {
|
|
44
|
+
.dds-btn[disabled] {
|
|
42
45
|
opacity: 0.45;
|
|
43
46
|
cursor: not-allowed;
|
|
44
47
|
}
|
|
48
|
+
|
|
49
|
+
/* Loading (D-043). The button keeps the exact box its label gives it, so the
|
|
50
|
+
* controls beside it do not move and a wrapped label does not wrap again
|
|
51
|
+
* when progress starts. The label stays in the layout and in the
|
|
52
|
+
* accessibility tree (its accessible name does not change) but is not
|
|
53
|
+
* painted: the text fill is transparent and element children (icons) are
|
|
54
|
+
* fully transparent. The spinner is taken out of the flow and centred over
|
|
55
|
+
* the label; it keeps the button's text color (currentColor).
|
|
56
|
+
*
|
|
57
|
+
* Not dimmed: the spinner is the only thing painted, and at the disabled
|
|
58
|
+
* 0.45 opacity it drops to about 2:1 against the button (WCAG 1.4.11 asks
|
|
59
|
+
* 3:1). The framework Buttons also set [disabled], so this rule comes after
|
|
60
|
+
* the one above to put the opacity back. */
|
|
45
61
|
.dds-btn[aria-busy="true"] {
|
|
62
|
+
opacity: 1;
|
|
63
|
+
cursor: not-allowed;
|
|
46
64
|
pointer-events: none;
|
|
65
|
+
-webkit-text-fill-color: transparent;
|
|
66
|
+
}
|
|
67
|
+
.dds-btn[aria-busy="true"] > :not(.dds-spinner) {
|
|
68
|
+
opacity: 0;
|
|
69
|
+
}
|
|
70
|
+
.dds-btn[aria-busy="true"] > .dds-spinner {
|
|
71
|
+
position: absolute;
|
|
72
|
+
inset: 0;
|
|
73
|
+
margin: auto;
|
|
47
74
|
}
|
|
48
75
|
|
|
49
76
|
/* variants ---------------------------------------------------------------- */
|
|
@@ -115,3 +142,22 @@
|
|
|
115
142
|
min-block-size: 44px;
|
|
116
143
|
}
|
|
117
144
|
}
|
|
145
|
+
|
|
146
|
+
/* Forced colors repaint every text color, transparent included, so the
|
|
147
|
+
* hidden label would come back on top of the spinner. A loading button opts
|
|
148
|
+
* out and paints itself with system colors: the face of a button, the
|
|
149
|
+
* disabled border, and the spinner in button text. No transition: opted out,
|
|
150
|
+
* the background would fade from the brand color it no longer forces. */
|
|
151
|
+
@media (forced-colors: active) {
|
|
152
|
+
.dds-btn[aria-busy="true"] {
|
|
153
|
+
forced-color-adjust: none;
|
|
154
|
+
background-color: ButtonFace;
|
|
155
|
+
border-color: GrayText;
|
|
156
|
+
color: ButtonText;
|
|
157
|
+
transition: none;
|
|
158
|
+
}
|
|
159
|
+
.dds-btn[aria-busy="true"] > .dds-spinner {
|
|
160
|
+
forced-color-adjust: none;
|
|
161
|
+
color: ButtonText;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* Ark DatePicker interaction with DDS visual tokens. */
|
|
2
|
+
.dds-date-picker-control {display:flex;align-items:stretch;gap:var(--dds-space-8);}
|
|
3
|
+
.dds-date-picker-control input {min-width:0;}
|
|
4
|
+
.dds-date-picker-control .dds-btn {flex-shrink:0;min-width:calc(var(--dds-space-40) + var(--dds-space-4));padding-inline:calc(var(--dds-space-8) + var(--dds-space-2));}
|
|
5
|
+
.dds-date-picker-positioner {z-index:var(--dds-overlay-z-index,1001);}
|
|
6
|
+
.dds-date-picker-content {width:calc(var(--dds-space-40) * 8);max-width:calc(100vw - var(--dds-space-32));max-height:min(calc(100dvh - var(--dds-space-32)),var(--available-height,100dvh));overflow:auto;box-sizing:border-box;padding:var(--dds-space-16);background:var(--dds-color-bg-default);color:var(--dds-color-text-primary);border:calc(var(--dds-space-2) / 2) solid var(--dds-color-border-default);border-radius:var(--dds-radius-md);font-family:var(--dds-font-family-sans);font-size:var(--dds-typo-body-2-font-size);}
|
|
7
|
+
.dds-date-picker-header {display:flex;align-items:center;justify-content:space-between;gap:var(--dds-space-12);font-weight:600;margin-bottom:var(--dds-space-12);}
|
|
8
|
+
.dds-date-picker-table {width:100%;border-collapse:collapse;table-layout:fixed;}
|
|
9
|
+
.dds-date-picker-table th {font-size:var(--dds-space-12);font-weight:500;color:var(--dds-color-text-secondary);height:var(--dds-space-32);}
|
|
10
|
+
.dds-date-picker-table td {padding:0;text-align:center;}
|
|
11
|
+
.dds-date-picker-table [data-part="table-cell-trigger"] {display:flex;align-items:center;justify-content:center;width:100%;height:var(--dds-space-40);border:0;border-radius:var(--dds-radius-sm);font:inherit;color:inherit;background:transparent;cursor:pointer;}
|
|
12
|
+
.dds-date-picker-table [data-part="table-cell-trigger"]:hover {background:var(--dds-color-bg-brand-subtle);}
|
|
13
|
+
.dds-date-picker-table [data-outside-range] {color:var(--dds-color-text-secondary);}
|
|
14
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-selected] {background:var(--dds-color-bg-brand);color:var(--dds-color-text-on-brand);}
|
|
15
|
+
.dds-date-picker-table [data-today]:not([data-selected]) {text-decoration:underline;text-underline-offset:var(--dds-space-4);}
|
|
16
|
+
.dds-date-picker-content :focus-visible {outline:var(--dds-space-2) solid var(--dds-color-text-brand);outline-offset:var(--dds-space-2);}
|
|
17
|
+
.dds-date-picker-footer {display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--dds-space-12);margin-top:var(--dds-space-12);padding-top:var(--dds-space-12);border-top:calc(var(--dds-space-2) / 2) solid var(--dds-color-border-default);}
|
|
18
|
+
|
|
19
|
+
/* Text box shared by DatePicker, MonthPicker and the DateRangePicker pair: same var(--dds-space-40) DDS input look. */
|
|
20
|
+
.dds-date-picker-control > input,.dds-date-range-box {box-sizing:border-box;flex:1;min-inline-size:0;block-size:var(--dds-space-40);border:calc(var(--dds-space-2) / 2) solid var(--dds-color-border-strong);border-radius:var(--dds-radius-md);background:var(--dds-color-bg-default);color:var(--dds-color-text-primary);font-family:inherit;font-size:var(--dds-typo-body-2-font-size);font-variant-numeric:tabular-nums;}
|
|
21
|
+
.dds-date-picker-control > input {padding-inline:var(--dds-space-12);}
|
|
22
|
+
.dds-date-picker-control > input:focus-visible,.dds-date-range-box:focus-within {outline:var(--dds-space-2) solid var(--dds-color-border-focus);outline-offset:0;}
|
|
23
|
+
.dds-date-picker-control > input[aria-invalid="true"],.dds-date-range-box[data-invalid] {border-color:var(--dds-color-status-danger);}
|
|
24
|
+
.dds-date-picker-control > input:disabled,.dds-date-range-box[data-disabled] {opacity:.45;cursor:not-allowed;background:var(--dds-color-bg-subtle);}
|
|
25
|
+
.dds-date-picker-control > input::placeholder,.dds-date-range-input::placeholder {color:var(--dds-color-text-muted);}
|
|
26
|
+
.dds-date-range-box {display:flex;align-items:center;gap:var(--dds-space-8);padding-inline:var(--dds-space-12);}
|
|
27
|
+
.dds-date-range-box[hidden] {display:none;}
|
|
28
|
+
.dds-date-range-input {flex:1;inline-size:100%;min-inline-size:0;block-size:100%;padding:0;border:0;background:transparent;color:inherit;font:inherit;font-variant-numeric:tabular-nums;outline:none;}
|
|
29
|
+
.dds-date-range-input:disabled {cursor:not-allowed;}
|
|
30
|
+
.dds-date-range-separator {flex:none;color:var(--dds-color-text-secondary);}
|
|
31
|
+
.dds-field__error {font-size:var(--dds-typo-caption-font-size);line-height:var(--dds-typo-caption-line-height);color:var(--dds-color-status-danger);}
|
|
32
|
+
@media (pointer:coarse) {.dds-date-picker-control > input,.dds-date-range-box {min-block-size:calc(var(--dds-space-40) + var(--dds-space-4));}}
|
|
33
|
+
|
|
34
|
+
/* Range selection: ends filled, days between tinted, hover previews the end being chosen. */
|
|
35
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-in-range] {background:var(--dds-color-bg-brand-subtle);color:var(--dds-color-text-primary);border-radius:0;}
|
|
36
|
+
.dds-date-picker-table [data-part="table-cell-trigger"]:is([data-range-start],[data-range-end]) {background:var(--dds-color-bg-brand);color:var(--dds-color-text-on-brand);border-radius:var(--dds-radius-sm);}
|
|
37
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-hover-range-end]:not([data-range-start]) {box-shadow:inset 0 0 0 var(--dds-space-2) var(--dds-color-bg-brand);border-radius:var(--dds-radius-sm);}
|
|
38
|
+
.dds-date-picker-presets {display:flex;flex-wrap:wrap;gap:var(--dds-space-8);flex:1 1 100%;}
|
|
39
|
+
.dds-date-picker-presets[hidden] {display:none;}
|
|
40
|
+
.dds-date-picker-footer > [data-part="clear-trigger"] {margin-inline-start:auto;}
|
|
41
|
+
/* Days and months outside min/max read as unavailable, not as ordinary choices. */
|
|
42
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-disabled] {opacity:.45;cursor:not-allowed;background:transparent;}
|
|
43
|
+
|
|
44
|
+
/* Month grid (MonthPicker): 3 columns × 4 rows, year paged in the header. */
|
|
45
|
+
.dds-date-picker-year {font-variant-numeric:tabular-nums;}
|
|
46
|
+
.dds-date-picker-table--months td {padding:var(--dds-space-4);}
|
|
47
|
+
.dds-date-picker-table--months [data-part="table-cell-trigger"] {height:var(--dds-space-40);}
|
|
48
|
+
|
|
49
|
+
/* Standalone Calendar shares the DatePicker view without popup positioning. */
|
|
50
|
+
.dds-calendar {display:block;}
|
|
51
|
+
.dds-date-picker--hidden > .dds-field__label {position:absolute;width:calc(var(--dds-space-2) / 2);height:calc(var(--dds-space-2) / 2);overflow:hidden;clip-path:inset(50%);}
|
|
52
|
+
.dds-date-picker--inside {position:relative;}
|
|
53
|
+
.dds-date-picker--inside > .dds-field__label {position:absolute;inset-inline-start:var(--dds-space-12);inset-block-start:calc(var(--dds-space-16) + var(--dds-space-2));z-index:1;pointer-events:none;}
|
|
54
|
+
.dds-date-picker--inside:focus-within > .dds-field__label,.dds-date-picker--inside[data-filled] > .dds-field__label {inset-block-start:var(--dds-space-2);font-size:var(--dds-typo-caption-font-size);}
|
|
55
|
+
.dds-date-picker--inside .dds-date-picker-control input {height:calc(var(--dds-space-40) + var(--dds-space-16));padding-block:var(--dds-space-20) var(--dds-space-4);}
|
|
56
|
+
.dds-date-picker--inside:not(:focus-within):not([data-filled]) input::placeholder {color:transparent;}
|
|
@@ -38,6 +38,15 @@
|
|
|
38
38
|
cursor: not-allowed;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/* Loading: the framework IconButtons swap the icon for a .dds-spinner, which
|
|
42
|
+
* the fixed box already centres. Same rule as .dds-btn (D-043): not dimmed,
|
|
43
|
+
* because a 0.45 spinner falls below 3:1 (danger is about 2.3:1). */
|
|
44
|
+
.dds-iconbtn[aria-busy="true"] {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
cursor: not-allowed;
|
|
47
|
+
pointer-events: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
41
50
|
/* variants ---------------------------------------------------------------- */
|
|
42
51
|
|
|
43
52
|
.dds-iconbtn--secondary {
|
|
@@ -27,8 +27,22 @@
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/* base.css stops every dds- animation after one 0.01ms run under reduced
|
|
31
|
+
* motion. The :root prefix ties its specificity and this file loads after
|
|
32
|
+
* base.css, so the spinner keeps turning, at half speed, instead of freezing. */
|
|
30
33
|
@media (prefers-reduced-motion: reduce) {
|
|
31
|
-
.dds-spinner {
|
|
34
|
+
:root .dds-spinner {
|
|
32
35
|
animation-duration: 1600ms;
|
|
36
|
+
animation-iteration-count: infinite;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* Forced colors repaint the transparent top border too, which closes the gap
|
|
41
|
+
* and leaves a ring that looks still. Opt out and paint it in the system text
|
|
42
|
+
* color (a loading button sets ButtonText instead, button.css). */
|
|
43
|
+
@media (forced-colors: active) {
|
|
44
|
+
.dds-spinner {
|
|
45
|
+
forced-color-adjust: none;
|
|
46
|
+
color: CanvasText;
|
|
33
47
|
}
|
|
34
48
|
}
|
package/dist/dds.css
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
* Variants: primary / secondary / ghost / danger. Sizes: sm / md(default) / lg.
|
|
53
53
|
* Control heights come from the spacing scale (32/40/48); type from the typo
|
|
54
54
|
* scale (label for sm/md, body-1 size for lg). Loading = aria-busy="true" with
|
|
55
|
-
* a .dds-spinner child. */
|
|
55
|
+
* a .dds-spinner child; the button keeps its size while loading (D-043). */
|
|
56
56
|
|
|
57
57
|
.dds-btn {
|
|
58
58
|
appearance: none;
|
|
@@ -79,6 +79,10 @@
|
|
|
79
79
|
-webkit-tap-highlight-color: transparent;
|
|
80
80
|
white-space: normal;
|
|
81
81
|
overflow-wrap: anywhere;
|
|
82
|
+
/* Containing block for the loading spinner, which is centred over the
|
|
83
|
+
* label rather than placed beside it. Set here, not only while loading,
|
|
84
|
+
* so a consumer's own position (a fixed action button) still wins. */
|
|
85
|
+
position: relative;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
.dds-btn:focus-visible {
|
|
@@ -87,13 +91,36 @@
|
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
/* opacity is allowed for disabled only (spec §4.2) */
|
|
90
|
-
.dds-btn[disabled]
|
|
91
|
-
.dds-btn[aria-busy="true"] {
|
|
94
|
+
.dds-btn[disabled] {
|
|
92
95
|
opacity: 0.45;
|
|
93
96
|
cursor: not-allowed;
|
|
94
97
|
}
|
|
98
|
+
|
|
99
|
+
/* Loading (D-043). The button keeps the exact box its label gives it, so the
|
|
100
|
+
* controls beside it do not move and a wrapped label does not wrap again
|
|
101
|
+
* when progress starts. The label stays in the layout and in the
|
|
102
|
+
* accessibility tree (its accessible name does not change) but is not
|
|
103
|
+
* painted: the text fill is transparent and element children (icons) are
|
|
104
|
+
* fully transparent. The spinner is taken out of the flow and centred over
|
|
105
|
+
* the label; it keeps the button's text color (currentColor).
|
|
106
|
+
*
|
|
107
|
+
* Not dimmed: the spinner is the only thing painted, and at the disabled
|
|
108
|
+
* 0.45 opacity it drops to about 2:1 against the button (WCAG 1.4.11 asks
|
|
109
|
+
* 3:1). The framework Buttons also set [disabled], so this rule comes after
|
|
110
|
+
* the one above to put the opacity back. */
|
|
95
111
|
.dds-btn[aria-busy="true"] {
|
|
112
|
+
opacity: 1;
|
|
113
|
+
cursor: not-allowed;
|
|
96
114
|
pointer-events: none;
|
|
115
|
+
-webkit-text-fill-color: transparent;
|
|
116
|
+
}
|
|
117
|
+
.dds-btn[aria-busy="true"] > :not(.dds-spinner) {
|
|
118
|
+
opacity: 0;
|
|
119
|
+
}
|
|
120
|
+
.dds-btn[aria-busy="true"] > .dds-spinner {
|
|
121
|
+
position: absolute;
|
|
122
|
+
inset: 0;
|
|
123
|
+
margin: auto;
|
|
97
124
|
}
|
|
98
125
|
|
|
99
126
|
/* variants ---------------------------------------------------------------- */
|
|
@@ -166,6 +193,25 @@
|
|
|
166
193
|
}
|
|
167
194
|
}
|
|
168
195
|
|
|
196
|
+
/* Forced colors repaint every text color, transparent included, so the
|
|
197
|
+
* hidden label would come back on top of the spinner. A loading button opts
|
|
198
|
+
* out and paints itself with system colors: the face of a button, the
|
|
199
|
+
* disabled border, and the spinner in button text. No transition: opted out,
|
|
200
|
+
* the background would fade from the brand color it no longer forces. */
|
|
201
|
+
@media (forced-colors: active) {
|
|
202
|
+
.dds-btn[aria-busy="true"] {
|
|
203
|
+
forced-color-adjust: none;
|
|
204
|
+
background-color: ButtonFace;
|
|
205
|
+
border-color: GrayText;
|
|
206
|
+
color: ButtonText;
|
|
207
|
+
transition: none;
|
|
208
|
+
}
|
|
209
|
+
.dds-btn[aria-busy="true"] > .dds-spinner {
|
|
210
|
+
forced-color-adjust: none;
|
|
211
|
+
color: ButtonText;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
169
215
|
/* IconButton — a Button whose only content is an icon (spec §4.3 v1 inventory).
|
|
170
216
|
* Same state set and sizes as .dds-btn (32/40/48 from the spacing scale) so an
|
|
171
217
|
* icon button never lands a few px off the text button next to it — the row
|
|
@@ -206,6 +252,15 @@
|
|
|
206
252
|
cursor: not-allowed;
|
|
207
253
|
}
|
|
208
254
|
|
|
255
|
+
/* Loading: the framework IconButtons swap the icon for a .dds-spinner, which
|
|
256
|
+
* the fixed box already centres. Same rule as .dds-btn (D-043): not dimmed,
|
|
257
|
+
* because a 0.45 spinner falls below 3:1 (danger is about 2.3:1). */
|
|
258
|
+
.dds-iconbtn[aria-busy="true"] {
|
|
259
|
+
opacity: 1;
|
|
260
|
+
cursor: not-allowed;
|
|
261
|
+
pointer-events: none;
|
|
262
|
+
}
|
|
263
|
+
|
|
209
264
|
/* variants ---------------------------------------------------------------- */
|
|
210
265
|
|
|
211
266
|
.dds-iconbtn--secondary {
|
|
@@ -467,6 +522,63 @@
|
|
|
467
522
|
.dds-choice[data-disabled] {opacity:.45;}
|
|
468
523
|
@media(pointer:coarse){.dds-choice-input,.dds-choice-trigger,.dds-choice-clear {min-block-size:44px;min-inline-size:44px;}}
|
|
469
524
|
|
|
525
|
+
/* Ark DatePicker interaction with DDS visual tokens. */
|
|
526
|
+
.dds-date-picker-control {display:flex;align-items:stretch;gap:var(--dds-space-8);}
|
|
527
|
+
.dds-date-picker-control input {min-width:0;}
|
|
528
|
+
.dds-date-picker-control .dds-btn {flex-shrink:0;min-width:calc(var(--dds-space-40) + var(--dds-space-4));padding-inline:calc(var(--dds-space-8) + var(--dds-space-2));}
|
|
529
|
+
.dds-date-picker-positioner {z-index:var(--dds-overlay-z-index,1001);}
|
|
530
|
+
.dds-date-picker-content {width:calc(var(--dds-space-40) * 8);max-width:calc(100vw - var(--dds-space-32));max-height:min(calc(100dvh - var(--dds-space-32)),var(--available-height,100dvh));overflow:auto;box-sizing:border-box;padding:var(--dds-space-16);background:var(--dds-color-bg-default);color:var(--dds-color-text-primary);border:calc(var(--dds-space-2) / 2) solid var(--dds-color-border-default);border-radius:var(--dds-radius-md);font-family:var(--dds-font-family-sans);font-size:var(--dds-typo-body-2-font-size);}
|
|
531
|
+
.dds-date-picker-header {display:flex;align-items:center;justify-content:space-between;gap:var(--dds-space-12);font-weight:600;margin-bottom:var(--dds-space-12);}
|
|
532
|
+
.dds-date-picker-table {width:100%;border-collapse:collapse;table-layout:fixed;}
|
|
533
|
+
.dds-date-picker-table th {font-size:var(--dds-space-12);font-weight:500;color:var(--dds-color-text-secondary);height:var(--dds-space-32);}
|
|
534
|
+
.dds-date-picker-table td {padding:0;text-align:center;}
|
|
535
|
+
.dds-date-picker-table [data-part="table-cell-trigger"] {display:flex;align-items:center;justify-content:center;width:100%;height:var(--dds-space-40);border:0;border-radius:var(--dds-radius-sm);font:inherit;color:inherit;background:transparent;cursor:pointer;}
|
|
536
|
+
.dds-date-picker-table [data-part="table-cell-trigger"]:hover {background:var(--dds-color-bg-brand-subtle);}
|
|
537
|
+
.dds-date-picker-table [data-outside-range] {color:var(--dds-color-text-secondary);}
|
|
538
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-selected] {background:var(--dds-color-bg-brand);color:var(--dds-color-text-on-brand);}
|
|
539
|
+
.dds-date-picker-table [data-today]:not([data-selected]) {text-decoration:underline;text-underline-offset:var(--dds-space-4);}
|
|
540
|
+
.dds-date-picker-content :focus-visible {outline:var(--dds-space-2) solid var(--dds-color-text-brand);outline-offset:var(--dds-space-2);}
|
|
541
|
+
.dds-date-picker-footer {display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--dds-space-12);margin-top:var(--dds-space-12);padding-top:var(--dds-space-12);border-top:calc(var(--dds-space-2) / 2) solid var(--dds-color-border-default);}
|
|
542
|
+
|
|
543
|
+
/* Text box shared by DatePicker, MonthPicker and the DateRangePicker pair: same var(--dds-space-40) DDS input look. */
|
|
544
|
+
.dds-date-picker-control > input,.dds-date-range-box {box-sizing:border-box;flex:1;min-inline-size:0;block-size:var(--dds-space-40);border:calc(var(--dds-space-2) / 2) solid var(--dds-color-border-strong);border-radius:var(--dds-radius-md);background:var(--dds-color-bg-default);color:var(--dds-color-text-primary);font-family:inherit;font-size:var(--dds-typo-body-2-font-size);font-variant-numeric:tabular-nums;}
|
|
545
|
+
.dds-date-picker-control > input {padding-inline:var(--dds-space-12);}
|
|
546
|
+
.dds-date-picker-control > input:focus-visible,.dds-date-range-box:focus-within {outline:var(--dds-space-2) solid var(--dds-color-border-focus);outline-offset:0;}
|
|
547
|
+
.dds-date-picker-control > input[aria-invalid="true"],.dds-date-range-box[data-invalid] {border-color:var(--dds-color-status-danger);}
|
|
548
|
+
.dds-date-picker-control > input:disabled,.dds-date-range-box[data-disabled] {opacity:.45;cursor:not-allowed;background:var(--dds-color-bg-subtle);}
|
|
549
|
+
.dds-date-picker-control > input::placeholder,.dds-date-range-input::placeholder {color:var(--dds-color-text-muted);}
|
|
550
|
+
.dds-date-range-box {display:flex;align-items:center;gap:var(--dds-space-8);padding-inline:var(--dds-space-12);}
|
|
551
|
+
.dds-date-range-box[hidden] {display:none;}
|
|
552
|
+
.dds-date-range-input {flex:1;inline-size:100%;min-inline-size:0;block-size:100%;padding:0;border:0;background:transparent;color:inherit;font:inherit;font-variant-numeric:tabular-nums;outline:none;}
|
|
553
|
+
.dds-date-range-input:disabled {cursor:not-allowed;}
|
|
554
|
+
.dds-date-range-separator {flex:none;color:var(--dds-color-text-secondary);}
|
|
555
|
+
.dds-field__error {font-size:var(--dds-typo-caption-font-size);line-height:var(--dds-typo-caption-line-height);color:var(--dds-color-status-danger);}
|
|
556
|
+
@media (pointer:coarse) {.dds-date-picker-control > input,.dds-date-range-box {min-block-size:calc(var(--dds-space-40) + var(--dds-space-4));}}
|
|
557
|
+
|
|
558
|
+
/* Range selection: ends filled, days between tinted, hover previews the end being chosen. */
|
|
559
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-in-range] {background:var(--dds-color-bg-brand-subtle);color:var(--dds-color-text-primary);border-radius:0;}
|
|
560
|
+
.dds-date-picker-table [data-part="table-cell-trigger"]:is([data-range-start],[data-range-end]) {background:var(--dds-color-bg-brand);color:var(--dds-color-text-on-brand);border-radius:var(--dds-radius-sm);}
|
|
561
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-hover-range-end]:not([data-range-start]) {box-shadow:inset 0 0 0 var(--dds-space-2) var(--dds-color-bg-brand);border-radius:var(--dds-radius-sm);}
|
|
562
|
+
.dds-date-picker-presets {display:flex;flex-wrap:wrap;gap:var(--dds-space-8);flex:1 1 100%;}
|
|
563
|
+
.dds-date-picker-presets[hidden] {display:none;}
|
|
564
|
+
.dds-date-picker-footer > [data-part="clear-trigger"] {margin-inline-start:auto;}
|
|
565
|
+
/* Days and months outside min/max read as unavailable, not as ordinary choices. */
|
|
566
|
+
.dds-date-picker-table [data-part="table-cell-trigger"][data-disabled] {opacity:.45;cursor:not-allowed;background:transparent;}
|
|
567
|
+
|
|
568
|
+
/* Month grid (MonthPicker): 3 columns × 4 rows, year paged in the header. */
|
|
569
|
+
.dds-date-picker-year {font-variant-numeric:tabular-nums;}
|
|
570
|
+
.dds-date-picker-table--months td {padding:var(--dds-space-4);}
|
|
571
|
+
.dds-date-picker-table--months [data-part="table-cell-trigger"] {height:var(--dds-space-40);}
|
|
572
|
+
|
|
573
|
+
/* Standalone Calendar shares the DatePicker view without popup positioning. */
|
|
574
|
+
.dds-calendar {display:block;}
|
|
575
|
+
.dds-date-picker--hidden > .dds-field__label {position:absolute;width:calc(var(--dds-space-2) / 2);height:calc(var(--dds-space-2) / 2);overflow:hidden;clip-path:inset(50%);}
|
|
576
|
+
.dds-date-picker--inside {position:relative;}
|
|
577
|
+
.dds-date-picker--inside > .dds-field__label {position:absolute;inset-inline-start:var(--dds-space-12);inset-block-start:calc(var(--dds-space-16) + var(--dds-space-2));z-index:1;pointer-events:none;}
|
|
578
|
+
.dds-date-picker--inside:focus-within > .dds-field__label,.dds-date-picker--inside[data-filled] > .dds-field__label {inset-block-start:var(--dds-space-2);font-size:var(--dds-typo-caption-font-size);}
|
|
579
|
+
.dds-date-picker--inside .dds-date-picker-control input {height:calc(var(--dds-space-40) + var(--dds-space-16));padding-block:var(--dds-space-20) var(--dds-space-4);}
|
|
580
|
+
.dds-date-picker--inside:not(:focus-within):not([data-filled]) input::placeholder {color:transparent;}
|
|
581
|
+
|
|
470
582
|
/* TimePicker: the Combobox structure from choice.css (same 40px control, list
|
|
471
583
|
* and focus), with fixed-width digits and a clock button instead of the caret. */
|
|
472
584
|
.dds-time-picker .dds-choice-input,.dds-time-picker .dds-choice-item {font-variant-numeric:tabular-nums;}
|
|
@@ -1129,9 +1241,23 @@
|
|
|
1129
1241
|
}
|
|
1130
1242
|
}
|
|
1131
1243
|
|
|
1244
|
+
/* base.css stops every dds- animation after one 0.01ms run under reduced
|
|
1245
|
+
* motion. The :root prefix ties its specificity and this file loads after
|
|
1246
|
+
* base.css, so the spinner keeps turning, at half speed, instead of freezing. */
|
|
1132
1247
|
@media (prefers-reduced-motion: reduce) {
|
|
1133
|
-
.dds-spinner {
|
|
1248
|
+
:root .dds-spinner {
|
|
1134
1249
|
animation-duration: 1600ms;
|
|
1250
|
+
animation-iteration-count: infinite;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/* Forced colors repaint the transparent top border too, which closes the gap
|
|
1255
|
+
* and leaves a ring that looks still. Opt out and paint it in the system text
|
|
1256
|
+
* color (a loading button sets ButtonText instead, button.css). */
|
|
1257
|
+
@media (forced-colors: active) {
|
|
1258
|
+
.dds-spinner {
|
|
1259
|
+
forced-color-adjust: none;
|
|
1260
|
+
color: CanvasText;
|
|
1135
1261
|
}
|
|
1136
1262
|
}
|
|
1137
1263
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devslab/dds-css",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "DDS CSS component layer — class-based, framework-neutral, semantic-token-only (spec §4.3 v1 inventory, 20 components)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|