@galaxy-io/dls 2.8.1 → 2.10.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.
- package/README.md +2 -2
- package/dist/beacons/Beacon.d.ts +1 -1
- package/dist/beacons/Beacon.js +12 -28
- package/dist/brand/GalaxyAlchemyWordmark.d.ts +4 -1
- package/dist/brand/GalaxyAlchemyWordmark.js +7 -1
- package/dist/brand/GalaxyFilamentWordmark.d.ts +5 -2
- package/dist/brand/GalaxyFilamentWordmark.js +9 -2
- package/dist/brand/GalaxyLogomark.js +3 -0
- package/dist/brand/PoweredBy.d.ts +27 -0
- package/dist/brand/PoweredBy.js +96 -0
- package/dist/brand/internal/svg/GalaxyAlchemyWordmarkSvg.d.ts +1 -1
- package/dist/brand/internal/svg/GalaxyAlchemyWordmarkSvg.js +34 -8
- package/dist/brand/internal/svg/GalaxyFilamentWordmarkSvg.d.ts +1 -1
- package/dist/brand/internal/svg/GalaxyFilamentWordmarkSvg.js +2 -2
- package/dist/charts/Heatmap.js +25 -9
- package/dist/charts/Sparkline.d.ts +1 -1
- package/dist/charts/Sparkline.js +10 -26
- package/dist/charts/chartFormat.d.ts +1 -1
- package/dist/charts/chartFormat.js +2 -2
- package/dist/charts/heatmapGeometry.d.ts +14 -0
- package/dist/charts/heatmapGeometry.js +17 -1
- package/dist/chips/Chip.d.ts +2 -2
- package/dist/chips/Chip.js +15 -31
- package/dist/drawer/Drawer.d.ts +2 -2
- package/dist/drawer/Drawer.js +1 -1
- package/dist/editor/CodeEditor.d.ts +1 -1
- package/dist/editor/CodeEditor.js +2 -1
- package/dist/feedback/Alert.d.ts +36 -9
- package/dist/feedback/Alert.js +26 -8
- package/dist/feedback/ProgressBar.d.ts +4 -1
- package/dist/feedback/ProgressBar.js +17 -30
- package/dist/feedback/ProgressCircle.d.ts +1 -1
- package/dist/feedback/ProgressCircle.js +14 -30
- package/dist/hooks/useEndReached.d.ts +40 -0
- package/dist/hooks/useEndReached.js +69 -0
- package/dist/icons/Icon.d.ts +36 -8
- package/dist/icons/Icon.js +14 -7
- package/dist/inputs/CronInput.js +114 -78
- package/dist/inputs/DateInput.d.ts +1 -1
- package/dist/inputs/DateInput.js +10 -10
- package/dist/inputs/MultiSelectInput.d.ts +3 -1
- package/dist/inputs/MultiSelectInput.js +8 -3
- package/dist/inputs/SelectInput.d.ts +8 -1
- package/dist/inputs/SelectInput.js +52 -25
- package/dist/inputs/internal/selectAll.d.ts +11 -0
- package/dist/inputs/internal/selectAll.js +28 -0
- package/dist/json/JsonViewer.js +7 -6
- package/dist/layout/AppFrame.d.ts +20 -0
- package/dist/layout/AppFrame.js +71 -0
- package/dist/layout/EmptyLayout.d.ts +53 -0
- package/dist/layout/EmptyLayout.js +59 -0
- package/dist/layout/ErrorLayout.d.ts +42 -0
- package/dist/layout/ErrorLayout.js +60 -0
- package/dist/layout/PageLayout.d.ts +26 -0
- package/dist/layout/PageLayout.js +116 -0
- package/dist/layout/PendingLayout.d.ts +30 -0
- package/dist/layout/PendingLayout.js +57 -0
- package/dist/layout/internal/errorState.d.ts +14 -0
- package/dist/layout/internal/errorState.js +49 -0
- package/dist/layout/internal/region.d.ts +10 -0
- package/dist/layout/internal/region.js +24 -0
- package/dist/lists/DescriptionList.js +1 -0
- package/dist/menu/Menu.d.ts +2 -2
- package/dist/menu/Menu.js +6 -13
- package/dist/modal/Modal.d.ts +2 -2
- package/dist/modal/Modal.js +1 -1
- package/dist/navigation/CommandPalette.js +4 -11
- package/dist/navigation/SidebarNav.d.ts +5 -0
- package/dist/navigation/SidebarNav.js +41 -22
- package/dist/navigation/Topbar.js +4 -0
- package/dist/shapes/Circle.d.ts +1 -1
- package/dist/shapes/Circle.js +10 -26
- package/dist/shapes/Square.d.ts +1 -1
- package/dist/shapes/Square.js +10 -26
- package/dist/styles/internal/roleColor.d.ts +3 -0
- package/dist/styles/internal/roleColor.js +42 -0
- package/dist/styles/mixins.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/table/InfiniteSpreadsheet.js +6 -6
- package/dist/table/InfiniteTable.d.ts +57 -18
- package/dist/table/InfiniteTable.js +5 -3
- package/dist/table/TableCore.d.ts +11 -2
- package/dist/table/TableCore.js +108 -87
- package/dist/table/VirtualizedInfiniteTable.d.ts +58 -19
- package/dist/table/VirtualizedInfiniteTable.js +9 -6
- package/dist/table/useInfiniteScrollSentinel.d.ts +13 -13
- package/dist/table/useInfiniteScrollSentinel.js +7 -51
- package/dist/table/useTableColumnLayout.d.ts +8 -2
- package/dist/table/useTableColumnLayout.js +36 -13
- package/dist/theme/tokens/dark.js +1 -1
- package/dist/theme/tokens/light.js +4 -3
- package/dist/theme/tokens/types.d.ts +7 -7
- package/dist/timeline/Timeline.d.ts +1 -1
- package/dist/timeline/Timeline.js +6 -24
- package/dist/tokens.css +1 -1
- package/dist/utils/format.d.ts +35 -10
- package/dist/utils/format.js +60 -12
- package/dist/utils/search.d.ts +15 -0
- package/dist/utils/search.js +24 -0
- package/dist/vite/index.d.ts +16 -2
- package/dist/vite/index.js +28 -19
- package/dist/vite/internal/themeBoot.d.ts +25 -0
- package/dist/vite/internal/themeBoot.js +44 -0
- package/dist/vite/internal/wywOptions.d.ts +46 -0
- package/dist/vite/internal/wywOptions.js +44 -0
- package/package.json +34 -1
|
@@ -13,6 +13,22 @@ import { CHART_PALETTE_TO_HUE_MAP } from "./chartPalette.js";
|
|
|
13
13
|
*/
|
|
14
14
|
/** @internal Cell corner radius: `radius.sm`. */
|
|
15
15
|
var HEATMAP_CELL_RADIUS = Number.parseFloat(RADIUS.sm);
|
|
16
|
+
/**
|
|
17
|
+
* @internal The placeholder grid a loading heatmap draws when it has no rows or columns yet: a
|
|
18
|
+
* week of hours (7 × 24), the shape most Galaxy heatmaps take, so the frame holds its final
|
|
19
|
+
* proportions and reads as a heatmap while data loads.
|
|
20
|
+
*/
|
|
21
|
+
var HEATMAP_LOADING_GRID = {
|
|
22
|
+
columns: 24,
|
|
23
|
+
rows: 7
|
|
24
|
+
};
|
|
25
|
+
/** @internal The loading grid's column and row keys: positional, never shown (no axes). */
|
|
26
|
+
function heatmapLoadingAxes() {
|
|
27
|
+
return {
|
|
28
|
+
columns: Array.from({ length: HEATMAP_LOADING_GRID.columns }, (_, index) => `c${index}`),
|
|
29
|
+
rows: Array.from({ length: HEATMAP_LOADING_GRID.rows }, (_, index) => `r${index}`)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
16
32
|
/** @internal Number of ramp steps. */
|
|
17
33
|
var HEATMAP_STEP_COUNT = 5;
|
|
18
34
|
/** @internal The aspect-ratio fallback is clamped to these, so cells stay near-square. */
|
|
@@ -152,4 +168,4 @@ function buildHeatmapGeometry({ cells, columns, rows, domain, plotWidth, plotHei
|
|
|
152
168
|
return geometry;
|
|
153
169
|
}
|
|
154
170
|
//#endregion
|
|
155
|
-
export { HEATMAP_CELL_RADIUS, HEATMAP_MAX_ASPECT_RATIO, HEATMAP_MIN_ASPECT_RATIO, HEATMAP_STEP_COUNT, HEATMAP_STEP_TO_TOKEN_MAP, buildHeatmapGeometry, estimateRowLabelInset, getHeatmapDomain, getHeatmapLabels, getHeatmapStep };
|
|
171
|
+
export { HEATMAP_CELL_RADIUS, HEATMAP_LOADING_GRID, HEATMAP_MAX_ASPECT_RATIO, HEATMAP_MIN_ASPECT_RATIO, HEATMAP_STEP_COUNT, HEATMAP_STEP_TO_TOKEN_MAP, buildHeatmapGeometry, estimateRowLabelInset, getHeatmapDomain, getHeatmapLabels, getHeatmapStep, heatmapLoadingAxes };
|
package/dist/chips/Chip.d.ts
CHANGED
|
@@ -15,8 +15,8 @@ export declare enum ChipSize {
|
|
|
15
15
|
X_LARGE = "X_LARGE"
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Color role (
|
|
19
|
-
* together. Categories take `color` instead.
|
|
18
|
+
* Color role (AGENTS.md "Variant": color set, meaning only): tints the fill, the text and the
|
|
19
|
+
* border together. Categories take `color` instead.
|
|
20
20
|
*/
|
|
21
21
|
export declare enum ChipVariant {
|
|
22
22
|
/** `background.primary` fill, `text.primary`. */
|
package/dist/chips/Chip.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Skeleton, { SkeletonSize, SkeletonVariant } from "../feedback/Skeleton.js";
|
|
2
2
|
import Text, { TextSize, TextVariant } from "../text/Text.js";
|
|
3
3
|
import Tooltip from "../tooltip/Tooltip.js";
|
|
4
|
+
import { ROLE_COLOR_TO_CSS_MAP } from "../styles/internal/roleColor.js";
|
|
4
5
|
import Beacon, { BeaconSize, BeaconVariant } from "../beacons/Beacon.js";
|
|
5
6
|
import Icon, { IconVariant } from "../icons/Icon.js";
|
|
6
7
|
/* empty css */
|
|
@@ -45,8 +46,8 @@ var ChipSize = /* @__PURE__ */ function(ChipSize) {
|
|
|
45
46
|
return ChipSize;
|
|
46
47
|
}({});
|
|
47
48
|
/**
|
|
48
|
-
* Color role (
|
|
49
|
-
* together. Categories take `color` instead.
|
|
49
|
+
* Color role (AGENTS.md "Variant": color set, meaning only): tints the fill, the text and the
|
|
50
|
+
* border together. Categories take `color` instead.
|
|
50
51
|
*/
|
|
51
52
|
var ChipVariant = /* @__PURE__ */ function(ChipVariant) {
|
|
52
53
|
/** `background.primary` fill, `text.primary`. */
|
|
@@ -150,36 +151,19 @@ var CHIP_VARIANT_TO_CSS_MAP = {
|
|
|
150
151
|
["WARNING"]: "gx-Chip-WARNING-wmla4eg",
|
|
151
152
|
["ERROR"]: "gx-Chip-ERROR-ey90mc4"
|
|
152
153
|
};
|
|
153
|
-
/**
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
orange: "gx-Chip-orange-o6qjmz2",
|
|
160
|
-
amber: "gx-Chip-amber-atd4jog",
|
|
161
|
-
yellow: "gx-Chip-yellow-yvlk44e",
|
|
162
|
-
lime: "gx-Chip-lime-l1pq316v",
|
|
163
|
-
green: "gx-Chip-green-gm0lqld",
|
|
164
|
-
emerald: "gx-Chip-emerald-eyyt7c0",
|
|
165
|
-
teal: "gx-Chip-teal-t11ah2de",
|
|
166
|
-
cyan: "gx-Chip-cyan-czbiez9",
|
|
167
|
-
sky: "gx-Chip-sky-s9o9u3v",
|
|
168
|
-
blue: "gx-Chip-blue-b1ec95in",
|
|
169
|
-
indigo: "gx-Chip-indigo-iptfyqj",
|
|
170
|
-
violet: "gx-Chip-violet-v1fzme42",
|
|
171
|
-
purple: "gx-Chip-purple-piztats",
|
|
172
|
-
fuchsia: "gx-Chip-fuchsia-f1g78mhs",
|
|
173
|
-
pink: "gx-Chip-pink-p1t4qqih",
|
|
174
|
-
rose: "gx-Chip-rose-r1na9n10"
|
|
175
|
-
};
|
|
154
|
+
/**
|
|
155
|
+
* Categorical `color`: the family's text, fill and border, as a status variant renders. Reads the
|
|
156
|
+
* shared `--gx-role-*` variables `ROLE_COLOR_TO_CSS_MAP` sets per family, so the twenty families
|
|
157
|
+
* are written once (`styles/internal/roleColor`).
|
|
158
|
+
*/
|
|
159
|
+
var CHIP_COLOR_CSS = "gx-Chip-CHIP_COLOR_CSS-c1buqu4j";
|
|
176
160
|
/** `hex`: declared after the variant and color maps so it wins over them. */
|
|
177
|
-
var HEX_CSS = "gx-Chip-HEX_CSS-
|
|
178
|
-
var HAS_BORDER_CSS = "gx-Chip-HAS_BORDER_CSS-
|
|
161
|
+
var HEX_CSS = "gx-Chip-HEX_CSS-h1xofe8u";
|
|
162
|
+
var HAS_BORDER_CSS = "gx-Chip-HAS_BORDER_CSS-hlle9kf";
|
|
179
163
|
/** Declared after `HAS_BORDER_CSS`, so selection wins. */
|
|
180
|
-
var SELECTED_CSS = "gx-Chip-SELECTED_CSS-
|
|
181
|
-
var PILL_CSS = "gx-Chip-PILL_CSS-
|
|
182
|
-
/** Label and count type step per rung (
|
|
164
|
+
var SELECTED_CSS = "gx-Chip-SELECTED_CSS-svehr9v";
|
|
165
|
+
var PILL_CSS = "gx-Chip-PILL_CSS-p6qjmz2";
|
|
166
|
+
/** Label and count type step per rung (AGENTS.md "Control rungs"). */
|
|
183
167
|
var CHIP_SIZE_TO_TEXT_SIZE_MAP = {
|
|
184
168
|
["X_SMALL"]: TextSize.CAPTION,
|
|
185
169
|
["SMALL"]: TextSize.BODY_SM,
|
|
@@ -337,7 +321,7 @@ var Chip = forwardRef(function Chip({ label, icon, leading, hasDot = false, coun
|
|
|
337
321
|
...rootRest,
|
|
338
322
|
ref,
|
|
339
323
|
id,
|
|
340
|
-
className: cx(CHIP_SIZE_TO_CSS_MAP[size], hasColor ?
|
|
324
|
+
className: cx(CHIP_SIZE_TO_CSS_MAP[size], hasColor ? cx(ROLE_COLOR_TO_CSS_MAP[color], CHIP_COLOR_CSS) : CHIP_VARIANT_TO_CSS_MAP[shownVariant], hasHex && HEX_CSS, hasBorder && HAS_BORDER_CSS, isSelected === true && SELECTED_CSS, isPill && PILL_CSS, className),
|
|
341
325
|
style: {
|
|
342
326
|
...variables,
|
|
343
327
|
...style
|
package/dist/drawer/Drawer.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type AriaAttributes, type CSSProperties, type ReactNode } from "react";
|
|
|
3
3
|
import { Side } from "../theme/enums.js";
|
|
4
4
|
/**
|
|
5
5
|
* Panel width (`LEFT` / `RIGHT`) or height (`TOP` / `BOTTOM`). Canonical rung names
|
|
6
|
-
* (
|
|
6
|
+
* (AGENTS.md "Size"); the values are lengths, not control heights.
|
|
7
7
|
*/
|
|
8
8
|
export declare enum DrawerSize {
|
|
9
9
|
/** 400px wide / 240px tall. */
|
|
@@ -60,7 +60,7 @@ interface DrawerBaseProps extends AriaAttributes {
|
|
|
60
60
|
* @default true
|
|
61
61
|
*/
|
|
62
62
|
isDismissable?: boolean;
|
|
63
|
-
/** Controlled open state. When set, Drawer calls `onOpenChange` and lets the caller decide. */
|
|
63
|
+
/** Controlled open state. When set, Drawer calls `onOpenChange` and lets the caller decide. While it closes, the panel keeps the `children` and slots it had when `isOpen` turned false, so pass the open record as a prop with no hook to retain it. */
|
|
64
64
|
isOpen?: boolean;
|
|
65
65
|
/**
|
|
66
66
|
* Initial open state while uncontrolled.
|
package/dist/drawer/Drawer.js
CHANGED
|
@@ -49,7 +49,7 @@ import { AnimatePresence, motion } from "framer-motion";
|
|
|
49
49
|
*/
|
|
50
50
|
/**
|
|
51
51
|
* Panel width (`LEFT` / `RIGHT`) or height (`TOP` / `BOTTOM`). Canonical rung names
|
|
52
|
-
* (
|
|
52
|
+
* (AGENTS.md "Size"); the values are lengths, not control heights.
|
|
53
53
|
*/
|
|
54
54
|
var DrawerSize = /* @__PURE__ */ function(DrawerSize) {
|
|
55
55
|
/** 400px wide / 240px tall. */
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import type { Extension } from "@codemirror/state";
|
|
17
17
|
import { type AriaAttributes, type CSSProperties } from "react";
|
|
18
|
-
/** Resting fill of the editor frame (
|
|
18
|
+
/** Resting fill of the editor frame (AGENTS.md "Variant": surface set; 1.x members). 1.x `noBorder` is `isGhost`. */
|
|
19
19
|
export declare enum CodeEditorVariant {
|
|
20
20
|
/** `background.base`. */
|
|
21
21
|
BASE = "BASE",
|
|
@@ -15,7 +15,7 @@ import { tags } from "@lezer/highlight";
|
|
|
15
15
|
import { createTheme } from "@uiw/codemirror-themes";
|
|
16
16
|
import CodeMirror from "@uiw/react-codemirror";
|
|
17
17
|
//#region src/editor/CodeEditor.tsx
|
|
18
|
-
/** Resting fill of the editor frame (
|
|
18
|
+
/** Resting fill of the editor frame (AGENTS.md "Variant": surface set; 1.x members). 1.x `noBorder` is `isGhost`. */
|
|
19
19
|
var CodeEditorVariant = /* @__PURE__ */ function(CodeEditorVariant) {
|
|
20
20
|
/** `background.base`. */
|
|
21
21
|
CodeEditorVariant["BASE"] = "BASE";
|
|
@@ -259,6 +259,7 @@ function getEditorViewTheme() {
|
|
|
259
259
|
lineHeight: t.font.mono.height.body_lg,
|
|
260
260
|
letterSpacing: t.font.mono.spacing.body_md
|
|
261
261
|
},
|
|
262
|
+
".cm-scroller:focus": { outline: "none" },
|
|
262
263
|
".cm-content": { padding: `${t.space[8]} 0` },
|
|
263
264
|
".cm-line": { padding: `0 ${t.space[12]}` },
|
|
264
265
|
".cm-gutters": {
|
package/dist/feedback/Alert.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Icon as PhosphorIcon } from "@phosphor-icons/react";
|
|
2
2
|
import { type AriaAttributes, type CSSProperties, type ReactNode } from "react";
|
|
3
|
-
|
|
3
|
+
import type { RoleColor } from "../theme/tokens/types.js";
|
|
4
|
+
/** Severity (AGENTS.md "Variant": color set, subset). */
|
|
4
5
|
export declare enum AlertVariant {
|
|
5
6
|
/** Neutral note: `background.secondary` surface, `InfoIcon` in `text.secondary`. The default. */
|
|
6
7
|
PRIMARY = "PRIMARY",
|
|
@@ -11,19 +12,15 @@ export declare enum AlertVariant {
|
|
|
11
12
|
/** Broken, blocked: error surface, `WarningCircleIcon`, `role="alert"`. */
|
|
12
13
|
ERROR = "ERROR"
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* Severity: sets the surface tint, the border, the icon and the ARIA role.
|
|
17
|
-
* @default AlertVariant.PRIMARY
|
|
18
|
-
*/
|
|
19
|
-
variant?: AlertVariant;
|
|
15
|
+
/** Every Alert prop except the color axis (`variant` or `color`). */
|
|
16
|
+
interface AlertBaseProps extends AriaAttributes {
|
|
20
17
|
/** Short headline ("Schema drift detected"). Medium weight; above the body inline, before it in a banner. */
|
|
21
18
|
header?: string;
|
|
22
19
|
/** The message. Rendered in a `Text`, so inline `Span`, `Code` and `Link` inherit its size and color. */
|
|
23
20
|
children?: ReactNode;
|
|
24
21
|
/**
|
|
25
|
-
* Replaces the
|
|
26
|
-
* @default the variant's icon
|
|
22
|
+
* Replaces the default icon. Pass the component (`PlugsIcon`), not an element.
|
|
23
|
+
* @default the variant's icon, or `InfoIcon` with `color`
|
|
27
24
|
*/
|
|
28
25
|
icon?: PhosphorIcon;
|
|
29
26
|
/** The way out: one `ButtonVariant.PRIMARY` button at `ButtonSize.SMALL`, any second action `TERTIARY`. A row under the body inline; trailing in a banner. */
|
|
@@ -44,6 +41,36 @@ export interface AlertProps extends AriaAttributes {
|
|
|
44
41
|
/** Inline style on the root `<div>`; only for setting CSS custom properties. */
|
|
45
42
|
style?: CSSProperties;
|
|
46
43
|
}
|
|
44
|
+
/** An alert colored by severity (`variant`), or the default `PRIMARY`. */
|
|
45
|
+
interface AlertVariantProps {
|
|
46
|
+
/**
|
|
47
|
+
* Severity: sets the surface tint, the border, the icon and the ARIA role. Not with `color`.
|
|
48
|
+
* @default AlertVariant.PRIMARY
|
|
49
|
+
*/
|
|
50
|
+
variant?: AlertVariant;
|
|
51
|
+
/**
|
|
52
|
+
* Categorical palette family (`"yellow"`) or a status name used as data: the family's surface,
|
|
53
|
+
* hairline and icon color, `role="status"`, announced as a "Note". For a notice tied to a
|
|
54
|
+
* category the page already shows; never a generic "info" tone. Not with `variant`.
|
|
55
|
+
*/
|
|
56
|
+
color?: undefined;
|
|
57
|
+
}
|
|
58
|
+
/** An alert colored by category (`color`). */
|
|
59
|
+
interface AlertColorProps {
|
|
60
|
+
/**
|
|
61
|
+
* Severity: sets the surface tint, the border, the icon and the ARIA role. Not with `color`.
|
|
62
|
+
* @default AlertVariant.PRIMARY
|
|
63
|
+
*/
|
|
64
|
+
variant?: undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Categorical palette family (`"yellow"`) or a status name used as data: the family's surface,
|
|
67
|
+
* hairline and icon color, `role="status"`, announced as a "Note". For a notice tied to a
|
|
68
|
+
* category the page already shows; never a generic "info" tone. Not with `variant`.
|
|
69
|
+
*/
|
|
70
|
+
color: RoleColor;
|
|
71
|
+
}
|
|
72
|
+
/** Alert props. An alert with both `variant` and `color` is a type error. */
|
|
73
|
+
export type AlertProps = AlertBaseProps & (AlertVariantProps | AlertColorProps);
|
|
47
74
|
/** A tinted, bordered message with a severity icon, optional header, actions and dismiss. */
|
|
48
75
|
declare const Alert: import("react").ForwardRefExoticComponent<AlertProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
49
76
|
export default Alert;
|
package/dist/feedback/Alert.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Text, { TextSize, TextVariant, TextWeight } from "../text/Text.js";
|
|
2
|
+
import { ROLE_COLOR_TO_CSS_MAP } from "../styles/internal/roleColor.js";
|
|
2
3
|
import Icon, { IconVariant, IconWeight } from "../icons/Icon.js";
|
|
3
4
|
import Button, { ButtonSize, ButtonVariant } from "../buttons/Button.js";
|
|
4
5
|
/* empty css */
|
|
@@ -21,11 +22,17 @@ import { CheckCircleIcon, InfoIcon, WarningCircleIcon, WarningIcon, XIcon } from
|
|
|
21
22
|
* A live region announces content that arrives after it is in the DOM, so mount the Alert when
|
|
22
23
|
* the condition becomes true rather than rendering it hidden and revealing it.
|
|
23
24
|
*
|
|
25
|
+
* `color` ties a notice to a category the page already shows (a schedule banner in the schedule's
|
|
26
|
+
* yellow): the surface is `background.<color>` and `border.<color>` through the shared
|
|
27
|
+
* `--gx-role-*` variables, the icon is `Icon color` (default `InfoIcon`), the role is `status` and
|
|
28
|
+
* the icon's accessible name is "Note". It is not an "info" tone: neutral news stays `PRIMARY`.
|
|
29
|
+
* `variant` and `color` are exclusive by type (the Chip union).
|
|
30
|
+
*
|
|
24
31
|
* Inline it is a rounded panel; `isBanner` makes it a full-width strip across the top of a page
|
|
25
32
|
* or panel (square corners, bottom hairline only, one line). No motion of its own: wrap it in
|
|
26
33
|
* `Fade` (or the app's own height animation) for an animated dismiss.
|
|
27
34
|
*/
|
|
28
|
-
/** Severity (
|
|
35
|
+
/** Severity (AGENTS.md "Variant": color set, subset). */
|
|
29
36
|
var AlertVariant = /* @__PURE__ */ function(AlertVariant) {
|
|
30
37
|
/** Neutral note: `background.secondary` surface, `InfoIcon` in `text.secondary`. The default. */
|
|
31
38
|
AlertVariant["PRIMARY"] = "PRIMARY";
|
|
@@ -80,6 +87,8 @@ var ALERT_VARIANT_TO_CSS_MAP = {
|
|
|
80
87
|
["WARNING"]: "gx-Alert-WARNING-w6btz5r",
|
|
81
88
|
["ERROR"]: "gx-Alert-ERROR-e1rogvwo"
|
|
82
89
|
};
|
|
90
|
+
/** Categorical `color`: the family's surface and hairline, read from the shared role variables. */
|
|
91
|
+
var COLOR_CSS = "gx-Alert-COLOR_CSS-cr7k6o5";
|
|
83
92
|
/** Default glyph per severity. `ERROR` differs in shape from `WARNING`, so severity is never color-only. */
|
|
84
93
|
var ALERT_VARIANT_TO_ICON_MAP = {
|
|
85
94
|
["PRIMARY"]: InfoIcon,
|
|
@@ -108,14 +117,17 @@ var ALERT_VARIANT_TO_SEVERITY_LABEL_MAP = {
|
|
|
108
117
|
["WARNING"]: "Warning",
|
|
109
118
|
["ERROR"]: "Error"
|
|
110
119
|
};
|
|
120
|
+
/** The icon's accessible name with `color`: a category is a note, never a severity. */
|
|
121
|
+
var COLOR_SEVERITY_LABEL = "Note";
|
|
111
122
|
/** Banner: square corners, bottom hairline only, centered one-line row. */
|
|
112
|
-
var BANNER_CSS = "gx-Alert-BANNER_CSS-
|
|
123
|
+
var BANNER_CSS = "gx-Alert-BANNER_CSS-b11mdnwt";
|
|
113
124
|
/** Banner: the header and body read as one line, wrapping when narrow. */
|
|
114
|
-
var BANNER_CONTENT_CSS = "gx-Alert-BANNER_CONTENT_CSS-
|
|
125
|
+
var BANNER_CONTENT_CSS = "gx-Alert-BANNER_CONTENT_CSS-by507ww";
|
|
115
126
|
/** Banner: the actions trail and never shrink. */
|
|
116
|
-
var BANNER_ACTIONS_CSS = "gx-Alert-BANNER_ACTIONS_CSS-
|
|
127
|
+
var BANNER_ACTIONS_CSS = "gx-Alert-BANNER_ACTIONS_CSS-b1imlr6o";
|
|
117
128
|
/** A tinted, bordered message with a severity icon, optional header, actions and dismiss. */
|
|
118
|
-
var Alert = forwardRef(function Alert({ variant = "PRIMARY", header, children, icon, actions, onDismiss, isBanner = false, id, className, style, ...rest }, ref) {
|
|
129
|
+
var Alert = forwardRef(function Alert({ variant = "PRIMARY", color, header, children, icon, actions, onDismiss, isBanner = false, id, className, style, ...rest }, ref) {
|
|
130
|
+
const hasColor = color !== void 0;
|
|
119
131
|
const hasHeader = header !== void 0 && header !== "";
|
|
120
132
|
const hasBody = children !== void 0 && children !== null && children !== false;
|
|
121
133
|
const actionsRow = actions !== void 0 && actions !== null && actions !== false && /* @__PURE__ */ jsx(Actions, {
|
|
@@ -123,14 +135,20 @@ var Alert = forwardRef(function Alert({ variant = "PRIMARY", header, children, i
|
|
|
123
135
|
children: actions
|
|
124
136
|
});
|
|
125
137
|
return /* @__PURE__ */ jsxs(Root, {
|
|
126
|
-
role: ALERT_VARIANT_TO_ROLE_MAP[variant],
|
|
138
|
+
role: hasColor ? "status" : ALERT_VARIANT_TO_ROLE_MAP[variant],
|
|
127
139
|
...rest,
|
|
128
140
|
ref,
|
|
129
141
|
id,
|
|
130
|
-
className: cx(ALERT_VARIANT_TO_CSS_MAP[variant], isBanner && BANNER_CSS, className),
|
|
142
|
+
className: cx(hasColor ? cx(ROLE_COLOR_TO_CSS_MAP[color], COLOR_CSS) : ALERT_VARIANT_TO_CSS_MAP[variant], isBanner && BANNER_CSS, className),
|
|
131
143
|
style,
|
|
132
144
|
children: [
|
|
133
|
-
/* @__PURE__ */ jsx(IconSlot, { children: /* @__PURE__ */ jsx(Icon, {
|
|
145
|
+
/* @__PURE__ */ jsx(IconSlot, { children: hasColor ? /* @__PURE__ */ jsx(Icon, {
|
|
146
|
+
component: icon ?? InfoIcon,
|
|
147
|
+
size: 16,
|
|
148
|
+
weight: IconWeight.FILL,
|
|
149
|
+
color,
|
|
150
|
+
ariaLabel: COLOR_SEVERITY_LABEL
|
|
151
|
+
}) : /* @__PURE__ */ jsx(Icon, {
|
|
134
152
|
component: icon ?? ALERT_VARIANT_TO_ICON_MAP[variant],
|
|
135
153
|
size: 16,
|
|
136
154
|
weight: IconWeight.FILL,
|
|
@@ -13,7 +13,10 @@ export declare enum ProgressBarSize {
|
|
|
13
13
|
/** 8px track, body_lg label. */
|
|
14
14
|
X_LARGE = "X_LARGE"
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Fill color (AGENTS.md "Variant": color set, subset; the same members as
|
|
18
|
+
* `ProgressCircleVariant`).
|
|
19
|
+
*/
|
|
17
20
|
export declare enum ProgressBarVariant {
|
|
18
21
|
/** `text.primary`. The default. */
|
|
19
22
|
PRIMARY = "PRIMARY",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Text, { TextSize, TextVariant } from "../text/Text.js";
|
|
2
|
+
import { ROLE_COLOR_TO_CSS_MAP } from "../styles/internal/roleColor.js";
|
|
2
3
|
import { formatPercent } from "../utils/format.js";
|
|
3
4
|
/* empty css */
|
|
4
5
|
import { styled } from "@linaria/react";
|
|
@@ -34,7 +35,10 @@ var ProgressBarSize = /* @__PURE__ */ function(ProgressBarSize) {
|
|
|
34
35
|
ProgressBarSize["X_LARGE"] = "X_LARGE";
|
|
35
36
|
return ProgressBarSize;
|
|
36
37
|
}({});
|
|
37
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Fill color (AGENTS.md "Variant": color set, subset; the same members as
|
|
40
|
+
* `ProgressCircleVariant`).
|
|
41
|
+
*/
|
|
38
42
|
var ProgressBarVariant = /* @__PURE__ */ function(ProgressBarVariant) {
|
|
39
43
|
/** `text.primary`. The default. */
|
|
40
44
|
ProgressBarVariant["PRIMARY"] = "PRIMARY";
|
|
@@ -95,36 +99,19 @@ var PROGRESS_BAR_VARIANT_TO_CSS_MAP = {
|
|
|
95
99
|
["WARNING"]: "gx-ProgressBar-WARNING-w1w2olvo",
|
|
96
100
|
["ERROR"]: "gx-ProgressBar-ERROR-e1qre8wf"
|
|
97
101
|
};
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
orange: "gx-ProgressBar-orange-ocvje08",
|
|
105
|
-
amber: "gx-ProgressBar-amber-ab5j54q",
|
|
106
|
-
yellow: "gx-ProgressBar-yellow-ylbvi15",
|
|
107
|
-
lime: "gx-ProgressBar-lime-lwaqggx",
|
|
108
|
-
green: "gx-ProgressBar-green-g6fb74o",
|
|
109
|
-
emerald: "gx-ProgressBar-emerald-e13m8tjk",
|
|
110
|
-
teal: "gx-ProgressBar-teal-t195062s",
|
|
111
|
-
cyan: "gx-ProgressBar-cyan-c1tjg1hb",
|
|
112
|
-
sky: "gx-ProgressBar-sky-s1hc7niq",
|
|
113
|
-
blue: "gx-ProgressBar-blue-b31v6jj",
|
|
114
|
-
indigo: "gx-ProgressBar-indigo-i1idth2y",
|
|
115
|
-
violet: "gx-ProgressBar-violet-vsz64tr",
|
|
116
|
-
purple: "gx-ProgressBar-purple-p121jrhu",
|
|
117
|
-
fuchsia: "gx-ProgressBar-fuchsia-foqk5ch",
|
|
118
|
-
pink: "gx-ProgressBar-pink-p1luqk3n",
|
|
119
|
-
rose: "gx-ProgressBar-rose-r1hbdj3k"
|
|
120
|
-
};
|
|
102
|
+
/**
|
|
103
|
+
* Categorical `color`: `mark.<family>` on the root, the way a status variant renders. Reads the
|
|
104
|
+
* shared `--gx-role-*` variables `ROLE_COLOR_TO_CSS_MAP` sets per family, so the twenty families
|
|
105
|
+
* are written once (`styles/internal/roleColor`).
|
|
106
|
+
*/
|
|
107
|
+
var PROGRESS_BAR_COLOR_CSS = "gx-ProgressBar-PROGRESS_BAR_COLOR_CSS-peiy0oi";
|
|
121
108
|
/** Track thickness and the gap between the label line and the track. */
|
|
122
109
|
var PROGRESS_BAR_SIZE_TO_CSS_MAP = {
|
|
123
|
-
["X_SMALL"]: "gx-ProgressBar-X_SMALL-
|
|
124
|
-
["SMALL"]: "gx-ProgressBar-SMALL-
|
|
125
|
-
["MEDIUM"]: "gx-ProgressBar-MEDIUM-
|
|
126
|
-
["LARGE"]: "gx-ProgressBar-LARGE-
|
|
127
|
-
["X_LARGE"]: "gx-ProgressBar-X_LARGE-
|
|
110
|
+
["X_SMALL"]: "gx-ProgressBar-X_SMALL-x1epzlep",
|
|
111
|
+
["SMALL"]: "gx-ProgressBar-SMALL-sasg8k0",
|
|
112
|
+
["MEDIUM"]: "gx-ProgressBar-MEDIUM-m1kkinrj",
|
|
113
|
+
["LARGE"]: "gx-ProgressBar-LARGE-lcvje08",
|
|
114
|
+
["X_LARGE"]: "gx-ProgressBar-X_LARGE-xb5j54q"
|
|
128
115
|
};
|
|
129
116
|
/** The label and value are the rung's text step (the ProgressCircle table). */
|
|
130
117
|
var PROGRESS_BAR_SIZE_TO_TEXT_SIZE_MAP = {
|
|
@@ -158,7 +145,7 @@ var ProgressBar = forwardRef(function ProgressBar({ value, isIndeterminate = fal
|
|
|
158
145
|
"aria-valuetext": isIndeterminate ? void 0 : rest["aria-valuetext"] ?? percentText,
|
|
159
146
|
"aria-label": hasLabel ? rest["aria-label"] : ariaLabel ?? rest["aria-label"],
|
|
160
147
|
"aria-labelledby": hasLabel ? labelId : rest["aria-labelledby"],
|
|
161
|
-
className: cx(color !== void 0 ?
|
|
148
|
+
className: cx(color !== void 0 ? cx(ROLE_COLOR_TO_CSS_MAP[color], PROGRESS_BAR_COLOR_CSS) : PROGRESS_BAR_VARIANT_TO_CSS_MAP[variant], PROGRESS_BAR_SIZE_TO_CSS_MAP[size], className),
|
|
162
149
|
style: {
|
|
163
150
|
...variables,
|
|
164
151
|
...style
|
|
@@ -13,7 +13,7 @@ export declare enum ProgressCircleSize {
|
|
|
13
13
|
/** 40px rung: 16px ring, body_lg label. */
|
|
14
14
|
X_LARGE = "X_LARGE"
|
|
15
15
|
}
|
|
16
|
-
/** Arc color (
|
|
16
|
+
/** Arc color (AGENTS.md "Variant": color set, subset; the same members as `ProgressBarVariant`). */
|
|
17
17
|
export declare enum ProgressCircleVariant {
|
|
18
18
|
/** `text.primary`. The default. */
|
|
19
19
|
PRIMARY = "PRIMARY",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Text, { TextSize, TextVariant } from "../text/Text.js";
|
|
2
|
+
import { ROLE_COLOR_TO_CSS_MAP } from "../styles/internal/roleColor.js";
|
|
2
3
|
import { formatPercent } from "../utils/format.js";
|
|
3
4
|
/* empty css */
|
|
4
5
|
import { styled } from "@linaria/react";
|
|
@@ -34,7 +35,7 @@ var ProgressCircleSize = /* @__PURE__ */ function(ProgressCircleSize) {
|
|
|
34
35
|
ProgressCircleSize["X_LARGE"] = "X_LARGE";
|
|
35
36
|
return ProgressCircleSize;
|
|
36
37
|
}({});
|
|
37
|
-
/** Arc color (
|
|
38
|
+
/** Arc color (AGENTS.md "Variant": color set, subset; the same members as `ProgressBarVariant`). */
|
|
38
39
|
var ProgressCircleVariant = /* @__PURE__ */ function(ProgressCircleVariant) {
|
|
39
40
|
/** `text.primary`. The default. */
|
|
40
41
|
ProgressCircleVariant["PRIMARY"] = "PRIMARY";
|
|
@@ -82,36 +83,19 @@ var PROGRESS_CIRCLE_VARIANT_TO_CSS_MAP = {
|
|
|
82
83
|
["WARNING"]: "gx-ProgressCircle-WARNING-w1ii09vl",
|
|
83
84
|
["ERROR"]: "gx-ProgressCircle-ERROR-e149xl4a"
|
|
84
85
|
};
|
|
85
|
-
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
orange: "gx-ProgressCircle-orange-os32e8h",
|
|
92
|
-
amber: "gx-ProgressCircle-amber-a1z891t",
|
|
93
|
-
yellow: "gx-ProgressCircle-yellow-y169l71b",
|
|
94
|
-
lime: "gx-ProgressCircle-lime-l7wy6jh",
|
|
95
|
-
green: "gx-ProgressCircle-green-gid9v1r",
|
|
96
|
-
emerald: "gx-ProgressCircle-emerald-ephjv2k",
|
|
97
|
-
teal: "gx-ProgressCircle-teal-t14y8mwv",
|
|
98
|
-
cyan: "gx-ProgressCircle-cyan-c1gpmklw",
|
|
99
|
-
sky: "gx-ProgressCircle-sky-s15o8mw",
|
|
100
|
-
blue: "gx-ProgressCircle-blue-b865hhm",
|
|
101
|
-
indigo: "gx-ProgressCircle-indigo-i1lkh9dd",
|
|
102
|
-
violet: "gx-ProgressCircle-violet-v4a8qsx",
|
|
103
|
-
purple: "gx-ProgressCircle-purple-pzljd4b",
|
|
104
|
-
fuchsia: "gx-ProgressCircle-fuchsia-foz9zwb",
|
|
105
|
-
pink: "gx-ProgressCircle-pink-pi0gudm",
|
|
106
|
-
rose: "gx-ProgressCircle-rose-r1tg3t7s"
|
|
107
|
-
};
|
|
86
|
+
/**
|
|
87
|
+
* Categorical `color`: `mark.<family>` on the root, the way a status variant renders. Reads the
|
|
88
|
+
* shared `--gx-role-*` variables `ROLE_COLOR_TO_CSS_MAP` sets per family, so the twenty families
|
|
89
|
+
* are written once (`styles/internal/roleColor`).
|
|
90
|
+
*/
|
|
91
|
+
var PROGRESS_CIRCLE_COLOR_CSS = "gx-ProgressCircle-PROGRESS_CIRCLE_COLOR_CSS-p5wr4fy";
|
|
108
92
|
/** Ring box, root height (the rung's text line height) and gap: the Spinner table. */
|
|
109
93
|
var PROGRESS_CIRCLE_SIZE_TO_CSS_MAP = {
|
|
110
|
-
["X_SMALL"]: "gx-ProgressCircle-X_SMALL-
|
|
111
|
-
["SMALL"]: "gx-ProgressCircle-SMALL-
|
|
112
|
-
["MEDIUM"]: "gx-ProgressCircle-MEDIUM-
|
|
113
|
-
["LARGE"]: "gx-ProgressCircle-LARGE-
|
|
114
|
-
["X_LARGE"]: "gx-ProgressCircle-X_LARGE-
|
|
94
|
+
["X_SMALL"]: "gx-ProgressCircle-X_SMALL-x3cpdk8",
|
|
95
|
+
["SMALL"]: "gx-ProgressCircle-SMALL-s3bcytf",
|
|
96
|
+
["MEDIUM"]: "gx-ProgressCircle-MEDIUM-m1b1indu",
|
|
97
|
+
["LARGE"]: "gx-ProgressCircle-LARGE-ls32e8h",
|
|
98
|
+
["X_LARGE"]: "gx-ProgressCircle-X_LARGE-x1z891t"
|
|
115
99
|
};
|
|
116
100
|
/** The label and value are the rung's text step (the ProgressBar table). */
|
|
117
101
|
var PROGRESS_CIRCLE_SIZE_TO_TEXT_SIZE_MAP = {
|
|
@@ -144,7 +128,7 @@ var ProgressCircle = forwardRef(function ProgressCircle({ value, shouldShowValue
|
|
|
144
128
|
"aria-valuetext": rest["aria-valuetext"] ?? percentText,
|
|
145
129
|
"aria-label": hasLabel ? rest["aria-label"] : ariaLabel ?? rest["aria-label"],
|
|
146
130
|
"aria-labelledby": hasLabel ? labelId : rest["aria-labelledby"],
|
|
147
|
-
className: cx(color !== void 0 ?
|
|
131
|
+
className: cx(color !== void 0 ? cx(ROLE_COLOR_TO_CSS_MAP[color], PROGRESS_CIRCLE_COLOR_CSS) : PROGRESS_CIRCLE_VARIANT_TO_CSS_MAP[variant], PROGRESS_CIRCLE_SIZE_TO_CSS_MAP[size], className),
|
|
148
132
|
style: {
|
|
149
133
|
...variables,
|
|
150
134
|
...style
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calls `onEndReached` when the end of a growing list comes within reach, for infinite scrolling.
|
|
3
|
+
* The caller renders a zero-size sentinel after its last item and attaches the returned ref; the
|
|
4
|
+
* hook observes it with an `IntersectionObserver` whose bottom margin is `marginPx`.
|
|
5
|
+
*
|
|
6
|
+
* The sentinel is zero-height on purpose: a 1px sentinel inside a scroll container makes it
|
|
7
|
+
* overflow by a pixel, which traps the wheel at the end of the list (AGENTS.md "Scrolling is the
|
|
8
|
+
* browser's"). Render it as `<div ref={ref} />` with no size of its own.
|
|
9
|
+
*
|
|
10
|
+
* The root is `scrollRef` when that element overflows, otherwise the viewport, so a list in an
|
|
11
|
+
* unbounded parent pages on page scroll. It is armed only while `isEnabled` (pause it while a page
|
|
12
|
+
* loads or after an error), re-armed when `itemCount` changes, and calls `onEndReached` at most
|
|
13
|
+
* once per `itemCount`: a list with no next page adds no items, so it is not called again. Without
|
|
14
|
+
* `IntersectionObserver` it falls back to a passive `scroll` listener. Nothing runs at module scope.
|
|
15
|
+
*
|
|
16
|
+
* The tables (InfiniteTable, VirtualizedInfiniteTable, InfiniteSpreadsheet) page through it; use it
|
|
17
|
+
* for an app list that is not a table.
|
|
18
|
+
*/
|
|
19
|
+
import { type RefObject } from "react";
|
|
20
|
+
/** Options for `useEndReached`. */
|
|
21
|
+
export interface UseEndReachedOptions {
|
|
22
|
+
/** Called when the end comes within reach; `undefined` observes nothing (no next page to load). */
|
|
23
|
+
onEndReached: (() => void) | undefined;
|
|
24
|
+
/** `false` while a page loads or after an error: paging pauses until it is `true` again. */
|
|
25
|
+
isEnabled: boolean;
|
|
26
|
+
/** Items loaded so far. A change re-arms the observer; the callback fires at most once per count. */
|
|
27
|
+
itemCount: number;
|
|
28
|
+
/**
|
|
29
|
+
* The list's own scroll container. Omitted (or not overflowing), the viewport is the root.
|
|
30
|
+
* @default the viewport
|
|
31
|
+
*/
|
|
32
|
+
scrollRef?: RefObject<HTMLElement | null>;
|
|
33
|
+
/**
|
|
34
|
+
* How far below the visible area the end counts as reached, in px.
|
|
35
|
+
* @default 500
|
|
36
|
+
*/
|
|
37
|
+
marginPx?: number;
|
|
38
|
+
}
|
|
39
|
+
/** Observes a zero-size sentinel after the last item and calls `onEndReached`; returns the sentinel's ref. */
|
|
40
|
+
export declare function useEndReached<TElement extends Element = HTMLDivElement>({ onEndReached, isEnabled, itemCount, scrollRef, marginPx, }: UseEndReachedOptions): RefObject<TElement | null>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
//#region src/hooks/useEndReached.ts
|
|
3
|
+
/**
|
|
4
|
+
* Calls `onEndReached` when the end of a growing list comes within reach, for infinite scrolling.
|
|
5
|
+
* The caller renders a zero-size sentinel after its last item and attaches the returned ref; the
|
|
6
|
+
* hook observes it with an `IntersectionObserver` whose bottom margin is `marginPx`.
|
|
7
|
+
*
|
|
8
|
+
* The sentinel is zero-height on purpose: a 1px sentinel inside a scroll container makes it
|
|
9
|
+
* overflow by a pixel, which traps the wheel at the end of the list (AGENTS.md "Scrolling is the
|
|
10
|
+
* browser's"). Render it as `<div ref={ref} />` with no size of its own.
|
|
11
|
+
*
|
|
12
|
+
* The root is `scrollRef` when that element overflows, otherwise the viewport, so a list in an
|
|
13
|
+
* unbounded parent pages on page scroll. It is armed only while `isEnabled` (pause it while a page
|
|
14
|
+
* loads or after an error), re-armed when `itemCount` changes, and calls `onEndReached` at most
|
|
15
|
+
* once per `itemCount`: a list with no next page adds no items, so it is not called again. Without
|
|
16
|
+
* `IntersectionObserver` it falls back to a passive `scroll` listener. Nothing runs at module scope.
|
|
17
|
+
*
|
|
18
|
+
* The tables (InfiniteTable, VirtualizedInfiniteTable, InfiniteSpreadsheet) page through it; use it
|
|
19
|
+
* for an app list that is not a table.
|
|
20
|
+
*/
|
|
21
|
+
/** How far below the visible area the end counts as reached by default: the tables' 500px. */
|
|
22
|
+
var DEFAULT_MARGIN_PX = 500;
|
|
23
|
+
/** Observes a zero-size sentinel after the last item and calls `onEndReached`; returns the sentinel's ref. */
|
|
24
|
+
function useEndReached({ onEndReached, isEnabled, itemCount, scrollRef, marginPx = DEFAULT_MARGIN_PX }) {
|
|
25
|
+
const sentinelRef = useRef(null);
|
|
26
|
+
const onEndReachedRef = useRef(onEndReached);
|
|
27
|
+
onEndReachedRef.current = onEndReached;
|
|
28
|
+
const calledForCountRef = useRef(null);
|
|
29
|
+
const hasHandler = onEndReached !== void 0;
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const scroll = scrollRef?.current ?? null;
|
|
32
|
+
const sentinel = sentinelRef.current;
|
|
33
|
+
if (!hasHandler || !isEnabled || sentinel === null) return;
|
|
34
|
+
if (calledForCountRef.current === itemCount) return;
|
|
35
|
+
const reach = () => {
|
|
36
|
+
if (calledForCountRef.current === itemCount) return;
|
|
37
|
+
calledForCountRef.current = itemCount;
|
|
38
|
+
onEndReachedRef.current?.();
|
|
39
|
+
};
|
|
40
|
+
const scrollRoot = scroll !== null && scroll.scrollHeight > scroll.clientHeight ? scroll : null;
|
|
41
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
42
|
+
const target = scrollRoot ?? window;
|
|
43
|
+
const check = () => {
|
|
44
|
+
const bottom = scrollRoot?.getBoundingClientRect().bottom ?? window.innerHeight;
|
|
45
|
+
if (sentinel.getBoundingClientRect().top - bottom < marginPx) reach();
|
|
46
|
+
};
|
|
47
|
+
check();
|
|
48
|
+
target.addEventListener("scroll", check, { passive: true });
|
|
49
|
+
return () => target.removeEventListener("scroll", check);
|
|
50
|
+
}
|
|
51
|
+
const observer = new IntersectionObserver((entries) => {
|
|
52
|
+
if (entries.some((entry) => entry.isIntersecting)) reach();
|
|
53
|
+
}, {
|
|
54
|
+
root: scrollRoot,
|
|
55
|
+
rootMargin: `0px 0px ${marginPx}px 0px`
|
|
56
|
+
});
|
|
57
|
+
observer.observe(sentinel);
|
|
58
|
+
return () => observer.disconnect();
|
|
59
|
+
}, [
|
|
60
|
+
scrollRef,
|
|
61
|
+
hasHandler,
|
|
62
|
+
isEnabled,
|
|
63
|
+
itemCount,
|
|
64
|
+
marginPx
|
|
65
|
+
]);
|
|
66
|
+
return sentinelRef;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { useEndReached };
|