@heyramzi/ui 7.0.0 → 8.0.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.
- package/COMPONENTS.md +28 -17
- package/README.md +5 -1
- package/package.json +25 -15
- package/scripts/sync-shadcn.mjs +17 -13
- package/scripts/sync-transitions.mjs +11 -11
- package/src/ai/ai-button/AiButton.svelte +86 -0
- package/src/ai/ai-button/index.ts +4 -0
- package/src/ai/confirmation/Confirmation.svelte +8 -8
- package/src/ai/confirmation/confirmation-context.svelte.ts +2 -2
- package/src/ai/generation-progress/GenerationProgress.svelte +354 -0
- package/src/ai/generation-progress/index.ts +7 -0
- package/src/ai/index.ts +16 -6
- package/src/ai/prompt-input/PromptInput.svelte +19 -1
- package/src/ai/prompt-input/PromptInputSubmit.svelte +9 -3
- package/src/ai/reasoning/Reasoning.svelte +11 -8
- package/src/ambient.d.ts +4 -0
- package/src/animations/README.md +14 -14
- package/src/animations/index.css +3 -14
- package/src/animations/upstream-coverage.test.ts +1 -1
- package/src/components/copy/clipboard.test.ts +206 -0
- package/src/components/copy/clipboard.ts +49 -0
- package/src/components/copy/copied.svelte.ts +39 -0
- package/src/components/copy/copy-button.svelte +175 -0
- package/src/components/copy/copy-button.test.ts +110 -0
- package/src/components/copy/index.ts +3 -0
- package/src/components/data-table/data-table.test.ts +134 -0
- package/src/components/data-table/data-table.ts +77 -0
- package/src/components/data-table/index.ts +20 -0
- package/src/components/data-table/infinite-scroll.svelte +69 -0
- package/src/components/data-table/pagination.svelte +62 -0
- package/src/components/data-table/row-arrow.svelte +28 -0
- package/src/components/data-table/row-context-menu.svelte +106 -0
- package/src/components/data-table/row-context-menu.test.ts +18 -0
- package/src/components/data-table/sortable-head.svelte +56 -0
- package/src/components/data-table/table-skeleton.svelte +83 -0
- package/src/components/hold-to-confirm/hold-to-confirm.svelte +232 -0
- package/src/components/hold-to-confirm/index.ts +1 -0
- package/src/components/icon/icon.svelte +23 -0
- package/src/components/icon/index.ts +1 -0
- package/src/components/language-flag/index.ts +1 -0
- package/src/components/language-flag/language-flag.svelte +60 -0
- package/src/components/list-page/detail-empty.svelte +50 -0
- package/src/components/list-page/detail-header.svelte +107 -0
- package/src/components/list-page/detail-panel.svelte +90 -0
- package/src/components/list-page/detail-row.svelte +36 -0
- package/src/components/list-page/detail-stack.svelte +33 -0
- package/src/components/list-page/empty-state.svelte +91 -0
- package/src/components/list-page/filter-item.svelte +49 -0
- package/src/components/list-page/filter-popover.svelte +88 -0
- package/src/components/list-page/filter-section.ts +12 -0
- package/src/components/list-page/grouped-list.svelte +116 -0
- package/src/components/list-page/index.ts +28 -0
- package/src/components/list-page/list-page-shell.svelte +195 -0
- package/src/components/list-page/list-table.ts +19 -0
- package/src/components/list-page/master-detail.svelte +206 -0
- package/src/components/list-page/master-detail.test.ts +37 -0
- package/src/components/list-page/notice-bar.svelte +68 -0
- package/src/components/list-page/prev-next.svelte +104 -0
- package/src/components/list-page/queue-rail.ts +25 -0
- package/src/components/list-page/rail-body.svelte +29 -0
- package/src/components/list-page/rail-empty.svelte +51 -0
- package/src/components/list-page/rail-head.svelte +49 -0
- package/src/components/list-page/rail-row.svelte +163 -0
- package/src/components/list-page/section-host.ts +24 -0
- package/src/components/list-page/section-label.svelte +39 -0
- package/src/components/list-page/step.test.ts +21 -0
- package/src/components/list-page/step.ts +10 -0
- package/src/components/list-page/toolbar-search.svelte +63 -0
- package/src/components/list-page/toolbar-trigger.ts +23 -0
- package/src/components/list-page/types.ts +1 -0
- package/src/components/locale-switch/index.ts +1 -0
- package/src/components/locale-switch/locale-switch.svelte +59 -0
- package/src/components/mark/index.ts +1 -0
- package/src/components/mark/mark.svelte +70 -0
- package/src/components/open-in/index.ts +6 -0
- package/src/components/open-in/open-in.svelte +106 -0
- package/src/components/picker/index.ts +4 -0
- package/src/components/picker/mark-picker.svelte +84 -0
- package/src/components/picker/picker.svelte +143 -0
- package/src/components/picker/trigger.ts +42 -0
- package/src/components/picker/types.ts +26 -0
- package/src/components/segmented/animated-tabs.svelte +175 -0
- package/src/components/segmented/collapse.test.ts +49 -0
- package/src/components/segmented/collapse.ts +39 -0
- package/src/components/segmented/index.ts +41 -0
- package/src/components/segmented/section-runs.svelte +79 -0
- package/src/components/segmented/segment.svelte +106 -0
- package/src/components/segmented/segmented-filter.svelte +125 -0
- package/src/components/segmented/segmented-nav.svelte +82 -0
- package/src/components/segmented/segmented-overflow.svelte +85 -0
- package/src/components/segmented/segmented-track.svelte +181 -0
- package/src/components/segmented/segmented.test.ts +20 -0
- package/src/components/segmented/segmented.ts +80 -0
- package/src/components/star-rating-input/index.ts +9 -0
- package/src/components/star-rating-input/star-rating-input.svelte +256 -0
- package/src/components/svg/index.ts +1 -0
- package/src/components/svg/svg.svelte +9 -0
- package/src/effects/border-beam/BorderBeam.svelte +1 -1
- package/src/effects/image-comparison/ImageComparison.css +42 -8
- package/src/effects/image-comparison/ImageComparison.svelte +138 -21
- package/src/effects/image-comparison/compare.test.ts +17 -0
- package/src/effects/image-comparison/compare.ts +5 -0
- package/src/effects/interactive-hover-button/InteractiveHoverButton.svelte +338 -0
- package/src/effects/magic-card/MagicCard.css +47 -0
- package/src/effects/magic-card/MagicCard.svelte +57 -0
- package/src/effects/marquee/Marquee.css +27 -1
- package/src/effects/marquee/Marquee.svelte +67 -3
- package/src/effects/reveal/index.ts +2 -1
- package/src/effects/reveal/observe.test.ts +60 -0
- package/src/effects/reveal/observe.ts +33 -1
- package/src/effects/reveal/types.ts +7 -0
- package/src/effects/theme-toggle/ThemeToggle.css +199 -6
- package/src/effects/theme-toggle/ThemeToggle.svelte +51 -26
- package/src/gallery.test.ts +52 -0
- package/src/index.ts +5 -1
- package/src/lib/panel.ts +7 -1
- package/src/lib/theme-transition.ts +37 -11
- package/src/lib/tone.ts +48 -0
- package/src/shadcn/accordion/accordion-trigger.svelte +15 -6
- package/src/shadcn/alert/alert.svelte +3 -1
- package/src/shadcn/badge/badge.svelte +8 -7
- package/src/shadcn/breadcrumb/breadcrumb-ellipsis.svelte +2 -2
- package/src/shadcn/breadcrumb/breadcrumb-separator.svelte +2 -2
- package/src/shadcn/calendar/calendar-month-select.svelte +2 -2
- package/src/shadcn/calendar/calendar-next-button.svelte +2 -2
- package/src/shadcn/calendar/calendar-prev-button.svelte +2 -2
- package/src/shadcn/calendar/calendar-year-select.svelte +2 -2
- package/src/shadcn/calendar/calendar.svelte +6 -0
- package/src/shadcn/code-block/code-block-copy-button.svelte +6 -55
- package/src/shadcn/command/index.ts +3 -0
- package/src/shadcn/field/index.ts +3 -0
- package/src/shadcn/field/simple-field.svelte +71 -0
- package/src/shadcn/field/simple-field.test.ts +47 -0
- package/src/shadcn/message-scroller/message-scroller-button.svelte +2 -2
- package/src/shadcn/radio-group/radio-group-item.svelte +3 -2
- package/src/shadcn/sheet/sheet-content.svelte +1 -0
- package/src/shadcn/sheet/sheet.css +48 -0
- package/src/shadcn/sonner/sonner.svelte +7 -10
- package/src/shadcn/toggle-group/toggle-group.svelte +10 -3
- package/src/shadcn/trace/trace-collapsible-trigger.svelte +2 -2
- package/src/ai/composer/Composer.css +0 -108
- package/src/ai/composer/Composer.svelte +0 -111
- package/src/ai/composer/index.ts +0 -10
- package/src/animations/accordion.css +0 -58
- package/src/animations/icon-swap.css +0 -43
- package/src/animations/notification-badge.css +0 -81
- package/src/animations/panel.css +0 -86
- package/src/animations/reasoning-stream.css +0 -49
- package/src/animations/skeleton-reveal.css +0 -97
- package/src/animations/streaming-text.css +0 -31
- package/src/animations/tabs-sliding.css +0 -83
- package/src/animations/texts-reveal.css +0 -70
- package/src/animations/tooltip.css +0 -72
- package/src/animations/view-transition-reveal.ts +0 -74
- package/src/lib/utils.ts +0 -45
- package/src/showcase/AiSection.svelte +0 -150
- package/src/showcase/AnimationsSection.svelte +0 -1658
- package/src/showcase/EffectsSection.svelte +0 -152
- package/src/showcase/ShadcnSection.svelte +0 -27
- package/src/showcase/ShowcaseImport.svelte +0 -126
- package/src/showcase/ShowcaseList.svelte +0 -132
- package/src/showcase/ShowcaseNav.svelte +0 -247
- package/src/showcase/ShowcaseSection.svelte +0 -112
- package/src/showcase/ShowcaseShell.svelte +0 -55
- package/src/showcase/ShowcaseStage.svelte +0 -342
- package/src/showcase/ShowcaseVariant.svelte +0 -109
- package/src/showcase/assets/image-reveal/art-1.jpg +0 -0
- package/src/showcase/assets/image-reveal/art-2.jpg +0 -0
- package/src/showcase/assets/image-reveal/art-3.jpg +0 -0
- package/src/showcase/check.svg +0 -1
- package/src/showcase/chevron-arms.svg +0 -2
- package/src/showcase/chevron-down.svg +0 -1
- package/src/showcase/copy.svg +0 -2
- package/src/showcase/demos/ai/confirmation.svelte +0 -59
- package/src/showcase/demos/ai/loading-state.svelte +0 -19
- package/src/showcase/demos/ai/prompt-input.svelte +0 -57
- package/src/showcase/demos/ai/reasoning.svelte +0 -19
- package/src/showcase/demos/ai/thinking-dots.svelte +0 -15
- package/src/showcase/demos/ai/voice-waveform.svelte +0 -24
- package/src/showcase/demos/effects/animated-beam.svelte +0 -50
- package/src/showcase/demos/effects/animated-group.svelte +0 -47
- package/src/showcase/demos/effects/border-beam-default.svelte +0 -20
- package/src/showcase/demos/effects/border-beam-line.svelte +0 -20
- package/src/showcase/demos/effects/border-beam-mono.svelte +0 -20
- package/src/showcase/demos/effects/border-beam-sunset.svelte +0 -20
- package/src/showcase/demos/effects/image-comparison.svelte +0 -25
- package/src/showcase/demos/effects/image-reveal.svelte +0 -49
- package/src/showcase/demos/effects/in-view.svelte +0 -41
- package/src/showcase/demos/effects/integrations-hub.svelte +0 -82
- package/src/showcase/demos/effects/magnetic.svelte +0 -31
- package/src/showcase/demos/effects/marquee.svelte +0 -33
- package/src/showcase/demos/effects/progressive-blur.svelte +0 -47
- package/src/showcase/demos/effects/spotlight.svelte +0 -40
- package/src/showcase/demos/effects/text-effect.svelte +0 -55
- package/src/showcase/demos/shadcn/accordion.svelte +0 -45
- package/src/showcase/demos/shadcn/alert-dialog.svelte +0 -23
- package/src/showcase/demos/shadcn/alert.svelte +0 -30
- package/src/showcase/demos/shadcn/attachment.svelte +0 -71
- package/src/showcase/demos/shadcn/avatar.svelte +0 -30
- package/src/showcase/demos/shadcn/badge.svelte +0 -26
- package/src/showcase/demos/shadcn/breadcrumb.svelte +0 -34
- package/src/showcase/demos/shadcn/bubble.svelte +0 -36
- package/src/showcase/demos/shadcn/button.svelte +0 -11
- package/src/showcase/demos/shadcn/calendar.svelte +0 -8
- package/src/showcase/demos/shadcn/card.svelte +0 -39
- package/src/showcase/demos/shadcn/checkbox.svelte +0 -39
- package/src/showcase/demos/shadcn/code-block.svelte +0 -80
- package/src/showcase/demos/shadcn/collapsible.svelte +0 -20
- package/src/showcase/demos/shadcn/command.svelte +0 -48
- package/src/showcase/demos/shadcn/context-menu.svelte +0 -54
- package/src/showcase/demos/shadcn/demo-harness.svelte +0 -12
- package/src/showcase/demos/shadcn/demos.test.ts +0 -20
- package/src/showcase/demos/shadcn/dialog.svelte +0 -38
- package/src/showcase/demos/shadcn/dropdown-menu.svelte +0 -59
- package/src/showcase/demos/shadcn/empty.svelte +0 -29
- package/src/showcase/demos/shadcn/field.svelte +0 -115
- package/src/showcase/demos/shadcn/hover-card.svelte +0 -32
- package/src/showcase/demos/shadcn/index.ts +0 -382
- package/src/showcase/demos/shadcn/input-otp.svelte +0 -19
- package/src/showcase/demos/shadcn/input.svelte +0 -5
- package/src/showcase/demos/shadcn/label.svelte +0 -11
- package/src/showcase/demos/shadcn/marker.svelte +0 -30
- package/src/showcase/demos/shadcn/message-scroller.svelte +0 -44
- package/src/showcase/demos/shadcn/message.svelte +0 -75
- package/src/showcase/demos/shadcn/popover.svelte +0 -36
- package/src/showcase/demos/shadcn/progress.svelte +0 -13
- package/src/showcase/demos/shadcn/radio-group.svelte +0 -19
- package/src/showcase/demos/shadcn/scroll-area.svelte +0 -18
- package/src/showcase/demos/shadcn/select.svelte +0 -29
- package/src/showcase/demos/shadcn/separator.svelte +0 -12
- package/src/showcase/demos/shadcn/sheet.svelte +0 -48
- package/src/showcase/demos/shadcn/skeleton.svelte +0 -11
- package/src/showcase/demos/shadcn/slider.svelte +0 -7
- package/src/showcase/demos/shadcn/sonner.svelte +0 -18
- package/src/showcase/demos/shadcn/spinner.svelte +0 -11
- package/src/showcase/demos/shadcn/switch.svelte +0 -9
- package/src/showcase/demos/shadcn/table.svelte +0 -76
- package/src/showcase/demos/shadcn/tabs.svelte +0 -62
- package/src/showcase/demos/shadcn/textarea.svelte +0 -5
- package/src/showcase/demos/shadcn/toggle-group.svelte +0 -18
- package/src/showcase/demos/shadcn/toggle.svelte +0 -14
- package/src/showcase/demos/shadcn/tooltip.svelte +0 -13
- package/src/showcase/demos/shadcn/trace.svelte +0 -51
- package/src/showcase/heart.svg +0 -1
- package/src/showcase/index.ts +0 -38
- package/src/showcase/kit.test.ts +0 -72
- package/src/showcase/kit.ts +0 -16
- package/src/showcase/plus.svg +0 -1
- package/src/showcase/showcase-shell.css +0 -91
- package/src/showcase/stacked-section.css +0 -15
- package/src/showcase/success-check.svg +0 -1
- package/src/showcase/types.ts +0 -29
- package/src/svg-raw.d.ts +0 -7
|
@@ -4,16 +4,13 @@
|
|
|
4
4
|
export const badgeVariants = tv({
|
|
5
5
|
base: "h-5 gap-1 rounded-full border border-transparent px-2 py-0.5 text-xs font-medium has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive group/badge inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap transition-[background-color,border-color,color,box-shadow] focus-visible:ring-[3px] [&>svg]:pointer-events-none",
|
|
6
6
|
variants: {
|
|
7
|
-
// Three weights a label can carry: filled, tinted, outlined. Severity is
|
|
8
|
-
// `
|
|
9
|
-
// `warning`, `ghost` and `link` went on 4 Sep 2026.
|
|
7
|
+
// Three weights a label can carry: filled, tinted, outlined. Severity is the
|
|
8
|
+
// `tone` prop, which reads `TONE_CLASS`, not a variant.
|
|
10
9
|
variant: {
|
|
11
10
|
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
12
11
|
secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
|
|
13
12
|
outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
// scale behind it.
|
|
13
|
+
// For a consumer that wants one "this is wrong" badge without a tone prop.
|
|
17
14
|
destructive: "bg-destructive/10 text-destructive [a]:hover:bg-destructive/20",
|
|
18
15
|
},
|
|
19
16
|
},
|
|
@@ -28,16 +25,20 @@
|
|
|
28
25
|
<script lang="ts">
|
|
29
26
|
import type { HTMLAnchorAttributes } from "svelte/elements";
|
|
30
27
|
import { cn, type WithElementRef } from "@heyramzi/utils";
|
|
28
|
+
import { TONE_CLASS, type Tone } from "../../lib/tone.js";
|
|
31
29
|
|
|
32
30
|
let {
|
|
33
31
|
ref = $bindable(null),
|
|
34
32
|
href,
|
|
35
33
|
class: className,
|
|
36
34
|
variant = "default",
|
|
35
|
+
tone,
|
|
37
36
|
children,
|
|
38
37
|
...restProps
|
|
39
38
|
}: WithElementRef<HTMLAnchorAttributes> & {
|
|
40
39
|
variant?: BadgeVariant;
|
|
40
|
+
/** The severity scale. Draws an outlined chip in the tone's colours and ignores `variant`. */
|
|
41
|
+
tone?: Tone;
|
|
41
42
|
} = $props();
|
|
42
43
|
</script>
|
|
43
44
|
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
bind:this={ref}
|
|
47
48
|
data-slot="badge"
|
|
48
49
|
{href}
|
|
49
|
-
class={cn(badgeVariants({ variant }), className)}
|
|
50
|
+
class={cn(badgeVariants({ variant: tone ? "outline" : variant }), tone && TONE_CLASS[tone], className)}
|
|
50
51
|
{...restProps}
|
|
51
52
|
>
|
|
52
53
|
{@render children?.()}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { DotsThree } from "phosphor-svelte";
|
|
3
3
|
import type { HTMLAttributes } from "svelte/elements";
|
|
4
4
|
import { cn, type WithElementRef, type WithoutChildren } from "@heyramzi/utils";
|
|
5
5
|
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
class={cn("flex size-9 items-center justify-center", className)}
|
|
19
19
|
{...restProps}
|
|
20
20
|
>
|
|
21
|
-
<
|
|
21
|
+
<DotsThree class="size-4" />
|
|
22
22
|
<span class="sr-only">More</span>
|
|
23
23
|
</span>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { CaretRight } from "phosphor-svelte";
|
|
3
3
|
import { cn, type WithElementRef } from "@heyramzi/utils";
|
|
4
4
|
import type { HTMLLiAttributes } from "svelte/elements";
|
|
5
5
|
|
|
@@ -22,6 +22,6 @@
|
|
|
22
22
|
{#if children}
|
|
23
23
|
{@render children?.()}
|
|
24
24
|
{:else}
|
|
25
|
-
<
|
|
25
|
+
<CaretRight />
|
|
26
26
|
{/if}
|
|
27
27
|
</li>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
|
3
3
|
import { cn, type WithoutChildrenOrChild } from "@heyramzi/utils";
|
|
4
|
-
import
|
|
4
|
+
import { CaretDown } from "phosphor-svelte";
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
ref = $bindable(null),
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
aria-hidden="true"
|
|
38
38
|
>
|
|
39
39
|
{monthItems.find((item) => item.value === value)?.label || selectedMonthItem.label}
|
|
40
|
-
<
|
|
40
|
+
<CaretDown class="size-4" />
|
|
41
41
|
</span>
|
|
42
42
|
{/snippet}
|
|
43
43
|
</CalendarPrimitive.MonthSelect>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
|
3
|
-
import
|
|
3
|
+
import { CaretRight } from "phosphor-svelte";
|
|
4
4
|
import { buttonVariants, type ButtonVariant } from "../button/index.js";
|
|
5
5
|
import { cn } from "@heyramzi/utils";
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
18
|
{#snippet Fallback()}
|
|
19
|
-
<
|
|
19
|
+
<CaretRight class="size-4" />
|
|
20
20
|
{/snippet}
|
|
21
21
|
|
|
22
22
|
<CalendarPrimitive.NextButton
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
|
3
|
-
import
|
|
3
|
+
import { CaretLeft } from "phosphor-svelte";
|
|
4
4
|
import { buttonVariants, type ButtonVariant } from "../button/index.js";
|
|
5
5
|
import { cn } from "@heyramzi/utils";
|
|
6
6
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
18
|
{#snippet Fallback()}
|
|
19
|
-
<
|
|
19
|
+
<CaretLeft class="size-4" />
|
|
20
20
|
{/snippet}
|
|
21
21
|
|
|
22
22
|
<CalendarPrimitive.PrevButton
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Calendar as CalendarPrimitive } from "bits-ui";
|
|
3
3
|
import { cn, type WithoutChildrenOrChild } from "@heyramzi/utils";
|
|
4
|
-
import
|
|
4
|
+
import { CaretDown } from "phosphor-svelte";
|
|
5
5
|
|
|
6
6
|
let {
|
|
7
7
|
ref = $bindable(null),
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
aria-hidden="true"
|
|
37
37
|
>
|
|
38
38
|
{yearItems.find((item) => item.value === value)?.label || selectedYearItem.label}
|
|
39
|
-
<
|
|
39
|
+
<CaretDown class="size-4" />
|
|
40
40
|
</span>
|
|
41
41
|
{/snippet}
|
|
42
42
|
</CalendarPrimitive.YearSelect>
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
yearFormat = "numeric",
|
|
25
25
|
day,
|
|
26
26
|
disableDaysOutsideMonth = false,
|
|
27
|
+
// Monday first and six rows always: a five-week month would otherwise resize
|
|
28
|
+
// the popover as the reader pages through the year.
|
|
29
|
+
weekStartsOn = 1,
|
|
30
|
+
fixedWeeks = true,
|
|
27
31
|
...restProps
|
|
28
32
|
}: WithoutChildrenOrChild<CalendarPrimitive.RootProps> & {
|
|
29
33
|
buttonVariant?: ButtonVariant;
|
|
@@ -52,6 +56,8 @@ get along, so we shut typescript up by casting `value` to `never`.
|
|
|
52
56
|
bind:placeholder
|
|
53
57
|
{weekdayFormat}
|
|
54
58
|
{disableDaysOutsideMonth}
|
|
59
|
+
{weekStartsOn}
|
|
60
|
+
{fixedWeeks}
|
|
55
61
|
class={cn(
|
|
56
62
|
"bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
|
|
57
63
|
className,
|
|
@@ -1,59 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import CopyIcon from "@lucide/svelte/icons/copy";
|
|
5
|
-
import { Button, type ButtonProps } from "../button/index.js";
|
|
6
|
-
import { cn } from "@heyramzi/utils";
|
|
2
|
+
import type { ComponentProps } from "svelte";
|
|
3
|
+
import CopyButton from "../../components/copy/copy-button.svelte";
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
value,
|
|
12
|
-
variant = "ghost",
|
|
13
|
-
size = "sm",
|
|
14
|
-
onclick,
|
|
15
|
-
...restProps
|
|
16
|
-
}: Omit<ButtonProps, "onclick"> & {
|
|
17
|
-
value: string;
|
|
18
|
-
onclick?: (e: MouseEvent) => void;
|
|
19
|
-
} = $props();
|
|
20
|
-
|
|
21
|
-
let copied = $state(false);
|
|
22
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
23
|
-
|
|
24
|
-
function copy() {
|
|
25
|
-
navigator.clipboard
|
|
26
|
-
.writeText(value)
|
|
27
|
-
.then(() => {
|
|
28
|
-
copied = true;
|
|
29
|
-
clearTimeout(timeout);
|
|
30
|
-
timeout = setTimeout(() => (copied = false), 2000);
|
|
31
|
-
})
|
|
32
|
-
.catch(() => {});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
onDestroy(() => clearTimeout(timeout));
|
|
5
|
+
// WHY this wraps the shared control: the code block's own copy button drew a
|
|
6
|
+
// second icon swap and a second clipboard write. `md` is the 28px icon Button.
|
|
7
|
+
let { size = "md", ...restProps }: ComponentProps<typeof CopyButton> = $props();
|
|
36
8
|
</script>
|
|
37
9
|
|
|
38
|
-
<
|
|
39
|
-
bind:ref
|
|
40
|
-
data-slot="code-block-copy-button"
|
|
41
|
-
data-copied={copied || undefined}
|
|
42
|
-
{variant}
|
|
43
|
-
{size}
|
|
44
|
-
icon
|
|
45
|
-
aria-label={copied ? "Copied" : "Copy"}
|
|
46
|
-
class={cn(className)}
|
|
47
|
-
onclick={(e) => {
|
|
48
|
-
onclick?.(e);
|
|
49
|
-
copy();
|
|
50
|
-
}}
|
|
51
|
-
{...restProps}
|
|
52
|
-
>
|
|
53
|
-
{#if copied}
|
|
54
|
-
<CheckIcon />
|
|
55
|
-
{:else}
|
|
56
|
-
<CopyIcon />
|
|
57
|
-
{/if}
|
|
58
|
-
</Button>
|
|
59
|
-
<span aria-live="polite" class="sr-only">{copied ? "Copied" : ""}</span>
|
|
10
|
+
<CopyButton data-slot="code-block-copy-button" {size} {...restProps} />
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { computeCommandScore } from "bits-ui";
|
|
1
2
|
import Root from "./command.svelte";
|
|
2
3
|
import Loading from "./command-loading.svelte";
|
|
3
4
|
import Dialog from "./command-dialog.svelte";
|
|
@@ -10,7 +11,9 @@ import Separator from "./command-separator.svelte";
|
|
|
10
11
|
import Shortcut from "./command-shortcut.svelte";
|
|
11
12
|
import LinkItem from "./command-link-item.svelte";
|
|
12
13
|
|
|
14
|
+
// The scorer Command uses by default, for a custom `filter` that wants to rank its own words.
|
|
13
15
|
export {
|
|
16
|
+
computeCommandScore,
|
|
14
17
|
Root,
|
|
15
18
|
Dialog,
|
|
16
19
|
Empty,
|
|
@@ -8,6 +8,7 @@ import Title from "./field-title.svelte";
|
|
|
8
8
|
import Description from "./field-description.svelte";
|
|
9
9
|
import Separator from "./field-separator.svelte";
|
|
10
10
|
import Error from "./field-error.svelte";
|
|
11
|
+
import Simple from "./simple-field.svelte";
|
|
11
12
|
|
|
12
13
|
export {
|
|
13
14
|
Field,
|
|
@@ -20,6 +21,7 @@ export {
|
|
|
20
21
|
Description,
|
|
21
22
|
Separator,
|
|
22
23
|
Error,
|
|
24
|
+
Simple,
|
|
23
25
|
//
|
|
24
26
|
Set as FieldSet,
|
|
25
27
|
Legend as FieldLegend,
|
|
@@ -30,4 +32,5 @@ export {
|
|
|
30
32
|
Description as FieldDescription,
|
|
31
33
|
Separator as FieldSeparator,
|
|
32
34
|
Error as FieldError,
|
|
35
|
+
Simple as SimpleField,
|
|
33
36
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from "@heyramzi/utils";
|
|
3
|
+
import type { Snippet } from "svelte";
|
|
4
|
+
import type { Attachment } from "svelte/attachments";
|
|
5
|
+
import Field from "./field.svelte";
|
|
6
|
+
import FieldLabel from "./field-label.svelte";
|
|
7
|
+
import FieldDescription from "./field-description.svelte";
|
|
8
|
+
import FieldError from "./field-error.svelte";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
label?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
error?: string;
|
|
14
|
+
/** Id of the control the label binds to. Also picks the control that gets the message link. */
|
|
15
|
+
for?: string;
|
|
16
|
+
/** "default" is text-sm foreground; "muted" is a text-xs micro-label. */
|
|
17
|
+
labelVariant?: "default" | "muted";
|
|
18
|
+
class?: string;
|
|
19
|
+
children: Snippet;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
label,
|
|
24
|
+
description,
|
|
25
|
+
error,
|
|
26
|
+
for: htmlFor,
|
|
27
|
+
labelVariant = "default",
|
|
28
|
+
class: className,
|
|
29
|
+
children,
|
|
30
|
+
}: Props = $props();
|
|
31
|
+
|
|
32
|
+
const uid = $props.id();
|
|
33
|
+
const messageId = `${uid}-message`;
|
|
34
|
+
let message = $derived(error ?? description);
|
|
35
|
+
|
|
36
|
+
// WHY an attachment: the control is the caller's snippet, so the wrapper can't
|
|
37
|
+
// set its props. Wiring the DOM here means no call site can forget the link.
|
|
38
|
+
const CONTROL = "input, textarea, select, [role=combobox], [role=switch], [role=checkbox]";
|
|
39
|
+
const link: Attachment<HTMLElement> = (node) => {
|
|
40
|
+
if (!message) return;
|
|
41
|
+
const control =
|
|
42
|
+
(htmlFor ? node.querySelector<HTMLElement>(`[id="${CSS.escape(htmlFor)}"]`) : null) ??
|
|
43
|
+
node.querySelector<HTMLElement>(CONTROL);
|
|
44
|
+
if (!control) return;
|
|
45
|
+
const before = control.getAttribute("aria-describedby");
|
|
46
|
+
control.setAttribute("aria-describedby", [before, messageId].filter(Boolean).join(" "));
|
|
47
|
+
if (error) control.setAttribute("aria-invalid", "true");
|
|
48
|
+
return () => {
|
|
49
|
+
if (before === null) control.removeAttribute("aria-describedby");
|
|
50
|
+
else control.setAttribute("aria-describedby", before);
|
|
51
|
+
if (error) control.removeAttribute("aria-invalid");
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<Field class={cn("gap-2", className)} data-invalid={error ? "true" : undefined} {@attach link}>
|
|
57
|
+
{#if label}
|
|
58
|
+
<FieldLabel
|
|
59
|
+
for={htmlFor}
|
|
60
|
+
class={labelVariant === "muted" ? "text-muted-foreground text-xs" : undefined}
|
|
61
|
+
>
|
|
62
|
+
{label}
|
|
63
|
+
</FieldLabel>
|
|
64
|
+
{/if}
|
|
65
|
+
{@render children()}
|
|
66
|
+
{#if error}
|
|
67
|
+
<FieldError id={messageId} class="text-xs">{error}</FieldError>
|
|
68
|
+
{:else if description}
|
|
69
|
+
<FieldDescription id={messageId} class="text-xs">{description}</FieldDescription>
|
|
70
|
+
{/if}
|
|
71
|
+
</Field>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createRawSnippet, flushSync, mount, unmount } from "svelte";
|
|
2
|
+
import { describe, expect, it } from "vite-plus/test";
|
|
3
|
+
import SimpleField from "./simple-field.svelte";
|
|
4
|
+
|
|
5
|
+
const input = createRawSnippet(() => ({ render: () => `<input id="email" />` }));
|
|
6
|
+
|
|
7
|
+
function render(props: { error?: string; description?: string }) {
|
|
8
|
+
const target = document.createElement("div");
|
|
9
|
+
document.body.appendChild(target);
|
|
10
|
+
const app = mount(SimpleField, { target, props: { label: "Email", for: "email", children: input, ...props } });
|
|
11
|
+
flushSync();
|
|
12
|
+
return {
|
|
13
|
+
target,
|
|
14
|
+
done: () => {
|
|
15
|
+
void unmount(app);
|
|
16
|
+
target.remove();
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("SimpleField", () => {
|
|
22
|
+
it("links the error to its input and marks it invalid", () => {
|
|
23
|
+
const { target, done } = render({ error: "Enter a valid email" });
|
|
24
|
+
const control = target.querySelector("input")!;
|
|
25
|
+
const message = target.querySelector("[data-slot=field-error]")!;
|
|
26
|
+
expect(message.textContent).toContain("Enter a valid email");
|
|
27
|
+
expect(message.getAttribute("role")).toBe("alert");
|
|
28
|
+
expect(control.getAttribute("aria-describedby")).toBe(message.id);
|
|
29
|
+
expect(control.getAttribute("aria-invalid")).toBe("true");
|
|
30
|
+
done();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("links the description when there is no error", () => {
|
|
34
|
+
const { target, done } = render({ description: "We never share it" });
|
|
35
|
+
const control = target.querySelector("input")!;
|
|
36
|
+
const message = target.querySelector("[data-slot=field-description]")!;
|
|
37
|
+
expect(control.getAttribute("aria-describedby")).toBe(message.id);
|
|
38
|
+
expect(control.hasAttribute("aria-invalid")).toBe(false);
|
|
39
|
+
done();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("leaves the input alone when there is nothing to say", () => {
|
|
43
|
+
const { target, done } = render({});
|
|
44
|
+
expect(target.querySelector("input")!.hasAttribute("aria-describedby")).toBe(false);
|
|
45
|
+
done();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { MessageScroller as MessageScrollerPrimitive } from "@shadcn-svelte/primitives/message-scroller";
|
|
3
|
-
import
|
|
3
|
+
import { ArrowDown } from "phosphor-svelte";
|
|
4
4
|
import { Button } from "../button/index.js";
|
|
5
5
|
import type { ButtonSize, ButtonVariant } from "../button/index.js";
|
|
6
6
|
import { cn } from "@heyramzi/utils";
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
{#if children}
|
|
42
42
|
{@render children()}
|
|
43
43
|
{:else}
|
|
44
|
-
<
|
|
44
|
+
<ArrowDown />
|
|
45
45
|
<span class="sr-only">
|
|
46
46
|
{direction === "end" ? "Scroll to end" : "Scroll to start"}
|
|
47
47
|
</span>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
|
3
|
-
import
|
|
3
|
+
import { Circle } from "phosphor-svelte";
|
|
4
4
|
import { cn, type WithoutChildrenOrChild } from "@heyramzi/utils";
|
|
5
5
|
|
|
6
6
|
let {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
{#snippet children({ checked })}
|
|
23
23
|
<div data-slot="radio-group-indicator" class="relative flex items-center justify-center">
|
|
24
24
|
{#if checked}
|
|
25
|
-
<
|
|
25
|
+
<Circle
|
|
26
|
+
weight="fill"
|
|
26
27
|
class="fill-primary absolute start-1/2 top-1/2 size-2 -translate-x-1/2 -translate-y-1/2"
|
|
27
28
|
/>
|
|
28
29
|
{/if}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* The sheet slide: transitions.dev panel reveal, owned by the sheet. */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--sheet-open-dur: 300ms;
|
|
5
|
+
--sheet-close-dur: 250ms;
|
|
6
|
+
--sheet-translate: 100%;
|
|
7
|
+
--sheet-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.t-sheet {
|
|
11
|
+
opacity: 0;
|
|
12
|
+
pointer-events: none;
|
|
13
|
+
transition:
|
|
14
|
+
transform var(--sheet-close-dur) var(--sheet-ease),
|
|
15
|
+
opacity var(--sheet-close-dur) var(--sheet-ease);
|
|
16
|
+
will-change: transform, opacity;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.t-sheet[data-side="right"] {
|
|
20
|
+
transform: translateX(var(--sheet-translate));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.t-sheet[data-side="left"] {
|
|
24
|
+
transform: translateX(calc(-1 * var(--sheet-translate)));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.t-sheet[data-side="top"] {
|
|
28
|
+
transform: translateY(calc(-1 * var(--sheet-translate)));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.t-sheet[data-side="bottom"] {
|
|
32
|
+
transform: translateY(var(--sheet-translate));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.t-sheet[data-state="open"] {
|
|
36
|
+
transform: translate(0, 0);
|
|
37
|
+
opacity: 1;
|
|
38
|
+
pointer-events: auto;
|
|
39
|
+
transition:
|
|
40
|
+
transform var(--sheet-open-dur) var(--sheet-ease),
|
|
41
|
+
opacity var(--sheet-open-dur) var(--sheet-ease);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media (prefers-reduced-motion: reduce) {
|
|
45
|
+
.t-sheet {
|
|
46
|
+
transition: none !important;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import InfoIcon from "@lucide/svelte/icons/info";
|
|
4
|
-
import Loader2Icon from "@lucide/svelte/icons/loader-2";
|
|
5
|
-
import OctagonXIcon from "@lucide/svelte/icons/octagon-x";
|
|
6
|
-
import TriangleAlertIcon from "@lucide/svelte/icons/triangle-alert";
|
|
2
|
+
import { CheckCircle, Info, Warning, XCircle } from "phosphor-svelte";
|
|
7
3
|
|
|
4
|
+
import { Spinner } from "../spinner/index.js";
|
|
8
5
|
import { Toaster as Sonner, type ToasterProps as SonnerProps } from "svelte-sonner";
|
|
9
6
|
import { mode } from "mode-watcher";
|
|
10
7
|
|
|
@@ -17,18 +14,18 @@
|
|
|
17
14
|
style="--normal-bg: var(--color-popover); --normal-text: var(--color-popover-foreground); --normal-border: var(--color-border);"
|
|
18
15
|
{...restProps}
|
|
19
16
|
>{#snippet loadingIcon()}
|
|
20
|
-
<
|
|
17
|
+
<Spinner />
|
|
21
18
|
{/snippet}
|
|
22
19
|
{#snippet successIcon()}
|
|
23
|
-
<
|
|
20
|
+
<CheckCircle class="size-4" />
|
|
24
21
|
{/snippet}
|
|
25
22
|
{#snippet errorIcon()}
|
|
26
|
-
<
|
|
23
|
+
<XCircle class="size-4" />
|
|
27
24
|
{/snippet}
|
|
28
25
|
{#snippet infoIcon()}
|
|
29
|
-
<
|
|
26
|
+
<Info class="size-4" />
|
|
30
27
|
{/snippet}
|
|
31
28
|
{#snippet warningIcon()}
|
|
32
|
-
<
|
|
29
|
+
<Warning class="size-4" />
|
|
33
30
|
{/snippet}
|
|
34
31
|
</Sonner>
|
|
@@ -32,10 +32,17 @@
|
|
|
32
32
|
...restProps
|
|
33
33
|
}: ToggleGroupPrimitive.RootProps & ToggleVariants & { spacing?: number } = $props();
|
|
34
34
|
|
|
35
|
+
// WHY: getters, so an item reads the group's current props, not the ones it mounted with.
|
|
35
36
|
setToggleGroupCtx({
|
|
36
|
-
variant
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
get variant() {
|
|
38
|
+
return variant;
|
|
39
|
+
},
|
|
40
|
+
get size() {
|
|
41
|
+
return size;
|
|
42
|
+
},
|
|
43
|
+
get spacing() {
|
|
44
|
+
return spacing;
|
|
45
|
+
},
|
|
39
46
|
});
|
|
40
47
|
</script>
|
|
41
48
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import * as Collapsible from "../collapsible/index.js";
|
|
3
|
-
import
|
|
3
|
+
import { CaretRight } from "phosphor-svelte";
|
|
4
4
|
import { cn, type WithoutChild } from "@heyramzi/utils";
|
|
5
5
|
import TraceIcon from "./trace-icon.svelte";
|
|
6
6
|
import type { Collapsible as CollapsiblePrimitive } from "bits-ui";
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
>
|
|
25
25
|
{@render children?.()}
|
|
26
26
|
<TraceIcon class="transition-transform group-aria-expanded/trace-collapsible-trigger:rotate-90">
|
|
27
|
-
<
|
|
27
|
+
<CaretRight />
|
|
28
28
|
</TraceIcon>
|
|
29
29
|
</Collapsible.Trigger>
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
.chat-composer {
|
|
2
|
-
border-top: 1px solid color-mix(in srgb, var(--border, rgba(0, 0, 0, 0.1)) 40%, transparent);
|
|
3
|
-
padding: 0.625rem 0.75rem;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.chat-composer-row {
|
|
7
|
-
display: flex;
|
|
8
|
-
align-items: flex-end;
|
|
9
|
-
gap: 0.375rem;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.chat-composer-input {
|
|
13
|
-
/* WHY: grows with content; min/max bounds can be widened via `inputClass`. */
|
|
14
|
-
field-sizing: content;
|
|
15
|
-
max-height: 6rem;
|
|
16
|
-
flex: 1;
|
|
17
|
-
resize: none;
|
|
18
|
-
border: 0;
|
|
19
|
-
border-radius: 1rem;
|
|
20
|
-
background: color-mix(in srgb, var(--muted, rgba(0, 0, 0, 0.06)) 40%, transparent);
|
|
21
|
-
padding: 0.5rem 0.875rem;
|
|
22
|
-
font-size: 0.875rem;
|
|
23
|
-
color: inherit;
|
|
24
|
-
transition: background-color 120ms ease;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.chat-composer-input::placeholder {
|
|
28
|
-
color: var(--muted-foreground, rgba(0, 0, 0, 0.45));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.chat-composer-input:focus {
|
|
32
|
-
outline: none;
|
|
33
|
-
background: color-mix(in srgb, var(--muted, rgba(0, 0, 0, 0.06)) 60%, transparent);
|
|
34
|
-
/* WHY: a soft ring in the conversation's accent, which is per-surface. */
|
|
35
|
-
box-shadow: 0 0 0 2px
|
|
36
|
-
color-mix(in srgb, var(--chat-accent, var(--primary, #6647f0)) 28%, transparent);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.chat-composer-input:disabled {
|
|
40
|
-
opacity: 0.4;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.chat-composer-send {
|
|
44
|
-
display: flex;
|
|
45
|
-
height: 2.25rem;
|
|
46
|
-
width: 2.25rem;
|
|
47
|
-
flex-shrink: 0;
|
|
48
|
-
align-items: center;
|
|
49
|
-
justify-content: center;
|
|
50
|
-
border: 0;
|
|
51
|
-
border-radius: 9999px;
|
|
52
|
-
background: var(--chat-accent, var(--primary, #6647f0));
|
|
53
|
-
color: var(--chat-accent-foreground, #fff);
|
|
54
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
transition:
|
|
57
|
-
transform 150ms ease,
|
|
58
|
-
box-shadow 150ms ease;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.chat-composer-send:hover:not(:disabled) {
|
|
62
|
-
transform: translateY(-1px);
|
|
63
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.chat-composer-send:active:not(:disabled) {
|
|
67
|
-
transform: translateY(0) scale(0.95);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.chat-composer-send:disabled {
|
|
71
|
-
cursor: not-allowed;
|
|
72
|
-
opacity: 0.2;
|
|
73
|
-
box-shadow: none;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.chat-composer-icon {
|
|
77
|
-
height: 0.875rem;
|
|
78
|
-
width: 0.875rem;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.chat-composer-spin {
|
|
82
|
-
animation: chat-composer-spin 800ms linear infinite;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@keyframes chat-composer-spin {
|
|
86
|
-
to {
|
|
87
|
-
transform: rotate(360deg);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.chat-composer-error {
|
|
92
|
-
margin-top: 0.25rem;
|
|
93
|
-
padding: 0 0.25rem;
|
|
94
|
-
font-size: 0.75rem;
|
|
95
|
-
color: var(--destructive, #dc2626);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
@media (prefers-reduced-motion: reduce) {
|
|
99
|
-
.chat-composer-send {
|
|
100
|
-
transition: background-color 150ms ease;
|
|
101
|
-
}
|
|
102
|
-
.chat-composer-send:hover:not(:disabled) {
|
|
103
|
-
transform: none;
|
|
104
|
-
}
|
|
105
|
-
.chat-composer-spin {
|
|
106
|
-
animation: none;
|
|
107
|
-
}
|
|
108
|
-
}
|