@rojaostudio/ds 2.0.0-next.10 → 2.0.0-next.12

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.
@@ -18,7 +18,7 @@ interface ChoiceCarouselProps<T> {
18
18
  /**
19
19
  * ChoiceCarousel — a horizontal, scroll-snapped row of options to pick one (radiogroup) or several (group of
20
20
  * checkboxes); the options are drawn by `renderCard`. On a wide screen two outline IconButtons (with their Tooltips)
21
- * scroll it by one option; the arrow keys do the same on the row. Styles: choice-carousel.css.
21
+ * scroll it by one option, each one there only while there is more that way; the arrow keys do the same on the row. Styles: choice-carousel.css.
22
22
  */
23
23
  declare function ChoiceCarousel<T>({ options, getKey, renderCard, value, onChange, multiple, ariaLabel, isDisabled, }: ChoiceCarouselProps<T>): react.JSX.Element;
24
24
 
@@ -75,7 +75,7 @@ function ChoiceCarousel({
75
75
  }
76
76
  };
77
77
  return /* @__PURE__ */ jsxs("div", { className: "rds-choice-carousel", children: [
78
- /* @__PURE__ */ jsx(Tooltip, { text: "Anterior", children: /* @__PURE__ */ jsx(
78
+ canScrollLeft && /* @__PURE__ */ jsx(Tooltip, { text: "Anterior", children: /* @__PURE__ */ jsx(
79
79
  IconButton,
80
80
  {
81
81
  className: "rds-choice-carousel__arrow rds-choice-carousel__arrow--prev",
@@ -84,7 +84,6 @@ function ChoiceCarousel({
84
84
  variant: "outline",
85
85
  tone: "neutral",
86
86
  onClick: () => scrollByAmount(-1),
87
- disabled: !canScrollLeft,
88
87
  tabIndex: -1
89
88
  }
90
89
  ) }),
@@ -123,7 +122,7 @@ function ChoiceCarousel({
123
122
  })
124
123
  }
125
124
  ),
126
- /* @__PURE__ */ jsx(Tooltip, { text: "Pr\xF3ximo", children: /* @__PURE__ */ jsx(
125
+ canScrollRight && /* @__PURE__ */ jsx(Tooltip, { text: "Pr\xF3ximo", children: /* @__PURE__ */ jsx(
127
126
  IconButton,
128
127
  {
129
128
  className: "rds-choice-carousel__arrow rds-choice-carousel__arrow--next",
@@ -132,7 +131,6 @@ function ChoiceCarousel({
132
131
  variant: "outline",
133
132
  tone: "neutral",
134
133
  onClick: () => scrollByAmount(1),
135
- disabled: !canScrollRight,
136
134
  tabIndex: -1
137
135
  }
138
136
  ) })
@@ -9,18 +9,12 @@ interface ChoicePreviewCardProps {
9
9
  preview: ReactNode;
10
10
  label: string;
11
11
  description?: string;
12
- /** Ignored: the ChoiceCard has no locked state. */
13
- locked?: boolean;
14
12
  disabled?: boolean;
15
- /** Ignored: the ChoiceCard has no badge on the picture. */
16
- badge?: ReactNode;
17
- /** Ignored: the picture is always 16:9. */
18
- previewAspect?: 'square' | 'video' | 'wide';
19
13
  className?: string;
20
14
  }
21
15
  /**
22
16
  * @deprecated Use ChoiceCard with layout="preview" (Figma [RDS] Content/ChoiceCard). A thin wrapper over it: `label`
23
- * is the children. It is a native radio now, not a toggle button; `locked`, `badge` and `previewAspect` are ignored.
17
+ * is the children. It is a native radio now, not a toggle button (`locked`, `badge` and `previewAspect` left in 2.0).
24
18
  */
25
19
  declare function ChoicePreviewCard({ selected, onSelect, preview, label, description, disabled, className }: ChoicePreviewCardProps): react.JSX.Element;
26
20
 
@@ -30,8 +30,6 @@ interface CurrencyInputProps {
30
30
  maxDigits?: number;
31
31
  /** Shows 0,00 instead of the placeholder when the value is zero. */
32
32
  showZero?: boolean;
33
- /** @deprecated The [RDS] Input has one height (44). Ignored. */
34
- size?: 'sm' | 'md' | 'lg';
35
33
  id?: string;
36
34
  className?: string;
37
35
  }
@@ -6,7 +6,6 @@ import {
6
6
  } from "../chunk-ORMEWXMH.js";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { useState } from "react";
9
- import { Badge } from "./badge.js";
10
9
  import { Button } from "./button.js";
11
10
  import { Chip } from "./chip.js";
12
11
  import { Drawer } from "./drawer.js";
@@ -32,10 +31,17 @@ function FilterDropdown({ f, placement = "bottom-start" }) {
32
31
  }
33
32
  function FiltersButton(_c) {
34
33
  var _d = _c, { count } = _d, rest = __objRest(_d, ["count"]);
35
- return /* @__PURE__ */ jsxs(Button, __spreadProps(__spreadValues({}, rest), { tone: "neutral", variant: count > 0 ? "fill" : "outline", icon: /* @__PURE__ */ jsx(SlidersIcon, {}), "data-filter-toggle": "", children: [
36
- "Filtros",
37
- count > 0 && /* @__PURE__ */ jsx(Badge, { value: count, tone: "neutral", variant: "soft" })
38
- ] }));
34
+ return /* @__PURE__ */ jsx(
35
+ Button,
36
+ __spreadProps(__spreadValues({}, rest), {
37
+ tone: "neutral",
38
+ variant: count > 0 ? "fill" : "outline",
39
+ icon: /* @__PURE__ */ jsx(SlidersIcon, {}),
40
+ iconPosition: "start",
41
+ "data-filter-toggle": "",
42
+ children: count > 0 ? `Filtros \xB7 ${count}` : "Filtros"
43
+ })
44
+ );
39
45
  }
40
46
  function FilterGroups({
41
47
  filters,
@@ -5,7 +5,7 @@ import { ReactNode } from 'react';
5
5
  * FloatingStepper — a composition of the Card (as a pill) and Buttons (Figma [RDS] Actions/Button, neutral): the
6
6
  * floating steps of a flow (point of sale, checkout). The current step is the filled Button (aria-current="step");
7
7
  * earlier steps go back, later ones are disabled; `canNavigate` changes the rule. `action` is a last Button after
8
- * a line (Reset). Where it floats is the caller's (className or a wrapper). Styles: floating-stepper.css.
8
+ * a vertical Separator (Reset). Where it floats is the caller's (className or a wrapper). Styles: floating-stepper.css.
9
9
  */
10
10
  type FloatingStepperStep = {
11
11
  key: string;
@@ -3,6 +3,7 @@ import "../chunk-ORMEWXMH.js";
3
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
4
  import { Button } from "./button.js";
5
5
  import { Card } from "./card.js";
6
+ import { Separator } from "./separator.js";
6
7
  function FloatingStepper({ steps, current, onNavigate, canNavigate, action, className, "aria-label": ariaLabel = "Etapas" }) {
7
8
  const currentIdx = steps.findIndex((s) => s.key === current);
8
9
  return /* @__PURE__ */ jsxs(Card, { as: "div", size: "sm", role: "navigation", "aria-label": ariaLabel, className: ["rds-floating-stepper", className].filter(Boolean).join(" "), children: [
@@ -25,7 +26,7 @@ function FloatingStepper({ steps, current, onNavigate, canNavigate, action, clas
25
26
  );
26
27
  }),
27
28
  action && /* @__PURE__ */ jsxs(Fragment, { children: [
28
- /* @__PURE__ */ jsx("span", { className: "rds-floating-stepper__divider", "aria-hidden": "true" }),
29
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "rds-floating-stepper__divider" }),
29
30
  /* @__PURE__ */ jsx(Button, { tone: "neutral", variant: "ghost", icon: action.icon, onClick: action.onClick, children: action.label })
30
31
  ] })
31
32
  ] });
@@ -0,0 +1,39 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ /** The [RDS] type scale for titles: band 36/48, heading 24/30, value 20/30. */
5
+ type HeadingLevel = 'band' | 'heading' | 'value';
6
+ /** default: text/heading (navy on light in Rojão, white on dark and on the brand plate). accent: the logo orange. */
7
+ type HeadingTone = 'default' | 'accent';
8
+ /** The element in the page outline. The visual level never decides it: the order of the page does. */
9
+ type HeadingElement = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
10
+ interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
11
+ /** The size, from the type scale (Figma `level`). */
12
+ level?: HeadingLevel;
13
+ /** The colour of the brand pair (Figma `tone`). The Mark takes the other one. */
14
+ tone?: HeadingTone;
15
+ /** The heading element. Default h2. */
16
+ as?: HeadingElement;
17
+ /** The text (Figma `text`), with an optional <Heading.Mark> stretch (Figma `showMark` + `mark`). */
18
+ children: ReactNode;
19
+ }
20
+ interface HeadingMarkProps extends HTMLAttributes<HTMLSpanElement> {
21
+ children: ReactNode;
22
+ }
23
+ /**
24
+ * Heading.Mark — Figma [RDS] .heading/mark. A stretch of the title in the other colour of the pair: accent inside a
25
+ * default Heading, default inside an accent one. A plain span: screen readers read the whole title, unannounced.
26
+ */
27
+ declare function HeadingMark({ className, children, ...rest }: HeadingMarkProps): react.JSX.Element;
28
+ /**
29
+ * Heading — Figma [RDS] Content/Heading. A title in the brand pair: one colour, or both in the same title with a
30
+ * Heading.Mark. The colour is chosen per screen; tone=default is the rule. Orange on white fails contrast even for
31
+ * a large title (2.9:1 in Rojão): tone=accent belongs on dark or on the brand plate. Styles: heading.css.
32
+ */
33
+ declare function HeadingRoot({ level, tone, as: Tag, className, children, ...rest }: HeadingProps): react.JSX.Element;
34
+ /** `<Heading>` with `<Heading.Mark>` for the stretch in the other colour. */
35
+ declare const Heading: typeof HeadingRoot & {
36
+ Mark: typeof HeadingMark;
37
+ };
38
+
39
+ export { Heading, type HeadingElement, type HeadingLevel, HeadingMark, type HeadingMarkProps, type HeadingProps, type HeadingTone };
@@ -0,0 +1,25 @@
1
+ import {
2
+ __objRest,
3
+ __spreadProps,
4
+ __spreadValues
5
+ } from "../chunk-ORMEWXMH.js";
6
+ import { jsx } from "react/jsx-runtime";
7
+ function HeadingMark(_a) {
8
+ var _b = _a, { className, children } = _b, rest = __objRest(_b, ["className", "children"]);
9
+ return /* @__PURE__ */ jsx("span", __spreadProps(__spreadValues({}, rest), { className: ["rds-heading__mark", className].filter(Boolean).join(" "), children }));
10
+ }
11
+ function HeadingRoot(_c) {
12
+ var _d = _c, { level = "heading", tone = "default", as: Tag = "h2", className, children } = _d, rest = __objRest(_d, ["level", "tone", "as", "className", "children"]);
13
+ return /* @__PURE__ */ jsx(
14
+ Tag,
15
+ __spreadProps(__spreadValues({}, rest), {
16
+ className: ["rds-heading", `rds-heading--${level}`, tone === "accent" && "rds-heading--accent", className].filter(Boolean).join(" "),
17
+ children
18
+ })
19
+ );
20
+ }
21
+ const Heading = Object.assign(HeadingRoot, { Mark: HeadingMark });
22
+ export {
23
+ Heading,
24
+ HeadingMark
25
+ };
@@ -1,9 +1,10 @@
1
1
  import * as react from 'react';
2
2
 
3
3
  /**
4
- * ImageCropModal — a composition of the Dialog, a ToggleGroup (the aspect presets), the Alert (an aspect out of
5
- * bounds) and the Spinner: crops an image before upload. Needs `react-image-crop` (an optional peer, needed only
6
- * here). Styles: image-crop-modal.css.
4
+ * ImageCropModal — Figma [RDS] Overlays/ImageCropModal: a composition of the Dialog, a ToggleGroup (the aspect
5
+ * presets), the Alert (an aspect out of bounds) and the Spinner: crops an image before upload. Needs
6
+ * `react-image-crop` (an optional peer, needed only here). The crop's shade, line and handles and the stage's
7
+ * background are its own tokens (Overlays, image-crop-modal/*). Styles: image-crop-modal.css.
7
8
  *
8
9
  * Uso:
9
10
  * <ImageCropModal
@@ -7,22 +7,14 @@ import "react-image-crop/dist/ReactCrop.css";
7
7
  import { Alert } from "./alert.js";
8
8
  import { Button } from "./button.js";
9
9
  import { Dialog } from "./dialog.js";
10
+ import { RectangleHorizontalIcon, RectangleVerticalIcon, SquareDashedIcon, SquareIcon } from "./internal/icons.js";
10
11
  import { Spinner } from "./spinner.js";
11
12
  import { ToggleGroup, ToggleGroupItem } from "./toggle-group.js";
12
- function RatioIcon({ w, h }) {
13
- const box = 16;
14
- const rw = w >= h ? box : w / h * box;
15
- const rh = h >= w ? box : h / w * box;
16
- return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("rect", { x: (18 - rw) / 2, y: (18 - rh) / 2, width: rw, height: rh, rx: "1.5", stroke: "currentColor", strokeWidth: "1.6" }) });
17
- }
18
- function FreeIcon() {
19
- return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("rect", { x: "2.5", y: "2.5", width: "13", height: "13", rx: "1.5", stroke: "currentColor", strokeWidth: "1.6", strokeDasharray: "2.5 2.2" }) });
20
- }
21
13
  const DEFAULT_PRESETS = [
22
- { id: "square", label: "1:1", aspect: 1, icon: /* @__PURE__ */ jsx(RatioIcon, { w: 1, h: 1 }) },
23
- { id: "portrait", label: "4:5", aspect: 4 / 5, icon: /* @__PURE__ */ jsx(RatioIcon, { w: 4, h: 5 }) },
24
- { id: "landscape", label: "16:9", aspect: 16 / 9, icon: /* @__PURE__ */ jsx(RatioIcon, { w: 16, h: 9 }) },
25
- { id: "free", label: "Livre", icon: /* @__PURE__ */ jsx(FreeIcon, {}) }
14
+ { id: "square", label: "1:1", aspect: 1, icon: /* @__PURE__ */ jsx(SquareIcon, {}) },
15
+ { id: "portrait", label: "4:5", aspect: 4 / 5, icon: /* @__PURE__ */ jsx(RectangleVerticalIcon, {}) },
16
+ { id: "landscape", label: "16:9", aspect: 16 / 9, icon: /* @__PURE__ */ jsx(RectangleHorizontalIcon, {}) },
17
+ { id: "free", label: "Livre", icon: /* @__PURE__ */ jsx(SquareDashedIcon, {}) }
26
18
  ];
27
19
  const DEFAULT_MIN_ASPECT = 0.5;
28
20
  const DEFAULT_MAX_ASPECT = 2;
@@ -238,13 +230,7 @@ function ImageCropModal({
238
230
  busy && /* @__PURE__ */ jsx("div", { className: "rds-image-crop__layer rds-image-crop__layer--busy", children: /* @__PURE__ */ jsx(Spinner, { size: "lg", tone: "inverse", label: "Enviando\u2026" }) })
239
231
  ] }),
240
232
  aspectError && /* @__PURE__ */ jsx(Alert, { tone: "danger", title: aspectError, announce: "alert" }),
241
- !aspectError && preset.id === "free" && /* @__PURE__ */ jsxs("p", { className: "rds-image-crop__hint", children: [
242
- "Livre: propor\xE7\xE3o entre ",
243
- minAspect.toFixed(1),
244
- " (vertical) e ",
245
- maxAspect.toFixed(1),
246
- " (horizontal)."
247
- ] })
233
+ !aspectError && imgLoaded && !busy && /* @__PURE__ */ jsx("p", { className: "rds-image-crop__hint", children: preset.aspect ? "Arraste as al\xE7as para ajustar o recorte." : `Livre: propor\xE7\xE3o entre ${minAspect.toFixed(1)} (vertical) e ${maxAspect.toFixed(1)} (horizontal).` })
248
234
  ] })
249
235
  }
250
236
  );
@@ -3,11 +3,10 @@ import { CropPreset } from './image-crop-modal.js';
3
3
 
4
4
  /**
5
5
  * @deprecated Use `<FileInput variant="tile">` (Figma [RDS] Forms/FileInput): the image's square with the preview
6
- * and the swap and remove buttons. ImageUpload is now a thin wrapper over it that keeps the 1.x API compiling and
7
- * keeps the upload (`onUpload`) and the crop (`crop`). Every variant renders the tile: an image asks for a preview.
6
+ * and the swap and remove buttons. ImageUpload is now a thin wrapper over it that keeps most of the 1.x API compiling and
7
+ * keeps the upload (`onUpload`) and the crop (`crop`). It is always the tile (`variant`, `aspect` and the preview
8
+ * class names left in 2.0): an image asks for a preview.
8
9
  */
9
- type ImageUploadAspect = 'logo' | 'banner' | 'square';
10
- type ImageUploadVariant = 'button' | 'dropzone' | 'tile';
11
10
  interface ImageUploadLabels {
12
11
  /** The empty tile's text (FileInput's `tileText`). */
13
12
  select: string;
@@ -36,10 +35,6 @@ interface ImageUploadCrop {
36
35
  confirmLabel?: string;
37
36
  }
38
37
  interface ImageUploadProps {
39
- /** @deprecated Ignored: the tile's preview fills the square. */
40
- previewClassName?: string;
41
- /** @deprecated Ignored. */
42
- previewWrapperClassName?: string;
43
38
  /** The form field name: a hidden input carries the image's URL. */
44
39
  name: string;
45
40
  /** The image's URL, '' for none. */
@@ -49,16 +44,12 @@ interface ImageUploadProps {
49
44
  onUpload: (file: File) => Promise<string>;
50
45
  label?: string;
51
46
  hint?: string;
52
- /** @deprecated Ignored: the tile is a 112 square. */
53
- aspect?: ImageUploadAspect;
54
47
  accept?: string;
55
48
  className?: string;
56
- /** @deprecated Ignored: every variant is the tile. */
57
- variant?: ImageUploadVariant;
58
49
  crop?: ImageUploadCrop;
59
50
  labels?: Partial<ImageUploadLabels>;
60
51
  }
61
52
  /** @deprecated Use `<FileInput variant="tile">`, with the upload in its `onFiles` and the URL in `preview`. */
62
53
  declare function ImageUpload({ name, value, onChange, onUpload, label, hint, accept, className, crop, labels, }: ImageUploadProps): react.JSX.Element;
63
54
 
64
- export { ImageUpload, type ImageUploadAspect, type ImageUploadCrop, type ImageUploadLabels, type ImageUploadProps, type ImageUploadVariant };
55
+ export { ImageUpload, type ImageUploadCrop, type ImageUploadLabels, type ImageUploadProps };
@@ -41,7 +41,7 @@ export { SectionHeader, SectionHeaderProps } from './section-header.js';
41
41
  export { FloatingStepper, FloatingStepperProps, FloatingStepperStep } from './floating-stepper.js';
42
42
  export { Stat, StatProps, StatTone } from './stat.js';
43
43
  export { SummaryBar, SummaryBarItem, SummaryBarLayout, SummaryBarProps, SummaryBarTone } from './summary-bar.js';
44
- export { ToggleCard, ToggleCardProps } from './toggle-card.js';
44
+ export { ToggleCard, ToggleCardLayout, ToggleCardProps } from './toggle-card.js';
45
45
  export { ToggleCardCompact, ToggleCardCompactProps } from './toggle-card-compact.js';
46
46
  export { ChipInput, ChipInputProps } from './chip-input.js';
47
47
  export { CopyField, CopyFieldProps } from './copy-field.js';
@@ -77,6 +77,7 @@ export { Switch, SwitchProps } from './switch.js';
77
77
  export { Tooltip, TooltipProps, TooltipSide } from './tooltip.js';
78
78
  export { ToastFn, ToastOptions, ToastTone, ToastVariant, ToastView, ToastViewProps, Toaster, ToasterProps, toast, toastClassName, useToast } from './toast.js';
79
79
  export { Separator, SeparatorOrientation, SeparatorProps } from './separator.js';
80
+ export { Heading, HeadingElement, HeadingLevel, HeadingMark, HeadingMarkProps, HeadingProps, HeadingTone } from './heading.js';
80
81
  export { Avatar, AvatarGroup, AvatarGroupProps, AvatarGroupSize, AvatarProps, AvatarSize, AvatarType, AvatarVariant, initials } from './avatar.js';
81
82
  export { IconButton, IconButtonProps } from './icon-button.js';
82
83
  export { ButtonGroup, ButtonGroupOrientation, ButtonGroupProps } from './button-group.js';
@@ -84,6 +84,7 @@ import { Switch } from "./switch.js";
84
84
  import { Tooltip } from "./tooltip.js";
85
85
  import { Toaster, ToastView, toast, useToast, toastClassName } from "./toast.js";
86
86
  import { Separator } from "./separator.js";
87
+ import { Heading, HeadingMark } from "./heading.js";
87
88
  import { Avatar, AvatarGroup, initials } from "./avatar.js";
88
89
  import { IconButton } from "./icon-button.js";
89
90
  import { ButtonGroup } from "./button-group.js";
@@ -208,6 +209,8 @@ export {
208
209
  GoogleButton,
209
210
  GoogleConsent,
210
211
  GoogleSignIn,
212
+ Heading,
213
+ HeadingMark,
211
214
  HoverCard,
212
215
  IconButton,
213
216
  Input,
@@ -104,5 +104,13 @@ declare function CopyIcon(): react.JSX.Element;
104
104
  declare function PencilIcon(): react.JSX.Element;
105
105
  /** Three sliders: the filters of a list. */
106
106
  declare function SlidersIcon(): react.JSX.Element;
107
+ /** A square: the 1:1 crop. */
108
+ declare function SquareIcon(): react.JSX.Element;
109
+ /** A standing rectangle: a portrait crop (4:5). */
110
+ declare function RectangleVerticalIcon(): react.JSX.Element;
111
+ /** A lying rectangle: a landscape crop (16:9). */
112
+ declare function RectangleHorizontalIcon(): react.JSX.Element;
113
+ /** A dashed square: a free crop, no fixed aspect. */
114
+ declare function SquareDashedIcon(): react.JSX.Element;
107
115
 
108
- 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, ReplyIcon, RotateCcwIcon, SearchIcon, SearchXIcon, SlidersIcon, SmileIcon, SparklesIcon, StarFilledIcon, StarIcon, TableIcon, ThumbsUpIcon, TriangleAlertIcon, UploadIcon, UserIcon };
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 };
@@ -260,6 +260,18 @@ function PencilIcon() {
260
260
  function SlidersIcon() {
261
261
  return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 4h-7M10 4H3M21 12h-9M8 12H3M21 20h-5M12 20H3M14 2v4M8 10v4M16 18v4" }) });
262
262
  }
263
+ function SquareIcon() {
264
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }) });
265
+ }
266
+ function RectangleVerticalIcon() {
267
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("rect", { width: "12", height: "20", x: "6", y: "2", rx: "2" }) });
268
+ }
269
+ function RectangleHorizontalIcon() {
270
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("rect", { width: "20", height: "12", x: "2", y: "6", rx: "2" }) });
271
+ }
272
+ function SquareDashedIcon() {
273
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M5 3a2 2 0 0 0-2 2M19 3a2 2 0 0 1 2 2M21 19a2 2 0 0 1-2 2M5 21a2 2 0 0 1-2-2M9 3h1M9 21h1M14 3h1M14 21h1M3 9v1M21 9v1M3 14v1M21 14v1" }) });
274
+ }
263
275
  export {
264
276
  AlertIcon,
265
277
  ArrowDownIcon,
@@ -299,6 +311,8 @@ export {
299
311
  PhoneIcon,
300
312
  PlusIcon,
301
313
  QuoteIcon,
314
+ RectangleHorizontalIcon,
315
+ RectangleVerticalIcon,
302
316
  ReplyIcon,
303
317
  RotateCcwIcon,
304
318
  SearchIcon,
@@ -306,6 +320,8 @@ export {
306
320
  SlidersIcon,
307
321
  SmileIcon,
308
322
  SparklesIcon,
323
+ SquareDashedIcon,
324
+ SquareIcon,
309
325
  StarFilledIcon,
310
326
  StarIcon,
311
327
  TableIcon,
@@ -6,12 +6,13 @@ import { ReactNode } from 'react';
6
6
  * title, kept because SettingsList composes it and the products still use it. New code uses
7
7
  * `<PageHeader titleAs="h2" title description actions />`.
8
8
  *
9
- * action → actions. eyebrow and number (not in the Figma) still render as a line above the title. Styles: section-header.css.
9
+ * action → actions. eyebrow and number are deprecated (not in the Figma); they still render as a line above the
10
+ * title. Styles: section-header.css.
10
11
  */
11
12
  interface SectionHeaderProps {
12
- /** Small uppercase line above the title (overline). */
13
+ /** @deprecated Not in the Figma [RDS] (the SectionHeader pattern): a small uppercase line above the title. */
13
14
  eyebrow?: string;
14
- /** Section or step number, before the eyebrow: "02 · CONTEÚDO". */
15
+ /** @deprecated Not in the Figma [RDS]: the section or step number, before the eyebrow ("02 · CONTEÚDO"). */
15
16
  number?: string;
16
17
  title: string;
17
18
  description?: string;
@@ -5,22 +5,14 @@ import { ReactNode } from 'react';
5
5
  interface SelectableCardProps {
6
6
  selected?: boolean;
7
7
  onClick?: () => void;
8
- /** Ignored: the card is a radio now, never a link. */
9
- as?: 'button' | 'a';
10
- /** Ignored: the card is a radio now, never a link. */
11
- href?: string;
12
- /** Ignored: the ChoiceCard row always shows its radio. */
13
- indicator?: 'radio' | 'check' | 'chevron' | 'none';
14
- /** Ignored: the ChoiceCard has no ribbon. */
15
- ribbon?: ReactNode;
16
8
  disabled?: boolean;
17
9
  className?: string;
18
10
  children: ReactNode;
19
11
  }
20
12
  /**
21
13
  * @deprecated Use ChoiceCard (Figma [RDS] Content/ChoiceCard, layout="row"). A thin wrapper over it: `children`
22
- * is the label, `onClick` is `onSelect`. It is a native radio now, not a button: `as`, `href`, `indicator` and
23
- * `ribbon` are ignored, and a chosen card cannot be un-chosen by clicking it again.
14
+ * is the label, `onClick` is `onSelect`. It is a native radio now, not a button (`as`, `href`, `indicator` and
15
+ * `ribbon` left in 2.0), and a chosen card cannot be un-chosen by clicking it again.
24
16
  */
25
17
  declare function SelectableCard({ selected, onClick, disabled, className, children }: SelectableCardProps): react.JSX.Element;
26
18
 
@@ -1,31 +1,12 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
2
+ import { ToggleCardProps } from './toggle-card.js';
3
3
 
4
- interface ToggleCardCompactProps {
5
- /** An icon before the text (the Item's media). */
6
- icon?: ReactNode;
7
- /** The setting it turns on (the Item's title and the Switch's name). */
8
- label: string;
9
- /** The line under the label while off. */
10
- description?: ReactNode;
11
- /** The line under the label while on (a summary of what is set); it replaces `description`. */
12
- summary?: ReactNode;
13
- checked: boolean;
14
- onCheckedChange?: (checked: boolean) => void;
15
- /** Shows the pencil (an IconButton) while on: opens the setting's options (a Dialog). */
16
- onEdit?: () => void;
17
- /** The pencil's accessible name and tooltip. */
18
- editLabel?: string;
19
- /** Submits 'on' (or '') under this name with a native form, through a hidden input. */
20
- name?: string;
21
- disabled?: boolean;
22
- className?: string;
23
- }
4
+ /** @deprecated Use ToggleCardProps (with layout="compact"). */
5
+ type ToggleCardCompactProps = Omit<ToggleCardProps, 'layout' | 'children'>;
24
6
  /**
25
- * ToggleCardCompact — a composition of the Item (outline), the Switch and the IconButton with its Tooltip: a
26
- * setting in one row, its summary under the label while on and a pencil that opens its options. Styles:
27
- * toggle-card-compact.css.
7
+ * @deprecated Use `<ToggleCard layout="compact">` (Figma [RDS] Forms/ToggleCard, layout=compact), with the same
8
+ * props. A thin wrapper over it, kept so the old name keeps compiling; the codemod rewrites it.
28
9
  */
29
- declare function ToggleCardCompact({ icon, label, description, summary, checked, onCheckedChange, onEdit, editLabel, name, disabled, className, }: ToggleCardCompactProps): react.JSX.Element;
10
+ declare function ToggleCardCompact(props: ToggleCardCompactProps): react.JSX.Element;
30
11
 
31
12
  export { ToggleCardCompact, type ToggleCardCompactProps };
@@ -1,39 +1,12 @@
1
1
  "use client";
2
- import "../chunk-ORMEWXMH.js";
3
- import { jsx, jsxs } from "react/jsx-runtime";
4
- import { IconButton } from "./icon-button.js";
5
- import { PencilIcon } from "./internal/icons.js";
6
- import { Item } from "./item.js";
7
- import { Switch } from "./switch.js";
8
- import { Tooltip } from "./tooltip.js";
9
- function ToggleCardCompact({
10
- icon,
11
- label,
12
- description,
13
- summary,
14
- checked,
15
- onCheckedChange,
16
- onEdit,
17
- editLabel = "Editar",
18
- name,
19
- disabled,
20
- className
21
- }) {
22
- return /* @__PURE__ */ jsx(
23
- Item,
24
- {
25
- variant: "outline",
26
- className: ["rds-toggle-card-compact", className].filter(Boolean).join(" "),
27
- media: icon,
28
- title: label,
29
- description: (checked ? summary : description) || void 0,
30
- action: /* @__PURE__ */ jsxs("span", { className: "rds-toggle-card-compact__actions", children: [
31
- name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: checked ? "on" : "" }),
32
- checked && onEdit && /* @__PURE__ */ jsx(Tooltip, { text: editLabel, children: /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(PencilIcon, {}), label: editLabel, variant: "ghost", tone: "neutral", onClick: onEdit, disabled }) }),
33
- /* @__PURE__ */ jsx(Switch, { "aria-label": label, checked, onCheckedChange, disabled })
34
- ] })
35
- }
36
- );
2
+ import {
3
+ __spreadProps,
4
+ __spreadValues
5
+ } from "../chunk-ORMEWXMH.js";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { ToggleCard } from "./toggle-card.js";
8
+ function ToggleCardCompact(props) {
9
+ return /* @__PURE__ */ jsx(ToggleCard, __spreadProps(__spreadValues({}, props), { layout: "compact" }));
37
10
  }
38
11
  export {
39
12
  ToggleCardCompact
@@ -1,24 +1,38 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
 
4
+ /** Figma [RDS] Forms/ToggleCard `layout`: the Card with the options below it, or one row (the Item). */
5
+ type ToggleCardLayout = 'default' | 'compact';
4
6
  interface ToggleCardProps {
5
- /** The setting it turns on (the Switch's label). */
7
+ /** `default`: a Card with the Switch and, while on, the options below it. `compact`: one row (an outline Item). */
8
+ layout?: ToggleCardLayout;
9
+ /** The setting it turns on (the Switch's label; in compact, the Item's title and the Switch's name). */
6
10
  label: string;
7
- /** A line under the label (the Switch's hint). */
8
- description?: string;
11
+ /** A line under the label (default: the Switch's hint; compact: shown while off). */
12
+ description?: ReactNode;
13
+ /** Compact only: the line under the label while on (a summary of what is set); it replaces `description`. */
14
+ summary?: ReactNode;
15
+ /** Compact only: an icon before the text (the Item's media). */
16
+ icon?: ReactNode;
9
17
  checked: boolean;
10
- onCheckedChange: (checked: boolean) => void;
18
+ onCheckedChange?: (checked: boolean) => void;
19
+ /** Compact only: shows the pencil (an IconButton) while on; it opens the setting's options (a Dialog). */
20
+ onEdit?: () => void;
21
+ /** Compact only: the pencil's accessible name and tooltip. Default "Editar". */
22
+ editLabel?: string;
11
23
  /** Submits 'on' (or '') under this name with a native form, through a hidden input. */
12
24
  name?: string;
13
- /** The setting's options, shown under it while it is on. */
25
+ /** Default only: the setting's options, shown under it while it is on. */
14
26
  children?: ReactNode;
15
27
  disabled?: boolean;
16
28
  className?: string;
17
29
  }
18
30
  /**
19
- * ToggleCard — a composition of the Card and the Switch (Figma [RDS] Forms/Switch): a setting that, when on, opens
20
- * its own options below it. Styles: toggle-card.css.
31
+ * ToggleCard — Figma [RDS] Forms/ToggleCard: a setting that, when on, opens its own options. `layout="default"` is
32
+ * a composition of the Card and the Switch, the options below it; `layout="compact"` is one row (the Item outline,
33
+ * the Switch and the IconButton with its Tooltip): the summary under the label while on and a pencil that opens the
34
+ * options. Styles: toggle-card.css.
21
35
  */
22
- declare function ToggleCard({ label, description, checked, onCheckedChange, name, children, disabled, className }: ToggleCardProps): react.JSX.Element;
36
+ declare function ToggleCard({ layout, label, description, summary, icon, checked, onCheckedChange, onEdit, editLabel, name, children, disabled, className, }: ToggleCardProps): react.JSX.Element;
23
37
 
24
- export { ToggleCard, type ToggleCardProps };
38
+ export { ToggleCard, type ToggleCardLayout, type ToggleCardProps };
@@ -2,10 +2,46 @@
2
2
  import "../chunk-ORMEWXMH.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { Card } from "./card.js";
5
+ import { IconButton } from "./icon-button.js";
6
+ import { PencilIcon } from "./internal/icons.js";
7
+ import { Item } from "./item.js";
5
8
  import { Switch } from "./switch.js";
6
- function ToggleCard({ label, description, checked, onCheckedChange, name, children, disabled, className }) {
9
+ import { Tooltip } from "./tooltip.js";
10
+ function ToggleCard({
11
+ layout = "default",
12
+ label,
13
+ description,
14
+ summary,
15
+ icon,
16
+ checked,
17
+ onCheckedChange,
18
+ onEdit,
19
+ editLabel = "Editar",
20
+ name,
21
+ children,
22
+ disabled,
23
+ className
24
+ }) {
25
+ const hidden = name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: checked ? "on" : "" });
26
+ if (layout === "compact") {
27
+ return /* @__PURE__ */ jsx(
28
+ Item,
29
+ {
30
+ variant: "outline",
31
+ className: ["rds-toggle-card", "rds-toggle-card--compact", className].filter(Boolean).join(" "),
32
+ media: icon,
33
+ title: label,
34
+ description: (checked ? summary : description) || void 0,
35
+ action: /* @__PURE__ */ jsxs("span", { className: "rds-toggle-card__actions", children: [
36
+ hidden,
37
+ checked && onEdit && /* @__PURE__ */ jsx(Tooltip, { text: editLabel, children: /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(PencilIcon, {}), label: editLabel, variant: "ghost", tone: "neutral", onClick: onEdit, disabled }) }),
38
+ /* @__PURE__ */ jsx(Switch, { "aria-label": label, checked, onCheckedChange, disabled })
39
+ ] })
40
+ }
41
+ );
42
+ }
7
43
  return /* @__PURE__ */ jsxs(Card, { as: "div", className: ["rds-toggle-card", className].filter(Boolean).join(" "), children: [
8
- name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: checked ? "on" : "" }),
44
+ hidden,
9
45
  /* @__PURE__ */ jsx("div", { className: "rds-toggle-card__header", children: /* @__PURE__ */ jsx(Switch, { checked, onCheckedChange, hint: description, disabled, children: label }) }),
10
46
  checked && children && /* @__PURE__ */ jsx("div", { className: "rds-toggle-card__content", children })
11
47
  ] });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rojaostudio/ds",
3
- "version": "2.0.0-next.10",
3
+ "version": "2.0.0-next.12",
4
4
  "type": "module",
5
5
  "description": "Rojão Design System — componentes React, estilos e alvo React Native. O motor vive em @rojaostudio/ds-core.",
6
6
  "license": "MIT",
@@ -191,7 +191,7 @@
191
191
  "@radix-ui/react-toggle": "^1.1.18",
192
192
  "@radix-ui/react-toggle-group": "^1.1.19",
193
193
  "@radix-ui/react-tooltip": "^1.2.16",
194
- "@rojaostudio/ds-core": "1.1.0-next.5"
194
+ "@rojaostudio/ds-core": "1.1.0-next.6"
195
195
  },
196
196
  "scripts": {
197
197
  "build": "pnpm run build:tokens && pnpm run build:themes && pnpm run build:rds && pnpm run build:native && tsup",
@@ -2978,7 +2978,7 @@ input:focus-visible + .rds-checkbox__box {
2978
2978
  /*
2979
2979
  * ChoiceCarousel: no tokens of its own; the IconButtons bring theirs. A row that scrolls sideways and snaps to each
2980
2980
  * option (160 wide, 200 from 768), 12 apart, no scrollbar. From 768 the outline arrows sit on the row's edges, half
2981
- * outside, and fade away when there is nothing more that way.
2981
+ * outside, and are not there when there is nothing more that way.
2982
2982
  */
2983
2983
  .rds-choice-carousel {
2984
2984
  position: relative;
@@ -3032,7 +3032,6 @@ input:focus-visible + .rds-checkbox__box {
3032
3032
  display: inline-flex;
3033
3033
  border-radius: var(--radius-full);
3034
3034
  box-shadow: var(--elevation-raised);
3035
- transition: opacity var(--motion-duration-base) var(--motion-easing-standard);
3036
3035
  }
3037
3036
 
3038
3037
  .rds-choice-carousel__arrow--prev {
@@ -3044,11 +3043,6 @@ input:focus-visible + .rds-checkbox__box {
3044
3043
  right: 0;
3045
3044
  transform: translate(50%, -50%);
3046
3045
  }
3047
-
3048
- .rds-choice-carousel__arrow[aria-disabled='true'] {
3049
- opacity: 0;
3050
- pointer-events: none;
3051
- }
3052
3046
  }
3053
3047
 
3054
3048
  @media (prefers-reduced-motion: reduce) {
@@ -3584,7 +3578,7 @@ input:focus-visible + .rds-checkbox__box {
3584
3578
  /* components/data-table-header.css */
3585
3579
  /* @tokens data-table-header */
3586
3580
  /*
3587
- * DataTableHeader: no tokens of its own; the Input, FilterChip, Chip, Button, Badge, Separator, DropdownMenu,
3581
+ * DataTableHeader: no tokens of its own; the Input, FilterChip, Chip, Button, Separator, DropdownMenu,
3588
3582
  * Popover and Drawer bring theirs. One row, 8 apart, 12 above the table; the search takes the free width. The wide
3589
3583
  * parts show from 768, the narrow ones below it. In the Popover and the Drawer the filters stack 16 apart, each
3590
3584
  * one a caption-sized label over its chips.
@@ -4409,8 +4403,8 @@ input:focus-visible + .rds-checkbox__box {
4409
4403
  /* @tokens floating-stepper */
4410
4404
  /*
4411
4405
  * FloatingStepper: no tokens of its own; the Card and the Buttons bring theirs. A pill (radius/full) of 44 Buttons,
4412
- * 4 inside and 4 apart, raised by elevation/overlay because it floats over the page. A 1 × 24 line in the card's
4413
- * border colour before the action.
4406
+ * 4 inside and 4 apart, raised by elevation/overlay because it floats over the page. A vertical Separator, 24
4407
+ * tall, before the action.
4414
4408
  */
4415
4409
  .rds-floating-stepper {
4416
4410
  flex-direction: row;
@@ -4429,12 +4423,9 @@ input:focus-visible + .rds-checkbox__box {
4429
4423
  border-radius: var(--radius-full);
4430
4424
  }
4431
4425
 
4432
- .rds-floating-stepper__divider {
4433
- flex: none;
4434
- width: var(--border-width);
4426
+ .rds-floating-stepper > .rds-floating-stepper__divider {
4427
+ align-self: center;
4435
4428
  height: var(--size-24);
4436
- margin-inline: var(--space-4);
4437
- background: var(--card-border);
4438
4429
  }
4439
4430
 
4440
4431
  /* components/footer.css */
@@ -4785,6 +4776,48 @@ input:focus-visible + .rds-checkbox__box {
4785
4776
  }
4786
4777
  }
4787
4778
 
4779
+ /* components/heading.css */
4780
+ /* @tokens heading */
4781
+ /*
4782
+ * Heading (Content collection, heading/*): a title in the brand pair. heading/default is text/heading, heading/accent
4783
+ * the logo orange; .heading/mark paints a stretch in the other one. level follows the type scale (band, heading,
4784
+ * value), all bold.
4785
+ */
4786
+ .rds-heading {
4787
+ margin: 0;
4788
+ font-family: var(--type-font-stack);
4789
+ font-weight: var(--type-heading-weight);
4790
+ color: var(--heading-default);
4791
+ text-wrap: balance;
4792
+ }
4793
+
4794
+ .rds-heading--band {
4795
+ font-size: var(--type-band-size);
4796
+ line-height: var(--type-band-line);
4797
+ }
4798
+
4799
+ .rds-heading--heading {
4800
+ font-size: var(--type-heading-size);
4801
+ line-height: var(--type-heading-line);
4802
+ }
4803
+
4804
+ .rds-heading--value {
4805
+ font-size: var(--type-value-size);
4806
+ line-height: var(--type-value-line);
4807
+ }
4808
+
4809
+ .rds-heading--accent {
4810
+ color: var(--heading-accent);
4811
+ }
4812
+
4813
+ .rds-heading__mark {
4814
+ color: var(--heading-accent);
4815
+ }
4816
+
4817
+ .rds-heading--accent .rds-heading__mark {
4818
+ color: var(--heading-default);
4819
+ }
4820
+
4788
4821
  /* components/hover-card.css */
4789
4822
  /* @tokens hovercard */
4790
4823
  /* HoverCard (Feedback collection, hovercard/*): 320 wide, 16 inside, 12 between avatar and text, elevation/overlay. */
@@ -4862,10 +4895,11 @@ input:focus-visible + .rds-checkbox__box {
4862
4895
  /* components/image-crop-modal.css */
4863
4896
  /* @tokens image-crop-modal */
4864
4897
  /*
4865
- * ImageCropModal: no tokens of its own; the Dialog, the ToggleGroup, the Alert and the Spinner bring theirs. 12
4866
- * apart: the presets (they share the width), the stage (at least 300, at most 60% of the viewport, the image
4867
- * letterboxed inside 16 of padding, a line in the dialog's border colour), the error or the hint. While sending,
4868
- * the dialog's scrim covers the image.
4898
+ * ImageCropModal (Figma [RDS] Overlays/ImageCropModal): the Dialog, the ToggleGroup, the Alert and the Spinner bring
4899
+ * their tokens; the crop brings its own (Overlays, image-crop-modal/*). 12 apart: the presets (they share the
4900
+ * width), the stage (320 tall, on image-crop-modal/stage/background, the image letterboxed inside 16 of padding, a
4901
+ * line in the dialog's border colour), the error or the hint. Over the image, outside the crop, the shade; the crop's
4902
+ * line and its handles in their own colours. While sending, the dialog's scrim covers the stage.
4869
4903
  */
4870
4904
  .rds-image-crop {
4871
4905
  display: flex;
@@ -4888,17 +4922,42 @@ input:focus-visible + .rds-checkbox__box {
4888
4922
  display: flex;
4889
4923
  align-items: center;
4890
4924
  justify-content: center;
4891
- min-height: 300px;
4925
+ height: 320px;
4926
+ /* On a short viewport (a phone on its side) the stage gives way so the footer stays in view. */
4892
4927
  max-height: 60vh;
4893
4928
  padding: var(--space-16);
4894
4929
  overflow: hidden;
4930
+ background: var(--image-crop-modal-stage-background);
4895
4931
  border: var(--border-width) solid var(--dialog-border);
4896
4932
  border-radius: var(--radius-control);
4897
4933
  }
4898
4934
 
4935
+ /*
4936
+ * react-image-crop's own stylesheet is unlayered, so it wins over these layered rules wherever both set the same
4937
+ * property. The shade is an SVG rect with fill as an attribute (black at 50%): any CSS beats it. The handles read
4938
+ * the library's variables, set here. The selection's marching ants are hard-coded: the two !important take them
4939
+ * off so the crop is one solid line in the selection colour (the library's focus outline stays).
4940
+ */
4899
4941
  .rds-image-crop__crop {
4900
4942
  max-width: 100%;
4901
- max-height: calc(60vh - var(--space-32));
4943
+ max-height: calc(min(320px, 60vh) - var(--space-32));
4944
+ --rc-drag-handle-bg-colour: var(--image-crop-modal-handle);
4945
+ --rc-border-color: var(--image-crop-modal-handle);
4946
+ }
4947
+
4948
+ .rds-image-crop__crop .ReactCrop__crop-mask > rect {
4949
+ fill: var(--image-crop-modal-shade);
4950
+ fill-opacity: 1;
4951
+ }
4952
+
4953
+ .rds-image-crop__crop .ReactCrop__crop-selection {
4954
+ background-image: none !important;
4955
+ border: var(--border-width) solid var(--image-crop-modal-selection);
4956
+ animation: none !important;
4957
+ }
4958
+
4959
+ .rds-image-crop__crop .ReactCrop__drag-handle {
4960
+ border-radius: var(--radius-xs);
4902
4961
  }
4903
4962
 
4904
4963
  .rds-image-crop__image {
@@ -7316,8 +7375,9 @@ body:has(.rds-modal) {
7316
7375
  /* @tokens page-skeleton */
7317
7376
  /*
7318
7377
  * PageSkeleton and CardsSkeleton: no tokens of their own; the Skeleton and the Card bring theirs. Blocks 24 apart
7319
- * (24 padding when padded). The table is a small Card: the header row on the card's footer background, a line
7320
- * between rows. The cards: 2 per row (4 from 1024), the charts 1 (2 from 1024), 16 apart.
7378
+ * (24 padding when padded). The Cards keep their elevation/raised, as in the Figma. The table is a small Card: the
7379
+ * header row on the card's footer background, a line between rows. The cards: 2 per row (4 from 1024), the charts
7380
+ * 1 (2 from 1024), 16 apart.
7321
7381
  */
7322
7382
  .rds-page-skeleton {
7323
7383
  display: flex;
@@ -7336,10 +7396,6 @@ body:has(.rds-modal) {
7336
7396
  gap: var(--space-16);
7337
7397
  }
7338
7398
 
7339
- .rds-page-skeleton__table {
7340
- box-shadow: none;
7341
- }
7342
-
7343
7399
  .rds-page-skeleton__row {
7344
7400
  display: flex;
7345
7401
  align-items: center;
@@ -7386,7 +7442,6 @@ body:has(.rds-modal) {
7386
7442
  .rds-page-skeleton__card {
7387
7443
  gap: var(--space-12);
7388
7444
  padding: var(--space-16);
7389
- box-shadow: none;
7390
7445
  }
7391
7446
 
7392
7447
  .rds-page-skeleton__card .rds-skeleton {
@@ -10600,23 +10655,13 @@ tbody > tr:last-child > .rds-table__status {
10600
10655
  }
10601
10656
  }
10602
10657
 
10603
- /* components/toggle-card-compact.css */
10604
- /* @tokens toggle-card-compact */
10605
- /*
10606
- * ToggleCardCompact: no tokens of its own; the Item, the Switch and the IconButton bring theirs. The pencil and the
10607
- * Switch 8 apart at the end of the row.
10608
- */
10609
- .rds-toggle-card-compact__actions {
10610
- display: inline-flex;
10611
- align-items: center;
10612
- gap: var(--space-8);
10613
- }
10614
-
10615
10658
  /* components/toggle-card.css */
10616
10659
  /* @tokens toggle-card */
10617
10660
  /*
10618
- * ToggleCard: no tokens of its own; the Card and the Switch bring theirs. The Switch row pads 16 on the sides (4 top and
10619
- * bottom); the options under it pad 16, 16 apart, after a line in the card's border colour.
10661
+ * ToggleCard: no tokens of its own; the Card, the Item, the Switch and the IconButton bring theirs.
10662
+ * layout=default: the Switch row pads 16 on the sides (4 top and bottom); the options under it pad 16, 16 apart,
10663
+ * after a line in the card's border colour.
10664
+ * layout=compact: the outline Item; the pencil and the Switch 8 apart at the end of the row.
10620
10665
  */
10621
10666
  .rds-toggle-card__header {
10622
10667
  padding: var(--space-4) var(--space-16);
@@ -10630,6 +10675,12 @@ tbody > tr:last-child > .rds-table__status {
10630
10675
  border-top: var(--border-width) solid var(--card-border);
10631
10676
  }
10632
10677
 
10678
+ .rds-toggle-card__actions {
10679
+ display: inline-flex;
10680
+ align-items: center;
10681
+ gap: var(--space-8);
10682
+ }
10683
+
10633
10684
  /* components/toggle-group.css */
10634
10685
  /* @tokens toggle-group */
10635
10686
  /* ToggleGroup: Toggles side by side, 4 apart (Figma: slot items, gap space/4). No tokens of its own. */
@@ -386,6 +386,8 @@
386
386
  --choice-list-item-trailing-disabled: var(--text-disabled);
387
387
  --choice-list-focus-ring: var(--focus-ring);
388
388
  --choice-list-item-description-selected: var(--text-on-tint);
389
+ --heading-default: var(--text-heading);
390
+ --heading-accent: var(--colors-accent-default);
389
391
 
390
392
  /* external */
391
393
  --google-button-light-background: #ffffff;
@@ -1004,5 +1006,9 @@
1004
1006
  --sheet-text: var(--text-body);
1005
1007
  --sheet-title: var(--text-heading);
1006
1008
  --dialog-scrim: var(--surface-scrim);
1009
+ --image-crop-modal-shade: var(--surface-scrim);
1010
+ --image-crop-modal-selection: var(--text-on-cover);
1011
+ --image-crop-modal-handle: var(--text-on-cover);
1012
+ --image-crop-modal-stage-background: var(--surface-muted);
1007
1013
  }
1008
1014
  }
@@ -11,7 +11,7 @@
11
11
  --colors-accent-default: #ff6a00;
12
12
  --colors-accent-hover: #ff9640;
13
13
  --colors-accent-invert: #ffffff;
14
- --text-heading: #ff6a00;
14
+ --text-heading: #1b2a4a;
15
15
  --text-body: #27272a;
16
16
  --text-link: #006bb5;
17
17
  --surface-page: #f4f4f5;