@payfit/unity-components 2.64.4 → 2.64.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.
Files changed (29) hide show
  1. package/dist/esm/components/actionable/Actionable.js +21 -20
  2. package/dist/esm/components/avatar/Avatar.js +22 -22
  3. package/dist/esm/components/avatar/AvatarWithTooltip.d.ts +46 -0
  4. package/dist/esm/components/avatar/AvatarWithTooltip.js +39 -0
  5. package/dist/esm/components/avatar/InteractiveAvatar.d.ts +65 -0
  6. package/dist/esm/components/avatar/InteractiveAvatar.js +39 -0
  7. package/dist/esm/components/avatar/parts/AvatarPair.js +1 -1
  8. package/dist/esm/components/avatar-group/AvatarGroup.context.d.ts +10 -0
  9. package/dist/esm/components/avatar-group/AvatarGroup.context.js +18 -0
  10. package/dist/esm/components/avatar-group/AvatarGroup.d.ts +60 -0
  11. package/dist/esm/components/avatar-group/AvatarGroup.js +60 -0
  12. package/dist/esm/components/avatar-group/AvatarGroup.variants.d.ts +32 -0
  13. package/dist/esm/components/avatar-group/AvatarGroup.variants.js +19 -0
  14. package/dist/esm/components/avatar-group/figma/AvatarGroup.figma.d.ts +10 -0
  15. package/dist/esm/components/avatar-group/parts/AvatarGroupCount.d.ts +54 -0
  16. package/dist/esm/components/avatar-group/parts/AvatarGroupCount.js +38 -0
  17. package/dist/esm/components/carousel/parts/CarouselContent.js +3 -3
  18. package/dist/esm/components/segmented-button-group/parts/ToggleButton.js +14 -14
  19. package/dist/esm/components/selectable-button-group/parts/SelectableButton.js +10 -10
  20. package/dist/esm/components/skeleton/Skeleton.d.ts +90 -0
  21. package/dist/esm/components/skeleton/Skeleton.js +47 -0
  22. package/dist/esm/components/skeleton/figma/SkeletonRectangular.figma.d.ts +7 -0
  23. package/dist/esm/components/skeleton/figma/SkeletonText.figma.d.ts +7 -0
  24. package/dist/esm/index.d.ts +6 -1
  25. package/dist/esm/index.js +204 -199
  26. package/i18n/fr-FR.json +1 -0
  27. package/package.json +10 -10
  28. package/src/agent-references/component-catalog.json +82 -0
  29. /package/dist/esm/components/{collapsible-group/figma/CollapsibleGroup.figma.d.ts → skeleton/figma/SkeletonCircular.figma.d.ts} +0 -0
@@ -1,6 +1,7 @@
1
1
  import { forwardRef as e, useMemo as t, useState as n } from "react";
2
2
  import { uyTv as r } from "@payfit/unity-themes";
3
- import { mergeProps as i, useFocus as a, useFocusVisible as o, useHover as s, useObjectRef as c } from "react-aria";
3
+ import { mergeProps as i, useFocus as a, useHover as o, useObjectRef as s } from "react-aria";
4
+ import { useFocusRing as c } from "react-aria/useFocusRing";
4
5
  import { useButton as l } from "react-aria/useButton";
5
6
  import { jsx as u } from "react/jsx-runtime";
6
7
  //#region src/components/actionable/Actionable.tsx
@@ -17,44 +18,44 @@ var d = r({
17
18
  defaultVariants: { isUnstyled: !1 }
18
19
  }), f = e((e, r) => {
19
20
  let { asElement: f = "div", isUnstyled: p = !1, className: m, children: h, ...g } = e;
20
- r = c(r);
21
- let { isFocusVisible: _ } = o(), { isHovered: v, hoverProps: y } = s({
21
+ r = s(r);
22
+ let { isFocusVisible: _, focusProps: v } = c(), { isHovered: y, hoverProps: b } = o({
22
23
  onHoverStart: g.onHoverStart,
23
24
  onHoverEnd: g.onHoverEnd,
24
25
  onHoverChange: g.onHoverChange,
25
26
  isDisabled: g.isDisabled
26
- }), [b, x] = n(!1), { focusProps: S } = a({
27
- onFocusChange: x,
27
+ }), [x, S] = n(!1), { focusProps: C } = a({
28
+ onFocusChange: S,
28
29
  isDisabled: g.isDisabled
29
- }), { buttonProps: C, isPressed: w } = l({
30
+ }), { buttonProps: w, isPressed: T } = l({
30
31
  ...g,
31
32
  isDisabled: g.isDisabled,
32
33
  elementType: f
33
- }, r), T = t(() => d({
34
+ }, r), E = t(() => d({
34
35
  isUnstyled: p,
35
36
  className: m
36
- }), [m, p]), E = f, D = (e) => {
37
+ }), [m, p]), D = f, O = (e) => {
37
38
  if (g.isDisabled) {
38
39
  e.preventDefault(), e.stopPropagation();
39
40
  return;
40
41
  }
41
- let t = i(C, y, S);
42
+ let t = i(w, b, C, v);
42
43
  t.onClick && t.onClick(e);
43
- }, { onClick: O, ...k } = i(C, y, S);
44
- return /* @__PURE__ */ u(E, {
45
- ...k,
46
- onClick: D,
47
- className: T,
48
- ...w && { "data-pressed": w },
49
- ...b && { "data-focused": b },
50
- ...v && { "data-hovered": v },
44
+ }, { onClick: k, ...A } = i(w, b, C, v);
45
+ return /* @__PURE__ */ u(D, {
46
+ ...A,
47
+ onClick: O,
48
+ className: E,
49
+ ...T && { "data-pressed": T },
50
+ ...x && { "data-focused": x },
51
+ ...y && { "data-hovered": y },
51
52
  ...g.isDisabled && { "data-disabled": g.isDisabled },
52
53
  ..._ && { "data-focus-visible": _ },
53
54
  ref: r,
54
55
  children: typeof h == "function" ? h({
55
- isHovered: v,
56
- isPressed: w,
57
- isFocused: b,
56
+ isHovered: y,
57
+ isPressed: T,
58
+ isFocused: x,
58
59
  isDisabled: !!g.isDisabled,
59
60
  isFocusVisible: _,
60
61
  isPending: !1,
@@ -1,38 +1,38 @@
1
1
  import { AvatarProvider as e } from "./Avatar.context.js";
2
2
  import { avatarBase as t } from "./Avatar.variants.js";
3
- import * as n from "react";
4
- import { uyTv as r } from "@payfit/unity-themes";
5
- import { jsx as i } from "react/jsx-runtime";
6
- import * as a from "@radix-ui/react-avatar";
3
+ import { useAvatarGroupContext as n } from "../avatar-group/AvatarGroup.context.js";
4
+ import * as r from "react";
5
+ import { uyMerge as i, uyTv as a } from "@payfit/unity-themes";
6
+ import { jsx as o } from "react/jsx-runtime";
7
+ import * as s from "@radix-ui/react-avatar";
7
8
  //#region src/components/avatar/Avatar.tsx
8
- var o = r({
9
+ var c = a({
9
10
  extend: t,
10
11
  base: "uy:inline-block uy:relative uy:shrink-0",
11
12
  defaultVariants: {
12
13
  size: "md",
13
14
  variant: "circle"
14
15
  }
15
- }), s = n.forwardRef(({ size: t = "md", variant: n = "circle", color: r, className: s, ...c }, l) => {
16
- let u = o({
17
- variant: n,
18
- size: t,
19
- color: r,
20
- className: s
21
- });
22
- return /* @__PURE__ */ i(e, {
23
- variant: n,
24
- size: t,
16
+ }), l = r.forwardRef(({ size: t, variant: r = "circle", color: a, className: l, ...u }, d) => {
17
+ let f = n(), p = t ?? f?.defaultSize ?? "md", m = i(c({
18
+ variant: r,
19
+ size: p,
20
+ color: a
21
+ }), f?.variant === "stack" ? "uy:outline-1 uy:outline-solid uy:outline-grayscale-l0" : void 0, l);
22
+ return /* @__PURE__ */ o(e, {
23
+ variant: r,
24
+ size: p,
25
25
  hasPair: !1,
26
- color: r,
27
- children: /* @__PURE__ */ i(a.Root, {
28
- ref: l,
26
+ color: a,
27
+ children: /* @__PURE__ */ o(s.Root, {
28
+ ref: d,
29
29
  role: "img",
30
- className: u,
30
+ className: m,
31
31
  "data-dd-privacy": "allow",
32
- ...c
32
+ ...u
33
33
  })
34
34
  });
35
35
  });
36
- s.displayName = a.Root.displayName;
36
+ l.displayName = s.Root.displayName;
37
37
  //#endregion
38
- export { s as Avatar };
38
+ export { l as Avatar };
@@ -0,0 +1,46 @@
1
+ import { AvatarProps } from './Avatar.js';
2
+ import * as React from 'react';
3
+ /** Props for a focusable Avatar that exposes a hover- and focus-triggered tooltip. */
4
+ export type AvatarWithTooltipProps = AvatarProps & {
5
+ /** Text shown when the avatar receives hover or keyboard focus. */
6
+ tooltip: string;
7
+ };
8
+ /**
9
+ * Makes an Avatar focusable so people can identify it with a tooltip.
10
+ *
11
+ * Use `AvatarWithTooltip` when the avatar needs hover and keyboard-focus
12
+ * feedback but does not perform an action. Use `InteractiveAvatar` when the
13
+ * avatar also needs a press action.
14
+ * @param props - Avatar content, accessible naming, visual options, and tooltip text.
15
+ * @param props.tooltip - Text shown on hover and keyboard focus.
16
+ * @param props.aria-label - Accessible name announced for the avatar trigger.
17
+ * @param props.aria-labelledby - ID of visible text that names the avatar trigger.
18
+ * @param props.variant - Avatar shape: `circle` for people or `square` for entities.
19
+ * @param props.size - Avatar size. The AvatarGroup context supplies a responsive
20
+ * size when this prop is omitted.
21
+ * @see {@link AvatarWithTooltipProps} for all available props.
22
+ * @see {@link InteractiveAvatar} for an actionable avatar with the same tooltip behavior.
23
+ * @example
24
+ * ```tsx
25
+ * import {
26
+ * AvatarFallback,
27
+ * AvatarWithTooltip,
28
+ * } from '@payfit/unity-components'
29
+ *
30
+ * export function EmployeeAvatar() {
31
+ * return (
32
+ * <AvatarWithTooltip tooltip="Alex Wu" aria-label="Alex Wu">
33
+ * <AvatarFallback variant="initials">AW</AvatarFallback>
34
+ * </AvatarWithTooltip>
35
+ * )
36
+ * }
37
+ * ```
38
+ * @remarks
39
+ * The component renders a real button as the tooltip trigger, but it does not
40
+ * attach press callbacks and keeps the default cursor. The trigger receives
41
+ * the avatar's focus ring and the tooltip opens on hover or keyboard focus.
42
+ * Provide `aria-label` or `aria-labelledby`; the visible Avatar is hidden from
43
+ * assistive technologies because the outer trigger owns the accessible name.
44
+ */
45
+ declare const AvatarWithTooltip: React.ForwardRefExoticComponent<AvatarWithTooltipProps & React.RefAttributes<HTMLButtonElement>>;
46
+ export { AvatarWithTooltip };
@@ -0,0 +1,39 @@
1
+ import { Actionable as e } from "../actionable/Actionable.js";
2
+ import { Tooltip as t } from "../tooltip/Tooltip.js";
3
+ import { avatarBase as n } from "./Avatar.variants.js";
4
+ import { useAvatarGroupContext as r } from "../avatar-group/AvatarGroup.context.js";
5
+ import { Avatar as i } from "./Avatar.js";
6
+ import * as a from "react";
7
+ import { uyMerge as o } from "@payfit/unity-themes";
8
+ import { jsx as s } from "react/jsx-runtime";
9
+ //#region src/components/avatar/AvatarWithTooltip.tsx
10
+ var c = a.forwardRef(({ tooltip: a, "aria-label": c, "aria-labelledby": l, "aria-describedby": u, "aria-details": d, className: f, size: p, variant: m, ...h }, g) => {
11
+ let _ = r(), v = m ?? "circle", y = p ?? _?.defaultSize ?? "md", b = c ? { "aria-label": c } : { "aria-labelledby": l ?? "" };
12
+ return /* @__PURE__ */ s(t, {
13
+ title: a,
14
+ children: /* @__PURE__ */ s(e, {
15
+ ref: g,
16
+ asElement: "button",
17
+ type: "button",
18
+ "aria-label": c,
19
+ "aria-labelledby": l,
20
+ "aria-describedby": u,
21
+ "aria-details": d,
22
+ className: o(n({
23
+ variant: v,
24
+ size: y
25
+ }), "uy:cursor-default uy:leading-[0] uy:outline-none uy:data-[focus-visible=true]:ring-2 uy:data-[focus-visible=true]:ring-utility-focus-ring uy:data-[focus-visible=true]:ring-offset-2"),
26
+ children: /* @__PURE__ */ s(i, {
27
+ ...h,
28
+ size: p,
29
+ variant: m,
30
+ className: f,
31
+ ...b,
32
+ "aria-hidden": !0
33
+ })
34
+ })
35
+ });
36
+ });
37
+ c.displayName = "AvatarWithTooltip";
38
+ //#endregion
39
+ export { c as AvatarWithTooltip };
@@ -0,0 +1,65 @@
1
+ import { ActionableProps } from '../actionable/Actionable.js';
2
+ import { AvatarProps } from './Avatar.js';
3
+ import * as React from 'react';
4
+ /** Props for an actionable Avatar with an accessible tooltip. */
5
+ export type InteractiveAvatarProps = Omit<AvatarProps, 'aria-label' | 'aria-labelledby'> & {
6
+ /** Text shown on hover and keyboard focus to describe the action. */
7
+ tooltip: string;
8
+ /** Accessible name for the button. */
9
+ 'aria-label': string;
10
+ /** Callback invoked when the avatar is pressed. */
11
+ onPress: NonNullable<ActionableProps['onPress']>;
12
+ } & Pick<ActionableProps, 'onPressStart' | 'onPressEnd' | 'onPressChange'>;
13
+ /**
14
+ * Combines an actionable Avatar with a tooltip that describes its action.
15
+ *
16
+ * Use `InteractiveAvatar` when a person or entity avatar activates an action,
17
+ * opens a Popover, or triggers navigation. Pass `onPress` for the action and
18
+ * provide the same action description through `tooltip` and `aria-label`.
19
+ * @param props - Avatar content, visual options, accessible naming, tooltip text, and press callbacks.
20
+ * @param props.tooltip - Text shown on hover and keyboard focus.
21
+ * @param props.aria-label - Accessible name announced for the button.
22
+ * @param props.onPress - Callback invoked after a pointer or keyboard press.
23
+ * @param props.onPressStart - Callback invoked when a press starts.
24
+ * @param props.onPressEnd - Callback invoked when a press ends.
25
+ * @param props.onPressChange - Callback invoked when the pressed state changes.
26
+ * @param props.variant - Avatar shape: `circle` for people or `square` for entities.
27
+ * @param props.size - Avatar size. The AvatarGroup context supplies a responsive
28
+ * size when this prop is omitted.
29
+ * @see {@link InteractiveAvatarProps} for all available props.
30
+ * @see {@link AvatarWithTooltip} for a focusable avatar without an action.
31
+ * @example
32
+ * ```tsx
33
+ * import {
34
+ * AvatarFallback,
35
+ * InteractiveAvatar,
36
+ * } from '@payfit/unity-components'
37
+ *
38
+ * export function EmployeeAction({ openProfile }: { openProfile: () => void }) {
39
+ * return (
40
+ * <InteractiveAvatar
41
+ * tooltip="Open Alex Wu's profile"
42
+ * aria-label="Open Alex Wu's profile"
43
+ * onPress={openProfile}
44
+ * >
45
+ * <AvatarFallback variant="initials">AW</AvatarFallback>
46
+ * </InteractiveAvatar>
47
+ * )
48
+ * }
49
+ * ```
50
+ * @remarks
51
+ * The component renders a real button and supports React Aria press
52
+ * callbacks, including keyboard activation. Its focus ring follows the
53
+ * selected `variant`. Provide `aria-label` because the inner visual Avatar is
54
+ * hidden from assistive technologies; use `PopoverTrigger` when the action
55
+ * opens a Popover.
56
+ */
57
+ declare const InteractiveAvatar: React.ForwardRefExoticComponent<Omit<AvatarProps, "aria-label" | "aria-labelledby"> & {
58
+ /** Text shown on hover and keyboard focus to describe the action. */
59
+ tooltip: string;
60
+ /** Accessible name for the button. */
61
+ 'aria-label': string;
62
+ /** Callback invoked when the avatar is pressed. */
63
+ onPress: NonNullable<ActionableProps["onPress"]>;
64
+ } & Pick<ActionableProps, "onPressStart" | "onPressEnd" | "onPressChange"> & React.RefAttributes<HTMLButtonElement>>;
65
+ export { InteractiveAvatar };
@@ -0,0 +1,39 @@
1
+ import { Actionable as e } from "../actionable/Actionable.js";
2
+ import { Tooltip as t } from "../tooltip/Tooltip.js";
3
+ import { avatarBase as n } from "./Avatar.variants.js";
4
+ import { useAvatarGroupContext as r } from "../avatar-group/AvatarGroup.context.js";
5
+ import { Avatar as i } from "./Avatar.js";
6
+ import * as a from "react";
7
+ import { uyMerge as o } from "@payfit/unity-themes";
8
+ import { jsx as s } from "react/jsx-runtime";
9
+ //#region src/components/avatar/InteractiveAvatar.tsx
10
+ var c = a.forwardRef(({ tooltip: a, onPress: c, onPressStart: l, onPressEnd: u, onPressChange: d, children: f, ...p }, m) => {
11
+ let h = r();
12
+ return /* @__PURE__ */ s(t, {
13
+ title: a,
14
+ children: /* @__PURE__ */ s(e, {
15
+ ref: m,
16
+ asElement: "button",
17
+ type: "button",
18
+ className: o(n({
19
+ variant: p.variant ?? "circle",
20
+ size: p.size ?? h?.defaultSize ?? "md"
21
+ }), "uy:cursor-pointer uy:leading-[0] uy:outline-none uy:data-[focus-visible=true]:ring-2 uy:data-[focus-visible=true]:ring-utility-focus-ring uy:data-[focus-visible=true]:ring-offset-2"),
22
+ onPress: c,
23
+ onPressStart: l,
24
+ onPressEnd: u,
25
+ onPressChange: d,
26
+ "aria-label": p["aria-label"],
27
+ "aria-describedby": p["aria-describedby"],
28
+ "aria-details": p["aria-details"],
29
+ children: /* @__PURE__ */ s(i, {
30
+ ...p,
31
+ "aria-hidden": !0,
32
+ children: f
33
+ })
34
+ })
35
+ });
36
+ });
37
+ c.displayName = "InteractiveAvatar";
38
+ //#endregion
39
+ export { c as InteractiveAvatar };
@@ -24,7 +24,7 @@ var s = i({
24
24
  isHidden: !1
25
25
  }
26
26
  }), c = r.forwardRef(({ variant: n, isHidden: r, children: i, ...c }, l) => {
27
- let { size: u } = t(), d = u === "xl", f = d ? "sm" : "xs", p = d ? 0 : 4, m = s({
27
+ let { size: u } = t(), d = u === "xl", f = d ? "sm" : "xs", p = d ? 8 : 4, m = s({
28
28
  variant: n,
29
29
  size: f,
30
30
  isHidden: r
@@ -0,0 +1,10 @@
1
+ import { AvatarProps } from '../avatar/Avatar.js';
2
+ type AvatarGroupContextValue = {
3
+ defaultSize: NonNullable<AvatarProps['size']>;
4
+ variant: 'pile' | 'stack';
5
+ };
6
+ export declare function AvatarGroupProvider({ defaultSize, variant, children, }: AvatarGroupContextValue & {
7
+ children: React.ReactNode;
8
+ }): import("react/jsx-runtime").JSX.Element;
9
+ export declare function useAvatarGroupContext(): AvatarGroupContextValue | null;
10
+ export {};
@@ -0,0 +1,18 @@
1
+ import { createContext as e, useContext as t } from "react";
2
+ import { jsx as n } from "react/jsx-runtime";
3
+ //#region src/components/avatar-group/AvatarGroup.context.tsx
4
+ var r = e(null);
5
+ function i({ defaultSize: e, variant: t, children: i }) {
6
+ return /* @__PURE__ */ n(r.Provider, {
7
+ value: {
8
+ defaultSize: e,
9
+ variant: t
10
+ },
11
+ children: i
12
+ });
13
+ }
14
+ function a() {
15
+ return t(r);
16
+ }
17
+ //#endregion
18
+ export { i as AvatarGroupProvider, a as useAvatarGroupContext };
@@ -0,0 +1,60 @@
1
+ import * as React from 'react';
2
+ /** Controls whether avatars are separated or overlap one another. */
3
+ export type AvatarGroupVariant = 'pile' | 'stack';
4
+ /** Renders one avatar from an item in the AvatarGroup render-prop API. */
5
+ export type AvatarGroupRenderItem<TItem> = (item: TItem, index: number) => React.ReactNode;
6
+ /** Renders the truncation indicator for a data-driven AvatarGroup. */
7
+ export type AvatarGroupRenderCount<TItem> = (count: number, truncatedItems: TItem[]) => React.ReactNode;
8
+ type AvatarGroupBaseProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'className' | 'style'> & {
9
+ /**
10
+ * Controls the relationship between adjacent avatars.
11
+ * @default 'stack'
12
+ * @remarks `stack` overlaps avatars and adds a separating outline; `pile`
13
+ * keeps avatars separated with the design-system gap.
14
+ */
15
+ variant?: AvatarGroupVariant;
16
+ /**
17
+ * Maximum number of visible slots, including the truncation count.
18
+ * @default 4
19
+ * @remarks Set this to `-1` to disable truncation, or to an integer of at
20
+ * least 2. When `items` exceeds the limit, the group renders `maxItems - 1`
21
+ * avatars and one non-interactive `AvatarGroupCount` status.
22
+ */
23
+ maxItems?: number;
24
+ };
25
+ type AvatarGroupStaticProps = AvatarGroupBaseProps & {
26
+ items?: never;
27
+ getItemKey?: never;
28
+ renderCount?: never;
29
+ /**
30
+ * Static Avatar children for the Avatar Group. You must pass a minimum of 2 Avatars
31
+ */
32
+ children: React.ReactNode;
33
+ };
34
+ type AvatarGroupDynamicProps<TItem> = AvatarGroupBaseProps & {
35
+ /**
36
+ * Data used by the render-prop API.
37
+ * @remarks Provide at least two items and pair this prop with a render
38
+ * function as `children`. The group validates the minimum and truncates
39
+ * items beyond `maxItems`.
40
+ */
41
+ items: readonly TItem[];
42
+ /** Returns a stable React key for a rendered item. */
43
+ getItemKey: (item: TItem, index: number) => React.Key;
44
+ /**
45
+ * Renders the truncation indicator for the data-driven API.
46
+ * @remarks The callback receives the number of hidden items and the exact
47
+ * truncated item subset. Return an `AvatarGroupCount` with `isInteractive`
48
+ * when the count should trigger a Popover or another disclosure.
49
+ */
50
+ renderCount?: AvatarGroupRenderCount<TItem>;
51
+ /**
52
+ * Renders one Avatar for each item in the data-driven API.
53
+ * @remarks The callback receives `(item, index)` and must return the Avatar
54
+ * content for that item.
55
+ */
56
+ children: AvatarGroupRenderItem<TItem>;
57
+ };
58
+ export type AvatarGroupProps<TItem = unknown> = AvatarGroupStaticProps | AvatarGroupDynamicProps<TItem>;
59
+ declare const AvatarGroupWithGenerics: <TItem = unknown>(props: AvatarGroupProps<TItem> & React.RefAttributes<HTMLDivElement>) => React.ReactElement | null;
60
+ export { AvatarGroupWithGenerics as AvatarGroup };
@@ -0,0 +1,60 @@
1
+ import { AvatarGroupProvider as e } from "./AvatarGroup.context.js";
2
+ import { useResponsiveValue as t } from "../../hooks/use-responsive-value.js";
3
+ import { avatarGroup as n } from "./AvatarGroup.variants.js";
4
+ import { AvatarGroupCount as r } from "./parts/AvatarGroupCount.js";
5
+ import * as i from "react";
6
+ import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ //#region src/components/avatar-group/AvatarGroup.tsx
8
+ var c = 2, l = 4, u = 1, d = -1;
9
+ function f(e) {
10
+ if (!Number.isInteger(e) || e !== d && e < c) throw Error(`AvatarGroup maxItems must be -1 or an integer greater than or equal to ${c}.`);
11
+ }
12
+ function p({ items: e, maxItems: t, getItemKey: n, renderItem: l, renderCount: f }) {
13
+ if (e.length < c) throw Error(`AvatarGroup expects at least ${c} items.`);
14
+ let p = t !== d && e.length > t, m = p ? t - u : e.length;
15
+ return /* @__PURE__ */ s(a, { children: [(p ? e.slice(0, m) : e).map((e, t) => /* @__PURE__ */ o(i.Fragment, { children: l(e, t) }, n(e, t))), p ? f?.(e.length - m, e.slice(m)) ?? /* @__PURE__ */ o(r, { count: e.length - m }) : null] });
16
+ }
17
+ function m(e, t) {
18
+ if (typeof e == "function") throw Error("AvatarGroup requires items, getItemKey, and a render function as children when using the dynamic API.");
19
+ let n = i.Children.count(e);
20
+ if (n < c || t !== d && n > t) {
21
+ let e = t === d ? `at least ${c}` : `between ${c} and ${t}`;
22
+ throw Error(`AvatarGroup expects ${e} visible children; received ${n}. Use the dynamic API for automatic truncation.`);
23
+ }
24
+ return e;
25
+ }
26
+ function h({ variant: r = "stack", maxItems: i = l, items: a, getItemKey: s, renderCount: c, children: u, "aria-label": d, ...h }, g) {
27
+ let _ = t({
28
+ base: "sm",
29
+ md: "md"
30
+ });
31
+ f(i);
32
+ let v = a !== void 0, y;
33
+ if (v) {
34
+ if (typeof u != "function" || typeof s != "function") throw Error("AvatarGroup dynamic API requires items, getItemKey, and a render function as children.");
35
+ y = p({
36
+ items: a,
37
+ maxItems: i,
38
+ getItemKey: s,
39
+ renderItem: u,
40
+ renderCount: c
41
+ });
42
+ } else y = m(u, i);
43
+ return /* @__PURE__ */ o(e, {
44
+ defaultSize: _,
45
+ variant: r,
46
+ children: /* @__PURE__ */ o("div", {
47
+ ref: g,
48
+ ...h,
49
+ role: "group",
50
+ "aria-label": d,
51
+ className: n({ variant: r }),
52
+ children: y
53
+ })
54
+ });
55
+ }
56
+ var g = i.forwardRef(h);
57
+ g.displayName = "AvatarGroup";
58
+ var _ = g;
59
+ //#endregion
60
+ export { _ as AvatarGroup };
@@ -0,0 +1,32 @@
1
+ export declare const avatarGroup: import('tailwind-variants').TVReturnType<{
2
+ variant: {
3
+ stack: "uy:[&>*]:relative uy:[&>*+*]:-ml-100";
4
+ pile: "uy:gap-50";
5
+ };
6
+ }, undefined, "uy:relative uy:isolate uy:flex uy:items-center uy:leading-[0] uy:group/avatar-group", {
7
+ variant: {
8
+ stack: "uy:[&>*]:relative uy:[&>*+*]:-ml-100";
9
+ pile: "uy:gap-50";
10
+ };
11
+ }, undefined, import('tailwind-variants').TVReturnTypeLike<{
12
+ variant: {
13
+ stack: "uy:[&>*]:relative uy:[&>*+*]:-ml-100";
14
+ pile: "uy:gap-50";
15
+ };
16
+ }, undefined>>;
17
+ export declare const avatarGroupCount: import('tailwind-variants').TVReturnType<{
18
+ size: {
19
+ sm: "uy:size-300";
20
+ md: "uy:size-400";
21
+ };
22
+ }, undefined, "uy:inline-flex uy:size-400 uy:shrink-0 uy:items-center uy:justify-center uy:rounded-circle uy:bg-surface-neutral-lowest uy:text-content-neutral uy:typography-body-small-strong uy:border uy:border-solid uy:border-content-inverted", {
23
+ size: {
24
+ sm: "uy:size-300";
25
+ md: "uy:size-400";
26
+ };
27
+ }, undefined, import('tailwind-variants').TVReturnTypeLike<{
28
+ size: {
29
+ sm: "uy:size-300";
30
+ md: "uy:size-400";
31
+ };
32
+ }, undefined>>;
@@ -0,0 +1,19 @@
1
+ import { uyTv as e } from "@payfit/unity-themes";
2
+ //#region src/components/avatar-group/AvatarGroup.variants.ts
3
+ var t = e({
4
+ base: "uy:relative uy:isolate uy:flex uy:items-center uy:leading-[0] uy:group/avatar-group",
5
+ variants: { variant: {
6
+ stack: "uy:[&>*]:relative uy:[&>*+*]:-ml-100",
7
+ pile: "uy:gap-50"
8
+ } },
9
+ defaultVariants: { variant: "stack" }
10
+ }), n = e({
11
+ base: "uy:inline-flex uy:size-400 uy:shrink-0 uy:items-center uy:justify-center uy:rounded-circle uy:bg-surface-neutral-lowest uy:text-content-neutral uy:typography-body-small-strong uy:border uy:border-solid uy:border-content-inverted",
12
+ variants: { size: {
13
+ sm: "uy:size-300",
14
+ md: "uy:size-400"
15
+ } },
16
+ defaultVariants: { size: "md" }
17
+ });
18
+ //#endregion
19
+ export { t as avatarGroup, n as avatarGroupCount };
@@ -0,0 +1,10 @@
1
+ import { default as figma } from 'figma';
2
+ declare const _default: {
3
+ example: figma.TemplateStringResult;
4
+ imports: string[];
5
+ id: string;
6
+ metadata: {
7
+ nestable: boolean;
8
+ };
9
+ };
10
+ export default _default;
@@ -0,0 +1,54 @@
1
+ import { ActionableProps } from '../../actionable/Actionable.js';
2
+ import * as React from 'react';
3
+ export interface AvatarGroupCountProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, keyof React.DOMAttributes<HTMLSpanElement>> {
4
+ /** Number of avatars hidden by truncation. */
5
+ count: number;
6
+ /** Overrides the localized accessible label announced for the count. */
7
+ 'aria-label'?: string;
8
+ /**
9
+ * Renders the count as a keyboard-accessible button.
10
+ * @default false
11
+ */
12
+ isInteractive?: boolean;
13
+ /** Action invoked when an interactive count is pressed. */
14
+ onPress?: ActionableProps['onPress'];
15
+ onPressStart?: ActionableProps['onPressStart'];
16
+ onPressEnd?: ActionableProps['onPressEnd'];
17
+ onPressChange?: ActionableProps['onPressChange'];
18
+ children?: React.ReactNode;
19
+ }
20
+ /**
21
+ * Displays the localized count of avatars hidden by an AvatarGroup.
22
+ * Use the default status presentation for automatic truncation. Set
23
+ * `isInteractive` to `true` when composing the count with `PopoverTrigger` or
24
+ * another disclosure that reveals the hidden avatars.
25
+ * @param props - Count content, interaction state, and press callbacks.
26
+ * @param props.count - Number of hidden avatars.
27
+ * @param props.aria-label - Optional accessible-label override. When omitted,
28
+ * the component uses the localized hidden-member count.
29
+ * @param props.isInteractive - Renders a button instead of a status.
30
+ * @param props.children - Optional visible content; defaults to `+{count}`.
31
+ * @param props.onPress - Callback invoked when an interactive count is pressed.
32
+ * @see {@link AvatarGroupCountProps} for all available props.
33
+ * @example
34
+ * ```tsx
35
+ * import {
36
+ * AvatarGroupCount,
37
+ * Popover,
38
+ * PopoverTrigger,
39
+ * } from '@payfit/unity-components'
40
+ *
41
+ * <PopoverTrigger>
42
+ * <AvatarGroupCount count={3} isInteractive />
43
+ * <Popover title="Other members" isTitleSrOnly>
44
+ * <p>Three hidden members</p>
45
+ * </Popover>
46
+ * </PopoverTrigger>
47
+ * ```
48
+ * @remarks
49
+ * The default branch renders `role="status"` with a localized label such as
50
+ * “3 more members”. The interactive branch renders a real button with the
51
+ * same accessible label and supports React Aria press callbacks.
52
+ */
53
+ declare const AvatarGroupCount: React.ForwardRefExoticComponent<AvatarGroupCountProps & React.RefAttributes<HTMLSpanElement | HTMLButtonElement>>;
54
+ export { AvatarGroupCount };
@@ -0,0 +1,38 @@
1
+ import { Actionable as e } from "../../actionable/Actionable.js";
2
+ import { useAvatarGroupContext as t } from "../AvatarGroup.context.js";
3
+ import { avatarGroupCount as n } from "../AvatarGroup.variants.js";
4
+ import * as r from "react";
5
+ import { cn as i } from "@payfit/unity-themes";
6
+ import { jsx as a } from "react/jsx-runtime";
7
+ import { useIntl as o } from "react-intl";
8
+ //#region src/components/avatar-group/parts/AvatarGroupCount.tsx
9
+ var s = r.forwardRef(({ count: r, "aria-label": s, children: c, className: l, isInteractive: u = !1, onPress: d, onPressStart: f, onPressEnd: p, onPressChange: m, ...h }, g) => {
10
+ let _ = t(), v = o(), y = c ?? `+${r}`, b = v.formatMessage({
11
+ id: "unity:component:avatar-group:more-members-label",
12
+ defaultMessage: "{count, plural, one {# more member} other {# more members}}"
13
+ }, { count: r }), x = s ?? b, S = i(n({ size: _?.defaultSize === "sm" ? "sm" : "md" }), "uy:relative uy:z-10", u && "uy:cursor-pointer uy:outline-none uy:data-[focus-visible=true]:ring-2 uy:data-[focus-visible=true]:ring-utility-focus-ring uy:data-[focus-visible=true]:ring-offset-2", l);
14
+ return u ? /* @__PURE__ */ a(e, {
15
+ ref: g,
16
+ asElement: "button",
17
+ isUnstyled: !0,
18
+ type: "button",
19
+ "aria-label": x,
20
+ className: S,
21
+ onPress: d,
22
+ onPressStart: f,
23
+ onPressEnd: p,
24
+ onPressChange: m,
25
+ ...h,
26
+ children: y
27
+ }) : /* @__PURE__ */ a("span", {
28
+ ref: g,
29
+ role: "status",
30
+ "aria-label": x,
31
+ className: S,
32
+ ...h,
33
+ children: y
34
+ });
35
+ });
36
+ s.displayName = "AvatarGroupCount";
37
+ //#endregion
38
+ export { s as AvatarGroupCount };