@giddaa-housing/ui 2.1.0 → 3.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.
Files changed (50) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/css/theme.css +24 -0
  3. package/dist/accordion.js +1 -1
  4. package/dist/{button-BZIeyUw6.d.ts → button-DW5OijoR.d.ts} +1 -1
  5. package/dist/button-group.d.ts +1 -1
  6. package/dist/button-group.js +2 -2
  7. package/dist/button.d.ts +1 -1
  8. package/dist/button.js +4 -3
  9. package/dist/call-card.d.ts +131 -0
  10. package/dist/call-card.js +300 -0
  11. package/dist/carousel.js +12 -9
  12. package/dist/chat.d.ts +208 -0
  13. package/dist/chat.js +528 -0
  14. package/dist/checkbox.js +1 -1
  15. package/dist/combobox.js +1 -1
  16. package/dist/cta.d.ts +1 -1
  17. package/dist/data-table.d.ts +1 -1
  18. package/dist/dialog.js +2 -2
  19. package/dist/dropdown-menu.js +1 -1
  20. package/dist/file-upload.js +3 -3
  21. package/dist/infinite-scroll.js +1 -1
  22. package/dist/infotip.js +1 -1
  23. package/dist/input-group.d.ts +1 -1
  24. package/dist/media-player.js +15 -8
  25. package/dist/message.d.ts +263 -0
  26. package/dist/message.js +524 -0
  27. package/dist/multi-step-form.js +10 -6
  28. package/dist/page-header.d.ts +6 -6
  29. package/dist/page-header.js +21 -7
  30. package/dist/pagination.d.ts +1 -1
  31. package/dist/popover.js +1 -1
  32. package/dist/price-tag.js +1 -1
  33. package/dist/property-listing-card.d.ts +1 -1
  34. package/dist/radio-group.js +1 -1
  35. package/dist/rich-text-editor.js +3 -3
  36. package/dist/select.js +1 -1
  37. package/dist/sheet.js +1 -1
  38. package/dist/sidebar.d.ts +1 -1
  39. package/dist/sidebar.js +5 -5
  40. package/dist/skeleton.js +1 -1
  41. package/dist/slider.js +3 -2
  42. package/dist/styles.css +1870 -162
  43. package/dist/switch.js +3 -3
  44. package/dist/tabs.js +2 -2
  45. package/dist/time-picker.js +85 -7
  46. package/dist/toast.js +1 -1
  47. package/dist/tooltip.d.ts +2 -1
  48. package/dist/tooltip.js +9 -2
  49. package/dist/use-reduced-motion-BDvOK14x.js +17 -0
  50. package/package.json +13 -1
package/dist/button.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { n as ButtonLink, r as buttonVariants, t as Button } from "./button-BZIeyUw6.js";
1
+ import { n as ButtonLink, r as buttonVariants, t as Button } from "./button-DW5OijoR.js";
2
2
  export { Button, ButtonLink, buttonVariants };
package/dist/button.js CHANGED
@@ -7,9 +7,10 @@ import { useRender } from "@base-ui/react/use-render";
7
7
  import { cva } from "class-variance-authority";
8
8
  import { Button as Button$1 } from "@base-ui/react/button";
9
9
  //#region src/button.tsx
10
- const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-full bg-clip-padding whitespace-nowrap font-bold transition-[background-color,color,border-color,box-shadow,transform] outline-none select-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-invalid:border-line-danger aria-invalid:ring-3 aria-invalid:ring-line-danger/20 aria-invalid:focus-visible:border-line-danger aria-invalid:focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-danger)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
10
+ const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-full bg-clip-padding whitespace-nowrap font-bold transition-[background-color,color,border-color,box-shadow,scale,translate] duration-(--duration-motion-press) ease-gdt-out outline-none select-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:not-aria-[haspopup]:translate-y-px motion-reduce:active:not-aria-[haspopup]:translate-y-0 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-invalid:border-line-danger aria-invalid:ring-3 aria-invalid:ring-line-danger/20 aria-invalid:focus-visible:border-line-danger aria-invalid:focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-danger)] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
11
11
  variants: {
12
12
  variant: {
13
+ back: "border border-line bg-canvas text-fg-primary hover:border-line-strong hover:bg-surface active:border-line-strong active:bg-surface-raised data-focused:border-line-strong data-focused:bg-surface data-pressed:border-line-strong data-pressed:bg-surface-raised disabled:border-line-subtle disabled:text-fg-caption-placeholder disabled:opacity-100 aria-disabled:border-line-subtle aria-disabled:text-fg-caption-placeholder aria-disabled:opacity-100",
13
14
  primary: "bg-action-primary text-fg-on-brand hover:bg-action-primary-hover active:bg-action-primary-pressed",
14
15
  "primary-outline": "border-2 border-action-primary bg-transparent text-fg-brand hover:bg-surface-brand-subtle active:bg-surface-brand-subtle data-focused:bg-surface-brand-subtle data-pressed:bg-surface-brand-subtle",
15
16
  secondary: "bg-surface-brand-subtle text-fg-brand hover:bg-action-primary-hover hover:text-fg-on-brand active:bg-action-primary-pressed active:text-fg-on-brand data-focused:bg-action-primary-hover data-pressed:bg-action-primary-pressed data-focused:text-fg-on-brand data-pressed:text-fg-on-brand",
@@ -19,7 +20,7 @@ const buttonVariants = cva("group/button inline-flex shrink-0 items-center justi
19
20
  ghost: "bg-transparent text-fg-primary hover:bg-surface active:bg-surface-raised data-focused:bg-surface data-pressed:bg-surface-raised",
20
21
  danger: "bg-action-danger text-fg-on-brand hover:bg-action-danger-hover active:bg-action-danger-pressed data-focused:bg-action-danger-hover data-pressed:bg-action-danger-pressed",
21
22
  whatsapp: "bg-whatsapp-button text-black [&_svg]:text-white hover:brightness-95 active:brightness-90 data-focused:brightness-95 data-pressed:brightness-90",
22
- "glass-overlay": "bg-surface-glass-overlay-button text-fg-on-brand shadow-2 backdrop-blur-sm hover:scale-105 active:scale-95",
23
+ "glass-overlay": "bg-surface-glass-overlay-button text-fg-on-brand shadow-2 backdrop-blur-sm active:scale-[0.97] motion-reduce:active:scale-100",
23
24
  "link-brand": "border-transparent bg-transparent px-0 text-fg-brand hover:underline active:underline active:opacity-70",
24
25
  "link-neutral": "border-transparent bg-transparent px-0 text-fg-secondary hover:underline active:underline active:opacity-70"
25
26
  },
@@ -54,7 +55,7 @@ function Button({ className, variant = "primary", size, isLoading = false, child
54
55
  disabled: _disabled,
55
56
  ...props,
56
57
  children: [
57
- isLoading && /* @__PURE__ */ jsx(Loader, { className: "size-4 animate-spin" }),
58
+ isLoading && /* @__PURE__ */ jsx(Loader, { className: "size-4 animate-spin motion-reduce:animate-none" }),
58
59
  " ",
59
60
  children
60
61
  ]
@@ -0,0 +1,131 @@
1
+ import { Avatar } from "./avatar.js";
2
+ import * as React from "react";
3
+ //#region src/call-card.d.ts
4
+ /**
5
+ * Docked vs full-window presentation. Purely structural: `full` is the centered
6
+ * call window that floats over an overlay; `minimized` is the horizontal docked
7
+ * bar. Everything below the card shell — direction, spacing, type ramp — keys
8
+ * off this one axis.
9
+ */
10
+ type CallCardSize = "full" | "minimized";
11
+ /**
12
+ * The five visual states from the design's two branches.
13
+ * OUTBOUND (a call we place): `calling` → `ringing` → `in-call` → `call-ended`,
14
+ * whose actions are Mute + End Call. INBOUND: `incoming`, whose actions are
15
+ * Ignore + Accept. `state` is the sole driver of the status-dot colour and of
16
+ * whether the End Call button retires to a neutral tone.
17
+ */
18
+ type CallCardState = "ringing" | "calling" | "in-call" | "call-ended" | "incoming";
19
+ type CallCardOverlayProps = React.ComponentProps<"div">;
20
+ /**
21
+ * The scrim behind a `size="full"` card. An overlay must not share a surface
22
+ * with the thread behind it, so the card floats on `bg-surface-overlay` above
23
+ * this dimmed, blurred layer. Centres its child; give it the card as children.
24
+ *
25
+ * Only for the full state — a minimized bar docks inline and needs no scrim.
26
+ */
27
+ declare function CallCardOverlay({ className, ...props }: CallCardOverlayProps): React.JSX.Element;
28
+ /** The card shell — surface, border, elevation, and the per-size layout. */
29
+ declare const callCardVariants: (props?: ({
30
+ size?: "full" | "minimized" | null | undefined;
31
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
32
+ interface CallCardProps extends React.ComponentProps<"section"> {
33
+ /** Docked bar vs full window — see {@link CallCardSize}. @default "full" */
34
+ size?: CallCardSize;
35
+ /**
36
+ * Which point of the call this is — see {@link CallCardState}. Required: it
37
+ * drives the status-dot colour and the End Call button's tone, so there is no
38
+ * safe default.
39
+ */
40
+ state: CallCardState;
41
+ }
42
+ /**
43
+ * The reusable call overlay — the in-product surface shown while a voice call is
44
+ * ringing, connecting, connected, or just ended. A presentational primitive:
45
+ * it owns shape, elevation and per-size layout, and exposes state through
46
+ * context so its parts size and colour themselves. Wiring (mute, hang up,
47
+ * accept) is the consumer's — pass handlers to the action parts.
48
+ *
49
+ * Compose it like a Dialog: a shell with slotted parts. For the full state,
50
+ * wrap it in {@link CallCardOverlay}; the minimized bar docks on its own.
51
+ */
52
+ declare function CallCard({ size, state, className, children, ...props }: CallCardProps): React.JSX.Element;
53
+ interface CallCardAvatarProps extends Omit<React.ComponentProps<typeof Avatar>, "size"> {
54
+ /** Contact photo. When absent, the fallback glyph shows. */
55
+ src?: string;
56
+ /** Alt text for the photo. */
57
+ alt?: string;
58
+ /** Fallback shown with no photo — initials or a glyph. @default person glyph */
59
+ fallback?: React.ReactNode;
60
+ }
61
+ /**
62
+ * The contact avatar. Wraps the giddaa `Avatar` so it inherits the brand-subtle
63
+ * wash and brand glyph tokens — 112px in the full window (the design's largest
64
+ * element), 40px on the docked bar. Pass `src` for a photo; the glyph is only a
65
+ * fallback.
66
+ */
67
+ declare function CallCardAvatar({ src, alt, fallback, className, ...props }: CallCardAvatarProps): React.JSX.Element;
68
+ type CallCardIdentityProps = React.ComponentProps<"div">;
69
+ /** Stacks the name over the status line; centred in full, start-aligned when docked. */
70
+ declare function CallCardIdentity({ className, ...props }: CallCardIdentityProps): React.JSX.Element;
71
+ type CallCardNameProps = React.ComponentProps<"p">;
72
+ /** The contact name. Full uses the heading ramp; the docked bar truncates. */
73
+ declare function CallCardName({ className, ...props }: CallCardNameProps): React.JSX.Element;
74
+ type CallCardStatusProps = React.ComponentProps<"div">;
75
+ /**
76
+ * The status line: a state-coloured dot followed by its copy — the number, the
77
+ * running timer, or the end notice. The dot's colour comes from the card's
78
+ * `state`; the copy is the caller's (never bake the number or timer in).
79
+ */
80
+ declare function CallCardStatus({ className, children, ...props }: CallCardStatusProps): React.JSX.Element;
81
+ type CallCardActionsProps = React.ComponentProps<"div">;
82
+ /**
83
+ * The action row. Holds the call actions, led by the window control. Turning an
84
+ * action off simply drops it — the row re-centres, no dead slot. Never leave it
85
+ * empty: an overlay with no controls traps the user in a live call.
86
+ */
87
+ declare function CallCardActions({ className, ...props }: CallCardActionsProps): React.JSX.Element;
88
+ type CallCardActionTone = "tertiary" | "danger" | "primary";
89
+ interface CallCardActionProps extends React.ComponentProps<"button"> {
90
+ /**
91
+ * Surface emphasis. `tertiary` = reversible/neutral (Mute), `danger` =
92
+ * destructive (End Call, Ignore), `primary` = the call to answer (Accept).
93
+ * @default "tertiary"
94
+ */
95
+ tone?: CallCardActionTone;
96
+ }
97
+ /**
98
+ * The circular icon-button primitive every call action is built from. Sizes
99
+ * itself off the card, colours itself off `tone`. Pass a single icon as its
100
+ * child; it's auto-sized. Use the presets below for the standard actions.
101
+ */
102
+ declare function CallCardAction({ tone, type, className, ...props }: CallCardActionProps): React.JSX.Element;
103
+ interface CallCardMuteButtonProps extends Omit<CallCardActionProps, "tone" | "children"> {
104
+ /** Whether the mic is currently muted — swaps the glyph and the label. */
105
+ muted?: boolean;
106
+ }
107
+ /** Mute toggle. Reversible, so it stays neutral and never competes with End Call. */
108
+ declare function CallCardMuteButton({ muted, "aria-label": ariaLabel, ...props }: CallCardMuteButtonProps): React.JSX.Element;
109
+ type CallCardEndCallButtonProps = Omit<CallCardActionProps, "tone" | "children">;
110
+ /**
111
+ * End Call. Destructive, so it's `danger` — except in `call-ended`, where the
112
+ * call is already over and it retires to a neutral tone. The rotated handset is
113
+ * a placeholder for the exact SVG.
114
+ */
115
+ declare function CallCardEndCallButton({ className, "aria-label": ariaLabel, ...props }: CallCardEndCallButtonProps): React.JSX.Element;
116
+ type CallCardAcceptButtonProps = Omit<CallCardActionProps, "tone" | "children">;
117
+ /** Accept an incoming call. The brand primary — the button the thumb finds first. */
118
+ declare function CallCardAcceptButton({ "aria-label": ariaLabel, ...props }: CallCardAcceptButtonProps): React.JSX.Element;
119
+ type CallCardIgnoreButtonProps = Omit<CallCardActionProps, "tone" | "children">;
120
+ /** Dismiss an incoming call. Same clay and rotated handset as End Call. */
121
+ declare function CallCardIgnoreButton({ "aria-label": ariaLabel, ...props }: CallCardIgnoreButtonProps): React.JSX.Element;
122
+ type CallCardWindowControlProps = React.ComponentProps<"button">;
123
+ /**
124
+ * The window chrome — Minimize in the full window (pinned top-right), Expand on
125
+ * the docked bar (leads the action row). Neutral and quiet by design: a window
126
+ * control is never destructive and must not pull the eye from End Call. Place it
127
+ * as the first child of {@link CallCardActions}; it self-positions per size.
128
+ */
129
+ declare function CallCardWindowControl({ className, "aria-label": ariaLabel, type, ...props }: CallCardWindowControlProps): React.JSX.Element;
130
+ //#endregion
131
+ export { CallCard, CallCardAcceptButton, type CallCardAcceptButtonProps, CallCardAction, type CallCardActionProps, type CallCardActionTone, CallCardActions, CallCardAvatar, type CallCardAvatarProps, CallCardEndCallButton, type CallCardEndCallButtonProps, CallCardIdentity, type CallCardIdentityProps, CallCardIgnoreButton, type CallCardIgnoreButtonProps, CallCardMuteButton, type CallCardMuteButtonProps, CallCardName, type CallCardNameProps, CallCardOverlay, type CallCardOverlayProps, type CallCardProps, type CallCardSize, type CallCardState, CallCardStatus, type CallCardStatusProps, CallCardWindowControl, type CallCardWindowControlProps, callCardVariants };
@@ -0,0 +1,300 @@
1
+ "use client";
2
+ import { t as cn } from "./cn-BI_4DMBf.js";
3
+ import { Avatar, AvatarFallback, AvatarImage } from "./avatar.js";
4
+ import { Maximize2, Mic, MicOff, Minimize2, Phone, User } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { cva } from "class-variance-authority";
7
+ import * as React from "react";
8
+ //#region src/call-card.tsx
9
+ const CallCardContext = React.createContext(null);
10
+ function useCallCardContext() {
11
+ const context = React.useContext(CallCardContext);
12
+ if (!context) throw new Error("CallCard parts must be rendered inside <CallCard>.");
13
+ return context;
14
+ }
15
+ /**
16
+ * Status-dot fill per state. The dot is the fastest read on the card, so it
17
+ * carries the state on its own — warning while the call is in flight, success
18
+ * once connected, danger once ended, info for an arriving call.
19
+ */
20
+ const STATUS_DOT_TONE = {
21
+ ringing: "bg-status-warning",
22
+ calling: "bg-status-warning",
23
+ "in-call": "bg-status-success",
24
+ "call-ended": "bg-status-danger",
25
+ incoming: "bg-status-info"
26
+ };
27
+ /**
28
+ * The scrim behind a `size="full"` card. An overlay must not share a surface
29
+ * with the thread behind it, so the card floats on `bg-surface-overlay` above
30
+ * this dimmed, blurred layer. Centres its child; give it the card as children.
31
+ *
32
+ * Only for the full state — a minimized bar docks inline and needs no scrim.
33
+ */
34
+ function CallCardOverlay({ className, ...props }) {
35
+ return /* @__PURE__ */ jsx("div", {
36
+ "data-slot": "call-card-overlay",
37
+ className: cn("fixed inset-0 isolate z-50 grid place-items-center p-4", "bg-black/10 supports-[backdrop-filter]:backdrop-blur-xl", "animate-in fade-in-0 duration-100", className),
38
+ ...props
39
+ });
40
+ }
41
+ /** The card shell — surface, border, elevation, and the per-size layout. */
42
+ const callCardVariants = cva("relative flex border border-line-subtle bg-surface-overlay shadow-2", {
43
+ variants: { size: {
44
+ full: "w-full max-w-[390px] flex-col items-center justify-center gap-7 rounded-2xl px-gdt-xl pt-14 pb-gdt-4xl md:max-w-[640px] md:gap-gdt-2xl md:px-gdt-4xl md:pt-gdt-4xl",
45
+ minimized: "h-14 w-full max-w-[358px] items-center gap-2.5 rounded-[14px] p-2.5 md:h-16 md:max-w-[360px] md:gap-gdt-md md:rounded-xl md:p-gdt-md"
46
+ } },
47
+ defaultVariants: { size: "full" }
48
+ });
49
+ /**
50
+ * The reusable call overlay — the in-product surface shown while a voice call is
51
+ * ringing, connecting, connected, or just ended. A presentational primitive:
52
+ * it owns shape, elevation and per-size layout, and exposes state through
53
+ * context so its parts size and colour themselves. Wiring (mute, hang up,
54
+ * accept) is the consumer's — pass handlers to the action parts.
55
+ *
56
+ * Compose it like a Dialog: a shell with slotted parts. For the full state,
57
+ * wrap it in {@link CallCardOverlay}; the minimized bar docks on its own.
58
+ */
59
+ function CallCard({ size = "full", state, className, children, ...props }) {
60
+ const context = React.useMemo(() => ({
61
+ size,
62
+ state
63
+ }), [size, state]);
64
+ return /* @__PURE__ */ jsx(CallCardContext.Provider, {
65
+ value: context,
66
+ children: /* @__PURE__ */ jsx("section", {
67
+ "data-slot": "call-card",
68
+ "data-size": size,
69
+ "data-state": state,
70
+ role: state === "incoming" ? "alert" : "status",
71
+ "aria-live": state === "incoming" ? "assertive" : "polite",
72
+ className: cn("group/call-card", callCardVariants({ size }), className),
73
+ ...props,
74
+ children
75
+ })
76
+ });
77
+ }
78
+ /**
79
+ * The contact avatar. Wraps the giddaa `Avatar` so it inherits the brand-subtle
80
+ * wash and brand glyph tokens — 112px in the full window (the design's largest
81
+ * element), 40px on the docked bar. Pass `src` for a photo; the glyph is only a
82
+ * fallback.
83
+ */
84
+ function CallCardAvatar({ src, alt, fallback, className, ...props }) {
85
+ const { size } = useCallCardContext();
86
+ const isFull = size === "full";
87
+ return /* @__PURE__ */ jsxs(Avatar, {
88
+ "data-slot": "call-card-avatar",
89
+ size: isFull ? "lg" : "md",
90
+ className: cn(isFull ? "size-24 md:size-28" : "size-9 md:size-10", className),
91
+ ...props,
92
+ children: [src ? /* @__PURE__ */ jsx(AvatarImage, {
93
+ src,
94
+ alt
95
+ }) : null, /* @__PURE__ */ jsx(AvatarFallback, { children: fallback ?? /* @__PURE__ */ jsx(User, {
96
+ className: isFull ? "size-[38px] md:size-11" : "size-4 md:size-[18px]",
97
+ "aria-hidden": true
98
+ }) })]
99
+ });
100
+ }
101
+ const identityVariants = cva("flex min-w-0 flex-col justify-center", {
102
+ variants: { size: {
103
+ full: "items-center gap-1.5 text-center",
104
+ minimized: "flex-1 items-start gap-px md:gap-0.5"
105
+ } },
106
+ defaultVariants: { size: "full" }
107
+ });
108
+ /** Stacks the name over the status line; centred in full, start-aligned when docked. */
109
+ function CallCardIdentity({ className, ...props }) {
110
+ const { size } = useCallCardContext();
111
+ return /* @__PURE__ */ jsx("div", {
112
+ "data-slot": "call-card-identity",
113
+ className: cn(identityVariants({ size }), className),
114
+ ...props
115
+ });
116
+ }
117
+ const nameVariants = cva("min-w-0 text-fg-primary", {
118
+ variants: { size: {
119
+ full: "text-gdt-h4 md:text-gdt-h3",
120
+ minimized: "w-full truncate text-gdt-sm font-semibold"
121
+ } },
122
+ defaultVariants: { size: "full" }
123
+ });
124
+ /** The contact name. Full uses the heading ramp; the docked bar truncates. */
125
+ function CallCardName({ className, ...props }) {
126
+ const { size } = useCallCardContext();
127
+ return /* @__PURE__ */ jsx("p", {
128
+ "data-slot": "call-card-name",
129
+ className: cn(nameVariants({ size }), className),
130
+ ...props
131
+ });
132
+ }
133
+ const statusVariants = cva("flex min-w-0 items-center text-fg-secondary", {
134
+ variants: { size: {
135
+ full: "justify-center gap-gdt-sm text-gdt-sm",
136
+ minimized: "gap-1.5 text-gdt-xs"
137
+ } },
138
+ defaultVariants: { size: "full" }
139
+ });
140
+ const statusDotVariants = cva("shrink-0 rounded-full", {
141
+ variants: { size: {
142
+ full: "size-2",
143
+ minimized: "size-1.5"
144
+ } },
145
+ defaultVariants: { size: "full" }
146
+ });
147
+ /**
148
+ * The status line: a state-coloured dot followed by its copy — the number, the
149
+ * running timer, or the end notice. The dot's colour comes from the card's
150
+ * `state`; the copy is the caller's (never bake the number or timer in).
151
+ */
152
+ function CallCardStatus({ className, children, ...props }) {
153
+ const { size, state } = useCallCardContext();
154
+ return /* @__PURE__ */ jsxs("div", {
155
+ "data-slot": "call-card-status",
156
+ className: cn(statusVariants({ size }), className),
157
+ ...props,
158
+ children: [/* @__PURE__ */ jsx("span", {
159
+ "data-slot": "call-card-status-dot",
160
+ className: cn(statusDotVariants({ size }), STATUS_DOT_TONE[state]),
161
+ "aria-hidden": true
162
+ }), /* @__PURE__ */ jsx("span", {
163
+ className: "min-w-0 truncate",
164
+ children
165
+ })]
166
+ });
167
+ }
168
+ const actionsVariants = cva("flex shrink-0 items-center justify-center", {
169
+ variants: { size: {
170
+ full: "gap-gdt-lg md:gap-5",
171
+ minimized: "gap-gdt-sm"
172
+ } },
173
+ defaultVariants: { size: "full" }
174
+ });
175
+ /**
176
+ * The action row. Holds the call actions, led by the window control. Turning an
177
+ * action off simply drops it — the row re-centres, no dead slot. Never leave it
178
+ * empty: an overlay with no controls traps the user in a live call.
179
+ */
180
+ function CallCardActions({ className, ...props }) {
181
+ const { size } = useCallCardContext();
182
+ return /* @__PURE__ */ jsx("div", {
183
+ "data-slot": "call-card-actions",
184
+ className: cn(actionsVariants({ size }), className),
185
+ ...props
186
+ });
187
+ }
188
+ const actionVariants = cva([
189
+ "grid shrink-0 place-items-center rounded-full outline-none transition-colors",
190
+ "focus-visible:ring-2 focus-visible:ring-line-focus focus-visible:ring-offset-2 focus-visible:ring-offset-surface-overlay",
191
+ "disabled:pointer-events-none disabled:opacity-50"
192
+ ], {
193
+ variants: {
194
+ size: {
195
+ full: "size-14 [&_svg]:size-6 md:size-16 md:[&_svg]:size-[26px]",
196
+ minimized: "size-[34px] [&_svg]:size-[15px] md:size-9 md:[&_svg]:size-4"
197
+ },
198
+ tone: {
199
+ tertiary: "bg-action-tertiary text-fg-primary hover:bg-action-tertiary-hover",
200
+ danger: "bg-action-danger text-fg-on-brand hover:bg-action-danger-hover",
201
+ primary: "bg-action-primary text-fg-on-brand hover:bg-action-primary-hover"
202
+ }
203
+ },
204
+ defaultVariants: {
205
+ size: "full",
206
+ tone: "tertiary"
207
+ }
208
+ });
209
+ /**
210
+ * The circular icon-button primitive every call action is built from. Sizes
211
+ * itself off the card, colours itself off `tone`. Pass a single icon as its
212
+ * child; it's auto-sized. Use the presets below for the standard actions.
213
+ */
214
+ function CallCardAction({ tone = "tertiary", type = "button", className, ...props }) {
215
+ const { size } = useCallCardContext();
216
+ return /* @__PURE__ */ jsx("button", {
217
+ "data-slot": "call-card-action",
218
+ type,
219
+ className: cn(actionVariants({
220
+ size,
221
+ tone
222
+ }), className),
223
+ ...props
224
+ });
225
+ }
226
+ /** Mute toggle. Reversible, so it stays neutral and never competes with End Call. */
227
+ function CallCardMuteButton({ muted = false, "aria-label": ariaLabel, ...props }) {
228
+ return /* @__PURE__ */ jsx(CallCardAction, {
229
+ tone: "tertiary",
230
+ "aria-pressed": muted,
231
+ "aria-label": ariaLabel ?? (muted ? "Unmute" : "Mute"),
232
+ ...props,
233
+ children: muted ? /* @__PURE__ */ jsx(MicOff, {}) : /* @__PURE__ */ jsx(Mic, {})
234
+ });
235
+ }
236
+ /**
237
+ * End Call. Destructive, so it's `danger` — except in `call-ended`, where the
238
+ * call is already over and it retires to a neutral tone. The rotated handset is
239
+ * a placeholder for the exact SVG.
240
+ */
241
+ function CallCardEndCallButton({ className, "aria-label": ariaLabel, ...props }) {
242
+ const { state } = useCallCardContext();
243
+ const ended = state === "call-ended";
244
+ return /* @__PURE__ */ jsx(CallCardAction, {
245
+ tone: ended ? "tertiary" : "danger",
246
+ "aria-label": ariaLabel ?? "End call",
247
+ className: cn(ended && "text-fg-primary", className),
248
+ ...props,
249
+ children: /* @__PURE__ */ jsx(Phone, { className: "rotate-[135deg]" })
250
+ });
251
+ }
252
+ /** Accept an incoming call. The brand primary — the button the thumb finds first. */
253
+ function CallCardAcceptButton({ "aria-label": ariaLabel, ...props }) {
254
+ return /* @__PURE__ */ jsx(CallCardAction, {
255
+ tone: "primary",
256
+ "aria-label": ariaLabel ?? "Accept",
257
+ ...props,
258
+ children: /* @__PURE__ */ jsx(Phone, {})
259
+ });
260
+ }
261
+ /** Dismiss an incoming call. Same clay and rotated handset as End Call. */
262
+ function CallCardIgnoreButton({ "aria-label": ariaLabel, ...props }) {
263
+ return /* @__PURE__ */ jsx(CallCardAction, {
264
+ tone: "danger",
265
+ "aria-label": ariaLabel ?? "Ignore",
266
+ ...props,
267
+ children: /* @__PURE__ */ jsx(Phone, { className: "rotate-[135deg]" })
268
+ });
269
+ }
270
+ const windowControlVariants = cva([
271
+ "grid shrink-0 place-items-center rounded-full outline-none transition-colors",
272
+ "bg-action-tertiary text-fg-secondary hover:bg-action-tertiary-hover",
273
+ "focus-visible:ring-2 focus-visible:ring-line-focus focus-visible:ring-offset-2 focus-visible:ring-offset-surface-overlay"
274
+ ], {
275
+ variants: { size: {
276
+ full: "absolute top-[15px] right-[15px] size-9 [&_svg]:size-4 md:top-[19px] md:right-[19px] md:size-10 md:[&_svg]:size-[18px]",
277
+ minimized: "size-[34px] [&_svg]:size-3.5 md:size-9 md:[&_svg]:size-[15px]"
278
+ } },
279
+ defaultVariants: { size: "full" }
280
+ });
281
+ /**
282
+ * The window chrome — Minimize in the full window (pinned top-right), Expand on
283
+ * the docked bar (leads the action row). Neutral and quiet by design: a window
284
+ * control is never destructive and must not pull the eye from End Call. Place it
285
+ * as the first child of {@link CallCardActions}; it self-positions per size.
286
+ */
287
+ function CallCardWindowControl({ className, "aria-label": ariaLabel, type = "button", ...props }) {
288
+ const { size } = useCallCardContext();
289
+ const minimized = size === "minimized";
290
+ return /* @__PURE__ */ jsx("button", {
291
+ "data-slot": "call-card-window-control",
292
+ type,
293
+ "aria-label": ariaLabel ?? (minimized ? "Expand" : "Minimize"),
294
+ className: cn(windowControlVariants({ size }), className),
295
+ ...props,
296
+ children: minimized ? /* @__PURE__ */ jsx(Maximize2, {}) : /* @__PURE__ */ jsx(Minimize2, {})
297
+ });
298
+ }
299
+ //#endregion
300
+ export { CallCard, CallCardAcceptButton, CallCardAction, CallCardActions, CallCardAvatar, CallCardEndCallButton, CallCardIdentity, CallCardIgnoreButton, CallCardMuteButton, CallCardName, CallCardOverlay, CallCardStatus, CallCardWindowControl, callCardVariants };
package/dist/carousel.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { t as cn } from "./cn-BI_4DMBf.js";
3
3
  import { useComponentSize } from "./size-context.js";
4
+ import { t as useReducedMotion } from "./use-reduced-motion-BDvOK14x.js";
4
5
  import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { cva } from "class-variance-authority";
@@ -31,6 +32,7 @@ function useCarousel() {
31
32
  }
32
33
  function Carousel({ orientation = "horizontal", opts, setApi, plugins, size, imageSize, className, children, ...props }) {
33
34
  const resolvedSize = useComponentSize(size);
35
+ const reducedMotion = useReducedMotion();
34
36
  const [carouselRef, api] = useEmblaCarousel({
35
37
  ...opts,
36
38
  axis: orientation === "horizontal" ? "x" : "y"
@@ -51,14 +53,14 @@ function Carousel({ orientation = "horizontal", opts, setApi, plugins, size, ima
51
53
  onSelect(api);
52
54
  }, [onSelect]);
53
55
  const scrollPrev = React.useCallback(() => {
54
- api?.scrollPrev();
55
- }, [api]);
56
+ api?.scrollPrev(reducedMotion);
57
+ }, [api, reducedMotion]);
56
58
  const scrollNext = React.useCallback(() => {
57
- api?.scrollNext();
58
- }, [api]);
59
+ api?.scrollNext(reducedMotion);
60
+ }, [api, reducedMotion]);
59
61
  const scrollTo = React.useCallback((index) => {
60
- api?.scrollTo(index);
61
- }, [api]);
62
+ api?.scrollTo(index, reducedMotion);
63
+ }, [api, reducedMotion]);
62
64
  const handleKeyDown = React.useCallback((event) => {
63
65
  const prevKey = orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
64
66
  const nextKey = orientation === "horizontal" ? "ArrowRight" : "ArrowDown";
@@ -138,7 +140,7 @@ function CarouselItem({ className, ...props }) {
138
140
  ...props
139
141
  });
140
142
  }
141
- const arrowVariants = cva(cn("absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center rounded-full text-fg-on-brand/95 shadow-1 transition-[transform,opacity] outline-none", glassChrome, "hover:scale-105 focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:scale-95 disabled:pointer-events-none disabled:opacity-40"), {
143
+ const arrowVariants = cva(cn("absolute top-1/2 z-10 grid -translate-y-1/2 place-items-center rounded-full text-fg-on-brand/95 shadow-1 transition-[opacity,scale] duration-[var(--duration-motion-press)] ease-gdt-out outline-none", glassChrome, "focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] active:scale-[0.97] motion-reduce:active:scale-100 disabled:pointer-events-none disabled:opacity-40"), {
142
144
  variants: {
143
145
  size: {
144
146
  sm: "size-8 [&_svg]:size-4",
@@ -287,6 +289,7 @@ const INDICATOR_OFFSET = {
287
289
  function CarouselIndicator({ className, count: countProp, selected: selectedProp, size: sizeProp, onSelect, ...props }) {
288
290
  const ctx = React.useContext(CarouselContext);
289
291
  const inheritedSize = useComponentSize(sizeProp);
292
+ const reducedMotion = useReducedMotion();
290
293
  const size = sizeProp ?? ctx?.size ?? inheritedSize;
291
294
  const count = countProp ?? ctx?.scrollSnaps.length ?? 0;
292
295
  const selected = selectedProp ?? ctx?.selectedIndex ?? 0;
@@ -307,7 +310,7 @@ function CarouselIndicator({ className, count: countProp, selected: selectedProp
307
310
  className: "overflow-hidden",
308
311
  style: { width: viewportWidth },
309
312
  children: /* @__PURE__ */ jsx("div", {
310
- className: "flex items-center transition-transform duration-300 ease-out",
313
+ className: "flex items-center transition-transform duration-300 ease-out motion-reduce:transition-none",
311
314
  style: {
312
315
  gap,
313
316
  transform: `translateX(${-start * step}px)`
@@ -325,7 +328,7 @@ function CarouselIndicator({ className, count: countProp, selected: selectedProp
325
328
  width: dot,
326
329
  height: dot,
327
330
  opacity: faded ? .3 : isActive ? 1 : .55,
328
- transform: faded ? "scale(0.6)" : "scale(1)"
331
+ transform: !reducedMotion && faded ? "scale(0.6)" : "scale(1)"
329
332
  }
330
333
  }, index);
331
334
  })