@openwarelabs/ui 0.14.1 → 0.15.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.
Files changed (33) hide show
  1. package/README.md +5 -5
  2. package/dist/components/InlineEdit/InlineEdit.d.cts +8 -0
  3. package/dist/components/InlineEdit/InlineEdit.d.ts +8 -0
  4. package/dist/components/InlineEdit/InlineEdit.types.d.cts +74 -0
  5. package/dist/components/InlineEdit/InlineEdit.types.d.ts +74 -0
  6. package/dist/components/NavigationMenu/NavigationMenu.d.cts +14 -0
  7. package/dist/components/NavigationMenu/NavigationMenu.d.ts +14 -0
  8. package/dist/components/NavigationMenu/NavigationMenu.types.d.cts +84 -0
  9. package/dist/components/NavigationMenu/NavigationMenu.types.d.ts +84 -0
  10. package/dist/components/SortableList/SortableList.d.cts +7 -0
  11. package/dist/components/SortableList/SortableList.d.ts +7 -0
  12. package/dist/components/SortableList/SortableList.types.d.cts +82 -0
  13. package/dist/components/SortableList/SortableList.types.d.ts +82 -0
  14. package/dist/components/TreeView/TreeView.d.cts +8 -0
  15. package/dist/components/TreeView/TreeView.d.ts +8 -0
  16. package/dist/components/TreeView/TreeView.types.d.cts +88 -0
  17. package/dist/components/TreeView/TreeView.types.d.ts +88 -0
  18. package/dist/components/VirtualList/VirtualList.d.cts +9 -0
  19. package/dist/components/VirtualList/VirtualList.d.ts +9 -0
  20. package/dist/components/VirtualList/VirtualList.types.d.cts +80 -0
  21. package/dist/components/VirtualList/VirtualList.types.d.ts +80 -0
  22. package/dist/components/VirtualList/useVirtualizer.d.cts +60 -0
  23. package/dist/components/VirtualList/useVirtualizer.d.ts +60 -0
  24. package/dist/components.css +637 -0
  25. package/dist/index.cjs +2732 -1328
  26. package/dist/index.cjs.map +4 -4
  27. package/dist/index.d.cts +12 -0
  28. package/dist/index.d.ts +12 -0
  29. package/dist/index.js +2695 -1267
  30. package/dist/index.js.map +4 -4
  31. package/dist/openware-ui.iife.js +9 -8
  32. package/dist/styles.css +637 -0
  33. package/package.json +1 -1
package/dist/styles.css CHANGED
@@ -1789,6 +1789,208 @@
1789
1789
  outline: 0;
1790
1790
  }
1791
1791
 
1792
+ /* components/InlineEdit/InlineEdit.css */
1793
+ /* InlineEdit: text that turns into a text box where it is. The button and the box share their font, padding and border,
1794
+ and pull back by them, so the text lines up with what's around it and doesn't move when the box opens. */
1795
+ .ow-inline-edit {
1796
+ --ow-inline-edit-x: 0.375em;
1797
+ --ow-inline-edit-y: 0.125em;
1798
+ --ow-inline-edit-icon: clamp(12px, 0.75em, 20px);
1799
+ display: inline-grid;
1800
+ max-width: 100%;
1801
+ grid-template-columns: minmax(0, 1fr);
1802
+ gap: var(--ow-space-2xs);
1803
+ }
1804
+
1805
+ .ow-inline-edit--multiline {
1806
+ display: grid;
1807
+ }
1808
+
1809
+ .ow-inline-edit__display,
1810
+ .ow-inline-edit__input,
1811
+ .ow-inline-edit__field::after {
1812
+ box-sizing: border-box;
1813
+ margin: 0;
1814
+ border: 1px solid transparent;
1815
+ border-radius: var(--ow-radius-sm);
1816
+ padding: var(--ow-inline-edit-y) var(--ow-inline-edit-x);
1817
+ color: inherit;
1818
+ font: inherit;
1819
+ letter-spacing: inherit;
1820
+ }
1821
+
1822
+ .ow-inline-edit__display,
1823
+ .ow-inline-edit__editor {
1824
+ margin-inline: calc(-1px - var(--ow-inline-edit-x));
1825
+ }
1826
+
1827
+ .ow-inline-edit__display {
1828
+ position: relative;
1829
+ display: inline-flex;
1830
+ min-width: 0;
1831
+ align-items: baseline;
1832
+ gap: 0.3em;
1833
+ background: transparent;
1834
+ cursor: pointer;
1835
+ text-align: start;
1836
+ }
1837
+
1838
+ .ow-inline-edit--multiline .ow-inline-edit__display {
1839
+ display: flex;
1840
+ }
1841
+
1842
+ .ow-inline-edit__display:hover:not(:disabled) {
1843
+ background: var(--ow-hover);
1844
+ }
1845
+
1846
+ .ow-inline-edit__display:focus-visible {
1847
+ outline: 2px solid var(--ow-focus-ring);
1848
+ outline-offset: 2px;
1849
+ }
1850
+
1851
+ .ow-inline-edit__display:disabled {
1852
+ cursor: not-allowed;
1853
+ opacity: 0.62;
1854
+ }
1855
+
1856
+ .ow-inline-edit__text {
1857
+ min-width: 0;
1858
+ overflow-wrap: anywhere;
1859
+ white-space: pre-wrap;
1860
+ }
1861
+
1862
+ .ow-inline-edit__text--empty {
1863
+ color: var(--ow-text-muted);
1864
+ }
1865
+
1866
+ /* The pencil shows on hover and focus; on touch screens, which can't hover, always. */
1867
+ .ow-inline-edit__icon {
1868
+ width: var(--ow-inline-edit-icon);
1869
+ height: var(--ow-inline-edit-icon);
1870
+ flex: none;
1871
+ align-self: center;
1872
+ color: var(--ow-icon);
1873
+ opacity: 0;
1874
+ }
1875
+
1876
+ .ow-inline-edit__display:hover .ow-inline-edit__icon,
1877
+ .ow-inline-edit__display:focus-visible .ow-inline-edit__icon {
1878
+ opacity: 1;
1879
+ }
1880
+
1881
+ @media (hover: none) {
1882
+ .ow-inline-edit__display:not(:disabled) .ow-inline-edit__icon {
1883
+ opacity: 1;
1884
+ }
1885
+ }
1886
+
1887
+ .ow-inline-edit__editor {
1888
+ display: flex;
1889
+ min-width: 0;
1890
+ align-items: center;
1891
+ gap: var(--ow-space-xs);
1892
+ }
1893
+
1894
+ /* The box is as wide as a hidden copy of its text, plus the pencil's room, in the same grid cell. */
1895
+ .ow-inline-edit__field {
1896
+ display: inline-grid;
1897
+ min-width: 0;
1898
+ grid-template-columns: minmax(0, 1fr);
1899
+ }
1900
+
1901
+ .ow-inline-edit__field::after {
1902
+ overflow: hidden;
1903
+ padding-inline-end: calc(var(--ow-inline-edit-x) + var(--ow-inline-edit-icon) + 0.3em);
1904
+ content: attr(data-value) " ";
1905
+ grid-area: 1 / 1;
1906
+ visibility: hidden;
1907
+ white-space: pre;
1908
+ }
1909
+
1910
+ .ow-inline-edit__input {
1911
+ display: block;
1912
+ width: 100%;
1913
+ min-width: 0;
1914
+ min-height: 0;
1915
+ flex: 1;
1916
+ grid-area: 1 / 1;
1917
+ border-color: var(--ow-border-strong);
1918
+ background: var(--ow-surface);
1919
+ outline: 0;
1920
+ }
1921
+
1922
+ .ow-inline-edit__input::placeholder {
1923
+ color: var(--ow-text-muted);
1924
+ opacity: 1;
1925
+ }
1926
+
1927
+ .ow-inline-edit__input:focus {
1928
+ border-color: var(--ow-focus-border);
1929
+ box-shadow: var(--ow-shadow-focus);
1930
+ }
1931
+
1932
+ .ow-inline-edit__input:focus-visible {
1933
+ outline: 2px solid var(--ow-focus-ring);
1934
+ outline-offset: 2px;
1935
+ }
1936
+
1937
+ .ow-inline-edit__input[aria-invalid="true"] {
1938
+ border-color: var(--ow-danger-solid);
1939
+ }
1940
+
1941
+ .ow-inline-edit__input[aria-invalid="true"]:focus {
1942
+ box-shadow: var(--ow-shadow-focus-danger);
1943
+ }
1944
+
1945
+ /* An auto-growing textarea is as tall as its scrollHeight, which leaves out the border, so it draws its border inside. */
1946
+ textarea.ow-inline-edit__input {
1947
+ border: 0;
1948
+ padding: calc(var(--ow-inline-edit-y) + 1px) calc(var(--ow-inline-edit-x) + 1px);
1949
+ box-shadow: inset 0 0 0 1px var(--ow-border-strong);
1950
+ }
1951
+
1952
+ textarea.ow-inline-edit__input:focus {
1953
+ box-shadow:
1954
+ inset 0 0 0 1px var(--ow-focus-border),
1955
+ var(--ow-shadow-focus);
1956
+ }
1957
+
1958
+ textarea.ow-inline-edit__input[aria-invalid="true"] {
1959
+ box-shadow: inset 0 0 0 1px var(--ow-danger-solid);
1960
+ }
1961
+
1962
+ textarea.ow-inline-edit__input[aria-invalid="true"]:focus {
1963
+ box-shadow:
1964
+ inset 0 0 0 1px var(--ow-danger-solid),
1965
+ var(--ow-shadow-focus-danger);
1966
+ }
1967
+
1968
+ .ow-inline-edit__actions {
1969
+ display: inline-flex;
1970
+ flex: none;
1971
+ gap: var(--ow-space-2xs);
1972
+ }
1973
+
1974
+ .ow-inline-edit__spinner {
1975
+ flex: none;
1976
+ }
1977
+
1978
+ .ow-inline-edit__error {
1979
+ color: var(--ow-danger-text);
1980
+ font: var(--ow-weight-regular) 14px / 1.4 var(--ow-font-sans);
1981
+ letter-spacing: normal;
1982
+ }
1983
+
1984
+ @media (prefers-reduced-motion: no-preference) {
1985
+ .ow-inline-edit__display,
1986
+ .ow-inline-edit__icon,
1987
+ .ow-inline-edit__input {
1988
+ transition-property: background-color, border-color, box-shadow, opacity;
1989
+ transition-duration: var(--ow-duration-fast);
1990
+ transition-timing-function: var(--ow-ease-standard);
1991
+ }
1992
+ }
1993
+
1792
1994
  /* components/Select/Select.css */
1793
1995
  /* Select: the trigger looks like a field; the listbox floats in the top layer. */
1794
1996
  .ow-select {
@@ -7036,6 +7238,125 @@
7036
7238
  font-size: 12px;
7037
7239
  }
7038
7240
 
7241
+ /* components/SortableList/SortableList.css */
7242
+ /* SortableList: rows (or chips, in a row) people put in order. The picked-up one lifts; the others slide aside. */
7243
+ .ow-sortable {
7244
+ display: flex;
7245
+ flex-direction: column;
7246
+ gap: var(--ow-space-xs);
7247
+ margin: 0;
7248
+ padding: 0;
7249
+ list-style: none;
7250
+ }
7251
+
7252
+ .ow-sortable--horizontal {
7253
+ flex-direction: row;
7254
+ overflow-x: auto;
7255
+ padding-block: var(--ow-space-2xs);
7256
+ }
7257
+
7258
+ .ow-sortable__item {
7259
+ position: relative;
7260
+ display: flex;
7261
+ flex: none;
7262
+ min-height: 40px;
7263
+ align-items: center;
7264
+ gap: var(--ow-space-xs);
7265
+ padding: var(--ow-space-xs) var(--ow-space-lg);
7266
+ border: 1px solid var(--ow-border);
7267
+ border-radius: var(--ow-radius-md);
7268
+ background: var(--ow-surface);
7269
+ color: var(--ow-text);
7270
+ font-size: 14px;
7271
+ outline: none;
7272
+ }
7273
+
7274
+ .ow-sortable--horizontal .ow-sortable__item {
7275
+ min-height: 32px;
7276
+ padding-block: var(--ow-space-2xs);
7277
+ }
7278
+
7279
+ .ow-sortable__content {
7280
+ flex: 1;
7281
+ min-width: 0;
7282
+ }
7283
+
7284
+ /* Whatever picks it up: the row, or its grip. Touch drags it rather than scrolling the page. */
7285
+ .ow-sortable__item--row,
7286
+ .ow-sortable__handle {
7287
+ cursor: grab;
7288
+ touch-action: none;
7289
+ user-select: none;
7290
+ -webkit-user-select: none;
7291
+ }
7292
+
7293
+ .ow-sortable__handle {
7294
+ display: inline-flex;
7295
+ width: 24px;
7296
+ height: 28px;
7297
+ flex: none;
7298
+ align-items: center;
7299
+ justify-content: center;
7300
+ margin-inline-start: calc(var(--ow-space-xs) * -1);
7301
+ padding: 0;
7302
+ border: 0;
7303
+ border-radius: var(--ow-radius-md);
7304
+ background: none;
7305
+ color: var(--ow-icon);
7306
+ }
7307
+
7308
+ .ow-sortable__handle:hover {
7309
+ background: var(--ow-hover);
7310
+ color: var(--ow-text-muted);
7311
+ }
7312
+
7313
+ .ow-sortable--horizontal .ow-sortable__grip {
7314
+ rotate: 90deg;
7315
+ }
7316
+
7317
+ .ow-sortable__item--row:focus-visible,
7318
+ .ow-sortable__handle:focus-visible {
7319
+ outline: 2px solid var(--ow-focus-ring);
7320
+ outline-offset: 1px;
7321
+ }
7322
+
7323
+ /* While one is picked up, the others slide to make room. */
7324
+ .ow-sortable--dragging .ow-sortable__item {
7325
+ transition: transform var(--ow-duration-base) var(--ow-ease-standard);
7326
+ }
7327
+
7328
+ .ow-sortable .ow-sortable__item--dragging {
7329
+ z-index: 1;
7330
+ border-color: var(--ow-border-strong);
7331
+ box-shadow: var(--ow-shadow-menu);
7332
+ transition: none;
7333
+ }
7334
+
7335
+ :root[data-ow-sortable-drag],
7336
+ :root[data-ow-sortable-drag] * {
7337
+ cursor: grabbing !important;
7338
+ user-select: none;
7339
+ -webkit-user-select: none;
7340
+ }
7341
+
7342
+ .ow-sortable--disabled .ow-sortable__item {
7343
+ background: var(--ow-surface-muted);
7344
+ color: var(--ow-text-muted);
7345
+ cursor: default;
7346
+ }
7347
+
7348
+ .ow-sortable--disabled .ow-sortable__handle {
7349
+ background: none;
7350
+ color: var(--ow-text-disabled);
7351
+ cursor: not-allowed;
7352
+ }
7353
+
7354
+ @media (prefers-reduced-motion: reduce) {
7355
+ .ow-sortable--dragging .ow-sortable__item {
7356
+ transition: none;
7357
+ }
7358
+ }
7359
+
7039
7360
  /* components/Table/Table.css */
7040
7361
  /* Table: a bordered card with a quiet header row and hairlines between rows. */
7041
7362
  .ow-table-wrap {
@@ -8002,6 +8323,134 @@
8002
8323
  font-size: 12px;
8003
8324
  }
8004
8325
 
8326
+ /* components/TreeView/TreeView.css */
8327
+ /* TreeView: rows that open, select and check. FileTree's hairline guides, NavList's 14px text. */
8328
+ .ow-treeview,
8329
+ .ow-treeview__group {
8330
+ display: grid;
8331
+ gap: 1px;
8332
+ margin: 0;
8333
+ padding: 0;
8334
+ list-style: none;
8335
+ }
8336
+
8337
+ .ow-treeview {
8338
+ color: var(--ow-text);
8339
+ font-size: 14px;
8340
+ }
8341
+
8342
+ /* The guide runs under the parent's chevron. */
8343
+ .ow-treeview__group {
8344
+ margin-inline-start: 14px;
8345
+ border-inline-start: 1px solid var(--ow-border);
8346
+ padding-inline-start: var(--ow-space-2xs);
8347
+ }
8348
+
8349
+ .ow-treeview__item {
8350
+ outline: none;
8351
+ }
8352
+
8353
+ .ow-treeview__row {
8354
+ display: flex;
8355
+ min-height: 32px;
8356
+ align-items: center;
8357
+ gap: var(--ow-space-xs);
8358
+ border-radius: var(--ow-radius-form);
8359
+ padding-block: var(--ow-space-2xs);
8360
+ padding-inline: var(--ow-space-2xs) var(--ow-space-sm);
8361
+ cursor: pointer;
8362
+ user-select: none;
8363
+ transition: background-color var(--ow-duration-fast) var(--ow-ease-standard);
8364
+ }
8365
+
8366
+ .ow-treeview__row:hover {
8367
+ background: var(--ow-surface-muted);
8368
+ }
8369
+
8370
+ .ow-treeview__item:focus-visible > .ow-treeview__row {
8371
+ box-shadow: 0 0 0 2px var(--ow-focus-ring);
8372
+ }
8373
+
8374
+ .ow-treeview__row--selected,
8375
+ .ow-treeview__row--selected:hover {
8376
+ background: var(--ow-primary-subtle);
8377
+ color: var(--ow-primary-text);
8378
+ }
8379
+
8380
+ .ow-treeview__row--disabled,
8381
+ .ow-treeview__row--loading {
8382
+ color: var(--ow-text-muted);
8383
+ cursor: default;
8384
+ }
8385
+
8386
+ .ow-treeview__toggle {
8387
+ display: inline-flex;
8388
+ width: 20px;
8389
+ height: 24px;
8390
+ flex-shrink: 0;
8391
+ align-items: center;
8392
+ justify-content: center;
8393
+ color: var(--ow-text-muted);
8394
+ }
8395
+
8396
+ .ow-treeview__toggle svg {
8397
+ transition: transform var(--ow-duration-base) var(--ow-ease-standard);
8398
+ }
8399
+
8400
+ .ow-treeview__toggle:dir(rtl) svg {
8401
+ transform: scaleX(-1);
8402
+ }
8403
+
8404
+ [aria-expanded="true"] > .ow-treeview__row .ow-treeview__toggle svg {
8405
+ transform: rotate(90deg);
8406
+ }
8407
+
8408
+ .ow-treeview .ow-checkbox__input {
8409
+ pointer-events: none;
8410
+ }
8411
+
8412
+ .ow-treeview__icon {
8413
+ display: inline-flex;
8414
+ flex-shrink: 0;
8415
+ color: var(--ow-text-muted);
8416
+ }
8417
+
8418
+ .ow-treeview__text {
8419
+ display: grid;
8420
+ min-width: 0;
8421
+ flex: 1;
8422
+ }
8423
+
8424
+ .ow-treeview__label,
8425
+ .ow-treeview__description {
8426
+ overflow: hidden;
8427
+ text-overflow: ellipsis;
8428
+ white-space: nowrap;
8429
+ }
8430
+
8431
+ .ow-treeview__description,
8432
+ .ow-treeview__end {
8433
+ color: var(--ow-text-muted);
8434
+ font-size: 12px;
8435
+ }
8436
+
8437
+ .ow-treeview__end {
8438
+ flex-shrink: 0;
8439
+ }
8440
+
8441
+ .ow-treeview__row--selected :is(.ow-treeview__icon, .ow-treeview__description, .ow-treeview__end) {
8442
+ color: inherit;
8443
+ }
8444
+
8445
+ .ow-treeview__row--error {
8446
+ color: var(--ow-danger-text);
8447
+ }
8448
+
8449
+ .ow-treeview__retry {
8450
+ font-weight: var(--ow-weight-emphasis);
8451
+ text-decoration: underline;
8452
+ }
8453
+
8005
8454
  /* components/EmptyState/EmptyState.css */
8006
8455
  /* EmptyState: centred, at most 360px of text, an icon tile above. */
8007
8456
  .ow-empty {
@@ -8212,6 +8661,148 @@
8212
8661
  font-weight: var(--ow-weight-regular);
8213
8662
  }
8214
8663
 
8664
+ /* components/NavigationMenu/NavigationMenu.css */
8665
+ /* NavigationMenu: a site's top links, with panels of links on Popover's surface. Rules are scoped under
8666
+ .ow-navigation-menu so SiteHeader's `nav a` colours don't reach into the panels. */
8667
+ .ow-navigation-menu {
8668
+ min-width: 0;
8669
+ font-family: var(--ow-font-sans);
8670
+ }
8671
+
8672
+ .ow-navigation-menu__list {
8673
+ display: flex;
8674
+ flex-wrap: wrap;
8675
+ align-items: center;
8676
+ gap: var(--ow-space-2xs);
8677
+ margin: 0;
8678
+ padding: 0;
8679
+ list-style: none;
8680
+ }
8681
+
8682
+ .ow-navigation-menu .ow-navigation-menu__trigger {
8683
+ display: inline-flex;
8684
+ min-height: 32px;
8685
+ align-items: center;
8686
+ gap: var(--ow-space-3xs);
8687
+ border: 0;
8688
+ border-radius: var(--ow-radius-pill);
8689
+ background: transparent;
8690
+ padding: 0 var(--ow-space-sm);
8691
+ color: var(--ow-text-soft);
8692
+ font: inherit;
8693
+ font-size: 14px;
8694
+ font-weight: var(--ow-weight-control);
8695
+ text-decoration: none;
8696
+ cursor: pointer;
8697
+ transition-property: color, background-color;
8698
+ transition-duration: var(--ow-duration-base);
8699
+ transition-timing-function: var(--ow-ease-standard);
8700
+ }
8701
+
8702
+ .ow-navigation-menu .ow-navigation-menu__trigger:hover,
8703
+ .ow-navigation-menu__trigger[aria-expanded="true"] {
8704
+ background: var(--ow-hover);
8705
+ color: var(--ow-text);
8706
+ }
8707
+
8708
+ .ow-navigation-menu__trigger[aria-current="page"],
8709
+ .ow-navigation-menu__trigger[data-active] {
8710
+ color: var(--ow-text);
8711
+ }
8712
+
8713
+ .ow-navigation-menu .ow-navigation-menu__trigger:focus-visible,
8714
+ .ow-navigation-menu .ow-navigation-menu__link:focus-visible {
8715
+ outline: 2px solid var(--ow-focus-ring);
8716
+ outline-offset: -2px;
8717
+ }
8718
+
8719
+ .ow-navigation-menu__chevron {
8720
+ color: var(--ow-text-muted);
8721
+ transition: transform var(--ow-duration-base) var(--ow-ease-standard);
8722
+ }
8723
+
8724
+ [aria-expanded="true"] > .ow-navigation-menu__chevron {
8725
+ transform: rotate(180deg);
8726
+ }
8727
+
8728
+ .ow-navigation-menu__panel {
8729
+ grid-template-columns: repeat(var(--ow-navigation-menu-columns), minmax(0, 15rem));
8730
+ max-width: calc(100vw - 16px);
8731
+ padding: var(--ow-space-sm);
8732
+ gap: var(--ow-space-sm);
8733
+ }
8734
+
8735
+ .ow-navigation-menu__panel--full {
8736
+ grid-template-columns: repeat(var(--ow-navigation-menu-columns), minmax(0, 1fr));
8737
+ }
8738
+
8739
+ .ow-navigation-menu__group {
8740
+ display: grid;
8741
+ align-content: start;
8742
+ gap: var(--ow-space-3xs);
8743
+ }
8744
+
8745
+ .ow-navigation-menu__group-title {
8746
+ padding: var(--ow-space-xs) var(--ow-space-sm) var(--ow-space-2xs);
8747
+ color: var(--ow-text-muted);
8748
+ font-size: 12px;
8749
+ font-weight: var(--ow-weight-label);
8750
+ }
8751
+
8752
+ .ow-navigation-menu .ow-navigation-menu__link {
8753
+ display: flex;
8754
+ align-items: flex-start;
8755
+ gap: var(--ow-space-sm);
8756
+ border-radius: var(--ow-radius-lg);
8757
+ padding: var(--ow-space-sm);
8758
+ color: var(--ow-text);
8759
+ text-decoration: none;
8760
+ transition: background-color var(--ow-duration-base) var(--ow-ease-standard);
8761
+ }
8762
+
8763
+ .ow-navigation-menu .ow-navigation-menu__link:hover,
8764
+ .ow-navigation-menu__link[aria-current="page"] {
8765
+ background: var(--ow-surface-muted);
8766
+ }
8767
+
8768
+ .ow-navigation-menu__icon {
8769
+ display: inline-flex;
8770
+ flex-shrink: 0;
8771
+ color: var(--ow-text-muted);
8772
+ }
8773
+
8774
+ .ow-navigation-menu__text {
8775
+ display: grid;
8776
+ min-width: 0;
8777
+ gap: 2px;
8778
+ }
8779
+
8780
+ .ow-navigation-menu__title {
8781
+ font-weight: var(--ow-weight-emphasis);
8782
+ line-height: 1.3;
8783
+ }
8784
+
8785
+ .ow-navigation-menu__description {
8786
+ color: var(--ow-text-muted);
8787
+ font-size: 13px;
8788
+ line-height: 1.4;
8789
+ }
8790
+
8791
+ .ow-navigation-menu .ow-navigation-menu__link--featured,
8792
+ .ow-navigation-menu .ow-navigation-menu__link--featured:hover {
8793
+ flex-direction: column;
8794
+ justify-content: flex-end;
8795
+ min-height: 9rem;
8796
+ background: var(--ow-primary-subtle);
8797
+ padding: var(--ow-space-lg);
8798
+ }
8799
+
8800
+ @media (max-width: 640px) {
8801
+ .ow-navigation-menu__panel {
8802
+ grid-template-columns: minmax(0, 1fr);
8803
+ }
8804
+ }
8805
+
8215
8806
  /* components/AppShell/AppShell.css */
8216
8807
  /* AppShell: a sidebar down the left and the page beside it. It measures its own width (a container query), so it
8217
8808
  folds into a drawer under its breakpoint (900px by default) whether it fills the window or sits in a smaller frame. */
@@ -8727,6 +9318,52 @@
8727
9318
  }
8728
9319
  }
8729
9320
 
9321
+ /* components/VirtualList/VirtualList.css */
9322
+ /* VirtualList: a scrolling list that renders only the rows in view, each placed by its offset from the top. */
9323
+ .ow-virtual-list {
9324
+ position: relative;
9325
+ display: flex;
9326
+ flex-direction: column;
9327
+ height: 100%;
9328
+ min-height: 0;
9329
+ }
9330
+
9331
+ .ow-virtual-list__scroll {
9332
+ flex: 1 1 auto;
9333
+ min-height: 0;
9334
+ overflow-x: hidden;
9335
+ overflow-y: auto;
9336
+ overscroll-behavior: contain;
9337
+ /* The list keeps its own place as rows are measured or added above; the browser's anchoring would double it. */
9338
+ overflow-anchor: none;
9339
+ border-radius: inherit;
9340
+ }
9341
+
9342
+ .ow-virtual-list__scroll:focus-visible,
9343
+ .ow-virtual-list__item:focus-visible {
9344
+ outline: 2px solid var(--ow-focus-ring);
9345
+ outline-offset: -2px;
9346
+ }
9347
+
9348
+ .ow-virtual-list__inner {
9349
+ position: relative;
9350
+ flex-shrink: 0;
9351
+ width: 100%;
9352
+ }
9353
+
9354
+ .ow-virtual-list__item {
9355
+ position: absolute;
9356
+ top: 0;
9357
+ inset-inline: 0;
9358
+ border-radius: var(--ow-radius-md);
9359
+ }
9360
+
9361
+ .ow-virtual-list__footer {
9362
+ display: flex;
9363
+ justify-content: center;
9364
+ padding: var(--ow-space-md);
9365
+ }
9366
+
8730
9367
  /* components/AspectRatio/AspectRatio.css */
8731
9368
  /* AspectRatio: a box that keeps its shape, with whatever is inside filling it. The hidden overflow keeps the ratio
8732
9369
  when the content is taller than the box would be. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openwarelabs/ui",
3
- "version": "0.14.1",
3
+ "version": "0.15.0",
4
4
  "description": "Openware UI: React components and design tokens — midnight and brass, tactile buttons and Inter, in light and dark.",
5
5
  "license": "MIT",
6
6
  "author": "Alexander Silver",