@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.
- package/dist/esm/components/actionable/Actionable.js +21 -20
- package/dist/esm/components/avatar/Avatar.js +22 -22
- package/dist/esm/components/avatar/AvatarWithTooltip.d.ts +46 -0
- package/dist/esm/components/avatar/AvatarWithTooltip.js +39 -0
- package/dist/esm/components/avatar/InteractiveAvatar.d.ts +65 -0
- package/dist/esm/components/avatar/InteractiveAvatar.js +39 -0
- package/dist/esm/components/avatar/parts/AvatarPair.js +1 -1
- package/dist/esm/components/avatar-group/AvatarGroup.context.d.ts +10 -0
- package/dist/esm/components/avatar-group/AvatarGroup.context.js +18 -0
- package/dist/esm/components/avatar-group/AvatarGroup.d.ts +60 -0
- package/dist/esm/components/avatar-group/AvatarGroup.js +60 -0
- package/dist/esm/components/avatar-group/AvatarGroup.variants.d.ts +32 -0
- package/dist/esm/components/avatar-group/AvatarGroup.variants.js +19 -0
- package/dist/esm/components/avatar-group/figma/AvatarGroup.figma.d.ts +10 -0
- package/dist/esm/components/avatar-group/parts/AvatarGroupCount.d.ts +54 -0
- package/dist/esm/components/avatar-group/parts/AvatarGroupCount.js +38 -0
- package/dist/esm/components/carousel/parts/CarouselContent.js +3 -3
- package/dist/esm/components/segmented-button-group/parts/ToggleButton.js +14 -14
- package/dist/esm/components/selectable-button-group/parts/SelectableButton.js +10 -10
- package/dist/esm/components/skeleton/Skeleton.d.ts +90 -0
- package/dist/esm/components/skeleton/Skeleton.js +47 -0
- package/dist/esm/components/skeleton/figma/SkeletonRectangular.figma.d.ts +7 -0
- package/dist/esm/components/skeleton/figma/SkeletonText.figma.d.ts +7 -0
- package/dist/esm/index.d.ts +6 -1
- package/dist/esm/index.js +204 -199
- package/i18n/fr-FR.json +1 -0
- package/package.json +10 -10
- package/src/agent-references/component-catalog.json +82 -0
- /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,
|
|
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 =
|
|
21
|
-
let { isFocusVisible: _ } =
|
|
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
|
-
}), [
|
|
27
|
-
onFocusChange:
|
|
27
|
+
}), [x, S] = n(!1), { focusProps: C } = a({
|
|
28
|
+
onFocusChange: S,
|
|
28
29
|
isDisabled: g.isDisabled
|
|
29
|
-
}), { buttonProps:
|
|
30
|
+
}), { buttonProps: w, isPressed: T } = l({
|
|
30
31
|
...g,
|
|
31
32
|
isDisabled: g.isDisabled,
|
|
32
33
|
elementType: f
|
|
33
|
-
}, r),
|
|
34
|
+
}, r), E = t(() => d({
|
|
34
35
|
isUnstyled: p,
|
|
35
36
|
className: m
|
|
36
|
-
}), [m, p]),
|
|
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(
|
|
42
|
+
let t = i(w, b, C, v);
|
|
42
43
|
t.onClick && t.onClick(e);
|
|
43
|
-
}, { onClick:
|
|
44
|
-
return /* @__PURE__ */ u(
|
|
45
|
-
...
|
|
46
|
-
onClick:
|
|
47
|
-
className:
|
|
48
|
-
...
|
|
49
|
-
...
|
|
50
|
-
...
|
|
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:
|
|
56
|
-
isPressed:
|
|
57
|
-
isFocused:
|
|
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
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
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
|
|
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
|
-
}),
|
|
16
|
-
let
|
|
17
|
-
variant:
|
|
18
|
-
size:
|
|
19
|
-
color:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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:
|
|
27
|
-
children: /* @__PURE__ */
|
|
28
|
-
ref:
|
|
26
|
+
color: a,
|
|
27
|
+
children: /* @__PURE__ */ o(s.Root, {
|
|
28
|
+
ref: d,
|
|
29
29
|
role: "img",
|
|
30
|
-
className:
|
|
30
|
+
className: m,
|
|
31
31
|
"data-dd-privacy": "allow",
|
|
32
|
-
...
|
|
32
|
+
...u
|
|
33
33
|
})
|
|
34
34
|
});
|
|
35
35
|
});
|
|
36
|
-
|
|
36
|
+
l.displayName = s.Root.displayName;
|
|
37
37
|
//#endregion
|
|
38
|
-
export {
|
|
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 ?
|
|
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,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 };
|