@payfit/unity-components 3.2.3 → 3.2.5

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/ai-kit.js +7 -1
  2. package/dist/esm/core/components/icon-button/CircularIconButton.js +5 -4
  3. package/dist/esm/modules/ai-kit/components/ai-button/AIButton.js +25 -6
  4. package/dist/esm/modules/ai-kit/components/ai-composer/AIComposer.context.d.ts +27 -0
  5. package/dist/esm/modules/ai-kit/components/ai-composer/AIComposer.context.js +11 -0
  6. package/dist/esm/modules/ai-kit/components/ai-composer/AIComposer.d.ts +43 -0
  7. package/dist/esm/modules/ai-kit/components/ai-composer/AIComposer.js +52 -0
  8. package/dist/esm/modules/ai-kit/components/ai-composer/AIComposer.variants.d.ts +34 -0
  9. package/dist/esm/modules/ai-kit/components/ai-composer/AIComposer.variants.js +68 -0
  10. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAction.d.ts +24 -0
  11. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAction.js +27 -0
  12. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerActions.d.ts +25 -0
  13. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerActions.js +25 -0
  14. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAlert.d.ts +31 -0
  15. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAlert.js +37 -0
  16. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAttachment.d.ts +23 -4
  17. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAttachment.js +30 -28
  18. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAttachmentsGroup.d.ts +13 -0
  19. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerAttachmentsGroup.js +19 -7
  20. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerSubmitAction.d.ts +36 -0
  21. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerSubmitAction.js +56 -0
  22. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerTextArea.d.ts +20 -0
  23. package/dist/esm/modules/ai-kit/components/ai-composer/parts/AIComposerTextArea.js +82 -0
  24. package/dist/esm/modules/ai-kit/components/ai-trigger-button/AITriggerButton.js +1 -14
  25. package/dist/esm/modules/ai-kit/index.d.ts +7 -0
  26. package/dist/esm/modules/ai-kit/utils/ai-gradient-effect.d.ts +24 -35
  27. package/dist/esm/modules/ai-kit/utils/ai-gradient-effect.js +25 -67
  28. package/package.json +7 -7
  29. package/src/agent-references/component-catalog.json +24 -0
@@ -1,16 +1,17 @@
1
1
  import { CircularIconButton as e } from "../../../../../core/components/icon-button/CircularIconButton.js";
2
2
  import { Text as t } from "../../../../../core/components/text/Text.js";
3
- import { forwardRef as n } from "react";
4
- import { uyMerge as r, uyTv as i } from "@payfit/unity-themes";
5
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
- import { useIntl as s } from "react-intl";
7
- import { Icon as c } from "@payfit/unity-icons";
8
- import { Tag as l } from "react-aria-components/TagGroup";
3
+ import { useAIComposerContext as n } from "../AIComposer.context.js";
4
+ import { forwardRef as r } from "react";
5
+ import { uyMerge as i, uyTv as a } from "@payfit/unity-themes";
6
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ import { useIntl as c } from "react-intl";
8
+ import { Icon as l } from "@payfit/unity-icons";
9
+ import { Tag as u } from "react-aria-components/TagGroup";
9
10
  //#region src/modules/ai-kit/components/ai-composer/parts/AIComposerAttachment.tsx
10
- var u = i({
11
+ var d = a({
11
12
  base: [
12
13
  "uy:group",
13
- "uy:inline-flex uy:min-w-0 uy:items-center uy:justify-center uy:gap-25",
14
+ "uy:inline-flex uy:shrink-0 uy:items-center uy:justify-center uy:gap-25",
14
15
  "uy:rounded-pill uy:bg-surface-neutral-lowest-enabled uy:pl-75 uy:pr-25 uy:text-content-neutral-enabled",
15
16
  "uy:enabled:hover:bg-surface-neutral-lowest-hover uy:enabled:hover:text-content-neutral-hover",
16
17
  "uy:enabled:active:bg-surface-neutral-lowest-active uy:enabled:active:text-content-neutral-active",
@@ -25,36 +26,37 @@ var u = i({
25
26
  label: "uy:min-w-0 uy:flex-1 uy:truncate",
26
27
  removeButton: "uy:data-[disabled=\"true\"]:bg-surface-neutral-lowest-disabled"
27
28
  }
28
- }), d = n(({ children: n, icon: i, isDisabled: d, maxCharactersTruncation: f = 12, className: p, ...m }, h) => {
29
- let g = s(), _ = u();
30
- return /* @__PURE__ */ o(l, {
31
- ref: h,
32
- ...m,
33
- isDisabled: d,
34
- className: r(_.base(), p),
29
+ }), f = r(({ children: r, icon: a, isDisabled: f, maxCharactersTruncation: p = 12, className: m, ...h }, g) => {
30
+ let _ = c(), v = n().state, y = f || v === "disabled" || v === "loading", b = h.textValue ?? (typeof r == "string" ? r : void 0), x = d();
31
+ return /* @__PURE__ */ s(u, {
32
+ ref: g,
33
+ ...h,
34
+ isDisabled: y,
35
+ textValue: b,
36
+ className: i(x.base(), m),
35
37
  children: [
36
- /* @__PURE__ */ a(c, {
37
- src: i,
38
+ /* @__PURE__ */ o(l, {
39
+ src: a,
38
40
  size: 20,
39
- color: d ? "content.neutral.lowest.disabled" : "content.neutral.lowest",
41
+ color: y ? "content.neutral.lowest.disabled" : "content.neutral.lowest",
40
42
  role: "presentation",
41
43
  "aria-hidden": "true"
42
44
  }),
43
- /* @__PURE__ */ a(t, {
45
+ /* @__PURE__ */ o(t, {
44
46
  asElement: "span",
45
- className: _.label(),
47
+ className: x.label(),
46
48
  isTruncated: !0,
47
- maxWidthCh: f,
49
+ maxWidthCh: p,
48
50
  variant: "bodySmallStrong",
49
- children: n
51
+ children: r
50
52
  }),
51
- /* @__PURE__ */ a(e, {
52
- className: _.removeButton(),
53
- isDisabled: d,
53
+ /* @__PURE__ */ o(e, {
54
+ className: x.removeButton(),
55
+ isDisabled: y,
54
56
  asElement: "button",
55
57
  icon: "CloseOutlined",
56
58
  slot: "remove",
57
- title: g.formatMessage({
59
+ title: _.formatMessage({
58
60
  id: "unity:module:ai-kit:composer:attachment:remove",
59
61
  defaultMessage: "Remove Attachment"
60
62
  })
@@ -62,6 +64,6 @@ var u = i({
62
64
  ]
63
65
  });
64
66
  });
65
- d.displayName = "AIComposerAttachment";
67
+ f.displayName = "AIComposerAttachment";
66
68
  //#endregion
67
- export { d as AIComposerAttachment };
69
+ export { f as AIComposerAttachment };
@@ -1,5 +1,18 @@
1
1
  import { ReactElement, RefAttributes } from 'react';
2
2
  import { TagGroupProps, TagListProps } from 'react-aria-components/TagGroup';
3
3
  type AIComposerAttachmentsGroupProps<T> = Omit<TagGroupProps, 'children' | 'className' | 'style'> & Omit<TagListProps<T>, 'className' | 'style'>;
4
+ /**
5
+ * Keeps prompt context scannable when a person adds one or many attachments.
6
+ *
7
+ * Render static `AIComposerAttachment` children or provide `items` and a
8
+ * render function for a dynamic collection. Pass `onRemove` to update the
9
+ * source collection after a person removes an attachment.
10
+ * @param props - React Aria tag-group and tag-list properties.
11
+ * @see {@link AIComposerAttachmentsGroupProps} for all available props.
12
+ * @remarks
13
+ * The group provides tag-list semantics, a default `Attachments` label, and a
14
+ * horizontally scrollable list. Supply `aria-label` when `Attachments` is too
15
+ * generic in the surrounding conversation.
16
+ */
4
17
  export declare const AIComposerAttachmentsGroup: <T>(props: AIComposerAttachmentsGroupProps<T> & RefAttributes<HTMLDivElement>) => ReactElement | null;
5
18
  export type { AIComposerAttachmentsGroupProps };
@@ -4,22 +4,34 @@ import { jsx as n } from "react/jsx-runtime";
4
4
  import { useIntl as r } from "react-intl";
5
5
  import { TagGroup as i, TagList as a } from "react-aria-components/TagGroup";
6
6
  //#region src/modules/ai-kit/components/ai-composer/parts/AIComposerAttachmentsGroup.tsx
7
- var o = t({ slots: { base: ["uy:flex uy:flex-wrap uy:items-start uy:gap-50"] } }), s = e(({ children: e, items: t, onRemove: s, renderEmptyState: c, "aria-label": l, ...u }, d) => {
8
- let f = r(), { base: p } = o();
7
+ var o = t({ slots: {
8
+ clip: "uy:w-full uy:min-w-0 uy:overflow-hidden uy:[contain:paint]",
9
+ base: [
10
+ "uy:flex uy:w-full uy:min-w-0 uy:flex-nowrap uy:items-start uy:gap-50 uy:mb-125 uy:p-50",
11
+ "uy:overflow-x-auto uy:overflow-y-hidden uy:scrollbar-thin",
12
+ "uy:scrollbar:h-1 uy:scrollbar-thumb:rounded-pill uy:scrollbar-thumb:bg-surface-neutral-low"
13
+ ]
14
+ } }), s = e(({ children: e, items: t, onRemove: s, renderEmptyState: c, "aria-label": l, ...u }, d) => {
15
+ let f = r(), { base: p, clip: m } = o();
9
16
  return /* @__PURE__ */ n(i, {
10
17
  ref: d,
11
18
  ...u,
19
+ className: "uy:w-full uy:min-w-0",
12
20
  selectionMode: "none",
13
21
  onRemove: s,
14
22
  "aria-label": l ?? f.formatMessage({
15
23
  id: "unity:module:ai-kit:composer:attachment-group",
16
24
  defaultMessage: "Attachments"
17
25
  }),
18
- children: /* @__PURE__ */ n(a, {
19
- items: t,
20
- renderEmptyState: c,
21
- className: p(),
22
- children: e
26
+ children: /* @__PURE__ */ n("div", {
27
+ className: m(),
28
+ children: /* @__PURE__ */ n(a, {
29
+ "data-unity-slot": "attachments",
30
+ items: t,
31
+ renderEmptyState: c,
32
+ className: p(),
33
+ children: e
34
+ })
23
35
  })
24
36
  });
25
37
  });
@@ -0,0 +1,36 @@
1
+ import { PressEvent } from 'react-aria-components';
2
+ import { AIComposerActionProps } from './AIComposerAction.js';
3
+ export interface AIComposerSubmitActionProps extends Omit<AIComposerActionProps, 'icon' | 'className' | 'style'> {
4
+ /** Names the send action while the Composer is ready for a prompt. */
5
+ sendAriaLabel?: string;
6
+ /** Names the pending action while the Composer uses `state="loading"`. */
7
+ loadingAriaLabel?: string;
8
+ /** Names the stop action while the Composer uses `state="streaming"`. */
9
+ stopAriaLabel?: string;
10
+ /** Overrides default form submission outside the `streaming` state. */
11
+ onPress?: (event: PressEvent) => void;
12
+ }
13
+ /**
14
+ * Gives people a consistently named primary action for sending a prompt or
15
+ * stopping an AI response.
16
+ *
17
+ * Render it in the `right` region of `AIComposerActions`. Without `onPress`,
18
+ * it submits the parent Composer form; during `state="streaming"`, it calls
19
+ * the parent `onStop` callback instead. Pass `sendAriaLabel`,
20
+ * `loadingAriaLabel`, or `stopAriaLabel` when the default
21
+ * state-specific names are not suitable.
22
+ * @param props - Accessible action props and optional custom press behavior.
23
+ * @param props.sendAriaLabel - Names the ready-to-send action. Defaults to
24
+ * `Send message`.
25
+ * @param props.loadingAriaLabel - Names the loading action. Defaults to
26
+ * `Sending message`.
27
+ * @param props.stopAriaLabel - Names the streaming stop action. Defaults to
28
+ * `Stop generating`.
29
+ * @param props.onPress - Replaces default form submission outside streaming.
30
+ * @see {@link AIComposerSubmitActionProps} for all available props.
31
+ * @remarks
32
+ * The action is disabled during `loading` and inherits `disabled` from the
33
+ * parent Composer. It remains a stop control during `streaming` even when an
34
+ * `onPress` callback is supplied.
35
+ */
36
+ export declare const AIComposerSubmitAction: import('react').ForwardRefExoticComponent<AIComposerSubmitActionProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,56 @@
1
+ import { CircularIconButton as e } from "../../../../../core/components/icon-button/CircularIconButton.js";
2
+ import { useAIComposerContext as t } from "../AIComposer.context.js";
3
+ import { getActionTitle as n } from "./AIComposerAction.js";
4
+ import { forwardRef as r } from "react";
5
+ import { uyTv 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/modules/ai-kit/components/ai-composer/parts/AIComposerSubmitAction.tsx
9
+ var s = i({ base: [
10
+ "uy:text-content-neutral-enabled uy:bg-surface-neutral-low-enabled",
11
+ "uy:data-[hovered=\"true\"]:text-content-neutral-hovered uy:data-[hovered=\"true\"]:bg-surface-neutral-low-hovered",
12
+ "uy:active:text-content-inverted-enabled uy:active:bg-surface-inverted",
13
+ "uy:data-[active=\"true\"]:text-content-inverted-enabled uy:data-[active=\"true\"]:bg-surface-inverted",
14
+ "uy:data-[pressed=\"true\"]:text-content-neutral-enabled uy:data-[pressed=\"true\"]:bg-surface-neutral-low-pressed",
15
+ "uy:data-[focus-visible=\"true\"]:text-content-neutral-enabled uy:data-[focus-visible=\"true\"]:bg-surface-neutral-low-focus",
16
+ "uy:data-[disabled=\"true\"]:text-content-neutral-disabled uy:data-[disabled=\"true\"]:bg-surface-neutral-low-disabled",
17
+ "uy:data-[pending=\"true\"]:bg-transparent"
18
+ ] }), c = r(({ title: r, "aria-label": i, isDisabled: c, loadingAriaLabel: l, onPress: u, sendAriaLabel: d, stopAriaLabel: f, ...p }, m) => {
19
+ let h = o(), { state: g, hasValue: _, onStop: v, requestSubmit: y } = t(), b = h.formatMessage({
20
+ id: "unity:module:ai-kit:composer:submit-action:send",
21
+ defaultMessage: "Send message"
22
+ }), x = h.formatMessage({
23
+ id: "unity:module:ai-kit:composer:submit-action:loading",
24
+ defaultMessage: "Sending message"
25
+ }), S = h.formatMessage({
26
+ id: "unity:module:ai-kit:composer:submit-action:stop",
27
+ defaultMessage: "Stop generating"
28
+ }), C = g === "streaming" ? f ?? S : g === "loading" ? l ?? x : i ?? d ?? b, w = n(r, C, b), T = s();
29
+ return /* @__PURE__ */ a(e, {
30
+ ...p,
31
+ ref: m,
32
+ asElement: "button",
33
+ type: "button",
34
+ icon: "ArrowUpOutlined",
35
+ title: w,
36
+ "aria-label": C,
37
+ isDisabled: c || g === "disabled",
38
+ className: T,
39
+ isLoading: g === "loading",
40
+ "data-active": _,
41
+ onPress: (e) => {
42
+ if (g === "streaming") {
43
+ v?.();
44
+ return;
45
+ }
46
+ if (u) {
47
+ u(e);
48
+ return;
49
+ }
50
+ y();
51
+ }
52
+ });
53
+ });
54
+ c.displayName = "AIComposerSubmitAction";
55
+ //#endregion
56
+ export { c as AIComposerSubmitAction };
@@ -0,0 +1,20 @@
1
+ import { TextAreaProps } from 'react-aria-components/TextArea';
2
+ /** Props for the prompt field rendered by {@link AIComposerTextArea}. */
3
+ export type AIComposerTextAreaProps = Omit<TextAreaProps, 'disabled'>;
4
+ /**
5
+ * Lets people write a multi-line AI request while the Composer keeps prompt
6
+ * readiness, sizing, and overflow feedback in sync.
7
+ *
8
+ * Pass an accessible name with `aria-label` or `aria-labelledby`; use standard
9
+ * React Aria `value`, `defaultValue`, and `onChange` props to manage the
10
+ * prompt. In `enterKeyBehavior="submit"`, Enter sends a non-empty prompt and
11
+ * Shift+Enter adds a new line.
12
+ * @param props - React Aria textarea props, including the accessible name and
13
+ * prompt value.
14
+ * @see {@link AIComposerTextAreaProps} for all available props.
15
+ * @remarks
16
+ * The field disables itself when the parent Composer uses `state="disabled"`.
17
+ * A decorative fade indicates additional text below the visible scroll area
18
+ * and remains hidden from assistive technology.
19
+ */
20
+ export declare const AIComposerTextArea: import('react').ForwardRefExoticComponent<AIComposerTextAreaProps & import('react').RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,82 @@
1
+ import { useAIComposerContext as e } from "../AIComposer.context.js";
2
+ import { forwardRef as t, useCallback as n, useLayoutEffect as r, useRef as i, useState as a } from "react";
3
+ import { uyTv as o } from "@payfit/unity-themes";
4
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
+ import { useResizeObserver as l } from "usehooks-ts";
6
+ import { TextArea as u } from "react-aria-components/TextArea";
7
+ //#region src/modules/ai-kit/components/ai-composer/parts/AIComposerTextArea.tsx
8
+ var d = o({ slots: {
9
+ wrapper: "uy:relative uy:group/textarea uy:flex uy:min-h-0 uy:flex-1",
10
+ base: [
11
+ "uy:field-sizing-content uy:min-h-10 uy:max-h-[240px] uy:flex-1 uy:resize-none uy:overflow-y-auto uy:p-0",
12
+ "uy:typography-body uy:text-content-neutral uy:placeholder:text-content-neutral-lowest",
13
+ "uy:disabled:cursor-not-allowed uy:disabled:text-content-neutral-disabled",
14
+ "uy:disabled:placeholder:text-content-neutral-low-disabled",
15
+ "uy:outline-none"
16
+ ],
17
+ fade: [
18
+ "uy:pointer-events-none uy:absolute uy:inset-x-0 uy:bottom-0 uy:h-300",
19
+ "uy:bg-gradient-to-t uy:from-surface-neutral uy:to-transparent",
20
+ "uy:opacity-0 uy:group-data-[scrollable-down=true]/textarea:opacity-100"
21
+ ]
22
+ } }), f = t((t, o) => {
23
+ let { enterKeyBehavior: f, hasValue: p, requestSubmit: m, setHasValue: h, state: g } = e(), _ = i(null), [v, y] = a(!1), { base: b, fade: x, wrapper: S } = d(), { onChange: C, onKeyDown: w, onScroll: T, value: E, ...D } = t, O = n((e) => {
24
+ h(!!e?.value.trim());
25
+ }, [h]), k = n((e) => {
26
+ let t = e ?? _.current;
27
+ t && y(t.scrollTop < t.scrollHeight - t.clientHeight - 1);
28
+ }, []), A = n((e) => {
29
+ requestAnimationFrame(() => {
30
+ k(e);
31
+ });
32
+ }, [k]);
33
+ r(() => {
34
+ O(_.current ?? void 0), A();
35
+ }, [
36
+ A,
37
+ O,
38
+ E
39
+ ]), l({
40
+ ref: _,
41
+ onResize: () => {
42
+ A();
43
+ }
44
+ });
45
+ let j = n((e) => {
46
+ _.current = e, typeof o == "function" ? o(e) : o && (o.current = e), O(e ?? void 0), e && A(e);
47
+ }, [
48
+ o,
49
+ A,
50
+ O
51
+ ]), M = (e) => {
52
+ O(e.target), C?.(e), A(e.target);
53
+ }, N = (e) => {
54
+ k(e.currentTarget), T?.(e);
55
+ }, P = (e) => {
56
+ w?.(e);
57
+ let t = e.key === "Enter" && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey;
58
+ e.defaultPrevented || !t || e.nativeEvent.isComposing || f !== "submit" || !p || g !== "enabled" || (e.preventDefault(), m());
59
+ };
60
+ return /* @__PURE__ */ c("div", {
61
+ className: S(),
62
+ "data-scrollable-down": v || void 0,
63
+ "data-unity-slot": "ai.composer.textarea-wrapper",
64
+ children: [/* @__PURE__ */ s(u, {
65
+ ...D,
66
+ value: E,
67
+ ref: j,
68
+ disabled: g === "disabled",
69
+ className: b(),
70
+ "data-unity-slot": "ai.composer.textarea",
71
+ onChange: M,
72
+ onKeyDown: P,
73
+ onScroll: N
74
+ }), /* @__PURE__ */ s("span", {
75
+ "aria-hidden": "true",
76
+ className: x()
77
+ })]
78
+ });
79
+ });
80
+ f.displayName = "AIComposerTextArea";
81
+ //#endregion
82
+ export { f as AIComposerTextArea };
@@ -9,19 +9,7 @@ import { ToggleButton as d } from "react-aria-components/ToggleButton";
9
9
  //#region src/modules/ai-kit/components/ai-trigger-button/AITriggerButton.tsx
10
10
  var f = c({
11
11
  extend: e,
12
- base: [
13
- "uy:relative uy:isolate uy:[--uy-ai-gradient-border-width:2px]",
14
- "uy:max-w-full",
15
- "uy:text-content-neutral-enabled",
16
- "uy:enabled:data-[hovered=\"true\"]:text-content-neutral-hover",
17
- "uy:enabled:active:text-content-neutral-active",
18
- "uy:enabled:data-[pressed=\"true\"]:text-content-neutral-pressed",
19
- "uy:enabled:data-[focus-visible=\"true\"]:text-content-neutral-focus",
20
- "uy:data-[pressed=\"true\"]:[--uy-ai-gradient-border-width:1px]",
21
- "uy:data-[selected=\"true\"]:[--uy-ai-gradient-border-width:1px]",
22
- "uy:data-[selected=\"true\"]:data-[hovered=\"true\"]:[--uy-ai-gradient-border-width:2px]",
23
- "uy:data-[selected=\"true\"]:hover:[--uy-ai-gradient-border-width:2px]"
24
- ],
12
+ base: /* @__PURE__ */ "uy:relative uy:isolate uy:[--uy-ai-gradient-border-width:2px],uy:[--uy-ai-gradient-border-opacity:0],uy:[--uy-ai-gradient-surface-opacity:0],uy:[--uy-ai-gradient-animation-play-state:paused],uy:max-w-full,uy:text-content-neutral-enabled,uy:enabled:data-[hovered=\"true\"]:text-content-neutral-hover,uy:enabled:active:text-content-neutral-active,uy:enabled:data-[pressed=\"true\"]:text-content-neutral-pressed,uy:enabled:data-[focus-visible=\"true\"]:text-content-neutral-focus,uy:data-[pressed=\"true\"]:[--uy-ai-gradient-border-width:1px],uy:data-[pressed=\"true\"]:[--uy-ai-gradient-border-opacity:1],uy:data-[pressed=\"true\"]:[--uy-ai-gradient-surface-opacity:0.06],uy:data-[pressed=\"true\"]:[--uy-ai-gradient-animation-play-state:paused],uy:data-[pressed=\"true\"]:data-[hovered=\"true\"]:[--uy-ai-gradient-animation-play-state:paused],uy:data-[pressed=\"true\"]:data-[focus-visible=\"true\"]:[--uy-ai-gradient-animation-play-state:paused],uy:data-[selected=\"true\"]:[--uy-ai-gradient-border-width:1px],uy:data-[selected=\"true\"]:[--uy-ai-gradient-border-opacity:1],uy:data-[selected=\"true\"]:[--uy-ai-gradient-surface-opacity:0.06],uy:data-[hovered=\"true\"]:[--uy-ai-gradient-border-opacity:1],uy:data-[hovered=\"true\"]:[--uy-ai-gradient-surface-opacity:0.06],uy:data-[hovered=\"true\"]:[--uy-ai-gradient-animation-play-state:running],uy:data-[focus-visible=\"true\"]:[--uy-ai-gradient-border-opacity:1],uy:data-[focus-visible=\"true\"]:[--uy-ai-gradient-surface-opacity:0.06],uy:data-[focus-visible=\"true\"]:[--uy-ai-gradient-animation-play-state:running],uy:data-[selected=\"true\"]:data-[hovered=\"true\"]:[--uy-ai-gradient-border-width:2px],uy:data-[selected=\"true\"]:hover:[--uy-ai-gradient-border-width:2px]".split(","),
25
13
  variants: {
26
14
  isDisabled: {
27
15
  true: [
@@ -41,7 +29,6 @@ var f = c({
41
29
  isDisabled: !1,
42
30
  className: n({
43
31
  gradient: "linear",
44
- variant: "ghost",
45
32
  glow: !1
46
33
  })
47
34
  }, {
@@ -3,4 +3,11 @@ export { PayfitAIBrand, type PayfitAIBrandProps, } from './components/payfit-ai-
3
3
  export { AITriggerButton, type AITriggerButtonBrandSlotProps, type AITriggerButtonProps, } from './components/ai-trigger-button/AITriggerButton.js';
4
4
  export { AIComposerAttachment, type AIComposerAttachmentProps, } from './components/ai-composer/parts/AIComposerAttachment.js';
5
5
  export { AIComposerAttachmentsGroup, type AIComposerAttachmentsGroupProps, } from './components/ai-composer/parts/AIComposerAttachmentsGroup.js';
6
+ export { AIComposer, type AIComposerProps, } from './components/ai-composer/AIComposer.js';
7
+ export { type AIComposerEnterKeyBehavior, type AIComposerState, } from './components/ai-composer/AIComposer.context.js';
8
+ export { AIComposerAction, type AIComposerActionProps, } from './components/ai-composer/parts/AIComposerAction.js';
9
+ export { AIComposerActions, type AIComposerActionsProps, } from './components/ai-composer/parts/AIComposerActions.js';
10
+ export { AIComposerAlert, type AIComposerAlertProps, } from './components/ai-composer/parts/AIComposerAlert.js';
11
+ export { AIComposerSubmitAction, type AIComposerSubmitActionProps, } from './components/ai-composer/parts/AIComposerSubmitAction.js';
12
+ export { AIComposerTextArea, type AIComposerTextAreaProps, } from './components/ai-composer/parts/AIComposerTextArea.js';
6
13
  export { aiGradientEffect, aiGradientSurfaceEffect, } from './utils/ai-gradient-effect.js';
@@ -1,42 +1,47 @@
1
1
  /**
2
2
  * @summary
3
- * Applies the Payfit AI gradient border effect to an enabled interactive host.
3
+ * Applies the Payfit AI gradient border renderer to a component host.
4
4
  * @description
5
5
  * Pass the returned classes to the interactive element itself. The element
6
6
  * continues to own its padding, margin, background, border radius, and
7
- * semantic state styles. Set `--uy-ai-gradient-border-width` on that host to
8
- * choose the visible border width.
7
+ * semantic state styles. Set its typed AI gradient custom properties on that
8
+ * host to choose the border geometry and visibility.
9
9
  * @param options - Variant options for the effect.
10
10
  * @param {string} [options.gradient="linear"] - Gradient movement model. `linear` sweeps through
11
11
  * a seamless repeat, `radial` pulses outward and inward, and `conic` rotates
12
12
  * around the host. Defaults to `linear`.
13
- * @param {string} [options.variant="outlined"] - Resting border visibility. `outlined` displays the
14
- * border at rest; `ghost` displays it only in interactive states. Defaults to
15
- * `outlined`.
16
- * @param {boolean} [options.glow=false] - Enables the animated three-colour outer shadow on
17
- * hover and focus-visible. Override `--uy-ai-gradient-glow-opacity` on the
18
- * host to tune its strength. Defaults to `false`.
13
+ * @param {boolean} [options.glow=false] - Enables an animated three-colour outer shadow on a
14
+ * decorative layer behind the host. Override `--uy-ai-gradient-glow-opacity`
15
+ * on the host to tune its strength. Defaults to `false`.
19
16
  * @remarks
20
17
  * - When the control needs an interior gradient surface, render a decorative
21
18
  * element as the first child and apply {@link aiGradientSurfaceEffect}.
22
19
  * - The surface utility creates the z-index 10 overlay layer. Elements that apply `aiGradientEffect`
23
- * use`isolation: isolate` to avoid z-index conflicts.
20
+ * use `isolation: isolate` to avoid z-index conflicts. The optional glow
21
+ * uses `::after` behind both the border and surface layers, so it does not
22
+ * replace a host-provided elevation shadow.
24
23
  * - Place all interactive content at z-index 20 so it remains above both the
25
24
  * gradient border and surface.
26
- * - The effect animates only on hover and focus-visible, respects
27
- * reduced-motion preferences, and should only be applied while the host is
28
- * enabled. Disabled states must supply their own non-animated
29
- * border and surface.
25
+ * - The effect respects reduced-motion preferences. Components control when
26
+ * the renderer is visible through the presentation contract.
30
27
  * @notes
31
28
  * This utility needs specific custom CSS properties set on the host element to work properly.
32
- * - `--uy-ai-gradient-border-width` may be set on the host to control the
29
+ * - `--uy-ai-gradient-border-width` controls the
33
30
  * visible gradient border width. It accepts a CSS length such as `1px` and
34
31
  * defaults to `1px`.
32
+ * - `--uy-ai-gradient-border-opacity` controls border visibility as a number
33
+ * between `0` and `1`; it defaults to `0`.
34
+ * - `--uy-ai-gradient-surface-opacity` controls decorative surface visibility
35
+ * as a number between `0` and `1`; it defaults to `0`.
36
+ * - `--uy-ai-gradient-animation-play-state` controls animation playback with
37
+ * `running` or `paused`; it defaults to `paused`.
35
38
  * - `--uy-ai-gradient-angle` when `gradient: 'conic`. Set it for an advanced static starting angle
36
39
  * for conic gradients and the glow. It accepts a CSS angle and defaults to
37
40
  * `0deg`; the effect animates it when required.
38
41
  * - `--uy-ai-gradient-glow-opacity` is optional when `glow: true`. It controls
39
42
  * the glow's opacity, defaulting to `20%`.
43
+ * - `--uy-ai-gradient-glow-visibility` controls the decorative glow layer as
44
+ * a number between `0` and `1`; it defaults to `0`.
40
45
  * @returns Tailwind classes to apply to the interactive host.
41
46
  * @example
42
47
  * ```tsx
@@ -48,7 +53,6 @@
48
53
  * 'uy:[--uy-ai-gradient-border-width:2px]',
49
54
  * aiGradientEffect({
50
55
  * gradient: 'linear',
51
- * variant: 'outlined',
52
56
  * glow: true,
53
57
  * }),
54
58
  * ],
@@ -74,10 +78,6 @@ export declare const aiGradientEffect: import('tailwind-variants').TVReturnType<
74
78
  radial: string[];
75
79
  conic: string[];
76
80
  };
77
- variant: {
78
- outlined: "uy:supports-mask-border:before:opacity-100";
79
- ghost: string[];
80
- };
81
81
  glow: {
82
82
  true: string[];
83
83
  false: never[];
@@ -88,10 +88,6 @@ export declare const aiGradientEffect: import('tailwind-variants').TVReturnType<
88
88
  radial: string[];
89
89
  conic: string[];
90
90
  };
91
- variant: {
92
- outlined: "uy:supports-mask-border:before:opacity-100";
93
- ghost: string[];
94
- };
95
91
  glow: {
96
92
  true: string[];
97
93
  false: never[];
@@ -102,10 +98,6 @@ export declare const aiGradientEffect: import('tailwind-variants').TVReturnType<
102
98
  radial: string[];
103
99
  conic: string[];
104
100
  };
105
- variant: {
106
- outlined: "uy:supports-mask-border:before:opacity-100";
107
- ghost: string[];
108
- };
109
101
  glow: {
110
102
  true: string[];
111
103
  false: never[];
@@ -115,19 +107,16 @@ export declare const aiGradientEffect: import('tailwind-variants').TVReturnType<
115
107
  * Applies the Payfit AI gradient surface effect to a decorative child layer.
116
108
  * @description
117
109
  * This utility takes no options. It positions a presentational layer over its relative host,
118
- * makes it non-interactive, inherits the host radius, and applies the Payfit AI
119
- * gradient at 6% opacity for enabled hover, focus-visible, active, pressed,
120
- * and selected states.
110
+ * makes it non-interactive, inherits the host radius, and paints the Payfit AI
111
+ * gradient using the host-controlled surface opacity.
121
112
  * @remarks
122
113
  * - Render the surface element as the first child of a host styled with
123
114
  * {@link aiGradientEffect}.
124
115
  * - It occupies z-index 10; the host's interactive content must use a higher z-index.
125
116
  * - The complete layer contract is shown in {@link aiGradientEffect}'s example.
126
117
  * @notes
127
- * - This utility has no consumer-set CSS custom properties. Set any host
128
- * properties through {@link aiGradientEffect} instead.
129
- * - The layer has no resting or disabled background. The host remains
130
- * responsible for its background, disabled styling, and loading styling.
118
+ * - Set `--uy-ai-gradient-surface-opacity` on the host to control visibility.
119
+ * It defaults to `0`, so an unconfigured surface remains idle.
131
120
  * - Mark the element `aria-hidden` because it is purely decorative.
132
121
  * @returns Tailwind classes to apply to the decorative surface element.
133
122
  * @example
@@ -1,85 +1,43 @@
1
1
  import { uyTv as e } from "@payfit/unity-themes";
2
2
  //#region src/modules/ai-kit/utils/ai-gradient-effect.ts
3
3
  var t = e({
4
- base: [
5
- "uy:relative",
6
- "uy:group",
7
- "uy:isolate",
8
- "uy:border-solid",
9
- "uy:border-(length:--uy-ai-gradient-border-width)",
10
- "uy:motion-safe:transition-[--uy-ai-gradient-border-width]",
11
- "uy:motion-safe:duration-50",
12
- "uy:motion-safe:ease-linear",
13
- "uy:supports-mask-border:border-transparent",
14
- "uy:supports-mask-border:before:content-['']",
15
- "uy:supports-mask-border:before:pointer-events-none",
16
- "uy:supports-mask-border:before:absolute",
17
- "uy:supports-mask-border:before:-inset-(--uy-ai-gradient-border-width)",
18
- "uy:supports-mask-border:before:z-0",
19
- "uy:supports-mask-border:before:rounded-[inherit]",
20
- "uy:supports-mask-border:before:p-(--uy-ai-gradient-border-width)",
21
- "uy:supports-mask-border:before:opacity-0",
22
- "uy:supports-mask-border:before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)]",
23
- "uy:supports-mask-border:before:[mask-origin:content-box,border-box]",
24
- "uy:supports-mask-border:before:[mask-clip:content-box,border-box]",
25
- "uy:supports-mask-border:before:[mask-composite:exclude]",
26
- "uy:supports-mask-border:before:[-webkit-mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)]",
27
- "uy:supports-mask-border:before:[-webkit-mask-origin:content-box,border-box]",
28
- "uy:supports-mask-border:before:[-webkit-mask-clip:content-box,border-box]",
29
- "uy:supports-mask-border:before:[-webkit-mask-composite:xor]"
30
- ],
4
+ base: /* @__PURE__ */ "uy:relative.uy:group.uy:isolate.uy:border-solid.uy:border-(length:--uy-ai-gradient-border-width).uy:motion-safe:transition-[--uy-ai-gradient-border-width,--uy-ai-gradient-border-opacity,--uy-ai-gradient-animation-play-state].uy:motion-safe:duration-50.uy:motion-safe:ease-linear.uy:supports-mask-border:border-transparent.uy:supports-mask-border:before:content-[''].uy:supports-mask-border:before:pointer-events-none.uy:supports-mask-border:before:absolute.uy:supports-mask-border:before:-inset-(--uy-ai-gradient-border-width).uy:supports-mask-border:before:z-0.uy:supports-mask-border:before:rounded-[inherit].uy:supports-mask-border:before:p-(--uy-ai-gradient-border-width).uy:supports-mask-border:before:opacity-[var(--uy-ai-gradient-border-opacity)].uy:motion-safe:before:[animation-play-state:var(--uy-ai-gradient-animation-play-state)].uy:supports-mask-border:before:[mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)].uy:supports-mask-border:before:[mask-origin:content-box,border-box].uy:supports-mask-border:before:[mask-clip:content-box,border-box].uy:supports-mask-border:before:[mask-composite:exclude].uy:supports-mask-border:before:[-webkit-mask-image:linear-gradient(#000_0_0),linear-gradient(#000_0_0)].uy:supports-mask-border:before:[-webkit-mask-origin:content-box,border-box].uy:supports-mask-border:before:[-webkit-mask-clip:content-box,border-box].uy:supports-mask-border:before:[-webkit-mask-composite:xor]".split("."),
31
5
  variants: {
32
6
  gradient: {
33
- linear: [
34
- "uy:supports-mask-border:before:[background:linear-gradient(90deg,var(--uy-gradient-payfit-ai-animated))_0%_50%/400%_100%_no-repeat]",
35
- "uy:motion-safe:enabled:data-[hovered=\"true\"]:before:animate-uy-ai-gradient-linear-sweep",
36
- "uy:motion-safe:enabled:data-[focus-visible=\"true\"]:before:animate-uy-ai-gradient-linear-sweep",
37
- "uy:motion-safe:enabled:hover:before:animate-uy-ai-gradient-linear-sweep",
38
- "uy:motion-safe:enabled:focus-visible:before:animate-uy-ai-gradient-linear-sweep"
39
- ],
40
- radial: [
41
- "uy:supports-mask-border:before:[background:radial-gradient(circle,var(--uy-gradient-payfit-ai))_center/100%_100%_no-repeat]",
42
- "uy:motion-safe:enabled:data-[hovered=\"true\"]:before:animate-uy-ai-gradient-radial-pulse",
43
- "uy:motion-safe:enabled:data-[focus-visible=\"true\"]:before:animate-uy-ai-gradient-radial-pulse",
44
- "uy:motion-safe:enabled:hover:before:animate-uy-ai-gradient-radial-pulse",
45
- "uy:motion-safe:enabled:focus-visible:before:animate-uy-ai-gradient-radial-pulse"
46
- ],
47
- conic: [
48
- "uy:supports-mask-border:before:[background:conic-gradient(from_var(--uy-ai-gradient-angle),var(--uy-gradient-payfit-ai))_center/cover_no-repeat]",
49
- "uy:motion-safe:enabled:data-[hovered=\"true\"]:before:animate-uy-ai-gradient-angle-rotate",
50
- "uy:motion-safe:enabled:data-[focus-visible=\"true\"]:before:animate-uy-ai-gradient-angle-rotate",
51
- "uy:motion-safe:enabled:hover:before:animate-uy-ai-gradient-angle-rotate",
52
- "uy:motion-safe:enabled:focus-visible:before:animate-uy-ai-gradient-angle-rotate"
53
- ]
54
- },
55
- variant: {
56
- outlined: "uy:supports-mask-border:before:opacity-100",
57
- ghost: [
58
- "uy:enabled:data-[hovered=\"true\"]:supports-mask-border:before:opacity-100",
59
- "uy:enabled:data-[pressed=\"true\"]:supports-mask-border:before:opacity-100",
60
- "uy:enabled:data-[selected=\"true\"]:supports-mask-border:before:opacity-100",
61
- "uy:enabled:data-[focus-visible=\"true\"]:supports-mask-border:before:opacity-100"
62
- ]
7
+ linear: ["uy:supports-mask-border:before:[background:linear-gradient(90deg,var(--uy-gradient-payfit-ai-animated))_0%_50%/400%_100%_no-repeat]", "uy:motion-safe:before:animate-uy-ai-gradient-linear-sweep"],
8
+ radial: ["uy:supports-mask-border:before:[background:radial-gradient(circle,var(--uy-gradient-payfit-ai))_center/100%_100%_no-repeat]", "uy:motion-safe:before:animate-uy-ai-gradient-radial-pulse"],
9
+ conic: ["uy:supports-mask-border:before:[background:conic-gradient(from_var(--uy-ai-gradient-angle),var(--uy-gradient-payfit-ai))_center/cover_no-repeat]", "uy:motion-safe:before:animate-uy-ai-gradient-angle-rotate"]
63
10
  },
64
11
  glow: {
65
12
  true: [
66
- "uy:enabled:data-[hovered=\"true\"]:[box-shadow:var(--uy-ai-gradient-glow)]",
67
- "uy:enabled:data-[focus-visible=\"true\"]:[box-shadow:var(--uy-ai-gradient-glow)]",
68
- "uy:enabled:hover:[box-shadow:var(--uy-ai-gradient-glow)]",
69
- "uy:enabled:focus-visible:[box-shadow:var(--uy-ai-gradient-glow)]",
70
- "uy:motion-safe:enabled:data-[hovered=\"true\"]:animate-uy-ai-gradient-angle-rotate",
71
- "uy:motion-safe:enabled:data-[focus-visible=\"true\"]:animate-uy-ai-gradient-angle-rotate",
72
- "uy:motion-safe:enabled:hover:animate-uy-ai-gradient-angle-rotate",
73
- "uy:motion-safe:enabled:focus-visible:animate-uy-ai-gradient-angle-rotate"
13
+ "uy:after:content-['']",
14
+ "uy:after:pointer-events-none",
15
+ "uy:after:absolute",
16
+ "uy:after:inset-0",
17
+ "uy:after:-z-10",
18
+ "uy:after:rounded-[inherit]",
19
+ "uy:after:[box-shadow:var(--uy-ai-gradient-glow)]",
20
+ "uy:after:opacity-[var(--uy-ai-gradient-glow-visibility)]",
21
+ "uy:motion-safe:after:animate-uy-ai-gradient-angle-rotate",
22
+ "uy:motion-safe:after:[animation-play-state:var(--uy-ai-gradient-animation-play-state)]"
74
23
  ],
75
24
  false: []
76
25
  }
77
26
  },
78
27
  defaultVariants: {
79
28
  gradient: "linear",
80
- variant: "outlined",
81
29
  glow: !1
82
30
  }
83
- }), n = e({ base: /* @__PURE__ */ "uy:pointer-events-none.uy:absolute.uy:inset-0.uy:z-10.uy:rounded-[inherit].uy:group-enabled:group-data-[hovered=\"true\"]:opacity-6.uy:group-enabled:group-data-[hovered=\"true\"]:bg-linear-45.uy:group-enabled:group-data-[hovered=\"true\"]:gradient-stops-payfit-ai.uy:group-enabled:group-hover:opacity-6.uy:group-enabled:group-hover:bg-linear-45.uy:group-enabled:group-hover:gradient-stops-payfit-ai.uy:group-enabled:group-data-[focus-visible=\"true\"]:opacity-6.uy:group-enabled:group-data-[focus-visible=\"true\"]:bg-linear-45.uy:group-enabled:group-data-[focus-visible=\"true\"]:gradient-stops-payfit-ai.uy:group-enabled:group-focus-visible:opacity-6.uy:group-enabled:group-focus-visible:bg-linear-45.uy:group-enabled:group-focus-visible:gradient-stops-payfit-ai.uy:group-enabled:group-data-active:opacity-6.uy:group-enabled:group-data-active:bg-linear-45.uy:group-enabled:group-data-active:gradient-stops-payfit-ai.uy:group-enabled:group-data-[pressed=\"true\"]:opacity-6.uy:group-enabled:group-data-[pressed=\"true\"]:bg-linear-45.uy:group-enabled:group-data-[pressed=\"true\"]:gradient-stops-payfit-ai.uy:group-enabled:group-data-[selected=\"true\"]:opacity-6.uy:group-enabled:group-data-[selected=\"true\"]:bg-linear-45.uy:group-enabled:group-data-[selected=\"true\"]:gradient-stops-payfit-ai".split(".") });
31
+ }), n = e({ base: [
32
+ "uy:pointer-events-none",
33
+ "uy:absolute",
34
+ "uy:inset-0",
35
+ "uy:z-10",
36
+ "uy:rounded-[inherit]",
37
+ "uy:bg-linear-45",
38
+ "uy:gradient-stops-payfit-ai",
39
+ "uy:opacity-[var(--uy-ai-gradient-surface-opacity)]",
40
+ "uy:motion-safe:transition-[--uy-ai-gradient-surface-opacity]"
41
+ ] });
84
42
  //#endregion
85
43
  export { t as aiGradientEffect, n as aiGradientSurfaceEffect };