@galaxy-io/dls 2.6.2 → 2.8.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/dist/charts/BarChart.js +1 -1
- package/dist/charts/BigNumber.d.ts +66 -0
- package/dist/charts/{StatChart.js → BigNumber.js} +57 -20
- package/dist/charts/BigNumberGroup.d.ts +51 -0
- package/dist/charts/BigNumberGroup.js +112 -0
- package/dist/charts/ChartCategoryTargets.js +1 -1
- package/dist/charts/ChartFrame.js +14 -15
- package/dist/charts/ChartPrimitives.d.ts +5 -0
- package/dist/charts/ChartPrimitives.js +22 -17
- package/dist/charts/Heatmap.js +2 -2
- package/dist/charts/LineChart.js +1 -1
- package/dist/charts/PieChart.js +10 -4
- package/dist/charts/Sparkline.js +1 -1
- package/dist/charts/types.d.ts +1 -1
- package/dist/charts/useChartInteraction.js +0 -2
- package/dist/drawer/Drawer.d.ts +12 -0
- package/dist/drawer/Drawer.js +28 -9
- package/dist/inputs/PasswordInput.d.ts +1 -1
- package/dist/layout/ResizablePanels.d.ts +5 -0
- package/dist/layout/ResizablePanels.js +34 -4
- package/dist/lists/DescriptionList.d.ts +10 -0
- package/dist/lists/DescriptionList.js +40 -9
- package/dist/modal/Modal.d.ts +12 -0
- package/dist/modal/Modal.js +26 -6
- package/dist/navigation/Tabs.d.ts +7 -1
- package/dist/navigation/Tabs.js +15 -7
- package/dist/styles.css +1 -1
- package/package.json +9 -5
- package/dist/charts/StatChart.d.ts +0 -48
package/dist/drawer/Drawer.d.ts
CHANGED
|
@@ -23,6 +23,18 @@ interface DrawerBaseProps extends AriaAttributes {
|
|
|
23
23
|
footer?: ReactNode;
|
|
24
24
|
/** Controls in the title row, before the close button, for the thing the drawer shows: one or two icon-only `TERTIARY` `SMALL` buttons and a ⋯ `Menu` for the rest. Not for Save or Cancel (those are `footer`). */
|
|
25
25
|
actions?: ReactNode;
|
|
26
|
+
/** A strip between the title row and the body that stays in place while the body scrolls: an `Alert isBanner`. */
|
|
27
|
+
banner?: ReactNode;
|
|
28
|
+
/**
|
|
29
|
+
* Hairlines between the title row and the body, and between the body and the footer. For a body that scrolls.
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
hasDividers?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* No body padding: the app owns it (sections of `Box padding={16}` and `Divider`s, a table edge to edge). The title row and footer keep theirs.
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
isFlush?: boolean;
|
|
26
38
|
/**
|
|
27
39
|
* The edge the drawer sits on and slides from.
|
|
28
40
|
* @default Side.RIGHT
|
package/dist/drawer/Drawer.js
CHANGED
|
@@ -6,6 +6,7 @@ import { useControlledOpenState } from "../hooks/useControlledOpenState.js";
|
|
|
6
6
|
import Portal from "../layout/Portal.js";
|
|
7
7
|
import { OverlayLayer, useOverlay } from "../overlay/useOverlay.js";
|
|
8
8
|
import { usePrefersReducedMotion } from "../hooks/usePrefersReducedMotion.js";
|
|
9
|
+
import Divider from "../layout/Divider.js";
|
|
9
10
|
import { OVERLAY_CONTENT_SHOWN, withContentFirstExit } from "../overlay/internal/contentFirstExit.js";
|
|
10
11
|
import { OverlayNode } from "../overlay/OverlayProvider.js";
|
|
11
12
|
import Button, { ButtonSize, ButtonVariant } from "../buttons/Button.js";
|
|
@@ -32,6 +33,11 @@ import { AnimatePresence, motion } from "framer-motion";
|
|
|
32
33
|
* link) and a ⋯ `Menu` for the rest (rename, duplicate, delete). `footer` finishes the drawer's
|
|
33
34
|
* task (Cancel, then the `PRIMARY` Save); a read-only detail drawer usually has no footer.
|
|
34
35
|
*
|
|
36
|
+
* The regions are plain by default, as in `Modal`. `hasDividers` draws a hairline between the
|
|
37
|
+
* title row and the body and between the body and the footer. `isFlush` drops the body's padding
|
|
38
|
+
* so the app owns it. `banner` is a slot between the title row and the body that stays put while
|
|
39
|
+
* the body scrolls, for an `Alert isBanner`.
|
|
40
|
+
*
|
|
35
41
|
* By default it is modal, like `Modal`: a portal over a dimmed, locked page with a focus trap,
|
|
36
42
|
* stacked through the overlay stack, closing on Escape or a backdrop click. With
|
|
37
43
|
* `isModal={false}` it is a docked panel: it renders in place in the layout and pushes the content
|
|
@@ -186,14 +192,22 @@ var Body = /*#__PURE__*/ styled("div")({
|
|
|
186
192
|
class: "gx-Drawer-Body-b45j7yl",
|
|
187
193
|
propsAsIs: false
|
|
188
194
|
});
|
|
195
|
+
/** `isFlush`: the body has no inset; the content pads itself. */
|
|
196
|
+
var FLUSH_BODY_CSS = "gx-Drawer-FLUSH_BODY_CSS-fov58xm";
|
|
197
|
+
/** `banner`: a strip pinned between the title row and the body; it never shrinks or scrolls. */
|
|
198
|
+
var Banner = /*#__PURE__*/ styled("div")({
|
|
199
|
+
name: "Banner",
|
|
200
|
+
class: "gx-Drawer-Banner-bckczr5",
|
|
201
|
+
propsAsIs: false
|
|
202
|
+
});
|
|
189
203
|
var Footer = /*#__PURE__*/ styled("div")({
|
|
190
204
|
name: "Footer",
|
|
191
|
-
class: "gx-Drawer-Footer-
|
|
205
|
+
class: "gx-Drawer-Footer-f1v64nx4",
|
|
192
206
|
propsAsIs: false
|
|
193
207
|
});
|
|
194
208
|
var CloseSlot = /*#__PURE__*/ styled("span")({
|
|
195
209
|
name: "CloseSlot",
|
|
196
|
-
class: "gx-Drawer-CloseSlot-
|
|
210
|
+
class: "gx-Drawer-CloseSlot-ct6k1c3",
|
|
197
211
|
propsAsIs: false
|
|
198
212
|
});
|
|
199
213
|
/**
|
|
@@ -202,17 +216,17 @@ var CloseSlot = /*#__PURE__*/ styled("span")({
|
|
|
202
216
|
* the stylesheet.
|
|
203
217
|
*/
|
|
204
218
|
var DRAWER_SIDE_TO_HANDLE_CSS_MAP = {
|
|
205
|
-
[Side.RIGHT]: "gx-Drawer-Side_RIGHT-
|
|
206
|
-
[Side.LEFT]: "gx-Drawer-Side_LEFT-
|
|
207
|
-
[Side.TOP]: "gx-Drawer-Side_TOP-
|
|
208
|
-
[Side.BOTTOM]: "gx-Drawer-Side_BOTTOM-
|
|
219
|
+
[Side.RIGHT]: "gx-Drawer-Side_RIGHT-s15lcrsa",
|
|
220
|
+
[Side.LEFT]: "gx-Drawer-Side_LEFT-s1ob4oh8",
|
|
221
|
+
[Side.TOP]: "gx-Drawer-Side_TOP-s14nwavk",
|
|
222
|
+
[Side.BOTTOM]: "gx-Drawer-Side_BOTTOM-s1ifjfam"
|
|
209
223
|
};
|
|
210
224
|
/** The viewport length on the side's axis, less the 48px strip. */
|
|
211
225
|
function readMaxSize(side) {
|
|
212
226
|
return (DRAWER_SIDE_TO_IS_HORIZONTAL_MAP[side] ? window.innerWidth : window.innerHeight) - DRAWER_VIEWPORT_GAP_PX;
|
|
213
227
|
}
|
|
214
228
|
/** A panel that slides in from an edge: title row, scrolling body, actions row. */
|
|
215
|
-
var Drawer = forwardRef(function Drawer({ children, header, subheader, icon, footer, actions, side = Side.RIGHT, size = "MEDIUM", isResizable = false, isModal = true, isDismissable = true, isOpen: isOpenProp, defaultIsOpen = false, onOpenChange, ariaLabel, id, className, style, ...rest }, ref) {
|
|
229
|
+
var Drawer = forwardRef(function Drawer({ children, header, subheader, icon, footer, actions, banner, hasDividers = false, isFlush = false, side = Side.RIGHT, size = "MEDIUM", isResizable = false, isModal = true, isDismissable = true, isOpen: isOpenProp, defaultIsOpen = false, onOpenChange, ariaLabel, id, className, style, ...rest }, ref) {
|
|
216
230
|
const generatedId = useId();
|
|
217
231
|
const titleId = useId();
|
|
218
232
|
const subheaderId = useId();
|
|
@@ -283,8 +297,13 @@ var Drawer = forwardRef(function Drawer({ children, header, subheader, icon, foo
|
|
|
283
297
|
subheaderId,
|
|
284
298
|
hasClose: isDismissable
|
|
285
299
|
}),
|
|
286
|
-
|
|
287
|
-
|
|
300
|
+
hasDividers && hasHeaderRow && /* @__PURE__ */ jsx(Divider, {}),
|
|
301
|
+
banner !== void 0 && /* @__PURE__ */ jsx(Banner, { children: banner }),
|
|
302
|
+
/* @__PURE__ */ jsx(Body, {
|
|
303
|
+
className: cx(isFlush && FLUSH_BODY_CSS),
|
|
304
|
+
children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx(Text, { children }) : children
|
|
305
|
+
}),
|
|
306
|
+
footer !== void 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [hasDividers && /* @__PURE__ */ jsx(Divider, {}), /* @__PURE__ */ jsx(Footer, { children: footer })] }),
|
|
288
307
|
isResizable && /* @__PURE__ */ jsx(ResizeHandle, {
|
|
289
308
|
orientation: DRAWER_SIDE_TO_HANDLE_ORIENTATION_MAP[side],
|
|
290
309
|
isReversed: DRAWER_SIDE_TO_IS_HANDLE_REVERSED_MAP[side],
|
|
@@ -8,7 +8,7 @@ export type PasswordInputProps = Omit<InputProps, "type" | "trailing" | "isClear
|
|
|
8
8
|
autoComplete?: InputProps["autoComplete"];
|
|
9
9
|
};
|
|
10
10
|
/** A masked single-line field with a "Show password" toggle: `Input` with `type="password"`. */
|
|
11
|
-
declare const PasswordInput: import("react").ForwardRefExoticComponent<Omit<InputProps, "type" | "spellCheck" | "prefix" | "inputMode" | "trailing" | "
|
|
11
|
+
declare const PasswordInput: import("react").ForwardRefExoticComponent<Omit<InputProps, "type" | "spellCheck" | "prefix" | "inputMode" | "trailing" | "suffix" | "autoComplete" | "isClearable"> & {
|
|
12
12
|
/**
|
|
13
13
|
* Password-manager hint. Use `"new-password"` on sign-up and change-password forms.
|
|
14
14
|
* @default "current-password"
|
|
@@ -10,6 +10,11 @@ export interface ResizablePanelsProps extends AriaAttributes {
|
|
|
10
10
|
orientation?: Orientation;
|
|
11
11
|
/** Persists each uncontrolled panel's size in `localStorage` under this key, by panel `id`. Off when omitted. */
|
|
12
12
|
storageKey?: string;
|
|
13
|
+
/**
|
|
14
|
+
* A hairline on the edge where two panels meet: a sized panel's edge facing its handle, so the handle's strip lies just inside the fluid panel.
|
|
15
|
+
* @default false
|
|
16
|
+
*/
|
|
17
|
+
hasDividers?: boolean;
|
|
13
18
|
/** DOM id on the root `<div>`. */
|
|
14
19
|
id?: string;
|
|
15
20
|
/** Any `data-*` attribute, forwarded to the root `<div>`. */
|
|
@@ -20,6 +20,11 @@ import { useMergeRefs } from "@floating-ui/react";
|
|
|
20
20
|
* Pass `ResizablePanel`s as direct children (Fragments are not flattened); `null` / `false`
|
|
21
21
|
* children are skipped, so a panel can be shown conditionally. A panel with neither `value` nor
|
|
22
22
|
* `defaultValue` is the fluid one; with none, the last panel is.
|
|
23
|
+
*
|
|
24
|
+
* The panels have no frame of their own. `hasDividers` draws a hairline on the edge where two
|
|
25
|
+
* panels meet: on a sized panel's edge that faces its handle (so the line sits on the sidebar's
|
|
26
|
+
* edge and the handle's strip lies just inside the fluid panel), and on the later panel's start
|
|
27
|
+
* edge where two panels meet without a handle.
|
|
23
28
|
*/
|
|
24
29
|
var ResizablePanelsContext = createContext(null);
|
|
25
30
|
/** The storage key while `storageKey` is unset; it lives in a per-instance memory adapter. */
|
|
@@ -68,6 +73,15 @@ var RESIZABLE_PANEL_ORIENTATION_TO_CSS_MAP = {
|
|
|
68
73
|
var SIZED_CSS = "gx-ResizablePanels-SIZED_CSS-s16ojr42";
|
|
69
74
|
/** The fluid panel takes the remaining space. */
|
|
70
75
|
var FLUID_CSS = "gx-ResizablePanels-FLUID_CSS-f1k6jei3";
|
|
76
|
+
/** `hasDividers`: the hairline on a panel's start or end edge along the layout axis. */
|
|
77
|
+
var RESIZABLE_PANEL_ORIENTATION_TO_START_DIVIDER_CSS_MAP = {
|
|
78
|
+
[Orientation.HORIZONTAL]: "gx-ResizablePanels-Orientation_HORIZONTAL-o1ikvfoe",
|
|
79
|
+
[Orientation.VERTICAL]: "gx-ResizablePanels-Orientation_VERTICAL-oa3x64k"
|
|
80
|
+
};
|
|
81
|
+
var RESIZABLE_PANEL_ORIENTATION_TO_END_DIVIDER_CSS_MAP = {
|
|
82
|
+
[Orientation.HORIZONTAL]: "gx-ResizablePanels-Orientation_HORIZONTAL-o1kf7v08",
|
|
83
|
+
[Orientation.VERTICAL]: "gx-ResizablePanels-Orientation_VERTICAL-o12hjusf"
|
|
84
|
+
};
|
|
71
85
|
/** Rounds and keeps `value` within `[min, max]`. */
|
|
72
86
|
function clamp(value, min, max) {
|
|
73
87
|
return Math.min(Math.max(Math.round(value), min), max);
|
|
@@ -76,7 +90,7 @@ function isPanelElement(node) {
|
|
|
76
90
|
return isValidElement(node) && node.type === ResizablePanel;
|
|
77
91
|
}
|
|
78
92
|
/** A split layout of `ResizablePanel`s with a `ResizeHandle` between each sized–fluid pair. */
|
|
79
|
-
var ResizablePanels = forwardRef(function ResizablePanels({ children, orientation = Orientation.HORIZONTAL, storageKey, className, style, ...rest }, ref) {
|
|
93
|
+
var ResizablePanels = forwardRef(function ResizablePanels({ children, orientation = Orientation.HORIZONTAL, storageKey, hasDividers = false, className, style, ...rest }, ref) {
|
|
80
94
|
const rootRef = useRef(null);
|
|
81
95
|
const mergedRef = useMergeRefs([rootRef, ref]);
|
|
82
96
|
const rootSize = useElementClientSize(rootRef);
|
|
@@ -130,10 +144,26 @@ var ResizablePanels = forwardRef(function ResizablePanels({ children, orientatio
|
|
|
130
144
|
}
|
|
131
145
|
return Math.max(target.min, Math.min(target.max, Math.floor(room)));
|
|
132
146
|
};
|
|
133
|
-
const
|
|
147
|
+
const dividerEdges = panels.map(() => ({
|
|
148
|
+
start: false,
|
|
149
|
+
end: false
|
|
150
|
+
}));
|
|
151
|
+
if (hasDividers) handleTargets.forEach((targetIndex, index) => {
|
|
152
|
+
if (index === 0) return;
|
|
153
|
+
if (targetIndex === void 0) {
|
|
154
|
+
const edges = dividerEdges[index];
|
|
155
|
+
if (edges !== void 0) edges.start = true;
|
|
156
|
+
} else {
|
|
157
|
+
const edges = dividerEdges[targetIndex];
|
|
158
|
+
if (edges !== void 0) edges[targetIndex === index ? "start" : "end"] = true;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
const layoutById = new Map(panels.map((panel, index) => [panel.props.id, {
|
|
134
162
|
size: panel.isFluid ? void 0 : sizeOf(panel),
|
|
135
163
|
min: panel.min,
|
|
136
|
-
isFluid: panel.isFluid
|
|
164
|
+
isFluid: panel.isFluid,
|
|
165
|
+
hasStartDivider: dividerEdges[index]?.start ?? false,
|
|
166
|
+
hasEndDivider: dividerEdges[index]?.end ?? false
|
|
137
167
|
}]));
|
|
138
168
|
const contextValue = {
|
|
139
169
|
orientation,
|
|
@@ -185,7 +215,7 @@ var ResizablePanel = forwardRef(function ResizablePanel({ id, children, value: _
|
|
|
185
215
|
id,
|
|
186
216
|
role: name ? "region" : void 0,
|
|
187
217
|
"aria-label": name,
|
|
188
|
-
className: cx(RESIZABLE_PANEL_ORIENTATION_TO_CSS_MAP[orientation], isFluid ? FLUID_CSS : SIZED_CSS, className),
|
|
218
|
+
className: cx(RESIZABLE_PANEL_ORIENTATION_TO_CSS_MAP[orientation], isFluid ? FLUID_CSS : SIZED_CSS, layout?.hasStartDivider && RESIZABLE_PANEL_ORIENTATION_TO_START_DIVIDER_CSS_MAP[orientation], layout?.hasEndDivider && RESIZABLE_PANEL_ORIENTATION_TO_END_DIVIDER_CSS_MAP[orientation], className),
|
|
189
219
|
style: {
|
|
190
220
|
...style,
|
|
191
221
|
...variables
|
|
@@ -83,6 +83,16 @@ export interface DescriptionListProps extends AriaAttributes {
|
|
|
83
83
|
* @default false
|
|
84
84
|
*/
|
|
85
85
|
isValueTrailing?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* A hairline between rows, with 8px (`HORIZONTAL`) or 12px (`VERTICAL`) above and below it; none above the first row or below the last.
|
|
88
|
+
* @default false
|
|
89
|
+
*/
|
|
90
|
+
hasDividers?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* A hairline frame with `lg` corners around the list, 16px from the first label and the last value, with a line between rows inside it (implies `hasDividers`) and 12px above and below every row: the detail card.
|
|
93
|
+
* @default false
|
|
94
|
+
*/
|
|
95
|
+
hasBorder?: boolean;
|
|
86
96
|
/** DOM id on the root `<dl>`. */
|
|
87
97
|
id?: string;
|
|
88
98
|
/** Any `data-*` attribute, forwarded to the root `<dl>`. */
|
|
@@ -19,6 +19,11 @@ import { cx } from "@linaria/core";
|
|
|
19
19
|
* by side. Rows take the copy button's height when any item is copyable, so the list keeps one
|
|
20
20
|
* rhythm.
|
|
21
21
|
*
|
|
22
|
+
* `hasDividers` draws a hairline under every row but the last (never above the first) and
|
|
23
|
+
* moves the grid gaps onto the cells so the line is continuous across the label and value tracks.
|
|
24
|
+
* `hasBorder` frames the list with a hairline and `lg` corners, pads the rows' outer edges (so the
|
|
25
|
+
* lines reach the frame) and implies `hasDividers`: the detail card.
|
|
26
|
+
*
|
|
22
27
|
* Read-only: editing is a form (`Field` + inputs); a list of plain lines is `BulletedList`.
|
|
23
28
|
*/
|
|
24
29
|
/** Type step of labels and values; canonical rungs `SMALL MEDIUM LARGE`. */
|
|
@@ -68,17 +73,42 @@ var DESCRIPTION_LIST_ORIENTATION_TO_CSS_MAP = {
|
|
|
68
73
|
[Orientation.HORIZONTAL]: "gx-DescriptionList-Orientation_HORIZONTAL-oarm5a8",
|
|
69
74
|
[Orientation.VERTICAL]: "gx-DescriptionList-Orientation_VERTICAL-o1itek1z"
|
|
70
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* `hasDividers`: the grid gaps become cell padding (`--gx-dl-col-gap` at the end of every item
|
|
78
|
+
* but the last in its row, `--gx-dl-row-pad` above and below every row boundary) and the rows
|
|
79
|
+
* after the first draw a hairline on their top edge. Which items start or end a row depends on
|
|
80
|
+
* `columns`, so the per-row custom properties are set in the columns map and read here. In
|
|
81
|
+
* `HORIZONTAL` the item leaves `display: contents` for a subgrid over its two tracks, so it is a
|
|
82
|
+
* box that can carry the border and padding while its label stays in the shared label track.
|
|
83
|
+
*/
|
|
84
|
+
var DIVIDERS_CSS = "gx-DescriptionList-DIVIDERS_CSS-d19oquh";
|
|
85
|
+
var DESCRIPTION_LIST_DIVIDERS_ORIENTATION_TO_CSS_MAP = {
|
|
86
|
+
[Orientation.HORIZONTAL]: "gx-DescriptionList-Orientation_HORIZONTAL-o108p3ql",
|
|
87
|
+
[Orientation.VERTICAL]: "gx-DescriptionList-Orientation_VERTICAL-o10x7q9y"
|
|
88
|
+
};
|
|
89
|
+
var DESCRIPTION_LIST_DIVIDERS_COLUMNS_TO_CSS_MAP = {
|
|
90
|
+
1: "gx-DescriptionList-1-_1g4xmgd",
|
|
91
|
+
2: "gx-DescriptionList-2-_1s7hmki",
|
|
92
|
+
3: "gx-DescriptionList-3-_1t8g3vn",
|
|
93
|
+
4: "gx-DescriptionList-4-_1k8wc0x"
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* `hasBorder`: a hairline frame with `lg` corners; the first and last columns pad 16 from it, every
|
|
97
|
+
* row pads 12 above and below (the outer rows through the edge fallbacks the cells read), and the
|
|
98
|
+
* `hasDividers` blocks draw the lines. Declared after the orientation map so its row pad wins.
|
|
99
|
+
*/
|
|
100
|
+
var BORDER_CSS = "gx-DescriptionList-BORDER_CSS-b6xkh13";
|
|
71
101
|
var DESCRIPTION_LIST_COLUMNS_TO_CSS_MAP = {
|
|
72
|
-
1: "gx-DescriptionList-1-
|
|
73
|
-
2: "gx-DescriptionList-2-
|
|
74
|
-
3: "gx-DescriptionList-3-
|
|
75
|
-
4: "gx-DescriptionList-4-
|
|
102
|
+
1: "gx-DescriptionList-1-_x7vzfq",
|
|
103
|
+
2: "gx-DescriptionList-2-_1wbhzfx",
|
|
104
|
+
3: "gx-DescriptionList-3-_6u7lmt",
|
|
105
|
+
4: "gx-DescriptionList-4-_10jrxrj"
|
|
76
106
|
};
|
|
77
107
|
/** Applied only when some item is copyable: every row is as tall as a row with a copy button. */
|
|
78
108
|
var DESCRIPTION_LIST_SIZE_TO_ROW_CSS_MAP = {
|
|
79
|
-
["SMALL"]: "gx-DescriptionList-SMALL-
|
|
80
|
-
["MEDIUM"]: "gx-DescriptionList-MEDIUM-
|
|
81
|
-
["LARGE"]: "gx-DescriptionList-LARGE-
|
|
109
|
+
["SMALL"]: "gx-DescriptionList-SMALL-s1xbu6g3",
|
|
110
|
+
["MEDIUM"]: "gx-DescriptionList-MEDIUM-m1okymsl",
|
|
111
|
+
["LARGE"]: "gx-DescriptionList-LARGE-l15jcjvy"
|
|
82
112
|
};
|
|
83
113
|
var DESCRIPTION_LIST_SIZE_TO_TEXT_SIZE_MAP = {
|
|
84
114
|
["SMALL"]: TextSize.BODY_SM,
|
|
@@ -99,9 +129,10 @@ var getCopyText = (item) => {
|
|
|
99
129
|
return isText(item.value) && !isEmpty(item.value) ? String(item.value) : void 0;
|
|
100
130
|
};
|
|
101
131
|
/** Labelled values in a `<dl>`: labels aligned in one column, or above their values. */
|
|
102
|
-
var DescriptionList = forwardRef(function DescriptionList({ items, size = "MEDIUM", orientation = Orientation.HORIZONTAL, columns = 1, isValueTrailing = false, id, className, style, ...rest }, ref) {
|
|
132
|
+
var DescriptionList = forwardRef(function DescriptionList({ items, size = "MEDIUM", orientation = Orientation.HORIZONTAL, columns = 1, isValueTrailing = false, hasDividers = false, hasBorder = false, id, className, style, ...rest }, ref) {
|
|
103
133
|
const textSize = DESCRIPTION_LIST_SIZE_TO_TEXT_SIZE_MAP[size];
|
|
104
134
|
const hasCopy = items.some((item) => item.isCopyable === true);
|
|
135
|
+
const hasLines = hasDividers || hasBorder;
|
|
105
136
|
const entries = items.map((item, position) => ({
|
|
106
137
|
item,
|
|
107
138
|
position
|
|
@@ -110,7 +141,7 @@ var DescriptionList = forwardRef(function DescriptionList({ items, size = "MEDIU
|
|
|
110
141
|
...rest,
|
|
111
142
|
ref,
|
|
112
143
|
id,
|
|
113
|
-
className: cx(DESCRIPTION_LIST_ORIENTATION_TO_CSS_MAP[orientation], DESCRIPTION_LIST_COLUMNS_TO_CSS_MAP[columns], hasCopy && DESCRIPTION_LIST_SIZE_TO_ROW_CSS_MAP[size], isValueTrailing && VALUE_TRAILING_CSS, className),
|
|
144
|
+
className: cx(DESCRIPTION_LIST_ORIENTATION_TO_CSS_MAP[orientation], DESCRIPTION_LIST_COLUMNS_TO_CSS_MAP[columns], hasCopy && DESCRIPTION_LIST_SIZE_TO_ROW_CSS_MAP[size], isValueTrailing && VALUE_TRAILING_CSS, hasLines && DIVIDERS_CSS, hasLines && DESCRIPTION_LIST_DIVIDERS_ORIENTATION_TO_CSS_MAP[orientation], hasLines && DESCRIPTION_LIST_DIVIDERS_COLUMNS_TO_CSS_MAP[columns], hasBorder && BORDER_CSS, className),
|
|
114
145
|
style,
|
|
115
146
|
children: entries.map(({ item, position }) => {
|
|
116
147
|
const copyText = getCopyText(item);
|
package/dist/modal/Modal.d.ts
CHANGED
|
@@ -17,6 +17,18 @@ interface ModalBaseProps extends AriaAttributes {
|
|
|
17
17
|
children?: ReactNode;
|
|
18
18
|
/** The actions row, end-aligned with an 8px gap. Put the least destructive action first. */
|
|
19
19
|
footer?: ReactNode;
|
|
20
|
+
/** A strip between the title row and the body that stays in place while the body scrolls: an `Alert isBanner`. */
|
|
21
|
+
banner?: ReactNode;
|
|
22
|
+
/**
|
|
23
|
+
* Hairlines between the title row and the body, and between the body and the footer. For a body that scrolls.
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
hasDividers?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* No body padding: the app owns it (sections of `Box padding={16}` and `Divider`s, a table edge to edge). The title row and footer keep theirs.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
isFlush?: boolean;
|
|
20
32
|
/**
|
|
21
33
|
* Panel width: 400 / 560 / 720px, or `X_LARGE` to fill the viewport less 32px on each side.
|
|
22
34
|
* @default ModalSize.MEDIUM
|
package/dist/modal/Modal.js
CHANGED
|
@@ -3,6 +3,7 @@ import Text from "../text/Text.js";
|
|
|
3
3
|
import { useControlledOpenState } from "../hooks/useControlledOpenState.js";
|
|
4
4
|
import Portal from "../layout/Portal.js";
|
|
5
5
|
import { OverlayLayer, useOverlay } from "../overlay/useOverlay.js";
|
|
6
|
+
import Divider from "../layout/Divider.js";
|
|
6
7
|
import { OverlayScaleFade } from "../overlay/internal/OverlayScaleFade.js";
|
|
7
8
|
import { OverlayNode } from "../overlay/OverlayProvider.js";
|
|
8
9
|
import Button, { ButtonSize, ButtonVariant } from "../buttons/Button.js";
|
|
@@ -11,7 +12,7 @@ import Fade from "../transform/Fade.js";
|
|
|
11
12
|
/* empty css */
|
|
12
13
|
import { styled } from "@linaria/react";
|
|
13
14
|
import { forwardRef, useId, useRef, useState } from "react";
|
|
14
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
15
16
|
import { cx } from "@linaria/core";
|
|
16
17
|
import { XIcon } from "@phosphor-icons/react";
|
|
17
18
|
//#region src/modal/Modal.tsx
|
|
@@ -23,6 +24,12 @@ import { XIcon } from "@phosphor-icons/react";
|
|
|
23
24
|
* and out (`Fade` backdrop, a scale-fade panel whose content leaves first). It has no trigger: the
|
|
24
25
|
* app opens it.
|
|
25
26
|
*
|
|
27
|
+
* The regions are plain by default. `hasDividers` draws a hairline between the title row and the
|
|
28
|
+
* body and between the body and the footer, for a body that scrolls. `isFlush` drops the body's
|
|
29
|
+
* padding so the app owns it (sections of `Box padding={16}` and `Divider`s, a table edge to
|
|
30
|
+
* edge). `banner` is a slot between the title row and the body that stays put while the body
|
|
31
|
+
* scrolls, for an `Alert isBanner`.
|
|
32
|
+
*
|
|
26
33
|
* A short yes/no question is `ConfirmDialog`; a panel beside the page is `Drawer`; an anchored
|
|
27
34
|
* panel is `Popover`.
|
|
28
35
|
*
|
|
@@ -80,18 +87,26 @@ var Body = /*#__PURE__*/ styled("div")({
|
|
|
80
87
|
class: "gx-Modal-Body-b1w4b032",
|
|
81
88
|
propsAsIs: false
|
|
82
89
|
});
|
|
90
|
+
/** `isFlush`: the body has no inset; the content pads itself. */
|
|
91
|
+
var FLUSH_BODY_CSS = "gx-Modal-FLUSH_BODY_CSS-fbri8ij";
|
|
92
|
+
/** `banner`: a strip pinned between the title row and the body; it never shrinks or scrolls. */
|
|
93
|
+
var Banner = /*#__PURE__*/ styled("div")({
|
|
94
|
+
name: "Banner",
|
|
95
|
+
class: "gx-Modal-Banner-bxdonbm",
|
|
96
|
+
propsAsIs: false
|
|
97
|
+
});
|
|
83
98
|
var Footer = /*#__PURE__*/ styled("div")({
|
|
84
99
|
name: "Footer",
|
|
85
|
-
class: "gx-Modal-Footer-
|
|
100
|
+
class: "gx-Modal-Footer-f1c1q51w",
|
|
86
101
|
propsAsIs: false
|
|
87
102
|
});
|
|
88
103
|
var CloseSlot = /*#__PURE__*/ styled("span")({
|
|
89
104
|
name: "CloseSlot",
|
|
90
|
-
class: "gx-Modal-CloseSlot-
|
|
105
|
+
class: "gx-Modal-CloseSlot-c1aye683",
|
|
91
106
|
propsAsIs: false
|
|
92
107
|
});
|
|
93
108
|
/** A blocking dialog over a dimmed page: title row, scrolling body, actions row. */
|
|
94
|
-
var Modal = forwardRef(function Modal({ children, header, subheader, icon, footer, size = "MEDIUM", isDismissable = true, isOpen: isOpenProp, defaultIsOpen = false, onOpenChange, ariaLabel, id, className, style, ...rest }, ref) {
|
|
109
|
+
var Modal = forwardRef(function Modal({ children, header, subheader, icon, footer, banner, hasDividers = false, isFlush = false, size = "MEDIUM", isDismissable = true, isOpen: isOpenProp, defaultIsOpen = false, onOpenChange, ariaLabel, id, className, style, ...rest }, ref) {
|
|
95
110
|
const generatedId = useId();
|
|
96
111
|
const titleId = useId();
|
|
97
112
|
const subheaderId = useId();
|
|
@@ -165,8 +180,13 @@ var Modal = forwardRef(function Modal({ children, header, subheader, icon, foote
|
|
|
165
180
|
subheaderId,
|
|
166
181
|
hasClose: isDismissable
|
|
167
182
|
}),
|
|
168
|
-
|
|
169
|
-
|
|
183
|
+
hasDividers && hasHeaderRow && /* @__PURE__ */ jsx(Divider, {}),
|
|
184
|
+
banner !== void 0 && /* @__PURE__ */ jsx(Banner, { children: banner }),
|
|
185
|
+
/* @__PURE__ */ jsx(Body, {
|
|
186
|
+
className: cx(isFlush && FLUSH_BODY_CSS),
|
|
187
|
+
children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx(Text, { children }) : children
|
|
188
|
+
}),
|
|
189
|
+
footer !== void 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [hasDividers && /* @__PURE__ */ jsx(Divider, {}), /* @__PURE__ */ jsx(Footer, { children: footer })] }),
|
|
170
190
|
isDismissable && /* @__PURE__ */ jsx(CloseSlot, { children: /* @__PURE__ */ jsx(Button, {
|
|
171
191
|
variant: ButtonVariant.TERTIARY,
|
|
172
192
|
size: ButtonSize.SMALL,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Icon as PhosphorIcon } from "@phosphor-icons/react";
|
|
2
2
|
import { type AriaAttributes, type CSSProperties, type ElementType, type ReactElement, type ReactNode, type RefAttributes } from "react";
|
|
3
|
-
import { Orientation } from "../theme/enums.js";
|
|
3
|
+
import { Orientation, type Space } from "../theme/enums.js";
|
|
4
4
|
/** Mode (Constitution V-A local mode set: Tabs UNDERLINE / PILL; declared in scripts/lint-dls.ts MODE_SETS). */
|
|
5
5
|
export declare enum TabsVariant {
|
|
6
6
|
/** Tabs on a hairline; the selected tab has a `text.primary` indicator on the edge facing the panel. The default. */
|
|
@@ -81,6 +81,12 @@ export interface TabsProps<TId extends string = string> extends AriaAttributes {
|
|
|
81
81
|
* @default false
|
|
82
82
|
*/
|
|
83
83
|
fillWidth?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Space between the ends of the row (or column) and its first and last tab, `actions` included; the `UNDERLINE` hairline still runs the full length.
|
|
86
|
+
* For a row flush with a panel's edges whose tabs should sit on the page's padding line (`16` in the island), instead of a padded wrapper, which would cut the hairline short.
|
|
87
|
+
* @default 0
|
|
88
|
+
*/
|
|
89
|
+
inset?: Space;
|
|
84
90
|
/** Controls at the end of the tab row (or the bottom of the column), outside the tablist, usually `Button`s one rung smaller. */
|
|
85
91
|
actions?: ReactNode;
|
|
86
92
|
/**
|
package/dist/navigation/Tabs.js
CHANGED
|
@@ -2,6 +2,7 @@ import { useIsomorphicLayoutEffect } from "../hooks/useIsomorphicLayoutEffect.js
|
|
|
2
2
|
import { Orientation, Placement } from "../theme/enums.js";
|
|
3
3
|
import Text, { TextSize, TextVariant, TextWeight } from "../text/Text.js";
|
|
4
4
|
import { useControlledState } from "../hooks/useControlledState.js";
|
|
5
|
+
import { spaceToCss } from "../utils/css.js";
|
|
5
6
|
import Icon, { IconVariant } from "../icons/Icon.js";
|
|
6
7
|
import Chip, { ChipSize, ChipVariant } from "../chips/Chip.js";
|
|
7
8
|
import Menu, { MenuItem, MenuSize } from "../menu/Menu.js";
|
|
@@ -19,7 +20,9 @@ import { CaretDownIcon } from "@phosphor-icons/react";
|
|
|
19
20
|
* navigates. Each tab can show an icon and a count `Chip`. `UNDERLINE` is the page-level mode (a
|
|
20
21
|
* hairline with a `text.primary` indicator under the selected tab); `PILL` is a quieter second level (the
|
|
21
22
|
* selected tab is a filled pill). Horizontal tabs that do not fit collapse into a "More" menu at
|
|
22
|
-
* the end of the row, so the row never wraps or scrolls.
|
|
23
|
+
* the end of the row, so the row never wraps or scrolls. `inset` pads the row (or column) from its
|
|
24
|
+
* ends while the `UNDERLINE` hairline keeps its full length: a row flush with a panel's edges, its
|
|
25
|
+
* tabs on the page's padding line.
|
|
23
26
|
*
|
|
24
27
|
* Height: a horizontal row takes the height it is given. Alone it is its rung tall; stretched by
|
|
25
28
|
* a taller flex row (the default `align-items: stretch`, e.g. a 48px app header) it fills that
|
|
@@ -58,7 +61,7 @@ var TabsSize = /* @__PURE__ */ function(TabsSize) {
|
|
|
58
61
|
}({});
|
|
59
62
|
/** Sub-pixel slack when comparing measured widths. */
|
|
60
63
|
var FIT_EPSILON_PX = .5;
|
|
61
|
-
/** The root block: bar, then panel (a horizontal bar with no panel fills the root's height). */
|
|
64
|
+
/** The root block: bar, then panel (a horizontal bar with no panel fills the root's height). `--gx-tabs-inset` is the `inset` prop. */
|
|
62
65
|
var Root = /*#__PURE__*/ styled("div")({
|
|
63
66
|
name: "Root",
|
|
64
67
|
class: "gx-Tabs-r1fvk33l",
|
|
@@ -114,6 +117,7 @@ var TABS_ORIENTATION_TO_CSS_MAP = {
|
|
|
114
117
|
var FILL_WIDTH_CSS = "gx-Tabs-FILL_WIDTH_CSS-fs6iug3";
|
|
115
118
|
/** Vertical `fillWidth`: a column with no panel beside it spans its parent, so the hairline sits on the parent's edge. */
|
|
116
119
|
var VERTICAL_FILL_WIDTH_CSS = "gx-Tabs-VERTICAL_FILL_WIDTH_CSS-vvxftzj";
|
|
120
|
+
/** The bar's `inset` is padding on the bar itself, so the `UNDERLINE` hairline (drawn on the bar's edge) spans it. */
|
|
117
121
|
var TABS_ORIENTATION_TO_BAR_CSS_MAP = {
|
|
118
122
|
[Orientation.HORIZONTAL]: "gx-Tabs-Orientation_HORIZONTAL-oduyhd6",
|
|
119
123
|
[Orientation.VERTICAL]: "gx-Tabs-Orientation_VERTICAL-oux4b2d"
|
|
@@ -252,7 +256,7 @@ function fitVisibleIndexes(count, selectedIndex, measurement, available) {
|
|
|
252
256
|
}
|
|
253
257
|
/** Tabs and their panel; the value is the selected tab's id. */
|
|
254
258
|
function TabsImpl(props, ref) {
|
|
255
|
-
const { items, value, defaultValue, onChange, variant = "UNDERLINE", size = "MEDIUM", orientation = Orientation.HORIZONTAL, fillWidth = false, actions, as, ariaLabel, id, className, style, ...rest } = props;
|
|
259
|
+
const { items, value, defaultValue, onChange, variant = "UNDERLINE", size = "MEDIUM", orientation = Orientation.HORIZONTAL, fillWidth = false, inset = 0, actions, as, ariaLabel, id, className, style, ...rest } = props;
|
|
256
260
|
const list = items;
|
|
257
261
|
const isLinks = list.some((item) => item.href !== void 0);
|
|
258
262
|
const isHorizontal = orientation === Orientation.HORIZONTAL;
|
|
@@ -281,13 +285,14 @@ function TabsImpl(props, ref) {
|
|
|
281
285
|
const [available, setAvailable] = useState(null);
|
|
282
286
|
const isMeasuring = isOverflowMode && (measurement === null || measurement.signature !== signature);
|
|
283
287
|
const hasActions = actions !== void 0 && actions !== null && actions !== false;
|
|
284
|
-
/** The row's width for tabs and the trigger: the bar minus `actions` and its gap. */
|
|
288
|
+
/** The row's width for tabs and the trigger: the bar minus its `inset` padding, `actions` and its gap. */
|
|
285
289
|
const readAvailable = useCallback(() => {
|
|
286
290
|
const bar = barRef.current;
|
|
287
291
|
if (bar === null) return;
|
|
288
|
-
|
|
292
|
+
const barStyle = getComputedStyle(bar);
|
|
293
|
+
let width = bar.getBoundingClientRect().width - pxOf(barStyle.paddingInlineStart) - pxOf(barStyle.paddingInlineEnd);
|
|
289
294
|
const actionsElement = actionsRef.current;
|
|
290
|
-
if (actionsElement !== null) width -= actionsElement.getBoundingClientRect().width + pxOf(
|
|
295
|
+
if (actionsElement !== null) width -= actionsElement.getBoundingClientRect().width + pxOf(barStyle.columnGap);
|
|
291
296
|
setAvailable((current) => current === width ? current : width);
|
|
292
297
|
}, []);
|
|
293
298
|
useIsomorphicLayoutEffect(() => {
|
|
@@ -472,7 +477,10 @@ function TabsImpl(props, ref) {
|
|
|
472
477
|
return /* @__PURE__ */ jsxs(Root, {
|
|
473
478
|
ref,
|
|
474
479
|
className: cx(TABS_ORIENTATION_TO_CSS_MAP[orientation], fillWidth && (isHorizontal ? FILL_WIDTH_CSS : VERTICAL_FILL_WIDTH_CSS), className),
|
|
475
|
-
style
|
|
480
|
+
style: inset === 0 ? style : {
|
|
481
|
+
...style,
|
|
482
|
+
"--gx-tabs-inset": spaceToCss(inset)
|
|
483
|
+
},
|
|
476
484
|
children: [/* @__PURE__ */ jsxs(Bar, {
|
|
477
485
|
ref: barRef,
|
|
478
486
|
className: cx(TABS_SIZE_TO_CSS_MAP[size], TABS_VARIANT_TO_BAR_CSS_MAP[variant][orientation], TABS_ORIENTATION_TO_BAR_CSS_MAP[orientation]),
|