@bspk/ui 1.1.26 → 1.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/dist/Avatar.d.ts +2 -1
  2. package/dist/Avatar.js.map +1 -1
  3. package/dist/Button.js +1 -1
  4. package/dist/Button.js.map +1 -1
  5. package/dist/FormField.d.ts +2 -2
  6. package/dist/FormField.js +1 -1
  7. package/dist/Popover.d.ts +2 -3
  8. package/dist/Popover.js +3 -4
  9. package/dist/Popover.js.map +1 -1
  10. package/dist/ProgressBar.d.ts +6 -7
  11. package/dist/ProgressBar.js +6 -7
  12. package/dist/ProgressBar.js.map +1 -1
  13. package/dist/ProgressCircle.d.ts +6 -7
  14. package/dist/ProgressCircle.js +6 -7
  15. package/dist/ProgressCircle.js.map +1 -1
  16. package/dist/ProgressionStepper.d.ts +3 -8
  17. package/dist/ProgressionStepper.js +3 -8
  18. package/dist/ProgressionStepper.js.map +1 -1
  19. package/dist/RadioGroup.d.ts +9 -2
  20. package/dist/RadioGroup.js.map +1 -1
  21. package/dist/SearchBar.d.ts +1 -2
  22. package/dist/SearchBar.js +5 -6
  23. package/dist/SearchBar.js.map +1 -1
  24. package/dist/SegmentedControl.d.ts +8 -15
  25. package/dist/SegmentedControl.js +2 -4
  26. package/dist/SegmentedControl.js.map +1 -1
  27. package/dist/{Dropdown.d.ts → Select.d.ts} +15 -15
  28. package/dist/Select.js +67 -0
  29. package/dist/Select.js.map +1 -0
  30. package/dist/{DropdownField.d.ts → SelectField.d.ts} +9 -9
  31. package/dist/SelectField.js +39 -0
  32. package/dist/SelectField.js.map +1 -0
  33. package/dist/StylesProviderAnywhere.js +1 -1
  34. package/dist/StylesProviderBetterHomesGardens.js +1 -1
  35. package/dist/StylesProviderCartus.js +1 -1
  36. package/dist/StylesProviderCentury21.js +1 -1
  37. package/dist/StylesProviderColdwellBanker.js +1 -1
  38. package/dist/StylesProviderCorcoran.js +1 -1
  39. package/dist/StylesProviderDenaliBoss.js +1 -1
  40. package/dist/StylesProviderEra.js +1 -1
  41. package/dist/StylesProviderSothebys.js +1 -1
  42. package/dist/TabGroup.d.ts +5 -6
  43. package/dist/TabGroup.js.map +1 -1
  44. package/dist/Tag.d.ts +1 -2
  45. package/dist/Tag.js +1 -2
  46. package/dist/Tag.js.map +1 -1
  47. package/dist/TextField.d.ts +2 -3
  48. package/dist/TextField.js +2 -4
  49. package/dist/TextField.js.map +1 -1
  50. package/dist/TextInput.d.ts +4 -13
  51. package/dist/TextInput.js +3 -11
  52. package/dist/TextInput.js.map +1 -1
  53. package/dist/Textarea.d.ts +5 -14
  54. package/dist/Textarea.js +6 -16
  55. package/dist/Textarea.js.map +1 -1
  56. package/dist/TextareaField.d.ts +1 -2
  57. package/dist/TextareaField.js +1 -2
  58. package/dist/TextareaField.js.map +1 -1
  59. package/dist/Txt.d.ts +1 -2
  60. package/dist/Txt.js +1 -2
  61. package/dist/Txt.js.map +1 -1
  62. package/dist/base.css +1 -1
  63. package/dist/demo/ExamplePlaceholder.js.map +1 -1
  64. package/dist/demo/examples.js +84 -15
  65. package/dist/demo/examples.js.map +1 -1
  66. package/dist/hooks/useCombobox.d.ts +45 -0
  67. package/dist/hooks/{useFloatingMenu.js → useCombobox.js} +17 -8
  68. package/dist/hooks/useCombobox.js.map +1 -0
  69. package/dist/hooks/useFloating.d.ts +39 -8
  70. package/dist/hooks/useFloating.js +2 -13
  71. package/dist/hooks/useFloating.js.map +1 -1
  72. package/dist/hooks/useKeyboardNavigation.d.ts +1 -1
  73. package/dist/hooks/useKeyboardNavigation.js +1 -1
  74. package/dist/hooks/useOutsideClick.d.ts +2 -2
  75. package/dist/hooks/useOutsideClick.js +2 -2
  76. package/dist/index.d.ts +3 -1
  77. package/dist/index.js +3 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/select.css +1 -0
  80. package/package.json +3 -2
  81. package/src/Avatar.tsx +2 -1
  82. package/src/Button.tsx +2 -2
  83. package/src/FormField.tsx +2 -2
  84. package/src/Popover.tsx +5 -27
  85. package/src/ProgressBar.tsx +6 -7
  86. package/src/ProgressCircle.tsx +6 -7
  87. package/src/ProgressionStepper.tsx +3 -8
  88. package/src/RadioGroup.tsx +9 -2
  89. package/src/SearchBar.tsx +8 -20
  90. package/src/SegmentedControl.tsx +14 -37
  91. package/src/{Dropdown.tsx → Select.tsx} +30 -32
  92. package/src/{DropdownField.tsx → SelectField.tsx} +15 -15
  93. package/src/TabGroup.tsx +6 -10
  94. package/src/Tag.tsx +1 -2
  95. package/src/TextField.tsx +6 -19
  96. package/src/TextInput.tsx +6 -27
  97. package/src/Textarea.tsx +10 -31
  98. package/src/TextareaField.tsx +3 -8
  99. package/src/Txt.tsx +2 -7
  100. package/src/base.scss +53 -70
  101. package/src/demo/ExamplePlaceholder.tsx +6 -1
  102. package/src/demo/examples.tsx +99 -21
  103. package/src/hooks/{useFloatingMenu.ts → useCombobox.ts} +28 -40
  104. package/src/hooks/useFloating.ts +45 -24
  105. package/src/hooks/useKeyboardNavigation.ts +1 -1
  106. package/src/hooks/useOutsideClick.ts +2 -2
  107. package/src/index.ts +3 -1
  108. package/src/{dropdown.scss → select.scss} +36 -36
  109. package/dist/Dropdown.js +0 -68
  110. package/dist/Dropdown.js.map +0 -1
  111. package/dist/DropdownField.js +0 -39
  112. package/dist/DropdownField.js.map +0 -1
  113. package/dist/dropdown.css +0 -1
  114. package/dist/hooks/useFloatingMenu.d.ts +0 -36
  115. package/dist/hooks/useFloatingMenu.js.map +0 -1
package/src/base.scss CHANGED
@@ -26,27 +26,40 @@ html:has(body[data-bspk]) {
26
26
  scroll-behavior: smooth;
27
27
  }
28
28
 
29
- body[data-bspk] {
29
+ :root {
30
30
  --z-index-tooltip-popover: 1100;
31
31
  --z-index-dialog: 1000;
32
32
  --z-index-dropdown: 900;
33
33
  --z-index-fab: 800;
34
34
  --z-index-navbar: 700;
35
35
  --z-index-footer: 600;
36
+ }
36
37
 
37
- height: 100%;
38
- scroll-behavior: smooth;
39
-
40
- @media (prefers-reduced-motion) {
41
- [data-animated] {
42
- animation: none !important;
43
- }
38
+ @media (prefers-reduced-motion) {
39
+ [data-animated] {
40
+ animation: none !important;
44
41
  }
42
+ }
45
43
 
44
+ body[data-bspk] {
45
+ height: 100%;
46
+ scroll-behavior: smooth;
46
47
  font: var(--body-base);
47
48
  background-color: var(--background-base);
48
49
  color: var(--foreground-neutral-on-surface);
49
50
 
51
+ /** Remove default input autofill styles */
52
+ input:-internal-autofill-previewed,
53
+ input:-internal-autofill-selected,
54
+ textarea:-internal-autofill-previewed,
55
+ textarea:-internal-autofill-selected,
56
+ select:-internal-autofill-previewed,
57
+ select:-internal-autofill-selected {
58
+ transition:
59
+ color calc(infinity * 1s) step-end,
60
+ background-color calc(infinity * 1s) step-end;
61
+ }
62
+
50
63
  a {
51
64
  color: var(--foreground-link-text-default);
52
65
 
@@ -178,73 +191,43 @@ body[data-bspk] {
178
191
  color: var(--foreground-neutral-inverse-on-surface) !important;
179
192
  }
180
193
  }
194
+ }
181
195
 
182
- /** Remove default input autofill styles */
183
- input:-internal-autofill-previewed,
184
- input:-internal-autofill-selected,
185
- textarea:-internal-autofill-previewed,
186
- textarea:-internal-autofill-selected,
187
- select:-internal-autofill-previewed,
188
- select:-internal-autofill-selected {
189
- transition:
190
- color calc(infinity * 1s) step-end,
191
- background-color calc(infinity * 1s) step-end;
192
- }
193
-
194
- [data-sr-only] {
195
- position: absolute;
196
- width: 1px;
197
- height: 1px;
198
- padding: 0;
199
- margin: -1px;
200
- overflow: hidden;
201
- clip: rect(0, 0, 0, 0);
202
- white-space: nowrap;
203
- border-width: 0;
204
- }
205
-
206
- ol {
207
- list-style-type: decimal;
208
-
209
- li {
210
- list-style-type: decimal;
211
- margin-left: var(--spacing-sizing-05);
212
- }
213
- }
196
+ [data-touch-target] {
197
+ display: none;
198
+ touch-action: manipulation;
199
+ -webkit-tap-highlight-color: transparent;
200
+ -webkit-touch-callout: none;
201
+ user-select: none;
202
+ position: absolute;
203
+ z-index: 1;
204
+ height: 100%;
205
+ width: 100%;
206
+ top: auto;
207
+ left: auto;
208
+ }
214
209
 
215
- ul {
216
- list-style-type: disc;
210
+ [data-sr-only] {
211
+ position: absolute;
212
+ width: 1px;
213
+ height: 1px;
214
+ padding: 0;
215
+ margin: -1px;
216
+ overflow: hidden;
217
+ clip: rect(0, 0, 0, 0);
218
+ white-space: nowrap;
219
+ border-width: 0;
220
+ }
217
221
 
218
- li {
219
- list-style-type: disc;
220
- margin-left: var(--spacing-sizing-05);
221
- }
222
- }
222
+ [data-touch-target] ~ * {
223
+ position: relative;
224
+ z-index: 2;
225
+ }
223
226
 
227
+ /* if touchscreen */
228
+ @media (any-pointer: coarse) {
224
229
  [data-touch-target] {
225
- display: none;
226
- touch-action: manipulation;
227
- -webkit-tap-highlight-color: transparent;
228
- -webkit-touch-callout: none;
229
- user-select: none;
230
- position: absolute;
231
- z-index: 1;
232
- height: 100%;
233
- width: 100%;
234
- top: auto;
235
- left: auto;
236
- }
237
-
238
- [data-touch-target] ~ * {
239
- position: relative;
240
- z-index: 2;
241
- }
242
-
243
- /* if touchscreen */
244
- @media (any-pointer: coarse) {
245
- [data-touch-target] {
246
- display: block;
247
- }
230
+ display: block;
248
231
  }
249
232
  }
250
233
 
@@ -12,7 +12,12 @@ export function ExamplePlaceholder({
12
12
  direction = 'row',
13
13
  ...props
14
14
  }: ElementProps<
15
- { hideSize?: boolean; height?: number | string; width?: number | string; direction?: 'column' | 'row' },
15
+ {
16
+ hideSize?: boolean;
17
+ height?: number | string;
18
+ width?: number | string;
19
+ direction?: 'column' | 'row';
20
+ },
16
21
  'div'
17
22
  >) {
18
23
  const ref = useRef<HTMLDivElement | null>(null);
@@ -12,7 +12,6 @@ import { BadgeProps } from '../Badge';
12
12
  import { BannerAlertProps } from '../BannerAlert';
13
13
  import { Button, ButtonProps } from '../Button';
14
14
  import { Checkbox } from '../Checkbox';
15
- import { DropdownOption, DropdownProps } from '../Dropdown';
16
15
  import { EmptyStateProps } from '../EmptyState';
17
16
  import { Img } from '../Img';
18
17
  import { LEADING_COMPONENTS, TRAILING_COMPONENTS, ListItem } from '../ListItem';
@@ -23,6 +22,7 @@ import { ProgressionStepperProps } from '../ProgressionStepper';
23
22
  import { Radio } from '../Radio';
24
23
  import { SearchBarProps } from '../SearchBar';
25
24
  import { SegmentedControlProps } from '../SegmentedControl';
25
+ import { SelectOption, SelectProps } from '../Select';
26
26
  import { Switch } from '../Switch';
27
27
  import { TabGroupProps } from '../TabGroup';
28
28
  import { Tag } from '../Tag';
@@ -146,7 +146,9 @@ export type Preset<P> = {
146
146
  isDefault?: boolean;
147
147
  };
148
148
 
149
- export type DemoPreset<P = Record<string, unknown>> = Preset<P> & { value: string };
149
+ export type DemoPreset<P = Record<string, unknown>> = Preset<P> & {
150
+ value: string;
151
+ };
150
152
 
151
153
  export function createUid(prefix: string = 'uid'): string {
152
154
  return `${prefix}-${Math.random().toString(36).substring(2, 9)}`;
@@ -309,8 +311,8 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
309
311
  );
310
312
  },
311
313
  },
312
- Dropdown: {
313
- presets: setPresets<DropdownProps>(() => {
314
+ Select: {
315
+ presets: setPresets<SelectProps>(() => {
314
316
  return [
315
317
  {
316
318
  label: 'Simple',
@@ -322,11 +324,28 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
322
324
  },
323
325
  {
324
326
  label: 'Trailing Tags',
325
- state: asProps<DropdownProps<DropdownOption & { tag?: string; tagColor?: ColorVariant }>>({
327
+ state: asProps<
328
+ SelectProps<
329
+ SelectOption & {
330
+ tag?: string;
331
+ tagColor?: ColorVariant;
332
+ }
333
+ >
334
+ >({
326
335
  options: [
327
336
  //
328
- { value: 'a', label: 'Package A', tag: 'Recommended', tagColor: 'blue' },
329
- { value: 'b', label: 'Package B', tag: 'Best Value', tagColor: 'green' },
337
+ {
338
+ value: 'a',
339
+ label: 'Package A',
340
+ tag: 'Recommended',
341
+ tagColor: 'blue',
342
+ },
343
+ {
344
+ value: 'b',
345
+ label: 'Package B',
346
+ tag: 'Best Value',
347
+ tagColor: 'green',
348
+ },
330
349
  { value: 'c', label: 'Package C' },
331
350
  { value: 'd', label: 'Package D' },
332
351
  ],
@@ -344,7 +363,7 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
344
363
  },
345
364
  {
346
365
  label: 'Trailing Text',
347
- state: asProps<DropdownProps<DropdownOption & { price: number }>>({
366
+ state: asProps<SelectProps<SelectOption & { price: number }>>({
348
367
  options: [
349
368
  //
350
369
  { value: '1', label: 'Option A', price: 400 },
@@ -367,7 +386,7 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
367
386
  {
368
387
  label: 'Leading Avatar',
369
388
  state: asProps<
370
- DropdownProps<
389
+ SelectProps<
371
390
  MenuItem & {
372
391
  profile: AvatarProps;
373
392
  }
@@ -380,9 +399,21 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
380
399
  label: 'Jessica P.',
381
400
  profile: { name: 'Jessica P.' },
382
401
  },
383
- { value: 'Louis', label: 'Louis L.', profile: { name: 'Louis L.' } },
384
- { value: 'Harvey', label: 'Harvey S.', profile: { name: 'Harvey S.' } },
385
- { value: 'Mike', label: 'Mike R.', profile: { name: 'Mike R.' } },
402
+ {
403
+ value: 'Louis',
404
+ label: 'Louis L.',
405
+ profile: { name: 'Louis L.' },
406
+ },
407
+ {
408
+ value: 'Harvey',
409
+ label: 'Harvey S.',
410
+ profile: { name: 'Harvey S.' },
411
+ },
412
+ {
413
+ value: 'Mike',
414
+ label: 'Mike R.',
415
+ profile: { name: 'Mike R.' },
416
+ },
386
417
  ],
387
418
  renderListItem: (props) => {
388
419
  return {
@@ -479,7 +510,12 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
479
510
  presets: setPresets<PopoverProps>([
480
511
  {
481
512
  label: 'With CallToAction',
482
- state: { callToAction: { label: 'Click me', onClick: () => action('Call to action clicked!') } },
513
+ state: {
514
+ callToAction: {
515
+ label: 'Click me',
516
+ onClick: () => action('Call to action clicked!'),
517
+ },
518
+ },
483
519
  },
484
520
  ]),
485
521
  },
@@ -568,9 +604,24 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
568
604
  label: 'With icons',
569
605
  state: {
570
606
  options: [
571
- { value: '1', label: 'Option 1', icon: <SvgDiamond />, iconActive: <SvgDiamondFill /> },
572
- { value: '2', label: 'Disabled 2', disabled: true, icon: <SvgCircle /> },
573
- { value: '3', label: 'Option 3', icon: <SvgSquare />, iconActive: <SvgSquareFill /> },
607
+ {
608
+ value: '1',
609
+ label: 'Option 1',
610
+ icon: <SvgDiamond />,
611
+ iconActive: <SvgDiamondFill />,
612
+ },
613
+ {
614
+ value: '2',
615
+ label: 'Disabled 2',
616
+ disabled: true,
617
+ icon: <SvgCircle />,
618
+ },
619
+ {
620
+ value: '3',
621
+ label: 'Option 3',
622
+ icon: <SvgSquare />,
623
+ iconActive: <SvgSquareFill />,
624
+ },
574
625
  ],
575
626
  },
576
627
  },
@@ -641,9 +692,24 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
641
692
  label: 'With icons',
642
693
  state: {
643
694
  options: [
644
- { value: '1', label: 'Option 1', icon: <SvgDiamond />, iconActive: <SvgDiamondFill /> },
645
- { value: '2', label: 'Disabled 2', disabled: true, icon: <SvgCircle /> },
646
- { value: '3', label: 'Option 3', icon: <SvgSquare />, iconActive: <SvgSquareFill /> },
695
+ {
696
+ value: '1',
697
+ label: 'Option 1',
698
+ icon: <SvgDiamond />,
699
+ iconActive: <SvgDiamondFill />,
700
+ },
701
+ {
702
+ value: '2',
703
+ label: 'Disabled 2',
704
+ disabled: true,
705
+ icon: <SvgCircle />,
706
+ },
707
+ {
708
+ value: '3',
709
+ label: 'Option 3',
710
+ icon: <SvgSquare />,
711
+ iconActive: <SvgSquareFill />,
712
+ },
647
713
  ],
648
714
  },
649
715
  },
@@ -658,8 +724,20 @@ export const examples: (setState: DemoSetState, action: DemoAction) => Record<st
658
724
  iconActive: <SvgDiamondFill />,
659
725
  badge: 1,
660
726
  },
661
- { value: '2', label: 'Disabled 2', disabled: true, icon: <SvgCircle />, badge: 2 },
662
- { value: '3', label: 'Option 3', icon: <SvgSquare />, iconActive: <SvgSquare />, badge: 3 },
727
+ {
728
+ value: '2',
729
+ label: 'Disabled 2',
730
+ disabled: true,
731
+ icon: <SvgCircle />,
732
+ badge: 2,
733
+ },
734
+ {
735
+ value: '3',
736
+ label: 'Option 3',
737
+ icon: <SvgSquare />,
738
+ iconActive: <SvgSquare />,
739
+ badge: 3,
740
+ },
663
741
  ],
664
742
  },
665
743
  },
@@ -3,44 +3,31 @@ import { AriaAttributes, useId, useState } from 'react';
3
3
  import { CommonProps, InvalidPropsLibrary } from '..';
4
4
  import { EVENT_KEY } from '../utils/keyboard';
5
5
 
6
- import { Placement, useFloating } from './useFloating';
6
+ import { useFloating, UseFloatingProps } from './useFloating';
7
7
  import { useKeyboardNavigation } from './useKeyboardNavigation';
8
8
  import { useOutsideClick } from './useOutsideClick';
9
9
 
10
- export type UseFloatingMenuProps = {
11
- placement: Placement;
12
- triggerProps?: CommonProps<'disabled' | 'readOnly'> & InvalidPropsLibrary;
13
- };
10
+ export type UseComboboxProps = CommonProps<'disabled' | 'readOnly'> &
11
+ InvalidPropsLibrary &
12
+ Pick<UseFloatingProps, 'offsetOptions' | 'placement' | 'refWidth'>;
14
13
 
15
- export type UseFloatingMenuReturn = {
16
- menuProps: {
17
- activeIndex: number;
18
- 'data-placement': Placement | undefined;
19
- id: string;
20
- innerRef: (node: HTMLElement | null) => void;
21
- role: 'listbox';
22
- style: React.CSSProperties;
23
- tabIndex: number;
24
- };
25
- triggerProps: {
26
- 'aria-activedescendant': string | undefined;
27
- 'aria-controls': string;
28
- 'aria-expanded': boolean;
29
- 'aria-haspopup': AriaAttributes['aria-haspopup'];
30
- 'aria-invalid': boolean | undefined;
31
- 'aria-owns': string;
32
- 'aria-readonly': boolean | undefined;
33
- 'aria-errormessage': string | undefined;
34
- role: 'combobox';
35
- tabIndex: number;
36
- ref: (node: HTMLElement | null) => void;
37
- onClick: (event: React.MouseEvent) => void;
38
- onKeyDownCapture: (event: React.KeyboardEvent) => boolean;
39
- };
40
- closeMenu: () => void;
41
- };
42
-
43
- export function useFloatingMenu({ placement, triggerProps }: UseFloatingMenuProps): UseFloatingMenuReturn {
14
+ /**
15
+ * Utility hook to manage a combobox component.
16
+ *
17
+ * It provides functionality for showing/hiding the menu, handling keyboard navigation, and managing ARIA attributes.
18
+ *
19
+ * @param {UseComboboxProps} props - The properties to configure the combobox.
20
+ * @returns {object} An object containing props for the menu and toggle elements, and a function to close the menu.
21
+ */
22
+ export function useCombobox({
23
+ placement = 'bottom',
24
+ refWidth = true,
25
+ disabled,
26
+ errorMessage,
27
+ invalid,
28
+ readOnly,
29
+ offsetOptions,
30
+ }: UseComboboxProps) {
44
31
  const menuId = useId();
45
32
 
46
33
  const [show, setShow] = useState(false);
@@ -50,8 +37,8 @@ export function useFloatingMenu({ placement, triggerProps }: UseFloatingMenuProp
50
37
  const { floatingStyles, middlewareData, elements } = useFloating({
51
38
  placement,
52
39
  strategy: 'fixed',
53
- offsetOptions: 4,
54
- refWidth: true,
40
+ offsetOptions,
41
+ refWidth,
55
42
  hide: !show,
56
43
  });
57
44
 
@@ -75,15 +62,16 @@ export function useFloatingMenu({ placement, triggerProps }: UseFloatingMenuProp
75
62
  style: floatingStyles,
76
63
  tabIndex: -1,
77
64
  },
78
- triggerProps: {
79
- 'aria-errormessage': triggerProps?.errorMessage || undefined,
65
+ toggleProps: {
66
+ 'aria-errormessage': errorMessage || undefined,
80
67
  'aria-activedescendant': selectedId || undefined,
81
68
  'aria-controls': menuId,
69
+ 'aria-disabled': disabled || undefined,
82
70
  'aria-expanded': show,
83
71
  'aria-haspopup': 'listbox' as AriaAttributes['aria-haspopup'],
84
- 'aria-invalid': triggerProps?.invalid || undefined,
72
+ 'aria-invalid': invalid || undefined,
85
73
  'aria-owns': menuId,
86
- 'aria-readonly': triggerProps?.readOnly || undefined,
74
+ 'aria-readonly': readOnly || undefined,
87
75
  role: 'combobox',
88
76
  tabIndex: 0,
89
77
  ref: (node: HTMLElement | null) => elements.setTrigger(node),
@@ -32,6 +32,45 @@ export type { Placement, Strategy };
32
32
 
33
33
  const TRANSITION_DELAY = 250;
34
34
 
35
+ export type UseFloatingProps = {
36
+ /**
37
+ * The preferred placement of the floating element.
38
+ *
39
+ * This determines where the floating element will be positioned relative to the reference element.
40
+ *
41
+ * @default bottom
42
+ */
43
+ placement: Placement;
44
+ /** A ref object for the arrow element. */
45
+ arrowRef?: React.MutableRefObject<HTMLElement | null>;
46
+ /**
47
+ * The positioning strategy ('absolute' or 'fixed').
48
+ *
49
+ * When set to 'fixed', the floating element will be positioned relative to the viewport.
50
+ *
51
+ * When set to 'absolute', the floating element will be positioned relative to the nearest positioned ancestor.
52
+ *
53
+ * @default fixed
54
+ */
55
+ strategy?: Strategy;
56
+ /**
57
+ * The offset options for the floating element.
58
+ *
59
+ * @default 0
60
+ */
61
+ offsetOptions?: OffsetOptions;
62
+ /**
63
+ * When set to true, the width of the floating element will match the width of the reference element.
64
+ *
65
+ * When set to an HTMLElement, the width of the floating element will match the width of that HTMLElement.
66
+ *
67
+ * @default true
68
+ */
69
+ refWidth?: HTMLElement | boolean;
70
+ /** Whether to hide the floating element. */
71
+ hide?: boolean;
72
+ };
73
+
35
74
  /**
36
75
  *
37
76
  *
@@ -39,20 +78,13 @@ const TRANSITION_DELAY = 250;
39
78
  * @returns
40
79
  */
41
80
  export function useFloating<TriggerElementType extends HTMLElement>({
42
- placement,
81
+ placement = 'bottom',
43
82
  arrowRef,
44
- strategy,
83
+ strategy = 'fixed',
45
84
  offsetOptions = 0,
46
- refWidth,
85
+ refWidth = true,
47
86
  hide = false,
48
- }: {
49
- placement: Placement;
50
- arrowRef?: React.MutableRefObject<HTMLElement | null>;
51
- strategy?: Strategy;
52
- offsetOptions?: OffsetOptions;
53
- refWidth?: boolean;
54
- hide?: boolean;
55
- }) {
87
+ }: UseFloatingProps) {
56
88
  const [floatingStyles, setFloatingStylesState] = useState<React.CSSProperties>({
57
89
  opacity: 0,
58
90
  pointerEvents: 'none',
@@ -72,18 +104,6 @@ export function useFloating<TriggerElementType extends HTMLElement>({
72
104
 
73
105
  const [floatingElement, setFloatingElement] = useState<HTMLElement | null>(null);
74
106
 
75
- // const elements: {
76
- // trigger: HTMLElement | null;
77
- // floating: HTMLElement | null;
78
- // setReference: (node: TriggerElementType | null) => void;
79
- // setFloating: (node: HTMLElement | null) => void;
80
- // } = {
81
- // trigger: triggerElement,
82
- // floating: floatingElement,
83
- // setReference: setTriggerElement,
84
- // setFloating: setFloatingElement,
85
- // };
86
-
87
107
  const computeDebounce = useTimeout();
88
108
  const transitionDelay = useTimeout();
89
109
 
@@ -129,7 +149,8 @@ export function useFloating<TriggerElementType extends HTMLElement>({
129
149
  size({
130
150
  apply({ rects, elements }: MiddlewareState) {
131
151
  Object.assign(elements.floating.style, {
132
- width: `${rects.reference.width}px`,
152
+ width:
153
+ refWidth === true ? `${rects.reference.width}px` : `${refWidth.offsetWidth}px`,
133
154
  });
134
155
  },
135
156
  }),
@@ -4,7 +4,7 @@ import { EVENT_KEY } from '../utils/keyboard';
4
4
  import { scrollElementIntoView } from '../utils/scrollElementIntoView';
5
5
 
6
6
  /**
7
- * This hook provides keyboard navigation for a list of elements. Used inside the Dropdown component.
7
+ * This hook provides keyboard navigation for a list of elements. Used inside the Select component.
8
8
  *
9
9
  * @example
10
10
  * import { useRef } from 'react';
@@ -1,13 +1,13 @@
1
1
  import { useEffect } from 'react';
2
2
  /**
3
- * A hook which calls a method when a click occurs outside of the provided ref. Used inside the Dropdown and Modal
3
+ * A hook which calls a method when a click occurs outside of the provided ref. Used inside the DropDown and Modal
4
4
  * components.
5
5
  *
6
6
  * @example
7
7
  * import { useOutsideClick } from '@bspk/ui/hooks/useOutsideClick';
8
8
  * import React, { useRef, useState } from 'react';
9
9
  *
10
- * export function Dropdown() {
10
+ * export function Example() {
11
11
  * const [isOpen, setIsOpen] = useState(false);
12
12
  * const containerRef = useRef<HTMLDivElement>(null);
13
13
  *
package/src/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * There are no barrel files for this repository.
3
3
  *
4
- * Components should be imported directly like "import { Txt } from @bspk/ui/Txt".
4
+ * Components should be imported directly like "import { Txt } from
5
+ *
6
+ * @bspk/ui/Txt".
5
7
  */
6
8
 
7
9
  import { ComponentProps, JSXElementConstructor, ReactNode } from 'react';