@noya-app/noya-designsystem 0.1.21 → 0.1.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noya-app/noya-designsystem",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -13,9 +13,9 @@
13
13
  "@dnd-kit/core": "3.1.1",
14
14
  "@dnd-kit/modifiers": "3.0.0",
15
15
  "@dnd-kit/sortable": "4.0.0",
16
- "@noya-app/noya-colorpicker": "0.1.9",
17
- "@noya-app/noya-utils": "0.1.1",
18
- "@noya-app/noya-geometry": "0.1.3",
16
+ "@noya-app/noya-colorpicker": "0.1.10",
17
+ "@noya-app/noya-utils": "0.1.2",
18
+ "@noya-app/noya-geometry": "0.1.4",
19
19
  "@noya-app/noya-icons": "0.1.4",
20
20
  "@noya-app/noya-keymap": "0.1.2",
21
21
  "@radix-ui/primitive": "^1.0.0",
@@ -34,6 +34,7 @@
34
34
  "@radix-ui/react-toggle-group": "^1.0.1",
35
35
  "@radix-ui/react-tooltip": "^1.0.2",
36
36
  "@radix-ui/react-utils": "^0.0.5",
37
+ "@radix-ui/react-select": "^2.1.1",
37
38
  "immer": "9.0.5",
38
39
  "kiwi.js": "^1.1.3",
39
40
  "react-resizable-panels": "2.0.22",
@@ -57,10 +57,10 @@ export const ButtonElement = styled.button<{
57
57
  borderRadius: "4px",
58
58
  paddingTop: $variant === "none" ? "0px" : "4px",
59
59
  paddingRight:
60
- $variant === "none" ? "0px" : $variant === "thin" ? "1px" : "8px",
60
+ $variant === "none" ? "0px" : $variant === "thin" ? "1px" : "6px",
61
61
  paddingBottom: $variant === "none" ? "0px" : "4px",
62
62
  paddingLeft:
63
- $variant === "none" ? "0px" : $variant === "thin" ? "1px" : "8px",
63
+ $variant === "none" ? "0px" : $variant === "thin" ? "1px" : "6px",
64
64
  ...($size === "large" && {
65
65
  paddingTop: "12px",
66
66
  paddingRight: "16px",
@@ -1,5 +1,5 @@
1
1
  import { Cross1Icon, PlusIcon } from "@noya-app/noya-icons";
2
- import React, { memo } from "react";
2
+ import React, { forwardRef, memo } from "react";
3
3
  import styled from "styled-components";
4
4
  import { useDesignSystemTheme } from "../contexts/DesignSystemConfiguration";
5
5
  import { useHover } from "../hooks/useHover";
@@ -141,10 +141,13 @@ const AddElement = styled(PlusIcon).withConfig({
141
141
  }));
142
142
 
143
143
  export interface ChipProps {
144
+ id?: string;
145
+ className?: string;
144
146
  colorScheme?: ChipColorScheme;
145
147
  variant?: ChipVariant;
146
148
  size?: ChipSize;
147
149
  children?: React.ReactNode;
150
+ clickable?: boolean;
148
151
  deletable?: boolean;
149
152
  addable?: boolean;
150
153
  monospace?: boolean;
@@ -156,78 +159,87 @@ export interface ChipProps {
156
159
  tabIndex?: number;
157
160
  }
158
161
 
159
- export const Chip = memo(function Chip({
160
- colorScheme,
161
- children,
162
- deletable,
163
- addable,
164
- style,
165
- size = "medium",
166
- variant = "solid",
167
- monospace = false,
168
- tabIndex,
169
- onDelete,
170
- onClick,
171
- onAdd,
172
- onHoverDeleteChange,
173
- }: ChipProps) {
174
- const theme = useDesignSystemTheme();
175
-
176
- const { hoverProps: hoverDeleteProps } = useHover({
177
- onHoverChange: onHoverDeleteChange,
178
- });
179
-
180
- const handleClick = !children && !deletable && addable ? onAdd : onClick;
181
-
182
- const color =
183
- colorScheme === "primary"
184
- ? theme.colors.primary
185
- : colorScheme === "secondary"
186
- ? theme.colors.secondary
187
- : theme.colors.text;
188
-
189
- return (
190
- <ChipElement
191
- $variant={variant}
192
- $colorScheme={colorScheme}
193
- style={style}
194
- onClick={handleClick}
195
- $size={size}
196
- $monospace={monospace}
197
- $isInteractive={!!handleClick}
198
- tabIndex={tabIndex}
199
- >
200
- {addable && (
201
- <AddElement
202
- size={size}
203
- isOnlyChild={!children && !deletable}
204
- onClick={
205
- onAdd
206
- ? (event) => {
207
- event.stopPropagation();
208
- onAdd?.();
209
- }
210
- : undefined
211
- }
212
- color={color}
213
- />
214
- )}
215
- {children}
216
- {deletable && (
217
- <DeleteElement
218
- size={size}
219
- {...(hoverDeleteProps as any)}
220
- onClick={
221
- onDelete
222
- ? (event) => {
223
- event.stopPropagation();
224
- onDelete?.();
225
- }
226
- : undefined
227
- }
228
- color={color}
229
- />
230
- )}
231
- </ChipElement>
232
- );
233
- });
162
+ export const Chip = memo(
163
+ forwardRef(function Chip(
164
+ {
165
+ colorScheme,
166
+ children,
167
+ deletable,
168
+ addable,
169
+ clickable,
170
+ style,
171
+ size = "medium",
172
+ variant = "solid",
173
+ monospace = false,
174
+ tabIndex,
175
+ onDelete,
176
+ onClick,
177
+ onAdd,
178
+ onHoverDeleteChange,
179
+ ...rest
180
+ }: ChipProps,
181
+ forwardedRef: React.ForwardedRef<HTMLSpanElement>
182
+ ) {
183
+ const theme = useDesignSystemTheme();
184
+
185
+ const { hoverProps: hoverDeleteProps } = useHover({
186
+ onHoverChange: onHoverDeleteChange,
187
+ });
188
+
189
+ const handleClick = !children && !deletable && addable ? onAdd : onClick;
190
+
191
+ const color =
192
+ colorScheme === "primary"
193
+ ? theme.colors.primary
194
+ : colorScheme === "secondary"
195
+ ? theme.colors.secondary
196
+ : theme.colors.text;
197
+
198
+ return (
199
+ <ChipElement
200
+ ref={forwardedRef}
201
+ $variant={variant}
202
+ $colorScheme={colorScheme}
203
+ style={style}
204
+ onClick={handleClick}
205
+ $size={size}
206
+ $monospace={monospace}
207
+ $isInteractive={!!handleClick || clickable === true}
208
+ tabIndex={tabIndex}
209
+ {...rest}
210
+ >
211
+ {addable && (
212
+ <AddElement
213
+ size={size}
214
+ isOnlyChild={!children && !deletable}
215
+ onClick={
216
+ onAdd
217
+ ? (event) => {
218
+ event.stopPropagation();
219
+ onAdd?.();
220
+ }
221
+ : undefined
222
+ }
223
+ color={color}
224
+ />
225
+ )}
226
+ {children}
227
+ {deletable && (
228
+ <DeleteElement
229
+ size={size}
230
+ {...(hoverDeleteProps as any)}
231
+ onClick={
232
+ onDelete
233
+ ? (event) => {
234
+ event.stopPropagation();
235
+ onDelete?.();
236
+ }
237
+ : undefined
238
+ }
239
+ color={color}
240
+ />
241
+ )}
242
+ </ChipElement>
243
+ );
244
+ })
245
+ );
@@ -1,15 +1,9 @@
1
- import { CheckIcon, ChevronRightIcon } from '@noya-app/noya-icons';
2
- import { useKeyboardShortcuts } from '@noya-app/noya-keymap';
3
- import * as RadixContextMenu from '@radix-ui/react-context-menu';
4
- import React, {
5
- ReactElement,
6
- ReactNode,
7
- memo,
8
- useCallback,
9
- useMemo,
10
- } from 'react';
11
- import styled from 'styled-components';
12
- import { Spacer } from './Spacer';
1
+ import { CheckIcon, ChevronRightIcon } from "@noya-app/noya-icons";
2
+ import { useKeyboardShortcuts } from "@noya-app/noya-keymap";
3
+ import * as RadixContextMenu from "@radix-ui/react-context-menu";
4
+ import React, { ReactNode, memo, useCallback, useMemo } from "react";
5
+ import styled from "styled-components";
6
+ import { Spacer } from "./Spacer";
13
7
  import {
14
8
  CHECKBOX_RIGHT_INSET,
15
9
  CHECKBOX_WIDTH,
@@ -18,14 +12,14 @@ import {
18
12
  SEPARATOR_ITEM,
19
13
  getKeyboardShortcutsForMenuItems,
20
14
  styles,
21
- } from './internal/Menu';
15
+ } from "./internal/Menu";
22
16
 
23
17
  /* ----------------------------------------------------------------------------
24
18
  * Separator
25
19
  * ------------------------------------------------------------------------- */
26
20
 
27
21
  const SeparatorElement = styled(RadixContextMenu.Separator)(
28
- styles.separatorStyle,
22
+ styles.separatorStyle
29
23
  );
30
24
 
31
25
  /* ----------------------------------------------------------------------------
@@ -35,11 +29,11 @@ const SeparatorElement = styled(RadixContextMenu.Separator)(
35
29
  const ItemElement = styled(RadixContextMenu.Item)(styles.itemStyle);
36
30
 
37
31
  const CheckboxItemElement = styled(RadixContextMenu.CheckboxItem)(
38
- styles.itemStyle,
32
+ styles.itemStyle
39
33
  );
40
34
 
41
35
  const StyledItemIndicator = styled(RadixContextMenu.ItemIndicator)(
42
- styles.itemIndicatorStyle,
36
+ styles.itemIndicatorStyle
43
37
  );
44
38
 
45
39
  export interface MenuItemProps<T extends string> {
@@ -50,7 +44,7 @@ export interface MenuItemProps<T extends string> {
50
44
  disabled: boolean;
51
45
  indented: boolean;
52
46
  shortcut?: string;
53
- icon?: ReactElement;
47
+ icon?: ReactNode;
54
48
  items?: MenuItem<T>[];
55
49
  }
56
50
 
@@ -69,7 +63,7 @@ const ContextMenuItem = memo(function ContextMenuItem<T extends string>({
69
63
  // context menu unless we stop it here.
70
64
  const handlePointerDown = useCallback(
71
65
  (event: React.PointerEvent) => event.stopPropagation(),
72
- [],
66
+ []
73
67
  );
74
68
 
75
69
  const handleSelectItem = useCallback(() => {
@@ -162,7 +156,7 @@ function ContextMenuRoot<T extends string>({
162
156
  onOpenChange,
163
157
  }: MenuProps<T>) {
164
158
  const hasCheckedItem = items.some(
165
- (item) => item !== SEPARATOR_ITEM && item.checked,
159
+ (item) => item !== SEPARATOR_ITEM && item.checked
166
160
  );
167
161
 
168
162
  const keymap = useMemo(
@@ -170,7 +164,7 @@ function ContextMenuRoot<T extends string>({
170
164
  isNested || shouldBindKeyboardShortcuts === false
171
165
  ? {}
172
166
  : getKeyboardShortcutsForMenuItems(items, onSelect),
173
- [isNested, items, onSelect, shouldBindKeyboardShortcuts],
167
+ [isNested, items, onSelect, shouldBindKeyboardShortcuts]
174
168
  );
175
169
 
176
170
  useKeyboardShortcuts(keymap);
@@ -213,7 +207,7 @@ function ContextMenuRoot<T extends string>({
213
207
  >
214
208
  {item.title}
215
209
  </ContextMenuItem>
216
- ),
210
+ )
217
211
  )}
218
212
  </ContentComponent>
219
213
  </RadixContextMenu.Portal>
@@ -15,6 +15,7 @@ import React, {
15
15
  useLayoutEffect,
16
16
  useMemo,
17
17
  useRef,
18
+ useState,
18
19
  } from "react";
19
20
  import styled from "styled-components";
20
21
  import handleNudge from "../utils/handleNudge";
@@ -431,10 +432,15 @@ function parseNumber(value: string) {
431
432
  }
432
433
 
433
434
  function InputFieldNumberInput(props: InputFieldNumberInputProps) {
434
- const { value, placeholder, onNudge, ...rest } = props;
435
+ const { value, placeholder, onNudge, onBlur, ...rest } = props;
435
436
  const onSubmit = "onSubmit" in props ? props.onSubmit : undefined;
436
437
  const onChange = "onChange" in props ? props.onChange : undefined;
437
438
 
439
+ // Internal value is used to handle empty string as a valid state,
440
+ // e.g. when the user deletes the value before entering a new one.
441
+ // This is only used for in the onChange case.
442
+ const [internalValue, setInternalValue] = useState<string | undefined>();
443
+
438
444
  const handleSubmit = useCallback(
439
445
  (value: string) => {
440
446
  const newValue = parseNumber(value);
@@ -453,6 +459,7 @@ function InputFieldNumberInput(props: InputFieldNumberInputProps) {
453
459
  if (!amount) return;
454
460
 
455
461
  onNudge?.(amount);
462
+ setInternalValue(undefined);
456
463
 
457
464
  event.preventDefault();
458
465
  event.stopPropagation();
@@ -462,17 +469,48 @@ function InputFieldNumberInput(props: InputFieldNumberInputProps) {
462
469
 
463
470
  const handleChange = useCallback(
464
471
  (value: string) => {
465
- onChange?.(parseNumber(value));
472
+ if (value === "" || value === "-" || value === ".") {
473
+ setInternalValue(value);
474
+ return;
475
+ }
476
+
477
+ if (value.endsWith(".")) {
478
+ setInternalValue(value);
479
+ return;
480
+ }
481
+
482
+ setInternalValue(undefined);
483
+
484
+ const newValue = parseNumber(value);
485
+
486
+ if (!isNaN(newValue)) {
487
+ onChange?.(newValue);
488
+ }
466
489
  },
467
490
  [onChange]
468
491
  );
469
492
 
493
+ const handleBlur = useCallback(
494
+ (event: React.FocusEvent<HTMLInputElement>) => {
495
+ setInternalValue(undefined);
496
+ onBlur?.(event);
497
+ },
498
+ [onBlur]
499
+ );
500
+
470
501
  return (
471
502
  <InputFieldInput
472
503
  {...rest}
473
- value={value === undefined ? "" : String(value)}
504
+ value={
505
+ internalValue !== undefined
506
+ ? String(internalValue)
507
+ : value === undefined
508
+ ? ""
509
+ : String(value)
510
+ }
474
511
  placeholder={placeholder}
475
512
  onKeyDown={handleKeyDown}
513
+ onBlur={handleBlur}
476
514
  {...("onChange" in props
477
515
  ? { onChange: handleChange }
478
516
  : { onSubmit: handleSubmit })}
@@ -505,6 +543,8 @@ interface InputFieldRootProps {
505
543
  size?: InputFieldSize;
506
544
  renderPopoverContent?: (options: { width: number }) => ReactNode;
507
545
  onFocusChange?: (isFocused: boolean) => void;
546
+ style?: React.CSSProperties;
547
+ className?: string;
508
548
  }
509
549
 
510
550
  function InputFieldRoot({
@@ -517,6 +557,8 @@ function InputFieldRoot({
517
557
  size = "medium",
518
558
  renderPopoverContent,
519
559
  onFocusChange,
560
+ style,
561
+ className,
520
562
  }: InputFieldRootProps) {
521
563
  const childrenArray = Children.toArray(children);
522
564
 
@@ -579,7 +621,13 @@ function InputFieldRoot({
579
621
  );
580
622
 
581
623
  const rootElement = (
582
- <RootContainer id={id} $width={width} $flex={flex}>
624
+ <RootContainer
625
+ id={id}
626
+ $width={width}
627
+ $flex={flex}
628
+ style={style}
629
+ className={className}
630
+ >
583
631
  {children}
584
632
  </RootContainer>
585
633
  );
@@ -333,6 +333,13 @@ interface ListViewRowProps<MenuItemType extends string = string> {
333
333
  onMenuOpenChange?: (isOpen: boolean) => void;
334
334
  onKeyDown?: (event: React.KeyboardEvent) => void;
335
335
  style?: CSSProperties;
336
+ dragIndicatorStyle?:
337
+ | CSSProperties
338
+ | ((props: {
339
+ depth: number;
340
+ indentation: number;
341
+ position: RelativeDropPosition;
342
+ }) => CSSProperties);
336
343
  }
337
344
 
338
345
  const ListViewRow = forwardRef(function ListViewRow<
@@ -359,6 +366,7 @@ const ListViewRow = forwardRef(function ListViewRow<
359
366
  onMenuOpenChange,
360
367
  onKeyDown,
361
368
  style,
369
+ dragIndicatorStyle,
362
370
  }: ListViewRowProps<MenuItemType>,
363
371
  forwardedRef: ForwardedRef<HTMLElement>
364
372
  ) {
@@ -461,7 +469,16 @@ const ListViewRow = forwardRef(function ListViewRow<
461
469
  $colorScheme={colorScheme}
462
470
  $relativeDropPosition={relativeDropPosition}
463
471
  $offsetLeft={33 + depth * indentation}
464
- $gap={listGap}
472
+ $gap={listGap + (divider ? 1 : 0)}
473
+ style={
474
+ typeof dragIndicatorStyle === "function"
475
+ ? dragIndicatorStyle({
476
+ depth,
477
+ indentation,
478
+ position: relativeDropPosition,
479
+ })
480
+ : dragIndicatorStyle
481
+ }
465
482
  />
466
483
  )}
467
484
  {depth > 0 && <Spacer.Horizontal size={depth * indentation} />}
@@ -676,6 +693,9 @@ type ListViewVariant = "normal" | "padded" | "bare";
676
693
  type ListViewSectionHeaderVariant = "normal" | "label";
677
694
 
678
695
  type ListViewRootProps = {
696
+ id?: string;
697
+ className?: string;
698
+ style?: CSSProperties;
679
699
  onPress?: () => void;
680
700
  scrollable?: boolean;
681
701
  expandable?: boolean;
@@ -696,6 +716,9 @@ type ListViewRootProps = {
696
716
 
697
717
  const ListViewRootInner = forwardRef(function ListViewRootInner<T>(
698
718
  {
719
+ id,
720
+ className,
721
+ style,
699
722
  onPress,
700
723
  scrollable = false,
701
724
  expandable = true,
@@ -895,6 +918,9 @@ const ListViewRootInner = forwardRef(function ListViewRootInner<T>(
895
918
  return (
896
919
  <DraggingContext.Provider value={draggingContextValue}>
897
920
  <RootContainer
921
+ id={id}
922
+ className={className}
923
+ style={style}
898
924
  {...{
899
925
  [pressEventName]: handleClick,
900
926
  }}
@@ -93,12 +93,12 @@ export function Popover({
93
93
  collisionPadding={8}
94
94
  arrowPadding={2}
95
95
  // Don't propagate pointer down events to the canvas
96
- onPointerDown={(event) => {
97
- event.stopPropagation();
98
- }}
99
- onWheel={(event) => {
100
- event.stopPropagation();
101
- }}
96
+ // onPointerDown={(event) => {
97
+ // event.stopPropagation();
98
+ // }}
99
+ // onWheel={(event) => {
100
+ // event.stopPropagation();
101
+ // }}
102
102
  >
103
103
  {children}
104
104
  {showArrow && <ArrowElement />}
@@ -77,7 +77,7 @@ const SelectElement = styled.select<{ $flex: CSSProperties["flex"] }>(
77
77
  borderRadius: "4px",
78
78
  paddingTop: "4px",
79
79
  paddingBottom: "4px",
80
- paddingLeft: "8px",
80
+ paddingLeft: "6px",
81
81
  paddingRight: "23px",
82
82
  background: [
83
83
  `calc(100% - 6px) / 15px url("data:image/svg+xml;utf8,${createChevronSVGString(
@@ -120,7 +120,7 @@ type Props<T extends string> = ChildrenProps<T> & {
120
120
  id: string;
121
121
  flex?: CSSProperties["flex"];
122
122
  value: T;
123
- label?: string;
123
+ label?: ReactNode;
124
124
  };
125
125
 
126
126
  export const Select = memo(function Select<T extends string>({
@@ -0,0 +1,100 @@
1
+ import { DropdownChevronIcon } from "@noya-app/noya-icons";
2
+ import * as Select from "@radix-ui/react-select";
3
+ import React, { memo } from "react";
4
+ import { styled } from "styled-components";
5
+ import { Button } from "./Button";
6
+ import { Spacer } from "./Spacer";
7
+ import { MenuItem, RegularMenuItem, styles } from "./internal/Menu";
8
+
9
+ type Props<T extends string> = {
10
+ id?: string;
11
+ style?: React.CSSProperties;
12
+ className?: string;
13
+ menuItems: MenuItem<T>[];
14
+ value: T;
15
+ onSelect?: (value: T) => void;
16
+ placeholder?: string;
17
+ };
18
+
19
+ export const SelectMenu = memo(function SelectMenu<T extends string = string>({
20
+ id,
21
+ style,
22
+ className,
23
+ menuItems,
24
+ value,
25
+ onSelect,
26
+ placeholder,
27
+ }: Props<T>) {
28
+ const selectedItem = menuItems.find(
29
+ (item): item is RegularMenuItem<T> =>
30
+ typeof item !== "string" && item.value === value
31
+ );
32
+ const icon = selectedItem?.icon;
33
+
34
+ return (
35
+ <Select.Root value={value} onValueChange={onSelect}>
36
+ <Select.SelectTrigger asChild>
37
+ <Button id={id} style={style} className={className}>
38
+ {icon && (
39
+ <>
40
+ {icon}
41
+ <Spacer.Horizontal size={8} />
42
+ </>
43
+ )}
44
+ <Select.Value placeholder={placeholder} />
45
+ <Spacer.Horizontal />
46
+ <DropdownChevronIcon />
47
+ </Button>
48
+ </Select.SelectTrigger>
49
+ <Select.Portal>
50
+ <SelectContent>
51
+ <SelectViewport>
52
+ {menuItems.map((menuItem) => {
53
+ if (typeof menuItem === "string") {
54
+ return <StyledSeparator />;
55
+ }
56
+
57
+ const value = menuItem.value ?? "";
58
+
59
+ return (
60
+ <SelectItem key={value} value={value} icon={menuItem.icon}>
61
+ {menuItem.title ?? value}
62
+ </SelectItem>
63
+ );
64
+ })}
65
+ </SelectViewport>
66
+ </SelectContent>
67
+ </Select.Portal>
68
+ </Select.Root>
69
+ );
70
+ });
71
+
72
+ const SelectContent = styled(Select.Content)(styles.contentStyle);
73
+
74
+ const SelectViewport = styled(Select.Viewport)({});
75
+
76
+ const SelectItem = React.forwardRef(
77
+ (
78
+ {
79
+ children,
80
+ icon,
81
+ ...props
82
+ }: Select.SelectItemProps & { icon?: React.ReactNode },
83
+ forwardedRef: React.ForwardedRef<HTMLDivElement>
84
+ ) => {
85
+ return (
86
+ <StyledItem {...props} ref={forwardedRef}>
87
+ {icon && (
88
+ <>
89
+ {icon}
90
+ <Spacer.Horizontal size={8} />
91
+ </>
92
+ )}
93
+ <Select.ItemText>{children}</Select.ItemText>
94
+ </StyledItem>
95
+ );
96
+ }
97
+ );
98
+
99
+ const StyledItem = styled(Select.Item)(styles.itemStyle);
100
+ const StyledSeparator = styled(Select.Separator)(styles.separatorStyle);
@@ -89,7 +89,17 @@ const Element = styled.div<{
89
89
  }));
90
90
 
91
91
  const StackBase = forwardRef(function StackBase(
92
- { id, as, children, separator, breakpoints, tabIndex, href, ...rest }: Props,
92
+ {
93
+ id,
94
+ className,
95
+ as,
96
+ children,
97
+ separator,
98
+ breakpoints,
99
+ tabIndex,
100
+ href,
101
+ ...rest
102
+ }: Props,
93
103
  forwardedRef: ForwardedRef<HTMLElement>
94
104
  ) {
95
105
  const elements = separator
@@ -107,6 +117,7 @@ const StackBase = forwardRef(function StackBase(
107
117
  <Element
108
118
  ref={forwardedRef as any}
109
119
  id={id}
120
+ className={className}
110
121
  as={as}
111
122
  $styleProps={styleProps}
112
123
  $breakpoints={breakpoints}