@salemcobalt/ui 0.2.0-rc.4 → 0.2.0-rc.5

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
@@ -1,4 +1,4 @@
1
- /* @salemcobalt/ui 0.2.0-rc.4 — requires @salemcobalt/tokens/css. */
1
+ /* @salemcobalt/ui 0.2.0-rc.5 — requires @salemcobalt/tokens/css. */
2
2
  @layer sc {
3
3
  /* ---- base.css ---- */
4
4
  /* Shared: focus ring, reduced motion. Component files follow. */
@@ -10,6 +10,7 @@
10
10
  .sc-input:focus-visible,
11
11
  .sc-select:focus-visible,
12
12
  .sc-select__item:focus-visible,
13
+ .sc-select__clear:focus-visible,
13
14
  .sc-checkbox:focus-visible,
14
15
  .sc-switch:focus-visible,
15
16
  .sc-tabs__tab:focus-visible,
@@ -1178,6 +1179,7 @@
1178
1179
  min-inline-size: 0;
1179
1180
  }
1180
1181
  .sc-input {
1182
+ appearance: none;
1181
1183
  box-sizing: border-box;
1182
1184
  inline-size: 100%;
1183
1185
  min-inline-size: 0;
@@ -1215,6 +1217,30 @@
1215
1217
  color: var(--sc-color-text-subtle);
1216
1218
  cursor: not-allowed;
1217
1219
  }
1220
+ /* Native date, time and number fields: same box, tabular digits, the picker indicator at the end edge. */
1221
+ .sc-input:is(
1222
+ [type='date'],
1223
+ [type='time'],
1224
+ [type='datetime-local'],
1225
+ [type='month'],
1226
+ [type='week'],
1227
+ [type='number']
1228
+ ) {
1229
+ font-variant-numeric: tabular-nums;
1230
+ }
1231
+ .sc-input::-webkit-date-and-time-value {
1232
+ min-block-size: 1lh;
1233
+ text-align: start;
1234
+ }
1235
+ .sc-input::-webkit-calendar-picker-indicator {
1236
+ margin-inline-start: var(--sc-spacing-xs);
1237
+ padding: 0;
1238
+ opacity: 0.7;
1239
+ cursor: pointer;
1240
+ }
1241
+ .sc-input::-webkit-calendar-picker-indicator:hover {
1242
+ opacity: 1;
1243
+ }
1218
1244
  .sc-input-wrap[data-icon-start] > .sc-input {
1219
1245
  padding-inline-start: calc(var(--_px) + var(--sc-size-icon-md) + var(--sc-spacing-xs));
1220
1246
  }
@@ -1252,7 +1278,29 @@
1252
1278
  .sc-textarea[data-resize='none'] {
1253
1279
  resize: none;
1254
1280
  }
1281
+ .sc-textarea[data-variant='code'] {
1282
+ font-family: var(--sc-font-family-mono);
1283
+ font-size: calc(var(--_fs) * 0.95);
1284
+ line-height: var(--sc-font-line-height-normal);
1285
+ tab-size: 2;
1286
+ hyphens: none;
1287
+ overflow-wrap: normal;
1288
+ }
1289
+ .sc-textarea[wrap='off'] {
1290
+ white-space: pre;
1291
+ overflow-x: auto;
1292
+ }
1255
1293
  /* Select */
1294
+ .sc-select__wrap {
1295
+ position: relative;
1296
+ display: inline-flex;
1297
+ max-inline-size: 100%;
1298
+ align-self: flex-start;
1299
+ }
1300
+ .sc-select__wrap[data-full-width] {
1301
+ display: flex;
1302
+ align-self: stretch;
1303
+ }
1256
1304
  .sc-select {
1257
1305
  box-sizing: border-box;
1258
1306
  display: inline-flex;
@@ -1284,6 +1332,30 @@
1284
1332
  inline-size: 100%;
1285
1333
  align-self: stretch;
1286
1334
  }
1335
+ /* Room for the × between the value and the chevron. The clear button is a sibling, never nested in the trigger. */
1336
+ .sc-select[data-clearable] > .sc-select__icon {
1337
+ margin-inline-start: calc(var(--sc-size-icon-lg) + var(--sc-spacing-2xs));
1338
+ }
1339
+ .sc-select__clear {
1340
+ position: absolute;
1341
+ inset-block-start: 50%;
1342
+ inset-inline-end: calc(var(--sc-spacing-xs) + var(--sc-size-icon-md) + var(--sc-spacing-2xs));
1343
+ translate: 0 -50%;
1344
+ display: inline-grid;
1345
+ place-items: center;
1346
+ inline-size: var(--sc-size-icon-lg);
1347
+ block-size: var(--sc-size-icon-lg);
1348
+ padding: 0;
1349
+ border: 0;
1350
+ border-radius: var(--sc-radius-sm);
1351
+ background: transparent;
1352
+ color: var(--sc-color-text-muted);
1353
+ cursor: pointer;
1354
+ }
1355
+ .sc-select__clear:hover {
1356
+ background: var(--sc-color-surface-hover);
1357
+ color: var(--sc-color-text-default);
1358
+ }
1287
1359
  .sc-select:hover:not([data-disabled]) {
1288
1360
  border-color: var(--sc-color-text-muted);
1289
1361
  }
@@ -2192,4 +2264,398 @@
2192
2264
  font-size: var(--sc-font-size-xs);
2193
2265
  }
2194
2266
 
2267
+ /* ---- chip.css ---- */
2268
+ /* ---- Chip ------------------------------------------------------------------ */
2269
+ .sc-chip {
2270
+ --_h: var(--sc-size-control-sm);
2271
+ --_px: var(--sc-spacing-sm);
2272
+ --_fs: var(--sc-font-size-sm);
2273
+ --_icon: var(--sc-size-icon-sm);
2274
+ --_bg: transparent;
2275
+ --_fg: var(--sc-color-text-default);
2276
+ --_bd: var(--sc-color-border-strong);
2277
+ --_bg-hover: var(--sc-color-surface-hover);
2278
+ --_bg-on: var(--sc-color-surface-active);
2279
+ --_fg-on: var(--sc-color-text-default);
2280
+ --_bd-on: var(--sc-color-text-muted);
2281
+ position: relative;
2282
+ display: inline-flex;
2283
+ align-items: center;
2284
+ box-sizing: border-box;
2285
+ max-inline-size: 100%;
2286
+ block-size: var(--_h);
2287
+ border-radius: var(--sc-radius-full);
2288
+ border: var(--sc-border-width-hairline) solid var(--_bd);
2289
+ background: var(--_bg);
2290
+ color: var(--_fg);
2291
+ font-family: var(--sc-font-family-sans);
2292
+ font-size: var(--_fs);
2293
+ font-weight: var(--sc-font-weight-medium);
2294
+ line-height: 1;
2295
+ white-space: nowrap;
2296
+ transition:
2297
+ background-color var(--sc-duration-fast) var(--sc-ease-standard),
2298
+ border-color var(--sc-duration-fast) var(--sc-ease-standard),
2299
+ color var(--sc-duration-fast) var(--sc-ease-standard);
2300
+ }
2301
+ .sc-chip[data-size='sm'] {
2302
+ --_h: var(--sc-size-badge-md);
2303
+ --_px: var(--sc-spacing-xs);
2304
+ --_fs: var(--sc-font-size-xs);
2305
+ --_icon: var(--sc-size-icon-xs);
2306
+ }
2307
+ .sc-chip[data-selected] {
2308
+ --_bg: var(--_bg-on);
2309
+ --_fg: var(--_fg-on);
2310
+ --_bd: var(--_bd-on);
2311
+ }
2312
+ .sc-chip[data-disabled] {
2313
+ opacity: 0.5;
2314
+ }
2315
+ /* The text, or the toggle button that holds it. */
2316
+ .sc-chip__action,
2317
+ .sc-chip > .sc-chip__icon,
2318
+ .sc-chip > .sc-chip__label {
2319
+ display: inline-flex;
2320
+ align-items: center;
2321
+ min-inline-size: 0;
2322
+ }
2323
+ .sc-chip > .sc-chip__icon {
2324
+ margin-inline-start: var(--_px);
2325
+ }
2326
+ .sc-chip > .sc-chip__label {
2327
+ padding-inline: var(--_px);
2328
+ }
2329
+ .sc-chip > .sc-chip__icon + .sc-chip__label {
2330
+ padding-inline-start: var(--sc-spacing-2xs);
2331
+ }
2332
+ .sc-chip__action {
2333
+ gap: var(--sc-spacing-2xs);
2334
+ box-sizing: border-box;
2335
+ block-size: 100%;
2336
+ margin: 0;
2337
+ padding-inline: var(--_px);
2338
+ border: 0;
2339
+ border-radius: inherit;
2340
+ background: transparent;
2341
+ color: inherit;
2342
+ font: inherit;
2343
+ line-height: 1;
2344
+ cursor: pointer;
2345
+ }
2346
+ .sc-chip__action:hover:not(:disabled) {
2347
+ background: var(--_bg-hover);
2348
+ }
2349
+ .sc-chip[data-selected] > .sc-chip__action:hover:not(:disabled) {
2350
+ background: transparent;
2351
+ filter: brightness(0.97);
2352
+ }
2353
+ .sc-chip__action:disabled {
2354
+ cursor: not-allowed;
2355
+ }
2356
+ .sc-chip__icon {
2357
+ flex: none;
2358
+ inline-size: var(--_icon);
2359
+ block-size: var(--_icon);
2360
+ }
2361
+ .sc-chip__icon > svg {
2362
+ inline-size: 100%;
2363
+ block-size: 100%;
2364
+ }
2365
+ .sc-chip__label {
2366
+ overflow: hidden;
2367
+ text-overflow: ellipsis;
2368
+ }
2369
+ .sc-chip[data-removable] > .sc-chip__action,
2370
+ .sc-chip[data-removable] > .sc-chip__label {
2371
+ padding-inline-end: var(--sc-spacing-2xs);
2372
+ }
2373
+ .sc-chip__remove {
2374
+ flex: none;
2375
+ display: inline-grid;
2376
+ place-items: center;
2377
+ box-sizing: border-box;
2378
+ inline-size: calc(var(--_h) - 2 * var(--sc-spacing-2xs) - 2px);
2379
+ block-size: calc(var(--_h) - 2 * var(--sc-spacing-2xs) - 2px);
2380
+ margin-inline-end: var(--sc-spacing-2xs);
2381
+ padding: 0;
2382
+ border: 0;
2383
+ border-radius: var(--sc-radius-full);
2384
+ background: transparent;
2385
+ color: inherit;
2386
+ opacity: 0.7;
2387
+ cursor: pointer;
2388
+ }
2389
+ .sc-chip__remove:hover:not(:disabled) {
2390
+ opacity: 1;
2391
+ background: var(--_bg-hover);
2392
+ }
2393
+ .sc-chip__remove:disabled {
2394
+ cursor: not-allowed;
2395
+ }
2396
+ .sc-chip__action:focus-visible,
2397
+ .sc-chip__remove:focus-visible {
2398
+ outline: var(--sc-border-width-focus) solid var(--sc-color-border-focus);
2399
+ outline-offset: 0;
2400
+ }
2401
+ /* 44px hit area on touch without changing layout. */
2402
+ @media (pointer: coarse) {
2403
+ .sc-chip__action::after,
2404
+ .sc-chip__remove::after {
2405
+ content: '';
2406
+ position: absolute;
2407
+ inset: 50% auto auto 50%;
2408
+ translate: -50% -50%;
2409
+ inline-size: max(100%, var(--sc-size-touch-target));
2410
+ block-size: max(100%, var(--sc-size-touch-target));
2411
+ }
2412
+ .sc-chip__action,
2413
+ .sc-chip__remove {
2414
+ position: relative;
2415
+ }
2416
+ }
2417
+ /* Tones: soft fill when selected, tinted outline otherwise. */
2418
+ .sc-chip[data-tone='accent'] {
2419
+ --_fg: var(--sc-color-accent-text);
2420
+ --_bd: var(--sc-color-accent-text);
2421
+ --_bg-hover: var(--sc-color-accent-subtle);
2422
+ --_bg-on: var(--sc-color-accent-subtle);
2423
+ --_fg-on: var(--sc-color-accent-text);
2424
+ --_bd-on: var(--sc-color-accent-default);
2425
+ }
2426
+ .sc-chip[data-tone='success'] {
2427
+ --_fg: var(--sc-color-success-text);
2428
+ --_bd: var(--sc-color-success-text);
2429
+ --_bg-hover: var(--sc-color-success-subtle);
2430
+ --_bg-on: var(--sc-color-success-subtle);
2431
+ --_fg-on: var(--sc-color-success-text);
2432
+ --_bd-on: var(--sc-color-success-solid);
2433
+ }
2434
+ .sc-chip[data-tone='warning'] {
2435
+ --_fg: var(--sc-color-warning-text);
2436
+ --_bd: var(--sc-color-warning-text);
2437
+ --_bg-hover: var(--sc-color-warning-subtle);
2438
+ --_bg-on: var(--sc-color-warning-subtle);
2439
+ --_fg-on: var(--sc-color-warning-text);
2440
+ --_bd-on: var(--sc-color-warning-solid);
2441
+ }
2442
+ .sc-chip[data-tone='danger'] {
2443
+ --_fg: var(--sc-color-danger-text);
2444
+ --_bd: var(--sc-color-danger-text);
2445
+ --_bg-hover: var(--sc-color-danger-subtle);
2446
+ --_bg-on: var(--sc-color-danger-subtle);
2447
+ --_fg-on: var(--sc-color-danger-text);
2448
+ --_bd-on: var(--sc-color-danger-solid);
2449
+ }
2450
+ .sc-chip[data-tone='info'] {
2451
+ --_fg: var(--sc-color-info-text);
2452
+ --_bd: var(--sc-color-info-text);
2453
+ --_bg-hover: var(--sc-color-info-subtle);
2454
+ --_bg-on: var(--sc-color-info-subtle);
2455
+ --_fg-on: var(--sc-color-info-text);
2456
+ --_bd-on: var(--sc-color-info-solid);
2457
+ }
2458
+ @media (prefers-reduced-motion: reduce) {
2459
+ .sc-chip {
2460
+ transition: none;
2461
+ }
2462
+ }
2463
+
2464
+ /* ---- disclosure.css ---- */
2465
+ /* ---- Disclosure ------------------------------------------------------------ */
2466
+ .sc-disclosure {
2467
+ display: flex;
2468
+ flex-direction: column;
2469
+ gap: var(--sc-spacing-xs);
2470
+ min-inline-size: 0;
2471
+ font-family: var(--sc-font-family-sans);
2472
+ font-size: var(--sc-font-size-sm);
2473
+ line-height: var(--sc-font-line-height-normal);
2474
+ color: var(--sc-color-text-default);
2475
+ }
2476
+ .sc-disclosure__summary {
2477
+ display: inline-flex;
2478
+ align-items: center;
2479
+ gap: var(--sc-spacing-2xs);
2480
+ inline-size: fit-content;
2481
+ margin-inline: calc(-1 * var(--sc-spacing-2xs));
2482
+ padding: var(--sc-spacing-2xs);
2483
+ border-radius: var(--sc-radius-sm);
2484
+ color: var(--sc-color-accent-text);
2485
+ font-weight: var(--sc-font-weight-medium);
2486
+ line-height: var(--sc-font-line-height-ui);
2487
+ list-style: none;
2488
+ cursor: pointer;
2489
+ user-select: none;
2490
+ }
2491
+ .sc-disclosure__summary::-webkit-details-marker,
2492
+ .sc-disclosure__summary::marker {
2493
+ display: none;
2494
+ content: '';
2495
+ }
2496
+ .sc-disclosure__summary:hover {
2497
+ background: var(--sc-color-surface-hover);
2498
+ }
2499
+ .sc-disclosure__summary:focus-visible {
2500
+ outline: var(--sc-border-width-focus) solid var(--sc-color-border-focus);
2501
+ outline-offset: 0;
2502
+ }
2503
+ .sc-disclosure__chevron {
2504
+ flex: none;
2505
+ inline-size: var(--sc-size-icon-md);
2506
+ block-size: var(--sc-size-icon-md);
2507
+ transition: rotate var(--sc-duration-fast) var(--sc-ease-standard);
2508
+ }
2509
+ .sc-disclosure[open] > .sc-disclosure__summary > .sc-disclosure__chevron {
2510
+ rotate: 180deg;
2511
+ }
2512
+ .sc-disclosure[data-summary-position='end'] > .sc-disclosure__summary {
2513
+ order: 1;
2514
+ }
2515
+ .sc-disclosure__content {
2516
+ min-inline-size: 0;
2517
+ }
2518
+ /* Preview: while closed, the content stays rendered, clipped to N lines and faded. Browsers without
2519
+ `::details-content` keep the native behaviour (content hidden until open). */
2520
+ .sc-disclosure[data-preview]:not([open])::details-content {
2521
+ content-visibility: visible;
2522
+ display: block;
2523
+ max-block-size: calc(var(--_lines, 3) * 1lh);
2524
+ overflow: clip;
2525
+ mask-image: linear-gradient(to bottom, #000 40%, transparent 100%);
2526
+ }
2527
+ @media (prefers-reduced-motion: reduce) {
2528
+ .sc-disclosure__chevron {
2529
+ transition: none;
2530
+ }
2531
+ }
2532
+
2533
+ /* ---- empty-state.css ---- */
2534
+ /* ---- EmptyState ------------------------------------------------------------ */
2535
+ .sc-empty-state {
2536
+ --_icon: var(--sc-size-icon-xl);
2537
+ --_ring: 48px;
2538
+ --_py: var(--sc-spacing-2xl);
2539
+ --_title: var(--sc-font-size-lg);
2540
+ display: flex;
2541
+ flex-direction: column;
2542
+ align-items: center;
2543
+ gap: var(--sc-spacing-xs);
2544
+ box-sizing: border-box;
2545
+ inline-size: 100%;
2546
+ margin: 0;
2547
+ padding: var(--_py) var(--sc-spacing-lg);
2548
+ list-style: none;
2549
+ text-align: center;
2550
+ font-family: var(--sc-font-family-sans);
2551
+ color: var(--sc-color-text-default);
2552
+ }
2553
+ .sc-empty-state[data-size='sm'] {
2554
+ --_icon: var(--sc-size-icon-lg);
2555
+ --_ring: 40px;
2556
+ --_py: var(--sc-spacing-lg);
2557
+ --_title: var(--sc-font-size-md);
2558
+ gap: var(--sc-spacing-2xs);
2559
+ }
2560
+ .sc-empty-state__icon {
2561
+ display: inline-grid;
2562
+ place-items: center;
2563
+ inline-size: var(--_ring);
2564
+ block-size: var(--_ring);
2565
+ margin-block-end: var(--sc-spacing-xs);
2566
+ border-radius: var(--sc-radius-full);
2567
+ background: var(--sc-color-surface-sunken);
2568
+ color: var(--sc-color-text-muted);
2569
+ }
2570
+ .sc-empty-state__icon > svg {
2571
+ inline-size: var(--_icon);
2572
+ block-size: var(--_icon);
2573
+ }
2574
+ .sc-empty-state__title {
2575
+ margin: 0;
2576
+ max-inline-size: 36ch;
2577
+ font-size: var(--_title);
2578
+ font-weight: var(--sc-font-weight-semibold);
2579
+ line-height: var(--sc-font-line-height-snug);
2580
+ letter-spacing: var(--sc-font-tracking-snug);
2581
+ text-wrap: balance;
2582
+ }
2583
+ .sc-empty-state__description {
2584
+ margin: 0;
2585
+ max-inline-size: 48ch;
2586
+ font-size: var(--sc-font-size-sm);
2587
+ line-height: var(--sc-font-line-height-normal);
2588
+ color: var(--sc-color-text-muted);
2589
+ text-wrap: pretty;
2590
+ }
2591
+ .sc-empty-state__actions {
2592
+ display: flex;
2593
+ flex-wrap: wrap;
2594
+ justify-content: center;
2595
+ gap: var(--sc-spacing-xs);
2596
+ margin-block-start: var(--sc-spacing-sm);
2597
+ }
2598
+
2599
+ /* ---- skeleton.css ---- */
2600
+ /* ---- Skeleton -------------------------------------------------------------- */
2601
+ .sc-skeleton {
2602
+ --_base: var(--sc-color-surface-active);
2603
+ --_sheen: var(--sc-color-surface-hover);
2604
+ display: block;
2605
+ box-sizing: border-box;
2606
+ inline-size: 100%;
2607
+ block-size: 1em;
2608
+ border-radius: var(--sc-radius-sm);
2609
+ background: var(--_base);
2610
+ background-image: linear-gradient(90deg, var(--_base) 0%, var(--_sheen) 50%, var(--_base) 100%);
2611
+ background-size: 200% 100%;
2612
+ animation: sc-shimmer 1.6s ease-in-out infinite;
2613
+ }
2614
+ .sc-skeleton[data-variant='text'] {
2615
+ display: inline-block;
2616
+ vertical-align: middle;
2617
+ block-size: 1em;
2618
+ border-radius: var(--sc-radius-sm);
2619
+ }
2620
+ .sc-skeleton[data-variant='rect'] {
2621
+ block-size: 80px;
2622
+ border-radius: var(--sc-radius-md);
2623
+ }
2624
+ .sc-skeleton[data-variant='circle'] {
2625
+ inline-size: 40px;
2626
+ aspect-ratio: 1;
2627
+ block-size: auto;
2628
+ border-radius: var(--sc-radius-full);
2629
+ }
2630
+ .sc-skeleton[data-still] {
2631
+ animation: none;
2632
+ background-image: none;
2633
+ }
2634
+ .sc-skeleton-lines {
2635
+ display: flex;
2636
+ flex-direction: column;
2637
+ gap: calc(1lh - 1em);
2638
+ inline-size: 100%;
2639
+ }
2640
+ .sc-skeleton-lines > .sc-skeleton {
2641
+ display: block;
2642
+ }
2643
+ .sc-skeleton-lines > .sc-skeleton[data-last] {
2644
+ inline-size: 60%;
2645
+ }
2646
+ @keyframes sc-shimmer {
2647
+ from {
2648
+ background-position: 200% 0;
2649
+ }
2650
+ to {
2651
+ background-position: -200% 0;
2652
+ }
2653
+ }
2654
+ @media (prefers-reduced-motion: reduce) {
2655
+ .sc-skeleton {
2656
+ animation: none;
2657
+ background-image: none;
2658
+ }
2659
+ }
2660
+
2195
2661
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@salemcobalt/ui",
3
- "version": "0.2.0-rc.4",
4
- "description": "React components for the Salem Cobalt design system: Button, IconButton, Icon set, Badge, Card, Stack, Inline, Kbd, Dialog, Tooltip, Menu, Toolbar, Banner, Spinner, Progress, Tabs, Input, Textarea, Select, Checkbox, Switch, Heading, Text, Table, Stat.",
3
+ "version": "0.2.0-rc.5",
4
+ "description": "React components for the Salem Cobalt design system: Button, IconButton, Icon set, Badge, Card, Stack, Inline, Kbd, Dialog, Tooltip, Menu, Toolbar, Banner, Spinner, Progress, Tabs, Input, Textarea, Select, Checkbox, Switch, Heading, Text, Table, Stat, Chip, Disclosure, EmptyState, Skeleton.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  "peerDependencies": {
34
34
  "react": "^19.0.0",
35
35
  "react-dom": "^19.0.0",
36
- "@salemcobalt/tokens": "^0.2.0-rc.4"
36
+ "@salemcobalt/tokens": "^0.2.0-rc.5"
37
37
  },
38
38
  "dependencies": {
39
39
  "@base-ui/react": "^1.9.0",
@@ -56,7 +56,7 @@
56
56
  "tsup": "^9.0.0",
57
57
  "typescript": "^5.9.3",
58
58
  "vitest": "^5.0.5",
59
- "@salemcobalt/tokens": "^0.2.0-rc.4"
59
+ "@salemcobalt/tokens": "^0.2.0-rc.5"
60
60
  },
61
61
  "publishConfig": {
62
62
  "access": "public"