@ttoss/ui 3.1.6 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -256,117 +256,172 @@ import { Text } from "theme-ui";
256
256
  // src/components/Select.tsx
257
257
  import * as React4 from "react";
258
258
  import { Icon as Icon5 } from "@ttoss/react-icons";
259
- import { Select as SelectUi } from "theme-ui";
260
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
261
- var Select = /*#__PURE__*/React4.forwardRef(({
262
- arrow,
263
- sx,
264
- leadingIcon,
265
- trailingIcon,
259
+ import ReactSelect, { components } from "react-select";
260
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
261
+ var Control = props => {
262
+ const isDisabled = props.selectProps.isDisabled;
263
+ const hasError = props.selectProps["aria-invalid"] === "true";
264
+ const border = (() => {
265
+ if (isDisabled) {
266
+ return "muted";
267
+ }
268
+ if (hasError) {
269
+ return "danger";
270
+ }
271
+ return "interaction";
272
+ })();
273
+ const backgroundColor = (() => {
274
+ if (isDisabled) {
275
+ return "muted";
276
+ }
277
+ return "surface";
278
+ })();
279
+ return /* @__PURE__ */jsx7(Box, {
280
+ sx: {
281
+ ".react-select__control": {
282
+ border,
283
+ backgroundColor,
284
+ paddingX: "xl",
285
+ paddingY: "lg",
286
+ borderRadius: "action"
287
+ }
288
+ },
289
+ children: /* @__PURE__ */jsx7(components.Control, {
290
+ ...props
291
+ })
292
+ });
293
+ };
294
+ var DropdownIndicator = props => {
295
+ const isDisabled = props.selectProps.isDisabled;
296
+ const color = (() => {
297
+ if (isDisabled) {
298
+ return "onMuted";
299
+ }
300
+ return "text";
301
+ })();
302
+ return /* @__PURE__ */jsx7(Text, {
303
+ sx: {
304
+ fontSize: "base",
305
+ color,
306
+ alignSelf: "center",
307
+ display: "flex",
308
+ alignItems: "center"
309
+ },
310
+ children: /* @__PURE__ */jsx7(Icon5, {
311
+ icon: "picker-down"
312
+ })
313
+ });
314
+ };
315
+ var IndicatorsContainer = ({
316
+ children,
317
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
266
318
  ...props
267
- }, ref) => {
268
- const hasError = props["aria-invalid"] === "true";
269
- const refEl = React4.useRef({});
270
- React4.useImperativeHandle(ref, () => {
271
- return refEl.current;
319
+ }) => {
320
+ return /* @__PURE__ */jsx7(Box, {
321
+ sx: {
322
+ marginLeft: "lg",
323
+ border: "none"
324
+ },
325
+ children
326
+ });
327
+ };
328
+ var Placeholder = ({
329
+ children
330
+ }) => {
331
+ return /* @__PURE__ */jsx7(Text, {
332
+ sx: {
333
+ color: "onMuted",
334
+ alignSelf: "center"
335
+ },
336
+ children
337
+ });
338
+ };
339
+ var SelectContainer = ({
340
+ children,
341
+ ...props
342
+ }) => {
343
+ const {
344
+ sx,
345
+ css: css2
346
+ } = props.selectProps;
347
+ return /* @__PURE__ */jsx7(Box, {
348
+ sx,
349
+ css: css2,
350
+ children: /* @__PURE__ */jsx7(components.SelectContainer, {
351
+ ...props,
352
+ children
353
+ })
272
354
  });
273
- React4.useEffect(() => {
274
- const parentEl = refEl.current?.parentElement;
275
- if (parentEl) {
276
- parentEl.style.position = "relative";
355
+ };
356
+ var ValueContainer = ({
357
+ children,
358
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
359
+ ...props
360
+ }) => {
361
+ const {
362
+ leadingIcon,
363
+ trailingIcon
364
+ } = props.selectProps;
365
+ const hasError = props.selectProps["aria-invalid"] === "true";
366
+ const trailingIconColor = (() => {
367
+ if (hasError) {
368
+ return "danger";
277
369
  }
278
- }, []);
279
- return /* @__PURE__ */jsx7(SelectUi, {
280
- arrow: /* @__PURE__ */jsxs6(Fragment2, {
281
- children: [leadingIcon && /* @__PURE__ */jsx7(Text, {
282
- sx: {
283
- alignSelf: "center",
284
- pointerEvents: "none",
285
- lineHeight: 0,
286
- fontSize: "base",
287
- position: "absolute",
288
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
289
- left: ({
290
- space
291
- }) => {
292
- const leftSpaceValue = space?.["xl"] || "16px";
293
- return leftSpaceValue;
294
- }
295
- },
296
- children: /* @__PURE__ */jsx7(Icon5, {
297
- icon: leadingIcon
298
- })
299
- }), /* @__PURE__ */jsxs6(Flex, {
300
- sx: {
301
- gap: "lg",
302
- position: "absolute",
303
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
304
- right: ({
305
- space
306
- }) => {
307
- const xlSpace = space?.["xl"] || "16px";
308
- return xlSpace;
309
- },
310
- alignSelf: "center",
311
- pointerEvents: "none"
312
- },
313
- children: [(trailingIcon || hasError) && /* @__PURE__ */jsx7(Text, {
314
- className: hasError ? "error-icon" : "",
315
- sx: {
316
- alignSelf: "center",
317
- pointerEvents: "none",
318
- lineHeight: 0,
319
- fontSize: "base"
320
- },
321
- children: /* @__PURE__ */jsx7(Icon5, {
322
- icon: hasError ? "warning-alt" : trailingIcon
323
- })
324
- }), arrow ?? /* @__PURE__ */jsx7(Text, {
325
- sx: {
326
- lineHeight: 0,
327
- fontSize: "base"
328
- },
329
- children: /* @__PURE__ */jsx7(Icon5, {
330
- icon: "picker-down"
331
- })
332
- })]
333
- })]
334
- }),
370
+ return "text";
371
+ })();
372
+ return /* @__PURE__ */jsxs6(Flex, {
335
373
  sx: {
336
- fontFamily: "body",
337
- width: "100%",
338
- paddingY: "lg",
339
- paddingX: "xl",
340
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
341
- paddingLeft: ({
342
- space,
343
- fontSizes
344
- }) => {
345
- const xlSpace = space?.["xl"] || "16px";
346
- const iconSize = fontSizes?.["base"] || "16px";
347
- const lgSpace = space?.["lg"] || "16px";
348
- if (leadingIcon) {
349
- return `calc(${xlSpace} + ${iconSize} + ${lgSpace})`;
350
- }
351
- return xlSpace;
374
+ gap: "lg",
375
+ flex: 1
376
+ },
377
+ children: [leadingIcon && /* @__PURE__ */jsx7(Text, {
378
+ sx: {
379
+ alignSelf: "center",
380
+ pointerEvents: "none",
381
+ lineHeight: 0,
382
+ fontSize: "base"
352
383
  },
353
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
354
- paddingRight: ({
355
- space,
356
- fontSizes
357
- }) => {
358
- const xlSpace = space?.["xl"] || "16px";
359
- const iconSize = fontSizes?.["base"] || "16px";
360
- const lgSpace = space?.["lg"] || "16px";
361
- if (trailingIcon || hasError) {
362
- return `calc(${lgSpace} + ${iconSize} + ${lgSpace} + ${iconSize} + ${xlSpace})`;
363
- }
364
- return `calc(${lgSpace} + ${iconSize} + ${xlSpace})`;
384
+ children: /* @__PURE__ */jsx7(Icon5, {
385
+ icon: leadingIcon
386
+ })
387
+ }), /* @__PURE__ */jsx7(Flex, {
388
+ sx: {
389
+ flex: 1,
390
+ alignItems: "center"
365
391
  },
366
- ...sx
392
+ children
393
+ }), (trailingIcon || hasError) && /* @__PURE__ */jsx7(Text, {
394
+ className: hasError ? "error-icon" : "",
395
+ sx: {
396
+ alignSelf: "center",
397
+ pointerEvents: "none",
398
+ lineHeight: 0,
399
+ fontSize: "base",
400
+ color: trailingIconColor
401
+ },
402
+ children: /* @__PURE__ */jsx7(Icon5, {
403
+ icon: hasError ? "warning-alt" : trailingIcon
404
+ })
405
+ })]
406
+ });
407
+ };
408
+ var Select = /*#__PURE__*/React4.forwardRef(({
409
+ ...props
410
+ }, ref) => {
411
+ return /* @__PURE__ */jsx7(ReactSelect, {
412
+ ref,
413
+ components: {
414
+ Control,
415
+ DropdownIndicator,
416
+ IndicatorsContainer,
417
+ Placeholder,
418
+ SelectContainer,
419
+ ValueContainer,
420
+ ...props.components
367
421
  },
368
- ref: refEl,
369
- ...props
422
+ isDisabled: props.disabled,
423
+ ...props,
424
+ classNamePrefix: "react-select"
370
425
  });
371
426
  });
372
427
  Select.displayName = "Select";
package/dist/index.d.mts CHANGED
@@ -1,11 +1,15 @@
1
1
  import * as theme_ui from 'theme-ui';
2
- import { Theme, BadgeProps as BadgeProps$1, ButtonProps as ButtonProps$1, InputProps as InputProps$1, LabelProps as LabelProps$1, LinkProps as LinkProps$1, SelectProps as SelectProps$1, IconButtonProps, TextareaProps as TextareaProps$1, TextProps, FlexProps } from 'theme-ui';
3
- export { BaseStyles, Box, BoxProps, Card, CardProps, Checkbox, CheckboxProps, ContainerProps, Divider, DividerProps, Flex, FlexProps, Global, Grid, GridProps, Heading, HeadingProps, IconButtonProps, Image, ImageProps, Progress as LinearProgress, ProgressProps as LinearProgressProps, Paragraph, ParagraphProps, Radio, RadioProps, Slider, SliderProps, Spinner, SpinnerProps, SxProp, Text, TextProps, Theme } from 'theme-ui';
2
+ import { Theme, BadgeProps as BadgeProps$1, ButtonProps as ButtonProps$1, InputProps as InputProps$1, LabelProps as LabelProps$1, LinkProps as LinkProps$1, SxProp, IconButtonProps, TextareaProps as TextareaProps$1, TextProps, FlexProps } from 'theme-ui';
3
+ export { BaseStyles, Box, BoxProps, Card, CardProps, Checkbox, CheckboxProps, ContainerProps, Divider, DividerProps, Flex, FlexProps, Global, Grid, GridProps, Heading, HeadingProps, IconButtonProps, Image, ImageProps, Progress as LinearProgress, ProgressProps as LinearProgressProps, Paragraph, ParagraphProps, Radio, RadioProps, Slider, SliderProps, Spinner, SpinnerProps, SxProp, Text, TextProps, Theme, ThemeUIStyleObject } from 'theme-ui';
4
4
  export { useBreakpointIndex, useResponsiveValue } from '@theme-ui/match-media';
5
5
  export { Keyframes, keyframes } from '@emotion/react';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
  import * as React from 'react';
8
8
  import { IconType } from '@ttoss/react-icons';
9
+ import * as react_select_dist_declarations_src_useStateManager from 'react-select/dist/declarations/src/useStateManager';
10
+ import * as react_select_dist_declarations_src_Select from 'react-select/dist/declarations/src/Select';
11
+ import * as react_select from 'react-select';
12
+ import { Props } from 'react-select';
9
13
 
10
14
  type ThemeProviderProps = {
11
15
  children?: React.ReactNode;
@@ -50,11 +54,28 @@ type LinkProps = LinkProps$1 & {
50
54
  };
51
55
  declare const Link: React.ForwardRefExoticComponent<Omit<LinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
52
56
 
53
- type SelectProps = SelectProps$1 & {
57
+ type SelectOption = {
58
+ label: string;
59
+ value: string | number;
60
+ };
61
+ type SelectOptions = SelectOption[];
62
+ /**
63
+ * TODO: remove this when we accept multi select.
64
+ */
65
+ type IsMulti = false;
66
+ type SelectProps = Props<SelectOption, IsMulti> & SxProp & {
67
+ disabled?: boolean;
54
68
  leadingIcon?: IconType;
55
69
  trailingIcon?: IconType;
56
70
  };
57
- declare const Select: React.ForwardRefExoticComponent<Omit<SelectProps, "ref"> & React.RefAttributes<HTMLSelectElement>>;
71
+ /**
72
+ * https://react-select.com/home
73
+ */
74
+ declare const Select: React.ForwardRefExoticComponent<Omit<react_select_dist_declarations_src_Select.PublicBaseSelectProps<SelectOption, false, react_select.GroupBase<SelectOption>>, "onChange" | "value" | "inputValue" | "menuIsOpen" | "onInputChange" | "onMenuOpen" | "onMenuClose"> & Partial<react_select_dist_declarations_src_Select.PublicBaseSelectProps<SelectOption, false, react_select.GroupBase<SelectOption>>> & react_select_dist_declarations_src_useStateManager.StateManagerAdditionalProps<SelectOption> & SxProp & {
75
+ disabled?: boolean | undefined;
76
+ leadingIcon?: IconType | undefined;
77
+ trailingIcon?: IconType | undefined;
78
+ } & React.RefAttributes<any>>;
58
79
 
59
80
  declare const IconButton: React.ForwardRefExoticComponent<Omit<IconButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
60
81
 
@@ -104,4 +125,4 @@ type ActionButtonProps = Omit<ButtonProps, 'rightIcon' | 'leftIcon' | 'variant'>
104
125
  };
105
126
  declare const ActionButton: ({ icon, variant, sx, ...props }: ActionButtonProps) => react_jsx_runtime.JSX.Element;
106
127
 
107
- export { ActionButton, ActionButtonProps, Badge, BadgeProps, Button, ButtonProps, CloseButton, CloseButtonProps, Container, HelpText, HelpTextProps, IconButton, InfiniteLinearProgress, Input, InputNumber, InputNumberProps, InputPassword, InputPasswordProps, InputProps, Label, LabelProps, Link, LinkProps, Select, SelectProps, Stack, StackProps, Textarea, TextareaProps, ThemeProvider, ThemeProviderProps, useTheme };
128
+ export { ActionButton, ActionButtonProps, Badge, BadgeProps, Button, ButtonProps, CloseButton, CloseButtonProps, Container, HelpText, HelpTextProps, IconButton, InfiniteLinearProgress, Input, InputNumber, InputNumberProps, InputPassword, InputPasswordProps, InputProps, Label, LabelProps, Link, LinkProps, Select, SelectOption, SelectOptions, SelectProps, Stack, StackProps, Textarea, TextareaProps, ThemeProvider, ThemeProviderProps, useTheme };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  import * as theme_ui from 'theme-ui';
2
- import { Theme, BadgeProps as BadgeProps$1, ButtonProps as ButtonProps$1, InputProps as InputProps$1, LabelProps as LabelProps$1, LinkProps as LinkProps$1, SelectProps as SelectProps$1, IconButtonProps, TextareaProps as TextareaProps$1, TextProps, FlexProps } from 'theme-ui';
3
- export { BaseStyles, Box, BoxProps, Card, CardProps, Checkbox, CheckboxProps, ContainerProps, Divider, DividerProps, Flex, FlexProps, Global, Grid, GridProps, Heading, HeadingProps, IconButtonProps, Image, ImageProps, Progress as LinearProgress, ProgressProps as LinearProgressProps, Paragraph, ParagraphProps, Radio, RadioProps, Slider, SliderProps, Spinner, SpinnerProps, SxProp, Text, TextProps, Theme } from 'theme-ui';
2
+ import { Theme, BadgeProps as BadgeProps$1, ButtonProps as ButtonProps$1, InputProps as InputProps$1, LabelProps as LabelProps$1, LinkProps as LinkProps$1, SxProp, IconButtonProps, TextareaProps as TextareaProps$1, TextProps, FlexProps } from 'theme-ui';
3
+ export { BaseStyles, Box, BoxProps, Card, CardProps, Checkbox, CheckboxProps, ContainerProps, Divider, DividerProps, Flex, FlexProps, Global, Grid, GridProps, Heading, HeadingProps, IconButtonProps, Image, ImageProps, Progress as LinearProgress, ProgressProps as LinearProgressProps, Paragraph, ParagraphProps, Radio, RadioProps, Slider, SliderProps, Spinner, SpinnerProps, SxProp, Text, TextProps, Theme, ThemeUIStyleObject } from 'theme-ui';
4
4
  export { useBreakpointIndex, useResponsiveValue } from '@theme-ui/match-media';
5
5
  export { Keyframes, keyframes } from '@emotion/react';
6
6
  import * as react_jsx_runtime from 'react/jsx-runtime';
7
7
  import * as React from 'react';
8
8
  import { IconType } from '@ttoss/react-icons';
9
+ import * as react_select_dist_declarations_src_useStateManager from 'react-select/dist/declarations/src/useStateManager';
10
+ import * as react_select_dist_declarations_src_Select from 'react-select/dist/declarations/src/Select';
11
+ import * as react_select from 'react-select';
12
+ import { Props } from 'react-select';
9
13
 
10
14
  type ThemeProviderProps = {
11
15
  children?: React.ReactNode;
@@ -50,11 +54,28 @@ type LinkProps = LinkProps$1 & {
50
54
  };
51
55
  declare const Link: React.ForwardRefExoticComponent<Omit<LinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
52
56
 
53
- type SelectProps = SelectProps$1 & {
57
+ type SelectOption = {
58
+ label: string;
59
+ value: string | number;
60
+ };
61
+ type SelectOptions = SelectOption[];
62
+ /**
63
+ * TODO: remove this when we accept multi select.
64
+ */
65
+ type IsMulti = false;
66
+ type SelectProps = Props<SelectOption, IsMulti> & SxProp & {
67
+ disabled?: boolean;
54
68
  leadingIcon?: IconType;
55
69
  trailingIcon?: IconType;
56
70
  };
57
- declare const Select: React.ForwardRefExoticComponent<Omit<SelectProps, "ref"> & React.RefAttributes<HTMLSelectElement>>;
71
+ /**
72
+ * https://react-select.com/home
73
+ */
74
+ declare const Select: React.ForwardRefExoticComponent<Omit<react_select_dist_declarations_src_Select.PublicBaseSelectProps<SelectOption, false, react_select.GroupBase<SelectOption>>, "onChange" | "value" | "inputValue" | "menuIsOpen" | "onInputChange" | "onMenuOpen" | "onMenuClose"> & Partial<react_select_dist_declarations_src_Select.PublicBaseSelectProps<SelectOption, false, react_select.GroupBase<SelectOption>>> & react_select_dist_declarations_src_useStateManager.StateManagerAdditionalProps<SelectOption> & SxProp & {
75
+ disabled?: boolean | undefined;
76
+ leadingIcon?: IconType | undefined;
77
+ trailingIcon?: IconType | undefined;
78
+ } & React.RefAttributes<any>>;
58
79
 
59
80
  declare const IconButton: React.ForwardRefExoticComponent<Omit<IconButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
60
81
 
@@ -104,4 +125,4 @@ type ActionButtonProps = Omit<ButtonProps, 'rightIcon' | 'leftIcon' | 'variant'>
104
125
  };
105
126
  declare const ActionButton: ({ icon, variant, sx, ...props }: ActionButtonProps) => react_jsx_runtime.JSX.Element;
106
127
 
107
- export { ActionButton, ActionButtonProps, Badge, BadgeProps, Button, ButtonProps, CloseButton, CloseButtonProps, Container, HelpText, HelpTextProps, IconButton, InfiniteLinearProgress, Input, InputNumber, InputNumberProps, InputPassword, InputPasswordProps, InputProps, Label, LabelProps, Link, LinkProps, Select, SelectProps, Stack, StackProps, Textarea, TextareaProps, ThemeProvider, ThemeProviderProps, useTheme };
128
+ export { ActionButton, ActionButtonProps, Badge, BadgeProps, Button, ButtonProps, CloseButton, CloseButtonProps, Container, HelpText, HelpTextProps, IconButton, InfiniteLinearProgress, Input, InputNumber, InputNumberProps, InputPassword, InputPasswordProps, InputProps, Label, LabelProps, Link, LinkProps, Select, SelectOption, SelectOptions, SelectProps, Stack, StackProps, Textarea, TextareaProps, ThemeProvider, ThemeProviderProps, useTheme };
package/dist/index.js CHANGED
@@ -40,16 +40,16 @@ var src_exports = {};
40
40
  __export(src_exports, {
41
41
  ActionButton: () => ActionButton,
42
42
  Badge: () => Badge,
43
- BaseStyles: () => import_theme_ui27.BaseStyles,
43
+ BaseStyles: () => import_theme_ui26.BaseStyles,
44
44
  Box: () => import_theme_ui4.Box,
45
45
  Button: () => Button,
46
46
  Card: () => import_theme_ui6.Card,
47
- Checkbox: () => import_theme_ui22.Checkbox,
47
+ Checkbox: () => import_theme_ui21.Checkbox,
48
48
  CloseButton: () => CloseButton,
49
49
  Container: () => Container,
50
50
  Divider: () => import_theme_ui7.Divider,
51
51
  Flex: () => import_theme_ui8.Flex,
52
- Global: () => import_theme_ui27.Global,
52
+ Global: () => import_theme_ui26.Global,
53
53
  Grid: () => import_theme_ui9.Grid,
54
54
  Heading: () => import_theme_ui10.Heading,
55
55
  HelpText: () => HelpText,
@@ -62,11 +62,11 @@ __export(src_exports, {
62
62
  Label: () => Label,
63
63
  LinearProgress: () => import_theme_ui15.Progress,
64
64
  Link: () => Link,
65
- Paragraph: () => import_theme_ui26.Paragraph,
66
- Radio: () => import_theme_ui19.Radio,
65
+ Paragraph: () => import_theme_ui25.Paragraph,
66
+ Radio: () => import_theme_ui18.Radio,
67
67
  Select: () => Select,
68
- Slider: () => import_theme_ui21.Slider,
69
- Spinner: () => import_theme_ui18.Spinner,
68
+ Slider: () => import_theme_ui20.Slider,
69
+ Spinner: () => import_theme_ui17.Spinner,
70
70
  Stack: () => Stack,
71
71
  Text: () => import_theme_ui16.Text,
72
72
  Textarea: () => Textarea,
@@ -77,7 +77,7 @@ __export(src_exports, {
77
77
  useTheme: () => useTheme
78
78
  });
79
79
  module.exports = __toCommonJS(src_exports);
80
- var import_theme_ui27 = require("theme-ui");
80
+ var import_theme_ui26 = require("theme-ui");
81
81
  var import_match_media = require("@theme-ui/match-media");
82
82
  var import_react2 = require("@emotion/react");
83
83
 
@@ -332,133 +332,188 @@ var import_theme_ui16 = require("theme-ui");
332
332
  // src/components/Select.tsx
333
333
  var React4 = __toESM(require("react"));
334
334
  var import_react_icons5 = require("@ttoss/react-icons");
335
- var import_theme_ui17 = require("theme-ui");
335
+ var import_react_select = __toESM(require("react-select"));
336
336
  var import_jsx_runtime7 = require("react/jsx-runtime");
337
- var Select = React4.forwardRef(({
338
- arrow,
339
- sx,
340
- leadingIcon,
341
- trailingIcon,
337
+ var Control = props => {
338
+ const isDisabled = props.selectProps.isDisabled;
339
+ const hasError = props.selectProps["aria-invalid"] === "true";
340
+ const border = (() => {
341
+ if (isDisabled) {
342
+ return "muted";
343
+ }
344
+ if (hasError) {
345
+ return "danger";
346
+ }
347
+ return "interaction";
348
+ })();
349
+ const backgroundColor = (() => {
350
+ if (isDisabled) {
351
+ return "muted";
352
+ }
353
+ return "surface";
354
+ })();
355
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui4.Box, {
356
+ sx: {
357
+ ".react-select__control": {
358
+ border,
359
+ backgroundColor,
360
+ paddingX: "xl",
361
+ paddingY: "lg",
362
+ borderRadius: "action"
363
+ }
364
+ },
365
+ children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_select.components.Control, {
366
+ ...props
367
+ })
368
+ });
369
+ };
370
+ var DropdownIndicator = props => {
371
+ const isDisabled = props.selectProps.isDisabled;
372
+ const color = (() => {
373
+ if (isDisabled) {
374
+ return "onMuted";
375
+ }
376
+ return "text";
377
+ })();
378
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
379
+ sx: {
380
+ fontSize: "base",
381
+ color,
382
+ alignSelf: "center",
383
+ display: "flex",
384
+ alignItems: "center"
385
+ },
386
+ children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_icons5.Icon, {
387
+ icon: "picker-down"
388
+ })
389
+ });
390
+ };
391
+ var IndicatorsContainer = ({
392
+ children,
393
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
342
394
  ...props
343
- }, ref) => {
344
- const hasError = props["aria-invalid"] === "true";
345
- const refEl = React4.useRef({});
346
- React4.useImperativeHandle(ref, () => {
347
- return refEl.current;
395
+ }) => {
396
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui4.Box, {
397
+ sx: {
398
+ marginLeft: "lg",
399
+ border: "none"
400
+ },
401
+ children
402
+ });
403
+ };
404
+ var Placeholder = ({
405
+ children
406
+ }) => {
407
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
408
+ sx: {
409
+ color: "onMuted",
410
+ alignSelf: "center"
411
+ },
412
+ children
348
413
  });
349
- React4.useEffect(() => {
350
- const parentEl = refEl.current?.parentElement;
351
- if (parentEl) {
352
- parentEl.style.position = "relative";
414
+ };
415
+ var SelectContainer = ({
416
+ children,
417
+ ...props
418
+ }) => {
419
+ const {
420
+ sx,
421
+ css: css2
422
+ } = props.selectProps;
423
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui4.Box, {
424
+ sx,
425
+ css: css2,
426
+ children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_select.components.SelectContainer, {
427
+ ...props,
428
+ children
429
+ })
430
+ });
431
+ };
432
+ var ValueContainer = ({
433
+ children,
434
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
435
+ ...props
436
+ }) => {
437
+ const {
438
+ leadingIcon,
439
+ trailingIcon
440
+ } = props.selectProps;
441
+ const hasError = props.selectProps["aria-invalid"] === "true";
442
+ const trailingIconColor = (() => {
443
+ if (hasError) {
444
+ return "danger";
353
445
  }
354
- }, []);
355
- return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui17.Select, {
356
- arrow: /* @__PURE__ */(0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, {
357
- children: [leadingIcon && /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
358
- sx: {
359
- alignSelf: "center",
360
- pointerEvents: "none",
361
- lineHeight: 0,
362
- fontSize: "base",
363
- position: "absolute",
364
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
365
- left: ({
366
- space
367
- }) => {
368
- const leftSpaceValue = space?.["xl"] || "16px";
369
- return leftSpaceValue;
370
- }
371
- },
372
- children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_icons5.Icon, {
373
- icon: leadingIcon
374
- })
375
- }), /* @__PURE__ */(0, import_jsx_runtime7.jsxs)(import_theme_ui8.Flex, {
376
- sx: {
377
- gap: "lg",
378
- position: "absolute",
379
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
380
- right: ({
381
- space
382
- }) => {
383
- const xlSpace = space?.["xl"] || "16px";
384
- return xlSpace;
385
- },
386
- alignSelf: "center",
387
- pointerEvents: "none"
388
- },
389
- children: [(trailingIcon || hasError) && /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
390
- className: hasError ? "error-icon" : "",
391
- sx: {
392
- alignSelf: "center",
393
- pointerEvents: "none",
394
- lineHeight: 0,
395
- fontSize: "base"
396
- },
397
- children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_icons5.Icon, {
398
- icon: hasError ? "warning-alt" : trailingIcon
399
- })
400
- }), arrow ?? /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
401
- sx: {
402
- lineHeight: 0,
403
- fontSize: "base"
404
- },
405
- children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_icons5.Icon, {
406
- icon: "picker-down"
407
- })
408
- })]
409
- })]
410
- }),
446
+ return "text";
447
+ })();
448
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsxs)(import_theme_ui8.Flex, {
411
449
  sx: {
412
- fontFamily: "body",
413
- width: "100%",
414
- paddingY: "lg",
415
- paddingX: "xl",
416
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
417
- paddingLeft: ({
418
- space,
419
- fontSizes
420
- }) => {
421
- const xlSpace = space?.["xl"] || "16px";
422
- const iconSize = fontSizes?.["base"] || "16px";
423
- const lgSpace = space?.["lg"] || "16px";
424
- if (leadingIcon) {
425
- return `calc(${xlSpace} + ${iconSize} + ${lgSpace})`;
426
- }
427
- return xlSpace;
450
+ gap: "lg",
451
+ flex: 1
452
+ },
453
+ children: [leadingIcon && /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
454
+ sx: {
455
+ alignSelf: "center",
456
+ pointerEvents: "none",
457
+ lineHeight: 0,
458
+ fontSize: "base"
428
459
  },
429
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
430
- paddingRight: ({
431
- space,
432
- fontSizes
433
- }) => {
434
- const xlSpace = space?.["xl"] || "16px";
435
- const iconSize = fontSizes?.["base"] || "16px";
436
- const lgSpace = space?.["lg"] || "16px";
437
- if (trailingIcon || hasError) {
438
- return `calc(${lgSpace} + ${iconSize} + ${lgSpace} + ${iconSize} + ${xlSpace})`;
439
- }
440
- return `calc(${lgSpace} + ${iconSize} + ${xlSpace})`;
460
+ children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_icons5.Icon, {
461
+ icon: leadingIcon
462
+ })
463
+ }), /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui8.Flex, {
464
+ sx: {
465
+ flex: 1,
466
+ alignItems: "center"
441
467
  },
442
- ...sx
468
+ children
469
+ }), (trailingIcon || hasError) && /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_theme_ui16.Text, {
470
+ className: hasError ? "error-icon" : "",
471
+ sx: {
472
+ alignSelf: "center",
473
+ pointerEvents: "none",
474
+ lineHeight: 0,
475
+ fontSize: "base",
476
+ color: trailingIconColor
477
+ },
478
+ children: /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_icons5.Icon, {
479
+ icon: hasError ? "warning-alt" : trailingIcon
480
+ })
481
+ })]
482
+ });
483
+ };
484
+ var Select = React4.forwardRef(({
485
+ ...props
486
+ }, ref) => {
487
+ return /* @__PURE__ */(0, import_jsx_runtime7.jsx)(import_react_select.default, {
488
+ ref,
489
+ components: {
490
+ Control,
491
+ DropdownIndicator,
492
+ IndicatorsContainer,
493
+ Placeholder,
494
+ SelectContainer,
495
+ ValueContainer,
496
+ ...props.components
443
497
  },
444
- ref: refEl,
445
- ...props
498
+ isDisabled: props.disabled,
499
+ ...props,
500
+ classNamePrefix: "react-select"
446
501
  });
447
502
  });
448
503
  Select.displayName = "Select";
449
504
 
450
505
  // src/components/Spinner.tsx
451
- var import_theme_ui18 = require("theme-ui");
506
+ var import_theme_ui17 = require("theme-ui");
452
507
 
453
508
  // src/components/Radio.tsx
454
- var import_theme_ui19 = require("theme-ui");
509
+ var import_theme_ui18 = require("theme-ui");
455
510
 
456
511
  // src/components/IconButton.tsx
457
512
  var React5 = __toESM(require("react"));
458
- var import_theme_ui20 = require("theme-ui");
513
+ var import_theme_ui19 = require("theme-ui");
459
514
  var import_jsx_runtime8 = require("react/jsx-runtime");
460
515
  var IconButton = React5.forwardRef((props, ref) => {
461
- return /* @__PURE__ */(0, import_jsx_runtime8.jsx)(import_theme_ui20.IconButton, {
516
+ return /* @__PURE__ */(0, import_jsx_runtime8.jsx)(import_theme_ui19.IconButton, {
462
517
  type: "button",
463
518
  ...props,
464
519
  ref
@@ -467,10 +522,10 @@ var IconButton = React5.forwardRef((props, ref) => {
467
522
  IconButton.displayName = "IconButton";
468
523
 
469
524
  // src/components/Slider.tsx
470
- var import_theme_ui21 = require("theme-ui");
525
+ var import_theme_ui20 = require("theme-ui");
471
526
 
472
527
  // src/components/Checkbox.tsx
473
- var import_theme_ui22 = require("theme-ui");
528
+ var import_theme_ui21 = require("theme-ui");
474
529
 
475
530
  // src/components/InfiniteLinearProgress.tsx
476
531
  var React6 = __toESM(require("react"));
@@ -509,7 +564,7 @@ var InfiniteLinearProgress = () => {
509
564
  // src/components/Textarea.tsx
510
565
  var React7 = __toESM(require("react"));
511
566
  var import_react_icons6 = require("@ttoss/react-icons");
512
- var import_theme_ui23 = require("theme-ui");
567
+ var import_theme_ui22 = require("theme-ui");
513
568
  var import_jsx_runtime10 = require("react/jsx-runtime");
514
569
  var Textarea = React7.forwardRef(({
515
570
  trailingIcon,
@@ -525,7 +580,7 @@ var Textarea = React7.forwardRef(({
525
580
  padding: 0,
526
581
  border: "none"
527
582
  },
528
- children: [/* @__PURE__ */(0, import_jsx_runtime10.jsx)(import_theme_ui23.Textarea, {
583
+ children: [/* @__PURE__ */(0, import_jsx_runtime10.jsx)(import_theme_ui22.Textarea, {
529
584
  ref,
530
585
  sx: {
531
586
  fontFamily: "body",
@@ -554,10 +609,10 @@ Textarea.displayName = "Textarea";
554
609
 
555
610
  // src/components/Container.tsx
556
611
  var React8 = __toESM(require("react"));
557
- var import_theme_ui24 = require("theme-ui");
612
+ var import_theme_ui23 = require("theme-ui");
558
613
  var import_jsx_runtime11 = require("react/jsx-runtime");
559
614
  var Container = React8.forwardRef((props, ref) => {
560
- return /* @__PURE__ */(0, import_jsx_runtime11.jsx)(import_theme_ui24.Container, {
615
+ return /* @__PURE__ */(0, import_jsx_runtime11.jsx)(import_theme_ui23.Container, {
561
616
  ref,
562
617
  ...props
563
618
  });
@@ -631,7 +686,7 @@ CloseButton.displayName = "CloseButton";
631
686
  // src/components/InputNumber.tsx
632
687
  var React10 = __toESM(require("react"));
633
688
  var import_react_icons8 = require("@ttoss/react-icons");
634
- var import_theme_ui25 = require("theme-ui");
689
+ var import_theme_ui24 = require("theme-ui");
635
690
  var import_jsx_runtime14 = require("react/jsx-runtime");
636
691
  var InputNumber = React10.forwardRef(({
637
692
  sx,
@@ -703,7 +758,7 @@ var InputNumber = React10.forwardRef(({
703
758
  },
704
759
  ref,
705
760
  "aria-invalid": inputProps["aria-invalid"],
706
- children: [/* @__PURE__ */(0, import_jsx_runtime14.jsx)(import_theme_ui25.Input, {
761
+ children: [/* @__PURE__ */(0, import_jsx_runtime14.jsx)(import_theme_ui24.Input, {
707
762
  ref,
708
763
  variant: "forms.inputNumber",
709
764
  sx: sxProps,
@@ -770,7 +825,7 @@ var Stack = React11.forwardRef((props, ref) => {
770
825
  Stack.displayName = "Stack";
771
826
 
772
827
  // src/components/Paragraph.tsx
773
- var import_theme_ui26 = require("theme-ui");
828
+ var import_theme_ui25 = require("theme-ui");
774
829
 
775
830
  // src/components/InputPassword/InputPassword.tsx
776
831
  var React13 = __toESM(require("react"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/ui",
3
- "version": "3.1.6",
3
+ "version": "4.0.0",
4
4
  "description": "Primitive layout, typographic, and other components for styling applications.",
5
5
  "author": "ttoss",
6
6
  "contributors": [
@@ -21,25 +21,26 @@
21
21
  "typings": "dist/index.d.ts",
22
22
  "dependencies": {
23
23
  "@theme-ui/match-media": "^0.16.1",
24
+ "react-select": "^5.8.0",
24
25
  "theme-ui": "^0.16.1",
25
- "@ttoss/theme": "^1.6.5"
26
+ "@ttoss/theme": "^1.6.6"
26
27
  },
27
28
  "peerDependencies": {
28
29
  "@emotion/react": "^11",
29
30
  "react": ">=16.8.0",
30
- "@ttoss/react-icons": "^0.2.0"
31
+ "@ttoss/react-icons": "^0.2.1"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@emotion/react": "^11.11.1",
34
35
  "@iconify-icons/mdi-light": "^1.2.5",
35
36
  "@types/jest": "^29.5.5",
36
- "@types/react": "^18.2.27",
37
+ "@types/react": "^18.2.29",
37
38
  "jest": "^29.7.0",
38
39
  "react": "^18.2.0",
39
40
  "tsup": "^7.2.0",
40
41
  "@ttoss/config": "^1.31.0",
41
- "@ttoss/react-icons": "^0.2.0",
42
- "@ttoss/test-utils": "^1.24.0"
42
+ "@ttoss/react-icons": "^0.2.1",
43
+ "@ttoss/test-utils": "^1.24.1"
43
44
  },
44
45
  "keywords": [
45
46
  "React",
@@ -1,137 +1,250 @@
1
+ /**
2
+ * We're using React Select component to build ttoss Select.
3
+ * More info about React Select: https://react-select.com/home
4
+ * ttoss Figma: https://www.figma.com/file/VrB76VkH4hKCDUe9iYhpYu/_Component-%2F-Forms-%2F-Select?type=design&mode=design&t=ZBIeOpqcvQn3yq2t-0
5
+ */
1
6
  import * as React from 'react';
2
- import { Flex, Text } from '..';
7
+ import { Box, Flex, Text } from '..';
3
8
  import { Icon, IconType } from '@ttoss/react-icons';
4
- import {
5
- type SelectProps as SelectPropsUi,
6
- Select as SelectUi,
7
- } from 'theme-ui';
8
-
9
- export type SelectProps = SelectPropsUi & {
10
- leadingIcon?: IconType;
11
- trailingIcon?: IconType;
9
+ import { type SxProp } from 'theme-ui';
10
+ import ReactSelect, {
11
+ type ContainerProps,
12
+ type ControlProps,
13
+ type DropdownIndicatorProps,
14
+ type IndicatorsContainerProps,
15
+ type PlaceholderProps,
16
+ type Props as ReactSelectProps,
17
+ type ValueContainerProps,
18
+ components,
19
+ } from 'react-select';
20
+
21
+ export type SelectOption = {
22
+ label: string;
23
+ value: string | number;
12
24
  };
13
25
 
14
- export const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
15
- ({ arrow, sx, leadingIcon, trailingIcon, ...props }, ref) => {
16
- const hasError = props['aria-invalid'] === 'true';
26
+ export type SelectOptions = SelectOption[];
17
27
 
18
- const refEl = React.useRef<HTMLSelectElement>({} as HTMLSelectElement);
28
+ /**
29
+ * TODO: remove this when we accept multi select.
30
+ */
31
+ type IsMulti = false;
19
32
 
20
- React.useImperativeHandle(ref, () => {
21
- return refEl.current;
22
- });
33
+ export type SelectProps = ReactSelectProps<SelectOption, IsMulti> &
34
+ SxProp & {
35
+ disabled?: boolean;
36
+ leadingIcon?: IconType;
37
+ trailingIcon?: IconType;
38
+ };
23
39
 
24
- React.useEffect(() => {
25
- const parentEl = refEl.current?.parentElement;
40
+ const Control = (props: ControlProps<SelectOption, IsMulti>) => {
41
+ const isDisabled = props.selectProps.isDisabled;
26
42
 
27
- if (parentEl) {
28
- parentEl.style.position = 'relative';
29
- }
30
- }, []);
43
+ const hasError = props.selectProps['aria-invalid'] === 'true';
31
44
 
32
- return (
33
- <SelectUi
34
- // https://theme-ui.com/components/select#custom-arrow-icon
35
- arrow={
36
- <>
37
- {leadingIcon && (
38
- <Text
39
- sx={{
40
- alignSelf: 'center',
41
- pointerEvents: 'none',
42
- lineHeight: 0,
43
- fontSize: 'base',
44
- position: 'absolute',
45
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
46
- left: ({ space }: any) => {
47
- const leftSpaceValue = space?.['xl'] || '16px';
48
-
49
- return leftSpaceValue;
50
- },
51
- }}
52
- >
53
- <Icon icon={leadingIcon} />
54
- </Text>
55
- )}
56
-
57
- <Flex
58
- sx={{
59
- gap: 'lg',
60
- position: 'absolute',
61
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
- right: ({ space }: any) => {
63
- const xlSpace = space?.['xl'] || '16px';
64
-
65
- return xlSpace;
66
- },
67
- alignSelf: 'center',
68
- pointerEvents: 'none',
69
- }}
70
- >
71
- {(trailingIcon || hasError) && (
72
- <Text
73
- className={hasError ? 'error-icon' : ''}
74
- sx={{
75
- alignSelf: 'center',
76
- pointerEvents: 'none',
77
- lineHeight: 0,
78
- fontSize: 'base',
79
- }}
80
- >
81
- <Icon
82
- icon={hasError ? 'warning-alt' : (trailingIcon as IconType)}
83
- />
84
- </Text>
85
- )}
86
-
87
- {arrow ?? (
88
- <Text
89
- sx={{
90
- lineHeight: 0,
91
- fontSize: 'base',
92
- }}
93
- >
94
- <Icon icon="picker-down" />
95
- </Text>
96
- )}
97
- </Flex>
98
- </>
99
- }
100
- sx={{
101
- fontFamily: 'body',
102
- width: '100%',
103
- paddingY: 'lg',
45
+ const border = (() => {
46
+ if (isDisabled) {
47
+ return 'muted';
48
+ }
49
+
50
+ if (hasError) {
51
+ return 'danger';
52
+ }
53
+
54
+ return 'interaction';
55
+ })();
56
+
57
+ const backgroundColor = (() => {
58
+ if (isDisabled) {
59
+ return 'muted';
60
+ }
61
+
62
+ return 'surface';
63
+ })();
64
+
65
+ return (
66
+ <Box
67
+ sx={{
68
+ '.react-select__control': {
69
+ border,
70
+ backgroundColor,
104
71
  paddingX: 'xl',
105
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
- paddingLeft: ({ space, fontSizes }: any) => {
107
- const xlSpace = space?.['xl'] || '16px';
108
- const iconSize = fontSizes?.['base'] || '16px';
109
- const lgSpace = space?.['lg'] || '16px';
110
-
111
- if (leadingIcon) {
112
- return `calc(${xlSpace} + ${iconSize} + ${lgSpace})`;
113
- }
114
-
115
- return xlSpace;
116
- },
117
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
- paddingRight: ({ space, fontSizes }: any) => {
119
- const xlSpace = space?.['xl'] || '16px';
120
- const iconSize = fontSizes?.['base'] || '16px';
121
- const lgSpace = space?.['lg'] || '16px';
122
-
123
- if (trailingIcon || hasError) {
124
- return `calc(${lgSpace} + ${iconSize} + ${lgSpace} + ${iconSize} + ${xlSpace})`;
125
- }
126
-
127
- return `calc(${lgSpace} + ${iconSize} + ${xlSpace})`;
128
- },
129
- ...sx,
72
+ paddingY: 'lg',
73
+ borderRadius: 'action',
74
+ },
75
+ }}
76
+ >
77
+ <components.Control {...props} />
78
+ </Box>
79
+ );
80
+ };
81
+
82
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
83
+ const DropdownIndicator = (
84
+ props: DropdownIndicatorProps<SelectOption, IsMulti>
85
+ ) => {
86
+ const isDisabled = props.selectProps.isDisabled;
87
+
88
+ const color = (() => {
89
+ if (isDisabled) {
90
+ return 'onMuted';
91
+ }
92
+
93
+ return 'text';
94
+ })();
95
+
96
+ return (
97
+ <Text
98
+ sx={{
99
+ fontSize: 'base',
100
+ color,
101
+ alignSelf: 'center',
102
+ display: 'flex',
103
+ alignItems: 'center',
104
+ }}
105
+ >
106
+ <Icon icon="picker-down" />
107
+ </Text>
108
+ );
109
+ };
110
+
111
+ const IndicatorsContainer = ({
112
+ children,
113
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
114
+ ...props
115
+ }: IndicatorsContainerProps<SelectOption, IsMulti>) => {
116
+ return (
117
+ <Box
118
+ sx={{
119
+ marginLeft: 'lg',
120
+ border: 'none',
121
+ }}
122
+ >
123
+ {children}
124
+ </Box>
125
+ );
126
+ };
127
+
128
+ const Placeholder = ({ children }: PlaceholderProps<SelectOption, IsMulti>) => {
129
+ return (
130
+ <Text
131
+ sx={{
132
+ color: 'onMuted',
133
+ alignSelf: 'center',
134
+ }}
135
+ >
136
+ {children}
137
+ </Text>
138
+ );
139
+ };
140
+
141
+ const SelectContainer = ({
142
+ children,
143
+ ...props
144
+ }: ContainerProps<SelectOption, IsMulti>) => {
145
+ const { sx, css } = props.selectProps as SelectProps;
146
+
147
+ return (
148
+ <Box sx={sx} css={css}>
149
+ <components.SelectContainer {...props}>
150
+ {children}
151
+ </components.SelectContainer>
152
+ </Box>
153
+ );
154
+ };
155
+
156
+ const ValueContainer = ({
157
+ children,
158
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
+ ...props
160
+ }: ValueContainerProps<SelectOption, IsMulti>) => {
161
+ const { leadingIcon, trailingIcon } = props.selectProps as SelectProps;
162
+
163
+ const hasError = props.selectProps['aria-invalid'] === 'true';
164
+
165
+ const trailingIconColor = (() => {
166
+ if (hasError) {
167
+ return 'danger';
168
+ }
169
+
170
+ return 'text';
171
+ })();
172
+
173
+ return (
174
+ <Flex
175
+ sx={{
176
+ gap: 'lg',
177
+ flex: 1,
178
+ }}
179
+ >
180
+ {leadingIcon && (
181
+ <Text
182
+ sx={{
183
+ alignSelf: 'center',
184
+ pointerEvents: 'none',
185
+ lineHeight: 0,
186
+ fontSize: 'base',
187
+ }}
188
+ >
189
+ <Icon icon={leadingIcon} />
190
+ </Text>
191
+ )}
192
+ <Flex
193
+ sx={{
194
+ flex: 1,
195
+ alignItems: 'center',
196
+ }}
197
+ >
198
+ {children}
199
+ </Flex>
200
+ {(trailingIcon || hasError) && (
201
+ <Text
202
+ className={hasError ? 'error-icon' : ''}
203
+ sx={{
204
+ alignSelf: 'center',
205
+ pointerEvents: 'none',
206
+ lineHeight: 0,
207
+ fontSize: 'base',
208
+ color: trailingIconColor,
209
+ }}
210
+ >
211
+ <Icon icon={hasError ? 'warning-alt' : (trailingIcon as IconType)} />
212
+ </Text>
213
+ )}
214
+ </Flex>
215
+ );
216
+ };
217
+
218
+ /**
219
+ * https://react-select.com/home
220
+ */
221
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
222
+ export const Select = React.forwardRef<any, SelectProps>(
223
+ ({ ...props }, ref) => {
224
+ return (
225
+ <ReactSelect<SelectOption, IsMulti>
226
+ ref={ref}
227
+ /**
228
+ * https://react-select.com/components
229
+ */
230
+ components={{
231
+ Control,
232
+ DropdownIndicator,
233
+ IndicatorsContainer,
234
+ Placeholder,
235
+ SelectContainer,
236
+ ValueContainer,
237
+ ...props.components,
130
238
  }}
131
- ref={refEl}
239
+ isDisabled={props.disabled}
132
240
  {...props}
241
+ /**
242
+ * https://react-select.com/styles#the-classnameprefix-prop
243
+ */
244
+ classNamePrefix="react-select"
133
245
  />
134
246
  );
135
247
  }
136
248
  );
249
+
137
250
  Select.displayName = 'Select';
package/src/index.ts CHANGED
@@ -1,4 +1,10 @@
1
- export { BaseStyles, type Theme, Global, type SxProp } from 'theme-ui';
1
+ export {
2
+ BaseStyles,
3
+ type Theme,
4
+ Global,
5
+ type SxProp,
6
+ type ThemeUIStyleObject,
7
+ } from 'theme-ui';
2
8
  export { useResponsiveValue, useBreakpointIndex } from '@theme-ui/match-media';
3
9
  export { keyframes, type Keyframes } from '@emotion/react';
4
10
 
@@ -23,7 +29,12 @@ export {
23
29
  type LinearProgressProps,
24
30
  } from './components/LinearProgress';
25
31
  export { Text, type TextProps } from './components/Text';
26
- export { Select, type SelectProps } from './components/Select';
32
+ export {
33
+ Select,
34
+ type SelectProps,
35
+ type SelectOptions,
36
+ type SelectOption,
37
+ } from './components/Select';
27
38
  export { Spinner, type SpinnerProps } from './components/Spinner';
28
39
  export { Radio, type RadioProps } from './components/Radio';
29
40
  export { IconButton, type IconButtonProps } from './components/IconButton';