@devslab/dds-css 0.22.1 → 0.24.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.
@@ -2,7 +2,8 @@
2
2
  .dds-choice-label {font-size:var(--dds-typo-label-font-size);line-height:var(--dds-typo-label-line-height);font-weight:var(--dds-typo-label-font-weight);}
3
3
  .dds-choice-control {position:relative;display:flex;align-items:center;inline-size:100%;min-block-size:var(--dds-space-40);border:1px solid var(--dds-color-border-strong);border-radius:var(--dds-radius-md);background:var(--dds-color-bg-default);}
4
4
  .dds-choice-control:focus-within {outline:var(--dds-space-2) solid var(--dds-color-border-focus);}
5
- .dds-choice-input,.dds-choice-trigger {box-sizing:border-box;min-inline-size:0;min-block-size:var(--dds-space-40);border:0;background:transparent;color:inherit;font:inherit;padding-inline:var(--dds-space-12);}
5
+ /* The control owns the 40px height (border included, like Input and DatePicker); parts stretch inside it. */
6
+ .dds-choice-input,.dds-choice-trigger {box-sizing:border-box;align-self:stretch;min-inline-size:0;min-block-size:0;border:0;background:transparent;color:inherit;font:inherit;padding-inline:var(--dds-space-12);}
6
7
  .dds-choice-input {flex:1;inline-size:100%;outline:none;}
7
8
  .dds-choice-trigger {cursor:pointer;text-align:start;}
8
9
  .dds-choice-control > .dds-choice-trigger:first-child {inline-size:100%;}
@@ -14,7 +15,8 @@
14
15
  .dds-choice-item[data-disabled] {opacity:.45;cursor:not-allowed;}
15
16
  .dds-choice-description {font-size:var(--dds-typo-caption-font-size);color:var(--dds-color-text-secondary);overflow:hidden;text-overflow:ellipsis;}
16
17
  .dds-choice-status {padding:var(--dds-space-12);color:var(--dds-color-text-secondary);}
17
- .dds-choice-status:empty {padding:0;}
18
+ /* Out of flow while empty so the field is as tall as Input (no stray gap); still in the tree as a live region. */
19
+ .dds-choice-status:empty {position:absolute;padding:0;}
18
20
  .dds-choice-validation {position:absolute;inline-size:1px;block-size:1px;padding:0;border:0;clip-path:inset(50%);overflow:hidden;}
19
21
  .dds-choice[data-label-placement="hidden"] .dds-choice-label {position:absolute;inline-size:1px;block-size:1px;clip-path:inset(50%);overflow:hidden;white-space:nowrap;}
20
22
  .dds-choice[data-label-placement="inside"] .dds-choice-label {position:absolute;z-index:1;inset-inline-start:var(--dds-space-12);inset-block-start:var(--dds-space-20);pointer-events:none;color:var(--dds-color-text-secondary);}
@@ -0,0 +1,139 @@
1
+ /* NumberInput — a localized number field. The bordered control has the
2
+ * same 40px outer box, border, radius and whole-control focus ring as Input
3
+ * and SelectPicker. Digits sit at the end with tabular figures; an optional
4
+ * unit (원, 개, 분) and the − / + steppers sit inside the control after them,
5
+ * so neither can overlap the digits. */
6
+
7
+ .dds-number-input {
8
+ position: relative;
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--dds-space-4);
12
+ min-inline-size: 0;
13
+ font-family: var(--dds-font-family-sans);
14
+ font-size: var(--dds-typo-body-2-font-size);
15
+ color: var(--dds-color-text-primary);
16
+ }
17
+ .dds-number-input[hidden] {
18
+ display: none;
19
+ }
20
+
21
+ .dds-number-input__label {
22
+ font-size: var(--dds-typo-label-font-size);
23
+ line-height: var(--dds-typo-label-line-height);
24
+ font-weight: var(--dds-typo-label-font-weight);
25
+ }
26
+ .dds-number-input[data-label-placement="hidden"] .dds-number-input__label {
27
+ position: absolute;
28
+ inline-size: 1px;
29
+ block-size: 1px;
30
+ padding: 0;
31
+ margin: -1px;
32
+ overflow: hidden;
33
+ clip-path: inset(50%);
34
+ white-space: nowrap;
35
+ }
36
+
37
+ .dds-number-input__control {
38
+ display: flex;
39
+ align-items: stretch;
40
+ inline-size: 100%;
41
+ min-inline-size: 0;
42
+ block-size: var(--dds-space-40);
43
+ border: 1px solid var(--dds-color-border-strong);
44
+ border-radius: var(--dds-radius-md);
45
+ background: var(--dds-color-bg-default);
46
+ overflow: hidden;
47
+ }
48
+ .dds-number-input__control:focus-within {
49
+ outline: var(--dds-space-2) solid var(--dds-color-border-focus);
50
+ }
51
+ .dds-number-input__control[data-invalid] {
52
+ border-color: var(--dds-color-status-danger);
53
+ }
54
+
55
+ .dds-number-input__field {
56
+ flex: 1 1 auto;
57
+ min-inline-size: 0;
58
+ inline-size: 100%;
59
+ padding-inline: var(--dds-space-12);
60
+ border: 0;
61
+ background: transparent;
62
+ color: inherit;
63
+ font: inherit;
64
+ font-variant-numeric: tabular-nums;
65
+ text-align: end;
66
+ outline: none;
67
+ }
68
+ .dds-number-input__field::placeholder {
69
+ color: var(--dds-color-text-muted);
70
+ }
71
+ .dds-number-input__control:has(.dds-number-input__suffix) .dds-number-input__field {
72
+ padding-inline-end: var(--dds-space-4);
73
+ }
74
+
75
+ .dds-number-input__suffix {
76
+ display: flex;
77
+ align-items: center;
78
+ flex: none;
79
+ padding-inline-end: var(--dds-space-12);
80
+ color: var(--dds-color-text-secondary);
81
+ white-space: nowrap;
82
+ }
83
+
84
+ .dds-number-input__steppers {
85
+ display: flex;
86
+ flex: none;
87
+ border-inline-start: 1px solid var(--dds-color-border-default);
88
+ }
89
+
90
+ .dds-number-input__step {
91
+ display: grid;
92
+ place-items: center;
93
+ inline-size: var(--dds-space-32);
94
+ padding: 0;
95
+ border: 0;
96
+ background: transparent;
97
+ color: var(--dds-color-text-secondary);
98
+ font: inherit;
99
+ cursor: pointer;
100
+ -webkit-tap-highlight-color: transparent;
101
+ }
102
+ .dds-number-input__step + .dds-number-input__step {
103
+ border-inline-start: 1px solid var(--dds-color-border-default);
104
+ }
105
+ .dds-number-input__step:not([disabled]):hover {
106
+ background: var(--dds-color-overlay-hover-tint);
107
+ color: var(--dds-color-text-primary);
108
+ }
109
+ .dds-number-input__step:not([disabled]):active {
110
+ background: var(--dds-color-overlay-pressed-tint);
111
+ }
112
+ /* opacity is allowed for disabled only (spec §4.2) */
113
+ .dds-number-input__step[disabled] {
114
+ opacity: 0.45;
115
+ cursor: not-allowed;
116
+ }
117
+
118
+ .dds-number-input[data-disabled] {
119
+ opacity: 0.45;
120
+ }
121
+ .dds-number-input[data-disabled] .dds-number-input__control {
122
+ background: var(--dds-color-bg-subtle);
123
+ cursor: not-allowed;
124
+ }
125
+ .dds-number-input[data-disabled] .dds-number-input__step[disabled] {
126
+ opacity: 1;
127
+ }
128
+ .dds-number-input[data-readonly] .dds-number-input__control {
129
+ background: var(--dds-color-bg-subtle);
130
+ }
131
+
132
+ @media (pointer: coarse) {
133
+ .dds-number-input__control {
134
+ block-size: 44px;
135
+ }
136
+ .dds-number-input__step {
137
+ inline-size: 44px;
138
+ }
139
+ }
@@ -0,0 +1,164 @@
1
+ /* SegmentedControl — one choice among a few visible options (view switch, filter).
2
+ * Markup is the radio-group pattern: .dds-segmented[role="radiogroup"] >
3
+ * .dds-segmented__track > label.dds-segmented__item[data-state] with a
4
+ * visually hidden native radio inside each item. Selection is data-state
5
+ * from the radio state, never a class alone.
6
+ *
7
+ * Heights: md is 40px and sm is 32px including the track border, the same
8
+ * outer box as the other single-line DDS controls. Segment labels never wrap;
9
+ * content-width segments never clip, and full-width segments ellipsize with
10
+ * the label repeated in a title. */
11
+
12
+ .dds-segmented {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: var(--dds-space-4);
16
+ min-inline-size: 0;
17
+ max-inline-size: 100%;
18
+ font-family: var(--dds-font-family-sans);
19
+ color: var(--dds-color-text-primary);
20
+ }
21
+ .dds-segmented[hidden] {
22
+ display: none;
23
+ }
24
+
25
+ .dds-segmented__label {
26
+ font-size: var(--dds-typo-label-font-size);
27
+ line-height: var(--dds-typo-label-line-height);
28
+ font-weight: var(--dds-typo-label-font-weight);
29
+ }
30
+
31
+ .dds-segmented__track {
32
+ display: inline-flex;
33
+ align-items: stretch;
34
+ align-self: flex-start;
35
+ gap: var(--dds-space-2);
36
+ max-inline-size: 100%;
37
+ block-size: var(--dds-space-40);
38
+ padding: var(--dds-space-2);
39
+ border: 1px solid var(--dds-color-border-strong);
40
+ border-radius: var(--dds-radius-md);
41
+ background: var(--dds-color-bg-subtle);
42
+ /* Too many segments for the width scroll inside the track instead of
43
+ * pushing the page sideways. */
44
+ overflow-x: auto;
45
+ scrollbar-width: none;
46
+ }
47
+ .dds-segmented__track::-webkit-scrollbar {
48
+ display: none;
49
+ }
50
+ .dds-segmented[data-size="sm"] .dds-segmented__track {
51
+ block-size: var(--dds-space-32);
52
+ }
53
+ .dds-segmented[data-full-width] .dds-segmented__track {
54
+ display: flex;
55
+ align-self: stretch;
56
+ }
57
+
58
+ .dds-segmented__item {
59
+ position: relative;
60
+ display: inline-flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ flex: none;
64
+ min-inline-size: 0;
65
+ padding-inline: var(--dds-space-12);
66
+ border: 1px solid transparent;
67
+ border-radius: var(--dds-radius-sm);
68
+ font-size: var(--dds-typo-label-font-size);
69
+ line-height: var(--dds-typo-label-line-height);
70
+ font-weight: var(--dds-typo-label-font-weight);
71
+ color: var(--dds-color-text-secondary);
72
+ white-space: nowrap;
73
+ cursor: pointer;
74
+ user-select: none;
75
+ -webkit-tap-highlight-color: transparent;
76
+ transition:
77
+ background-color var(--dds-motion-duration-fast) var(--dds-motion-easing-standard),
78
+ border-color var(--dds-motion-duration-fast) var(--dds-motion-easing-standard),
79
+ box-shadow var(--dds-motion-duration-fast) var(--dds-motion-easing-standard),
80
+ color var(--dds-motion-duration-fast) var(--dds-motion-easing-standard);
81
+ }
82
+ .dds-segmented[data-size="sm"] .dds-segmented__item {
83
+ padding-inline: var(--dds-space-8);
84
+ }
85
+ .dds-segmented[data-full-width] .dds-segmented__item {
86
+ flex: 1 1 0;
87
+ }
88
+
89
+ /* The bold selected label reserves its width in every state, so choosing a
90
+ * segment never shifts its neighbours. */
91
+ .dds-segmented__text {
92
+ display: inline-grid;
93
+ min-inline-size: 0;
94
+ max-inline-size: 100%;
95
+ }
96
+ .dds-segmented__text::after {
97
+ content: attr(data-text);
98
+ block-size: 0;
99
+ overflow: hidden;
100
+ visibility: hidden;
101
+ font-weight: 600;
102
+ }
103
+ .dds-segmented[data-full-width] .dds-segmented__text {
104
+ display: block;
105
+ overflow: hidden;
106
+ text-overflow: ellipsis;
107
+ }
108
+ .dds-segmented[data-full-width] .dds-segmented__text::after {
109
+ content: none;
110
+ }
111
+
112
+ .dds-segmented__item:not([data-disabled]):not([data-state="checked"]):hover {
113
+ color: var(--dds-color-text-primary);
114
+ background: var(--dds-color-overlay-hover-tint);
115
+ }
116
+
117
+ .dds-segmented__item[data-state="checked"] {
118
+ border-color: var(--dds-color-border-strong);
119
+ background: var(--dds-color-bg-default);
120
+ box-shadow: var(--dds-elevation-1);
121
+ color: var(--dds-color-text-primary);
122
+ font-weight: 600;
123
+ }
124
+
125
+ .dds-segmented__item[data-focus-visible] {
126
+ outline: var(--dds-space-2) solid var(--dds-color-border-focus);
127
+ outline-offset: calc(var(--dds-space-2) * -1);
128
+ }
129
+
130
+ .dds-segmented[data-invalid] .dds-segmented__track {
131
+ border-color: var(--dds-color-status-danger);
132
+ }
133
+
134
+ /* opacity is allowed for disabled only (spec §4.2) */
135
+ .dds-segmented__item[data-disabled] {
136
+ opacity: 0.45;
137
+ cursor: not-allowed;
138
+ }
139
+ .dds-segmented[data-disabled] .dds-segmented__item[data-disabled] {
140
+ opacity: 1;
141
+ }
142
+ .dds-segmented[data-disabled] .dds-segmented__track {
143
+ opacity: 0.45;
144
+ cursor: not-allowed;
145
+ }
146
+ .dds-segmented__item[data-readonly] {
147
+ cursor: default;
148
+ }
149
+
150
+ @media (prefers-reduced-motion: reduce) {
151
+ .dds-segmented__item {
152
+ transition: none;
153
+ }
154
+ }
155
+
156
+ @media (pointer: coarse) {
157
+ .dds-segmented__track,
158
+ .dds-segmented[data-size="sm"] .dds-segmented__track {
159
+ block-size: calc(44px + var(--dds-space-4) + 2px);
160
+ }
161
+ .dds-segmented__item {
162
+ min-inline-size: 44px;
163
+ }
164
+ }
@@ -0,0 +1,6 @@
1
+ /* TimePicker: the Combobox structure from choice.css (same 40px control, list
2
+ * and focus), with fixed-width digits and a clock button instead of the caret. */
3
+ .dds-time-picker .dds-choice-input,.dds-time-picker .dds-choice-item {font-variant-numeric:tabular-nums;}
4
+ .dds-time-picker .dds-choice-trigger {display:inline-flex;flex:none;align-items:center;justify-content:center;padding-inline:var(--dds-space-8);color:var(--dds-color-text-secondary);}
5
+ .dds-time-picker .dds-choice-trigger:hover {color:var(--dds-color-text-primary);}
6
+ .dds-time-picker .dds-choice-trigger:disabled {cursor:not-allowed;}
package/dist/dds.css CHANGED
@@ -441,7 +441,8 @@
441
441
  .dds-choice-label {font-size:var(--dds-typo-label-font-size);line-height:var(--dds-typo-label-line-height);font-weight:var(--dds-typo-label-font-weight);}
442
442
  .dds-choice-control {position:relative;display:flex;align-items:center;inline-size:100%;min-block-size:var(--dds-space-40);border:1px solid var(--dds-color-border-strong);border-radius:var(--dds-radius-md);background:var(--dds-color-bg-default);}
443
443
  .dds-choice-control:focus-within {outline:var(--dds-space-2) solid var(--dds-color-border-focus);}
444
- .dds-choice-input,.dds-choice-trigger {box-sizing:border-box;min-inline-size:0;min-block-size:var(--dds-space-40);border:0;background:transparent;color:inherit;font:inherit;padding-inline:var(--dds-space-12);}
444
+ /* The control owns the 40px height (border included, like Input and DatePicker); parts stretch inside it. */
445
+ .dds-choice-input,.dds-choice-trigger {box-sizing:border-box;align-self:stretch;min-inline-size:0;min-block-size:0;border:0;background:transparent;color:inherit;font:inherit;padding-inline:var(--dds-space-12);}
445
446
  .dds-choice-input {flex:1;inline-size:100%;outline:none;}
446
447
  .dds-choice-trigger {cursor:pointer;text-align:start;}
447
448
  .dds-choice-control > .dds-choice-trigger:first-child {inline-size:100%;}
@@ -453,7 +454,8 @@
453
454
  .dds-choice-item[data-disabled] {opacity:.45;cursor:not-allowed;}
454
455
  .dds-choice-description {font-size:var(--dds-typo-caption-font-size);color:var(--dds-color-text-secondary);overflow:hidden;text-overflow:ellipsis;}
455
456
  .dds-choice-status {padding:var(--dds-space-12);color:var(--dds-color-text-secondary);}
456
- .dds-choice-status:empty {padding:0;}
457
+ /* Out of flow while empty so the field is as tall as Input (no stray gap); still in the tree as a live region. */
458
+ .dds-choice-status:empty {position:absolute;padding:0;}
457
459
  .dds-choice-validation {position:absolute;inline-size:1px;block-size:1px;padding:0;border:0;clip-path:inset(50%);overflow:hidden;}
458
460
  .dds-choice[data-label-placement="hidden"] .dds-choice-label {position:absolute;inline-size:1px;block-size:1px;clip-path:inset(50%);overflow:hidden;white-space:nowrap;}
459
461
  .dds-choice[data-label-placement="inside"] .dds-choice-label {position:absolute;z-index:1;inset-inline-start:var(--dds-space-12);inset-block-start:var(--dds-space-20);pointer-events:none;color:var(--dds-color-text-secondary);}
@@ -465,6 +467,318 @@
465
467
  .dds-choice[data-disabled] {opacity:.45;}
466
468
  @media(pointer:coarse){.dds-choice-input,.dds-choice-trigger,.dds-choice-clear {min-block-size:44px;min-inline-size:44px;}}
467
469
 
470
+ /* TimePicker: the Combobox structure from choice.css (same 40px control, list
471
+ * and focus), with fixed-width digits and a clock button instead of the caret. */
472
+ .dds-time-picker .dds-choice-input,.dds-time-picker .dds-choice-item {font-variant-numeric:tabular-nums;}
473
+ .dds-time-picker .dds-choice-trigger {display:inline-flex;flex:none;align-items:center;justify-content:center;padding-inline:var(--dds-space-8);color:var(--dds-color-text-secondary);}
474
+ .dds-time-picker .dds-choice-trigger:hover {color:var(--dds-color-text-primary);}
475
+ .dds-time-picker .dds-choice-trigger:disabled {cursor:not-allowed;}
476
+
477
+ /* NumberInput — a localized number field. The bordered control has the
478
+ * same 40px outer box, border, radius and whole-control focus ring as Input
479
+ * and SelectPicker. Digits sit at the end with tabular figures; an optional
480
+ * unit (원, 개, 분) and the − / + steppers sit inside the control after them,
481
+ * so neither can overlap the digits. */
482
+
483
+ .dds-number-input {
484
+ position: relative;
485
+ display: flex;
486
+ flex-direction: column;
487
+ gap: var(--dds-space-4);
488
+ min-inline-size: 0;
489
+ font-family: var(--dds-font-family-sans);
490
+ font-size: var(--dds-typo-body-2-font-size);
491
+ color: var(--dds-color-text-primary);
492
+ }
493
+ .dds-number-input[hidden] {
494
+ display: none;
495
+ }
496
+
497
+ .dds-number-input__label {
498
+ font-size: var(--dds-typo-label-font-size);
499
+ line-height: var(--dds-typo-label-line-height);
500
+ font-weight: var(--dds-typo-label-font-weight);
501
+ }
502
+ .dds-number-input[data-label-placement="hidden"] .dds-number-input__label {
503
+ position: absolute;
504
+ inline-size: 1px;
505
+ block-size: 1px;
506
+ padding: 0;
507
+ margin: -1px;
508
+ overflow: hidden;
509
+ clip-path: inset(50%);
510
+ white-space: nowrap;
511
+ }
512
+
513
+ .dds-number-input__control {
514
+ display: flex;
515
+ align-items: stretch;
516
+ inline-size: 100%;
517
+ min-inline-size: 0;
518
+ block-size: var(--dds-space-40);
519
+ border: 1px solid var(--dds-color-border-strong);
520
+ border-radius: var(--dds-radius-md);
521
+ background: var(--dds-color-bg-default);
522
+ overflow: hidden;
523
+ }
524
+ .dds-number-input__control:focus-within {
525
+ outline: var(--dds-space-2) solid var(--dds-color-border-focus);
526
+ }
527
+ .dds-number-input__control[data-invalid] {
528
+ border-color: var(--dds-color-status-danger);
529
+ }
530
+
531
+ .dds-number-input__field {
532
+ flex: 1 1 auto;
533
+ min-inline-size: 0;
534
+ inline-size: 100%;
535
+ padding-inline: var(--dds-space-12);
536
+ border: 0;
537
+ background: transparent;
538
+ color: inherit;
539
+ font: inherit;
540
+ font-variant-numeric: tabular-nums;
541
+ text-align: end;
542
+ outline: none;
543
+ }
544
+ .dds-number-input__field::placeholder {
545
+ color: var(--dds-color-text-muted);
546
+ }
547
+ .dds-number-input__control:has(.dds-number-input__suffix) .dds-number-input__field {
548
+ padding-inline-end: var(--dds-space-4);
549
+ }
550
+
551
+ .dds-number-input__suffix {
552
+ display: flex;
553
+ align-items: center;
554
+ flex: none;
555
+ padding-inline-end: var(--dds-space-12);
556
+ color: var(--dds-color-text-secondary);
557
+ white-space: nowrap;
558
+ }
559
+
560
+ .dds-number-input__steppers {
561
+ display: flex;
562
+ flex: none;
563
+ border-inline-start: 1px solid var(--dds-color-border-default);
564
+ }
565
+
566
+ .dds-number-input__step {
567
+ display: grid;
568
+ place-items: center;
569
+ inline-size: var(--dds-space-32);
570
+ padding: 0;
571
+ border: 0;
572
+ background: transparent;
573
+ color: var(--dds-color-text-secondary);
574
+ font: inherit;
575
+ cursor: pointer;
576
+ -webkit-tap-highlight-color: transparent;
577
+ }
578
+ .dds-number-input__step + .dds-number-input__step {
579
+ border-inline-start: 1px solid var(--dds-color-border-default);
580
+ }
581
+ .dds-number-input__step:not([disabled]):hover {
582
+ background: var(--dds-color-overlay-hover-tint);
583
+ color: var(--dds-color-text-primary);
584
+ }
585
+ .dds-number-input__step:not([disabled]):active {
586
+ background: var(--dds-color-overlay-pressed-tint);
587
+ }
588
+ /* opacity is allowed for disabled only (spec §4.2) */
589
+ .dds-number-input__step[disabled] {
590
+ opacity: 0.45;
591
+ cursor: not-allowed;
592
+ }
593
+
594
+ .dds-number-input[data-disabled] {
595
+ opacity: 0.45;
596
+ }
597
+ .dds-number-input[data-disabled] .dds-number-input__control {
598
+ background: var(--dds-color-bg-subtle);
599
+ cursor: not-allowed;
600
+ }
601
+ .dds-number-input[data-disabled] .dds-number-input__step[disabled] {
602
+ opacity: 1;
603
+ }
604
+ .dds-number-input[data-readonly] .dds-number-input__control {
605
+ background: var(--dds-color-bg-subtle);
606
+ }
607
+
608
+ @media (pointer: coarse) {
609
+ .dds-number-input__control {
610
+ block-size: 44px;
611
+ }
612
+ .dds-number-input__step {
613
+ inline-size: 44px;
614
+ }
615
+ }
616
+
617
+ /* SegmentedControl — one choice among a few visible options (view switch, filter).
618
+ * Markup is the radio-group pattern: .dds-segmented[role="radiogroup"] >
619
+ * .dds-segmented__track > label.dds-segmented__item[data-state] with a
620
+ * visually hidden native radio inside each item. Selection is data-state
621
+ * from the radio state, never a class alone.
622
+ *
623
+ * Heights: md is 40px and sm is 32px including the track border, the same
624
+ * outer box as the other single-line DDS controls. Segment labels never wrap;
625
+ * content-width segments never clip, and full-width segments ellipsize with
626
+ * the label repeated in a title. */
627
+
628
+ .dds-segmented {
629
+ display: flex;
630
+ flex-direction: column;
631
+ gap: var(--dds-space-4);
632
+ min-inline-size: 0;
633
+ max-inline-size: 100%;
634
+ font-family: var(--dds-font-family-sans);
635
+ color: var(--dds-color-text-primary);
636
+ }
637
+ .dds-segmented[hidden] {
638
+ display: none;
639
+ }
640
+
641
+ .dds-segmented__label {
642
+ font-size: var(--dds-typo-label-font-size);
643
+ line-height: var(--dds-typo-label-line-height);
644
+ font-weight: var(--dds-typo-label-font-weight);
645
+ }
646
+
647
+ .dds-segmented__track {
648
+ display: inline-flex;
649
+ align-items: stretch;
650
+ align-self: flex-start;
651
+ gap: var(--dds-space-2);
652
+ max-inline-size: 100%;
653
+ block-size: var(--dds-space-40);
654
+ padding: var(--dds-space-2);
655
+ border: 1px solid var(--dds-color-border-strong);
656
+ border-radius: var(--dds-radius-md);
657
+ background: var(--dds-color-bg-subtle);
658
+ /* Too many segments for the width scroll inside the track instead of
659
+ * pushing the page sideways. */
660
+ overflow-x: auto;
661
+ scrollbar-width: none;
662
+ }
663
+ .dds-segmented__track::-webkit-scrollbar {
664
+ display: none;
665
+ }
666
+ .dds-segmented[data-size="sm"] .dds-segmented__track {
667
+ block-size: var(--dds-space-32);
668
+ }
669
+ .dds-segmented[data-full-width] .dds-segmented__track {
670
+ display: flex;
671
+ align-self: stretch;
672
+ }
673
+
674
+ .dds-segmented__item {
675
+ position: relative;
676
+ display: inline-flex;
677
+ align-items: center;
678
+ justify-content: center;
679
+ flex: none;
680
+ min-inline-size: 0;
681
+ padding-inline: var(--dds-space-12);
682
+ border: 1px solid transparent;
683
+ border-radius: var(--dds-radius-sm);
684
+ font-size: var(--dds-typo-label-font-size);
685
+ line-height: var(--dds-typo-label-line-height);
686
+ font-weight: var(--dds-typo-label-font-weight);
687
+ color: var(--dds-color-text-secondary);
688
+ white-space: nowrap;
689
+ cursor: pointer;
690
+ user-select: none;
691
+ -webkit-tap-highlight-color: transparent;
692
+ transition:
693
+ background-color var(--dds-motion-duration-fast) var(--dds-motion-easing-standard),
694
+ border-color var(--dds-motion-duration-fast) var(--dds-motion-easing-standard),
695
+ box-shadow var(--dds-motion-duration-fast) var(--dds-motion-easing-standard),
696
+ color var(--dds-motion-duration-fast) var(--dds-motion-easing-standard);
697
+ }
698
+ .dds-segmented[data-size="sm"] .dds-segmented__item {
699
+ padding-inline: var(--dds-space-8);
700
+ }
701
+ .dds-segmented[data-full-width] .dds-segmented__item {
702
+ flex: 1 1 0;
703
+ }
704
+
705
+ /* The bold selected label reserves its width in every state, so choosing a
706
+ * segment never shifts its neighbours. */
707
+ .dds-segmented__text {
708
+ display: inline-grid;
709
+ min-inline-size: 0;
710
+ max-inline-size: 100%;
711
+ }
712
+ .dds-segmented__text::after {
713
+ content: attr(data-text);
714
+ block-size: 0;
715
+ overflow: hidden;
716
+ visibility: hidden;
717
+ font-weight: 600;
718
+ }
719
+ .dds-segmented[data-full-width] .dds-segmented__text {
720
+ display: block;
721
+ overflow: hidden;
722
+ text-overflow: ellipsis;
723
+ }
724
+ .dds-segmented[data-full-width] .dds-segmented__text::after {
725
+ content: none;
726
+ }
727
+
728
+ .dds-segmented__item:not([data-disabled]):not([data-state="checked"]):hover {
729
+ color: var(--dds-color-text-primary);
730
+ background: var(--dds-color-overlay-hover-tint);
731
+ }
732
+
733
+ .dds-segmented__item[data-state="checked"] {
734
+ border-color: var(--dds-color-border-strong);
735
+ background: var(--dds-color-bg-default);
736
+ box-shadow: var(--dds-elevation-1);
737
+ color: var(--dds-color-text-primary);
738
+ font-weight: 600;
739
+ }
740
+
741
+ .dds-segmented__item[data-focus-visible] {
742
+ outline: var(--dds-space-2) solid var(--dds-color-border-focus);
743
+ outline-offset: calc(var(--dds-space-2) * -1);
744
+ }
745
+
746
+ .dds-segmented[data-invalid] .dds-segmented__track {
747
+ border-color: var(--dds-color-status-danger);
748
+ }
749
+
750
+ /* opacity is allowed for disabled only (spec §4.2) */
751
+ .dds-segmented__item[data-disabled] {
752
+ opacity: 0.45;
753
+ cursor: not-allowed;
754
+ }
755
+ .dds-segmented[data-disabled] .dds-segmented__item[data-disabled] {
756
+ opacity: 1;
757
+ }
758
+ .dds-segmented[data-disabled] .dds-segmented__track {
759
+ opacity: 0.45;
760
+ cursor: not-allowed;
761
+ }
762
+ .dds-segmented__item[data-readonly] {
763
+ cursor: default;
764
+ }
765
+
766
+ @media (prefers-reduced-motion: reduce) {
767
+ .dds-segmented__item {
768
+ transition: none;
769
+ }
770
+ }
771
+
772
+ @media (pointer: coarse) {
773
+ .dds-segmented__track,
774
+ .dds-segmented[data-size="sm"] .dds-segmented__track {
775
+ block-size: calc(44px + var(--dds-space-4) + 2px);
776
+ }
777
+ .dds-segmented__item {
778
+ min-inline-size: 44px;
779
+ }
780
+ }
781
+
468
782
  /* Checkbox / Radio — one class for both; the input's own type decides the
469
783
  * shape (square + tick vs circle + dot), so markup never has to declare the
470
784
  * shape twice. The control stays a real <input> (keyboard, form data, AT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devslab/dds-css",
3
- "version": "0.22.1",
3
+ "version": "0.24.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",