@startsimpli/ui 0.4.120 → 0.4.122

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.
@@ -20,6 +20,13 @@ export const TABLE_SHELL_CLASS = 'ss-table-shell'
20
20
  export const TABLE_EDGE_CLASS = 'ss-table-edge'
21
21
  export const TABLE_EDGE_LEFT_CLASS = 'ss-table-edge-left'
22
22
  export const TABLE_EDGE_RIGHT_CLASS = 'ss-table-edge-right'
23
+ /**
24
+ * A second, sticky horizontal scrollbar for the table, pinned to the bottom of
25
+ * the viewport while the real one is off screen (startsim-xe1uo.1).
26
+ */
27
+ export const TABLE_RAIL_CLASS = 'ss-table-rail'
28
+ /** The rail's only child: a strut as wide as the table, so the rail overflows. */
29
+ export const TABLE_RAIL_TRACK_CLASS = 'ss-table-rail-track'
23
30
 
24
31
  /**
25
32
  * The edge hint SHADES its surface; it must never try to MATCH it.
@@ -63,6 +70,26 @@ export const TABLE_EDGE_RIGHT_CLASS = 'ss-table-edge-right'
63
70
  const EDGE_SHADE = 'hsl(var(--foreground) / 0.14)'
64
71
  const EDGE_SHADE_NONE = 'hsl(var(--foreground) / 0)'
65
72
 
73
+ /**
74
+ * The rail's bar is LOUDER than the in-gutter one, on purpose.
75
+ *
76
+ * The shared thumb sits in a gutter below the table, on bare surface, and 22%
77
+ * of `currentColor` is enough to read there. The rail floats OVER the last rows
78
+ * of the table with a transparent track, so at 22% it competes with row text
79
+ * and, on the routes this was built for, is the only thing a mouse user can
80
+ * grab. 45% is the value the shared rule already uses on `:hover`, so this is
81
+ * the same ink, not a new colour, and it inverts with the theme like the rest.
82
+ * The faint track makes the rail read as a bar rather than as a stray thumb.
83
+ *
84
+ * This does NOT supersede startsim-xe1uo.2, which is about the 10px height the
85
+ * shared rule takes from the platform's ~15px classic bar on Windows/Linux --
86
+ * that trade only gets more load-bearing now that the rail is the grab target,
87
+ * and it wants the runtime overlay/classic probe described on that bead, not a
88
+ * different alpha.
89
+ */
90
+ const RAIL_THUMB = 'color-mix(in srgb, currentColor 45%, transparent)'
91
+ const RAIL_TRACK = 'color-mix(in srgb, currentColor 8%, transparent)'
92
+
66
93
  /**
67
94
  * Content scrolls, but on macOS nothing says so (startsim-5pq7h, 5pq7h.1).
68
95
  *
@@ -130,6 +157,15 @@ const EDGE_SHADE_NONE = 'hsl(var(--foreground) / 0)'
130
157
  * Nothing here animates or transitions, so `prefers-reduced-motion` has nothing
131
158
  * to honour.
132
159
  *
160
+ * THE BAR BEING VISIBLE IS NOT THE SAME AS THE BAR BEING REACHABLE. The
161
+ * scroller is as tall as the whole table, so the bar it grows sits at the
162
+ * BOTTOM OF THE DOCUMENT -- measured 2,741-5,994px below the truncated header
163
+ * on the marketing-agents tenant (startsim-xe1uo). A macOS trackpad swipes
164
+ * horizontally anywhere over the table, so nobody here ever noticed; a Windows
165
+ * wheel mouse has no horizontal axis, so its owner's only options were
166
+ * Shift+Wheel or a scrollbar three screens down. `.ss-table-rail` is the answer
167
+ * to that half -- see `useScrollRail` in components/ui/table-scroll.ts.
168
+ *
133
169
  * ONE stylesheet, ONE id, ONE string: `ensureInjectedStyle` rewrites the sheet
134
170
  * when an existing id carries different text, so two call sites shipping
135
171
  * different CSS under this id would overwrite each other on every mount. Add
@@ -137,6 +173,7 @@ const EDGE_SHADE_NONE = 'hsl(var(--foreground) / 0)'
137
173
  */
138
174
  export const SCROLL_AFFORDANCE_CSS = `
139
175
  .${TABLE_SCROLLER_CLASS}::-webkit-scrollbar,
176
+ .${TABLE_RAIL_CLASS}::-webkit-scrollbar,
140
177
  .${SCROLLER_CLASS}::-webkit-scrollbar {
141
178
  height: 10px;
142
179
  width: 10px;
@@ -146,16 +183,50 @@ export const SCROLL_AFFORDANCE_CSS = `
146
183
  background: transparent;
147
184
  }
148
185
  .${TABLE_SCROLLER_CLASS}::-webkit-scrollbar-thumb,
186
+ .${TABLE_RAIL_CLASS}::-webkit-scrollbar-thumb,
149
187
  .${SCROLLER_CLASS}::-webkit-scrollbar-thumb {
150
188
  border-radius: 9999px;
151
189
  background-color: color-mix(in srgb, currentColor 22%, transparent);
152
190
  }
153
191
  .${TABLE_SCROLLER_CLASS}::-webkit-scrollbar-thumb:hover,
192
+ .${TABLE_RAIL_CLASS}::-webkit-scrollbar-thumb:hover,
154
193
  .${SCROLLER_CLASS}::-webkit-scrollbar-thumb:hover {
155
194
  background-color: color-mix(in srgb, currentColor 45%, transparent);
156
195
  }
157
196
  .${TABLE_SHELL_CLASS} {
158
197
  position: relative;
198
+ /*
199
+ * min-width and overflow-x do two different jobs here, and the shell used to
200
+ * get BOTH of them by accident from a single Tailwind overflow-x-auto in
201
+ * DataTableCore. That class had to go, because a scroll container is a
202
+ * scrollport and position:sticky inside one resolves against IT, not the
203
+ * viewport -- which pinned the rail below to the bottom of the TABLE instead
204
+ * of the bottom of the SCREEN.
205
+ *
206
+ * MEASURED 2026-09-09, Chromium, a shell holding a 1600px table inside a
207
+ * 400px flex line, scrolled so the shell's bottom is 1.4k px below the fold:
208
+ *
209
+ * shell overflow-x computed overflow-y shell width sticky rail bottom
210
+ * auto (what shipped) auto 400 2022 (off screen)
211
+ * hidden auto 400 2022 (off screen)
212
+ * clip visible 1602 <-- blows out the flex line
213
+ * clip + min-width:0 visible 400 614 (= viewport)
214
+ *
215
+ * So clip is the one overflow value that clips without becoming a scrollport
216
+ * -- but it does NOT bring the automatic minimum size with it. min-width:auto
217
+ * resolves to zero only for a SCROLL CONTAINER, and a clip container is not
218
+ * one, so the shell stopped shrinking and pushed its flex parent to 1602px.
219
+ * Hence both declarations, and neither is optional: drop min-width and wide
220
+ * tables blow out their layout, drop clip and the rail never reaches the
221
+ * viewport.
222
+ *
223
+ * hidden first is the fallback for engines without clip (Safari < 16): they
224
+ * keep today's clipping and today's non-sticky rail, rather than letting the
225
+ * table escape the shell's rounded border.
226
+ */
227
+ min-width: 0;
228
+ overflow-x: hidden;
229
+ overflow-x: clip;
159
230
  }
160
231
  .${TABLE_EDGE_CLASS} {
161
232
  position: absolute;
@@ -172,6 +243,22 @@ export const SCROLL_AFFORDANCE_CSS = `
172
243
  left: 0;
173
244
  background-image: linear-gradient(to right, ${EDGE_SHADE}, ${EDGE_SHADE_NONE});
174
245
  }
246
+ .${TABLE_RAIL_CLASS} {
247
+ position: sticky;
248
+ bottom: 0;
249
+ z-index: 1;
250
+ overflow-x: auto;
251
+ overflow-y: hidden;
252
+ }
253
+ .${TABLE_RAIL_TRACK_CLASS} {
254
+ height: 1px;
255
+ }
256
+ .${TABLE_RAIL_CLASS}::-webkit-scrollbar-track {
257
+ background-color: ${RAIL_TRACK};
258
+ }
259
+ .${TABLE_RAIL_CLASS}::-webkit-scrollbar-thumb {
260
+ background-color: ${RAIL_THUMB};
261
+ }
175
262
  `.trim()
176
263
 
177
264
  /**