@vygruppen/spor-react 2.4.3 → 2.5.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @vygruppen/spor-react@2.4.3 build
2
+ > @vygruppen/spor-react@2.5.0 build
3
3
  > tsup src/index.tsx --dts --treeshake --format cjs,esm
4
4
 
5
5
  CLI Building entry: src/index.tsx
@@ -10,12 +10,12 @@
10
10
  ESM Build start
11
11
  DTS Build start
12
12
  "toTime" is imported from external module "@internationalized/date" but never used in "dist/index.js".
13
- "toTime" is imported from external module "@internationalized/date" but never used in "dist/chunk-Z3I6W6PC.mjs".
14
- CJS dist/index.js 896.27 KB
15
- CJS ⚡️ Build success in 5484ms
16
- ESM dist/index.mjs 2.08 KB
17
- ESM dist/CountryCodeSelect-GFQIGSFV.mjs 351.67 KB
18
- ESM dist/chunk-Z3I6W6PC.mjs 416.47 KB
19
- ESM ⚡️ Build success in 5484ms
20
- DTS ⚡️ Build success in 22623ms
21
- DTS dist/index.d.ts 262.86 KB
13
+ "toTime" is imported from external module "@internationalized/date" but never used in "dist/chunk-7GRTZA6T.mjs".
14
+ CJS dist/index.js 895.46 KB
15
+ CJS ⚡️ Build success in 5694ms
16
+ ESM dist/index.mjs 2.06 KB
17
+ ESM dist/CountryCodeSelect-ZTEYBERS.mjs 351.67 KB
18
+ ESM dist/chunk-7GRTZA6T.mjs 415.76 KB
19
+ ESM ⚡️ Build success in 5707ms
20
+ DTS ⚡️ Build success in 21517ms
21
+ DTS dist/index.d.ts 259.31 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @vygruppen/spor-react
2
2
 
3
+ ## 2.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 042dba35: Make accordions and cards default to the sm size
8
+
9
+ ### Patch Changes
10
+
11
+ - f9d6bd34: Combobox: Fix a bug where menuTrigger="focus" wouldn't work
12
+ - 76914a15: Remove non-working Autosuggest component
13
+
3
14
  ## 2.4.3
4
15
 
5
16
  ### Patch Changes
@@ -1,4 +1,4 @@
1
- import { createTexts, useTranslation, InfoSelect, SelectItem } from './chunk-Z3I6W6PC.mjs';
1
+ import { createTexts, useTranslation, InfoSelect, SelectItem } from './chunk-7GRTZA6T.mjs';
2
2
  import React from 'react';
3
3
 
4
4
  // ../../node_modules/awesome-phonenumber/index-esm.mjs
@@ -12,7 +12,7 @@ import { usePopover, Overlay, DismissButton, useOverlayTrigger, useButton, usePr
12
12
  import { motion } from 'framer-motion';
13
13
  import { DateFormatter, parseTime, createCalendar, Time, toCalendarDate, toCalendarDateTime, toCalendar, getMinimumDayInMonth, getMinimumMonthInYear, today, startOfWeek, startOfMonth, endOfWeek, endOfMonth, isSameDay, getDayOfWeek, maxDate, minDate, isEqualDay, getWeeksInMonth, getLocalTimeZone, GregorianCalendar, now, startOfYear, isSameMonth, isToday } from '@internationalized/date';
14
14
  export { Time } from '@internationalized/date';
15
- import { useOverlayTriggerState, useTimeFieldState, useAsyncList, useComboBoxState, Item, useSelectState } from 'react-stately';
15
+ import { useOverlayTriggerState, useTimeFieldState, useComboBoxState, Item, useSelectState } from 'react-stately';
16
16
  export { Item, Section } from 'react-stately';
17
17
  import { useSwipeable } from 'react-swipeable';
18
18
  import { Global, keyframes } from '@emotion/react';
@@ -1523,7 +1523,7 @@ var Stack = forwardRef(
1523
1523
 
1524
1524
  // src/card/Card.tsx
1525
1525
  var Card = forwardRef(
1526
- ({ size: size2 = "lg", colorScheme = "white", children, ...props }, ref) => {
1526
+ ({ size: size2 = "sm", colorScheme = "white", children, ...props }, ref) => {
1527
1527
  const styles2 = useStyleConfig("Card", {
1528
1528
  colorScheme,
1529
1529
  size: size2
@@ -4019,46 +4019,6 @@ var AttachedInputs = ({
4019
4019
  }
4020
4020
  );
4021
4021
  };
4022
- function Autosuggest({
4023
- label,
4024
- fetcher,
4025
- onSelectionChange,
4026
- ...props
4027
- }) {
4028
- const list2 = useAsyncList({
4029
- async load({ filterText }) {
4030
- return {
4031
- items: await fetcher(filterText)
4032
- };
4033
- }
4034
- });
4035
- const handleSelectionChange = (key) => {
4036
- if (!onSelectionChange) {
4037
- return;
4038
- }
4039
- let selectedItem = list2.getItem(key);
4040
- if (!selectedItem) {
4041
- selectedItem = list2.items.flatMap(
4042
- (item) => "children" in item && Array.isArray(item.children) ? item.children : []
4043
- ).find((child) => child.key === key);
4044
- }
4045
- if (selectedItem) {
4046
- onSelectionChange(selectedItem);
4047
- }
4048
- };
4049
- return /* @__PURE__ */ React49__default.createElement(
4050
- Combobox,
4051
- {
4052
- label,
4053
- items: list2.items,
4054
- inputValue: list2.filterText,
4055
- onInputChange: list2.setFilterText,
4056
- onSelectionChange: handleSelectionChange,
4057
- isLoading: list2.isLoading,
4058
- ...props
4059
- }
4060
- );
4061
- }
4062
4022
  var Dialog = ({ title, children, ...props }) => {
4063
4023
  const ref = useRef(null);
4064
4024
  const { dialogProps, titleProps } = useDialog(props, ref);
@@ -4252,17 +4212,18 @@ function Combobox({
4252
4212
  paddingLeft,
4253
4213
  paddingX,
4254
4214
  paddingY,
4255
- onFocus,
4215
+ emptyContent,
4256
4216
  ...rest
4257
4217
  }) {
4258
4218
  const { contains: contains2 } = useFilter({ sensitivity: "base" });
4259
- const state2 = useComboBoxState({
4260
- ...rest,
4261
- defaultFilter: contains2
4262
- });
4263
4219
  const inputRef = useRef(null);
4264
4220
  const listBoxRef = useRef(null);
4265
4221
  const popoverRef = useRef(null);
4222
+ const state2 = useComboBoxState({
4223
+ ...rest,
4224
+ defaultFilter: contains2,
4225
+ allowsEmptyCollection: Boolean(emptyContent)
4226
+ });
4266
4227
  const {
4267
4228
  inputProps: { size: size2, ...inputProps },
4268
4229
  listBoxProps
@@ -4281,7 +4242,6 @@ function Combobox({
4281
4242
  ...inputProps,
4282
4243
  ref: inputRef,
4283
4244
  label,
4284
- onFocus,
4285
4245
  borderBottomLeftRadius: state2.isOpen ? 0 : borderBottomLeftRadius,
4286
4246
  borderBottomRightRadius: state2.isOpen ? 0 : borderBottomRightRadius,
4287
4247
  borderTopLeftRadius,
@@ -4327,7 +4287,7 @@ function Combobox({
4327
4287
  ...listBoxProps,
4328
4288
  state: state2,
4329
4289
  listBoxRef,
4330
- borderBottomRadius: "sm"
4290
+ emptyContent
4331
4291
  },
4332
4292
  rest.children
4333
4293
  )
@@ -4414,6 +4374,7 @@ function ListBox({
4414
4374
  sx: styles2.container,
4415
4375
  "aria-busy": isLoading
4416
4376
  },
4377
+ state2.collection.size === 0 && props.emptyContent,
4417
4378
  Array.from(state2.collection).map(
4418
4379
  (item) => item.type === "section" ? /* @__PURE__ */ React49__default.createElement(ListBoxSection, { key: item.key, section: item, state: state2 }) : /* @__PURE__ */ React49__default.createElement(Option, { key: item.key, item, state: state2 })
4419
4380
  )
@@ -4466,18 +4427,18 @@ function ListBoxSection({ section, state: state2 }) {
4466
4427
  heading: section.rendered,
4467
4428
  "aria-label": section["aria-label"]
4468
4429
  });
4469
- const isFirstSection = section.key !== state2.collection.getFirstKey();
4470
- const titleBackgroundColor = useColorModeValue("platinum", "dimGrey");
4430
+ const isFirstSection = section.key === state2.collection.getFirstKey();
4471
4431
  const titleColor = useColorModeValue("darkGrey", "white");
4472
4432
  return /* @__PURE__ */ React49__default.createElement(ListItem, { ...itemProps }, section.rendered && /* @__PURE__ */ React49__default.createElement(
4473
4433
  Box,
4474
4434
  {
4475
- textStyle: "xs",
4476
- backgroundColor: titleBackgroundColor,
4435
+ fontSize: "mobile.xs",
4477
4436
  color: titleColor,
4478
4437
  paddingX: 3,
4479
4438
  paddingY: 1,
4480
- marginTop: isFirstSection ? 0 : 0,
4439
+ marginTop: isFirstSection ? 0 : 3,
4440
+ textTransform: "uppercase",
4441
+ fontWeight: "bold",
4481
4442
  ...headingProps
4482
4443
  },
4483
4444
  section.rendered
@@ -4561,7 +4522,7 @@ var texts10 = createTexts({
4561
4522
  }
4562
4523
  });
4563
4524
  var Input = forwardRef(
4564
- ({ label, leftIcon, rightIcon, id, ...props }, ref) => {
4525
+ ({ label, leftIcon, rightIcon, id, size: size2, ...props }, ref) => {
4565
4526
  const formControlProps = useFormControlContext();
4566
4527
  const fallbackId = `input-${useId()}`;
4567
4528
  const inputId = id ?? (formControlProps == null ? void 0 : formControlProps.id) ?? fallbackId;
@@ -4576,7 +4537,7 @@ var Input = forwardRef(
4576
4537
  ref,
4577
4538
  placeholder: " "
4578
4539
  }
4579
- ), /* @__PURE__ */ React49__default.createElement(FormLabel, { htmlFor: inputId, pointerEvents: "none" }, label), rightIcon && /* @__PURE__ */ React49__default.createElement(InputRightElement, null, rightIcon));
4540
+ ), /* @__PURE__ */ React49__default.createElement(FormLabel, { htmlFor: inputId }, label), rightIcon && /* @__PURE__ */ React49__default.createElement(InputRightElement, null, rightIcon));
4580
4541
  }
4581
4542
  );
4582
4543
  var InputLeftElement2 = forwardRef(
@@ -4826,7 +4787,7 @@ var texts11 = createTexts({
4826
4787
  }
4827
4788
  });
4828
4789
  var PasswordInput = forwardRef(
4829
- ({ leftIcon, id, label, ...props }, ref) => {
4790
+ ({ leftIcon, id, label, size: size2, ...props }, ref) => {
4830
4791
  const { isOpen: isShowingPassword, onToggle } = useDisclosure();
4831
4792
  const { t: t2 } = useTranslation();
4832
4793
  const formControlProps = useFormControlContext();
@@ -4939,7 +4900,7 @@ var texts13 = createTexts({
4939
4900
  sv: "Telefonnummer"
4940
4901
  }
4941
4902
  });
4942
- var LazyCountryCodeSelect = React49__default.lazy(() => import('./CountryCodeSelect-GFQIGSFV.mjs'));
4903
+ var LazyCountryCodeSelect = React49__default.lazy(() => import('./CountryCodeSelect-ZTEYBERS.mjs'));
4943
4904
  var Radio = forwardRef((props, ref) => {
4944
4905
  return /* @__PURE__ */ React49__default.createElement(Radio$1, { ...props, ref });
4945
4906
  });
@@ -10986,7 +10947,7 @@ var config3 = helpers.defineMultiStyleConfig({
10986
10947
  },
10987
10948
  defaultProps: {
10988
10949
  variant: "list",
10989
- size: "md"
10950
+ size: "sm"
10990
10951
  }
10991
10952
  });
10992
10953
  var accordion_default = config3;
@@ -13050,19 +13011,27 @@ var config24 = helpers15.defineMultiStyleConfig({
13050
13011
  overflowY: "auto",
13051
13012
  maxHeight: "50vh",
13052
13013
  width: "100%",
13053
- listStyle: "none"
13014
+ listStyle: "none",
13015
+ borderBottomRadius: "sm"
13054
13016
  },
13055
13017
  item: {
13056
- paddingX: 3,
13057
- paddingY: 2,
13018
+ paddingX: 2,
13019
+ paddingY: 1,
13020
+ marginY: 1,
13021
+ marginX: 1,
13022
+ borderRadius: "sm",
13058
13023
  color: mode("darkGrey", "white")(props),
13059
13024
  _hover: {
13060
- background: mode("mint", "darkTeal")(props),
13025
+ backgroundColor: mode("seaMist", "darkTeal")(props),
13026
+ outline: "none"
13027
+ },
13028
+ _active: {
13029
+ backgroundColor: mode("mint", "darkTeal")(props),
13061
13030
  outline: "none"
13062
13031
  },
13063
13032
  _focus: {
13064
13033
  outline: "none",
13065
- backgroundColor: mode("mint", "darkTeal")(props)
13034
+ backgroundColor: mode("seaMist", "darkTeal")(props)
13066
13035
  },
13067
13036
  _selected: {
13068
13037
  backgroundColor: mode("pine", "pine")(props),
@@ -14567,4 +14536,4 @@ var getToastComponent = (opts) => {
14567
14536
  return ({ id }) => /* @__PURE__ */ React49__default.createElement(BaseToast, { id, variant: opts.variant }, opts.text);
14568
14537
  };
14569
14538
 
14570
- export { Accordion, AttachedInputs, Autosuggest, Badge, Button, ButtonGroup, Card, CardSelect, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, ColorInlineLoader, ColorSpinner, Combobox, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerContent, Expandable, ExpandableAlert, ExpandableItem, FloatingActionButton, FormControl, FormErrorMessage, FormLabel3 as FormLabel, Heading, IconButton, InfoSelect, InfoTag, Input, InputLeftElement2 as InputLeftElement, InputRightElement2 as InputRightElement, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightSpinner, LineIcon, ListBox, ModalHeader, NativeSelect, NumericStepper, PasswordInput, PhoneNumberInput, PlayPauseButton, PopoverWizardBody, ProgressBar, ProgressLoader, Radio, RadioGroup, SearchInput, SelectItem, SelectItemDescription, SelectItemLabel, SimpleDrawer, SimplePopover, Skeleton, SkeletonCircle, SkeletonText, SkipButton, SporProvider, Stack, StaticAlert, Stepper, StepperStep, Switch, Table, Tabs, Text4 as Text, TextLink, Textarea, TimePicker, TravelTag, VyLogo, WizardPopover, createTexts, fontFaces, theme, useToast, useTranslation };
14539
+ export { Accordion, AttachedInputs, Badge, Button, ButtonGroup, Card, CardSelect, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, ColorInlineLoader, ColorSpinner, Combobox, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerContent, Expandable, ExpandableAlert, ExpandableItem, FloatingActionButton, FormControl, FormErrorMessage, FormLabel3 as FormLabel, Heading, IconButton, InfoSelect, InfoTag, Input, InputLeftElement2 as InputLeftElement, InputRightElement2 as InputRightElement, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightSpinner, LineIcon, ListBox, ModalHeader, NativeSelect, NumericStepper, PasswordInput, PhoneNumberInput, PlayPauseButton, PopoverWizardBody, ProgressBar, ProgressLoader, Radio, RadioGroup, SearchInput, SelectItem, SelectItemDescription, SelectItemLabel, SimpleDrawer, SimplePopover, Skeleton, SkeletonCircle, SkeletonText, SkipButton, SporProvider, Stack, StaticAlert, Stepper, StepperStep, Switch, Table, Tabs, Text4 as Text, TextLink, Textarea, TimePicker, TravelTag, VyLogo, WizardPopover, createTexts, fontFaces, theme, useToast, useTranslation };
package/dist/index.d.ts CHANGED
@@ -397,10 +397,10 @@ type CardProps = Exclude<BoxProps, "size"> & {
397
397
  * </Card>
398
398
  * ```
399
399
  *
400
- * There are lots of color schemes available. You can also set the size as either `sm` or `lg`. The default is `lg`.
400
+ * There are lots of color schemes available. You can also set the size as either `sm` or `lg`. The default is `sm`.
401
401
  *
402
402
  * ```tsx
403
- * <Card colorScheme="orange" size="sm">
403
+ * <Card colorScheme="orange" size="lg">
404
404
  * A smaller card
405
405
  * </Card>
406
406
  * ```
@@ -607,109 +607,6 @@ type AttachedInputsProps = FlexProps;
607
607
  */
608
608
  declare const AttachedInputs: ({ flexDirection, ...rest }: AttachedInputsProps) => React__default.JSX.Element;
609
609
 
610
- type AutosuggestProps<T> = {
611
- /** The label of the search field */
612
- label: string;
613
- /**
614
- * The function responsible for fetching new suggestion items, based on the query.
615
- *
616
- * This will typically be an API call to a backend service.
617
- *
618
- * @example
619
- * ```tsx
620
- * const fetcher = async (query?: string) => {
621
- * const response = await fetch(`https://some.api.com/filter=${query}`);
622
- * const json = await response.json();
623
- * return json;
624
- * };
625
- * ```
626
- * */
627
- fetcher: (query?: string) => Promise<Iterable<T>>;
628
- /**
629
- * A render function that receives each item, and returns the UI for each item in the list.
630
- *
631
- * @example
632
- * ```tsx
633
- * <Autosuggest {...otherProps}>
634
- * {(user) => (
635
- * <Item key={user.id} textValue={user.fullName}>
636
- * <ItemLabel>{user.fullName}</ItemLabel>
637
- * <ItemDescription>{user.asl}</ItemDescription>
638
- * </Item>
639
- * )}
640
- * </Autosuggest>
641
- * ```
642
- *
643
- * You technically don't need to use the `<SelectItemLabel />` and `<SelectItemDescription />` components, but they are recommended to improve the accessibility of the search results. You can style them however you want, so there should never be a reason not to include at least the `<SelectItemLabel />` component. But who's judging?
644
- * */
645
- children: ComboboxProps<T>["children"];
646
- /**
647
- * Callback for when the selection changes. Returns the entire item.
648
- */
649
- onSelectionChange?: (item: T) => void;
650
- /** The selected item key (controlled) */
651
- selectedKey?: ComboboxProps<T>["selectedKey"];
652
- /** What should open the menu.
653
- *
654
- * Defaults to "input"
655
- */
656
- menuTrigger?: ComboboxProps<T>["menuTrigger"];
657
- } & Pick<InputProps, "marginTop" | "marginBottom" | "marginRight" | "marginLeft" | "marginY" | "marginX" | "paddingTop" | "paddingBottom" | "paddingLeft" | "paddingRight" | "paddingY" | "paddingX" | "leftIcon" | "rightIcon" | "borderTopRightRadius" | "borderTopLeftRadius" | "borderBottomRightRadius" | "borderBottomLeftRadius" | "onFocus">;
658
- /**
659
- * A component that provides an autocomplete search field with suggestions.
660
- *
661
- * This component requires a `fetcher` prop, which is a function that receives a query string, and returns a list of items that match the query.
662
- *
663
- * @example
664
- * ```tsx
665
- * const fetcher = async (query?: string) => {
666
- * const response = await fetch(`https://some.api.vy.no/filter=${query}`);
667
- * const json = await response.json();
668
- * return json;
669
- * };
670
- *
671
- * const Example = () => {
672
- * return (
673
- * <Autosuggest
674
- * label="Search for users"
675
- * fetcher={fetcher}
676
- * onSelectionChange={(item) => console.log(item)}
677
- * >
678
- * {(user) => (
679
- * <Item key={user.id} textValue={user.fullName}>
680
- * <ItemLabel>{user.fullName}</ItemLabel>
681
- * <ItemDescription>{user.asl}</ItemDescription>
682
- * </Item>
683
- * )}
684
- * </Autosuggest>
685
- * );
686
- * };
687
- * ```
688
- *
689
- * The `fetcher` function can be any function that returns an iterable of items. This means that you can use any API library you want, as long as it returns an iterable of items.
690
- *
691
- * The items need to have a `key` property, which is used to identify the item. The `key` property can be any type, but it needs to be unique for each item.
692
- *
693
- * ```tsx
694
- * [{ key: 'some-key', ...}, { key: 'some-other-key', ... }]
695
- * ```
696
- *
697
- * You can also return a set of nested items, which will be rendered as a sub-list (or section). This is useful if you want to group your items. These items need to have a title prop (for labelling the section), as well as a `children` prop, which in turn will contain an iterable of items:
698
- *
699
- * ```tsx
700
- * [
701
- * {
702
- * title: 'The title of the section',
703
- * children: [{ key: 'some-key', ... }]
704
- * },
705
- * {...}
706
- * ]
707
- * ```
708
- *
709
- * The `onSelectionChanged` will return the correct `item` (the one with the matching `key`), even if the item is in a sub-list.
710
- */
711
- declare function Autosuggest<T extends object>({ label, fetcher, onSelectionChange, ...props }: AutosuggestProps<T>): React__default.JSX.Element;
712
-
713
610
  type CardSelectProps = BoxProps & {
714
611
  /** The design of the trigger button.
715
612
  *
@@ -845,6 +742,8 @@ type ComboboxProps<T> = AriaComboBoxProps<T> & {
845
742
  label: string;
846
743
  /** Whether or not the combobox is waiting for new suggestions */
847
744
  isLoading?: boolean;
745
+ /** Optional UI to show when there are no matching items */
746
+ emptyContent?: React__default.ReactNode;
848
747
  } & Pick<InputProps, "marginTop" | "marginBottom" | "marginRight" | "marginLeft" | "marginY" | "marginX" | "paddingTop" | "paddingBottom" | "paddingLeft" | "paddingRight" | "paddingY" | "paddingX" | "leftIcon" | "rightIcon" | "borderTopRightRadius" | "borderTopLeftRadius" | "borderBottomRightRadius" | "borderBottomLeftRadius" | "onFocus">;
849
748
  /**
850
749
  * A combobox is a combination of an input and a list of suggestions.
@@ -869,7 +768,7 @@ type ComboboxProps<T> = AriaComboBoxProps<T> & {
869
768
  * </Combobox>
870
769
  * ```
871
770
  */
872
- declare function Combobox<T extends object>({ label, isLoading, leftIcon, rightIcon, borderBottomLeftRadius, borderBottomRightRadius, borderTopLeftRadius, borderTopRightRadius, marginBottom, marginTop, marginX, marginY, marginRight, marginLeft, paddingBottom, paddingRight, paddingTop, paddingLeft, paddingX, paddingY, onFocus, ...rest }: ComboboxProps<T>): React__default.JSX.Element;
771
+ declare function Combobox<T extends object>({ label, isLoading, leftIcon, rightIcon, borderBottomLeftRadius, borderBottomRightRadius, borderTopLeftRadius, borderTopRightRadius, marginBottom, marginTop, marginX, marginY, marginRight, marginLeft, paddingBottom, paddingRight, paddingTop, paddingLeft, paddingX, paddingY, emptyContent, ...rest }: ComboboxProps<T>): React__default.JSX.Element;
873
772
 
874
773
  type FormControlProps = FormControlProps$1;
875
774
  declare const FormControl: _chakra_ui_system_dist_system_types.ComponentWithAs<"div", FormControlProps$1>;
@@ -1045,7 +944,7 @@ type InfoSelectProps<T extends object> = {
1045
944
  */
1046
945
  declare function InfoSelect<T extends object>({ placeholder, width, height, onChange, value, isLabelSrOnly, defaultValue, ...props }: InfoSelectProps<T>): React__default.JSX.Element;
1047
946
 
1048
- type InputProps = Exclude<InputProps$1, "variant" | "size"> & {
947
+ type InputProps = Omit<InputProps$1, "variant" | "size"> & {
1049
948
  /** The input's label */
1050
949
  label: string;
1051
950
  /** Icon that shows up to the left */
@@ -1112,6 +1011,8 @@ type ListBoxProps<T> = AriaListBoxProps<T> & Omit<BoxProps, "filter" | "autoFocu
1112
1011
  isLoading?: boolean;
1113
1012
  /** The state of the listbox, provided externally somehow. */
1114
1013
  state: ListState<T> | SelectState<T>;
1014
+ /** UI to render if the collection is empty */
1015
+ emptyContent?: React__default.ReactNode;
1115
1016
  };
1116
1017
  /**
1117
1018
  * A component that renders a list box with selectable options.
@@ -3750,13 +3651,21 @@ declare const theme: {
3750
3651
  maxHeight: string;
3751
3652
  width: string;
3752
3653
  listStyle: string;
3654
+ borderBottomRadius: string;
3753
3655
  };
3754
3656
  item: {
3755
3657
  paddingX: number;
3756
3658
  paddingY: number;
3659
+ marginY: number;
3660
+ marginX: number;
3661
+ borderRadius: string;
3757
3662
  color: string;
3758
3663
  _hover: {
3759
- background: string;
3664
+ backgroundColor: string;
3665
+ outline: string;
3666
+ };
3667
+ _active: {
3668
+ backgroundColor: string;
3760
3669
  outline: string;
3761
3670
  };
3762
3671
  _focus: {
@@ -7099,4 +7008,4 @@ type TextProps = Omit<TextProps$1, "textStyle"> & {
7099
7008
  */
7100
7009
  declare const Text: _chakra_ui_system_dist_system_types.ComponentWithAs<"p", TextProps>;
7101
7010
 
7102
- export { Accordion, AccordionProps, AttachedInputs, Autosuggest, Badge, BadgeProps, Button, ButtonGroup, ButtonGroupProps, ButtonProps, Card, CardProps, CardSelect, Checkbox, CheckboxGroup, CheckboxGroupProps, CheckboxProps, ChoiceChip, ChoiceChipProps, ClosableAlert, CloseButton, CloseButtonProps, Code, CodeProps, ColorInlineLoader, ColorInlineLoaderProps, ColorSpinner, ColorSpinnerProps, Combobox, ComboboxProps, ContentLoader, ContentLoaderProps, DarkFullScreenLoader, DarkInlineLoader, DarkInlineLoaderProps, DarkSpinner, DarkSpinnerProps, DatePicker, DateRangePicker, Divider, DividerProps, Drawer, DrawerContent, ModalHeader as DrawerHeader, Expandable, ExpandableAlert, ExpandableItem, ExpandableItemProps, FloatingActionButton, FormControl, FormControlProps, FormErrorMessage, FormErrorMessageProps, FormLabel, FormLabelProps, Heading, HeadingProps, IconButton, IconButtonProps, InfoSelect, InfoTag, InfoTagProps, Input, InputElementProps, InputLeftElement, InputProps, InputRightElement, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightInlineLoaderProps, LightSpinner, LightSpinnerProps, LineIcon, LineIconProps, ListBox, ModalHeader, ModalHeaderProps, NativeSelect, NativeSelectProps, NumericStepper, PasswordInput, PasswordInputProps, PhoneNumberInput, PlayPauseButton, PopoverWizardBody, PopoverWizardProps, ProgressBar, ProgressLoader, Radio, RadioGroup, RadioGroupProps, RadioProps, SearchInput, SearchInputProps, SelectItem, SelectItemDescription, SelectItemLabel, SimpleDrawer, SimpleDrawerProps, SimplePopover, Skeleton, SkeletonCircle, SkeletonCircleProps, SkeletonProps, SkeletonText, SkeletonTextProps, SkipButton, SpinnerProps, SporProvider, Stack, StackProps, StaticAlert, Stepper, StepperStep, Switch, SwitchProps, Table, TableProps, Tabs, TabsProps, Text, TextLink, TextProps, Textarea, TextareaProps, TimePicker, ToastOptions, Translations, TravelTag, TravelTagProps, VyLogo, VyLogoProps, WizardPopover, WizardPopoverProps, createTexts, fontFaces, theme, useToast, useTranslation };
7011
+ export { Accordion, AccordionProps, AttachedInputs, Badge, BadgeProps, Button, ButtonGroup, ButtonGroupProps, ButtonProps, Card, CardProps, CardSelect, Checkbox, CheckboxGroup, CheckboxGroupProps, CheckboxProps, ChoiceChip, ChoiceChipProps, ClosableAlert, CloseButton, CloseButtonProps, Code, CodeProps, ColorInlineLoader, ColorInlineLoaderProps, ColorSpinner, ColorSpinnerProps, Combobox, ComboboxProps, ContentLoader, ContentLoaderProps, DarkFullScreenLoader, DarkInlineLoader, DarkInlineLoaderProps, DarkSpinner, DarkSpinnerProps, DatePicker, DateRangePicker, Divider, DividerProps, Drawer, DrawerContent, ModalHeader as DrawerHeader, Expandable, ExpandableAlert, ExpandableItem, ExpandableItemProps, FloatingActionButton, FormControl, FormControlProps, FormErrorMessage, FormErrorMessageProps, FormLabel, FormLabelProps, Heading, HeadingProps, IconButton, IconButtonProps, InfoSelect, InfoTag, InfoTagProps, Input, InputElementProps, InputLeftElement, InputProps, InputRightElement, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightInlineLoaderProps, LightSpinner, LightSpinnerProps, LineIcon, LineIconProps, ListBox, ModalHeader, ModalHeaderProps, NativeSelect, NativeSelectProps, NumericStepper, PasswordInput, PasswordInputProps, PhoneNumberInput, PlayPauseButton, PopoverWizardBody, PopoverWizardProps, ProgressBar, ProgressLoader, Radio, RadioGroup, RadioGroupProps, RadioProps, SearchInput, SearchInputProps, SelectItem, SelectItemDescription, SelectItemLabel, SimpleDrawer, SimpleDrawerProps, SimplePopover, Skeleton, SkeletonCircle, SkeletonCircleProps, SkeletonProps, SkeletonText, SkeletonTextProps, SkipButton, SpinnerProps, SporProvider, Stack, StackProps, StaticAlert, Stepper, StepperStep, Switch, SwitchProps, Table, TableProps, Tabs, TabsProps, Text, TextLink, TextProps, Textarea, TextareaProps, TimePicker, ToastOptions, Translations, TravelTag, TravelTagProps, VyLogo, VyLogoProps, WizardPopover, WizardPopoverProps, createTexts, fontFaces, theme, useToast, useTranslation };
package/dist/index.js CHANGED
@@ -1075,7 +1075,7 @@ var init_Card = __esm({
1075
1075
  "src/card/Card.tsx"() {
1076
1076
  init_layout();
1077
1077
  exports.Card = react.forwardRef(
1078
- ({ size: size2 = "lg", colorScheme = "white", children, ...props }, ref) => {
1078
+ ({ size: size2 = "sm", colorScheme = "white", children, ...props }, ref) => {
1079
1079
  const styles2 = react.useStyleConfig("Card", {
1080
1080
  colorScheme,
1081
1081
  size: size2
@@ -3750,51 +3750,6 @@ var init_AttachedInputs = __esm({
3750
3750
  };
3751
3751
  }
3752
3752
  });
3753
- function Autosuggest({
3754
- label,
3755
- fetcher,
3756
- onSelectionChange,
3757
- ...props
3758
- }) {
3759
- const list2 = reactStately.useAsyncList({
3760
- async load({ filterText }) {
3761
- return {
3762
- items: await fetcher(filterText)
3763
- };
3764
- }
3765
- });
3766
- const handleSelectionChange = (key) => {
3767
- if (!onSelectionChange) {
3768
- return;
3769
- }
3770
- let selectedItem = list2.getItem(key);
3771
- if (!selectedItem) {
3772
- selectedItem = list2.items.flatMap(
3773
- (item) => "children" in item && Array.isArray(item.children) ? item.children : []
3774
- ).find((child) => child.key === key);
3775
- }
3776
- if (selectedItem) {
3777
- onSelectionChange(selectedItem);
3778
- }
3779
- };
3780
- return /* @__PURE__ */ React49__namespace.default.createElement(
3781
- Combobox,
3782
- {
3783
- label,
3784
- items: list2.items,
3785
- inputValue: list2.filterText,
3786
- onInputChange: list2.setFilterText,
3787
- onSelectionChange: handleSelectionChange,
3788
- isLoading: list2.isLoading,
3789
- ...props
3790
- }
3791
- );
3792
- }
3793
- var init_Autosuggest = __esm({
3794
- "src/input/Autosuggest.tsx"() {
3795
- init_src();
3796
- }
3797
- });
3798
3753
  var Dialog;
3799
3754
  var init_Dialog = __esm({
3800
3755
  "src/input/Dialog.tsx"() {
@@ -4767,17 +4722,18 @@ function Combobox({
4767
4722
  paddingLeft,
4768
4723
  paddingX,
4769
4724
  paddingY,
4770
- onFocus,
4725
+ emptyContent,
4771
4726
  ...rest
4772
4727
  }) {
4773
4728
  const { contains: contains2 } = reactAria.useFilter({ sensitivity: "base" });
4774
- const state2 = reactStately.useComboBoxState({
4775
- ...rest,
4776
- defaultFilter: contains2
4777
- });
4778
4729
  const inputRef = React49.useRef(null);
4779
4730
  const listBoxRef = React49.useRef(null);
4780
4731
  const popoverRef = React49.useRef(null);
4732
+ const state2 = reactStately.useComboBoxState({
4733
+ ...rest,
4734
+ defaultFilter: contains2,
4735
+ allowsEmptyCollection: Boolean(emptyContent)
4736
+ });
4781
4737
  const {
4782
4738
  inputProps: { size: size2, ...inputProps },
4783
4739
  listBoxProps
@@ -4796,7 +4752,6 @@ function Combobox({
4796
4752
  ...inputProps,
4797
4753
  ref: inputRef,
4798
4754
  label,
4799
- onFocus,
4800
4755
  borderBottomLeftRadius: state2.isOpen ? 0 : borderBottomLeftRadius,
4801
4756
  borderBottomRightRadius: state2.isOpen ? 0 : borderBottomRightRadius,
4802
4757
  borderTopLeftRadius,
@@ -4842,7 +4797,7 @@ function Combobox({
4842
4797
  ...listBoxProps,
4843
4798
  state: state2,
4844
4799
  listBoxRef,
4845
- borderBottomRadius: "sm"
4800
+ emptyContent
4846
4801
  },
4847
4802
  rest.children
4848
4803
  )
@@ -4949,6 +4904,7 @@ function ListBox({
4949
4904
  sx: styles2.container,
4950
4905
  "aria-busy": isLoading
4951
4906
  },
4907
+ state2.collection.size === 0 && props.emptyContent,
4952
4908
  Array.from(state2.collection).map(
4953
4909
  (item) => item.type === "section" ? /* @__PURE__ */ React49__namespace.default.createElement(ListBoxSection, { key: item.key, section: item, state: state2 }) : /* @__PURE__ */ React49__namespace.default.createElement(Option, { key: item.key, item, state: state2 })
4954
4910
  )
@@ -4992,18 +4948,18 @@ function ListBoxSection({ section, state: state2 }) {
4992
4948
  heading: section.rendered,
4993
4949
  "aria-label": section["aria-label"]
4994
4950
  });
4995
- const isFirstSection = section.key !== state2.collection.getFirstKey();
4996
- const titleBackgroundColor = react.useColorModeValue("platinum", "dimGrey");
4951
+ const isFirstSection = section.key === state2.collection.getFirstKey();
4997
4952
  const titleColor = react.useColorModeValue("darkGrey", "white");
4998
4953
  return /* @__PURE__ */ React49__namespace.default.createElement(react.ListItem, { ...itemProps }, section.rendered && /* @__PURE__ */ React49__namespace.default.createElement(
4999
4954
  react.Box,
5000
4955
  {
5001
- textStyle: "xs",
5002
- backgroundColor: titleBackgroundColor,
4956
+ fontSize: "mobile.xs",
5003
4957
  color: titleColor,
5004
4958
  paddingX: 3,
5005
4959
  paddingY: 1,
5006
- marginTop: isFirstSection ? 0 : 0,
4960
+ marginTop: isFirstSection ? 0 : 3,
4961
+ textTransform: "uppercase",
4962
+ fontWeight: "bold",
5007
4963
  ...headingProps
5008
4964
  },
5009
4965
  section.rendered
@@ -5111,7 +5067,7 @@ exports.Input = void 0;
5111
5067
  var init_Input = __esm({
5112
5068
  "src/input/Input.tsx"() {
5113
5069
  exports.Input = react.forwardRef(
5114
- ({ label, leftIcon, rightIcon, id, ...props }, ref) => {
5070
+ ({ label, leftIcon, rightIcon, id, size: size2, ...props }, ref) => {
5115
5071
  const formControlProps = react.useFormControlContext();
5116
5072
  const fallbackId = `input-${React49.useId()}`;
5117
5073
  const inputId = id ?? (formControlProps == null ? void 0 : formControlProps.id) ?? fallbackId;
@@ -5126,7 +5082,7 @@ var init_Input = __esm({
5126
5082
  ref,
5127
5083
  placeholder: " "
5128
5084
  }
5129
- ), /* @__PURE__ */ React49__namespace.default.createElement(react.FormLabel, { htmlFor: inputId, pointerEvents: "none" }, label), rightIcon && /* @__PURE__ */ React49__namespace.default.createElement(react.InputRightElement, null, rightIcon));
5085
+ ), /* @__PURE__ */ React49__namespace.default.createElement(react.FormLabel, { htmlFor: inputId }, label), rightIcon && /* @__PURE__ */ React49__namespace.default.createElement(react.InputRightElement, null, rightIcon));
5130
5086
  }
5131
5087
  );
5132
5088
  }
@@ -5422,7 +5378,7 @@ var init_PasswordInput = __esm({
5422
5378
  init_input();
5423
5379
  init_src();
5424
5380
  exports.PasswordInput = react.forwardRef(
5425
- ({ leftIcon, id, label, ...props }, ref) => {
5381
+ ({ leftIcon, id, label, size: size2, ...props }, ref) => {
5426
5382
  const { isOpen: isShowingPassword, onToggle } = react.useDisclosure();
5427
5383
  const { t: t2 } = useTranslation();
5428
5384
  const formControlProps = react.useFormControlContext();
@@ -12358,7 +12314,6 @@ var init_Textarea = __esm({
12358
12314
  var init_input = __esm({
12359
12315
  "src/input/index.tsx"() {
12360
12316
  init_AttachedInputs();
12361
- init_Autosuggest();
12362
12317
  init_CardSelect();
12363
12318
  init_Checkbox();
12364
12319
  init_CheckboxGroup();
@@ -18993,7 +18948,7 @@ var init_accordion2 = __esm({
18993
18948
  },
18994
18949
  defaultProps: {
18995
18950
  variant: "list",
18996
- size: "md"
18951
+ size: "sm"
18997
18952
  }
18998
18953
  });
18999
18954
  accordion_default = config3;
@@ -21200,19 +21155,27 @@ var init_listbox = __esm({
21200
21155
  overflowY: "auto",
21201
21156
  maxHeight: "50vh",
21202
21157
  width: "100%",
21203
- listStyle: "none"
21158
+ listStyle: "none",
21159
+ borderBottomRadius: "sm"
21204
21160
  },
21205
21161
  item: {
21206
- paddingX: 3,
21207
- paddingY: 2,
21162
+ paddingX: 2,
21163
+ paddingY: 1,
21164
+ marginY: 1,
21165
+ marginX: 1,
21166
+ borderRadius: "sm",
21208
21167
  color: themeTools.mode("darkGrey", "white")(props),
21209
21168
  _hover: {
21210
- background: themeTools.mode("mint", "darkTeal")(props),
21169
+ backgroundColor: themeTools.mode("seaMist", "darkTeal")(props),
21170
+ outline: "none"
21171
+ },
21172
+ _active: {
21173
+ backgroundColor: themeTools.mode("mint", "darkTeal")(props),
21211
21174
  outline: "none"
21212
21175
  },
21213
21176
  _focus: {
21214
21177
  outline: "none",
21215
- backgroundColor: themeTools.mode("mint", "darkTeal")(props)
21178
+ backgroundColor: themeTools.mode("seaMist", "darkTeal")(props)
21216
21179
  },
21217
21180
  _selected: {
21218
21181
  backgroundColor: themeTools.mode("pine", "pine")(props),
@@ -23271,7 +23234,6 @@ Object.defineProperty(exports, 'Section', {
23271
23234
  get: function () { return reactStately.Section; }
23272
23235
  });
23273
23236
  exports.tokens = tokens10__namespace;
23274
- exports.Autosuggest = Autosuggest;
23275
23237
  exports.Combobox = Combobox;
23276
23238
  exports.DatePicker = DatePicker;
23277
23239
  exports.DateRangePicker = DateRangePicker;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, AttachedInputs, Autosuggest, Badge, Box, Button, ButtonGroup, Card, CardSelect, Center, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, Collapse, ColorInlineLoader, ColorSpinner, Combobox, Container, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkMode, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, ModalHeader as DrawerHeader, DrawerOverlay, Expandable, ExpandableAlert, ExpandableItem, Fade, Flex, FloatingActionButton, FormControl, FormErrorMessage, FormHelperText, FormLabel, Grid, GridItem, HStack, Heading, IconButton, Image, Img, InfoSelect, InfoTag, Input, InputGroup, InputLeftElement, InputRightElement, Item, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightMode, LightSpinner, LineIcon, ListBox, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, NativeSelect, NumericStepper, PasswordInput, PhoneNumberInput, PlayPauseButton, Popover, PopoverAnchor, PopoverArrow, PopoverBody, PopoverCloseButton, PopoverContent, PopoverFooter, PopoverHeader, PopoverTrigger, PopoverWizardBody, ProgressBar, ProgressLoader, Radio, RadioGroup, ScaleFade, SearchInput, Section, SelectItem, SelectItemDescription, SelectItemLabel, SimpleDrawer, SimpleGrid, SimplePopover, Skeleton, SkeletonCircle, SkeletonText, SkipButton, Slide, SlideFade, Spacer, SporProvider, Stack, StaticAlert, Stepper, StepperStep, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableCaption, Tabs, Tbody, Td, Text, TextLink, Textarea, Tfoot, Th, Thead, Time, TimePicker, Tr, TravelTag, VStack, VyLogo, WizardPopover, Wrap, WrapItem, createTexts, extendTheme, fontFaces, theme, tokens, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMediaQuery, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useTheme, useToast, useToken, useTranslation } from './chunk-Z3I6W6PC.mjs';
1
+ export { Accordion, AccordionButton, AccordionIcon, AccordionItem, AccordionPanel, AttachedInputs, Badge, Box, Button, ButtonGroup, Card, CardSelect, Center, Checkbox, CheckboxGroup, ChoiceChip, ClosableAlert, CloseButton, Code, Collapse, ColorInlineLoader, ColorSpinner, Combobox, Container, ContentLoader, DarkFullScreenLoader, DarkInlineLoader, DarkMode, DarkSpinner, DatePicker, DateRangePicker, Divider, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerFooter, ModalHeader as DrawerHeader, DrawerOverlay, Expandable, ExpandableAlert, ExpandableItem, Fade, Flex, FloatingActionButton, FormControl, FormErrorMessage, FormHelperText, FormLabel, Grid, GridItem, HStack, Heading, IconButton, Image, Img, InfoSelect, InfoTag, Input, InputGroup, InputLeftElement, InputRightElement, Item, ItemDescription, ItemLabel, JumpButton, Language, LanguageProvider, LightFullScreenLoader, LightInlineLoader, LightMode, LightSpinner, LineIcon, ListBox, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, NativeSelect, NumericStepper, PasswordInput, PhoneNumberInput, PlayPauseButton, Popover, PopoverAnchor, PopoverArrow, PopoverBody, PopoverCloseButton, PopoverContent, PopoverFooter, PopoverHeader, PopoverTrigger, PopoverWizardBody, ProgressBar, ProgressLoader, Radio, RadioGroup, ScaleFade, SearchInput, Section, SelectItem, SelectItemDescription, SelectItemLabel, SimpleDrawer, SimpleGrid, SimplePopover, Skeleton, SkeletonCircle, SkeletonText, SkipButton, Slide, SlideFade, Spacer, SporProvider, Stack, StaticAlert, Stepper, StepperStep, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableCaption, Tabs, Tbody, Td, Text, TextLink, Textarea, Tfoot, Th, Thead, Time, TimePicker, Tr, TravelTag, VStack, VyLogo, WizardPopover, Wrap, WrapItem, createTexts, extendTheme, fontFaces, theme, tokens, useBreakpointValue, useClipboard, useColorMode, useColorModePreference, useColorModeValue, useControllableProp, useDisclosure, useMediaQuery, useMergeRefs, useOutsideClick, usePrefersReducedMotion, useTheme, useToast, useToken, useTranslation } from './chunk-7GRTZA6T.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vygruppen/spor-react",
3
- "version": "2.4.3",
3
+ "version": "2.5.0",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
package/src/card/Card.tsx CHANGED
@@ -25,10 +25,10 @@ export type CardProps = Exclude<BoxProps, "size"> & {
25
25
  * </Card>
26
26
  * ```
27
27
  *
28
- * There are lots of color schemes available. You can also set the size as either `sm` or `lg`. The default is `lg`.
28
+ * There are lots of color schemes available. You can also set the size as either `sm` or `lg`. The default is `sm`.
29
29
  *
30
30
  * ```tsx
31
- * <Card colorScheme="orange" size="sm">
31
+ * <Card colorScheme="orange" size="lg">
32
32
  * A smaller card
33
33
  * </Card>
34
34
  * ```
@@ -45,7 +45,7 @@ export type CardProps = Exclude<BoxProps, "size"> & {
45
45
  * ```
46
46
  */
47
47
  export const Card = forwardRef<CardProps, As>(
48
- ({ size = "lg", colorScheme = "white", children, ...props }, ref) => {
48
+ ({ size = "sm", colorScheme = "white", children, ...props }, ref) => {
49
49
  const styles = useStyleConfig("Card", {
50
50
  colorScheme,
51
51
  size,
@@ -9,6 +9,8 @@ export type ComboboxProps<T> = AriaComboBoxProps<T> & {
9
9
  label: string;
10
10
  /** Whether or not the combobox is waiting for new suggestions */
11
11
  isLoading?: boolean;
12
+ /** Optional UI to show when there are no matching items */
13
+ emptyContent?: React.ReactNode;
12
14
  } & Pick<
13
15
  InputProps,
14
16
  | "marginTop"
@@ -75,19 +77,21 @@ export function Combobox<T extends object>({
75
77
  paddingLeft,
76
78
  paddingX,
77
79
  paddingY,
78
- onFocus,
80
+ emptyContent,
79
81
  ...rest
80
82
  }: ComboboxProps<T>) {
81
83
  const { contains } = useFilter({ sensitivity: "base" });
82
- const state = useComboBoxState({
83
- ...rest,
84
- defaultFilter: contains,
85
- });
86
84
 
87
85
  const inputRef = useRef(null);
88
86
  const listBoxRef = useRef(null);
89
87
  const popoverRef = useRef(null);
90
88
 
89
+ const state = useComboBoxState({
90
+ ...rest,
91
+ defaultFilter: contains,
92
+ allowsEmptyCollection: Boolean(emptyContent),
93
+ });
94
+
91
95
  const {
92
96
  inputProps: { size, ...inputProps },
93
97
  listBoxProps,
@@ -107,7 +111,6 @@ export function Combobox<T extends object>({
107
111
  {...inputProps}
108
112
  ref={inputRef}
109
113
  label={label}
110
- onFocus={onFocus}
111
114
  borderBottomLeftRadius={state.isOpen ? 0 : borderBottomLeftRadius}
112
115
  borderBottomRightRadius={state.isOpen ? 0 : borderBottomRightRadius}
113
116
  borderTopLeftRadius={borderTopLeftRadius}
@@ -153,7 +156,7 @@ export function Combobox<T extends object>({
153
156
  {...listBoxProps}
154
157
  state={state}
155
158
  listBoxRef={listBoxRef}
156
- borderBottomRadius="sm"
159
+ emptyContent={emptyContent}
157
160
  >
158
161
  {rest.children}
159
162
  </ListBox>
@@ -10,7 +10,7 @@ import {
10
10
  } from "@chakra-ui/react";
11
11
  import React, { useId } from "react";
12
12
 
13
- export type InputProps = Exclude<ChakraInputProps, "variant" | "size"> & {
13
+ export type InputProps = Omit<ChakraInputProps, "variant" | "size"> & {
14
14
  /** The input's label */
15
15
  label: string;
16
16
  /** Icon that shows up to the left */
@@ -34,7 +34,7 @@ export type InputProps = Exclude<ChakraInputProps, "variant" | "size"> & {
34
34
  * ```
35
35
  */
36
36
  export const Input = forwardRef<InputProps, "input">(
37
- ({ label, leftIcon, rightIcon, id, ...props }, ref) => {
37
+ ({ label, leftIcon, rightIcon, id, size, ...props }, ref) => {
38
38
  const formControlProps = useFormControlContext();
39
39
  const fallbackId = `input-${useId()}`;
40
40
  const inputId = id ?? formControlProps?.id ?? fallbackId;
@@ -50,9 +50,7 @@ export const Input = forwardRef<InputProps, "input">(
50
50
  ref={ref}
51
51
  placeholder=" " // This is needed to make the label work as expected
52
52
  />
53
- <FormLabel htmlFor={inputId} pointerEvents="none">
54
- {label}
55
- </FormLabel>
53
+ <FormLabel htmlFor={inputId}>{label}</FormLabel>
56
54
  {rightIcon && <InputRightElement>{rightIcon}</InputRightElement>}
57
55
  </InputGroup>
58
56
  );
@@ -28,6 +28,8 @@ type ListBoxProps<T> = AriaListBoxProps<T> &
28
28
  isLoading?: boolean;
29
29
  /** The state of the listbox, provided externally somehow. */
30
30
  state: ListState<T> | SelectState<T>;
31
+ /** UI to render if the collection is empty */
32
+ emptyContent?: React.ReactNode;
31
33
  };
32
34
 
33
35
  /**
@@ -80,6 +82,7 @@ export function ListBox<T extends object>({
80
82
  sx={styles.container}
81
83
  aria-busy={isLoading}
82
84
  >
85
+ {state.collection.size === 0 && props.emptyContent}
83
86
  {Array.from(state.collection).map((item) =>
84
87
  item.type === "section" ? (
85
88
  <ListBoxSection key={item.key} section={item} state={state} />
@@ -184,19 +187,19 @@ function ListBoxSection({ section, state }: ListBoxSectionProps) {
184
187
  "aria-label": section["aria-label"],
185
188
  });
186
189
 
187
- const isFirstSection = section.key !== state.collection.getFirstKey();
188
- const titleBackgroundColor = useColorModeValue("platinum", "dimGrey");
190
+ const isFirstSection = section.key === state.collection.getFirstKey();
189
191
  const titleColor = useColorModeValue("darkGrey", "white");
190
192
  return (
191
193
  <ListItem {...itemProps}>
192
194
  {section.rendered && (
193
195
  <Box
194
- textStyle="xs"
195
- backgroundColor={titleBackgroundColor}
196
+ fontSize="mobile.xs"
196
197
  color={titleColor}
197
198
  paddingX={3}
198
199
  paddingY={1}
199
- marginTop={isFirstSection ? 0 : 0}
200
+ marginTop={isFirstSection ? 0 : 3}
201
+ textTransform="uppercase"
202
+ fontWeight="bold"
200
203
  {...headingProps}
201
204
  >
202
205
  {section.rendered}
@@ -17,7 +17,7 @@ import { createTexts, useTranslation } from "..";
17
17
 
18
18
  export type PasswordInputProps = InputProps;
19
19
  export const PasswordInput = forwardRef<PasswordInputProps, "input">(
20
- ({ leftIcon, id, label, ...props }, ref) => {
20
+ ({ leftIcon, id, label, size, ...props }, ref) => {
21
21
  const { isOpen: isShowingPassword, onToggle } = useDisclosure();
22
22
  const { t } = useTranslation();
23
23
  const formControlProps = useFormControlContext();
@@ -1,7 +1,6 @@
1
1
  export { FormHelperText, InputGroup } from "@chakra-ui/react";
2
2
  export type { InputGroupProps } from "@chakra-ui/react";
3
3
  export * from "./AttachedInputs";
4
- export * from "./Autosuggest";
5
4
  export * from "./CardSelect";
6
5
  export * from "./Checkbox";
7
6
  export * from "./CheckboxGroup";
@@ -136,7 +136,7 @@ const config = helpers.defineMultiStyleConfig({
136
136
  },
137
137
  defaultProps: {
138
138
  variant: "list",
139
- size: "md",
139
+ size: "sm",
140
140
  },
141
141
  });
142
142
 
@@ -20,18 +20,26 @@ const config = helpers.defineMultiStyleConfig({
20
20
  maxHeight: "50vh",
21
21
  width: "100%",
22
22
  listStyle: "none",
23
+ borderBottomRadius: "sm",
23
24
  },
24
25
  item: {
25
- paddingX: 3,
26
- paddingY: 2,
26
+ paddingX: 2,
27
+ paddingY: 1,
28
+ marginY: 1,
29
+ marginX: 1,
30
+ borderRadius: "sm",
27
31
  color: mode("darkGrey", "white")(props),
28
32
  _hover: {
29
- background: mode("mint", "darkTeal")(props),
33
+ backgroundColor: mode("seaMist", "darkTeal")(props),
34
+ outline: "none",
35
+ },
36
+ _active: {
37
+ backgroundColor: mode("mint", "darkTeal")(props),
30
38
  outline: "none",
31
39
  },
32
40
  _focus: {
33
41
  outline: "none",
34
- backgroundColor: mode("mint", "darkTeal")(props),
42
+ backgroundColor: mode("seaMist", "darkTeal")(props),
35
43
  },
36
44
  _selected: {
37
45
  backgroundColor: mode("pine", "pine")(props),
@@ -1,172 +0,0 @@
1
- import React from "react";
2
- import { useAsyncList } from "react-stately";
3
- import { Combobox, ComboboxProps, InputProps } from "../";
4
-
5
- type AutosuggestProps<T> = {
6
- /** The label of the search field */
7
- label: string;
8
- /**
9
- * The function responsible for fetching new suggestion items, based on the query.
10
- *
11
- * This will typically be an API call to a backend service.
12
- *
13
- * @example
14
- * ```tsx
15
- * const fetcher = async (query?: string) => {
16
- * const response = await fetch(`https://some.api.com/filter=${query}`);
17
- * const json = await response.json();
18
- * return json;
19
- * };
20
- * ```
21
- * */
22
- fetcher: (query?: string) => Promise<Iterable<T>>;
23
- /**
24
- * A render function that receives each item, and returns the UI for each item in the list.
25
- *
26
- * @example
27
- * ```tsx
28
- * <Autosuggest {...otherProps}>
29
- * {(user) => (
30
- * <Item key={user.id} textValue={user.fullName}>
31
- * <ItemLabel>{user.fullName}</ItemLabel>
32
- * <ItemDescription>{user.asl}</ItemDescription>
33
- * </Item>
34
- * )}
35
- * </Autosuggest>
36
- * ```
37
- *
38
- * You technically don't need to use the `<SelectItemLabel />` and `<SelectItemDescription />` components, but they are recommended to improve the accessibility of the search results. You can style them however you want, so there should never be a reason not to include at least the `<SelectItemLabel />` component. But who's judging?
39
- * */
40
- children: ComboboxProps<T>["children"];
41
- /**
42
- * Callback for when the selection changes. Returns the entire item.
43
- */
44
- onSelectionChange?: (item: T) => void;
45
- /** The selected item key (controlled) */
46
- selectedKey?: ComboboxProps<T>["selectedKey"];
47
- /** What should open the menu.
48
- *
49
- * Defaults to "input"
50
- */
51
- menuTrigger?: ComboboxProps<T>["menuTrigger"];
52
- } & Pick<
53
- InputProps,
54
- | "marginTop"
55
- | "marginBottom"
56
- | "marginRight"
57
- | "marginLeft"
58
- | "marginY"
59
- | "marginX"
60
- | "paddingTop"
61
- | "paddingBottom"
62
- | "paddingLeft"
63
- | "paddingRight"
64
- | "paddingY"
65
- | "paddingX"
66
- | "leftIcon"
67
- | "rightIcon"
68
- | "borderTopRightRadius"
69
- | "borderTopLeftRadius"
70
- | "borderBottomRightRadius"
71
- | "borderBottomLeftRadius"
72
- | "onFocus"
73
- >;
74
- /**
75
- * A component that provides an autocomplete search field with suggestions.
76
- *
77
- * This component requires a `fetcher` prop, which is a function that receives a query string, and returns a list of items that match the query.
78
- *
79
- * @example
80
- * ```tsx
81
- * const fetcher = async (query?: string) => {
82
- * const response = await fetch(`https://some.api.vy.no/filter=${query}`);
83
- * const json = await response.json();
84
- * return json;
85
- * };
86
- *
87
- * const Example = () => {
88
- * return (
89
- * <Autosuggest
90
- * label="Search for users"
91
- * fetcher={fetcher}
92
- * onSelectionChange={(item) => console.log(item)}
93
- * >
94
- * {(user) => (
95
- * <Item key={user.id} textValue={user.fullName}>
96
- * <ItemLabel>{user.fullName}</ItemLabel>
97
- * <ItemDescription>{user.asl}</ItemDescription>
98
- * </Item>
99
- * )}
100
- * </Autosuggest>
101
- * );
102
- * };
103
- * ```
104
- *
105
- * The `fetcher` function can be any function that returns an iterable of items. This means that you can use any API library you want, as long as it returns an iterable of items.
106
- *
107
- * The items need to have a `key` property, which is used to identify the item. The `key` property can be any type, but it needs to be unique for each item.
108
- *
109
- * ```tsx
110
- * [{ key: 'some-key', ...}, { key: 'some-other-key', ... }]
111
- * ```
112
- *
113
- * You can also return a set of nested items, which will be rendered as a sub-list (or section). This is useful if you want to group your items. These items need to have a title prop (for labelling the section), as well as a `children` prop, which in turn will contain an iterable of items:
114
- *
115
- * ```tsx
116
- * [
117
- * {
118
- * title: 'The title of the section',
119
- * children: [{ key: 'some-key', ... }]
120
- * },
121
- * {...}
122
- * ]
123
- * ```
124
- *
125
- * The `onSelectionChanged` will return the correct `item` (the one with the matching `key`), even if the item is in a sub-list.
126
- */
127
- export function Autosuggest<T extends object>({
128
- label,
129
- fetcher,
130
- onSelectionChange,
131
- ...props
132
- }: AutosuggestProps<T>) {
133
- const list = useAsyncList<T>({
134
- async load({ filterText }) {
135
- return {
136
- items: await fetcher(filterText),
137
- };
138
- },
139
- });
140
-
141
- const handleSelectionChange = (key: React.Key) => {
142
- if (!onSelectionChange) {
143
- return;
144
- }
145
-
146
- let selectedItem = list.getItem(key);
147
- if (!selectedItem) {
148
- // If the item is not in the list, it might be in a sub-list
149
- selectedItem = list.items
150
- .flatMap((item) =>
151
- "children" in item && Array.isArray(item.children)
152
- ? item.children
153
- : []
154
- )
155
- .find((child) => child.key === key);
156
- }
157
- if (selectedItem) {
158
- onSelectionChange(selectedItem);
159
- }
160
- };
161
- return (
162
- <Combobox
163
- label={label}
164
- items={list.items}
165
- inputValue={list.filterText}
166
- onInputChange={list.setFilterText}
167
- onSelectionChange={handleSelectionChange}
168
- isLoading={list.isLoading}
169
- {...props}
170
- />
171
- );
172
- }