@rojaostudio/ds 2.0.0-next.30 → 2.0.0-next.31
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/components/form-actions.d.ts +19 -11
- package/dist/components/form-actions.js +32 -2
- package/dist/components/internal/bottom-bar.d.ts +13 -10
- package/dist/components/internal/bottom-bar.js +39 -0
- package/dist/components/internal/icons.d.ts +3 -1
- package/dist/components/internal/icons.js +7 -0
- package/dist/components/saving-bar.d.ts +8 -6
- package/dist/components/saving-bar.js +16 -1
- package/dist/components/toast.d.ts +6 -4
- package/package.json +1 -1
- package/styles/rds/components-styles.css +64 -17
- package/styles/rds/components.css +2 -1
|
@@ -6,19 +6,21 @@ type FormActionsPlacement = BottomBarPlacement;
|
|
|
6
6
|
interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
7
|
/**
|
|
8
8
|
* The actions (Figma: the exposed `cancel` and `primary` Buttons), in reading order: Cancelar (tone neutral, ghost)
|
|
9
|
-
* first, the primary (tone action, fill) last. Expanded (from 1024) they all show, on the right
|
|
10
|
-
* 1024)
|
|
9
|
+
* first, the primary (tone action, fill) last. Expanded (from 1024) they all show, on the right, 8 apart. Compact
|
|
10
|
+
* (below 1024) the first one, Cancelar, becomes an IconButton with the X (tone neutral, ghost, md), named by its
|
|
11
|
+
* label and with its Tooltip, beside the primary: leading, X, primary. Any action between the two is `display: none` in compact.
|
|
11
12
|
*/
|
|
12
13
|
children: ReactNode;
|
|
13
14
|
/**
|
|
14
|
-
* docked (default: the container's width, against the foot) or floating (from 1024 up:
|
|
15
|
-
*
|
|
15
|
+
* docked (default: the container's width, against the foot) or floating (from 1024 up: in the bottom right corner,
|
|
16
|
+
* 24 off the foot and the right, hugging its content, rounded, the overlay shadow). Below 1024 floating is docked
|
|
17
|
+
* (Figma: `placement`).
|
|
16
18
|
*/
|
|
17
19
|
placement?: FormActionsPlacement;
|
|
18
20
|
/**
|
|
19
|
-
* One ~44 control on the left, never running text (Figma: slot `leading`, `showLeading`).
|
|
20
|
-
* while its control is hidden, it reserves 44 so the actions do not jump. Whoever fills it says its own
|
|
21
|
-
* (its own aria-live); the bar says nothing.
|
|
21
|
+
* One ~44 control on the left, never running text (Figma: slot `leading`, `showLeading`). Left out, no slot. Present,
|
|
22
|
+
* even `null` while its control is hidden, it reserves 44 so the actions do not jump. Whoever fills it says its own
|
|
23
|
+
* changes (its own aria-live); the bar says nothing.
|
|
22
24
|
*/
|
|
23
25
|
leading?: ReactNode;
|
|
24
26
|
}
|
|
@@ -29,8 +31,14 @@ interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
29
31
|
* shell: a band in the brand's primary colour (bottom-bar/background), 64 plus the safe area compact, 68 expanded,
|
|
30
32
|
* 24 at the sides, sticky at the bottom of the scrolling container. Styles: form-actions.css, internal/bottom-bar.css.
|
|
31
33
|
*
|
|
32
|
-
* `<FormActions placement="docked" leading={…}><Button tone="neutral" variant="ghost">Cancelar
|
|
33
|
-
* tone="action">Criar produto</Button></FormActions>`: the last child is the primary
|
|
34
|
+
* `<FormActions placement="docked" leading={…}><Button tone="neutral" variant="ghost" onClick={cancel}>Cancelar
|
|
35
|
+
* </Button><Button tone="action">Criar produto</Button></FormActions>`: the last child is the primary, the first
|
|
36
|
+
* (when there are two or more) is Cancelar.
|
|
37
|
+
*
|
|
38
|
+
* Compact, Cancelar is drawn as the X: an IconButton built from the first child's props, so give that child its
|
|
39
|
+
* label as text (or `aria-label`), its `onClick` and, if it has one, `disabled`. The X's `aria-label` is that label.
|
|
40
|
+
* With more than two children, the ones between Cancelar and the primary are not shown in compact (`display: none`):
|
|
41
|
+
* put them somewhere else on the phone, or keep two.
|
|
34
42
|
*
|
|
35
43
|
* The app's rules around it:
|
|
36
44
|
* - The primary is never disabled: validate on click, show the error on the field and move the focus to the first
|
|
@@ -41,8 +49,8 @@ interface FormActionsProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
41
49
|
* - On the phone (below 1024) the bar leaves while the on-screen keyboard is open (a field is focused and the visible
|
|
42
50
|
* area shrinks): it slides down (no motion with prefers-reduced-motion) and comes back on blur; it never takes the
|
|
43
51
|
* focus.
|
|
44
|
-
* -
|
|
45
|
-
* editando] [Sair sem criar])
|
|
52
|
+
* - Leaving with something typed (Cancelar or the X) asks first, with an AlertDialog "Sair sem criar?" ([Continuar
|
|
53
|
+
* editando] [Sair sem criar]).
|
|
46
54
|
* - Buttons at the end of a card or a dialog are loose Buttons or a ButtonGroup, not this.
|
|
47
55
|
*/
|
|
48
56
|
declare function FormActions({ children, placement, leading, className, ...rest }: FormActionsProps): react.JSX.Element;
|
|
@@ -4,11 +4,41 @@ import {
|
|
|
4
4
|
__spreadProps,
|
|
5
5
|
__spreadValues
|
|
6
6
|
} from "../chunk-ORMEWXMH.js";
|
|
7
|
-
import { jsx } from "react/jsx-runtime";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { Children, isValidElement } from "react";
|
|
9
|
+
import { IconButton } from "./icon-button.js";
|
|
8
10
|
import { BottomBar } from "./internal/bottom-bar.js";
|
|
11
|
+
import { CloseIcon } from "./internal/icons.js";
|
|
12
|
+
import { Tooltip } from "./tooltip.js";
|
|
13
|
+
function textOf(node) {
|
|
14
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
15
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
16
|
+
if (isValidElement(node)) return textOf(node.props.children);
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
9
19
|
function FormActions(_a) {
|
|
10
20
|
var _b = _a, { children, placement = "docked", leading, className } = _b, rest = __objRest(_b, ["children", "placement", "leading", "className"]);
|
|
11
|
-
|
|
21
|
+
const actions = Children.toArray(children);
|
|
22
|
+
const cancel = actions.length > 1 && isValidElement(actions[0]) ? actions[0].props : null;
|
|
23
|
+
const cancelLabel = cancel ? cancel["aria-label"] || textOf(cancel.children) : "";
|
|
24
|
+
const primary = actions[actions.length - 1];
|
|
25
|
+
return /* @__PURE__ */ jsx(BottomBar, __spreadProps(__spreadValues({}, rest), { placement, leading, className: ["rds-form-actions", className].filter(Boolean).join(" "), children: /* @__PURE__ */ jsxs("div", { className: "rds-form-actions__actions", children: [
|
|
26
|
+
actions.slice(0, -1),
|
|
27
|
+
cancel && /* @__PURE__ */ jsx(Tooltip, { text: cancelLabel, children: /* @__PURE__ */ jsx(
|
|
28
|
+
IconButton,
|
|
29
|
+
{
|
|
30
|
+
className: "rds-form-actions__cancel-icon",
|
|
31
|
+
icon: /* @__PURE__ */ jsx(CloseIcon, {}),
|
|
32
|
+
label: cancelLabel,
|
|
33
|
+
tone: "neutral",
|
|
34
|
+
variant: "ghost",
|
|
35
|
+
size: "md",
|
|
36
|
+
disabled: cancel.disabled,
|
|
37
|
+
onClick: cancel.onClick
|
|
38
|
+
}
|
|
39
|
+
) }),
|
|
40
|
+
primary
|
|
41
|
+
] }) }));
|
|
12
42
|
}
|
|
13
43
|
export {
|
|
14
44
|
FormActions
|
|
@@ -4,15 +4,17 @@ import { HTMLAttributes, ReactNode } from 'react';
|
|
|
4
4
|
type BottomBarPlacement = 'docked' | 'floating';
|
|
5
5
|
interface BottomBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
6
|
/**
|
|
7
|
-
* docked (the container's width, against the foot, square corners) or floating (from lg 1024 up:
|
|
8
|
-
*
|
|
9
|
-
* elevation/overlay shadow). Below 1024
|
|
7
|
+
* docked (the container's width, against the foot, square corners) or floating (from lg 1024 up: in the bottom
|
|
8
|
+
* right corner of the scrolling container, bottom-bar/floating/margin off the foot and the right, hugging its
|
|
9
|
+
* content, bottom-bar/floating/padding-*, bottom-bar/floating/radius and the elevation/overlay shadow). Below 1024
|
|
10
|
+
* floating is exactly docked (Figma: `placement`).
|
|
10
11
|
*/
|
|
11
12
|
placement?: BottomBarPlacement;
|
|
12
13
|
/**
|
|
13
|
-
* The leading slot, on the left: one ~44 control, never running text.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* The leading slot, on the left: one ~44 control, never running text. Left out (`undefined`), there is no slot: no
|
|
15
|
+
* wrapper is rendered. Present (even `null` or `false` while its control is hidden, as the Figma's showLeading on
|
|
16
|
+
* with the slot empty), the slot is there and reserves bottom-bar/leading/min-width (44, no minimum height), so what
|
|
17
|
+
* follows does not jump when the control comes and goes. Whoever fills it says its own changes.
|
|
16
18
|
*/
|
|
17
19
|
leading?: ReactNode;
|
|
18
20
|
children: ReactNode;
|
|
@@ -20,10 +22,11 @@ interface BottomBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
20
22
|
/**
|
|
21
23
|
* BottomBar — Figma [RDS] Actions/.bottom-bar, private: the shell at the foot of the screen under the FormActions and
|
|
22
24
|
* the SavingBar. Not exported from the package. It owns the colour (bottom-bar/background, the brand's primary), the
|
|
23
|
-
* height (64 plus env(safe-area-inset-bottom) compact, 68 expanded), the padding and gap, the
|
|
24
|
-
* bottom of the scrolling container
|
|
25
|
-
* on-screen keyboard (compact: it slides away while a field
|
|
26
|
-
*
|
|
25
|
+
* height (64 plus env(safe-area-inset-bottom) compact, 68 expanded docked, 64 floating), the padding and gap, the
|
|
26
|
+
* place (sticky at the bottom of the scrolling container; floating, in its bottom right corner), the placement, the
|
|
27
|
+
* leading slot, the Button tokens in the bar's colours, the on-screen keyboard (compact: it slides away while a field
|
|
28
|
+
* is being typed in) and the Toaster's offset (--toast-offset-bottom, while it is on screen). Whoever builds on it
|
|
29
|
+
* puts the actions. Styles: bottom-bar.css.
|
|
27
30
|
*/
|
|
28
31
|
declare function BottomBar({ placement, leading, className, children, ...rest }: BottomBarProps): react.JSX.Element;
|
|
29
32
|
|
|
@@ -5,13 +5,52 @@ import {
|
|
|
5
5
|
__spreadValues
|
|
6
6
|
} from "../../chunk-ORMEWXMH.js";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { useEffect, useRef } from "react";
|
|
8
9
|
import { useOnScreenKeyboard } from "./use-on-screen-keyboard.js";
|
|
10
|
+
const TOAST_OFFSET = "--toast-offset-bottom";
|
|
11
|
+
const onScreen = /* @__PURE__ */ new Map();
|
|
12
|
+
function footprint(el) {
|
|
13
|
+
const bottom = Number.parseFloat(getComputedStyle(el).bottom);
|
|
14
|
+
return el.getBoundingClientRect().height + (Number.isFinite(bottom) ? bottom : 0);
|
|
15
|
+
}
|
|
16
|
+
function publishToastOffset() {
|
|
17
|
+
const root = document.documentElement;
|
|
18
|
+
if (!onScreen.size) {
|
|
19
|
+
root.style.removeProperty(TOAST_OFFSET);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const taken = Math.max(...onScreen.values());
|
|
23
|
+
root.style.setProperty(TOAST_OFFSET, `calc(${taken}px + var(--space-16))`);
|
|
24
|
+
}
|
|
25
|
+
function useToastOffset(ref, visible) {
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const el = ref.current;
|
|
28
|
+
if (!el || !visible) return;
|
|
29
|
+
const measure = () => {
|
|
30
|
+
onScreen.set(el, footprint(el));
|
|
31
|
+
publishToastOffset();
|
|
32
|
+
};
|
|
33
|
+
measure();
|
|
34
|
+
const observer = typeof ResizeObserver === "function" ? new ResizeObserver(measure) : null;
|
|
35
|
+
observer == null ? void 0 : observer.observe(el);
|
|
36
|
+
window.addEventListener("resize", measure);
|
|
37
|
+
return () => {
|
|
38
|
+
observer == null ? void 0 : observer.disconnect();
|
|
39
|
+
window.removeEventListener("resize", measure);
|
|
40
|
+
onScreen.delete(el);
|
|
41
|
+
publishToastOffset();
|
|
42
|
+
};
|
|
43
|
+
}, [ref, visible]);
|
|
44
|
+
}
|
|
9
45
|
function BottomBar(_a) {
|
|
10
46
|
var _b = _a, { placement = "docked", leading, className, children } = _b, rest = __objRest(_b, ["placement", "leading", "className", "children"]);
|
|
11
47
|
const keyboard = useOnScreenKeyboard();
|
|
48
|
+
const ref = useRef(null);
|
|
49
|
+
useToastOffset(ref, !keyboard);
|
|
12
50
|
return /* @__PURE__ */ jsxs(
|
|
13
51
|
"div",
|
|
14
52
|
__spreadProps(__spreadValues({}, rest), {
|
|
53
|
+
ref,
|
|
15
54
|
className: ["rds-bottom-bar", `rds-bottom-bar--${placement}`, keyboard && "rds-bottom-bar--keyboard", className].filter(Boolean).join(" "),
|
|
16
55
|
children: [
|
|
17
56
|
leading !== void 0 && /* @__PURE__ */ jsx("div", { className: "rds-bottom-bar__leading", children: leading }),
|
|
@@ -62,6 +62,8 @@ declare function ImageIcon(): react.JSX.Element;
|
|
|
62
62
|
declare function ImageOffIcon(): react.JSX.Element;
|
|
63
63
|
/** A circular arrow: try again. */
|
|
64
64
|
declare function RotateCcwIcon(): react.JSX.Element;
|
|
65
|
+
/** An arrow bending back (Lucide undo-2): undo, discard the changes. */
|
|
66
|
+
declare function Undo2Icon(): react.JSX.Element;
|
|
65
67
|
/** Sparkles: the assistant. */
|
|
66
68
|
declare function SparklesIcon(): react.JSX.Element;
|
|
67
69
|
/** A thumb up: a reaction. */
|
|
@@ -113,4 +115,4 @@ declare function RectangleHorizontalIcon(): react.JSX.Element;
|
|
|
113
115
|
/** A dashed square: a free crop, no fixed aspect. */
|
|
114
116
|
declare function SquareDashedIcon(): react.JSX.Element;
|
|
115
117
|
|
|
116
|
-
export { AlertIcon, ArrowDownIcon, ArrowLeftIcon, ArrowUpDownIcon, ArrowUpIcon, BadgeCheckIcon, BuildingIcon, CalendarIcon, CameraIcon, CheckCheckIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CircleCheckIcon, ClockIcon, CloseIcon, CopyIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileTextIcon, ImageIcon, ImageOffIcon, ImagePlusIcon, InfoIcon, LockIcon, MapPinIcon, MegaphoneIcon, MenuIcon, MicIcon, MinusIcon, MoreVerticalIcon, PaperclipIcon, PencilIcon, PhoneIcon, PlusIcon, QuoteIcon, RectangleHorizontalIcon, RectangleVerticalIcon, ReplyIcon, RotateCcwIcon, SearchIcon, SearchXIcon, SlidersIcon, SmileIcon, SparklesIcon, SquareDashedIcon, SquareIcon, StarFilledIcon, StarIcon, TableIcon, ThumbsUpIcon, TriangleAlertIcon, UploadIcon, UserIcon };
|
|
118
|
+
export { AlertIcon, ArrowDownIcon, ArrowLeftIcon, ArrowUpDownIcon, ArrowUpIcon, BadgeCheckIcon, BuildingIcon, CalendarIcon, CameraIcon, CheckCheckIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, CircleCheckIcon, ClockIcon, CloseIcon, CopyIcon, ExternalLinkIcon, EyeIcon, EyeOffIcon, FileTextIcon, ImageIcon, ImageOffIcon, ImagePlusIcon, InfoIcon, LockIcon, MapPinIcon, MegaphoneIcon, MenuIcon, MicIcon, MinusIcon, MoreVerticalIcon, PaperclipIcon, PencilIcon, PhoneIcon, PlusIcon, QuoteIcon, RectangleHorizontalIcon, RectangleVerticalIcon, ReplyIcon, RotateCcwIcon, SearchIcon, SearchXIcon, SlidersIcon, SmileIcon, SparklesIcon, SquareDashedIcon, SquareIcon, StarFilledIcon, StarIcon, TableIcon, ThumbsUpIcon, TriangleAlertIcon, Undo2Icon, UploadIcon, UserIcon };
|
|
@@ -150,6 +150,12 @@ function RotateCcwIcon() {
|
|
|
150
150
|
/* @__PURE__ */ jsx("path", { d: "M3 3v5h5" })
|
|
151
151
|
] });
|
|
152
152
|
}
|
|
153
|
+
function Undo2Icon() {
|
|
154
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
155
|
+
/* @__PURE__ */ jsx("path", { d: "M9 14 4 9l5-5" }),
|
|
156
|
+
/* @__PURE__ */ jsx("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" })
|
|
157
|
+
] });
|
|
158
|
+
}
|
|
153
159
|
function SparklesIcon() {
|
|
154
160
|
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
155
161
|
/* @__PURE__ */ jsx("path", { d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z" }),
|
|
@@ -327,6 +333,7 @@ export {
|
|
|
327
333
|
TableIcon,
|
|
328
334
|
ThumbsUpIcon,
|
|
329
335
|
TriangleAlertIcon,
|
|
336
|
+
Undo2Icon,
|
|
330
337
|
UploadIcon,
|
|
331
338
|
UserIcon
|
|
332
339
|
};
|
|
@@ -22,17 +22,18 @@ interface SavingBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
22
22
|
/** Called by Salvar (and by Tentar de novo, on error). */
|
|
23
23
|
onSave: () => void;
|
|
24
24
|
/**
|
|
25
|
-
* Shows Descartar and is called when it is pressed (Figma: `showDiscard`). Expanded
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* Shows Descartar and is called when it is pressed (Figma: `showDiscard`). Expanded, a Button (tone neutral,
|
|
26
|
+
* ghost); compact (the phone), an IconButton with the undo icon (undo-2), named `discardLabel`. Disabled while
|
|
27
|
+
* saving, in both.
|
|
28
28
|
*/
|
|
29
29
|
onDiscard?: () => void;
|
|
30
30
|
saveLabel?: string;
|
|
31
31
|
retryLabel?: string;
|
|
32
32
|
discardLabel?: string;
|
|
33
33
|
/**
|
|
34
|
-
* docked (default: the container's width, against the foot) or floating (from 1024 up:
|
|
35
|
-
*
|
|
34
|
+
* docked (default: the container's width, against the foot) or floating (from 1024 up: in the bottom right corner,
|
|
35
|
+
* 24 off the foot and the right, hugging its content but at least 320 wide, rounded, the overlay shadow). Below 1024
|
|
36
|
+
* floating is docked (Figma: `placement`).
|
|
36
37
|
*/
|
|
37
38
|
placement?: SavingBarPlacement;
|
|
38
39
|
/**
|
|
@@ -48,7 +49,8 @@ interface SavingBarProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
48
49
|
* primary colour (bottom-bar/background) in light, dark and every brand, 64 plus the safe area compact, 68 expanded,
|
|
49
50
|
* 24 at the sides, sticky at the bottom of the scrolling container. Its Buttons are Salvar in tone action fill and
|
|
50
51
|
* Descartar in tone neutral ghost, with the bar's colours (bottom-bar/button/*). Below 1024 (compact, the phone) it is
|
|
51
|
-
* one row: the message on the left
|
|
52
|
+
* one row: the message on the left, Descartar as an IconButton with the undo icon (aria-label `discardLabel`) and
|
|
53
|
+
* Salvar on the right. While
|
|
52
54
|
* saving, the indicator is Salvar in loading, alone (with the LoadingOverlay too). On the phone it leaves while the
|
|
53
55
|
* on-screen keyboard is open and comes back on blur, never taking the focus. The content needs room below as tall as
|
|
54
56
|
* the bar (`scroll-padding-bottom`, plus `env(safe-area-inset-bottom)`). Styles: saving-bar.css,
|
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
} from "../chunk-ORMEWXMH.js";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { Button } from "./button.js";
|
|
9
|
+
import { IconButton } from "./icon-button.js";
|
|
9
10
|
import { BottomBar } from "./internal/bottom-bar.js";
|
|
10
|
-
import { AlertIcon } from "./internal/icons.js";
|
|
11
|
+
import { AlertIcon, Undo2Icon } from "./internal/icons.js";
|
|
12
|
+
import { Tooltip } from "./tooltip.js";
|
|
11
13
|
function SavingBar(_a) {
|
|
12
14
|
var _b = _a, {
|
|
13
15
|
status = "unsaved",
|
|
@@ -57,6 +59,19 @@ function SavingBar(_a) {
|
|
|
57
59
|
] }),
|
|
58
60
|
/* @__PURE__ */ jsxs("div", { className: "rds-savingbar__actions", children: [
|
|
59
61
|
onDiscard && /* @__PURE__ */ jsx(Button, { className: "rds-savingbar__discard", tone: "neutral", variant: "ghost", disabled: saving, onClick: onDiscard, children: discardLabel }),
|
|
62
|
+
onDiscard && /* @__PURE__ */ jsx(Tooltip, { text: discardLabel, children: /* @__PURE__ */ jsx(
|
|
63
|
+
IconButton,
|
|
64
|
+
{
|
|
65
|
+
className: "rds-savingbar__discard-icon",
|
|
66
|
+
icon: /* @__PURE__ */ jsx(Undo2Icon, {}),
|
|
67
|
+
label: discardLabel,
|
|
68
|
+
tone: "neutral",
|
|
69
|
+
variant: "ghost",
|
|
70
|
+
size: "md",
|
|
71
|
+
disabled: saving,
|
|
72
|
+
onClick: onDiscard
|
|
73
|
+
}
|
|
74
|
+
) }),
|
|
60
75
|
/* @__PURE__ */ jsx(Button, { tone: "action", variant: "fill", loading: saving, loadingLabel: savingLabel, onClick: onSave, children: saving ? savingLabel : error ? retryLabel : saveLabel })
|
|
61
76
|
] })
|
|
62
77
|
]
|
|
@@ -64,10 +64,12 @@ interface ToasterProps {
|
|
|
64
64
|
/** @internal How long a toast stays: 5 s, or until closed when it has an action (WCAG 2.2.1). */
|
|
65
65
|
declare const toastDuration: (duration: number | undefined, hasAction: boolean) => number;
|
|
66
66
|
/**
|
|
67
|
-
* Toaster — the region where the toasts of the Figma [RDS] Feedback/Toast appear (Radix Toast):
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
67
|
+
* Toaster — the region where the toasts of the Figma [RDS] Feedback/Toast appear (Radix Toast): bottom-center on
|
|
68
|
+
* every screen width (no switch by breakpoint; on the phone, the width minus 16 on each side), up to three at a time
|
|
69
|
+
* (a fourth pushes the oldest out). With a bar at the foot on screen (FormActions, SavingBar) the stack rises above
|
|
70
|
+
* it (--toast-offset-bottom, filled by the bar) and goes back to 16 when the bar leaves. Each one is announced in a
|
|
71
|
+
* live region (danger assertively, the others politely). F8 takes the focus to the region; swiping right dismisses.
|
|
72
|
+
* A toast closes by itself after 5 s; one with an action stays until the action or the × (WCAG 2.2.1). Styles: toast.css.
|
|
71
73
|
*/
|
|
72
74
|
declare function Toaster({ label, closeLabel, children }: ToasterProps): react.JSX.Element;
|
|
73
75
|
|
package/package.json
CHANGED
|
@@ -4653,8 +4653,10 @@ input:focus-visible + .rds-checkbox__box {
|
|
|
4653
4653
|
/* @tokens bottom-bar */
|
|
4654
4654
|
/*
|
|
4655
4655
|
* FormActions: no tokens of its own; the shell (internal/bottom-bar.css, bottom-bar/*) brings the colour, the height,
|
|
4656
|
-
* the padding, the place and the Buttons' colours
|
|
4657
|
-
*
|
|
4656
|
+
* the padding, the place and the Buttons' colours (the X too: the neutral ghost reads bottom-bar/button/ghost/label,
|
|
4657
|
+
* its hover that colour at 15%, its ring bottom-bar/focus/ring). Here only the actions: on the right, 8 apart,
|
|
4658
|
+
* Cancelar then the primary. Compact (below lg 1024, by the screen width as the Figma viewport mode), Cancelar is the
|
|
4659
|
+
* X (an IconButton) and the primary; the actions between them are not shown.
|
|
4658
4660
|
*/
|
|
4659
4661
|
.rds-form-actions__actions {
|
|
4660
4662
|
display: flex;
|
|
@@ -4663,11 +4665,20 @@ input:focus-visible + .rds-checkbox__box {
|
|
|
4663
4665
|
margin-inline-start: auto;
|
|
4664
4666
|
}
|
|
4665
4667
|
|
|
4668
|
+
/* Expanded: the labelled Cancelar; the X is the compact one. */
|
|
4669
|
+
.rds-form-actions__actions > .rds-form-actions__cancel-icon {
|
|
4670
|
+
display: none;
|
|
4671
|
+
}
|
|
4672
|
+
|
|
4666
4673
|
@media (max-width: 1023px) {
|
|
4667
|
-
/*
|
|
4674
|
+
/* The X and the primary (the last action): every other action leaves. */
|
|
4668
4675
|
.rds-form-actions__actions > :not(:last-child) {
|
|
4669
4676
|
display: none;
|
|
4670
4677
|
}
|
|
4678
|
+
|
|
4679
|
+
.rds-form-actions__actions > .rds-form-actions__cancel-icon {
|
|
4680
|
+
display: inline-flex;
|
|
4681
|
+
}
|
|
4671
4682
|
}
|
|
4672
4683
|
|
|
4673
4684
|
/* components/google-account-chooser.css */
|
|
@@ -5399,10 +5410,17 @@ input:focus-visible + .rds-checkbox__box {
|
|
|
5399
5410
|
* container, bottom-bar/padding-x (24) at the sides, bottom-bar/gap (16) between the parts.
|
|
5400
5411
|
* Height, by the screen width as the Figma viewport mode (layout/compact below lg 1024): compact, bottom-bar/padding-y
|
|
5401
5412
|
* (10) above and below, 64 = 10 + 44 + 10, plus the safe area at the bottom; expanded, 2 more inside each side, 68.
|
|
5402
|
-
* The leading slot reserves bottom-bar/leading/min-width (44, the md Button height)
|
|
5403
|
-
*
|
|
5404
|
-
*
|
|
5405
|
-
*
|
|
5413
|
+
* The leading slot, only when there is one, reserves bottom-bar/leading/min-width (44, the md Button height) and no
|
|
5414
|
+
* height of its own.
|
|
5415
|
+
* floating, from 1024 only: in the bottom right corner of the scrolling container, bottom-bar/floating/margin (24) off
|
|
5416
|
+
* the foot and the right; it hugs its content (width: fit-content, never wider than the container minus the margins),
|
|
5417
|
+
* with bottom-bar/floating/padding-y (8) and padding-x (12) plus the 2 of the expanded arrangement above and below:
|
|
5418
|
+
* 64 = 10 + 44 + 10; bottom-bar/floating/radius and elevation/overlay. Still sticky, not fixed: it stays inside the
|
|
5419
|
+
* scrolling container (a page beside a sidebar never has the sidebar covered, a panel keeps its bar), and the room it
|
|
5420
|
+
* takes at the end of the content is the room the content needs below. Below 1024 it is docked: no radius, no
|
|
5421
|
+
* shadow, no margin, the full width.
|
|
5422
|
+
* While it is on screen, BottomBar fills --toast-offset-bottom on the root (its height, plus the margin when
|
|
5423
|
+
* floating, plus 16): the Toaster's stack rises above it (toast.css).
|
|
5406
5424
|
* The Buttons on it stay the Button: the action fill and the neutral ghost read their tokens, redeclared here in the
|
|
5407
5425
|
* bar's colours (bottom-bar/button/*): the fill's hover at 85% over the bar (active 70%), the ghost's hover the label
|
|
5408
5426
|
* colour at 15% (active 25%), disabled at 40% over the bar (the Figma layer opacity), the focus ring
|
|
@@ -5461,10 +5479,12 @@ input:focus-visible + .rds-checkbox__box {
|
|
|
5461
5479
|
@media (min-width: 1024px) {
|
|
5462
5480
|
.rds-bottom-bar--floating {
|
|
5463
5481
|
bottom: var(--bottom-bar-floating-margin);
|
|
5464
|
-
width:
|
|
5465
|
-
|
|
5466
|
-
|
|
5482
|
+
width: fit-content;
|
|
5483
|
+
min-width: 0;
|
|
5484
|
+
max-width: calc(100% - 2 * var(--bottom-bar-floating-margin));
|
|
5485
|
+
margin-inline: auto var(--bottom-bar-floating-margin);
|
|
5467
5486
|
margin-bottom: var(--bottom-bar-floating-margin);
|
|
5487
|
+
padding: calc(var(--bottom-bar-floating-padding-y) + 2px) var(--bottom-bar-floating-padding-x);
|
|
5468
5488
|
border-radius: var(--bottom-bar-floating-radius);
|
|
5469
5489
|
box-shadow: var(--elevation-overlay);
|
|
5470
5490
|
}
|
|
@@ -8614,9 +8634,10 @@ input:focus-visible + .rds-radio__circle {
|
|
|
8614
8634
|
* SavingBar: no tokens of its own; the shell (internal/bottom-bar.css, bottom-bar/*) brings the colour, the height,
|
|
8615
8635
|
* the padding, the place and the Buttons' colours. Here the message (label, medium, in bottom-bar/text, at most 2
|
|
8616
8636
|
* lines with an ellipsis; on error the alert 20 before it, 12 apart) and the actions (8 apart, Descartar then Salvar).
|
|
8617
|
-
* Expanded (from lg 1024) the message grows (at least 160) beside Descartar and Salvar;
|
|
8618
|
-
*
|
|
8619
|
-
* Descartar
|
|
8637
|
+
* Expanded (from lg 1024) the message grows (at least 160) beside Descartar and Salvar; floating there, the bar hugs
|
|
8638
|
+
* them but stays at least 320 wide. Compact (below 1024, by the screen width as the Figma viewport mode) one row, the
|
|
8639
|
+
* message (flex 1) on the left, Descartar as the undo IconButton (its colours and ring from the shell's neutral ghost)
|
|
8640
|
+
* and Salvar on the right.
|
|
8620
8641
|
*/
|
|
8621
8642
|
.rds-savingbar__message {
|
|
8622
8643
|
display: flex;
|
|
@@ -8658,15 +8679,30 @@ input:focus-visible + .rds-radio__circle {
|
|
|
8658
8679
|
gap: var(--space-8);
|
|
8659
8680
|
}
|
|
8660
8681
|
|
|
8682
|
+
/* Expanded: the labelled Descartar; the undo icon is the compact one. */
|
|
8683
|
+
.rds-savingbar__actions > .rds-savingbar__discard-icon {
|
|
8684
|
+
display: none;
|
|
8685
|
+
}
|
|
8686
|
+
|
|
8687
|
+
@media (min-width: 1024px) {
|
|
8688
|
+
.rds-savingbar.rds-bottom-bar--floating {
|
|
8689
|
+
min-width: 320px;
|
|
8690
|
+
}
|
|
8691
|
+
}
|
|
8692
|
+
|
|
8661
8693
|
@media (max-width: 1023px) {
|
|
8662
8694
|
.rds-savingbar__message {
|
|
8663
8695
|
flex: 1 1 0;
|
|
8664
8696
|
min-width: 0;
|
|
8665
8697
|
}
|
|
8666
8698
|
|
|
8667
|
-
.rds-
|
|
8699
|
+
.rds-savingbar__actions > .rds-savingbar__discard {
|
|
8668
8700
|
display: none;
|
|
8669
8701
|
}
|
|
8702
|
+
|
|
8703
|
+
.rds-savingbar__actions > .rds-savingbar__discard-icon {
|
|
8704
|
+
display: inline-flex;
|
|
8705
|
+
}
|
|
8670
8706
|
}
|
|
8671
8707
|
|
|
8672
8708
|
/* components/section-card.css */
|
|
@@ -10704,13 +10740,23 @@ tbody > tr:last-child > .rds-table__status {
|
|
|
10704
10740
|
/*
|
|
10705
10741
|
* Toast (Feedback collection, toast/*): 460 wide, 8 8 8 16 inside, 12 between icon, text, action and ×,
|
|
10706
10742
|
* elevation/overlay. outline: white with a border, the icon in the tone; soft and fill: the tone's plate, and
|
|
10707
|
-
* everything on it (icon, text, action, ×) in the plate's text colour. Stacked
|
|
10708
|
-
*
|
|
10743
|
+
* everything on it (icon, text, action, ×) in the plate's text colour. Stacked at the bottom centre on every screen
|
|
10744
|
+
* width (bottom-center, no switch by breakpoint: the bottom right corner belongs to the floating bar at the foot),
|
|
10745
|
+
* 16 from the foot and 8 apart; on the phone, the screen width minus 16 on each side (calc(100% - 32px)).
|
|
10746
|
+
* With a bar at the foot on screen (FormActions, SavingBar), the stack rises above it: --toast-offset-bottom, filled
|
|
10747
|
+
* on the root by the bar while it is mounted and visible (its height, plus its margin when floating, plus 16), and
|
|
10748
|
+
* back to 16 when it leaves or the on-screen keyboard hides it. The default lives on the root; the bar sets it inline
|
|
10749
|
+
* on the root (so it wins) and removes it.
|
|
10709
10750
|
*/
|
|
10751
|
+
:root {
|
|
10752
|
+
--toast-offset-bottom: var(--space-16);
|
|
10753
|
+
}
|
|
10754
|
+
|
|
10710
10755
|
.rds-toast-viewport {
|
|
10711
10756
|
position: fixed;
|
|
10712
10757
|
right: 0;
|
|
10713
10758
|
bottom: 0;
|
|
10759
|
+
left: 0;
|
|
10714
10760
|
z-index: var(--z-toast);
|
|
10715
10761
|
box-sizing: border-box;
|
|
10716
10762
|
display: flex;
|
|
@@ -10718,8 +10764,9 @@ tbody > tr:last-child > .rds-table__status {
|
|
|
10718
10764
|
gap: var(--space-8);
|
|
10719
10765
|
width: min(calc(460px + var(--space-16) * 2), 100vw);
|
|
10720
10766
|
max-width: 100vw;
|
|
10721
|
-
margin: 0;
|
|
10767
|
+
margin: 0 auto;
|
|
10722
10768
|
padding: var(--space-16);
|
|
10769
|
+
padding-bottom: var(--toast-offset-bottom);
|
|
10723
10770
|
list-style: none;
|
|
10724
10771
|
outline: none;
|
|
10725
10772
|
}
|
|
@@ -127,7 +127,8 @@
|
|
|
127
127
|
--bottom-bar-leading-min-width: var(--button-size-md-height);
|
|
128
128
|
--bottom-bar-floating-radius: var(--radius-container);
|
|
129
129
|
--bottom-bar-floating-margin: var(--space-24);
|
|
130
|
-
--bottom-bar-floating-
|
|
130
|
+
--bottom-bar-floating-padding-y: var(--space-8);
|
|
131
|
+
--bottom-bar-floating-padding-x: var(--space-12);
|
|
131
132
|
|
|
132
133
|
/* blocks */
|
|
133
134
|
--topnav-background: var(--surface-card);
|