@choice-ui/react 1.7.7 → 1.8.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.
Files changed (27) hide show
  1. package/dist/components/emoji-picker/dist/index.d.ts +29 -1
  2. package/dist/components/emoji-picker/dist/index.js +144 -42
  3. package/dist/components/emoji-picker/src/components/emoji-empty.d.ts +4 -0
  4. package/dist/components/emoji-picker/src/components/emoji-empty.js +9 -3
  5. package/dist/components/emoji-picker/src/components/emoji-footer.d.ts +4 -1
  6. package/dist/components/emoji-picker/src/components/emoji-footer.js +11 -3
  7. package/dist/components/emoji-picker/src/emoji-picker.d.ts +16 -0
  8. package/dist/components/emoji-picker/src/emoji-picker.js +59 -19
  9. package/dist/components/emoji-picker/src/hooks/index.d.ts +1 -1
  10. package/dist/components/emoji-picker/src/hooks/use-emoji-data.d.ts +13 -10
  11. package/dist/components/emoji-picker/src/hooks/use-emoji-data.js +41 -13
  12. package/dist/components/emoji-picker/src/hooks/use-emoji-scroll.js +24 -3
  13. package/dist/components/emoji-picker/src/tv.js +1 -1
  14. package/dist/components/icon-button/dist/index.d.ts +1 -1
  15. package/dist/components/icon-button/dist/index.js +29 -0
  16. package/dist/components/icon-button/src/icon-button.d.ts +1 -1
  17. package/dist/components/icon-button/src/tv.d.ts +9 -0
  18. package/dist/components/icon-button/src/tv.js +29 -0
  19. package/dist/components/textarea/dist/index.js +3 -1
  20. package/dist/components/tooltip/dist/index.d.ts +2 -0
  21. package/dist/components/tooltip/dist/index.js +23 -5
  22. package/dist/components/tooltip/src/components/tooltip-content.js +20 -4
  23. package/dist/components/tooltip/src/tooltip.js +3 -1
  24. package/dist/components/tooltip/src/types.d.ts +3 -0
  25. package/dist/components/virtual-select/dist/index.d.ts +48 -0
  26. package/dist/styles/components.css +15 -0
  27. package/package.json +20 -32
@@ -16,47 +16,50 @@ export type VirtualItem = {
16
16
  };
17
17
  export declare const categories: readonly [{
18
18
  readonly id: "frequently_used";
19
- readonly name: "Frequently used";
20
19
  }, {
21
20
  readonly id: "smileys_people";
22
- readonly name: "Smileys & People";
23
21
  readonly range: readonly [1, 460];
24
22
  }, {
25
23
  readonly id: "animals_nature";
26
- readonly name: "Animals & Nature";
27
24
  readonly range: readonly [465, 591];
28
25
  }, {
29
26
  readonly id: "food_drink";
30
- readonly name: "Food & Drink";
31
27
  readonly range: readonly [592, 712];
32
28
  }, {
33
29
  readonly id: "travel_places";
34
- readonly name: "Travel & Places";
35
30
  readonly range: readonly [713, 922];
36
31
  }, {
37
32
  readonly id: "activities";
38
- readonly name: "Activities";
39
33
  readonly range: readonly [923, 1001];
40
34
  }, {
41
35
  readonly id: "objects";
42
- readonly name: "Objects";
43
36
  readonly range: readonly [1002, 1234];
44
37
  }, {
45
38
  readonly id: "symbols";
46
- readonly name: "Symbols";
47
39
  readonly range: readonly [1235, 1451];
48
40
  }, {
49
41
  readonly id: "flags";
50
- readonly name: "Flags";
51
42
  readonly range: readonly [1452, 1719];
52
43
  }];
53
44
  export declare function getEmojiCategory(id: number): EmojiCategory;
45
+ export interface CategoryNames {
46
+ activities: string;
47
+ animalsNature: string;
48
+ flags: string;
49
+ foodDrink: string;
50
+ frequentlyUsed: string;
51
+ objects: string;
52
+ smileysPeople: string;
53
+ symbols: string;
54
+ travelPlaces: string;
55
+ }
54
56
  interface UseEmojiDataProps {
57
+ categoryNames?: CategoryNames;
55
58
  columns: number;
56
59
  searchQuery: string;
57
60
  showFrequentlyUsed: boolean;
58
61
  }
59
- export declare function useEmojiData({ searchQuery, columns, showFrequentlyUsed }: UseEmojiDataProps): {
62
+ export declare function useEmojiData({ searchQuery, columns, showFrequentlyUsed, categoryNames, }: UseEmojiDataProps): {
60
63
  categorizedData: VirtualItem[];
61
64
  categoryIndexMap: Map<EmojiCategory, number>;
62
65
  searchResults: {
@@ -2,15 +2,15 @@ import { useState, useEffect, useMemo } from "react";
2
2
  import { emojis } from "../utils/emoji-data.js";
3
3
  import { isBrowser } from "../../../../shared/utils/ssr.js";
4
4
  const categories = [
5
- { id: "frequently_used", name: "Frequently used" },
6
- { id: "smileys_people", name: "Smileys & People", range: [1, 460] },
7
- { id: "animals_nature", name: "Animals & Nature", range: [465, 591] },
8
- { id: "food_drink", name: "Food & Drink", range: [592, 712] },
9
- { id: "travel_places", name: "Travel & Places", range: [713, 922] },
10
- { id: "activities", name: "Activities", range: [923, 1001] },
11
- { id: "objects", name: "Objects", range: [1002, 1234] },
12
- { id: "symbols", name: "Symbols", range: [1235, 1451] },
13
- { id: "flags", name: "Flags", range: [1452, 1719] }
5
+ { id: "frequently_used" },
6
+ { id: "smileys_people", range: [1, 460] },
7
+ { id: "animals_nature", range: [465, 591] },
8
+ { id: "food_drink", range: [592, 712] },
9
+ { id: "travel_places", range: [713, 922] },
10
+ { id: "activities", range: [923, 1001] },
11
+ { id: "objects", range: [1002, 1234] },
12
+ { id: "symbols", range: [1235, 1451] },
13
+ { id: "flags", range: [1452, 1719] }
14
14
  ];
15
15
  const STORAGE_KEY = "emoji-picker-frequently-used";
16
16
  function getEmojiCategory(id) {
@@ -44,7 +44,34 @@ function saveFrequentlyUsedEmoji(emojiId) {
44
44
  } catch {
45
45
  }
46
46
  }
47
- function useEmojiData({ searchQuery, columns, showFrequentlyUsed }) {
47
+ const defaultCategoryNames = {
48
+ frequentlyUsed: "Frequently used",
49
+ smileysPeople: "Smileys & People",
50
+ animalsNature: "Animals & Nature",
51
+ foodDrink: "Food & Drink",
52
+ travelPlaces: "Travel & Places",
53
+ activities: "Activities",
54
+ objects: "Objects",
55
+ symbols: "Symbols",
56
+ flags: "Flags"
57
+ };
58
+ const categoryIdToI18nKey = {
59
+ frequently_used: "frequentlyUsed",
60
+ smileys_people: "smileysPeople",
61
+ animals_nature: "animalsNature",
62
+ food_drink: "foodDrink",
63
+ travel_places: "travelPlaces",
64
+ activities: "activities",
65
+ objects: "objects",
66
+ symbols: "symbols",
67
+ flags: "flags"
68
+ };
69
+ function useEmojiData({
70
+ searchQuery,
71
+ columns,
72
+ showFrequentlyUsed,
73
+ categoryNames = defaultCategoryNames
74
+ }) {
48
75
  const [frequentlyUsed, setFrequentlyUsed] = useState([]);
49
76
  useEffect(() => {
50
77
  if (showFrequentlyUsed) {
@@ -74,7 +101,7 @@ function useEmojiData({ searchQuery, columns, showFrequentlyUsed }) {
74
101
  items.push({
75
102
  type: "header",
76
103
  category: "frequently_used",
77
- title: "Frequently used"
104
+ title: categoryNames.frequentlyUsed
78
105
  });
79
106
  for (let i = 0; i < frequentlyUsed.length; i += columns) {
80
107
  items.push({
@@ -89,10 +116,11 @@ function useEmojiData({ searchQuery, columns, showFrequentlyUsed }) {
89
116
  (emoji) => emoji.id >= category.range[0] && emoji.id <= category.range[1]
90
117
  );
91
118
  if (categoryEmojis.length > 0) {
119
+ const i18nKey = categoryIdToI18nKey[category.id];
92
120
  items.push({
93
121
  type: "header",
94
122
  category: category.id,
95
- title: category.name
123
+ title: i18nKey ? categoryNames[i18nKey] : category.id
96
124
  });
97
125
  for (let i = 0; i < categoryEmojis.length; i += columns) {
98
126
  items.push({
@@ -103,7 +131,7 @@ function useEmojiData({ searchQuery, columns, showFrequentlyUsed }) {
103
131
  }
104
132
  });
105
133
  return items;
106
- }, [searchQuery, searchResults, frequentlyUsed, columns, showFrequentlyUsed]);
134
+ }, [searchQuery, searchResults, frequentlyUsed, columns, showFrequentlyUsed, categoryNames]);
107
135
  const categoryIndexMap = useMemo(() => {
108
136
  const map = /* @__PURE__ */ new Map();
109
137
  categorizedData.forEach((item, index) => {
@@ -17,6 +17,8 @@ function useEmojiScroll({
17
17
  const [currentVisibleCategory, setCurrentVisibleCategory] = useState("frequently_used");
18
18
  const isScrollingToTarget = useRef(false);
19
19
  const isInternalUpdate = useRef(false);
20
+ const scrollingTimeoutRef = useRef(null);
21
+ const internalUpdateTimeoutRef = useRef(null);
20
22
  const virtualizer = useVirtualizer({
21
23
  count: categorizedData.length,
22
24
  getScrollElement: () => scrollRef.current,
@@ -81,7 +83,10 @@ function useEmojiScroll({
81
83
  align: "start",
82
84
  behavior: "auto"
83
85
  });
84
- setTimeout(() => {
86
+ if (scrollingTimeoutRef.current) {
87
+ clearTimeout(scrollingTimeoutRef.current);
88
+ }
89
+ scrollingTimeoutRef.current = setTimeout(() => {
85
90
  isScrollingToTarget.current = false;
86
91
  }, 100);
87
92
  }
@@ -94,17 +99,33 @@ function useEmojiScroll({
94
99
  align: "center",
95
100
  behavior: "auto"
96
101
  });
97
- setTimeout(() => {
102
+ if (scrollingTimeoutRef.current) {
103
+ clearTimeout(scrollingTimeoutRef.current);
104
+ }
105
+ scrollingTimeoutRef.current = setTimeout(() => {
98
106
  isScrollingToTarget.current = false;
99
107
  }, 100);
100
108
  }
101
109
  });
102
110
  const markInternalUpdate = useEventCallback(() => {
103
111
  isInternalUpdate.current = true;
104
- setTimeout(() => {
112
+ if (internalUpdateTimeoutRef.current) {
113
+ clearTimeout(internalUpdateTimeoutRef.current);
114
+ }
115
+ internalUpdateTimeoutRef.current = setTimeout(() => {
105
116
  isInternalUpdate.current = false;
106
117
  }, 50);
107
118
  });
119
+ useEffect(() => {
120
+ return () => {
121
+ if (scrollingTimeoutRef.current) {
122
+ clearTimeout(scrollingTimeoutRef.current);
123
+ }
124
+ if (internalUpdateTimeoutRef.current) {
125
+ clearTimeout(internalUpdateTimeoutRef.current);
126
+ }
127
+ };
128
+ }, []);
108
129
  useEffect(() => {
109
130
  if (value && !searchQuery.trim() && !isInternalUpdate.current) {
110
131
  scrollToEmoji(value);
@@ -132,7 +132,7 @@ const emojiFooterTv = tcv({
132
132
  const emojiEmptyTv = tcv({
133
133
  slots: {
134
134
  container: "flex h-32 flex-col items-center justify-center p-4 text-center",
135
- title: "text-heading-display",
135
+ title: "text-body-large-strong",
136
136
  description: "mt-2 w-32"
137
137
  },
138
138
  variants: {
@@ -14,7 +14,7 @@ interface IconButtonProps extends Omit<HTMLProps<HTMLElement>, "size" | "as"> {
14
14
  readOnly?: boolean;
15
15
  size?: "default" | "large" | "reset";
16
16
  tooltip?: TooltipProps;
17
- variant?: "default" | "secondary" | "solid" | "highlight" | "ghost" | "dark" | "reset";
17
+ variant?: "default" | "secondary" | "solid" | "highlight" | "ghost" | "dark" | "submit" | "reset";
18
18
  }
19
19
  declare const IconButton: react.ForwardRefExoticComponent<Omit<IconButtonProps, "ref"> & react.RefAttributes<HTMLElement>>;
20
20
 
@@ -28,6 +28,12 @@ var iconButtonTv = tcv({
28
28
  highlight: {},
29
29
  ghost: {},
30
30
  dark: { button: "text-white" },
31
+ submit: {
32
+ button: [
33
+ "bg-[var(--theme-submit-btn-bg)] text-[var(--theme-submit-btn-text)]",
34
+ "focus-visible:border-transparent"
35
+ ]
36
+ },
31
37
  reset: {}
32
38
  },
33
39
  active: {
@@ -141,6 +147,29 @@ var iconButtonTv = tcv({
141
147
  variant: "dark",
142
148
  disabled: true,
143
149
  class: { button: "text-gray-500" }
150
+ },
151
+ {
152
+ variant: "submit",
153
+ class: {
154
+ button: "focus-visible:shadow-focus"
155
+ }
156
+ },
157
+ {
158
+ variant: "submit",
159
+ focused: true,
160
+ class: {
161
+ button: ["shadow-focus", "border-transparent"]
162
+ }
163
+ },
164
+ {
165
+ variant: "submit",
166
+ loading: true,
167
+ class: { button: "opacity-70" }
168
+ },
169
+ {
170
+ variant: "submit",
171
+ disabled: true,
172
+ class: { button: "opacity-50" }
144
173
  }
145
174
  ],
146
175
  defaultVariants: {
@@ -12,6 +12,6 @@ export interface IconButtonProps extends Omit<HTMLProps<HTMLElement>, "size" | "
12
12
  readOnly?: boolean;
13
13
  size?: "default" | "large" | "reset";
14
14
  tooltip?: TooltipProps;
15
- variant?: "default" | "secondary" | "solid" | "highlight" | "ghost" | "dark" | "reset";
15
+ variant?: "default" | "secondary" | "solid" | "highlight" | "ghost" | "dark" | "submit" | "reset";
16
16
  }
17
17
  export declare const IconButton: import('react').ForwardRefExoticComponent<Omit<IconButtonProps, "ref"> & import('react').RefAttributes<HTMLElement>>;
@@ -21,6 +21,9 @@ export declare const iconButtonTv: import('tailwind-variants').TVReturnType<{
21
21
  dark: {
22
22
  button: string;
23
23
  };
24
+ submit: {
25
+ button: string[];
26
+ };
24
27
  reset: {};
25
28
  };
26
29
  active: {
@@ -68,6 +71,9 @@ export declare const iconButtonTv: import('tailwind-variants').TVReturnType<{
68
71
  dark: {
69
72
  button: string;
70
73
  };
74
+ submit: {
75
+ button: string[];
76
+ };
71
77
  reset: {};
72
78
  };
73
79
  active: {
@@ -115,6 +121,9 @@ export declare const iconButtonTv: import('tailwind-variants').TVReturnType<{
115
121
  dark: {
116
122
  button: string;
117
123
  };
124
+ submit: {
125
+ button: string[];
126
+ };
118
127
  reset: {};
119
128
  };
120
129
  active: {
@@ -23,6 +23,12 @@ const iconButtonTv = tcv({
23
23
  highlight: {},
24
24
  ghost: {},
25
25
  dark: { button: "text-white" },
26
+ submit: {
27
+ button: [
28
+ "bg-[var(--theme-submit-btn-bg)] text-[var(--theme-submit-btn-text)]",
29
+ "focus-visible:border-transparent"
30
+ ]
31
+ },
26
32
  reset: {}
27
33
  },
28
34
  active: {
@@ -136,6 +142,29 @@ const iconButtonTv = tcv({
136
142
  variant: "dark",
137
143
  disabled: true,
138
144
  class: { button: "text-gray-500" }
145
+ },
146
+ {
147
+ variant: "submit",
148
+ class: {
149
+ button: "focus-visible:shadow-focus"
150
+ }
151
+ },
152
+ {
153
+ variant: "submit",
154
+ focused: true,
155
+ class: {
156
+ button: ["shadow-focus", "border-transparent"]
157
+ }
158
+ },
159
+ {
160
+ variant: "submit",
161
+ loading: true,
162
+ class: { button: "opacity-70" }
163
+ },
164
+ {
165
+ variant: "submit",
166
+ disabled: true,
167
+ class: { button: "opacity-50" }
139
168
  }
140
169
  ],
141
170
  defaultVariants: {
@@ -507,7 +507,9 @@ var TextareaTv = tcv({
507
507
  container: "bg-gray-700",
508
508
  textarea: "text-white placeholder:text-white/40"
509
509
  },
510
- reset: {}
510
+ reset: {
511
+ container: "rounded-none border-0"
512
+ }
511
513
  },
512
514
  resize: {
513
515
  auto: {},
@@ -10,6 +10,7 @@ interface TooltipProps {
10
10
  className?: string;
11
11
  content?: React.ReactNode;
12
12
  disabled?: boolean;
13
+ interactive?: boolean;
13
14
  offset?: number;
14
15
  onOpenChange?: (open: boolean) => void;
15
16
  open?: boolean;
@@ -23,6 +24,7 @@ interface TooltipProps {
23
24
  withArrow?: boolean;
24
25
  }
25
26
  interface TooltipContentProps extends React.HTMLProps<HTMLDivElement> {
27
+ interactive?: boolean;
26
28
  portalId?: string;
27
29
  variant?: "default" | "light";
28
30
  withArrow?: boolean;
@@ -128,7 +128,15 @@ var TooltipArrow = forwardRef(function TooltipArrow2({ className, variant = "def
128
128
  });
129
129
  var TooltipContent = forwardRef(
130
130
  function TooltipContent2(props, propRef) {
131
- const { className, withArrow = true, variant = "default", children, portalId, ...rest } = props;
131
+ const {
132
+ className,
133
+ withArrow = true,
134
+ variant = "default",
135
+ children,
136
+ portalId,
137
+ interactive = true,
138
+ ...rest
139
+ } = props;
132
140
  const state = useTooltipState();
133
141
  const ref = useMergeRefs([state.refs.setFloating, propRef]);
134
142
  const { isInstantPhase, currentId } = useDelayGroup(state.context, {
@@ -157,19 +165,27 @@ var TooltipContent = forwardRef(
157
165
  });
158
166
  const tv = useMemo(() => tooltipContentVariants({ variant }), [variant]);
159
167
  if (state.disabled || !isMounted) return null;
168
+ const floatingProps = state.getFloatingProps(rest);
160
169
  return /* @__PURE__ */ jsx(FloatingPortal, { id: portalId, children: /* @__PURE__ */ jsx(
161
170
  "div",
162
171
  {
163
172
  ref,
164
- style: state.floatingStyles,
165
- ...state.getFloatingProps(rest),
173
+ style: {
174
+ ...state.floatingStyles,
175
+ pointerEvents: interactive ? void 0 : "none"
176
+ },
177
+ ...floatingProps,
166
178
  className: "z-tooltip",
167
179
  children: /* @__PURE__ */ jsxs(
168
180
  "div",
169
181
  {
170
182
  className: tcx(tv.root({ className })),
171
183
  "data-state": state.open ? "open" : "closed",
172
- style: styles,
184
+ style: {
185
+ ...styles,
186
+ pointerEvents: interactive ? void 0 : "none",
187
+ cursor: interactive ? void 0 : "default"
188
+ },
173
189
  children: [
174
190
  children,
175
191
  withArrow && /* @__PURE__ */ jsx(TooltipArrow, { variant })
@@ -272,7 +288,8 @@ function TooltipRoot(props) {
272
288
  withArrow = true,
273
289
  variant = "default",
274
290
  offset: offset2 = 8,
275
- portalId = PORTAL_ROOT_ID
291
+ portalId = PORTAL_ROOT_ID,
292
+ interactive = true
276
293
  } = props;
277
294
  const tooltip = useTooltip({
278
295
  placement,
@@ -291,6 +308,7 @@ function TooltipRoot(props) {
291
308
  variant,
292
309
  portalId,
293
310
  className,
311
+ interactive,
294
312
  children: [
295
313
  content,
296
314
  shortcut && /* @__PURE__ */ jsx(
@@ -7,7 +7,15 @@ import { TooltipArrow } from "./tooltip-arrow.js";
7
7
  import { tcx } from "../../../../shared/utils/tcx/tcx.js";
8
8
  const TooltipContent = forwardRef(
9
9
  function TooltipContent2(props, propRef) {
10
- const { className, withArrow = true, variant = "default", children, portalId, ...rest } = props;
10
+ const {
11
+ className,
12
+ withArrow = true,
13
+ variant = "default",
14
+ children,
15
+ portalId,
16
+ interactive = true,
17
+ ...rest
18
+ } = props;
11
19
  const state = useTooltipState();
12
20
  const ref = useMergeRefs([state.refs.setFloating, propRef]);
13
21
  const { isInstantPhase, currentId } = useDelayGroup(state.context, {
@@ -36,19 +44,27 @@ const TooltipContent = forwardRef(
36
44
  });
37
45
  const tv = useMemo(() => tooltipContentVariants({ variant }), [variant]);
38
46
  if (state.disabled || !isMounted) return null;
47
+ const floatingProps = state.getFloatingProps(rest);
39
48
  return /* @__PURE__ */ jsx(FloatingPortal, { id: portalId, children: /* @__PURE__ */ jsx(
40
49
  "div",
41
50
  {
42
51
  ref,
43
- style: state.floatingStyles,
44
- ...state.getFloatingProps(rest),
52
+ style: {
53
+ ...state.floatingStyles,
54
+ pointerEvents: interactive ? void 0 : "none"
55
+ },
56
+ ...floatingProps,
45
57
  className: "z-tooltip",
46
58
  children: /* @__PURE__ */ jsxs(
47
59
  "div",
48
60
  {
49
61
  className: tcx(tv.root({ className })),
50
62
  "data-state": state.open ? "open" : "closed",
51
- style: styles,
63
+ style: {
64
+ ...styles,
65
+ pointerEvents: interactive ? void 0 : "none",
66
+ cursor: interactive ? void 0 : "default"
67
+ },
52
68
  children: [
53
69
  children,
54
70
  withArrow && /* @__PURE__ */ jsx(TooltipArrow, { variant })
@@ -17,7 +17,8 @@ function TooltipRoot(props) {
17
17
  withArrow = true,
18
18
  variant = "default",
19
19
  offset = 8,
20
- portalId = PORTAL_ROOT_ID
20
+ portalId = PORTAL_ROOT_ID,
21
+ interactive = true
21
22
  } = props;
22
23
  const tooltip = useTooltip({
23
24
  placement,
@@ -36,6 +37,7 @@ function TooltipRoot(props) {
36
37
  variant,
37
38
  portalId,
38
39
  className,
40
+ interactive,
39
41
  children: [
40
42
  content,
41
43
  shortcut && /* @__PURE__ */ jsx(
@@ -4,6 +4,7 @@ import { KbdKey } from '../../kbd/src';
4
4
  export interface TooltipOptions {
5
5
  disabled?: boolean;
6
6
  initialOpen?: boolean;
7
+ interactive?: boolean;
7
8
  offset?: number;
8
9
  onOpenChange?: (open: boolean) => void;
9
10
  open?: boolean;
@@ -32,6 +33,7 @@ export interface TooltipProps {
32
33
  className?: string;
33
34
  content?: React.ReactNode;
34
35
  disabled?: boolean;
36
+ interactive?: boolean;
35
37
  offset?: number;
36
38
  onOpenChange?: (open: boolean) => void;
37
39
  open?: boolean;
@@ -45,6 +47,7 @@ export interface TooltipProps {
45
47
  withArrow?: boolean;
46
48
  }
47
49
  export interface TooltipContentProps extends React.HTMLProps<HTMLDivElement> {
50
+ interactive?: boolean;
48
51
  portalId?: string;
49
52
  variant?: "default" | "light";
50
53
  withArrow?: boolean;
@@ -0,0 +1,48 @@
1
+ import { MenuContextContent, MenuDivider, MenuEmpty, MenuContextItem, MenuSearch, MenuTrigger, MenuValue } from '../../menus/src';
2
+ import { FloatingFocusManagerProps } from '@floating-ui/react';
3
+ import { default as React } from 'react';
4
+ interface VirtualSelectOption<T = unknown> {
5
+ value: string;
6
+ label: string;
7
+ disabled?: boolean;
8
+ data?: T;
9
+ }
10
+ interface VirtualSelectProps<T = unknown> {
11
+ className?: string;
12
+ closeOnEscape?: boolean;
13
+ disabled?: boolean;
14
+ emptyText?: string;
15
+ focusManagerProps?: Partial<FloatingFocusManagerProps>;
16
+ matchTriggerWidth?: boolean;
17
+ maxHeight?: number;
18
+ onChange?: (value: string) => void;
19
+ onOpenChange?: (open: boolean) => void;
20
+ open?: boolean;
21
+ options: VirtualSelectOption<T>[];
22
+ overscan?: number;
23
+ placeholder?: string;
24
+ placement?: "bottom-start" | "bottom-end";
25
+ portalId?: string;
26
+ readOnly?: boolean;
27
+ renderOption?: (option: VirtualSelectOption<T>, isSelected: boolean) => React.ReactNode;
28
+ renderValue?: (option: VirtualSelectOption<T> | null) => React.ReactNode;
29
+ root?: HTMLElement | null;
30
+ searchPlaceholder?: string;
31
+ size?: "default" | "large";
32
+ value?: string | null;
33
+ variant?: "default" | "light" | "reset";
34
+ }
35
+ interface VirtualSelectComponentType {
36
+ <T = unknown>(props: VirtualSelectProps<T>): React.ReactElement | null;
37
+ displayName?: string;
38
+ Content: typeof MenuContextContent;
39
+ Divider: typeof MenuDivider;
40
+ Empty: typeof MenuEmpty;
41
+ Item: typeof MenuContextItem;
42
+ Search: typeof MenuSearch;
43
+ Trigger: typeof MenuTrigger;
44
+ Value: typeof MenuValue;
45
+ }
46
+ declare const VirtualSelect: VirtualSelectComponentType;
47
+
48
+ export { VirtualSelect, type VirtualSelectOption, type VirtualSelectProps };
@@ -26,6 +26,9 @@
26
26
  --animate-spinner-bounce-right: spinner-bounce-right 0.5s infinite alternate ease;
27
27
  --animate-indeterminate-bar: indeterminate-bar 1.5s cubic-bezier(0.65, 0.815, 0.735, 0.395)
28
28
  infinite normal none running;
29
+
30
+ --theme-submit-btn-bg: var(--default-theme-submit-btn-bg);
31
+ --theme-submit-btn-text: var(--default-theme-submit-btn-text);
29
32
  }
30
33
 
31
34
  /* Base styles */
@@ -654,3 +657,15 @@
654
657
  }
655
658
  }
656
659
  }
660
+
661
+ /* Submit button theme variables */
662
+ :root {
663
+ --default-theme-submit-btn-bg: #000;
664
+ --default-theme-submit-btn-text: #fff;
665
+ }
666
+
667
+ .dark,
668
+ .light .dark {
669
+ --default-theme-submit-btn-bg: #fff;
670
+ --default-theme-submit-btn-text: #000;
671
+ }