@scalewing/react 1.12.0 → 1.14.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/styles.css CHANGED
@@ -660,6 +660,31 @@ body {
660
660
  outline-offset: var(--sw-focus-ring-offset);
661
661
  }
662
662
 
663
+ /* The browser's placeholder gray is one fixed #757575 (2.3:1 on a dark
664
+ field); muted is tuned per palette and scheme. */
665
+ [data-theme] :is(input[type='text'], input[type='email'], input[type='number'], input[type='search'], input[type='url'], input[type='password'], input:not([type]), textarea)::placeholder {
666
+ color: var(--sw-color-muted);
667
+ opacity: 1;
668
+ }
669
+
670
+ [data-theme] :is(input[type='text'], input[type='email'], input[type='number'], input[type='search'], input[type='url'], input[type='password'], input:not([type]), textarea):disabled,
671
+ [data-theme] select:disabled {
672
+ background-color: var(--sw-color-subtle);
673
+ border-style: dashed;
674
+ cursor: not-allowed;
675
+ opacity: 1;
676
+ -webkit-text-fill-color: currentColor;
677
+ }
678
+
679
+ @media (forced-colors: active) {
680
+ [data-theme] :is(input[type='text'], input[type='email'], input[type='number'], input[type='search'], input[type='url'], input[type='password'], input:not([type]), textarea):disabled,
681
+ [data-theme] select:disabled {
682
+ border-color: GrayText;
683
+ color: GrayText;
684
+ -webkit-text-fill-color: GrayText;
685
+ }
686
+ }
687
+
663
688
  .sw-padding-0 { padding: var(--sw-space-0); }
664
689
  .sw-padding-1 { padding: var(--sw-space-1); }
665
690
  .sw-padding-2 { padding: var(--sw-space-2); }
@@ -857,7 +882,8 @@ body {
857
882
  .sw-button[aria-pressed='true'] { box-shadow: 0 0 0 2px var(--sw-color-background), 0 0 0 4px var(--sw-color-accent); }
858
883
  .sw-button[aria-pressed='true']:focus-visible { outline-offset: calc(var(--sw-focus-ring-offset) + 4px); }
859
884
  @media (forced-colors: active) {
860
- .sw-button[aria-pressed='true'] { background: Highlight; border-color: Highlight; color: HighlightText; }
885
+ .sw-button[aria-pressed='true'] { border-color: Highlight; position: relative; }
886
+ .sw-button[aria-pressed='true']::after { border: 2px solid Highlight; border-radius: inherit; content: ''; inset: calc(-1px - 4px); pointer-events: none; position: absolute; }
861
887
  }
862
888
  .sw-button-xs { min-height: 28px; padding-inline: 10px; }
863
889
  .sw-button-sm { min-height: 32px; padding-inline: 12px; }
@@ -1082,6 +1108,14 @@ body {
1082
1108
  opacity: var(--sw-disabled-opacity);
1083
1109
  }
1084
1110
 
1111
+ /* A consumer glyph beside the label, in the label's color and the option's gap. */
1112
+ .sw-radio-group-icon {
1113
+ align-items: center;
1114
+ color: var(--sw-color-text);
1115
+ display: inline-flex;
1116
+ flex: none;
1117
+ }
1118
+
1085
1119
  .sw-radio-group-text {
1086
1120
  color: var(--sw-color-text);
1087
1121
  font-family: var(--sw-font-sans);
@@ -1168,6 +1202,36 @@ body {
1168
1202
 
1169
1203
  :is(.sw-button-primary, .sw-button-secondary, .sw-button-tertiary, .sw-button-danger) .sw-badge { background: var(--sw-color-surface); color: var(--sw-color-text); }
1170
1204
 
1205
+ .sw-segmented-field {
1206
+ display: inline-flex;
1207
+ flex-direction: column;
1208
+ gap: var(--sw-space-1);
1209
+ }
1210
+
1211
+ .sw-segmented-field-filled {
1212
+ display: flex;
1213
+ }
1214
+
1215
+ .sw-segmented-field > .sw-field-error {
1216
+ contain: inline-size;
1217
+ }
1218
+
1219
+ .sw-segmented-field:has(> .sw-field-error:not(:empty)) {
1220
+ min-inline-size: min(100%, 24ch);
1221
+ }
1222
+
1223
+ .sw-inline > .sw-segmented-field > .sw-segmented {
1224
+ align-self: flex-start;
1225
+ }
1226
+
1227
+ .sw-segmented[aria-invalid='true'] {
1228
+ border-color: var(--sw-color-danger);
1229
+ }
1230
+
1231
+ @media (forced-colors: active) {
1232
+ .sw-segmented[aria-invalid='true'] { border-color: Mark; }
1233
+ }
1234
+
1171
1235
  .sw-segmented {
1172
1236
  background: var(--sw-glass-fill);
1173
1237
  border: 1px solid var(--sw-glass-border);
@@ -1298,28 +1362,20 @@ body {
1298
1362
  }
1299
1363
 
1300
1364
  .sw-table-row-selected > :first-child {
1301
- padding-inline-start: var(--sw-space-5);
1302
1365
  position: relative;
1303
1366
  }
1304
1367
 
1305
- .sw-table-compact .sw-table-row-selected > :first-child {
1306
- padding-inline-start: var(--sw-space-4);
1307
- }
1308
-
1309
1368
  .sw-table-row-selected > :first-child::before {
1310
- background: var(--sw-color-accent);
1311
- border-radius: var(--sw-radius-pill);
1369
+ border-inline-start: var(--sw-space-1) solid var(--sw-color-accent);
1312
1370
  content: '';
1313
- height: var(--sw-space-2);
1314
- inset-block-start: 50%;
1315
- inset-inline-start: var(--sw-space-2);
1371
+ inset-block: 0;
1372
+ inset-inline-start: 0;
1373
+ pointer-events: none;
1316
1374
  position: absolute;
1317
- transform: translateY(-50%);
1318
- width: var(--sw-space-2);
1319
1375
  }
1320
1376
 
1321
- .sw-table-compact .sw-table-row-selected > :first-child::before {
1322
- inset-inline-start: var(--sw-space-1);
1377
+ @media (forced-colors: active) {
1378
+ .sw-table-row-selected > :first-child::before { border-color: Highlight; }
1323
1379
  }
1324
1380
 
1325
1381
  .sw-date-field {
@@ -1331,12 +1387,11 @@ body {
1331
1387
  width: max-content;
1332
1388
  }
1333
1389
 
1390
+ /* The label inherits the canvas's body type, as Field's does; the label
1391
+ words inside it are a Text label span. The same line box gives the same
1392
+ gap to the entry as a Field beside it. */
1334
1393
  .sw-date-field-label {
1335
1394
  color: var(--sw-color-text);
1336
- font-family: var(--sw-font-sans);
1337
- font-size: 15px;
1338
- font-weight: 600;
1339
- line-height: 20px;
1340
1395
  }
1341
1396
 
1342
1397
  .sw-date-field-control {
@@ -1383,7 +1438,15 @@ body {
1383
1438
  border-color: var(--sw-color-danger);
1384
1439
  }
1385
1440
 
1386
- .sw-date-field .sw-date-field-control > .sw-date-field-input:disabled,
1441
+ /* The entry looks locked as every text control does; its button fades as buttons do. */
1442
+ .sw-date-field .sw-date-field-control > .sw-date-field-input:disabled {
1443
+ background-color: var(--sw-color-subtle);
1444
+ border-style: dashed;
1445
+ cursor: not-allowed;
1446
+ opacity: 1;
1447
+ -webkit-text-fill-color: currentColor;
1448
+ }
1449
+
1387
1450
  .sw-date-field-button:disabled {
1388
1451
  cursor: not-allowed;
1389
1452
  opacity: var(--sw-disabled-opacity);
@@ -1580,6 +1643,11 @@ body {
1580
1643
 
1581
1644
  @media (forced-colors: active) {
1582
1645
  .sw-date-field .sw-date-field-control > .sw-date-field-input[aria-invalid='true'] { border-color: CanvasText; }
1646
+ .sw-date-field .sw-date-field-control > .sw-date-field-input:disabled {
1647
+ border-color: GrayText;
1648
+ color: GrayText;
1649
+ -webkit-text-fill-color: GrayText;
1650
+ }
1583
1651
  .sw-date-field-calendar { border-color: CanvasText; }
1584
1652
  .sw-date-field-day[aria-current='date'] { border-color: CanvasText; }
1585
1653
  .sw-date-field-day[aria-selected='true'] {
@@ -1844,6 +1912,25 @@ body {
1844
1912
  width: max-content;
1845
1913
  }
1846
1914
 
1915
+ /*
1916
+ * width="full": the field and its trigger fill the container's inline size.
1917
+ * The value still takes the free space and ellipsizes, and the chevron stays
1918
+ * last, at the inline end. In an Inline row the field takes only the space
1919
+ * its siblings leave, so a Button beside it keeps its label on one line.
1920
+ */
1921
+ .sw-select-full {
1922
+ width: 100%;
1923
+ }
1924
+
1925
+ .sw-inline > .sw-select-full {
1926
+ flex: 1 1 0;
1927
+ min-width: 0;
1928
+ }
1929
+
1930
+ .sw-select-full .sw-select-trigger {
1931
+ width: 100%;
1932
+ }
1933
+
1847
1934
  .sw-select-control {
1848
1935
  position: relative;
1849
1936
  }
@@ -1964,6 +2051,15 @@ body {
1964
2051
  z-index: 10;
1965
2052
  }
1966
2053
 
2054
+ /*
2055
+ * A full-width field's open list is exactly the trigger's width (min-width
2056
+ * already beats the dialog-max cap), so it never runs past a phone's edge;
2057
+ * a long option wraps inside it, even a single long word.
2058
+ */
2059
+ .sw-select-full .sw-select-list {
2060
+ width: 100%;
2061
+ }
2062
+
1967
2063
  .sw-select-option {
1968
2064
  border-radius: var(--sw-radius-sm);
1969
2065
  box-sizing: border-box;
@@ -1974,6 +2070,10 @@ body {
1974
2070
  padding-inline: var(--sw-control-xs-padding-inline);
1975
2071
  }
1976
2072
 
2073
+ .sw-select-full .sw-select-option {
2074
+ overflow-wrap: anywhere;
2075
+ }
2076
+
1977
2077
  .sw-select-option[aria-selected='true'] {
1978
2078
  font-weight: 600;
1979
2079
  }
@@ -2984,10 +3084,26 @@ body {
2984
3084
 
2985
3085
  .sw-field-invalid .sw-field-adorned { border-color: var(--sw-color-danger); }
2986
3086
 
3087
+ /* The frame draws the surface, so it carries the disabled look for its input. */
3088
+ .sw-field-adorned:has(> input:disabled) {
3089
+ background-color: var(--sw-color-subtle);
3090
+ border-style: dashed;
3091
+ cursor: not-allowed;
3092
+ opacity: 1;
3093
+ -webkit-text-fill-color: currentColor;
3094
+ }
3095
+
3096
+ [data-theme] .sw-field-adorned > input:disabled { background: transparent; }
3097
+
2987
3098
  @media (forced-colors: active) {
2988
3099
  [data-theme] .sw-field-invalid :is(input, select, textarea),
2989
3100
  .sw-field-invalid .sw-field-adorned { border-color: Mark; }
2990
3101
  .sw-field-prefix, .sw-field-suffix { color: CanvasText; }
3102
+ .sw-field-adorned:has(> input:disabled) {
3103
+ border-color: GrayText;
3104
+ color: GrayText;
3105
+ -webkit-text-fill-color: GrayText;
3106
+ }
2991
3107
  .sw-field-error, .sw-field-required { color: Mark; }
2992
3108
  }
2993
3109
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalewing/react",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "Scalewing DOM components and package-owned CSS utilities.",
5
5
  "type": "module",
6
6
  "license": "MIT",