@parallelworks/ui 0.58.0 → 0.59.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.
@@ -37,12 +37,14 @@ var labelSizes = {
37
37
  sm: {
38
38
  text: "text-xs text-(--theme-muted-text-color)",
39
39
  inlineHeight: "min-h-7",
40
- stackGap: "gap-1"
40
+ stackGap: "gap-1",
41
+ inlineLine: "py-1.5"
41
42
  },
42
43
  md: {
43
44
  text: "text-sm text-(--theme-app)",
44
45
  inlineHeight: "min-h-9",
45
- stackGap: "gap-1.5"
46
+ stackGap: "gap-1.5",
47
+ inlineLine: "py-2"
46
48
  }
47
49
  };
48
50
  var labelClassName = "flex items-center gap-1 font-medium";
@@ -64,7 +66,7 @@ function ErrorText({ id, children }) {
64
66
  }
65
67
  /** A control with its label, help and error, tied to it for assistive technology. One frame
66
68
  * for every field, in a form or standing alone. */
67
- function Field$1({ label, hint, help, actions, description, error, invalid, required = false, disabled = false, layout = "stacked", compact = false, size = "md", group = false, id: ownId, className, children }) {
69
+ function Field$1({ label, hint, help, actions, description, error, invalid, required = false, disabled = false, layout = "stacked", compact = false, size = "md", group = false, controlFirst = false, id: ownId, className, children }) {
68
70
  const uid = useId();
69
71
  const id = ownId ?? `${uid}control`;
70
72
  const labelId = `${uid}label`;
@@ -125,8 +127,8 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
125
127
  }
126
128
  } : {};
127
129
  const labelBox = cx(labelClassName, labelSize.text, inline && cx(labelSize.inlineHeight, "shrink-0", compact ? "mr-2 w-fit" : "w-52 pr-3"), inRow && "row-start-1 self-end");
128
- const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
129
- /* @__PURE__ */ jsxs("span", { children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})] }),
130
+ const nameContent = /* @__PURE__ */ jsxs(Fragment, { children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})] });
131
+ const labelExtras = /* @__PURE__ */ jsxs(Fragment, { children: [
130
132
  helpTip,
131
133
  hint,
132
134
  actions && /* @__PURE__ */ jsx("span", {
@@ -135,42 +137,83 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
135
137
  })
136
138
  ] });
137
139
  const placed = typeof children === "function" ? children(control) : children;
140
+ const controlInContext = /* @__PURE__ */ jsx(FieldRowContext, {
141
+ value: false,
142
+ children: /* @__PURE__ */ jsx(ControlContext, {
143
+ value: controlContext,
144
+ children: placed
145
+ })
146
+ });
147
+ const messages = /* @__PURE__ */ jsxs(Fragment, { children: [
148
+ description && /* @__PURE__ */ jsx(Field.Description, {
149
+ id: descriptionId,
150
+ className: "text-xs leading-relaxed text-(--theme-muted-text-color)",
151
+ children: description
152
+ }),
153
+ help && /* @__PURE__ */ jsx(Field.Description, {
154
+ id: helpId,
155
+ hidden: true,
156
+ children: formatInfoTipContent(help)
157
+ }),
158
+ error && /* @__PURE__ */ jsxs(Field.Error, {
159
+ id: errorId,
160
+ match: true,
161
+ role: "alert",
162
+ className: errorTextClassName,
163
+ children: [/* @__PURE__ */ jsx(WarningIcon, {
164
+ "aria-hidden": "true",
165
+ className: "size-3.5 shrink-0"
166
+ }), error]
167
+ })
168
+ ] });
169
+ const fieldLabel = (className) => /* @__PURE__ */ jsx(Field.Label, {
170
+ ...labelledBy > 0 ? {
171
+ htmlFor: void 0,
172
+ onClick: () => document.getElementById(id)?.focus()
173
+ } : typeof children === "function" || ownId !== void 0 ? { htmlFor: id } : {},
174
+ id: labelId,
175
+ className,
176
+ "data-field-label": true,
177
+ children: nameContent
178
+ });
179
+ if (controlFirst && !group) {
180
+ const lined = inline || inRow;
181
+ return /* @__PURE__ */ jsxs(Field.Root, {
182
+ invalid: isInvalid,
183
+ disabled,
184
+ className: inRow ? cx("contents", className) : cx("flex w-full items-start", className),
185
+ "data-field-row": inRow || void 0,
186
+ children: [inline && !compact && /* @__PURE__ */ jsx("div", {
187
+ "aria-hidden": "true",
188
+ className: "w-52 shrink-0"
189
+ }), /* @__PURE__ */ jsxs("div", {
190
+ ref: help ? setControlBox : void 0,
191
+ className: cx("flex w-fit max-w-full min-w-0 items-start gap-2", lined && labelSize.inlineLine, inRow && "row-start-2"),
192
+ children: [/* @__PURE__ */ jsx("div", {
193
+ className: cx("flex h-lh shrink-0 items-center", labelSize.text),
194
+ ...helpFocus,
195
+ children: controlInContext
196
+ }), /* @__PURE__ */ jsxs("div", {
197
+ className: "flex min-w-0 flex-col gap-1",
198
+ children: [/* @__PURE__ */ jsxs("div", {
199
+ className: cx("font-medium", labelSize.text, disabled && "opacity-60"),
200
+ children: [fieldLabel(disabled ? "cursor-not-allowed" : "cursor-pointer"), (help || hint || actions) && /* @__PURE__ */ jsx("span", {
201
+ className: "ms-1 inline-flex items-center gap-1 align-[-0.125em]",
202
+ children: labelExtras
203
+ })]
204
+ }), messages]
205
+ })]
206
+ })]
207
+ });
208
+ }
138
209
  const body = /* @__PURE__ */ jsxs("div", {
139
210
  ref: help ? setControlBox : void 0,
140
211
  className: cx("flex w-full min-w-0 flex-col gap-1", inRow && "row-start-2"),
141
212
  ...helpFocus,
142
- children: [
143
- /* @__PURE__ */ jsx(FieldRowContext, {
144
- value: false,
145
- children: /* @__PURE__ */ jsx(ControlContext, {
146
- value: controlContext,
147
- children: inline ? /* @__PURE__ */ jsx("div", {
148
- className: cx("grid items-center", labelSize.inlineHeight),
149
- children: placed
150
- }) : placed
151
- })
152
- }),
153
- description && /* @__PURE__ */ jsx(Field.Description, {
154
- id: descriptionId,
155
- className: "text-xs leading-relaxed text-(--theme-muted-text-color)",
156
- children: description
157
- }),
158
- help && /* @__PURE__ */ jsx(Field.Description, {
159
- id: helpId,
160
- hidden: true,
161
- children: formatInfoTipContent(help)
162
- }),
163
- error && /* @__PURE__ */ jsxs(Field.Error, {
164
- id: errorId,
165
- match: true,
166
- role: "alert",
167
- className: errorTextClassName,
168
- children: [/* @__PURE__ */ jsx(WarningIcon, {
169
- "aria-hidden": "true",
170
- className: "size-3.5 shrink-0"
171
- }), error]
172
- })
173
- ]
213
+ children: [inline ? /* @__PURE__ */ jsx("div", {
214
+ className: cx("grid items-center", labelSize.inlineHeight),
215
+ children: controlInContext
216
+ }) : controlInContext, messages]
174
217
  });
175
218
  const frame = inRow ? cx("contents", className) : cx("flex w-full", inline ? "items-start" : cx("flex-col", labelSize.stackGap), className);
176
219
  if (group) return /* @__PURE__ */ jsx(Field.Root, {
@@ -182,10 +225,10 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
182
225
  }),
183
226
  children: /* @__PURE__ */ jsxs("div", {
184
227
  className: frame,
185
- children: [/* @__PURE__ */ jsx(Fieldset.Legend, {
228
+ children: [/* @__PURE__ */ jsxs(Fieldset.Legend, {
186
229
  id: labelId,
187
230
  className: labelBox,
188
- children: labelContent
231
+ children: [/* @__PURE__ */ jsx("span", { children: nameContent }), labelExtras]
189
232
  }), body]
190
233
  })
191
234
  });
@@ -196,23 +239,7 @@ function Field$1({ label, hint, help, actions, description, error, invalid, requ
196
239
  "data-field-row": inRow || void 0,
197
240
  children: [/* @__PURE__ */ jsxs("div", {
198
241
  className: labelBox,
199
- children: [
200
- /* @__PURE__ */ jsxs(Field.Label, {
201
- ...labelledBy > 0 ? {
202
- htmlFor: void 0,
203
- onClick: () => document.getElementById(id)?.focus()
204
- } : typeof children === "function" || ownId !== void 0 ? { htmlFor: id } : {},
205
- id: labelId,
206
- "data-field-label": true,
207
- children: [label, required && /* @__PURE__ */ jsx(RequiredMark, {})]
208
- }),
209
- helpTip,
210
- hint,
211
- actions && /* @__PURE__ */ jsx("span", {
212
- className: actionsClassName,
213
- children: actions
214
- })
215
- ]
242
+ children: [fieldLabel(), labelExtras]
216
243
  }), body]
217
244
  });
218
245
  }
@@ -3,6 +3,17 @@ import { useFullscreenContainer } from "./fullscreen.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { PreviewCard } from "@base-ui/react/preview-card";
5
5
  //#region src/components/HoverCard.tsx
6
+ var stop = (event) => event.stopPropagation();
7
+ var pressHandlers = {
8
+ onClick: stop,
9
+ onAuxClick: stop,
10
+ onDoubleClick: stop,
11
+ onContextMenu: stop,
12
+ onPointerDown: stop,
13
+ onPointerUp: stop,
14
+ onMouseDown: stop,
15
+ onMouseUp: stop
16
+ };
6
17
  /** Detail about its anchor, such as a person's profile, after a short hover or
7
18
  * on focus. A visual enhancement: whatever the card shows must also be
8
19
  * reachable another way, such as the page the anchor links to. The card
@@ -25,6 +36,7 @@ function HoverCard({ card, children, defaultOpen = false }) {
25
36
  className: positionerClassName,
26
37
  children: /* @__PURE__ */ jsx(PreviewCard.Popup, {
27
38
  className: cardClassName,
39
+ ...pressHandlers,
28
40
  children: card
29
41
  })
30
42
  })
@@ -744,7 +744,12 @@ export interface UIProviderProps {
744
744
  /** The engine, or a loader that resolves to it. A loader is called once, the first one
745
745
  * passed, so it may be written inline. */
746
746
  engine?: WorkflowEngineSource | undefined;
747
+ /** The nonce the page's Content Security Policy allows inline scripts by,
748
+ * for a host that renders on the server: a few components emit a script
749
+ * that places them before hydration. The components render no inline
750
+ * `<style>`, so a policy without 'unsafe-inline' styles needs none. */
751
+ nonce?: string | undefined;
747
752
  children: React.ReactNode;
748
753
  }
749
- export declare function UIProvider({ strings, navigation, data, slots, engine: engineProp, children, }: UIProviderProps): import("react").JSX.Element;
754
+ export declare function UIProvider({ strings, navigation, data, slots, engine: engineProp, nonce, children, }: UIProviderProps): import("react").JSX.Element;
750
755
  export {};
@@ -4,6 +4,7 @@ import { Toaster } from "./Toast.js";
4
4
  import { TooltipProvider } from "./Tooltip.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { createContext, use, useCallback, useContext, useEffect, useRef, useState } from "react";
7
+ import { CSPProvider } from "@base-ui/react/csp-provider";
7
8
  import { dequal } from "dequal";
8
9
  //#region src/components/Provider.tsx
9
10
  var isGroup = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
@@ -694,7 +695,7 @@ function useMerged(compute, input) {
694
695
  };
695
696
  return ref.current.value;
696
697
  }
697
- function UIProvider({ strings, navigation, data, slots, engine: engineProp, children }) {
698
+ function UIProvider({ strings, navigation, data, slots, engine: engineProp, nonce, children }) {
698
699
  const [firstLoader] = useState(() => typeof engineProp === "function" ? engineProp : void 0);
699
700
  const engine = typeof engineProp === "function" ? firstLoader ?? engineProp : engineProp;
700
701
  useEffect(() => {
@@ -721,9 +722,13 @@ function UIProvider({ strings, navigation, data, slots, engine: engineProp, chil
721
722
  value: mergedData,
722
723
  children: /* @__PURE__ */ jsx(SlotsContext, {
723
724
  value: stableSlots,
724
- children: /* @__PURE__ */ jsxs(EngineContext, {
725
+ children: /* @__PURE__ */ jsx(EngineContext, {
725
726
  value: engine,
726
- children: [/* @__PURE__ */ jsx(TooltipProvider, { children }), /* @__PURE__ */ jsx(Toaster, {})]
727
+ children: /* @__PURE__ */ jsxs(CSPProvider, {
728
+ nonce,
729
+ disableStyleElements: true,
730
+ children: [/* @__PURE__ */ jsx(TooltipProvider, { children }), /* @__PURE__ */ jsx(Toaster, {})]
731
+ })
727
732
  })
728
733
  })
729
734
  })
@@ -0,0 +1,14 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface StickyBarProps {
3
+ /** Padding, borders and layout; the bar sets its own position, `top`,
4
+ * layer and background. */
5
+ className?: string | undefined;
6
+ testId?: string | undefined;
7
+ children?: ReactNode;
8
+ }
9
+ /** A strip of a page's own controls, such as a row of filters or a page's
10
+ * actions, pinned as the page scrolls. It stops just below whatever its
11
+ * scroller already pins at the top, such as the page header, and moves with
12
+ * it as that wraps or changes height. For an `ActionToolbar` or `Tabs` alone,
13
+ * give them `sticky` instead. */
14
+ export declare function StickyBar({ className, testId, children }: StickyBarProps): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { cx } from "../cx.js";
2
+ import { stickyClasses, useStickyTop } from "./stickyTop.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { useState } from "react";
5
+ //#region src/components/StickyBar.tsx
6
+ /** A strip of a page's own controls, such as a row of filters or a page's
7
+ * actions, pinned as the page scrolls. It stops just below whatever its
8
+ * scroller already pins at the top, such as the page header, and moves with
9
+ * it as that wraps or changes height. For an `ActionToolbar` or `Tabs` alone,
10
+ * give them `sticky` instead. */
11
+ function StickyBar({ className, testId, children }) {
12
+ const [el, setEl] = useState(null);
13
+ useStickyTop(el, true);
14
+ return /* @__PURE__ */ jsx("div", {
15
+ ref: setEl,
16
+ "data-testid": testId,
17
+ className: cx(stickyClasses, className),
18
+ children
19
+ });
20
+ }
21
+ //#endregion
22
+ export { StickyBar };
@@ -3,7 +3,7 @@ import { SortDownIcon, SortUnsortedIcon, SortUpIcon } from "../icons.js";
3
3
  import { Loader } from "./Loader.js";
4
4
  import { useStickyTop } from "./stickyTop.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
- import React, { createContext, useContext, useRef } from "react";
6
+ import React, { createContext, useContext, useState } from "react";
7
7
  //#region src/components/Table.tsx
8
8
  var DensityContext = createContext("comfortable");
9
9
  var cellX = "px-3";
@@ -48,7 +48,7 @@ var isHeaderChild = (child) => {
48
48
  * the children, then `<tr>`s of `Table.Item`s. */
49
49
  function Table({ density = "comfortable", borderless = false, panel = true, className, wrapperClassName = "", tbodyClassName = "divide-y", theadClassName = "theme-muted-panel", children, roundedTop = false, rounded = false, roundedBottom = false, isLoading = false, stickyHeader = false, tableProps }) {
50
50
  const childList = React.Children.toArray(children);
51
- const thead = useRef(null);
51
+ const [thead, setThead] = useState(null);
52
52
  useStickyTop(thead, stickyHeader && !isLoading);
53
53
  const hasOverflow = wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-"));
54
54
  return /* @__PURE__ */ jsx(DensityContext, {
@@ -65,7 +65,7 @@ function Table({ density = "comfortable", borderless = false, panel = true, clas
65
65
  className: cx("min-w-full divide-y theme-border", className),
66
66
  ...tableProps,
67
67
  children: [/* @__PURE__ */ jsx("thead", {
68
- ref: thead,
68
+ ref: setThead,
69
69
  className: cx(stickyHeader && "sticky top-0 z-(--layer-sticky) border-b-0 shadow-[inset_0_-1px_0_var(--theme-border)]", theadClassName),
70
70
  children: /* @__PURE__ */ jsx("tr", { children: childList.filter(isHeaderChild) })
71
71
  }), /* @__PURE__ */ jsx("tbody", {
@@ -25,8 +25,8 @@ export interface TabsProps<Value extends string> extends SegmentLayout {
25
25
  variant?: 'line' | 'segmented' | undefined;
26
26
  /** At the tab row's far end, such as a picker for what the tabs show. */
27
27
  end?: ReactNode;
28
- /** Pins the tab row to the top of the page's scroller as it scrolls; give it a
29
- * `top-*` in `className` to pin it under something else pinned there. */
28
+ /** Pins the tab row as the page scrolls, just below whatever the page's
29
+ * scroller already pins at the top, such as the page header and a toolbar. */
30
30
  sticky?: boolean | undefined;
31
31
  /** On the tab row. */
32
32
  className?: string | undefined;
@@ -2,11 +2,11 @@ import { cx } from "../cx.js";
2
2
  import { Tooltip } from "./Tooltip.js";
3
3
  import { AppLink } from "./AppLink.js";
4
4
  import { SegmentContent, segmentClassName, segmentGroupClassName } from "./segmented.js";
5
+ import { useStickyTop } from "./stickyTop.js";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { useState } from "react";
7
8
  import { Tabs } from "@base-ui/react/tabs";
8
9
  //#region src/components/Tabs.tsx
9
- var stickyClassName = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
10
10
  /** Views of one thing, one shown at a time: panels below the tabs, or pages
11
11
  * the tabs link to. A lone tab would only repeat the page's title, so the row
12
12
  * hides unless there are two or more, or something at its end. */
@@ -19,6 +19,8 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
19
19
  const [own, setOwn] = useState(defaultValue ?? items[0]?.value);
20
20
  const current = value ?? own;
21
21
  const showRow = items.length > 1 || !!end;
22
+ const [row, setRow] = useState(null);
23
+ useStickyTop(row, !!sticky);
22
24
  const tabs = items.map((item) => {
23
25
  const tab = /* @__PURE__ */ jsx(Tabs.Tab, {
24
26
  value: item.value,
@@ -50,7 +52,8 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
50
52
  "data-testid": testId,
51
53
  className: children ? void 0 : "contents",
52
54
  children: [showRow && /* @__PURE__ */ jsxs("div", {
53
- className: cx("flex items-center justify-between gap-2", !segmented && "border-b border-(--theme-border)", sticky && stickyClassName, className),
55
+ ref: setRow,
56
+ className: cx("flex items-center justify-between gap-2", !segmented && "border-b border-(--theme-border)", sticky && "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)", className),
54
57
  children: [/* @__PURE__ */ jsxs(Tabs.List, {
55
58
  "aria-label": label,
56
59
  className: cx(segmented ? segmentGroupClassName(layout) : "relative flex min-w-0 overflow-x-auto"),
@@ -1,10 +1,14 @@
1
- import { type RefObject } from 'react';
1
+ /** Pins a bar to the top of its scroller, over what scrolls under it.
2
+ * `useStickyTop` moves it below whatever else is pinned there. */
3
+ export declare const stickyClasses = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
2
4
  /**
3
5
  * Pins a `sticky` element just below whatever its scroller already pins at
4
6
  * the top, such as a page header, a toolbar and a tab row, rather than at
5
7
  * `top: 0` behind them. It finds them in the page, so neither they nor the
6
8
  * host declare anything, and it follows them as they change height (a toolbar
7
- * wrapping on a narrow screen) or come and go, before the browser paints.
9
+ * wrapping on a narrow screen), move, or come and go, before the browser
10
+ * paints. Chrome that uses it stacks: each piece pins under the ones before
11
+ * it, and its own `top` moving is a change the pieces after it follow.
8
12
  * In a box that scrolls on its own, nothing sits above, so it pins at 0.
9
13
  */
10
- export declare function useStickyTop(ref: RefObject<HTMLElement | null>, enabled: boolean): void;
14
+ export declare function useStickyTop(el: HTMLElement | null, enabled: boolean): void;
@@ -1,5 +1,8 @@
1
1
  import { useLayoutEffect } from "react";
2
2
  //#region src/components/stickyTop.ts
3
+ /** Pins a bar to the top of its scroller, over what scrolls under it.
4
+ * `useStickyTop` moves it below whatever else is pinned there. */
5
+ var stickyClasses = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
3
6
  var scrolls = (style) => /auto|scroll|hidden|overlay/.test(`${style.overflow} ${style.overflowX} ${style.overflowY}`);
4
7
  /** The box a sticky element sticks to: its nearest ancestor that scrolls, or
5
8
  * the document's when none does. */
@@ -49,16 +52,18 @@ function pinnedBottom(chrome) {
49
52
  * the top, such as a page header, a toolbar and a tab row, rather than at
50
53
  * `top: 0` behind them. It finds them in the page, so neither they nor the
51
54
  * host declare anything, and it follows them as they change height (a toolbar
52
- * wrapping on a narrow screen) or come and go, before the browser paints.
55
+ * wrapping on a narrow screen), move, or come and go, before the browser
56
+ * paints. Chrome that uses it stacks: each piece pins under the ones before
57
+ * it, and its own `top` moving is a change the pieces after it follow.
53
58
  * In a box that scrolls on its own, nothing sits above, so it pins at 0.
54
59
  */
55
- function useStickyTop(ref, enabled) {
60
+ function useStickyTop(el, enabled) {
56
61
  useLayoutEffect(() => {
57
- const el = ref.current;
58
62
  if (!enabled || !el) return;
59
63
  let chrome = [];
60
64
  const place = () => {
61
- el.style.top = `${Math.max(0, ...chrome.map(pinnedBottom))}px`;
65
+ const top = `${Math.max(0, ...chrome.map(pinnedBottom))}px`;
66
+ if (el.style.top !== top) el.style.top = top;
62
67
  };
63
68
  const resizes = new ResizeObserver(place);
64
69
  const changes = new MutationObserver(gather);
@@ -82,7 +87,7 @@ function useStickyTop(ref, enabled) {
82
87
  changes.disconnect();
83
88
  el.style.top = "";
84
89
  };
85
- }, [ref, enabled]);
90
+ }, [el, enabled]);
86
91
  }
87
92
  //#endregion
88
- export { useStickyTop };
93
+ export { stickyClasses, useStickyTop };
@@ -681,7 +681,7 @@ function FileExplorer({ storages, onRefresh, refreshKey, onOpenFile, showUserHie
681
681
  extra: [
682
682
  {
683
683
  label: t.preview.path,
684
- value: node.root ? void 0 : getObjectKeyFromNode(node),
684
+ value: node.root ? void 0 : getObjectKeyFromNode(node).replace(/\/$/, ""),
685
685
  icon: /* @__PURE__ */ jsx(FolderTreeIcon, {})
686
686
  },
687
687
  {
package/dist/index.d.ts CHANGED
@@ -56,6 +56,7 @@ export { SettingRow, SettingsCard, type SettingsCardProps, SettingsHeading, } fr
56
56
  export { LoadingRegion, Skeleton, type SkeletonProps } from './components/Skeleton.js';
57
57
  export { Slider, type SliderProps } from './components/Slider.js';
58
58
  export { type BadgeVariant, StatusBadge, StatusDot, statusTextClass, } from './components/StatusBadge.js';
59
+ export { StickyBar, type StickyBarProps } from './components/StickyBar.js';
59
60
  export { Switch, type SwitchProps } from './components/Switch.js';
60
61
  export { isTextEntryContext, useShortcutKey } from './components/shortcutKey.js';
61
62
  export { type SortDirection, Table, type TableDensity } from './components/Table.js';
package/dist/index.js CHANGED
@@ -67,10 +67,11 @@ import { SettingModeOption } from "./components/SettingModeOption.js";
67
67
  import { SettingRow, SettingsCard, SettingsHeading } from "./components/SettingsCard.js";
68
68
  import { Slider } from "./components/Slider.js";
69
69
  import { StatusBadge, StatusDot, statusTextClass } from "./components/StatusBadge.js";
70
+ import { StickyBar } from "./components/StickyBar.js";
70
71
  import { Table } from "./components/Table.js";
71
72
  import { TabPanel, Tabs } from "./components/Tabs.js";
72
73
  import { ThemeEditor, ThemePreview } from "./components/ThemeEditor.js";
73
74
  import { ToggleGroup } from "./components/ToggleGroup.js";
74
75
  import { useCssIsDark } from "./components/useCssIsDark.js";
75
76
  import { useApplyTheme, useColorMode } from "./components/useTheme.js";
76
- export { ActionMenu, AppLink, Autocomplete, Avatar, Button, CODE_STYLES, Callout, Card, CardHeader, Checkbox, CheckboxGroup, ColorInput, Combobox, ConfirmModal, CopyButton, CopyCodeBlock, CreateModal, CreateModalSelect, CreateModalSwitch, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, DatePicker, DescriptionList, DescriptionListGroup, DescriptionListItem, Disclosure, DisclosurePanel, Drawer, Elapsed, EmptyState, ErrorText, ExternalLink, Field, FieldOption, FieldValue, HoverCard, IconButton, InfoTip, Input, JND, LetterBadge, Loader, LoadingRegion, Markdown, MenuCheckboxItem, MenuEntries, MenuFilter, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger, Meter, MethodButton, Modal, ModalDescription, ModalTitle, NumberInput, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, Switch, THEME_PRESETS, THEME_TOKENS, TabPanel, Table, Tabs, Textarea, ThemeEditor, ThemePreview, ToggleGroup, Tooltip, TooltipProvider, UIProvider, apcaContrast, applyTheme, avatarInitials, buttonClasses, categoryClasses, categoryOf, composite, contrastRatio, cx, deltaE, deriveTheme, fieldBox, fitSeed, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatTimeLeft, generateTheme, isDarkColor, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusTone, schemeFor, serializeTheme, statusTextClass, themeStylesheet, toHex, toP3, toast, useApplyTheme, useClock, useClosePopover, useColorMode, useContextMenu, useCopy, useCssIsDark, useElapsed, useFieldControl, useFieldLabelledControl, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRelativeTime, useRunFile, useShortcutKey, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader };
77
+ export { ActionMenu, AppLink, Autocomplete, Avatar, Button, CODE_STYLES, Callout, Card, CardHeader, Checkbox, CheckboxGroup, ColorInput, Combobox, ConfirmModal, CopyButton, CopyCodeBlock, CreateModal, CreateModalSelect, CreateModalSwitch, DEFAULT_CONTRAST, DEFAULT_PRESET, DEFAULT_THEME, DatePicker, DescriptionList, DescriptionListGroup, DescriptionListItem, Disclosure, DisclosurePanel, Drawer, Elapsed, EmptyState, ErrorText, ExternalLink, Field, FieldOption, FieldValue, HoverCard, IconButton, InfoTip, Input, JND, LetterBadge, Loader, LoadingRegion, Markdown, MenuCheckboxItem, MenuEntries, MenuFilter, MenuGroupLabel, MenuItem, MenuLinkItem, MenuPopup, MenuRadioItem, MenuSeparator, MenuSubmenuTrigger, Meter, MethodButton, Modal, ModalDescription, ModalTitle, NumberInput, OneTimeCodeInput, Overview, PAGE_SIZES, PageHeader, PageHeaderAction, PageHeaderAddButton, PageHeaderBar, PageHeaderMenu, PageHeaderProvider, Pagination, Popover, PopoverClose, ProgressBar, Radio, RadioGroup, RefreshButton, RelativeTime, RequiredMark, RevealToggle, RunStatusIcon, SIDEBAR_TOKENS, SearchInput, Section, SegmentedControl, Select, SettingModeOption, SettingRow, SettingsCard, SettingsHeading, Skeleton, Slider, StatusBadge, StatusDot, StickyBar, Switch, THEME_PRESETS, THEME_TOKENS, TabPanel, Table, Tabs, Textarea, ThemeEditor, ThemePreview, ToggleGroup, Tooltip, TooltipProvider, UIProvider, apcaContrast, applyTheme, avatarInitials, buttonClasses, categoryClasses, categoryOf, composite, contrastRatio, cx, deltaE, deriveTheme, fieldBox, fitSeed, formatBytes, formatCount, formatDateTime, formatDuration, formatInfoTipContent, formatTimeLeft, generateTheme, isDarkColor, isPlainClick, isTextEntryContext, levelTone, menuDivider, modalPanelClassName, modeOf, parseColor, parseTheme, prefersWideGamut, resolveMode, runStatusTone, schemeFor, serializeTheme, statusTextClass, themeStylesheet, toHex, toP3, toast, useApplyTheme, useClock, useClosePopover, useColorMode, useContextMenu, useCopy, useCssIsDark, useElapsed, useFieldControl, useFieldLabelledControl, useNavigation, useOptionalWorkflowEngine, usePersistedState, useProvisionCorsRules, useRelativeTime, useRunFile, useShortcutKey, useSlots, useStrings, useWorkflowActions, useWorkflowEditing, useWorkflowEngine, useWorkflowEngineLoader };
@@ -42,8 +42,6 @@ export interface ItemWidth {
42
42
  * moves, and its label folds only once nothing else is left to try.
43
43
  */
44
44
  export declare function fitToolbar(groups: ItemWidth[][], right: ItemWidth[], available: number): ToolbarFit;
45
- /** Pins a toolbar to the top of the page's scroll area while the content scrolls under it. */
46
- export declare const stickyToolbarClasses = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
47
45
  /** A view's controls in one WAI-ARIA toolbar: a single tab stop, with the arrow
48
46
  * keys moving between its items, the `…` menu and disabled ones included, so
49
47
  * their reasons stay reachable. Action groups sit on the left and `right` holds
@@ -55,7 +53,8 @@ export declare const stickyToolbarClasses = "sticky top-0 z-(--layer-sticky) bg-
55
53
  export declare function ActionToolbar({ groups, right, sticky, label, }: {
56
54
  groups: ToolbarItem[][];
57
55
  right?: ToolbarItem[];
58
- /** Pins it to the top of the page's scroll area while the page scrolls. */
56
+ /** Pins it as the page scrolls, just below whatever the page's scroller
57
+ * already pins at the top, such as the page header. */
59
58
  sticky?: boolean;
60
59
  /** Names the toolbar for assistive technology, such as "Log controls";
61
60
  * defaults to "Actions". */
@@ -7,6 +7,7 @@ import { Tooltip } from "../components/Tooltip.js";
7
7
  import { useStrings } from "../components/Provider.js";
8
8
  import { AppLink } from "../components/AppLink.js";
9
9
  import { MenuEntries, useRunAction, warnIfInert } from "../components/MenuEntries.js";
10
+ import { useStickyTop } from "../components/stickyTop.js";
10
11
  import { Menu } from "@base-ui/react/menu";
11
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
13
  import { Fragment as Fragment$1, cloneElement, createContext, isValidElement, use, useLayoutEffect, useRef, useState } from "react";
@@ -264,8 +265,6 @@ function ItemSlot({ item, folded }) {
264
265
  }) : /* @__PURE__ */ jsx(ToolbarButton, { action: item })
265
266
  });
266
267
  }
267
- /** Pins a toolbar to the top of the page's scroll area while the content scrolls under it. */
268
- var stickyToolbarClasses = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
269
268
  /** A view's controls in one WAI-ARIA toolbar: a single tab stop, with the arrow
270
269
  * keys moving between its items, the `…` menu and disabled ones included, so
271
270
  * their reasons stay reachable. Action groups sit on the left and `right` holds
@@ -284,6 +283,7 @@ function ActionToolbar({ groups, right = [], sticky = false, label }) {
284
283
  warnIfManyPrimary(all);
285
284
  warnIfIconsRepeat(all);
286
285
  const fit = useToolbarFit(root, copy, visibleGroups, visibleRight);
286
+ useStickyTop(root, sticky);
287
287
  const overflow = new Set(fit.overflow);
288
288
  const folded = new Set(fit.folded);
289
289
  const shown = (items) => items.filter((item) => !overflow.has(item.key));
@@ -347,4 +347,4 @@ function warnIfIconsRepeat(items) {
347
347
  }
348
348
  }
349
349
  //#endregion
350
- export { ActionToolbar, ToolbarButton, fitToolbar, stickyToolbarClasses };
350
+ export { ActionToolbar, ToolbarButton, fitToolbar };
@@ -1,4 +1,4 @@
1
- export { ActionToolbar, stickyToolbarClasses, type ToolbarAction, ToolbarButton, type ToolbarItem, } from './ActionToolbar.js';
1
+ export { ActionToolbar, type ToolbarAction, ToolbarButton, type ToolbarItem, } from './ActionToolbar.js';
2
2
  export { ListColumns, ListPage, type ListPageProps, ListRow, ListRowActionsProvider, useListNavigate, } from './ListPage.js';
3
3
  export { actionsColumnWidth, GroupRow, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, listTableFixedProps, listTableProps, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, } from './ListTable.js';
4
4
  export { ListDisplayMenu, ListFilterMenu } from './ListViewControls.js';
@@ -1,4 +1,4 @@
1
- import { ActionToolbar, ToolbarButton, stickyToolbarClasses } from "./ActionToolbar.js";
1
+ import { ActionToolbar, ToolbarButton } from "./ActionToolbar.js";
2
2
  import { GroupRow, ListActionsHeader, ListError, ListSelectAllHeader, ListSkeleton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, actionsColumnWidth, listTableFixedProps, listTableProps } from "./ListTable.js";
3
3
  import { MoreButton, assembleRowMenu, rowContextMenuProps, useCopySubmenu, useRowMenuActive } from "./rowMenu.js";
4
4
  import { ListColumns, ListPage, ListRow, ListRowActionsProvider, useListNavigate } from "./ListPage.js";
@@ -6,4 +6,4 @@ import { ListDisplayMenu, ListFilterMenu } from "./ListViewControls.js";
6
6
  import { ListCount, ListSearchControl, useListSearch } from "./listSearch.js";
7
7
  import { DEFAULT_ORDER, FAVORITE_ORDER, useListView } from "./listView.js";
8
8
  import { HoverCardRow, UserHoverCard } from "./UserHoverCard.js";
9
- export { ActionToolbar, DEFAULT_ORDER, FAVORITE_ORDER, GroupRow, HoverCardRow, ListActionsHeader, ListColumns, ListCount, ListDisplayMenu, ListError, ListFilterMenu, ListPage, ListRow, ListRowActionsProvider, ListSearchControl, ListSelectAllHeader, ListSkeleton, MoreButton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, ToolbarButton, UserHoverCard, actionsColumnWidth, assembleRowMenu, listTableFixedProps, listTableProps, rowContextMenuProps, stickyToolbarClasses, useCopySubmenu, useListNavigate, useListSearch, useListView, useRowMenuActive };
9
+ export { ActionToolbar, DEFAULT_ORDER, FAVORITE_ORDER, GroupRow, HoverCardRow, ListActionsHeader, ListColumns, ListCount, ListDisplayMenu, ListError, ListFilterMenu, ListPage, ListRow, ListRowActionsProvider, ListSearchControl, ListSelectAllHeader, ListSkeleton, MoreButton, NAME_MIN_WIDTH_PX, NameCell, RowSelectCheckbox, ToolbarButton, UserHoverCard, actionsColumnWidth, assembleRowMenu, listTableFixedProps, listTableProps, rowContextMenuProps, useCopySubmenu, useListNavigate, useListSearch, useListView, useRowMenuActive };
@@ -183,6 +183,17 @@
183
183
  text-align: left !important;
184
184
  }
185
185
 
186
+ /* Base UI hides the native scrollbar of a select or scroll area with this
187
+ * class, and would inject the rule as an inline <style>, which a same-origin
188
+ * style policy blocks. UIProvider turns that off, so the rule ships here. */
189
+ .base-ui-disable-scrollbar {
190
+ scrollbar-width: none;
191
+ }
192
+
193
+ .base-ui-disable-scrollbar::-webkit-scrollbar {
194
+ display: none;
195
+ }
196
+
186
197
  /* Theme-aware scrollbars */
187
198
  .theme-scrollbar {
188
199
  scrollbar-width: thin;