@dxos/react-ui-pickers 0.7.5-labs.c0e040f → 0.7.5-labs.d199c0f

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 (33) hide show
  1. package/dist/lib/browser/index.mjs +137 -97
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +144 -109
  5. package/dist/lib/node/index.cjs.map +4 -4
  6. package/dist/lib/node/meta.json +1 -1
  7. package/dist/lib/node-esm/index.mjs +137 -97
  8. package/dist/lib/node-esm/index.mjs.map +4 -4
  9. package/dist/lib/node-esm/meta.json +1 -1
  10. package/dist/types/src/components/EmojiPicker.d.ts +3 -3
  11. package/dist/types/src/components/EmojiPicker.d.ts.map +1 -1
  12. package/dist/types/src/components/EmojiPicker.stories.d.ts.map +1 -1
  13. package/dist/types/src/components/HuePicker.d.ts +7 -14
  14. package/dist/types/src/components/HuePicker.d.ts.map +1 -1
  15. package/dist/types/src/components/HuePicker.stories.d.ts +1 -2
  16. package/dist/types/src/components/HuePicker.stories.d.ts.map +1 -1
  17. package/dist/types/src/components/IconPicker.d.ts +11 -0
  18. package/dist/types/src/components/IconPicker.d.ts.map +1 -0
  19. package/dist/types/src/components/IconPicker.stories.d.ts +7 -0
  20. package/dist/types/src/components/IconPicker.stories.d.ts.map +1 -0
  21. package/dist/types/src/components/ToolbarPicker.d.ts +17 -0
  22. package/dist/types/src/components/ToolbarPicker.d.ts.map +1 -0
  23. package/dist/types/src/components/index.d.ts +2 -0
  24. package/dist/types/src/components/index.d.ts.map +1 -1
  25. package/package.json +9 -8
  26. package/src/components/EmojiPicker.stories.tsx +4 -1
  27. package/src/components/EmojiPicker.tsx +1 -0
  28. package/src/components/HuePicker.stories.tsx +14 -29
  29. package/src/components/HuePicker.tsx +24 -172
  30. package/src/components/IconPicker.stories.tsx +39 -0
  31. package/src/components/IconPicker.tsx +92 -0
  32. package/src/components/ToolbarPicker.tsx +112 -0
  33. package/src/components/index.ts +2 -0
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-pickers",
3
- "version": "0.7.5-labs.c0e040f",
3
+ "version": "0.7.5-labs.d199c0f",
4
4
  "description": "A collection of picker components.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
7
7
  "license": "MIT",
8
8
  "author": "DXOS.org",
9
+ "type": "module",
9
10
  "exports": {
10
11
  ".": {
11
12
  "types": "./dist/types/src/index.d.ts",
@@ -25,8 +26,8 @@
25
26
  "@emoji-mart/data": "^1.1.2",
26
27
  "@emoji-mart/react": "^1.1.1",
27
28
  "@radix-ui/react-use-controllable-state": "1.1.0",
28
- "@dxos/util": "0.7.5-labs.c0e040f",
29
- "@dxos/react-ui-types": "0.7.5-labs.c0e040f"
29
+ "@dxos/react-ui-types": "0.7.5-labs.d199c0f",
30
+ "@dxos/util": "0.7.5-labs.d199c0f"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@types/react": "~18.2.0",
@@ -34,15 +35,15 @@
34
35
  "react": "~18.2.0",
35
36
  "react-dom": "~18.2.0",
36
37
  "vite": "5.4.7",
37
- "@dxos/react-ui": "0.7.5-labs.c0e040f",
38
- "@dxos/react-ui-theme": "0.7.5-labs.c0e040f",
39
- "@dxos/storybook-utils": "0.7.5-labs.c0e040f"
38
+ "@dxos/react-ui-theme": "0.7.5-labs.d199c0f",
39
+ "@dxos/react-ui": "0.7.5-labs.d199c0f",
40
+ "@dxos/storybook-utils": "0.7.5-labs.d199c0f"
40
41
  },
41
42
  "peerDependencies": {
42
43
  "react": "~18.2.0",
43
44
  "react-dom": "~18.2.0",
44
- "@dxos/react-ui": "0.7.5-labs.c0e040f",
45
- "@dxos/react-ui-theme": "0.7.5-labs.c0e040f"
45
+ "@dxos/react-ui": "0.7.5-labs.d199c0f",
46
+ "@dxos/react-ui-theme": "0.7.5-labs.d199c0f"
46
47
  },
47
48
  "publishConfig": {
48
49
  "access": "public"
@@ -53,7 +53,10 @@ export const Block: StoryObj<EmojiPickerProps> = {
53
53
 
54
54
  const meta: Meta = {
55
55
  title: 'ui/react-ui-pickers/EmojiPicker',
56
- decorators: [withTheme, withLayout({ fullscreen: false, tooltips: true })],
56
+ decorators: [withTheme, withLayout({ tooltips: true })],
57
+ parameters: {
58
+ layout: 'centered',
59
+ },
57
60
  };
58
61
 
59
62
  export default meta;
@@ -121,6 +121,7 @@ export const EmojiPickerToolbarButton = ({
121
121
 
122
122
  /**
123
123
  * A button for picking an emoji alongside a button for unsetting it.
124
+ * @deprecated
124
125
  */
125
126
  export const EmojiPickerBlock = ({ disabled, defaultEmoji, emoji, onChangeEmoji, onClickClear }: EmojiPickerProps) => {
126
127
  const { t } = useTranslation('os');
@@ -10,46 +10,31 @@ import React, { useState } from 'react';
10
10
  import { Toolbar } from '@dxos/react-ui';
11
11
  import { withLayout, withTheme } from '@dxos/storybook-utils';
12
12
 
13
- import { HuePickerBlock, HuePickerToolbarButton, type HuePickerProps } from './HuePicker';
13
+ import { HuePicker, type HuePickerProps } from './HuePicker';
14
14
 
15
15
  const ToolbarStory = (props: HuePickerProps) => {
16
- const [hue, setHue] = useState<string>(props.defaultHue ?? 'red');
16
+ const [hue, setHue] = useState<string | undefined>(props.defaultValue);
17
17
 
18
18
  return (
19
19
  <Toolbar.Root>
20
- <HuePickerToolbarButton {...props} hue={hue} onChangeHue={setHue} />
20
+ <HuePicker {...props} value={hue} onChange={setHue} onReset={() => setHue(undefined)} />
21
21
  </Toolbar.Root>
22
22
  );
23
23
  };
24
24
 
25
- const BlockStory = (props: HuePickerProps) => {
26
- const [hue, setHue] = useState<string>(props.defaultHue ?? 'red');
27
-
28
- return (
29
- <div className='flex gap-2'>
30
- <HuePickerBlock
31
- {...props}
32
- hue={hue}
33
- onChangeHue={setHue}
34
- onClickClear={() => setHue(props.defaultHue ?? 'red')}
35
- />
36
- </div>
37
- );
38
- };
39
-
40
- export const ToolbarButtonStory: StoryObj<HuePickerProps> = {
41
- render: ToolbarStory,
42
- args: { defaultHue: 'red' },
43
- };
44
-
45
- export const BlockPickerStory: StoryObj<HuePickerProps> = {
46
- render: BlockStory,
47
- args: { defaultHue: 'red' },
48
- };
49
-
50
25
  const meta: Meta = {
51
26
  title: 'ui/react-ui-pickers/HuePicker',
52
- decorators: [withTheme, withLayout({ fullscreen: false, tooltips: true })],
27
+ decorators: [withTheme, withLayout({ tooltips: true })],
28
+ parameters: {
29
+ layout: 'centered',
30
+ },
53
31
  };
54
32
 
55
33
  export default meta;
34
+
35
+ export const Default: StoryObj<HuePickerProps> = {
36
+ render: ToolbarStory,
37
+ args: {
38
+ defaultValue: 'red',
39
+ },
40
+ };
@@ -2,190 +2,42 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { useControllableState } from '@radix-ui/react-use-controllable-state';
6
- import React, { useRef, useState } from 'react';
5
+ import React from 'react';
7
6
 
8
- import {
9
- Button,
10
- type ButtonProps,
11
- DropdownMenu,
12
- Icon,
13
- type ThemedClassName,
14
- Toolbar,
15
- Tooltip,
16
- useTranslation,
17
- } from '@dxos/react-ui';
18
- import { hues, mx } from '@dxos/react-ui-theme';
7
+ import { type ButtonProps, type ThemedClassName, useTranslation } from '@dxos/react-ui';
8
+ import { hues } from '@dxos/react-ui-theme';
19
9
 
20
- const HuePreview = ({ hue }: { hue: string }) => {
21
- const size = 20;
22
- return (
23
- <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
24
- <rect x={0} y={0} width={size} height={size} fill={`var(--dx-${hue}Surface)`} />
25
- <text x='10' y='15' textAnchor='middle' fontSize='14' fontWeight='bold' fill={`var(--dx-${hue}SurfaceText)`}>
26
- T
27
- </text>
28
- </svg>
29
- );
30
- };
10
+ import { ToolbarPickerButton, type ToolbarPickerProps } from './ToolbarPicker';
31
11
 
32
12
  export type HuePickerProps = {
33
13
  disabled?: boolean;
34
- defaultHue?: string;
35
- hue?: string;
36
- onChangeHue?: (nextHue: string) => void;
37
- onClickClear?: ButtonProps['onClick'];
38
- };
14
+ defaultValue?: string;
15
+ value?: string;
16
+ onChange?: (nextHue: string) => void;
17
+ onReset?: ButtonProps['onClick'];
18
+ } & Pick<ToolbarPickerProps, 'disabled' | 'defaultValue' | 'value' | 'onChange' | 'onReset'>;
39
19
 
40
- /**
41
- * A toolbar button for picking hue. Use only in `role=toolbar` elements. Unable to unset the value.
42
- */
43
- export const HuePickerToolbarButton = ({
44
- disabled,
45
- hue,
46
- onChangeHue,
47
- classNames,
48
- defaultHue,
49
- }: ThemedClassName<Omit<HuePickerProps, 'onClickClear'>>) => {
20
+ export const HuePicker = (props: ThemedClassName<HuePickerProps>) => {
50
21
  const { t } = useTranslation('os');
51
22
 
52
- const [hueValue, setHueValue] = useControllableState<string>({
53
- prop: hue,
54
- onChange: onChangeHue,
55
- defaultProp: defaultHue,
56
- });
57
-
58
- const [huePickerOpen, setHuePickerOpen] = useState<boolean>(false);
59
-
60
- const suppressNextTooltip = useRef<boolean>(false);
61
- const [triggerTooltipOpen, setTriggerTooltipOpen] = useState(false);
62
-
63
23
  return (
64
- <Tooltip.Root
65
- open={triggerTooltipOpen}
66
- onOpenChange={(nextOpen) => {
67
- if (suppressNextTooltip.current) {
68
- setTriggerTooltipOpen(false);
69
- suppressNextTooltip.current = false;
70
- } else {
71
- setTriggerTooltipOpen(nextOpen);
72
- }
73
- }}
74
- >
75
- <DropdownMenu.Root
76
- modal={false}
77
- open={huePickerOpen}
78
- onOpenChange={(nextOpen) => {
79
- setHuePickerOpen(nextOpen);
80
- suppressNextTooltip.current = true;
81
- }}
82
- >
83
- <Tooltip.Trigger asChild>
84
- <DropdownMenu.Trigger asChild>
85
- <Toolbar.Button classNames={mx('gap-2 plb-1', classNames)} disabled={disabled}>
86
- <span className='sr-only'>{t('select hue label')}</span>
87
- <Icon icon='ph--palette--regular' size={5} />
88
- </Toolbar.Button>
89
- </DropdownMenu.Trigger>
90
- </Tooltip.Trigger>
91
- <Tooltip.Portal>
92
- <Tooltip.Content side='bottom'>
93
- {t('select hue label')}
94
- <Tooltip.Arrow />
95
- </Tooltip.Content>
96
- </Tooltip.Portal>
97
- <DropdownMenu.Portal>
98
- <DropdownMenu.Content side='bottom' classNames='!w-40'>
99
- <DropdownMenu.Viewport classNames='grid grid-cols-6'>
100
- {hues.map((hue) => {
101
- return (
102
- <DropdownMenu.CheckboxItem
103
- key={hue}
104
- checked={hue === hueValue}
105
- onCheckedChange={() => setHueValue(hue)}
106
- classNames={'px-0 py-2 items-center justify-center'}
107
- >
108
- <HuePreview hue={hue} />
109
- </DropdownMenu.CheckboxItem>
110
- );
111
- })}
112
- </DropdownMenu.Viewport>
113
- <DropdownMenu.Arrow />
114
- </DropdownMenu.Content>
115
- </DropdownMenu.Portal>
116
- </DropdownMenu.Root>
117
- </Tooltip.Root>
24
+ <ToolbarPickerButton
25
+ Component={HuePreview}
26
+ label={t('select hue label')}
27
+ icon='ph--palette--regular'
28
+ values={hues}
29
+ {...props}
30
+ />
118
31
  );
119
32
  };
120
33
 
121
- /**
122
- * A button for picking hue alongside a button for unsetting it.
123
- */
124
- export const HuePickerBlock = ({ disabled, hue, onChangeHue, defaultHue, onClickClear }: HuePickerProps) => {
125
- const { t } = useTranslation('os');
126
-
127
- const [hueValue, setHueValue] = useControllableState<string>({
128
- prop: hue,
129
- onChange: onChangeHue,
130
- defaultProp: defaultHue,
131
- });
132
-
34
+ const HuePreview = ({ value }: { value: string }) => {
35
+ const size = 16;
133
36
  return (
134
- <>
135
- <DropdownMenu.Root modal={false}>
136
- <DropdownMenu.Trigger asChild>
137
- <Button variant='ghost' classNames='gap-2 plb-1' disabled={disabled}>
138
- <span className='sr-only'>{t('select hue label')}</span>
139
- <div role='none' className='pis-14 grow flex items-center justify-center gap-2'>
140
- {hue ? (
141
- <>
142
- <HuePreview hue={hueValue!} />
143
- <span>{t(`${hueValue} label`)}</span>
144
- </>
145
- ) : (
146
- <span>{t('select a hue label')}</span>
147
- )}
148
- </div>
149
- <Icon icon='ph--caret-down--regular' size={4} />
150
- </Button>
151
- </DropdownMenu.Trigger>
152
- <DropdownMenu.Portal>
153
- <DropdownMenu.Content side='right'>
154
- <DropdownMenu.Viewport>
155
- {hues.map((hue) => {
156
- return (
157
- <DropdownMenu.CheckboxItem
158
- key={hue}
159
- checked={hue === hueValue}
160
- onCheckedChange={() => setHueValue(hue)}
161
- >
162
- <HuePreview hue={hue} />
163
- <span className='grow'>{t(`${hue} label`)}</span>
164
- <DropdownMenu.ItemIndicator>
165
- <Icon icon='ph--check--regular' size={4} />
166
- </DropdownMenu.ItemIndicator>
167
- </DropdownMenu.CheckboxItem>
168
- );
169
- })}
170
- </DropdownMenu.Viewport>
171
- <DropdownMenu.Arrow />
172
- </DropdownMenu.Content>
173
- </DropdownMenu.Portal>
174
- </DropdownMenu.Root>
175
- <Tooltip.Root>
176
- <Tooltip.Trigger asChild>
177
- <Button variant='ghost' onClick={onClickClear} disabled={disabled}>
178
- <span className='sr-only'>{t('clear label')}</span>
179
- <Icon icon='ph--arrow-counter-clockwise--regular' size={5} />
180
- </Button>
181
- </Tooltip.Trigger>
182
- <Tooltip.Portal>
183
- <Tooltip.Content side='right'>
184
- {t('clear label')}
185
- <Tooltip.Arrow />
186
- </Tooltip.Content>
187
- </Tooltip.Portal>
188
- </Tooltip.Root>
189
- </>
37
+ <div className='flex p-[2px] justify-center items-center'>
38
+ <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
39
+ <rect x={0} y={0} width={size} height={size} fill={`var(--dx-${value}Fill)`} strokeWidth={4} />
40
+ </svg>
41
+ </div>
190
42
  );
191
43
  };
@@ -0,0 +1,39 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta, type StoryObj } from '@storybook/react';
8
+ import React, { useState } from 'react';
9
+
10
+ import { Toolbar } from '@dxos/react-ui';
11
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
12
+
13
+ import { IconPicker, type IconPickerProps } from './IconPicker';
14
+
15
+ const ToolbarStory = (props: IconPickerProps) => {
16
+ const [icon, setIcon] = useState<string | undefined>(props.value ?? props.defaultValue);
17
+ console.log(icon);
18
+
19
+ return (
20
+ <Toolbar.Root>
21
+ <IconPicker {...props} value={icon} onChange={setIcon} onReset={() => setIcon(undefined)} />
22
+ </Toolbar.Root>
23
+ );
24
+ };
25
+
26
+ const meta: Meta = {
27
+ title: 'ui/react-ui-pickers/IconPicker',
28
+ decorators: [withTheme, withLayout({ tooltips: true })],
29
+ parameters: {
30
+ layout: 'centered',
31
+ },
32
+ };
33
+
34
+ export default meta;
35
+
36
+ export const Default: StoryObj<IconPickerProps> = {
37
+ render: ToolbarStory,
38
+ args: {},
39
+ };
@@ -0,0 +1,92 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { type ButtonProps, Icon, type ThemedClassName, useTranslation } from '@dxos/react-ui';
8
+
9
+ import { ToolbarPickerButton, type ToolbarPickerProps } from './ToolbarPicker';
10
+
11
+ export type IconPickerProps = {
12
+ disabled?: boolean;
13
+ defaultValue?: string;
14
+ value?: string;
15
+ onChange?: (nextHue: string) => void;
16
+ onReset?: ButtonProps['onClick'];
17
+ } & Pick<ToolbarPickerProps, 'disabled' | 'defaultValue' | 'value' | 'onChange' | 'onReset'>;
18
+
19
+ export const IconPicker = ({ ...props }: ThemedClassName<IconPickerProps>) => {
20
+ const { t } = useTranslation('os');
21
+
22
+ return (
23
+ <ToolbarPickerButton
24
+ Component={IconPreview}
25
+ label={t('select icon label')}
26
+ icon='ph--selection--regular'
27
+ values={iconValues}
28
+ {...props}
29
+ />
30
+ );
31
+ };
32
+
33
+ const IconPreview = ({ value }: { value: string }) => {
34
+ return <Icon icon={`ph--${value}--regular`} size={5} />;
35
+ };
36
+
37
+ /**
38
+ * https://phosphoricons.com
39
+ * NOTE: Select icons that we are unlikely to use for the UI.
40
+ */
41
+ const icons = [
42
+ 'ph--air-traffic-control--regular',
43
+ 'ph--asterisk--regular',
44
+ 'ph--atom--regular',
45
+ 'ph--basketball--regular',
46
+ 'ph--butterfly--regular',
47
+ 'ph--cactus--regular',
48
+ 'ph--cake--regular',
49
+ 'ph--calendar-dots--regular',
50
+ 'ph--campfire--regular',
51
+ 'ph--command--regular',
52
+ 'ph--confetti--regular',
53
+ 'ph--detective--regular',
54
+ 'ph--disco-ball--regular',
55
+ 'ph--dna--regular',
56
+ 'ph--factory--regular',
57
+ 'ph--flag-banner-fold--regular',
58
+ 'ph--flask--regular',
59
+ 'ph--flower-lotus--regular',
60
+ 'ph--flying-saucer--regular',
61
+ 'ph--game-controller--regular',
62
+ 'ph--gavel--regular',
63
+ 'ph--gift--regular',
64
+ 'ph--guitar--regular',
65
+ 'ph--hamburger--regular',
66
+ 'ph--handshake--regular',
67
+ 'ph--heart--regular',
68
+ 'ph--lightbulb--regular',
69
+ 'ph--lock--regular',
70
+ 'ph--martini--regular',
71
+ 'ph--medal-military--regular',
72
+ 'ph--moped-front--regular',
73
+ 'ph--office-chair--regular',
74
+ 'ph--paint-brush-household--regular',
75
+ 'ph--peace--regular',
76
+ 'ph--person-simple-hike--regular',
77
+ 'ph--piggy-bank--regular',
78
+ 'ph--potted-plant--regular',
79
+ 'ph--radioactive--regular',
80
+ 'ph--rocket-launch--regular',
81
+ 'ph--shield-star--regular',
82
+ 'ph--shopping-cart--regular',
83
+ 'ph--stethoscope--regular',
84
+ 'ph--student--regular',
85
+ 'ph--sun--regular',
86
+ 'ph--tote--regular',
87
+ 'ph--tree--regular',
88
+ 'ph--users-three--regular',
89
+ 'ph--yin-yang--regular',
90
+ ];
91
+
92
+ const iconValues = icons.map((icon) => icon.match(/ph--(.+)--regular/)?.[1] ?? icon);
@@ -0,0 +1,112 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { useControllableState } from '@radix-ui/react-use-controllable-state';
6
+ import React, { type FC, useEffect, useRef, useState } from 'react';
7
+
8
+ import { DropdownMenu, Icon, type ThemedClassName, Toolbar, Tooltip } from '@dxos/react-ui';
9
+ import { mx } from '@dxos/react-ui-theme';
10
+
11
+ export type ToolbarPickerProps = {
12
+ Component: FC<{ value: string }>;
13
+ label: string;
14
+ icon: string;
15
+ values: string[];
16
+ disabled?: boolean;
17
+ defaultValue?: string;
18
+ value?: string;
19
+ onChange?: (value: string) => void;
20
+ onReset?: () => void;
21
+ };
22
+
23
+ export const ToolbarPickerButton = ({
24
+ Component,
25
+ disabled,
26
+ classNames,
27
+ defaultValue: _defaultValue,
28
+ value: _value,
29
+ values,
30
+ label,
31
+ icon,
32
+ onChange,
33
+ onReset,
34
+ }: ThemedClassName<ToolbarPickerProps>) => {
35
+ const [value, setValue] = useControllableState<string>({
36
+ prop: _value,
37
+ defaultProp: _defaultValue,
38
+ onChange,
39
+ });
40
+ // TODO(burdon): useControllableState doesn't update the prop when the value is changed. Replace it.
41
+ useEffect(() => setValue(_value), [_value]);
42
+
43
+ const [open, setOpen] = useState<boolean>(false);
44
+
45
+ const suppressNextTooltip = useRef<boolean>(false);
46
+ const [triggerTooltipOpen, setTriggerTooltipOpen] = useState(false);
47
+
48
+ return (
49
+ <Tooltip.Root
50
+ open={triggerTooltipOpen}
51
+ onOpenChange={(nextOpen) => {
52
+ if (suppressNextTooltip.current) {
53
+ setTriggerTooltipOpen(false);
54
+ suppressNextTooltip.current = false;
55
+ } else {
56
+ setTriggerTooltipOpen(nextOpen);
57
+ }
58
+ }}
59
+ >
60
+ <DropdownMenu.Root
61
+ modal={false}
62
+ open={open}
63
+ onOpenChange={(nextOpen) => {
64
+ setOpen(nextOpen);
65
+ suppressNextTooltip.current = true;
66
+ }}
67
+ >
68
+ <Tooltip.Trigger asChild>
69
+ <DropdownMenu.Trigger asChild>
70
+ <Toolbar.Button classNames={mx('gap-2 plb-1', classNames)} disabled={disabled}>
71
+ <span className='sr-only'>{label}</span>
72
+ {(value && <Component value={value} />) || <Icon icon={icon} size={5} />}
73
+ </Toolbar.Button>
74
+ </DropdownMenu.Trigger>
75
+ </Tooltip.Trigger>
76
+ <Tooltip.Portal>
77
+ <Tooltip.Content side='bottom'>
78
+ {label}
79
+ <Tooltip.Arrow />
80
+ </Tooltip.Content>
81
+ </Tooltip.Portal>
82
+ <DropdownMenu.Portal>
83
+ <DropdownMenu.Content side='bottom' classNames='!w-40'>
84
+ <DropdownMenu.Viewport classNames='grid grid-cols-6'>
85
+ {values.map((_value) => {
86
+ return (
87
+ <DropdownMenu.CheckboxItem
88
+ key={_value}
89
+ checked={_value === value}
90
+ onCheckedChange={() => setValue(_value)}
91
+ classNames={'!p-0 items-center justify-center'}
92
+ >
93
+ <Component value={_value} />
94
+ </DropdownMenu.CheckboxItem>
95
+ );
96
+ })}
97
+ {onReset && (
98
+ <DropdownMenu.CheckboxItem
99
+ onCheckedChange={() => onReset()}
100
+ classNames={'!p-0 items-center justify-center'}
101
+ >
102
+ <Icon icon='ph--x--regular' size={5} />
103
+ </DropdownMenu.CheckboxItem>
104
+ )}
105
+ </DropdownMenu.Viewport>
106
+ <DropdownMenu.Arrow />
107
+ </DropdownMenu.Content>
108
+ </DropdownMenu.Portal>
109
+ </DropdownMenu.Root>
110
+ </Tooltip.Root>
111
+ );
112
+ };
@@ -4,3 +4,5 @@
4
4
 
5
5
  export * from './EmojiPicker';
6
6
  export * from './HuePicker';
7
+ export * from './IconPicker';
8
+ export * from './ToolbarPicker';