@salemcobalt/ui 0.2.0-rc.8 → 0.2.0-rc.9

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.8 — requires @salemcobalt/tokens/css. */
1
+ /* @salemcobalt/ui 0.2.0-rc.9 — requires @salemcobalt/tokens/css. */
2
2
  @layer sc {
3
3
  /* ---- base.css ---- */
4
4
  /* Shared: focus ring, reduced motion. Component files follow. */
@@ -306,6 +306,10 @@
306
306
  .sc-button[data-loading] > .sc-button__label {
307
307
  opacity: 0;
308
308
  }
309
+ /* Its own line box, so descenders sit inside the label (the button sets line-height: 1 for centring). */
310
+ .sc-button__label {
311
+ line-height: var(--sc-font-line-height-ui);
312
+ }
309
313
  .sc-button__icon {
310
314
  display: inline-flex;
311
315
  inline-size: 1.125em;
@@ -325,6 +329,44 @@
325
329
  border-inline-end-color: transparent;
326
330
  animation: sc-spin 0.8s linear infinite;
327
331
  }
332
+ /* Icon-only: square, the label kept for assistive tech only, no shortcut hint. Same element, so focus and
333
+ any open tooltip survive the switch. */
334
+ .sc-button[data-icon-only] {
335
+ inline-size: var(--_h);
336
+ padding-inline: 0;
337
+ }
338
+ .sc-button[data-icon-only] > .sc-button__label {
339
+ position: absolute;
340
+ inline-size: 1px;
341
+ block-size: 1px;
342
+ overflow: hidden;
343
+ clip-path: inset(50%);
344
+ white-space: nowrap;
345
+ }
346
+ .sc-button[data-icon-only] > .sc-button__shortcut {
347
+ display: none;
348
+ }
349
+ /* A shortcut hint after the label: a Kbd tinted to the button's own colour, so it reads on every variant. */
350
+ .sc-button__shortcut {
351
+ display: inline-flex;
352
+ align-items: center;
353
+ gap: var(--sc-spacing-3xs);
354
+ flex: none;
355
+ margin-inline-start: var(--sc-spacing-3xs);
356
+ }
357
+ .sc-button__shortcut .sc-kbd {
358
+ background: transparent;
359
+ color: inherit;
360
+ border-color: currentColor;
361
+ box-shadow: none;
362
+ opacity: 0.72;
363
+ }
364
+ .sc-button__shortcut .sc-kbd-group {
365
+ color: inherit;
366
+ }
367
+ .sc-button[data-loading] > .sc-button__shortcut {
368
+ opacity: 0;
369
+ }
328
370
  @keyframes sc-spin {
329
371
  to {
330
372
  rotate: 1turn;
@@ -361,6 +403,40 @@
361
403
  .sc-icon-button[data-loading] > .sc-button__icon {
362
404
  opacity: 0;
363
405
  }
406
+ /* Status dot, top-left: icons such as the broom own the top-right and fill the bottom. Physical corner on
407
+ purpose, because the glyph does not mirror in RTL either. */
408
+ .sc-icon-button__dot {
409
+ --_dot: var(--sc-color-accent-default);
410
+ position: absolute;
411
+ inset: var(--sc-spacing-2xs) auto auto var(--sc-spacing-2xs);
412
+ inline-size: 8px;
413
+ block-size: 8px;
414
+ border-radius: var(--sc-radius-full);
415
+ background: var(--_dot);
416
+ box-shadow: 0 0 0 var(--sc-border-width-focus)
417
+ var(--sc-icon-button-dot-ring, var(--sc-color-surface-default));
418
+ pointer-events: none;
419
+ }
420
+ .sc-icon-button[data-size='sm'] > .sc-icon-button__dot {
421
+ inset: var(--sc-spacing-3xs) auto auto var(--sc-spacing-3xs);
422
+ inline-size: 6px;
423
+ block-size: 6px;
424
+ }
425
+ .sc-icon-button__dot[data-tone='neutral'] {
426
+ --_dot: var(--sc-color-text-subtle);
427
+ }
428
+ .sc-icon-button__dot[data-tone='success'] {
429
+ --_dot: var(--sc-color-success-solid);
430
+ }
431
+ .sc-icon-button__dot[data-tone='warning'] {
432
+ --_dot: var(--sc-color-warning-solid);
433
+ }
434
+ .sc-icon-button__dot[data-tone='danger'] {
435
+ --_dot: var(--sc-color-danger-solid);
436
+ }
437
+ .sc-icon-button__dot[data-tone='info'] {
438
+ --_dot: var(--sc-color-info-solid);
439
+ }
364
440
  .sc-button[data-popup-open] {
365
441
  background: var(--sc-color-surface-active);
366
442
  }
@@ -1703,6 +1779,50 @@
1703
1779
  .sc-tabs__panel[data-hidden] {
1704
1780
  display: none;
1705
1781
  }
1782
+ /* Segmented: a quiet control. Sunken track, the active tab raised on `surface-default` by the sliding
1783
+ indicator, no accent colour; counts are plain muted numbers
1784
+ (`text-muted`, not `text-subtle`, which fails AA on the sunken track). */
1785
+ .sc-tabs__list[data-variant='segmented'] {
1786
+ display: inline-flex;
1787
+ align-self: flex-start;
1788
+ max-inline-size: 100%;
1789
+ gap: var(--sc-spacing-3xs);
1790
+ padding: var(--sc-spacing-3xs);
1791
+ border-block-end: 0;
1792
+ border-radius: var(--sc-radius-md);
1793
+ background: var(--sc-color-surface-sunken);
1794
+ isolation: isolate;
1795
+ }
1796
+ .sc-tabs__list[data-variant='segmented'][data-fill] {
1797
+ display: flex;
1798
+ align-self: stretch;
1799
+ }
1800
+ .sc-tabs__list[data-variant='segmented'] > .sc-tabs__tab {
1801
+ position: relative;
1802
+ z-index: 1;
1803
+ block-size: var(--sc-size-control-sm);
1804
+ padding-inline: var(--sc-spacing-sm);
1805
+ border-radius: var(--sc-radius-sm);
1806
+ }
1807
+ .sc-tabs__list[data-variant='segmented'] > .sc-tabs__tab:hover:not([data-disabled]) {
1808
+ background: transparent;
1809
+ }
1810
+ .sc-tabs__list[data-variant='segmented'] .sc-tabs__count,
1811
+ .sc-tabs__list[data-variant='segmented'] > .sc-tabs__tab[data-active] > .sc-tabs__count {
1812
+ padding-inline: 0;
1813
+ background: transparent;
1814
+ color: var(--sc-color-text-muted);
1815
+ font-weight: var(--sc-font-weight-regular);
1816
+ }
1817
+ .sc-tabs__list[data-variant='segmented'] > .sc-tabs__indicator {
1818
+ inset-block: 0 auto;
1819
+ z-index: 0;
1820
+ block-size: var(--active-tab-height);
1821
+ translate: var(--active-tab-left) var(--active-tab-top);
1822
+ background: var(--sc-color-surface-default);
1823
+ border-radius: var(--sc-radius-sm);
1824
+ box-shadow: var(--sc-elevation-1);
1825
+ }
1706
1826
  @media (prefers-reduced-motion: reduce) {
1707
1827
  .sc-tabs__tab,
1708
1828
  .sc-tabs__indicator {
@@ -1710,6 +1830,440 @@
1710
1830
  }
1711
1831
  }
1712
1832
 
1833
+ /* ---- priority-nav.css ---- */
1834
+ /* ---- PriorityNav ----------------------------------------------------------- */
1835
+ /* Takes the free space in a flex header (brand · nav · actions) without sizing to its own links, so the
1836
+ row can grow back after collapsing. In a grid, give it a `minmax(0, 1fr)` track. */
1837
+ .sc-priority-nav {
1838
+ position: relative;
1839
+ flex: 1 1 0%;
1840
+ min-inline-size: 0;
1841
+ /* The toggle goes icon-only when the nav itself is narrow (below), whatever the viewport. */
1842
+ container: sc-priority-nav / inline-size;
1843
+ font-family: var(--sc-font-family-sans);
1844
+ font-size: var(--sc-font-size-sm);
1845
+ }
1846
+ .sc-priority-nav__list {
1847
+ display: flex;
1848
+ flex-wrap: nowrap;
1849
+ align-items: center;
1850
+ gap: var(--sc-spacing-2xs);
1851
+ min-inline-size: 0;
1852
+ margin: 0;
1853
+ padding: 0;
1854
+ list-style: none;
1855
+ }
1856
+ .sc-priority-nav__item,
1857
+ .sc-priority-nav__more {
1858
+ flex: none;
1859
+ display: flex;
1860
+ }
1861
+ .sc-priority-nav__more[hidden] {
1862
+ display: none;
1863
+ }
1864
+ /* Once measured, the current link is the one item that may shrink (ellipsis) when the row cannot hold it
1865
+ and "More". While measuring it keeps its full width like the others. */
1866
+ .sc-priority-nav:not([data-measuring]) .sc-priority-nav__item[data-current] {
1867
+ flex: 0 1 auto;
1868
+ min-inline-size: 0;
1869
+ }
1870
+ /* Before measurement (server HTML, pre-hydration, no JS): one line that never wraps. With JS the line
1871
+ clips for the few frames before hydration measures it; without JS it scrolls sideways (below). */
1872
+ .sc-priority-nav[data-measuring] > .sc-priority-nav__list {
1873
+ overflow-x: auto;
1874
+ overflow-y: hidden;
1875
+ scrollbar-width: none;
1876
+ }
1877
+ .sc-priority-nav[data-measuring] .sc-priority-nav__more[hidden] {
1878
+ display: flex;
1879
+ position: absolute;
1880
+ visibility: hidden;
1881
+ pointer-events: none;
1882
+ }
1883
+ @media (scripting: none) {
1884
+ .sc-priority-nav[data-measuring] > .sc-priority-nav__list {
1885
+ scrollbar-width: thin;
1886
+ }
1887
+ }
1888
+ .sc-priority-nav__link,
1889
+ .sc-priority-nav__toggle {
1890
+ display: inline-flex;
1891
+ align-items: center;
1892
+ gap: var(--sc-spacing-2xs);
1893
+ box-sizing: border-box;
1894
+ block-size: var(--sc-size-control-sm);
1895
+ margin: 0;
1896
+ padding-inline: var(--sc-spacing-sm);
1897
+ border: 0;
1898
+ border-radius: var(--sc-radius-sm);
1899
+ background: transparent;
1900
+ color: var(--sc-color-text-muted);
1901
+ font: inherit;
1902
+ font-weight: var(--sc-font-weight-medium);
1903
+ line-height: var(--sc-font-line-height-ui);
1904
+ white-space: nowrap;
1905
+ text-decoration: none;
1906
+ cursor: pointer;
1907
+ user-select: none;
1908
+ transition:
1909
+ background-color var(--sc-duration-fast) var(--sc-ease-standard),
1910
+ color var(--sc-duration-fast) var(--sc-ease-standard);
1911
+ }
1912
+ .sc-priority-nav__link {
1913
+ min-inline-size: 0;
1914
+ }
1915
+ .sc-priority-nav__label {
1916
+ min-inline-size: 0;
1917
+ overflow: hidden;
1918
+ text-overflow: ellipsis;
1919
+ }
1920
+ .sc-priority-nav__link:hover,
1921
+ .sc-priority-nav__toggle:hover {
1922
+ background: var(--sc-color-surface-hover);
1923
+ color: var(--sc-color-text-default);
1924
+ }
1925
+ .sc-priority-nav__link:active,
1926
+ .sc-priority-nav__toggle:active {
1927
+ background: var(--sc-color-surface-active);
1928
+ }
1929
+ .sc-priority-nav__link[aria-current='page'] {
1930
+ color: var(--sc-color-text-default);
1931
+ box-shadow: inset 0 calc(-1 * var(--sc-border-width-focus)) 0 var(--sc-color-accent-default);
1932
+ border-end-start-radius: 0;
1933
+ border-end-end-radius: 0;
1934
+ }
1935
+ .sc-priority-nav__link:focus-visible,
1936
+ .sc-priority-nav__toggle:focus-visible {
1937
+ outline: var(--sc-border-width-focus) solid var(--sc-color-border-focus);
1938
+ outline-offset: calc(-1 * var(--sc-border-width-focus));
1939
+ }
1940
+ .sc-priority-nav__toggle[aria-expanded='true'] {
1941
+ background: var(--sc-color-surface-active);
1942
+ color: var(--sc-color-text-default);
1943
+ }
1944
+ .sc-priority-nav__ellipsis {
1945
+ display: none;
1946
+ }
1947
+ @container sc-priority-nav (inline-size <= 400px) {
1948
+ .sc-priority-nav__toggle {
1949
+ justify-content: center;
1950
+ inline-size: var(--sc-size-control-sm);
1951
+ padding-inline: 0;
1952
+ }
1953
+ .sc-priority-nav__ellipsis {
1954
+ display: inline-block;
1955
+ }
1956
+ .sc-priority-nav__chevron {
1957
+ display: none;
1958
+ }
1959
+ /* Visually hidden, still part of the accessible name ("More, 3 links"). */
1960
+ .sc-priority-nav__toggle-label {
1961
+ position: absolute;
1962
+ inline-size: 1px;
1963
+ block-size: 1px;
1964
+ overflow: hidden;
1965
+ clip-path: inset(50%);
1966
+ white-space: nowrap;
1967
+ }
1968
+ }
1969
+ .sc-priority-nav__chevron {
1970
+ transition: rotate var(--sc-duration-fast) var(--sc-ease-standard);
1971
+ }
1972
+ .sc-priority-nav__toggle[aria-expanded='true'] > .sc-priority-nav__chevron {
1973
+ rotate: 180deg;
1974
+ }
1975
+ /* The panel: Menu's surface, a list of the collapsed links. While open it is in the top layer (Popover
1976
+ API), so no ancestor's overflow clips it; it is fixed-positioned against the viewport either way. */
1977
+ .sc-priority-nav__toggle {
1978
+ anchor-name: var(--_anchor);
1979
+ }
1980
+ .sc-priority-nav__panel {
1981
+ --_gutter: var(--sc-spacing-md);
1982
+ position: fixed;
1983
+ inset: auto;
1984
+ z-index: var(--sc-z-dropdown);
1985
+ display: flex;
1986
+ flex-direction: column;
1987
+ box-sizing: border-box;
1988
+ inline-size: max-content;
1989
+ min-inline-size: min(180px, 100vw - 2 * var(--_gutter));
1990
+ max-inline-size: min(320px, 100vw - 2 * var(--_gutter));
1991
+ max-block-size: min(28rem, 100dvh - 2 * var(--_gutter));
1992
+ overflow-y: auto;
1993
+ overscroll-behavior: contain;
1994
+ margin: 0;
1995
+ padding: var(--sc-spacing-2xs);
1996
+ list-style: none;
1997
+ border-radius: var(--sc-radius-lg);
1998
+ background: var(--sc-color-surface-raised);
1999
+ --sc-color-surface-hover: var(--sc-color-surface-raised-hover);
2000
+ --sc-color-surface-active: var(--sc-color-surface-raised-active);
2001
+ color: var(--sc-color-text-default);
2002
+ border: var(--sc-border-width-hairline) solid var(--sc-color-border-default);
2003
+ box-shadow: var(--sc-elevation-2);
2004
+ font-family: var(--sc-font-family-sans);
2005
+ font-size: var(--sc-font-size-sm);
2006
+ transition:
2007
+ opacity var(--sc-duration-fast) var(--sc-ease-enter),
2008
+ translate var(--sc-duration-fast) var(--sc-ease-enter);
2009
+ }
2010
+ /* Anchored below the toggle, aligned to its inline-end edge; flips to its inline-start edge (and above
2011
+ it) when that would leave the viewport; when no edge fits, it spans the viewport row under the toggle,
2012
+ centred on it and kept a gutter from both edges. Without anchor positioning, JS sets left/top (place.ts). */
2013
+ @supports (anchor-name: --a) {
2014
+ .sc-priority-nav__panel {
2015
+ position-anchor: var(--_anchor);
2016
+ position-area: block-end span-inline-start;
2017
+ margin-block: var(--sc-spacing-2xs);
2018
+ /* Makes an option that ends closer than the gutter to the viewport edge count as overflowing. */
2019
+ margin-inline-start: var(--_gutter);
2020
+ position-try-fallbacks:
2021
+ flip-inline,
2022
+ flip-block,
2023
+ flip-block flip-inline,
2024
+ --sc-priority-nav-fit;
2025
+ }
2026
+ }
2027
+ @position-try --sc-priority-nav-fit {
2028
+ position-area: block-end span-all;
2029
+ justify-self: anchor-center;
2030
+ margin-inline: var(--_gutter);
2031
+ }
2032
+ @starting-style {
2033
+ .sc-priority-nav__panel {
2034
+ opacity: 0;
2035
+ translate: 0 calc(-1 * var(--sc-spacing-2xs));
2036
+ }
2037
+ }
2038
+ .sc-priority-nav__panel[hidden] {
2039
+ display: none;
2040
+ }
2041
+ .sc-priority-nav__panel .sc-priority-nav__link {
2042
+ display: flex;
2043
+ inline-size: 100%;
2044
+ padding-inline: var(--sc-spacing-xs);
2045
+ color: var(--sc-color-text-default);
2046
+ }
2047
+ @media (prefers-reduced-motion: reduce) {
2048
+ .sc-priority-nav__link,
2049
+ .sc-priority-nav__toggle,
2050
+ .sc-priority-nav__chevron,
2051
+ .sc-priority-nav__panel {
2052
+ transition: none;
2053
+ }
2054
+ }
2055
+
2056
+ /* ---- popover.css ---- */
2057
+ /* ---- Popover --------------------------------------------------------------- */
2058
+ .sc-popover__positioner {
2059
+ z-index: var(--sc-z-dropdown);
2060
+ outline: 0;
2061
+ }
2062
+ /* Menu's surface: raised background, hairline border, large radius, elevation 2. */
2063
+ .sc-popover {
2064
+ position: relative;
2065
+ box-sizing: border-box;
2066
+ inline-size: max-content;
2067
+ max-inline-size: min(100vw - 2 * var(--sc-spacing-md), 360px);
2068
+ max-block-size: var(--available-height);
2069
+ overflow: auto;
2070
+ padding: var(--sc-spacing-md);
2071
+ border-radius: var(--sc-radius-lg);
2072
+ background: var(--sc-color-surface-raised);
2073
+ --sc-color-surface-hover: var(--sc-color-surface-raised-hover);
2074
+ --sc-color-surface-active: var(--sc-color-surface-raised-active);
2075
+ color: var(--sc-color-text-default);
2076
+ border: var(--sc-border-width-hairline) solid var(--sc-color-border-default);
2077
+ box-shadow: var(--sc-elevation-2);
2078
+ font-family: var(--sc-font-family-sans);
2079
+ font-size: var(--sc-font-size-sm);
2080
+ line-height: var(--sc-font-line-height-normal);
2081
+ outline: 0;
2082
+ transform-origin: var(--transform-origin);
2083
+ transition:
2084
+ opacity var(--sc-duration-fast) var(--sc-ease-enter),
2085
+ scale var(--sc-duration-fast) var(--sc-ease-enter);
2086
+ }
2087
+ /* With an arrow the popup must not clip it. */
2088
+ .sc-popover:has(> .sc-popover__arrow) {
2089
+ overflow: visible;
2090
+ }
2091
+ .sc-popover[data-starting-style],
2092
+ .sc-popover[data-ending-style] {
2093
+ opacity: 0;
2094
+ scale: 0.97;
2095
+ }
2096
+ .sc-popover[data-ending-style] {
2097
+ transition-timing-function: var(--sc-ease-exit);
2098
+ }
2099
+ .sc-popover[data-instant] {
2100
+ transition: none;
2101
+ }
2102
+ .sc-popover__title {
2103
+ margin: 0;
2104
+ font-size: var(--sc-font-size-md);
2105
+ line-height: var(--sc-font-line-height-snug);
2106
+ font-weight: var(--sc-font-weight-semibold);
2107
+ }
2108
+ .sc-popover__title:has(~ .sc-popover__close),
2109
+ .sc-popover__close ~ .sc-popover__title {
2110
+ padding-inline-end: var(--sc-spacing-xl);
2111
+ }
2112
+ .sc-popover__description {
2113
+ margin: var(--sc-spacing-2xs) 0 0;
2114
+ color: var(--sc-color-text-muted);
2115
+ }
2116
+ .sc-popover__close {
2117
+ position: absolute;
2118
+ inset-block-start: var(--sc-spacing-xs);
2119
+ inset-inline-end: var(--sc-spacing-xs);
2120
+ display: inline-grid;
2121
+ place-items: center;
2122
+ inline-size: var(--sc-size-control-sm);
2123
+ block-size: var(--sc-size-control-sm);
2124
+ padding: 0;
2125
+ border: 0;
2126
+ border-radius: var(--sc-radius-md);
2127
+ background: transparent;
2128
+ color: var(--sc-color-text-muted);
2129
+ cursor: pointer;
2130
+ }
2131
+ .sc-popover__close:hover {
2132
+ background: var(--sc-color-surface-hover);
2133
+ color: var(--sc-color-text-default);
2134
+ }
2135
+ .sc-popover__close:focus-visible {
2136
+ outline: var(--sc-border-width-focus) solid var(--sc-color-border-focus);
2137
+ outline-offset: calc(-1 * var(--sc-border-width-focus));
2138
+ }
2139
+ /* A 16×8 tip with the popup's fill and border, placed by Base UI on the side facing the trigger. It overlaps
2140
+ the popup's border by one hairline so the border does not run across its base. */
2141
+ .sc-popover__arrow {
2142
+ --_w: 16px;
2143
+ --_h: 8px;
2144
+ display: block;
2145
+ inline-size: var(--_w);
2146
+ block-size: calc(var(--_h) + var(--sc-border-width-hairline));
2147
+ overflow: clip;
2148
+ pointer-events: none;
2149
+ }
2150
+ .sc-popover__arrow::before {
2151
+ content: '';
2152
+ position: absolute;
2153
+ inset-block-end: 0;
2154
+ inset-inline-start: 50%;
2155
+ box-sizing: border-box;
2156
+ inline-size: calc(var(--_h) * 1.4142);
2157
+ block-size: calc(var(--_h) * 1.4142);
2158
+ background: var(--sc-color-surface-raised);
2159
+ border: var(--sc-border-width-hairline) solid var(--sc-color-border-default);
2160
+ translate: -50% 50%;
2161
+ rotate: 45deg;
2162
+ }
2163
+ .sc-popover__arrow[data-side='top'] {
2164
+ inset-block-end: calc(-1 * var(--_h));
2165
+ rotate: 180deg;
2166
+ }
2167
+ .sc-popover__arrow[data-side='bottom'] {
2168
+ inset-block-start: calc(-1 * var(--_h));
2169
+ }
2170
+ .sc-popover__arrow[data-side='left'],
2171
+ .sc-popover__arrow[data-side='inline-start'] {
2172
+ inset-inline-end: calc(-1 * (var(--_w) + var(--_h)) / 2);
2173
+ rotate: 90deg;
2174
+ }
2175
+ .sc-popover__arrow[data-side='right'],
2176
+ .sc-popover__arrow[data-side='inline-end'] {
2177
+ inset-inline-start: calc(-1 * (var(--_w) + var(--_h)) / 2);
2178
+ rotate: -90deg;
2179
+ }
2180
+ @media (prefers-reduced-motion: reduce) {
2181
+ .sc-popover {
2182
+ transition-duration: 0ms;
2183
+ }
2184
+ .sc-popover[data-starting-style],
2185
+ .sc-popover[data-ending-style] {
2186
+ scale: none;
2187
+ }
2188
+ }
2189
+
2190
+ /* ---- broom-icon.css ---- */
2191
+ /* ---- BroomIcon ------------------------------------------------------------- */
2192
+ /* Geometry and motion as approved: the body pivots on the handle top (20.2, 2.2) from -14deg to 8deg while
2193
+ the dust fades in and drifts left in step; strokes stay a fixed screen width at any size. */
2194
+ .sc-broom {
2195
+ --sc-broom-stroke: 1.25px;
2196
+ }
2197
+ /* `display` (72px) is a one-off for the broom's showcase and empty states. Move it into the Icon sizes and
2198
+ tokens if a second icon ever needs it. */
2199
+ .sc-icon.sc-broom[data-size='display'] {
2200
+ --_s: calc(var(--sc-size-icon-xl) * 3);
2201
+ --sc-broom-stroke: 1.75px;
2202
+ }
2203
+ .sc-broom__body,
2204
+ .sc-broom__dust {
2205
+ transform-box: view-box;
2206
+ stroke-width: var(--sc-broom-stroke);
2207
+ }
2208
+ .sc-broom__body {
2209
+ transform-origin: 20.2px 2.2px;
2210
+ }
2211
+ .sc-broom * {
2212
+ vector-effect: non-scaling-stroke;
2213
+ }
2214
+ .sc-broom__band {
2215
+ fill: currentColor;
2216
+ stroke: none;
2217
+ }
2218
+ .sc-broom__dust {
2219
+ opacity: 0;
2220
+ }
2221
+ .sc-broom[data-sweeping] .sc-broom__body {
2222
+ animation: sc-broom-sweep 0.9s ease-in-out infinite alternate;
2223
+ }
2224
+ .sc-broom[data-sweeping] .sc-broom__dust {
2225
+ animation: sc-broom-dust 0.9s ease-in-out infinite alternate;
2226
+ }
2227
+ @keyframes sc-broom-sweep {
2228
+ from {
2229
+ transform: rotate(-14deg);
2230
+ }
2231
+ to {
2232
+ transform: rotate(8deg);
2233
+ }
2234
+ }
2235
+ /* At the top of the sweep (8deg) the head stays about 2 grid units clear of the dust. */
2236
+ @keyframes sc-broom-dust {
2237
+ from {
2238
+ opacity: 0;
2239
+ transform: translateX(0.5px);
2240
+ }
2241
+ to {
2242
+ opacity: 0.9;
2243
+ transform: translateX(-1px);
2244
+ }
2245
+ }
2246
+ @media (prefers-reduced-motion: reduce) {
2247
+ .sc-broom[data-sweeping] .sc-broom__body,
2248
+ .sc-broom[data-sweeping] .sc-broom__dust {
2249
+ animation: none;
2250
+ }
2251
+ .sc-broom[data-sweeping] .sc-broom__dust {
2252
+ opacity: 0.9;
2253
+ }
2254
+ }
2255
+ /* Drawn on a 24px grid (the shipped icons use 16px), so inside an IconButton it takes the next icon size up:
2256
+ 20px in an md button, as in the approved nav mock. */
2257
+ .sc-icon-button > .sc-button__icon:has(> .sc-broom) {
2258
+ --_icon: var(--sc-size-icon-lg);
2259
+ }
2260
+ .sc-icon-button[data-size='sm'] > .sc-button__icon:has(> .sc-broom) {
2261
+ --_icon: var(--sc-size-icon-md);
2262
+ }
2263
+ .sc-icon-button[data-size='lg'] > .sc-button__icon:has(> .sc-broom) {
2264
+ --_icon: var(--sc-size-icon-xl);
2265
+ }
2266
+
1713
2267
  /* ---- toolbar.css ---- */
1714
2268
  /* ---- Toolbar --------------------------------------------------------------- */
1715
2269
  .sc-toolbar {
@@ -2374,9 +2928,11 @@
2374
2928
  inline-size: 100%;
2375
2929
  block-size: 100%;
2376
2930
  }
2931
+ /* The label clips for the ellipsis, so it needs a real line box or descenders get cut (the chip sets line-height: 1). */
2377
2932
  .sc-chip__label {
2378
2933
  overflow: hidden;
2379
2934
  text-overflow: ellipsis;
2935
+ line-height: var(--sc-font-line-height-ui);
2380
2936
  }
2381
2937
  .sc-chip[data-removable] > .sc-chip__action,
2382
2938
  .sc-chip[data-removable] > .sc-chip__label {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@salemcobalt/ui",
3
- "version": "0.2.0-rc.8",
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, FileInput, Checkbox, Switch, Heading, Text, Table, Stat, Chip, Disclosure, EmptyState, Skeleton.",
3
+ "version": "0.2.0-rc.9",
4
+ "description": "React components for the Salem Cobalt design system: Button, IconButton, Icon set, BroomIcon, Badge, Card, Stack, Inline, Kbd, Dialog, Tooltip, Menu, Popover, PriorityNav, Toolbar, Banner, Spinner, Progress, Tabs, Input, Textarea, Select, FileInput, 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.8"
36
+ "@salemcobalt/tokens": "^0.2.0-rc.9"
37
37
  },
38
38
  "dependencies": {
39
39
  "@base-ui/react": "^1.9.0",
@@ -57,7 +57,7 @@
57
57
  "tsup": "^9.0.0",
58
58
  "typescript": "^5.9.3",
59
59
  "vitest": "^5.0.5",
60
- "@salemcobalt/tokens": "^0.2.0-rc.8"
60
+ "@salemcobalt/tokens": "^0.2.0-rc.9"
61
61
  },
62
62
  "publishConfig": {
63
63
  "access": "public"