@dust-tt/sparkle 0.7.6-rc-3 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +14 -14
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/components/AssistantCard.js +1 -1
- package/dist/esm/components/AssistantCard.js.map +1 -1
- package/dist/esm/components/Button.d.ts +10 -25
- package/dist/esm/components/Button.d.ts.map +1 -1
- package/dist/esm/components/Button.js +7 -21
- package/dist/esm/components/Button.js.map +1 -1
- package/dist/esm/components/ButtonGroup.d.ts +2 -2
- package/dist/esm/components/ButtonGroup.d.ts.map +1 -1
- package/dist/esm/components/ButtonGroup.js +2 -4
- package/dist/esm/components/ButtonGroup.js.map +1 -1
- package/dist/esm/components/Card.d.ts +13 -6
- package/dist/esm/components/Card.d.ts.map +1 -1
- package/dist/esm/components/Card.js +2 -2
- package/dist/esm/components/Card.js.map +1 -1
- package/dist/esm/components/InteractiveImageGrid.d.ts +3 -3
- package/dist/esm/components/InteractiveImageGrid.js +4 -4
- package/dist/esm/components/InteractiveImageGrid.js.map +1 -1
- package/dist/esm/components/NavigationList.js +3 -3
- package/dist/esm/components/Tabs.d.ts +1 -14
- package/dist/esm/components/Tabs.d.ts.map +1 -1
- package/dist/esm/components/VoicePicker.d.ts +17 -0
- package/dist/esm/components/VoicePicker.d.ts.map +1 -0
- package/dist/esm/components/VoicePicker.js +137 -0
- package/dist/esm/components/VoicePicker.js.map +1 -0
- package/dist/esm/components/index.d.ts +2 -0
- package/dist/esm/components/index.d.ts.map +1 -1
- package/dist/esm/components/index.js +1 -0
- package/dist/esm/components/index.js.map +1 -1
- package/dist/esm/logo/platforms/Ukg.d.ts +5 -0
- package/dist/esm/logo/platforms/Ukg.d.ts.map +1 -0
- package/dist/esm/logo/platforms/Ukg.js +6 -0
- package/dist/esm/logo/platforms/Ukg.js.map +1 -0
- package/dist/esm/logo/platforms/index.d.ts +1 -0
- package/dist/esm/logo/platforms/index.d.ts.map +1 -1
- package/dist/esm/logo/platforms/index.js +1 -0
- package/dist/esm/logo/platforms/index.js.map +1 -1
- package/dist/esm/logo/src/platforms/UKG.svg +5 -0
- package/dist/esm/lottie/collapseBar.d.ts +21 -21
- package/dist/esm/lottie/dragArea.d.ts +30 -30
- package/dist/esm/lottie/spinnerColor.d.ts +73 -73
- package/dist/esm/lottie/spinnerColorLG.d.ts +125 -125
- package/dist/esm/lottie/spinnerColorXS.d.ts +11 -11
- package/dist/esm/lottie/spinnerDark.d.ts +73 -73
- package/dist/esm/lottie/spinnerDarkLG.d.ts +142 -142
- package/dist/esm/lottie/spinnerDarkXS.d.ts +38 -38
- package/dist/esm/lottie/spinnerLight.d.ts +66 -66
- package/dist/esm/lottie/spinnerLightLG.d.ts +142 -142
- package/dist/esm/lottie/spinnerLightXS.d.ts +38 -38
- package/dist/esm/stories/Button.stories.d.ts +12 -30
- package/dist/esm/stories/Button.stories.d.ts.map +1 -1
- package/dist/esm/stories/Button.stories.js +7 -15
- package/dist/esm/stories/Button.stories.js.map +1 -1
- package/dist/esm/stories/ButtonGroup.stories.d.ts +1 -1
- package/dist/esm/stories/ButtonGroup.stories.js +1 -1
- package/dist/esm/stories/ButtonGroup.stories.js.map +1 -1
- package/dist/esm/stories/Card.stories.js +2 -2
- package/dist/esm/stories/Card.stories.js.map +1 -1
- package/dist/esm/stories/InteractiveImageGrid.stories.d.ts.map +1 -1
- package/dist/esm/stories/InteractiveImageGrid.stories.js.map +1 -1
- package/dist/esm/stories/VoicePicker.stories.d.ts +49 -0
- package/dist/esm/stories/VoicePicker.stories.d.ts.map +1 -0
- package/dist/esm/stories/VoicePicker.stories.js +111 -0
- package/dist/esm/stories/VoicePicker.stories.js.map +1 -0
- package/dist/esm/styles/allotment.css +36 -14
- package/package.json +1 -1
- package/src/components/AssistantCard.tsx +1 -1
- package/src/components/Button.tsx +15 -30
- package/src/components/ButtonGroup.tsx +6 -9
- package/src/components/Card.tsx +2 -7
- package/src/components/InteractiveImageGrid.tsx +4 -4
- package/src/components/NavigationList.tsx +3 -3
- package/src/components/VoicePicker.tsx +267 -0
- package/src/components/index.ts +2 -0
- package/src/logo/platforms/Ukg.tsx +22 -0
- package/src/logo/platforms/index.ts +1 -0
- package/src/logo/src/platforms/UKG.svg +5 -0
- package/src/styles/allotment.css +36 -14
|
@@ -17,28 +17,37 @@
|
|
|
17
17
|
width: 100%;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
.allotment-module_splitView__L-yRc
|
|
20
|
+
.allotment-module_splitView__L-yRc
|
|
21
|
+
> .allotment-module_sashContainer__fzwJF
|
|
22
|
+
> .allotment-module_sash__QA-2t {
|
|
21
23
|
pointer-events: auto;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
.allotment-module_splitView__L-yRc
|
|
26
|
+
.allotment-module_splitView__L-yRc
|
|
27
|
+
> .allotment-module_splitViewContainer__rQnVa {
|
|
25
28
|
height: 100%;
|
|
26
29
|
position: relative;
|
|
27
30
|
white-space: nowrap;
|
|
28
31
|
width: 100%;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
.allotment-module_splitView__L-yRc
|
|
34
|
+
.allotment-module_splitView__L-yRc
|
|
35
|
+
> .allotment-module_splitViewContainer__rQnVa
|
|
36
|
+
> .allotment-module_splitViewView__MGZ6O {
|
|
32
37
|
overflow: hidden;
|
|
33
38
|
position: absolute;
|
|
34
39
|
white-space: initial;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
.allotment-module_splitView__L-yRc.allotment-module_vertical__WSwwa
|
|
42
|
+
.allotment-module_splitView__L-yRc.allotment-module_vertical__WSwwa
|
|
43
|
+
> .allotment-module_splitViewContainer__rQnVa
|
|
44
|
+
> .allotment-module_splitViewView__MGZ6O {
|
|
38
45
|
width: 100%;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
.allotment-module_splitView__L-yRc.allotment-module_horizontal__7doS8
|
|
48
|
+
.allotment-module_splitView__L-yRc.allotment-module_horizontal__7doS8
|
|
49
|
+
> .allotment-module_splitViewContainer__rQnVa
|
|
50
|
+
> .allotment-module_splitViewView__MGZ6O {
|
|
42
51
|
height: 100%;
|
|
43
52
|
}
|
|
44
53
|
|
|
@@ -129,7 +138,8 @@
|
|
|
129
138
|
height: var(--sash-size);
|
|
130
139
|
}
|
|
131
140
|
|
|
132
|
-
.sash-module_sash__K-9lB:not(.sash-module_disabled__Hm-wx)
|
|
141
|
+
.sash-module_sash__K-9lB:not(.sash-module_disabled__Hm-wx)
|
|
142
|
+
> .sash-module_orthogonal-drag-handle__Yii2- {
|
|
133
143
|
content: " ";
|
|
134
144
|
height: calc(var(--sash-size) * 2);
|
|
135
145
|
width: calc(var(--sash-size) * 2);
|
|
@@ -139,36 +149,48 @@
|
|
|
139
149
|
position: absolute;
|
|
140
150
|
}
|
|
141
151
|
|
|
142
|
-
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-north__f7Noe:not(
|
|
152
|
+
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-north__f7Noe:not(
|
|
153
|
+
.sash-module_disabled__Hm-wx
|
|
154
|
+
)
|
|
143
155
|
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk,
|
|
144
|
-
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-south__6ZrFC:not(
|
|
156
|
+
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-south__6ZrFC:not(
|
|
157
|
+
.sash-module_disabled__Hm-wx
|
|
158
|
+
)
|
|
145
159
|
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R {
|
|
146
160
|
cursor: nwse-resize;
|
|
147
161
|
}
|
|
148
162
|
|
|
149
|
-
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-north__f7Noe:not(
|
|
163
|
+
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-north__f7Noe:not(
|
|
164
|
+
.sash-module_disabled__Hm-wx
|
|
165
|
+
)
|
|
150
166
|
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R,
|
|
151
|
-
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-south__6ZrFC:not(
|
|
167
|
+
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw.sash-module_orthogonal-edge-south__6ZrFC:not(
|
|
168
|
+
.sash-module_disabled__Hm-wx
|
|
169
|
+
)
|
|
152
170
|
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk {
|
|
153
171
|
cursor: nesw-resize;
|
|
154
172
|
}
|
|
155
173
|
|
|
156
|
-
.sash-module_sash__K-9lB.sash-module_vertical__pB-rs
|
|
174
|
+
.sash-module_sash__K-9lB.sash-module_vertical__pB-rs
|
|
175
|
+
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk {
|
|
157
176
|
left: calc(var(--sash-size) * -0.5);
|
|
158
177
|
top: calc(var(--sash-size) * -1);
|
|
159
178
|
}
|
|
160
179
|
|
|
161
|
-
.sash-module_sash__K-9lB.sash-module_vertical__pB-rs
|
|
180
|
+
.sash-module_sash__K-9lB.sash-module_vertical__pB-rs
|
|
181
|
+
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R {
|
|
162
182
|
left: calc(var(--sash-size) * -0.5);
|
|
163
183
|
bottom: calc(var(--sash-size) * -1);
|
|
164
184
|
}
|
|
165
185
|
|
|
166
|
-
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw
|
|
186
|
+
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw
|
|
187
|
+
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_start__uZEDk {
|
|
167
188
|
top: calc(var(--sash-size) * -0.5);
|
|
168
189
|
left: calc(var(--sash-size) * -1);
|
|
169
190
|
}
|
|
170
191
|
|
|
171
|
-
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw
|
|
192
|
+
.sash-module_sash__K-9lB.sash-module_horizontal__kFbiw
|
|
193
|
+
> .sash-module_orthogonal-drag-handle__Yii2-.sash-module_end__0TP-R {
|
|
172
194
|
top: calc(var(--sash-size) * -0.5);
|
|
173
195
|
right: calc(var(--sash-size) * -1);
|
|
174
196
|
}
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ export const AssistantCardMore = React.forwardRef<
|
|
|
27
27
|
HTMLButtonElement,
|
|
28
28
|
AssistantCardMore
|
|
29
29
|
>(({ ...props }, ref) => {
|
|
30
|
-
return <CardActionButton ref={ref} icon={MoreIcon} {...props} />;
|
|
30
|
+
return <CardActionButton size="mini" ref={ref} icon={MoreIcon} {...props} />;
|
|
31
31
|
});
|
|
32
32
|
AssistantCardMore.displayName = "AssistantCardMore";
|
|
33
33
|
|
|
@@ -34,15 +34,9 @@ export const BUTTON_VARIANTS = [
|
|
|
34
34
|
|
|
35
35
|
export type ButtonVariantType = (typeof BUTTON_VARIANTS)[number];
|
|
36
36
|
|
|
37
|
-
export const BUTTON_SIZES = ["
|
|
37
|
+
export const BUTTON_SIZES = ["xmini", "mini", "xs", "sm", "md"] as const;
|
|
38
38
|
export type ButtonSizeType = (typeof BUTTON_SIZES)[number];
|
|
39
39
|
|
|
40
|
-
// Icon-only button sizes (fixed width, labels hidden)
|
|
41
|
-
export const ICON_ONLY_SIZES = ["icon-xs", "icon"] as const;
|
|
42
|
-
|
|
43
|
-
// Small button sizes that use xs spinner size
|
|
44
|
-
export const SMALL_BUTTON_SIZES = ["icon-xs", "icon", "xmini", "mini"] as const;
|
|
45
|
-
|
|
46
40
|
// Define button styling with cva
|
|
47
41
|
const buttonVariants = cva(
|
|
48
42
|
cn(
|
|
@@ -147,17 +141,13 @@ const buttonVariants = cva(
|
|
|
147
141
|
),
|
|
148
142
|
},
|
|
149
143
|
size: {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
xmini: "s-h-6 s-px-1.5 s-label-xs s-gap-1 s-shrink-0",
|
|
153
|
-
mini: "s-h-7 s-px-2 s-label-xs s-gap-1.5 s-shrink-0",
|
|
144
|
+
xmini: "s-h-6 s-w-6 s-label-xs s-gap-1 s-shrink-0",
|
|
145
|
+
mini: "s-h-7 s-w-7 s-label-xs s-gap-1.5 s-shrink-0",
|
|
154
146
|
xs: "s-h-7 s-px-2.5 s-label-xs s-gap-1.5 s-shrink-0",
|
|
155
147
|
sm: "s-h-9 s-px-3 s-label-sm s-gap-2 s-shrink-0",
|
|
156
148
|
md: "s-h-12 s-px-4 s-py-2 s-label-base s-gap-2.5 s-shrink-0",
|
|
157
149
|
},
|
|
158
150
|
rounded: {
|
|
159
|
-
"icon-xs": "s-rounded-lg",
|
|
160
|
-
icon: "s-rounded-lg",
|
|
161
151
|
xmini: "s-rounded-lg",
|
|
162
152
|
mini: "s-rounded-lg",
|
|
163
153
|
xs: "s-rounded-lg",
|
|
@@ -177,10 +167,8 @@ const buttonVariants = cva(
|
|
|
177
167
|
const labelVariants = cva("", {
|
|
178
168
|
variants: {
|
|
179
169
|
size: {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
xmini: "s-label-xs",
|
|
183
|
-
mini: "s-label-xs",
|
|
170
|
+
xmini: "s-label-xs s-hidden",
|
|
171
|
+
mini: "s-label-xs s-hidden",
|
|
184
172
|
xs: "s-label-xs",
|
|
185
173
|
sm: "s-label-sm",
|
|
186
174
|
md: "s-label-base",
|
|
@@ -258,8 +246,6 @@ type IconSizeType = "xs" | "sm" | "md";
|
|
|
258
246
|
type CounterSizeType = "xs" | "sm" | "md";
|
|
259
247
|
|
|
260
248
|
export const ICON_SIZE_MAP: Record<ButtonSizeType, IconSizeType> = {
|
|
261
|
-
"icon-xs": "xs",
|
|
262
|
-
icon: "sm",
|
|
263
249
|
xmini: "xs",
|
|
264
250
|
mini: "sm",
|
|
265
251
|
xs: "xs",
|
|
@@ -268,8 +254,6 @@ export const ICON_SIZE_MAP: Record<ButtonSizeType, IconSizeType> = {
|
|
|
268
254
|
};
|
|
269
255
|
|
|
270
256
|
const COUNTER_SIZE_MAP: Record<ButtonSizeType, CounterSizeType> = {
|
|
271
|
-
"icon-xs": "xs",
|
|
272
|
-
icon: "xs",
|
|
273
257
|
xmini: "xs",
|
|
274
258
|
mini: "xs",
|
|
275
259
|
xs: "xs",
|
|
@@ -289,19 +273,19 @@ type CommonButtonProps = Omit<MetaButtonProps, "children"> &
|
|
|
289
273
|
isRounded?: boolean;
|
|
290
274
|
};
|
|
291
275
|
|
|
292
|
-
export type ButtonProps = CommonButtonProps & {
|
|
293
|
-
size?: ButtonSizeType;
|
|
294
|
-
icon?: React.ComponentType;
|
|
295
|
-
label?: string;
|
|
296
|
-
};
|
|
297
|
-
|
|
298
276
|
export type MiniButtonProps = CommonButtonProps & {
|
|
299
277
|
size: "mini";
|
|
300
278
|
icon: React.ComponentType;
|
|
301
279
|
label?: never;
|
|
302
280
|
};
|
|
303
281
|
|
|
304
|
-
export type RegularButtonProps =
|
|
282
|
+
export type RegularButtonProps = CommonButtonProps & {
|
|
283
|
+
size?: Exclude<ButtonSizeType, "mini">;
|
|
284
|
+
icon?: React.ComponentType;
|
|
285
|
+
label?: string;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export type ButtonProps = MiniButtonProps | RegularButtonProps;
|
|
305
289
|
|
|
306
290
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
307
291
|
(
|
|
@@ -368,11 +352,12 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
368
352
|
<div
|
|
369
353
|
className={cn(
|
|
370
354
|
"-s-mx-0.5",
|
|
371
|
-
|
|
355
|
+
size === "mini" && "s-w-5 s-px-0.5",
|
|
356
|
+
size === "xmini" && "s-w-5 s-px-0.5"
|
|
372
357
|
)}
|
|
373
358
|
>
|
|
374
359
|
<Spinner
|
|
375
|
-
size={
|
|
360
|
+
size={size === "mini" || size === "xmini" ? "xs" : iconSize}
|
|
376
361
|
variant={(variant && spinnerVariantsMap[variant]) || "gray400"}
|
|
377
362
|
/>
|
|
378
363
|
</div>
|
|
@@ -4,10 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import { cn } from "@sparkle/lib/utils";
|
|
5
5
|
|
|
6
6
|
import type { ButtonProps, ButtonSizeType, ButtonVariantType } from "./Button";
|
|
7
|
-
import { Button
|
|
8
|
-
|
|
9
|
-
// Sizes that must be set per-item in ButtonGroup (not at group level)
|
|
10
|
-
const PER_ITEM_SIZES = ["mini", ...ICON_ONLY_SIZES] as const;
|
|
7
|
+
import { Button } from "./Button";
|
|
11
8
|
import type { DropdownMenuItemProps } from "./Dropdown";
|
|
12
9
|
import {
|
|
13
10
|
DropdownMenu,
|
|
@@ -95,9 +92,9 @@ export interface ButtonGroupProps
|
|
|
95
92
|
*/
|
|
96
93
|
variant?: ButtonGroupVariantType;
|
|
97
94
|
/**
|
|
98
|
-
* Size to apply to all buttons in the group.
|
|
95
|
+
* Size to apply to all buttons in the group. Mini buttons must opt-in per item.
|
|
99
96
|
*/
|
|
100
|
-
size?: Exclude<ButtonSizeType, "mini"
|
|
97
|
+
size?: Exclude<ButtonSizeType, "mini">;
|
|
101
98
|
/**
|
|
102
99
|
* Whether every button should be disabled.
|
|
103
100
|
*/
|
|
@@ -171,10 +168,10 @@ const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
|
|
|
171
168
|
if (item.type === "button") {
|
|
172
169
|
const nextVariant = sanitizeVariant(variant ?? item.props.variant);
|
|
173
170
|
const rawSize = size ?? item.props.size;
|
|
174
|
-
const nextSize: Exclude<ButtonSizeType, "mini"
|
|
175
|
-
|
|
171
|
+
const nextSize: Exclude<ButtonSizeType, "mini"> | undefined =
|
|
172
|
+
rawSize === "mini"
|
|
176
173
|
? undefined
|
|
177
|
-
: (rawSize as Exclude<ButtonSizeType, "mini"
|
|
174
|
+
: (rawSize as Exclude<ButtonSizeType, "mini"> | undefined);
|
|
178
175
|
|
|
179
176
|
return (
|
|
180
177
|
<Button
|
package/src/components/Card.tsx
CHANGED
|
@@ -225,20 +225,15 @@ const CardActions = React.forwardRef<
|
|
|
225
225
|
|
|
226
226
|
CardActions.displayName = "CardActions";
|
|
227
227
|
|
|
228
|
-
export type CardActionButtonProps = Omit<MiniButtonProps, "size"> & {
|
|
229
|
-
size?: "icon" | "icon-xs";
|
|
230
|
-
};
|
|
231
|
-
|
|
232
228
|
export const CardActionButton = React.forwardRef<
|
|
233
229
|
HTMLButtonElement,
|
|
234
|
-
|
|
235
|
-
>(({ className, variant = "outline", icon = XMarkIcon,
|
|
230
|
+
MiniButtonProps
|
|
231
|
+
>(({ className, variant = "outline", icon = XMarkIcon, ...props }, ref) => {
|
|
236
232
|
return (
|
|
237
233
|
<Button
|
|
238
234
|
ref={ref}
|
|
239
235
|
variant={variant}
|
|
240
236
|
icon={icon}
|
|
241
|
-
size={size}
|
|
242
237
|
className={className}
|
|
243
238
|
{...props}
|
|
244
239
|
/>
|
|
@@ -5,9 +5,9 @@ import { ImageZoomDialog } from "@sparkle/components/ImageZoomDialog";
|
|
|
5
5
|
import { cn } from "@sparkle/lib/utils";
|
|
6
6
|
|
|
7
7
|
const SIZE_CLASSES = {
|
|
8
|
-
sm: "s-h-24 s-w-24",
|
|
9
|
-
md: "s-h-48 s-w-48",
|
|
10
|
-
lg: "s-h-80 s-w-80",
|
|
8
|
+
sm: "s-relative s-h-24 s-w-24",
|
|
9
|
+
md: "s-relative s-h-48 s-w-48",
|
|
10
|
+
lg: "s-relative s-h-80 s-w-80",
|
|
11
11
|
} as const;
|
|
12
12
|
|
|
13
13
|
type InteractiveImageGridSize = keyof typeof SIZE_CLASSES;
|
|
@@ -101,7 +101,7 @@ function InteractiveImageGrid({
|
|
|
101
101
|
downloadUrl={image.downloadUrl}
|
|
102
102
|
isLoading={image.isLoading}
|
|
103
103
|
onClick={() => setCurrentImageIndex(idx)}
|
|
104
|
-
variant="
|
|
104
|
+
variant="standalone"
|
|
105
105
|
titlePosition="center"
|
|
106
106
|
manageZoomDialog={false}
|
|
107
107
|
/>
|
|
@@ -167,7 +167,7 @@ const NavigationListItem = React.forwardRef<
|
|
|
167
167
|
{icon && <Icon visual={icon} size="xs" className="s-m-0.5" />}
|
|
168
168
|
{avatar}
|
|
169
169
|
{label && (
|
|
170
|
-
<span className="s-grow s-overflow-hidden s-text-ellipsis s-whitespace-nowrap group-
|
|
170
|
+
<span className="s-grow s-overflow-hidden s-text-ellipsis s-whitespace-nowrap group-focus-within/menu-item:s-pr-8 group-hover/menu-item:s-pr-8 group-data-[selected=true]/menu-item:s-pr-8">
|
|
171
171
|
{label}
|
|
172
172
|
</span>
|
|
173
173
|
)}
|
|
@@ -179,7 +179,7 @@ const NavigationListItem = React.forwardRef<
|
|
|
179
179
|
className={cn(
|
|
180
180
|
"s-flex-shrink-0 s-translate-x-0.5",
|
|
181
181
|
moreMenu &&
|
|
182
|
-
"group-
|
|
182
|
+
"group-focus-within/menu-item:s-hidden group-hover/menu-item:s-hidden"
|
|
183
183
|
)}
|
|
184
184
|
/>
|
|
185
185
|
)}
|
|
@@ -188,7 +188,7 @@ const NavigationListItem = React.forwardRef<
|
|
|
188
188
|
className={cn(
|
|
189
189
|
"s-heading-xs s-flex s-flex-shrink-0 s-items-center s-justify-center s-rounded-full",
|
|
190
190
|
moreMenu &&
|
|
191
|
-
"group-
|
|
191
|
+
"group-focus-within/menu-item:s-hidden group-hover/menu-item:s-hidden",
|
|
192
192
|
getStatusDotColor()
|
|
193
193
|
)}
|
|
194
194
|
/>
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import type { ButtonProps, ButtonSizeType } from "@sparkle/components/Button";
|
|
4
|
+
import { Button } from "@sparkle/components/Button";
|
|
5
|
+
import { MicIcon, SquareIcon } from "@sparkle/icons/app";
|
|
6
|
+
import { cn } from "@sparkle/lib/utils";
|
|
7
|
+
|
|
8
|
+
const DEFAULT_PRESS_DELAY_MS = 150;
|
|
9
|
+
const VOICE_LEVEL_BASE_HEIGHTS = [
|
|
10
|
+
22, 33, 18, 64, 98, 56, 6, 34, 76, 46, 12, 22,
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
export type VoicePickerStatus =
|
|
14
|
+
| "idle"
|
|
15
|
+
| "authorizing_microphone"
|
|
16
|
+
| "recording"
|
|
17
|
+
| "transcribing";
|
|
18
|
+
|
|
19
|
+
type VoicePickerInteractionMode = "hold" | "click";
|
|
20
|
+
|
|
21
|
+
export interface VoicePickerProps {
|
|
22
|
+
status: VoicePickerStatus;
|
|
23
|
+
level: number;
|
|
24
|
+
elapsedSeconds: number;
|
|
25
|
+
onRecordStart: () => void | Promise<void>;
|
|
26
|
+
onRecordStop: () => void | Promise<void>;
|
|
27
|
+
size?: Exclude<ButtonSizeType, "xmini" | "mini">;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
showStopLabel?: boolean;
|
|
30
|
+
pressDelayMs?: number;
|
|
31
|
+
buttonProps?: Omit<
|
|
32
|
+
ButtonProps,
|
|
33
|
+
"icon" | "label" | "variant" | "isLoading" | "disabled" | "size"
|
|
34
|
+
>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function VoicePicker({
|
|
38
|
+
status,
|
|
39
|
+
level,
|
|
40
|
+
elapsedSeconds,
|
|
41
|
+
onRecordStart,
|
|
42
|
+
onRecordStop,
|
|
43
|
+
size = "xs",
|
|
44
|
+
disabled = false,
|
|
45
|
+
showStopLabel = false,
|
|
46
|
+
pressDelayMs = DEFAULT_PRESS_DELAY_MS,
|
|
47
|
+
buttonProps,
|
|
48
|
+
}: VoicePickerProps): React.ReactElement {
|
|
49
|
+
const [interactionMode, setInteractionMode] =
|
|
50
|
+
React.useState<VoicePickerInteractionMode>("hold");
|
|
51
|
+
const pressStartRef = React.useRef<number | null>(null);
|
|
52
|
+
const pressTimeoutRef = React.useRef<number | null>(null);
|
|
53
|
+
|
|
54
|
+
const isRecording = status === "recording";
|
|
55
|
+
const isTranscribing = status === "transcribing";
|
|
56
|
+
const isLoading =
|
|
57
|
+
status === "transcribing" || status === "authorizing_microphone";
|
|
58
|
+
const shouldShowStop = isRecording && interactionMode === "click";
|
|
59
|
+
|
|
60
|
+
function clearPressTimeout(): void {
|
|
61
|
+
if (pressTimeoutRef.current !== null) {
|
|
62
|
+
window.clearTimeout(pressTimeoutRef.current);
|
|
63
|
+
pressTimeoutRef.current = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function stopEvent(event: React.SyntheticEvent): void {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
event.stopPropagation();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function handlePointerDown(
|
|
73
|
+
event: React.PointerEvent<HTMLButtonElement>
|
|
74
|
+
): Promise<void> {
|
|
75
|
+
buttonProps?.onPointerDown?.(event);
|
|
76
|
+
if (event.defaultPrevented) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
stopEvent(event);
|
|
81
|
+
|
|
82
|
+
if (disabled) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
pressStartRef.current = Date.now();
|
|
87
|
+
|
|
88
|
+
clearPressTimeout();
|
|
89
|
+
pressTimeoutRef.current = window.setTimeout(async () => {
|
|
90
|
+
if (pressStartRef.current !== null) {
|
|
91
|
+
setInteractionMode("hold");
|
|
92
|
+
if (status === "idle") {
|
|
93
|
+
await onRecordStart();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}, pressDelayMs);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function handlePointerUp(
|
|
100
|
+
event: React.PointerEvent<HTMLButtonElement>
|
|
101
|
+
): Promise<void> {
|
|
102
|
+
buttonProps?.onPointerUp?.(event);
|
|
103
|
+
if (event.defaultPrevented) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
stopEvent(event);
|
|
108
|
+
|
|
109
|
+
if (disabled) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const start = pressStartRef.current;
|
|
114
|
+
clearPressTimeout();
|
|
115
|
+
pressStartRef.current = null;
|
|
116
|
+
|
|
117
|
+
const duration =
|
|
118
|
+
start === null ? Number.POSITIVE_INFINITY : Date.now() - start;
|
|
119
|
+
|
|
120
|
+
if (duration < pressDelayMs) {
|
|
121
|
+
setInteractionMode("click");
|
|
122
|
+
if (status === "idle") {
|
|
123
|
+
await onRecordStart();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
await onRecordStop();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (status === "recording") {
|
|
131
|
+
await onRecordStop();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function handlePointerLeave(
|
|
136
|
+
event: React.PointerEvent<HTMLButtonElement>
|
|
137
|
+
): Promise<void> {
|
|
138
|
+
buttonProps?.onPointerLeave?.(event);
|
|
139
|
+
if (event.defaultPrevented) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
stopEvent(event);
|
|
144
|
+
|
|
145
|
+
if (disabled || interactionMode !== "hold") {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (status === "recording") {
|
|
149
|
+
await onRecordStop();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function handleClick(
|
|
154
|
+
event: React.MouseEvent<HTMLButtonElement>
|
|
155
|
+
): Promise<void> {
|
|
156
|
+
buttonProps?.onClick?.(event);
|
|
157
|
+
if (event.defaultPrevented) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
stopEvent(event);
|
|
162
|
+
|
|
163
|
+
if (disabled || interactionMode !== "click") {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (status === "recording") {
|
|
167
|
+
await onRecordStop();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const icon = shouldShowStop ? SquareIcon : MicIcon;
|
|
172
|
+
const variant = shouldShowStop ? "highlight" : "ghost-secondary";
|
|
173
|
+
const label = shouldShowStop && showStopLabel ? "Stop" : undefined;
|
|
174
|
+
const tooltip = computeTooltip(interactionMode, isRecording, isTranscribing);
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<>
|
|
178
|
+
<div
|
|
179
|
+
className={cn(
|
|
180
|
+
"s-duration-600 s-flex s-items-center s-justify-end s-gap-2 s-overflow-hidden s-px-2 s-transition-all s-ease-in-out",
|
|
181
|
+
isRecording ? "s-opacity-100" : "s-hidden"
|
|
182
|
+
)}
|
|
183
|
+
>
|
|
184
|
+
<div className="s-heading-xs s-font-mono">
|
|
185
|
+
{formatTime(elapsedSeconds)}
|
|
186
|
+
</div>
|
|
187
|
+
<VoiceLevelDisplay level={level} />
|
|
188
|
+
</div>
|
|
189
|
+
<Button
|
|
190
|
+
{...buttonProps}
|
|
191
|
+
size={size}
|
|
192
|
+
icon={icon}
|
|
193
|
+
isLoading={isLoading}
|
|
194
|
+
variant={variant}
|
|
195
|
+
tooltip={tooltip}
|
|
196
|
+
label={label}
|
|
197
|
+
disabled={disabled}
|
|
198
|
+
onPointerDown={handlePointerDown}
|
|
199
|
+
onPointerUp={handlePointerUp}
|
|
200
|
+
onPointerLeave={handlePointerLeave}
|
|
201
|
+
onClick={handleClick}
|
|
202
|
+
/>
|
|
203
|
+
</>
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface VoiceLevelDisplayProps {
|
|
208
|
+
level: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function VoiceLevelDisplay({
|
|
212
|
+
level,
|
|
213
|
+
}: VoiceLevelDisplayProps): React.ReactElement {
|
|
214
|
+
const clampedLevel = Math.max(0, Math.min(1, level * 1.2));
|
|
215
|
+
const easedLevel = Math.pow(clampedLevel, 0.8);
|
|
216
|
+
|
|
217
|
+
const minHeights = VOICE_LEVEL_BASE_HEIGHTS.map((height) =>
|
|
218
|
+
Math.max(6, Math.round(height * 0.3))
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const heights = VOICE_LEVEL_BASE_HEIGHTS.map((height, index) =>
|
|
222
|
+
Math.max(
|
|
223
|
+
1,
|
|
224
|
+
Math.min(
|
|
225
|
+
100,
|
|
226
|
+
Math.round(
|
|
227
|
+
minHeights[index] + (height - minHeights[index]) * easedLevel
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<div className="s-flex s-h-5 s-items-center s-gap-0.5">
|
|
235
|
+
{heights.map((height, index) => (
|
|
236
|
+
<div
|
|
237
|
+
key={index}
|
|
238
|
+
className="s-min-h-1 s-w-0.5 s-rounded-full s-bg-muted-foreground s-transition-all s-duration-150 s-ease-out"
|
|
239
|
+
style={{ height: `${height}%` }}
|
|
240
|
+
/>
|
|
241
|
+
))}
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function computeTooltip(
|
|
247
|
+
mode: VoicePickerInteractionMode,
|
|
248
|
+
isRecording: boolean,
|
|
249
|
+
isTranscribing: boolean
|
|
250
|
+
): string {
|
|
251
|
+
if (isTranscribing) {
|
|
252
|
+
return "Transcribing...";
|
|
253
|
+
}
|
|
254
|
+
if (mode === "hold" && isRecording) {
|
|
255
|
+
return "Release to stop";
|
|
256
|
+
}
|
|
257
|
+
if (isRecording) {
|
|
258
|
+
return "Stop recording";
|
|
259
|
+
}
|
|
260
|
+
return "Click, or Press & Hold to record";
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function formatTime(seconds: number): string {
|
|
264
|
+
const minutes = Math.floor(seconds / 60);
|
|
265
|
+
const remainingSeconds = seconds % 60;
|
|
266
|
+
return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`;
|
|
267
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -221,3 +221,5 @@ export {
|
|
|
221
221
|
export { Tree } from "./Tree";
|
|
222
222
|
export { TypingAnimation } from "./TypingAnimation";
|
|
223
223
|
export { ValueCard } from "./ValueCard";
|
|
224
|
+
export type { VoicePickerProps, VoicePickerStatus } from "./VoicePicker";
|
|
225
|
+
export { VoicePicker } from "./VoicePicker";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { SVGProps } from "react";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
const SvgUkg = (props: SVGProps<SVGSVGElement>) => (
|
|
4
|
+
<svg
|
|
5
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
6
|
+
width="1em"
|
|
7
|
+
height="1em"
|
|
8
|
+
fill="none"
|
|
9
|
+
viewBox="0 0 24 24"
|
|
10
|
+
{...props}
|
|
11
|
+
>
|
|
12
|
+
<path
|
|
13
|
+
fill="#2CD5C4"
|
|
14
|
+
d="M6.937 4.467A2.469 2.469 0 1 1 2 4.47a2.469 2.469 0 0 1 4.937-.003ZM22 4.467A2.46 2.46 0 1 1 19.55 2 2.47 2.47 0 0 1 22 4.467Z"
|
|
15
|
+
/>
|
|
16
|
+
<path
|
|
17
|
+
fill="#005857"
|
|
18
|
+
d="M12.02 22c-2.657-.002-5.205-.976-7.084-2.709-1.878-1.733-2.934-4.083-2.934-6.533v-1.466a2.02 2.02 0 0 1 .152-.857c.113-.273.285-.522.504-.733.22-.21.484-.378.776-.492a2.529 2.529 0 0 1 1.845 0c.291.114.555.282.775.492.22.21.391.46.504.733.113.274.165.565.152.857v1.523c0 2.685 1.727 4.874 5.29 4.874 3.314 0 5.288-2.19 5.288-4.874v-1.523c-.018-.295.03-.59.14-.867.111-.278.282-.531.502-.746a2.37 2.37 0 0 1 .78-.502 2.53 2.53 0 0 1 1.864 0c.294.117.56.288.78.502.22.215.391.468.502.745.11.278.158.573.14.868v1.466a8.57 8.57 0 0 1-.746 3.534 9.175 9.175 0 0 1-2.162 3c-.928.858-2.03 1.538-3.245 2.002a10.71 10.71 0 0 1-3.83.701"
|
|
19
|
+
/>
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
export default SvgUkg;
|
|
@@ -59,6 +59,7 @@ export { default as SnowflakeLogo } from "./Snowflake";
|
|
|
59
59
|
export { default as StripeLogo } from "./Stripe";
|
|
60
60
|
export { default as SupabaseLogo } from "./Supabase";
|
|
61
61
|
export { default as TogetheraiLogo } from "./Togetherai";
|
|
62
|
+
export { default as UkgLogo } from "./Ukg";
|
|
62
63
|
export { default as ValTownLogo } from "./ValTown";
|
|
63
64
|
export { default as VantaLogo } from "./Vanta";
|
|
64
65
|
export { default as ZapierLogo } from "./Zapier";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M6.9373 4.46699C6.93764 4.95539 6.7931 5.43291 6.52197 5.83914C6.25084 6.24538 5.86531 6.56205 5.41415 6.74911C4.963 6.93617 4.46649 6.9852 3.98746 6.89001C3.50843 6.79481 3.0684 6.55966 2.72305 6.21431C2.3777 5.86896 2.14255 5.42893 2.04735 4.9499C1.95215 4.47087 2.00119 3.97436 2.18824 3.52321C2.3753 3.07205 2.69198 2.68652 3.09821 2.41539C3.50444 2.14426 3.98197 1.99972 4.47037 2.00006C5.1245 2.00052 5.75171 2.26057 6.21425 2.72311C6.67679 3.18565 6.93684 3.81286 6.9373 4.46699Z" fill="#2CD5C4"/>
|
|
3
|
+
<path d="M22 4.46695C21.9986 4.95365 21.8529 5.429 21.5813 5.83287C21.3097 6.23674 20.9245 6.55097 20.4742 6.73581C20.024 6.92064 19.529 6.96777 19.052 6.87124C18.575 6.7747 18.1373 6.53884 17.7944 6.19349C17.4514 5.84815 17.2186 5.40883 17.1254 4.93114C17.0322 4.45345 17.0828 3.95885 17.2708 3.50991C17.4588 3.06098 17.7757 2.6779 18.1814 2.40913C18.5872 2.14036 19.0636 1.99798 19.5503 2.00002C20.2013 2.00545 20.8238 2.26765 21.2825 2.7296C21.7413 3.19156 21.9991 3.81592 22 4.46695Z" fill="#2CD5C4"/>
|
|
4
|
+
<path d="M12.0209 22C9.36334 21.9983 6.8152 21.0239 4.93649 19.291C3.05778 17.5581 2.00221 15.2084 2.00174 12.7583V11.292C1.98955 10.9999 2.04141 10.7086 2.15424 10.4354C2.26706 10.1622 2.43852 9.9129 2.65835 9.70228C2.87818 9.49167 3.14185 9.32412 3.43358 9.20968C3.7253 9.09523 4.03908 9.03624 4.35612 9.03624C4.67316 9.03624 4.98694 9.09523 5.27867 9.20968C5.57039 9.32412 5.83407 9.49167 6.05389 9.70228C6.27372 9.9129 6.44518 10.1622 6.558 10.4354C6.67083 10.7086 6.72269 10.9999 6.7105 11.292V12.8146C6.7105 15.4996 8.43704 17.6895 12 17.6895C15.3136 17.6895 17.2878 15.4996 17.2878 12.8146V11.292C17.2703 10.997 17.3183 10.7018 17.4288 10.4245C17.5392 10.1472 17.7098 9.89355 17.9301 9.67905C18.1505 9.46456 18.4159 9.29372 18.7103 9.17697C19.0046 9.06021 19.3217 9 19.6421 9C19.9626 9 20.2796 9.06021 20.574 9.17697C20.8683 9.29372 21.1338 9.46456 21.3541 9.67905C21.5745 9.89355 21.7451 10.1472 21.8555 10.4245C21.966 10.7018 22.0139 10.997 21.9965 11.292V12.7583C22.0027 13.9702 21.749 15.1713 21.2498 16.2924C20.7507 17.4136 20.0161 18.4327 19.0881 19.2911C18.1602 20.1496 17.0574 20.8304 15.843 21.2945C14.6287 21.7585 13.3268 21.9967 12.0122 21.9952" fill="#005857"/>
|
|
5
|
+
</svg>
|