@crewlethq/ui 0.82.0 → 0.83.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 (139) hide show
  1. package/README.md +29 -1
  2. package/dist/AppShell/AccountRow.d.ts +6 -1
  3. package/dist/AppShell/AppShell.d.ts +15 -6
  4. package/dist/AppShell/index.d.ts +1 -1
  5. package/dist/AppShell/index.js +8 -5
  6. package/dist/AppShell/railMotion.d.ts +60 -0
  7. package/dist/AppShell/railShape.d.ts +5 -0
  8. package/dist/{AppShell-F7RID4P4.css → AppShell-U7D2MUUF.css} +177 -56
  9. package/dist/ArrangeList/index.js +3 -2
  10. package/dist/ArtifactBar/index.js +7 -5
  11. package/dist/ArtifactCard/index.js +2 -2
  12. package/dist/AuthLayout/index.js +3 -3
  13. package/dist/AvatarPicker/index.js +7 -6
  14. package/dist/BrandLockup/index.js +2 -2
  15. package/dist/Canvas/index.js +4 -2
  16. package/dist/CanvasBoard/index.js +6 -4
  17. package/dist/CanvasToolbar/index.js +5 -3
  18. package/dist/ChangeMark/index.js +4 -2
  19. package/dist/ChatThread/index.js +2 -2
  20. package/dist/CommandPalette/index.js +3 -2
  21. package/dist/CompactNav/index.js +2 -1
  22. package/dist/ContrastHelp/index.js +3 -2
  23. package/dist/DataGrid/index.js +2 -2
  24. package/dist/DataTable/index.js +4 -3
  25. package/dist/DataView/index.js +7 -6
  26. package/dist/DateTimePicker/index.js +3 -2
  27. package/dist/DeepWorkCard/index.js +2 -2
  28. package/dist/DocTabsEditor/index.js +5 -3
  29. package/dist/DockColumn/DockColumn.d.ts +68 -0
  30. package/dist/DockColumn/index.d.ts +3 -0
  31. package/dist/DockColumn/index.js +6 -0
  32. package/dist/DockColumn-SMJCXHS4.css +61 -0
  33. package/dist/{Editor-7EQWP3RN.js → Editor-5D5Z3LBQ.js} +3 -2
  34. package/dist/EmojiPicker/index.js +5 -3
  35. package/dist/FactList/index.js +4 -2
  36. package/dist/HuePicker/index.js +5 -4
  37. package/dist/LinkInterstitial/index.js +3 -2
  38. package/dist/ListInput/index.js +3 -2
  39. package/dist/MarkdownEditor/index.js +5 -4
  40. package/dist/MediaMatch/index.d.ts +1 -1
  41. package/dist/MediaMatch/index.js +1 -1
  42. package/dist/MediaMatch/useMediaMatch.d.ts +14 -0
  43. package/dist/Menu/index.js +2 -1
  44. package/dist/MergeConflicts/index.js +5 -4
  45. package/dist/MessageActions/index.js +6 -4
  46. package/dist/Modal/index.js +2 -1
  47. package/dist/OpenInAppCard/index.js +2 -2
  48. package/dist/Outline/index.js +2 -1
  49. package/dist/Popover/index.js +2 -1
  50. package/dist/Presence/index.d.ts +2 -0
  51. package/dist/Presence/index.js +4 -0
  52. package/dist/Presence/usePresence.d.ts +109 -0
  53. package/dist/ReactionBar/index.js +6 -4
  54. package/dist/RecordChip/index.js +3 -2
  55. package/dist/Reorder/index.js +2 -1
  56. package/dist/RichEditor/index.js +1 -1
  57. package/dist/SegmentedControl/index.js +4 -3
  58. package/dist/SetupWizard/index.js +2 -2
  59. package/dist/ShareDialog/index.js +4 -3
  60. package/dist/SheetColumnEditor/index.js +6 -5
  61. package/dist/SheetGrid/index.js +8 -6
  62. package/dist/SlideFilmstrip/index.js +5 -3
  63. package/dist/Switcher/index.js +5 -4
  64. package/dist/Tabs/index.js +3 -2
  65. package/dist/ThemeSwitcher/index.js +5 -4
  66. package/dist/TimeRangePicker/index.js +6 -5
  67. package/dist/TimeWindowPicker/index.js +3 -2
  68. package/dist/Tooltip/index.js +3 -1
  69. package/dist/TreeCanvas/index.js +6 -3
  70. package/dist/VersionCompare/index.js +5 -4
  71. package/dist/{chunk-KJR5X4II.js → chunk-22CU7V4J.js} +2 -2
  72. package/dist/{chunk-4RYELYWG.js → chunk-2SVQBQAD.js} +2 -2
  73. package/dist/{chunk-HQFOZJQ4.js → chunk-46FIBJCV.js} +4 -4
  74. package/dist/{chunk-LQRN2XZK.js → chunk-4DEKONVJ.js} +2 -2
  75. package/dist/chunk-5JPOFAVN.js +58 -0
  76. package/dist/{chunk-C7UHDM7Y.js → chunk-5V6GW6HK.js} +1 -1
  77. package/dist/{chunk-XGLMPPDW.js → chunk-7K6LVM5I.js} +1 -1
  78. package/dist/{chunk-FKAJBN6G.js → chunk-7M7WKYOV.js} +3 -3
  79. package/dist/{chunk-A5YKNRG6.js → chunk-7QCSISHM.js} +2 -1
  80. package/dist/{chunk-3QQIGMY3.js → chunk-7ZSEUO5Q.js} +6 -30
  81. package/dist/{chunk-57BFL323.js → chunk-ABRWL5FJ.js} +1 -1
  82. package/dist/{chunk-HFOTRZFU.js → chunk-AQNP3KQU.js} +2 -2
  83. package/dist/{chunk-N2T7Y5KR.js → chunk-AUSFKGKL.js} +1 -1
  84. package/dist/{chunk-GZVAZ3LL.js → chunk-AZYE7NR4.js} +1 -1
  85. package/dist/{chunk-6IOQWMYJ.js → chunk-BN5FEJL5.js} +1 -1
  86. package/dist/{chunk-MPVMB2DV.js → chunk-BVML4UVB.js} +3 -2
  87. package/dist/{chunk-XY4O2XMR.js → chunk-BXGBGYKH.js} +3 -3
  88. package/dist/{chunk-OAHRMR4U.js → chunk-C42XW5YP.js} +1 -1
  89. package/dist/{chunk-HA2PL7PA.js → chunk-DRFOTWJE.js} +1 -1
  90. package/dist/{chunk-SM4P2SHB.js → chunk-EC6EUIAD.js} +7 -4
  91. package/dist/{chunk-AMUXSJ2A.js → chunk-FPU7AA3X.js} +4 -15
  92. package/dist/{chunk-KLAVEJIO.js → chunk-GLKQHN7G.js} +1 -1
  93. package/dist/chunk-HTS5RJ7S.js +6 -0
  94. package/dist/{chunk-GP5TNTZH.js → chunk-ICE3D63E.js} +3 -5
  95. package/dist/{chunk-ISQANI6Q.js → chunk-JLOESTT2.js} +2 -1
  96. package/dist/{chunk-C75WZMXG.js → chunk-K6RWEQ6P.js} +1 -1
  97. package/dist/{chunk-GVPUCEWH.js → chunk-KXWJJWBD.js} +1 -1
  98. package/dist/chunk-L72URIHR.js +36 -0
  99. package/dist/{chunk-2TOGGCDM.js → chunk-LT44RL62.js} +2 -2
  100. package/dist/{chunk-HCUECVZ3.js → chunk-MVKUE4FI.js} +1 -1
  101. package/dist/{chunk-6YBBQAEM.js → chunk-MYAARF4Z.js} +1 -1
  102. package/dist/{chunk-SEKO6P3Y.js → chunk-NCUSI4ZU.js} +1 -1
  103. package/dist/chunk-PCAT2EFB.js +104 -0
  104. package/dist/{chunk-T4IEESXN.js → chunk-PGBKZSSQ.js} +87 -24
  105. package/dist/{chunk-TGCGLKD4.js → chunk-RBQRTGXX.js} +1 -1
  106. package/dist/{chunk-B3X4DHRB.js → chunk-RDIQB5ZE.js} +2 -2
  107. package/dist/{chunk-T7WESRZF.js → chunk-RO5JU6SN.js} +2 -2
  108. package/dist/{chunk-IUWP2LSE.js → chunk-SGMWLUYQ.js} +2 -2
  109. package/dist/{chunk-LSOR77RZ.js → chunk-SHH7UD5U.js} +1 -1
  110. package/dist/{chunk-JV6JM6W6.js → chunk-SNQ7PH3D.js} +1 -1
  111. package/dist/{chunk-MPYRC3GO.js → chunk-SPNTUQBV.js} +2 -2
  112. package/dist/{chunk-YM77TZ7Q.js → chunk-T3S3D4FC.js} +1 -1
  113. package/dist/{chunk-YOJAGKTS.js → chunk-TGGYSQRD.js} +3 -4
  114. package/dist/{chunk-2KJCUCVE.js → chunk-TQKQRS2J.js} +2 -2
  115. package/dist/{chunk-ONNXUS5Y.js → chunk-VB3FVKNI.js} +1 -1
  116. package/dist/{chunk-JHQGNFN3.js → chunk-VONEKR3J.js} +2 -2
  117. package/dist/{chunk-P6F3PE4V.js → chunk-WANKINXG.js} +2 -2
  118. package/dist/{chunk-PXLS6JKL.js → chunk-WMO722J2.js} +1 -1
  119. package/dist/{chunk-SYVQXMLO.js → chunk-XRWHDW6F.js} +4 -4
  120. package/dist/{chunk-WT3B76MG.js → chunk-XTJHMP3W.js} +1 -1
  121. package/dist/{chunk-RTPQDNW3.js → chunk-YJQXESOJ.js} +5 -1
  122. package/dist/{chunk-VGOWSOUA.js → chunk-YXKSUILG.js} +1 -1
  123. package/dist/{chunk-G6ZFSUIH.js → chunk-ZJVLGYE3.js} +2 -2
  124. package/dist/{chunk-BSAU7QRW.js → chunk-ZPTKAYJK.js} +1 -1
  125. package/dist/{chunk-XXDB6KPV.js → chunk-ZXXZESCD.js} +3 -4
  126. package/dist/generated/index.d.ts +2 -0
  127. package/dist/generated/index.js +97 -93
  128. package/dist/index.js +97 -93
  129. package/dist/styles.css +242 -57
  130. package/dist/utils/composedRef.d.ts +39 -0
  131. package/dist/utils/index.d.ts +2 -0
  132. package/dist/utils/index.js +3 -1
  133. package/dist/utils/tokenMs.d.ts +6 -0
  134. package/package.json +5 -5
  135. package/dist/{chunk-IYI6HWKN.js → chunk-CV2LU2T2.js} +1 -1
  136. package/dist/{chunk-FVZPSTL2.js → chunk-G4EHZHKM.js} +1 -1
  137. package/dist/{chunk-FEJANUZK.js → chunk-KBSD476L.js} +0 -0
  138. package/dist/{chunk-2H6YDUR5.js → chunk-QM3432PH.js} +1 -1
  139. /package/dist/{chunk-KLWWNV25.js → chunk-REEZQCML.js} +0 -0
package/dist/styles.css CHANGED
@@ -944,7 +944,7 @@
944
944
  }
945
945
 
946
946
 
947
- /* AppShell-F7RID4P4.css */
947
+ /* AppShell-U7D2MUUF.css */
948
948
  /*
949
949
  * The application frame: a rail on the FRAME, and the screen on a SHEET that
950
950
  * floats beside it.
@@ -974,30 +974,40 @@
974
974
  --crewlet-app-shell-rail: var(--size-shell-rail);
975
975
  --crewlet-app-shell-topbar: var(--size-shell-topbar);
976
976
  /* What stands on the frame to the sheet's left: the rail's column, or
977
- nothing where there is no rail or the rail is a drawer. The aside's cap
978
- below subtracts it, so it is one name for both. */
977
+ nothing where there is no rail or the rail is a drawer. */
979
978
  --crewlet-app-shell-beside: var(--crewlet-app-shell-rail);
980
- /* THE ASIDE'S TRACK, while it is a column: the panel's width and the inset
981
- it is held off the window's edge by, capped so the sheet keeps the
982
- host's floor (`--crewlet-app-shell-aside-reserve`, the page's sheet with
983
- its own inset and hairlines). The host publishes both widths on this
984
- element; with no reserve the panel takes the width it was given. */
985
- --crewlet-app-shell-aside-track: calc(
986
- min(
987
- var(--crewlet-app-shell-aside),
988
- max(
989
- 0px,
990
- 100% - var(--crewlet-app-shell-beside) - var(--crewlet-app-shell-aside-reserve, 0px) - var(--size-shell-inset)
991
- )
992
- ) +
993
- var(--size-shell-inset)
979
+ /*
980
+ * THE ASIDE'S TRACK, while it is a column: the inset it is held off the
981
+ * window's edge by at least, and the panel's width and that inset at most.
982
+ * THE CAP IS THE GRID'S. The page's sheet takes the host's floor as its
983
+ * own track's minimum (`--crewlet-app-shell-aside-reserve`, the page's sheet
984
+ * with its own inset and hairlines), and the grid hands the aside what is
985
+ * left once the rail and that floor have theirs, up to its width. The rail's
986
+ * track is the rail's live width, so while the rail eases between its
987
+ * shapes the cap eases with it: a cap computed from the rail's VARIABLE
988
+ * named the shape drawn, and jumped at both ends of a fold. With no reserve
989
+ * the panel takes the width it was given, as far as the window holds it.
990
+ */
991
+ --crewlet-app-shell-aside-track: minmax(
992
+ var(--size-shell-inset),
993
+ calc(var(--crewlet-app-shell-aside) + var(--size-shell-inset))
994
+ );
995
+ /* The page's floor beside an aside column, never more than the window
996
+ leaves it: on a window too narrow for the floor, the page gives way rather
997
+ than the shell growing past the window's edge. */
998
+ --crewlet-app-shell-sheet-floor: min(
999
+ var(--crewlet-app-shell-aside-reserve, 0px),
1000
+ max(0px, 100% - var(--crewlet-app-shell-beside) - var(--size-shell-inset))
994
1001
  );
995
1002
  /* Where the drawer's veil sits while it is open. The shell replaces it with
996
1003
  the surface's own place in the layer band; this default only has to clear
997
1004
  the page chrome for the moment before that lands. */
998
1005
  --crewlet-app-shell-drawer-z: var(--z-index-overlay);
999
1006
  display: grid;
1000
- grid-template-columns: var(--crewlet-app-shell-rail) minmax(0, 1fr);
1007
+ /* The rail's track is the rail's own width (`auto`), and the rail takes
1008
+ `--crewlet-app-shell-rail` itself, so the track follows it while it eases
1009
+ between its two shapes (see the rail's motion, below). */
1010
+ grid-template-columns: auto minmax(0, 1fr);
1001
1011
  /* One row, the viewport's height less nothing: the sheet's own margin is
1002
1012
  what holds it off the frame's edges, and a row sized by its content would
1003
1013
  let a tall screen push the sheet's bottom edge off the window. */
@@ -1036,11 +1046,11 @@
1036
1046
  keeps its column and is only narrower, so nothing under the bar moves but
1037
1047
  its end edge. */
1038
1048
  .crewlet-app-shell[data-aside='column'] {
1039
- grid-template-columns: var(--crewlet-app-shell-rail) minmax(0, 1fr) var(--crewlet-app-shell-aside-track);
1049
+ grid-template-columns: auto minmax(var(--crewlet-app-shell-sheet-floor), 1fr) var(--crewlet-app-shell-aside-track);
1040
1050
  }
1041
1051
 
1042
1052
  .crewlet-app-shell--no-rail[data-aside='column'] {
1043
- grid-template-columns: minmax(0, 1fr) var(--crewlet-app-shell-aside-track);
1053
+ grid-template-columns: minmax(var(--crewlet-app-shell-sheet-floor), 1fr) var(--crewlet-app-shell-aside-track);
1044
1054
  }
1045
1055
 
1046
1056
  /* The skip link, drawn only while it holds focus, over everything. */
@@ -1086,14 +1096,25 @@
1086
1096
  position: relative;
1087
1097
  display: flex;
1088
1098
  flex-direction: column;
1099
+ width: var(--crewlet-app-shell-rail);
1089
1100
  min-height: 0;
1090
1101
  min-width: 0;
1102
+ /* THE MOVING EDGE CUTS WHAT IT PASSES. While the rail eases between its
1103
+ shapes its content keeps the width of the shape drawn (below), and the
1104
+ edge clips it rather than squeezing it. Across only: a ring or a badge
1105
+ at a row's top or bottom is never cut. */
1106
+ overflow-x: clip;
1091
1107
  background: var(--color-surface-frame);
1108
+ transition: width var(--motion-duration-slow) var(--motion-easing-emphasized);
1092
1109
  }
1093
1110
 
1111
+ /* THE CONTENT IS LAID OUT AT ITS SHAPE'S WIDTH, never at a width between the
1112
+ two, so no word in the rail rewraps while it moves and nothing drifts with
1113
+ the edge: the column stands still and the edge travels over it. */
1094
1114
  .crewlet-app-shell__rail-inner {
1095
1115
  display: flex;
1096
1116
  flex-direction: column;
1117
+ width: var(--crewlet-app-shell-rail);
1097
1118
  min-height: 0;
1098
1119
  height: 100%;
1099
1120
  }
@@ -1837,7 +1858,7 @@
1837
1858
  }
1838
1859
 
1839
1860
  /*
1840
- * THE COMPACT RAIL: the same track, narrowed to the compact column. One
1861
+ * THE COMPACT RAIL: the same rail, narrowed to the compact column. One
1841
1862
  * variable is the rail's width for the grid, the aside's cap and the drawer
1842
1863
  * alike, so folding the rail is this one declaration. The shell writes the
1843
1864
  * attribute only where the layout is wide: the drawer under the step is
@@ -1848,21 +1869,29 @@
1848
1869
  }
1849
1870
 
1850
1871
  /*
1851
- * THE FOLD CONTROL stands over the compact column's centre, in the row under
1852
- * the head, in both shapes, so it never moves under the pointer that pressed
1853
- * it. Quiet until the rail is pointed at: the tertiary ink, which holds 3:1
1854
- * on the frame, then the secondary, and the ghost's own primary under the
1855
- * pointer.
1872
+ * THE FOLD CONTROL stands in the rail's top left corner, in both shapes, so
1873
+ * it never moves under the pointer that pressed it: a minus while the rail is
1874
+ * full and a plus while it is compact. The corner is the square the head
1875
+ * leaves empty up and to the left of the brand's mark, and the control is the
1876
+ * target floor (`--size-target-min`), so it ends short of the mark on the
1877
+ * compact column's centre at every density.
1878
+ *
1879
+ * Quiet until the rail is pointed at: the tertiary ink, which holds 3:1 on
1880
+ * the frame, then the secondary, and the ghost's own primary under the
1881
+ * pointer. Its ring is drawn inside its own box, because the corner it
1882
+ * stands in is the window's, and a ring outside it would be cut there.
1856
1883
  */
1857
1884
  .crewlet-app-shell__fold {
1858
1885
  position: absolute;
1859
- top: calc(var(--size-shell-inset) + var(--crewlet-app-shell-topbar));
1860
- left: calc((var(--size-shell-rail-compact) - var(--size-control-sm)) / 2);
1886
+ top: 0;
1887
+ left: 0;
1861
1888
  z-index: 1;
1862
1889
  display: inline-flex;
1863
1890
  }
1864
1891
 
1865
1892
  .crewlet-app-shell__fold > .crewlet-icon-btn {
1893
+ width: var(--size-target-min);
1894
+ height: var(--size-target-min);
1866
1895
  color: var(--color-text-tertiary);
1867
1896
  }
1868
1897
 
@@ -1870,6 +1899,10 @@
1870
1899
  color: var(--color-text-secondary);
1871
1900
  }
1872
1901
 
1902
+ .crewlet-app-shell__fold > .crewlet-icon-btn:focus-visible {
1903
+ outline-offset: var(--size-focus-ring-inset-offset);
1904
+ }
1905
+
1873
1906
  /*
1874
1907
  * THE MARK STANDS WHERE THE COMPACT RAIL'S DOES, in both shapes: centred over
1875
1908
  * the compact column, in the head. Full, the name follows it; compact, the
@@ -1886,30 +1919,16 @@
1886
1919
  }
1887
1920
 
1888
1921
  /*
1889
- * FULL, THE FIELD STARTS AFTER THE FOLD CONTROL, a step off it, on the row
1890
- * the control stands in. The field holds its place at the top of the rail's
1891
- * middle while the rows scroll under it, on the frame's own ground, so the
1892
- * control beside it is always beside it.
1922
+ * COMPACT, THE STATUS HAS A ROW OF ITS OWN under the mark, a small control
1923
+ * step tall, its dot and its count centred in the column: the first thing
1924
+ * under the head, before the places, where the fold control stood before it
1925
+ * moved to the corner.
1893
1926
  */
1894
- /* The middle is a stacking context of its own, so the field pinned in it
1895
- stands over the rows scrolling under it and the whole middle stands under
1896
- the fold control, which is painted a step above the rail. */
1897
- .crewlet-app-shell--foldable .crewlet-app-shell__rail-body {
1898
- isolation: isolate;
1899
- }
1900
-
1901
- .crewlet-app-shell--foldable[data-rail='full'] .crewlet-app-shell__rail-search {
1902
- position: sticky;
1903
- top: 0;
1904
- z-index: 1;
1905
- padding-left: calc((var(--size-shell-rail-compact) + var(--size-control-sm)) / 2 + var(--spacing-2));
1906
- background: var(--color-surface-frame);
1907
- }
1908
-
1909
- /* COMPACT, THE FOLD CONTROL HAS A ROW OF ITS OWN under the mark, which the
1910
- head leaves room for, and the column of tiles starts under it. */
1911
- .crewlet-app-shell--foldable[data-rail='compact'] .crewlet-app-shell__rail-head {
1912
- margin-bottom: var(--size-control-sm);
1927
+ .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-inner > .crewlet-app-shell__rail-status {
1928
+ justify-content: center;
1929
+ min-width: 0;
1930
+ min-height: var(--size-control-sm);
1931
+ margin: 0;
1913
1932
  }
1914
1933
 
1915
1934
  .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-body {
@@ -1919,7 +1938,7 @@
1919
1938
 
1920
1939
  /*
1921
1940
  * The compact foot: what the full foot holds, centred in the column, a step
1922
- * apart: the status's dot, a Settings tile, the reader's face.
1941
+ * apart: a Settings tile, the reader's face.
1923
1942
  */
1924
1943
  .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-foot {
1925
1944
  align-items: center;
@@ -1931,10 +1950,85 @@
1931
1950
  align-self: stretch;
1932
1951
  }
1933
1952
 
1934
- .crewlet-app-shell[data-rail='compact'] .crewlet-app-shell__rail-foot > .crewlet-app-shell__rail-status {
1935
- justify-content: center;
1936
- min-width: 0;
1937
- margin: 0;
1953
+ /*
1954
+ * THE COMPACT FACE IS CENTRED ON THE TILES' LINE. It gives up the full row's
1955
+ * badge column and the step after it (above): kept, the step stood the face
1956
+ * 4px left of the column's centre, in a box 8px wider than the face, so the
1957
+ * face sat off the line every tile above it is centred on.
1958
+ */
1959
+ .crewlet-app-shell__rail-foot .crewlet-account-row--compact .crewlet-account-row__avatar {
1960
+ width: auto;
1961
+ margin-inline-end: 0;
1962
+ }
1963
+
1964
+ /*
1965
+ * THE RAIL'S MOTION (railMotion.ts). The rail's width eases between the two
1966
+ * shapes on the slow step with the emphasized curve, the motion a
1967
+ * `DockColumn` opens and closes by, so a column of the frame and a column of
1968
+ * a screen move as one. What the rail holds keeps the width of the shape
1969
+ * drawn, so the moving edge clips the words rather than squeezing them.
1970
+ *
1971
+ * FOLDING, the full rail stays drawn, inert, while the edge narrows to the
1972
+ * compact column, and its words fade out on the base step; the compact column
1973
+ * is drawn when the rail's motion has ended, and fades in on the fast step.
1974
+ * UNFOLDING, the full rail is drawn at once and fades in while the edge
1975
+ * uncovers it. The brand's mark and the fold control are in the same place in
1976
+ * both shapes, so neither fades.
1977
+ *
1978
+ * THE WORDS LEAVE BY A TRANSITION and arrive by keyframes. A fold takes their
1979
+ * opacity to nothing; a fold pressed again mid way (`reverse`) declares
1980
+ * nothing of its own, so the same transition takes the opacity back from
1981
+ * wherever it had reached. Faded out by keyframes instead, a reversal could
1982
+ * only start an entrance from nothing, and the words blinked out and back.
1983
+ * The transition is declared only while the rail moves, so nothing else that
1984
+ * sets these parts' opacity is eased.
1985
+ */
1986
+ .crewlet-app-shell[data-rail-motion='fold'] > .crewlet-app-shell__rail {
1987
+ width: var(--size-shell-rail-compact);
1988
+ }
1989
+
1990
+ /* Two names for one entrance, so an unfold pressed while the compact column
1991
+ is still arriving starts the full rail's entrance afresh. */
1992
+ @keyframes crewlet-app-shell-rail-unfold {
1993
+ from {
1994
+ opacity: 0;
1995
+ }
1996
+ }
1997
+
1998
+ @keyframes crewlet-app-shell-rail-settle {
1999
+ from {
2000
+ opacity: 0;
2001
+ }
2002
+ }
2003
+
2004
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-body,
2005
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-foot,
2006
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-status,
2007
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__name,
2008
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__context {
2009
+ transition: opacity var(--motion-duration-base) var(--motion-easing-out);
2010
+ }
2011
+
2012
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-body,
2013
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-foot,
2014
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-status,
2015
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-head .crewlet-brand__name,
2016
+ .crewlet-app-shell[data-rail-motion='fold'] .crewlet-app-shell__rail-head .crewlet-brand__context {
2017
+ opacity: 0;
2018
+ }
2019
+
2020
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-body,
2021
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-foot,
2022
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-status,
2023
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__name,
2024
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__context {
2025
+ animation: crewlet-app-shell-rail-unfold var(--motion-duration-slow) var(--motion-easing-out);
2026
+ }
2027
+
2028
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-body,
2029
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-foot,
2030
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-status {
2031
+ animation: crewlet-app-shell-rail-settle var(--motion-duration-fast) var(--motion-easing-out);
1938
2032
  }
1939
2033
 
1940
2034
  @media (width < 1024px) {
@@ -1947,7 +2041,7 @@
1947
2041
  step is still a column; the rail is a drawer here and takes no track. */
1948
2042
  .crewlet-app-shell[data-aside='column'],
1949
2043
  .crewlet-app-shell--no-rail[data-aside='column'] {
1950
- grid-template-columns: minmax(0, 1fr) var(--crewlet-app-shell-aside-track);
2044
+ grid-template-columns: minmax(var(--crewlet-app-shell-sheet-floor), 1fr) var(--crewlet-app-shell-aside-track);
1951
2045
  }
1952
2046
 
1953
2047
  .crewlet-app-shell--no-rail {
@@ -2012,6 +2106,12 @@
2012
2106
  transition: transform var(--motion-duration-slow) var(--motion-easing-emphasized);
2013
2107
  }
2014
2108
 
2109
+ /* The drawer never changes shape, and on a window narrower than the rail
2110
+ it is the window's width: its content fills it rather than being cut. */
2111
+ .crewlet-app-shell__rail-inner {
2112
+ width: auto;
2113
+ }
2114
+
2015
2115
  .crewlet-app-shell__toggle {
2016
2116
  display: inline-flex;
2017
2117
  }
@@ -2046,6 +2146,27 @@
2046
2146
  .crewlet-app-shell__aside[data-shape='sheet'] {
2047
2147
  animation: none;
2048
2148
  }
2149
+
2150
+ /* Under reduced motion the shell draws the new shape at once
2151
+ (`usePresence`), so no phase starts; these hold even if one did. */
2152
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-body,
2153
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-foot,
2154
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-status,
2155
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__name,
2156
+ .crewlet-app-shell[data-rail-motion] .crewlet-app-shell__rail-head .crewlet-brand__context {
2157
+ transition: none;
2158
+ }
2159
+
2160
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-body,
2161
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-foot,
2162
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-status,
2163
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__name,
2164
+ .crewlet-app-shell[data-rail-motion='unfold'] .crewlet-app-shell__rail-head .crewlet-brand__context,
2165
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-body,
2166
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-foot,
2167
+ .crewlet-app-shell[data-rail-motion='folded'] .crewlet-app-shell__rail-status {
2168
+ animation: none;
2169
+ }
2049
2170
  }
2050
2171
 
2051
2172
  /* ── the account row ───────────────────────────────────────────────────── */
@@ -19563,6 +19684,70 @@ svg.crewlet-datetime__chevron {
19563
19684
  }
19564
19685
 
19565
19686
 
19687
+ /* DockColumn-SMJCXHS4.css */
19688
+ /*
19689
+ * A column docked beside the content (DockColumn.tsx).
19690
+ *
19691
+ * THE COLUMN EASES ITS WIDTH between none and its panel's, on the slow step
19692
+ * with the emphasized curve: the motion the application rail folds by,
19693
+ * so a column of the frame and a column of a screen open and close as one
19694
+ * movement. The host gives it an `auto` track, so its width is the track.
19695
+ * Clipped rather than hidden, so it is never a scroll container a focus or a
19696
+ * scrollIntoView could scroll.
19697
+ *
19698
+ * THE PANEL KEEPS ITS WIDTH and is held to the column's edge that faces the
19699
+ * content: before the content (`start`) it is held to the column's end, so
19700
+ * the moving edge uncovers it from the start edge, and after the content
19701
+ * (`end`) the other way round.
19702
+ *
19703
+ * Tokens only. The width is the component's own variable, set from the
19704
+ * `width` prop, so the column and the panel read one value.
19705
+ */
19706
+
19707
+ .crewlet-dock-column {
19708
+ display: flex;
19709
+ justify-content: flex-end;
19710
+ width: 0;
19711
+ min-width: 0;
19712
+ min-height: 0;
19713
+ overflow: clip;
19714
+ transition: width var(--motion-duration-slow) var(--motion-easing-emphasized);
19715
+ }
19716
+
19717
+ .crewlet-dock-column[data-side='end'] {
19718
+ justify-content: flex-start;
19719
+ }
19720
+
19721
+ .crewlet-dock-column[data-open] {
19722
+ width: var(--crewlet-dock-column-width);
19723
+ }
19724
+
19725
+ .crewlet-dock-column__panel {
19726
+ display: flex;
19727
+ flex: none;
19728
+ flex-direction: column;
19729
+ box-sizing: border-box;
19730
+ width: var(--crewlet-dock-column-width);
19731
+ min-height: 0;
19732
+ background: var(--crewlet-dock-column-ground, transparent);
19733
+ }
19734
+
19735
+ /* The hairline on the panel's edge that faces the content. */
19736
+ .crewlet-dock-column--divider[data-side='start'] > .crewlet-dock-column__panel {
19737
+ border-inline-end: 1px solid var(--color-border-default);
19738
+ }
19739
+
19740
+ .crewlet-dock-column--divider[data-side='end'] > .crewlet-dock-column__panel {
19741
+ border-inline-start: 1px solid var(--color-border-default);
19742
+ }
19743
+
19744
+ @media (prefers-reduced-motion: reduce) {
19745
+ .crewlet-dock-column {
19746
+ transition: none;
19747
+ }
19748
+ }
19749
+
19750
+
19566
19751
  /* Document-M6JYGLWV.css */
19567
19752
  /*
19568
19753
  * Rendered markdown, set as a document (Document.tsx).
@@ -0,0 +1,39 @@
1
+ /**
2
+ * One ref for an element several owners need: a component that clones its
3
+ * trigger (a tooltip, a popover) and the ref the trigger already carried.
4
+ *
5
+ * STABLE WHILE THE REFS IT JOINS ARE. A ref callback written inline is a new
6
+ * function on every render, and React treats a new ref as a change: it
7
+ * releases the old one in the commit's mutation phase and attaches the new
8
+ * one in its layout phase, in tree order. So every render of the component
9
+ * that cloned the trigger set the trigger's own ref to null and back, and a
10
+ * layout effect EARLIER in the tree (a dock handing focus to that very
11
+ * control as it closes) read null while the element stood in the document.
12
+ * Memoised on the refs it joins, the joined ref changes only when one of
13
+ * them does, which is exactly when React would have moved a ref of its own.
14
+ */
15
+ import { type Ref, type RefCallback } from 'react';
16
+ /**
17
+ * Hands `element` to one ref, and returns how to take it back, the way React
18
+ * would have released that ref itself: a callback that returns its own
19
+ * teardown gets the teardown called, any other callback is called with null,
20
+ * and an object's `current` is emptied.
21
+ */
22
+ export declare function attachRef<T>(ref: Ref<T> | undefined, element: T | null): () => void;
23
+ /**
24
+ * One ref callback that hands the element to every ref given and releases
25
+ * each as React would, for code outside a component.
26
+ */
27
+ export declare function composeRefs<T>(...refs: readonly (Ref<T> | undefined)[]): RefCallback<T>;
28
+ /**
29
+ * `composeRefs` for a component: any number of refs joined into one callback
30
+ * that is THE SAME CALLBACK for as long as the refs given are the same, in the
31
+ * same order, and a new one the render any of them changes.
32
+ *
33
+ * Held in a ref and compared ref by ref rather than memoised on a dependency
34
+ * list, which must be written out, and a list of refs of any length cannot
35
+ * be. Not state: a ref written inline beside the hook is new on every render,
36
+ * and replacing state for it would render again for ever. Here it simply
37
+ * makes a new callback, which is what React does with an inline ref.
38
+ */
39
+ export declare function useComposedRef<T>(...refs: readonly (Ref<T> | undefined)[]): RefCallback<T>;
@@ -1,4 +1,6 @@
1
1
  export { cx } from './cx.js';
2
+ export { attachRef, composeRefs, useComposedRef } from './composedRef.js';
3
+ export { tokenMs } from './tokenMs.js';
2
4
  export { useClipboard, writeClipboard } from './useClipboard.js';
3
5
  export type { Clipboard, ClipboardOptions, ClipboardState } from './useClipboard.js';
4
6
  export { useOutcome } from './useOutcome.js';
@@ -1,8 +1,10 @@
1
- export { ElementToPngError, elementToPng, parseCsv, serializeElement, toCsv } from '../chunk-FEJANUZK.js';
1
+ export { ElementToPngError, elementToPng, parseCsv, serializeElement, toCsv } from '../chunk-KBSD476L.js';
2
2
  export { downloadBlob, downloadText, safeFilename, useDownload } from '../chunk-YNRKVY7X.js';
3
3
  export { useClipboard, writeClipboard } from '../chunk-STJ7QBC3.js';
4
4
  export { useOutcome } from '../chunk-DTIW4CHZ.js';
5
5
  export { NODE_HUES, NODE_HUE_NAMES, isNodeHue } from '../chunk-AYKXMIOR.js';
6
+ export { tokenMs } from '../chunk-HTS5RJ7S.js';
7
+ export { attachRef, composeRefs, useComposedRef } from '../chunk-L72URIHR.js';
6
8
  export { FOCUS_MODALITY_ATTRIBUTE, FOCUS_RETURNED_ATTRIBUTE, isVisibleFocus, returnFocus, trackFocusModality, useFocusModality } from '../chunk-4ITETIGZ.js';
7
9
  export { HeadingLevelProvider, headingTag, nextHeadingLevel, useHeadingLevel } from '../chunk-PQADV6P6.js';
8
10
  export { cx } from '../chunk-ODEQTPFM.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A motion token as a number of milliseconds, for a delay or a bound that
3
+ * JavaScript has to count (`tokenMs(motion.duration.fast)`). The tokens are
4
+ * written in ms (`120ms`), so the number is the token's own, never a copy.
5
+ */
6
+ export declare function tokenMs(value: string): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crewlethq/ui",
3
- "version": "0.82.0",
3
+ "version": "0.83.0",
4
4
  "description": "Crewlet shared React components built on @crewlethq/tokens and @crewlethq/icons.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,8 +42,8 @@
42
42
  "clean": "rm -rf dist src/generated"
43
43
  },
44
44
  "dependencies": {
45
- "@crewlethq/icons": "0.82.0",
46
- "@crewlethq/tokens": "0.82.0",
45
+ "@crewlethq/icons": "0.83.0",
46
+ "@crewlethq/tokens": "0.83.0",
47
47
  "prosemirror-commands": "1.7.2",
48
48
  "prosemirror-gapcursor": "1.4.1",
49
49
  "prosemirror-history": "1.5.1",
@@ -57,8 +57,8 @@
57
57
  "uqr": "0.1.3"
58
58
  },
59
59
  "peerDependencies": {
60
- "react": ">=18",
61
- "react-dom": ">=18"
60
+ "react": ">=19",
61
+ "react-dom": ">=19"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@types/react": "^19.0.0",
@@ -1,6 +1,6 @@
1
1
  import { StepList } from './chunk-RJWO2PC5.js';
2
- import { Meter } from './chunk-RQFRRPV6.js';
3
2
  import { ReceiptStrip } from './chunk-ZWCK4N4L.js';
3
+ import { Meter } from './chunk-RQFRRPV6.js';
4
4
  import { StatusCard } from './chunk-FLW5U7YS.js';
5
5
  import { Disclosure } from './chunk-LVJGN5II.js';
6
6
  import { Spinner } from './chunk-XSPCITPN.js';
@@ -1,5 +1,5 @@
1
- import { IconTile } from './chunk-3LI4TRUR.js';
2
1
  import { safeHref } from './chunk-KBZO4B33.js';
2
+ import { IconTile } from './chunk-3LI4TRUR.js';
3
3
  import { ReceiptStrip } from './chunk-ZWCK4N4L.js';
4
4
  import { StatusCard } from './chunk-FLW5U7YS.js';
5
5
  import { ButtonLink, Button } from './chunk-DGXZ635L.js';
File without changes
@@ -4,8 +4,8 @@ import { RelativeTime } from './chunk-EJNJMHQG.js';
4
4
  import { Card } from './chunk-U2IQNDDR.js';
5
5
  import { AvatarStack } from './chunk-IRONPJB4.js';
6
6
  import { ArtifactKindGround } from './chunk-ZB3E2Z4Y.js';
7
- import { ArtifactAccessGlyph } from './chunk-DOY3KC6I.js';
8
7
  import { Checkbox } from './chunk-YQ7Q52XU.js';
8
+ import { ArtifactAccessGlyph } from './chunk-DOY3KC6I.js';
9
9
  import { ArtifactKindGlyph } from './chunk-RSKW25Y5.js';
10
10
  import { VisuallyHidden } from './chunk-UT6CW3C7.js';
11
11
  import { cx } from './chunk-ODEQTPFM.js';
File without changes