@rojaostudio/ds 2.0.0-next.2 → 2.0.0-next.20

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.
Files changed (101) hide show
  1. package/README.md +42 -2
  2. package/THIRD_PARTY_NOTICES.md +66 -0
  3. package/dist/components/avatar.d.ts +20 -12
  4. package/dist/components/avatar.js +8 -6
  5. package/dist/components/badge.d.ts +7 -6
  6. package/dist/components/badge.js +2 -1
  7. package/dist/components/breadcrumb.d.ts +4 -4
  8. package/dist/components/breadcrumb.js +1 -1
  9. package/dist/components/bubble.d.ts +26 -11
  10. package/dist/components/bubble.js +3 -3
  11. package/dist/components/button.d.ts +1 -1
  12. package/dist/components/card.d.ts +28 -12
  13. package/dist/components/card.js +4 -2
  14. package/dist/components/chart.d.ts +17 -3
  15. package/dist/components/chart.js +70 -24
  16. package/dist/components/choice-carousel.d.ts +1 -1
  17. package/dist/components/choice-carousel.js +2 -4
  18. package/dist/components/choice-list.d.ts +40 -0
  19. package/dist/components/choice-list.js +122 -0
  20. package/dist/components/choice-preview-card.d.ts +1 -7
  21. package/dist/components/color-input.d.ts +1 -1
  22. package/dist/components/context-menu.d.ts +5 -2
  23. package/dist/components/currency-input.d.ts +0 -2
  24. package/dist/components/data-table-header.d.ts +26 -16
  25. package/dist/components/data-table-header.js +75 -12
  26. package/dist/components/date-picker.d.ts +1 -1
  27. package/dist/components/dialog.d.ts +6 -3
  28. package/dist/components/dialog.js +2 -2
  29. package/dist/components/dropdown-menu.d.ts +5 -2
  30. package/dist/components/dropzone.d.ts +2 -2
  31. package/dist/components/dropzone.js +1 -1
  32. package/dist/components/file-input.d.ts +13 -8
  33. package/dist/components/file-input.js +24 -21
  34. package/dist/components/filter-chip.d.ts +11 -5
  35. package/dist/components/filter-chip.js +15 -6
  36. package/dist/components/floating-stepper.d.ts +11 -28
  37. package/dist/components/floating-stepper.js +2 -30
  38. package/dist/components/heading.d.ts +42 -0
  39. package/dist/components/heading.js +25 -0
  40. package/dist/components/icon-button.d.ts +1 -1
  41. package/dist/components/image-crop-dialog.d.ts +60 -0
  42. package/dist/components/image-crop-dialog.js +240 -0
  43. package/dist/components/image-crop-modal.d.ts +12 -55
  44. package/dist/components/image-crop-modal.js +2 -249
  45. package/dist/components/image-upload.d.ts +8 -17
  46. package/dist/components/image-upload.js +3 -3
  47. package/dist/components/index.d.ts +11 -8
  48. package/dist/components/index.js +8 -0
  49. package/dist/components/internal/button.d.ts +1 -1
  50. package/dist/components/internal/icons.d.ts +11 -1
  51. package/dist/components/internal/icons.js +20 -0
  52. package/dist/components/internal/menu.d.ts +3 -2
  53. package/dist/components/internal/menu.js +1 -1
  54. package/dist/components/internal/modal.js +9 -0
  55. package/dist/components/internal/toggle.d.ts +1 -1
  56. package/dist/components/item.d.ts +14 -7
  57. package/dist/components/item.js +5 -2
  58. package/dist/components/marker.d.ts +11 -3
  59. package/dist/components/marker.js +4 -3
  60. package/dist/components/number-input.d.ts +1 -1
  61. package/dist/components/progress.d.ts +3 -3
  62. package/dist/components/progress.js +2 -2
  63. package/dist/components/row-actions.d.ts +3 -0
  64. package/dist/components/row-actions.js +8 -4
  65. package/dist/components/saving-bar.d.ts +16 -4
  66. package/dist/components/saving-bar.js +37 -9
  67. package/dist/components/section-header.d.ts +4 -3
  68. package/dist/components/selectable-card.d.ts +2 -10
  69. package/dist/components/sidebar.d.ts +8 -11
  70. package/dist/components/sidebar.js +4 -5
  71. package/dist/components/spinner.d.ts +9 -6
  72. package/dist/components/spinner.js +3 -3
  73. package/dist/components/star-rating.d.ts +3 -3
  74. package/dist/components/star-rating.js +2 -2
  75. package/dist/components/stat.d.ts +18 -6
  76. package/dist/components/stat.js +9 -3
  77. package/dist/components/status.d.ts +4 -4
  78. package/dist/components/status.js +2 -2
  79. package/dist/components/stepper.d.ts +33 -0
  80. package/dist/components/stepper.js +36 -0
  81. package/dist/components/summary-bar.d.ts +3 -2
  82. package/dist/components/summary-bar.js +10 -1
  83. package/dist/components/tile.d.ts +5 -5
  84. package/dist/components/tile.js +2 -2
  85. package/dist/components/time-picker.d.ts +1 -1
  86. package/dist/components/toast.d.ts +17 -6
  87. package/dist/components/toast.js +5 -3
  88. package/dist/components/toggle-card-compact.d.ts +6 -25
  89. package/dist/components/toggle-card-compact.js +8 -35
  90. package/dist/components/toggle-card.d.ts +23 -9
  91. package/dist/components/toggle-card.js +38 -2
  92. package/dist/components/toggle.d.ts +1 -1
  93. package/dist/components/typing-indicator.d.ts +2 -2
  94. package/dist/components/typing-indicator.js +1 -1
  95. package/package.json +4 -4
  96. package/styles/base.css +13 -1
  97. package/styles/rds/components-styles.css +593 -172
  98. package/styles/rds/components.css +40 -25
  99. package/styles/rds/foundation.css +1 -1
  100. package/styles/rds/theme.css +40 -29
  101. package/styles/rds.css +1 -1
@@ -30,7 +30,7 @@ interface DatePickerProps extends FieldTextProps {
30
30
  }
31
31
  /**
32
32
  * DatePicker — Figma [RDS] Forms/DatePicker. A date field that takes typing (dd/mm/aaaa, the slashes come by
33
- * themselves) and, from the calendar button, opens the Calendar in a popover (Figma: `menu`). Choosing a day
33
+ * themselves) and, from the calendar button, opens the Calendar in a popover (Figma: `open`). Choosing a day
34
34
  * closes it and gives the focus back to the field; Escape closes without choosing. For a date near today, where
35
35
  * seeing the month helps: a birth date is an Input. Styles: date-picker.css, internal/field.css, calendar.css.
36
36
  */
@@ -2,10 +2,13 @@ import * as _radix_ui_react_dialog from '@radix-ui/react-dialog';
2
2
  import * as react from 'react';
3
3
  import { ModalProps } from './internal/modal.js';
4
4
 
5
- type DialogSize = 'sm' | 'default' | 'lg';
5
+ type DialogSize = 'sm' | 'md' | 'lg';
6
6
  interface DialogProps extends ModalProps {
7
- /** sm 400 (a question with one field), default 560 (a short form), lg 720 (a table or a preview). */
8
- size?: DialogSize;
7
+ /**
8
+ * sm 400 (a question with one field), md 560 (a short form, the default), lg 720 (a table or a preview) (Figma:
9
+ * `size`). `'default'` is deprecated (2.0.0-next): it is `'md'`.
10
+ */
11
+ size?: DialogSize | 'default';
9
12
  }
10
13
  /**
11
14
  * Dialog — Figma [RDS] Overlays/Dialog. A window over the screen for a short task: create, edit (Radix Dialog).
@@ -6,8 +6,8 @@ import {
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { ModalClose, ModalShell } from "./internal/modal.js";
8
8
  function Dialog(_a) {
9
- var _b = _a, { size = "default" } = _b, props = __objRest(_b, ["size"]);
10
- return /* @__PURE__ */ jsx(ModalShell, __spreadValues({ prefix: "rds-dialog", modifiers: [`rds-dialog--${size}`] }, props));
9
+ var _b = _a, { size = "md" } = _b, props = __objRest(_b, ["size"]);
10
+ return /* @__PURE__ */ jsx(ModalShell, __spreadValues({ prefix: "rds-dialog", modifiers: [`rds-dialog--${size === "default" ? "md" : size}`] }, props));
11
11
  }
12
12
  const DialogClose = ModalClose;
13
13
  export {
@@ -30,8 +30,11 @@ declare function DropdownMenu({ trigger, children, align, side, open, defaultOpe
30
30
  interface DropdownMenuItemProps extends MenuItemContentProps {
31
31
  /** Runs when the item is chosen (click, Enter or Space); the menu then closes. A destructive action asks first (AlertDialog). */
32
32
  onSelect?: () => void;
33
- /** danger for what destroys: last, after a separator (Figma: `tone`). */
34
- tone?: DropdownMenuItemTone;
33
+ /**
34
+ * neutral (default), or danger for what destroys: last, after a separator (Figma: `tone`). `'default'` is
35
+ * deprecated (2.0.0-next): it is `'neutral'`.
36
+ */
37
+ tone?: DropdownMenuItemTone | 'default';
35
38
  /** Stays in the list, can't be chosen, and the arrows skip it. */
36
39
  disabled?: boolean;
37
40
  /** The text typing jumps by, when the label is not plain text. */
@@ -2,7 +2,7 @@ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
 
4
4
  /**
5
- * @deprecated Use `<FileInput variant="dropzone">` (Figma [RDS] Forms/FileInput), which has the label, the hint, the
5
+ * @deprecated Use `<FileInput layout="dropzone">` (Figma [RDS] Forms/FileInput), which has the label, the hint, the
6
6
  * error and the chosen file's row. Kept as a thin wrapper so 1.x code keeps compiling.
7
7
  */
8
8
  interface DropzoneProps {
@@ -17,7 +17,7 @@ interface DropzoneProps {
17
17
  'aria-label'?: string;
18
18
  }
19
19
  /**
20
- * @deprecated Use `<FileInput variant="dropzone">`. A drop target only: it hands the files over and stays empty,
20
+ * @deprecated Use `<FileInput layout="dropzone">`. A drop target only: it hands the files over and stays empty,
21
21
  * ready for the next ones, as the 1.x Dropzone did.
22
22
  */
23
23
  declare function Dropzone({ onFiles, accept, multiple, disabled, className, children, 'aria-label': ariaLabel, }: DropzoneProps): react.JSX.Element;
@@ -14,7 +14,7 @@ function Dropzone({
14
14
  return /* @__PURE__ */ jsx(
15
15
  FileInput,
16
16
  {
17
- variant: "dropzone",
17
+ layout: "dropzone",
18
18
  "aria-label": ariaLabel,
19
19
  dropTitle: children,
20
20
  fileName: "",
@@ -2,14 +2,19 @@ import * as react from 'react';
2
2
  import { ComponentPropsWithRef, ReactNode } from 'react';
3
3
  import { FieldTextProps } from './internal/field.js';
4
4
 
5
- type FileInputVariant = 'field' | 'dropzone' | 'tile';
5
+ /** The field's arrangement (Figma: `layout`). */
6
+ type FileInputLayout = 'field' | 'dropzone' | 'tile';
7
+ /** @deprecated Use FileInputLayout (2.0.0-next: `variant` is `layout`). */
8
+ type FileInputVariant = FileInputLayout;
6
9
  interface FileInputProps extends Omit<FieldTextProps, 'labelPosition'>, Omit<ComponentPropsWithRef<'input'>, 'type' | 'children' | 'prefix' | 'value' | 'defaultValue' | 'size'> {
7
10
  /**
8
- * The shape (Figma: `variant`). field (default): the Input's box, for a dense form. dropzone: a dashed area to drop
9
- * the file on, when the file is what the screen is about (a receipt, a spreadsheet). tile: a 112 square with the image's
10
- * preview, for a photo or a logo.
11
+ * The arrangement (Figma: `layout`). field (default): the Input's box, for a dense form. dropzone: a dashed area to
12
+ * drop the file on, when the file is what the screen is about (a receipt, a spreadsheet). tile: a 112 square with
13
+ * the image's preview, for a photo or a logo.
11
14
  */
12
- variant?: FileInputVariant;
15
+ layout?: FileInputLayout;
16
+ /** @deprecated Use `layout` (2.0.0-next): the same three values. */
17
+ variant?: FileInputLayout;
13
18
  /** Controlled: the name shown (Figma: `fileName`). By default, the chosen file's name. */
14
19
  fileName?: string;
15
20
  /** Controlled: the size beside the name in the dropzone (Figma: `fileSize`). By default, the chosen file's, as "1,2 MB". */
@@ -43,7 +48,7 @@ interface FileInputProps extends Omit<FieldTextProps, 'labelPosition'>, Omit<Com
43
48
  /** "1,2 MB", "830 KB", "512 B": the size the way a person reads it. */
44
49
  declare function formatFileSize(bytes: number): string;
45
50
  /**
46
- * FileInput — Figma [RDS] Forms/FileInput. A file field in three shapes (`variant`): field, the Input's box with the
51
+ * FileInput — Figma [RDS] Forms/FileInput. A file field in three layouts (`layout`): field, the Input's box with the
47
52
  * clip, "Escolher arquivo" and the name; dropzone, a dashed area that takes a dragged file; tile, a square with the
48
53
  * image's preview and the buttons to swap or remove it. In every shape the native <input type="file"> does the work:
49
54
  * it lies transparent over the box, so a click, Enter or Space open the system's chooser, the label names it,
@@ -51,6 +56,6 @@ declare function formatFileSize(bytes: number): string;
51
56
  * size in the hint and check them in code (a failure is the errorMessage). Styles: file-input.css and
52
57
  * internal/field.css.
53
58
  */
54
- declare function FileInput({ variant, label, hint, error, errorMessage, required, fileName, fileSize, preview, previewAlt, dropTitle, tileText, clearable, onClear, onFiles, clearLabel, replaceLabel, chooseLabel, emptyLabel, id, disabled, className, style, onChange, ref, ...input }: FileInputProps): react.JSX.Element;
59
+ declare function FileInput({ layout: layoutProp, variant, label, hint, error, errorMessage, required, fileName, fileSize, preview, previewAlt, dropTitle, tileText, clearable, onClear, onFiles, clearLabel, replaceLabel, chooseLabel, emptyLabel, id, disabled, className, style, onChange, ref, ...input }: FileInputProps): react.JSX.Element;
55
60
 
56
- export { FileInput, type FileInputProps, type FileInputVariant, formatFileSize };
61
+ export { FileInput, type FileInputLayout, type FileInputProps, type FileInputVariant, formatFileSize };
@@ -25,7 +25,8 @@ function formatFileSize(bytes) {
25
25
  }
26
26
  function FileInput(_a) {
27
27
  var _b = _a, {
28
- variant = "field",
28
+ layout: layoutProp,
29
+ variant,
29
30
  label,
30
31
  hint,
31
32
  error,
@@ -51,6 +52,7 @@ function FileInput(_a) {
51
52
  onChange,
52
53
  ref
53
54
  } = _b, input = __objRest(_b, [
55
+ "layout",
54
56
  "variant",
55
57
  "label",
56
58
  "hint",
@@ -77,23 +79,24 @@ function FileInput(_a) {
77
79
  "onChange",
78
80
  "ref"
79
81
  ]);
80
- var _a2, _b2, _c;
82
+ var _a2, _b2, _c, _d;
83
+ const layout = (_a2 = layoutProp != null ? layoutProp : variant) != null ? _a2 : "field";
81
84
  warnIfUnlabelled("FileInput", label, input["aria-label"], input["aria-labelledby"]);
82
- const inside = variant === "dropzone";
85
+ const inside = layout === "dropzone";
83
86
  const ids = useFieldIds(id, inside ? void 0 : hint, error, errorMessage);
84
87
  const { controlId, errorId, invalid } = ids;
85
88
  const own = useRef(null);
86
89
  const [chosen, setChosen] = useState(null);
87
90
  const [dragging, setDragging] = useState(false);
88
91
  useEffect(() => () => revoke(chosen), [chosen]);
89
- const shownName = (_a2 = fileName != null ? fileName : chosen == null ? void 0 : chosen.name) != null ? _a2 : "";
92
+ const shownName = (_b2 = fileName != null ? fileName : chosen == null ? void 0 : chosen.name) != null ? _b2 : "";
90
93
  const shownSize = fileSize != null ? fileSize : fileName === void 0 && chosen ? formatFileSize(chosen.size) : void 0;
91
- const shownPreview = (_b2 = preview != null ? preview : chosen == null ? void 0 : chosen.url) != null ? _b2 : "";
92
- const filled = variant === "tile" ? Boolean(shownPreview) : Boolean(shownName);
94
+ const shownPreview = (_c = preview != null ? preview : chosen == null ? void 0 : chosen.url) != null ? _c : "";
95
+ const filled = layout === "tile" ? Boolean(shownPreview) : Boolean(shownName);
93
96
  const showClear = clearable && filled && !disabled;
94
97
  const insideHintId = inside && hasContent(hint) && !filled ? `${controlId}-hint` : void 0;
95
98
  const describedBy = [inside ? insideHintId : ids.hintId, errorId, input["aria-describedby"]].filter(Boolean).join(" ") || void 0;
96
- const removeName = clearLabel != null ? clearLabel : variant === "tile" ? "Remover imagem" : "Remover arquivo";
99
+ const removeName = clearLabel != null ? clearLabel : layout === "tile" ? "Remover imagem" : "Remover arquivo";
97
100
  function change(event) {
98
101
  const files = event.target.files;
99
102
  if (!(files == null ? void 0 : files.length)) {
@@ -101,7 +104,7 @@ function FileInput(_a) {
101
104
  } else {
102
105
  const size = Array.from(files).reduce((sum, file) => sum + file.size, 0);
103
106
  const first = files[0];
104
- const url = variant === "tile" && first.type.startsWith("image/") && typeof URL.createObjectURL === "function" ? URL.createObjectURL(first) : void 0;
107
+ const url = layout === "tile" && first.type.startsWith("image/") && typeof URL.createObjectURL === "function" ? URL.createObjectURL(first) : void 0;
105
108
  setChosen({ name: files.length === 1 ? first.name : `${files.length} arquivos`, size, url });
106
109
  }
107
110
  onChange == null ? void 0 : onChange(event);
@@ -149,14 +152,14 @@ function FileInput(_a) {
149
152
  },
150
153
  onDrop: drop
151
154
  };
152
- const covered = !(variant === "tile" && filled);
155
+ const covered = !(layout === "tile" && filled);
153
156
  const control = /* @__PURE__ */ jsx(
154
157
  "input",
155
158
  __spreadProps(__spreadValues({}, input), {
156
159
  ref: setRef,
157
160
  id: controlId,
158
161
  type: "file",
159
- accept: (_c = input.accept) != null ? _c : variant === "tile" ? "image/*" : void 0,
162
+ accept: (_d = input.accept) != null ? _d : layout === "tile" ? "image/*" : void 0,
160
163
  className: ["rds-field__control", "rds-file-input__control", !covered && "rds-file-input__control--off"].filter(Boolean).join(" "),
161
164
  tabIndex: covered ? input.tabIndex : -1,
162
165
  required,
@@ -168,7 +171,7 @@ function FileInput(_a) {
168
171
  );
169
172
  const clearButton = showClear && /* @__PURE__ */ jsx(FieldAction, { label: removeName, icon: /* @__PURE__ */ jsx(CloseIcon, {}), onClick: clear });
170
173
  let face;
171
- if (variant === "dropzone") {
174
+ if (layout === "dropzone") {
172
175
  face = filled ? /* @__PURE__ */ jsxs("span", { className: "rds-file-input__file", children: [
173
176
  /* @__PURE__ */ jsx("span", { className: "rds-file-input__circle", "aria-hidden": "true", children: /* @__PURE__ */ jsx(PaperclipIcon, {}) }),
174
177
  /* @__PURE__ */ jsxs("span", { className: "rds-file-input__file-texts", "aria-hidden": "true", children: [
@@ -183,7 +186,7 @@ function FileInput(_a) {
183
186
  hasContent(hint) && /* @__PURE__ */ jsx("span", { id: insideHintId, className: "rds-file-input__caption", children: hint })
184
187
  ] })
185
188
  ] });
186
- } else if (variant === "tile") {
189
+ } else if (layout === "tile") {
187
190
  face = filled ? /* @__PURE__ */ jsx("img", { className: "rds-file-input__preview", src: shownPreview, alt: previewAlt != null ? previewAlt : typeof label === "string" ? `Pr\xE9via de ${label}` : "Pr\xE9via" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
188
191
  /* @__PURE__ */ jsx("span", { className: "rds-file-input__tile-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ImagePlusIcon, {}) }),
189
192
  /* @__PURE__ */ jsx("span", { className: "rds-file-input__tile-text", "aria-hidden": "true", children: tileText })
@@ -198,16 +201,16 @@ function FileInput(_a) {
198
201
  ] });
199
202
  }
200
203
  const boxClassName = [
201
- variant === "field" && showClear && "rds-field__box--action",
202
- variant === "dropzone" && "rds-file-input__area",
203
- variant === "tile" && "rds-file-input__area rds-file-input__tile",
204
- variant !== "field" && filled && "rds-file-input__area--filled",
205
- variant !== "field" && dragging && "rds-file-input__area--dragging"
204
+ layout === "field" && showClear && "rds-field__box--action",
205
+ layout === "dropzone" && "rds-file-input__area",
206
+ layout === "tile" && "rds-file-input__area rds-file-input__tile",
207
+ layout !== "field" && filled && "rds-file-input__area--filled",
208
+ layout !== "field" && dragging && "rds-file-input__area--dragging"
206
209
  ].filter(Boolean).join(" ");
207
210
  return /* @__PURE__ */ jsxs(
208
211
  FieldShell,
209
212
  {
210
- kind: `rds-file-input rds-file-input--${variant}`,
213
+ kind: `rds-file-input rds-file-input--${layout}`,
211
214
  controlId,
212
215
  hintId: inside ? void 0 : ids.hintId,
213
216
  errorId,
@@ -218,19 +221,19 @@ function FileInput(_a) {
218
221
  required,
219
222
  disabled,
220
223
  boxClassName: boxClassName || void 0,
221
- boxProps: variant === "field" ? void 0 : boxProps,
224
+ boxProps: layout === "field" ? void 0 : boxProps,
222
225
  className,
223
226
  style,
224
227
  children: [
225
228
  face,
226
229
  control,
227
- variant === "tile" ? filled && !disabled && /* @__PURE__ */ jsxs("span", { className: "rds-file-input__actions", children: [
230
+ layout === "tile" ? filled && !disabled && /* @__PURE__ */ jsxs("span", { className: "rds-file-input__actions", children: [
228
231
  /* @__PURE__ */ jsx(FieldAction, { label: replaceLabel, icon: /* @__PURE__ */ jsx(UploadIcon, {}), onClick: () => {
229
232
  var _a3;
230
233
  return (_a3 = own.current) == null ? void 0 : _a3.click();
231
234
  } }),
232
235
  clearButton
233
- ] }) : variant === "field" && clearButton
236
+ ] }) : layout === "field" && clearButton
234
237
  ]
235
238
  }
236
239
  );
@@ -8,17 +8,23 @@ interface FilterChipProps extends Omit<ComponentPropsWithRef<'button'>, 'childre
8
8
  count?: ReactNode;
9
9
  /** An icon before the label, in the label's colour (Figma: `showIcon` + `icon`). Decorative. */
10
10
  icon?: ReactNode;
11
- /** Controlled: the filter is on (Figma: state=active). */
12
- active?: boolean;
11
+ /** Controlled: the filter is on (Figma: `pressed`), as the Toggle. */
12
+ pressed?: boolean;
13
13
  /** Uncontrolled: on at first. */
14
- defaultActive?: boolean;
14
+ defaultPressed?: boolean;
15
15
  /** Called with the new state when the chip is pressed (a button, not a link). */
16
+ onPressedChange?: (pressed: boolean) => void;
17
+ /** @deprecated Use `pressed` (2.0.0-next). */
18
+ active?: boolean;
19
+ /** @deprecated Use `defaultPressed` (2.0.0-next). */
20
+ defaultActive?: boolean;
21
+ /** @deprecated Use `onPressedChange` (2.0.0-next). */
16
22
  onActiveChange?: (active: boolean) => void;
17
23
  /** Rendered as aria-disabled="true": stays in the tab order and takes focus, but does not turn on or navigate. */
18
24
  disabled?: boolean;
19
25
  /**
20
26
  * Render the single child element (an `<a>`, a framework `Link`) with the chip's classes, for a filter that
21
- * lives in the URL and should survive back/forward. The link gets aria-current when active.
27
+ * lives in the URL and should survive back/forward. The link gets aria-current when pressed.
22
28
  */
23
29
  asChild?: boolean;
24
30
  }
@@ -28,7 +34,7 @@ interface FilterChipProps extends Omit<ComponentPropsWithRef<'button'>, 'childre
28
34
  * brand tint, brand border and label. Up to 5 in a FilterChipGroup; more than that, the Select. A value that can
29
35
  * be removed is the Chip. Styles: filter-chip.css.
30
36
  */
31
- declare function FilterChip({ children, count, icon, active, defaultActive, onActiveChange, disabled, asChild, type, className, onClick, ...rest }: FilterChipProps): react.JSX.Element;
37
+ declare function FilterChip({ children, count, icon, pressed: pressedProp, defaultPressed, onPressedChange, active, defaultActive, onActiveChange, disabled, asChild, type, className, onClick, ...rest }: FilterChipProps): react.JSX.Element;
32
38
  interface FilterChipGroupProps extends HTMLAttributes<HTMLDivElement> {
33
39
  /** Required: what the filters cut, such as "Filtrar por tipo". Several groups on a page must be told apart. */
34
40
  'aria-label': string;
@@ -13,8 +13,11 @@ function FilterChip(_a) {
13
13
  children,
14
14
  count,
15
15
  icon,
16
+ pressed: pressedProp,
17
+ defaultPressed,
18
+ onPressedChange,
16
19
  active,
17
- defaultActive = false,
20
+ defaultActive,
18
21
  onActiveChange,
19
22
  disabled,
20
23
  asChild,
@@ -25,6 +28,9 @@ function FilterChip(_a) {
25
28
  "children",
26
29
  "count",
27
30
  "icon",
31
+ "pressed",
32
+ "defaultPressed",
33
+ "onPressedChange",
28
34
  "active",
29
35
  "defaultActive",
30
36
  "onActiveChange",
@@ -34,20 +40,23 @@ function FilterChip(_a) {
34
40
  "className",
35
41
  "onClick"
36
42
  ]);
37
- const [own, setOwn] = useState(defaultActive);
38
- const on = active != null ? active : own;
43
+ var _a2;
44
+ const pressed = pressedProp != null ? pressedProp : active;
45
+ const [own, setOwn] = useState((_a2 = defaultPressed != null ? defaultPressed : defaultActive) != null ? _a2 : false);
46
+ const on = pressed != null ? pressed : own;
39
47
  const Root = asChild ? Slot : "button";
40
48
  function click(event) {
49
+ var _a3;
41
50
  onClick == null ? void 0 : onClick(event);
42
51
  if (event.defaultPrevented || asChild) return;
43
- if (active === void 0) setOwn(!on);
44
- onActiveChange == null ? void 0 : onActiveChange(!on);
52
+ if (pressed === void 0) setOwn(!on);
53
+ (_a3 = onPressedChange != null ? onPressedChange : onActiveChange) == null ? void 0 : _a3(!on);
45
54
  }
46
55
  return /* @__PURE__ */ jsxs(
47
56
  Root,
48
57
  __spreadProps(__spreadValues({}, rest), {
49
58
  type: asChild ? void 0 : type,
50
- className: ["rds-filter-chip", on && "rds-filter-chip--active", className].filter(Boolean).join(" "),
59
+ className: ["rds-filter-chip", on && "rds-filter-chip--pressed", className].filter(Boolean).join(" "),
51
60
  "aria-pressed": asChild ? void 0 : on,
52
61
  "aria-current": asChild && on ? "true" : void 0,
53
62
  "aria-disabled": disabled || void 0,
@@ -1,33 +1,16 @@
1
- import * as react from 'react';
2
- import { ReactNode } from 'react';
1
+ import { Stepper, StepperProps, StepperStep } from './stepper.js';
2
+ import 'react';
3
3
 
4
4
  /**
5
- * FloatingStepper — a composition of the Card (as a pill) and Buttons (Figma [RDS] Actions/Button, neutral): the
6
- * floating steps of a flow (point of sale, checkout). The current step is the filled Button (aria-current="step");
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.
5
+ * floating-stepper — the 1.x and 2.0-next name of the Stepper, kept so `@rojaostudio/ds/components/floating-stepper`
6
+ * and `FloatingStepper` still work in 2.0. The codemod (`npx @rojaostudio/ds-codemod`) renames both.
9
7
  */
10
- type FloatingStepperStep = {
11
- key: string;
12
- label: string;
13
- };
14
- interface FloatingStepperProps {
15
- steps: FloatingStepperStep[];
16
- /** key da etapa atual */
17
- current: string;
18
- onNavigate?: (key: string) => void;
19
- /** Regra de navegação por etapa. Default: só etapas anteriores à atual. */
20
- canNavigate?: (key: string, index: number, currentIndex: number) => boolean;
21
- /** Ação à direita, separada por divisor (ex.: Reset). */
22
- action?: {
23
- label: string;
24
- icon?: ReactNode;
25
- onClick: () => void;
26
- };
27
- className?: string;
28
- /** The navigation's name. Default "Etapas". */
29
- 'aria-label'?: string;
30
- }
31
- declare function FloatingStepper({ steps, current, onNavigate, canNavigate, action, className, 'aria-label': ariaLabel }: FloatingStepperProps): react.JSX.Element;
8
+
9
+ /** @deprecated Renamed to `Stepper` (`@rojaostudio/ds/components/stepper`) in 2.0. Same props. */
10
+ declare const FloatingStepper: typeof Stepper;
11
+ /** @deprecated Renamed to `StepperProps` in 2.0. */
12
+ type FloatingStepperProps = StepperProps;
13
+ /** @deprecated Renamed to `StepperStep` in 2.0. */
14
+ type FloatingStepperStep = StepperStep;
32
15
 
33
16
  export { FloatingStepper, type FloatingStepperProps, type FloatingStepperStep };
@@ -1,35 +1,7 @@
1
1
  "use client";
2
2
  import "../chunk-ORMEWXMH.js";
3
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- import { Button } from "./button.js";
5
- import { Card } from "./card.js";
6
- function FloatingStepper({ steps, current, onNavigate, canNavigate, action, className, "aria-label": ariaLabel = "Etapas" }) {
7
- const currentIdx = steps.findIndex((s) => s.key === current);
8
- return /* @__PURE__ */ jsxs(Card, { as: "div", size: "sm", role: "navigation", "aria-label": ariaLabel, className: ["rds-floating-stepper", className].filter(Boolean).join(" "), children: [
9
- steps.map((s, idx) => {
10
- const isCurrent = idx === currentIdx;
11
- const canGo = canNavigate ? canNavigate(s.key, idx, currentIdx) : idx < currentIdx;
12
- return /* @__PURE__ */ jsx(
13
- Button,
14
- {
15
- tone: "neutral",
16
- variant: isCurrent ? "fill" : "ghost",
17
- disabled: !canGo && !isCurrent,
18
- "aria-current": isCurrent ? "step" : void 0,
19
- onClick: () => {
20
- if (canGo && !isCurrent) onNavigate == null ? void 0 : onNavigate(s.key);
21
- },
22
- children: s.label
23
- },
24
- s.key
25
- );
26
- }),
27
- action && /* @__PURE__ */ jsxs(Fragment, { children: [
28
- /* @__PURE__ */ jsx("span", { className: "rds-floating-stepper__divider", "aria-hidden": "true" }),
29
- /* @__PURE__ */ jsx(Button, { tone: "neutral", variant: "ghost", icon: action.icon, onClick: action.onClick, children: action.label })
30
- ] })
31
- ] });
32
- }
3
+ import { Stepper } from "./stepper.js";
4
+ const FloatingStepper = Stepper;
33
5
  export {
34
6
  FloatingStepper
35
7
  };
@@ -0,0 +1,42 @@
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
+ /** neutral: text/heading (navy on light in Rojão, white on dark and on the brand plate). accent: the logo orange. */
7
+ type HeadingTone = 'neutral' | '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
+ /**
14
+ * The colour of the brand pair (Figma `tone`): neutral (default) or accent. The Mark takes the other one.
15
+ * `'default'` is deprecated (2.0.0-next): it is `'neutral'`.
16
+ */
17
+ tone?: HeadingTone | 'default';
18
+ /** The heading element. Default h2. */
19
+ as?: HeadingElement;
20
+ /** The text (Figma `text`), with an optional <Heading.Mark> stretch (Figma `showMark` + `mark`). */
21
+ children: ReactNode;
22
+ }
23
+ interface HeadingMarkProps extends HTMLAttributes<HTMLSpanElement> {
24
+ children: ReactNode;
25
+ }
26
+ /**
27
+ * Heading.Mark — Figma [RDS] .heading/mark. A stretch of the title in the other colour of the pair: accent inside a
28
+ * neutral Heading, neutral inside an accent one. A plain span: screen readers read the whole title, unannounced.
29
+ */
30
+ declare function HeadingMark({ className, children, ...rest }: HeadingMarkProps): react.JSX.Element;
31
+ /**
32
+ * Heading — Figma [RDS] Content/Heading. A title in the brand pair: one colour, or both in the same title with a
33
+ * Heading.Mark. The colour is chosen per screen; tone=neutral is the rule. Orange on white fails contrast even for
34
+ * a large title (2.9:1 in Rojão): tone=accent belongs on dark or on the brand plate. Styles: heading.css.
35
+ */
36
+ declare function HeadingRoot({ level, tone, as: Tag, className, children, ...rest }: HeadingProps): react.JSX.Element;
37
+ /** `<Heading>` with `<Heading.Mark>` for the stretch in the other colour. */
38
+ declare const Heading: typeof HeadingRoot & {
39
+ Mark: typeof HeadingMark;
40
+ };
41
+
42
+ 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 = "neutral", 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
+ };
@@ -9,7 +9,7 @@ interface IconButtonProps extends Omit<ComponentPropsWithRef<'button'>, 'childre
9
9
  label: string;
10
10
  /** Same tones as the Button. */
11
11
  tone?: ButtonTone;
12
- /** Figma calls this property `style`. */
12
+ /** The emphasis (Figma: `variant`). */
13
13
  variant?: ButtonVariant;
14
14
  /**
15
15
  * The size of the square (Figma: `size`): sm 36 with a 16 icon, md 44 with a 20 icon (default), lg 52 with a 24
@@ -0,0 +1,60 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * ImageCropDialog — Figma [RDS] Overlays/ImageCropDialog: 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-dialog/*). Styles: image-crop-dialog.css.
8
+ *
9
+ * Uso:
10
+ * <ImageCropDialog
11
+ * open={open}
12
+ * file={selectedFile}
13
+ * onCancel={() => setOpen(false)}
14
+ * onConfirm={(blob) => uploadCroppedImage(blob)}
15
+ * />
16
+ *
17
+ * Presets default: Livre (1:2 a 2:1), 1:1, 4:5, 16:9.
18
+ * Customize via prop `presets`.
19
+ */
20
+ interface CropPreset {
21
+ id: string;
22
+ label: string;
23
+ /** Aspect ratio fixo. undefined = livre (com bounds MIN/MAX_ASPECT). */
24
+ aspect?: number;
25
+ /** Ícone opcional exibido antes do rótulo (ajuda quem não decodifica "16:9"). */
26
+ icon?: React.ReactNode;
27
+ }
28
+ interface ImageCropDialogProps {
29
+ open: boolean;
30
+ file: File | null;
31
+ /** Label de contexto pro título (ex: "Foto 2 de 4"). */
32
+ position?: string;
33
+ onCancel: () => void;
34
+ /**
35
+ * Recebe o blob do recorte. Pode ser assíncrono (ex.: upload) — o modal AGUARDA a promise
36
+ * e mantém o botão travado/carregando até resolver, evitando duplo-clique que duplicaria a
37
+ * imagem (o upload roda fora do `busy` se o modal não esperar).
38
+ */
39
+ onConfirm: (blob: Blob) => void | Promise<void>;
40
+ /** Presets disponíveis. default = Livre + 1:1 + 4:5 + 16:9. */
41
+ presets?: CropPreset[];
42
+ /** Limite mínimo de aspect ratio (alto-baixo). default = 0.5 (1:2). */
43
+ minAspect?: number;
44
+ /** Limite máximo de aspect ratio (largo-baixo). default = 2.0 (2:1). */
45
+ maxAspect?: number;
46
+ /** Título do modal. default = "Ajustar foto". */
47
+ title?: string;
48
+ /** Label do botão confirmar. default = "Aplicar e enviar". */
49
+ confirmLabel?: string;
50
+ /**
51
+ * Teto de tamanho do blob de saída (bytes). Quando definido, a saída do crop
52
+ * é forçada a JPEG e comprimida (qualidade + downscale) até caber no limite —
53
+ * evita que foto de celular grande estoure o limite de upload. Sem ele, a
54
+ * saída mantém o tipo original e qualidade fixa (comportamento inalterado).
55
+ */
56
+ maxSizeBytes?: number;
57
+ }
58
+ declare function ImageCropDialog({ open, file, position, onCancel, onConfirm, presets, minAspect, maxAspect, title, confirmLabel, maxSizeBytes, }: ImageCropDialogProps): react.JSX.Element;
59
+
60
+ export { type CropPreset, ImageCropDialog, type ImageCropDialogProps };