@agent-native/toolkit 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/agent-native.eject.json +71 -0
  2. package/dist/chat-history/ChatHistoryRail.d.ts +15 -1
  3. package/dist/chat-history/ChatHistoryRail.d.ts.map +1 -1
  4. package/dist/chat-history/ChatHistoryRail.js +26 -13
  5. package/dist/chat-history/ChatHistoryRail.js.map +1 -1
  6. package/dist/chat-history/ChatHistoryRail.spec.js +77 -1
  7. package/dist/chat-history/ChatHistoryRail.spec.js.map +1 -1
  8. package/dist/chat-history/index.d.ts +2 -1
  9. package/dist/chat-history/index.d.ts.map +1 -1
  10. package/dist/chat-history/index.js +2 -1
  11. package/dist/chat-history/index.js.map +1 -1
  12. package/dist/chat-history/useChatHistoryRailController.d.ts +26 -0
  13. package/dist/chat-history/useChatHistoryRailController.d.ts.map +1 -0
  14. package/dist/chat-history/useChatHistoryRailController.js +36 -0
  15. package/dist/chat-history/useChatHistoryRailController.js.map +1 -0
  16. package/dist/chat-history/useChatHistoryRailController.spec.d.ts +2 -0
  17. package/dist/chat-history/useChatHistoryRailController.spec.d.ts.map +1 -0
  18. package/dist/chat-history/useChatHistoryRailController.spec.js +101 -0
  19. package/dist/chat-history/useChatHistoryRailController.spec.js.map +1 -0
  20. package/dist/chat-history.css +2 -0
  21. package/dist/composer/ComposerPlusMenu.js +1 -1
  22. package/dist/composer/ComposerPlusMenu.js.map +1 -1
  23. package/dist/composer/PromptComposer.d.ts.map +1 -1
  24. package/dist/composer/PromptComposer.js +22 -4
  25. package/dist/composer/PromptComposer.js.map +1 -1
  26. package/dist/composer/useRealtimeVoiceMode.d.ts +7 -0
  27. package/dist/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  28. package/dist/composer/useRealtimeVoiceMode.js +91 -19
  29. package/dist/composer/useRealtimeVoiceMode.js.map +1 -1
  30. package/dist/composer/useRealtimeVoiceMode.spec.js +58 -9
  31. package/dist/composer/useRealtimeVoiceMode.spec.js.map +1 -1
  32. package/dist/conformance/__fixtures__/css-in-js-adapter.d.ts +7 -0
  33. package/dist/conformance/__fixtures__/css-in-js-adapter.d.ts.map +1 -0
  34. package/dist/conformance/__fixtures__/css-in-js-adapter.js +84 -0
  35. package/dist/conformance/__fixtures__/css-in-js-adapter.js.map +1 -0
  36. package/dist/conformance/conformance.spec.d.ts +2 -0
  37. package/dist/conformance/conformance.spec.d.ts.map +1 -0
  38. package/dist/conformance/conformance.spec.js +58 -0
  39. package/dist/conformance/conformance.spec.js.map +1 -0
  40. package/dist/conformance/index.d.ts +4 -0
  41. package/dist/conformance/index.d.ts.map +1 -0
  42. package/dist/conformance/index.js +4 -0
  43. package/dist/conformance/index.js.map +1 -0
  44. package/dist/conformance/runner.d.ts +12 -0
  45. package/dist/conformance/runner.d.ts.map +1 -0
  46. package/dist/conformance/runner.js +441 -0
  47. package/dist/conformance/runner.js.map +1 -0
  48. package/dist/conformance/types.d.ts +26 -0
  49. package/dist/conformance/types.d.ts.map +1 -0
  50. package/dist/conformance/types.js +13 -0
  51. package/dist/conformance/types.js.map +1 -0
  52. package/dist/conformance/version.d.ts +6 -0
  53. package/dist/conformance/version.d.ts.map +1 -0
  54. package/dist/conformance/version.js +14 -0
  55. package/dist/conformance/version.js.map +1 -0
  56. package/dist/design-system/components.d.ts +64 -0
  57. package/dist/design-system/components.d.ts.map +1 -0
  58. package/dist/design-system/components.js +50 -0
  59. package/dist/design-system/components.js.map +1 -0
  60. package/dist/design-system/context.d.ts +11 -0
  61. package/dist/design-system/context.d.ts.map +1 -0
  62. package/dist/design-system/context.js +17 -0
  63. package/dist/design-system/context.js.map +1 -0
  64. package/dist/design-system/default-adapter.d.ts +3 -0
  65. package/dist/design-system/default-adapter.d.ts.map +1 -0
  66. package/dist/design-system/default-adapter.js +166 -0
  67. package/dist/design-system/default-adapter.js.map +1 -0
  68. package/dist/design-system/default-adapter.spec.d.ts +2 -0
  69. package/dist/design-system/default-adapter.spec.d.ts.map +1 -0
  70. package/dist/design-system/default-adapter.spec.js +96 -0
  71. package/dist/design-system/default-adapter.spec.js.map +1 -0
  72. package/dist/design-system/definition.d.ts +9 -0
  73. package/dist/design-system/definition.d.ts.map +1 -0
  74. package/dist/design-system/definition.js +4 -0
  75. package/dist/design-system/definition.js.map +1 -0
  76. package/dist/design-system/design-system.spec.d.ts +2 -0
  77. package/dist/design-system/design-system.spec.d.ts.map +1 -0
  78. package/dist/design-system/design-system.spec.js +121 -0
  79. package/dist/design-system/design-system.spec.js.map +1 -0
  80. package/dist/design-system/error-boundary.d.ts +18 -0
  81. package/dist/design-system/error-boundary.d.ts.map +1 -0
  82. package/dist/design-system/error-boundary.js +16 -0
  83. package/dist/design-system/error-boundary.js.map +1 -0
  84. package/dist/design-system/index.d.ts +8 -0
  85. package/dist/design-system/index.d.ts.map +1 -0
  86. package/dist/design-system/index.js +8 -0
  87. package/dist/design-system/index.js.map +1 -0
  88. package/dist/design-system/theme.d.ts +30 -0
  89. package/dist/design-system/theme.d.ts.map +1 -0
  90. package/dist/design-system/theme.js +95 -0
  91. package/dist/design-system/theme.js.map +1 -0
  92. package/dist/design-system/theme.spec.d.ts +2 -0
  93. package/dist/design-system/theme.spec.d.ts.map +1 -0
  94. package/dist/design-system/theme.spec.js +43 -0
  95. package/dist/design-system/theme.spec.js.map +1 -0
  96. package/dist/design-system/types.d.ts +288 -0
  97. package/dist/design-system/types.d.ts.map +1 -0
  98. package/dist/design-system/types.js +2 -0
  99. package/dist/design-system/types.js.map +1 -0
  100. package/dist/provider.d.ts +4 -3
  101. package/dist/provider.d.ts.map +1 -1
  102. package/dist/provider.js +46 -4
  103. package/dist/provider.js.map +1 -1
  104. package/dist/ui/button.d.ts +5 -0
  105. package/dist/ui/button.d.ts.map +1 -1
  106. package/dist/ui/button.js +25 -4
  107. package/dist/ui/button.js.map +1 -1
  108. package/dist/ui/dialog.d.ts +4 -0
  109. package/dist/ui/dialog.d.ts.map +1 -1
  110. package/dist/ui/dialog.js +2 -2
  111. package/dist/ui/dialog.js.map +1 -1
  112. package/dist/ui/popover.d.ts +1 -0
  113. package/dist/ui/popover.d.ts.map +1 -1
  114. package/dist/ui/popover.js +2 -2
  115. package/dist/ui/popover.js.map +1 -1
  116. package/dist/ui/select.d.ts +3 -1
  117. package/dist/ui/select.d.ts.map +1 -1
  118. package/dist/ui/select.js +1 -1
  119. package/dist/ui/select.js.map +1 -1
  120. package/dist/ui/sidebar.d.ts +6 -2
  121. package/dist/ui/sidebar.d.ts.map +1 -1
  122. package/dist/ui/sidebar.js +12 -15
  123. package/dist/ui/sidebar.js.map +1 -1
  124. package/dist/ui/tooltip.d.ts +3 -1
  125. package/dist/ui/tooltip.d.ts.map +1 -1
  126. package/dist/ui/tooltip.js +2 -2
  127. package/dist/ui/tooltip.js.map +1 -1
  128. package/package.json +31 -1
  129. package/src/chat-history/ChatHistoryRail.spec.tsx +174 -0
  130. package/src/chat-history/ChatHistoryRail.tsx +100 -39
  131. package/src/chat-history/index.ts +9 -0
  132. package/src/chat-history/useChatHistoryRailController.spec.tsx +131 -0
  133. package/src/chat-history/useChatHistoryRailController.ts +76 -0
  134. package/src/chat-history.css +2 -0
  135. package/src/composer/ComposerPlusMenu.tsx +11 -8
  136. package/src/composer/PromptComposer.tsx +27 -6
  137. package/src/composer/useRealtimeVoiceMode.spec.ts +82 -8
  138. package/src/composer/useRealtimeVoiceMode.tsx +107 -22
  139. package/src/conformance/__fixtures__/css-in-js-adapter.tsx +401 -0
  140. package/src/conformance/conformance.spec.tsx +83 -0
  141. package/src/conformance/index.ts +3 -0
  142. package/src/conformance/runner.tsx +710 -0
  143. package/src/conformance/types.ts +45 -0
  144. package/src/conformance/version.ts +22 -0
  145. package/src/design-system/components.tsx +146 -0
  146. package/src/design-system/context.tsx +31 -0
  147. package/src/design-system/default-adapter.spec.tsx +143 -0
  148. package/src/design-system/default-adapter.tsx +915 -0
  149. package/src/design-system/definition.ts +14 -0
  150. package/src/design-system/design-system.spec.tsx +183 -0
  151. package/src/design-system/error-boundary.tsx +37 -0
  152. package/src/design-system/index.ts +7 -0
  153. package/src/design-system/theme.spec.ts +61 -0
  154. package/src/design-system/theme.ts +145 -0
  155. package/src/design-system/types.ts +363 -0
  156. package/src/provider.tsx +98 -5
  157. package/src/ui/button.tsx +95 -6
  158. package/src/ui/dialog.tsx +48 -23
  159. package/src/ui/popover.tsx +16 -2
  160. package/src/ui/select.tsx +7 -3
  161. package/src/ui/sidebar.tsx +47 -48
  162. package/src/ui/tooltip.tsx +7 -3
@@ -0,0 +1,45 @@
1
+ import type { DesignSystemComponents } from "../design-system/types.js";
2
+
3
+ export type DesignSystemConformanceCategory =
4
+ | "contract"
5
+ | "leaf"
6
+ | "behavior"
7
+ | "overlay-interoperability";
8
+
9
+ export interface DesignSystemConformanceCheckResult {
10
+ id: string;
11
+ category: DesignSystemConformanceCategory;
12
+ components: readonly (keyof DesignSystemComponents)[];
13
+ passed: boolean;
14
+ message?: string;
15
+ }
16
+
17
+ export interface DesignSystemConformanceReport {
18
+ contractVersion: number;
19
+ adapterName: string;
20
+ passed: boolean;
21
+ results: readonly DesignSystemConformanceCheckResult[];
22
+ }
23
+
24
+ export interface RunDesignSystemConformanceOptions {
25
+ adapterName?: string;
26
+ components: DesignSystemComponents;
27
+ contractVersion: number;
28
+ document?: Document;
29
+ }
30
+
31
+ export class DesignSystemConformanceError extends Error {
32
+ readonly report: DesignSystemConformanceReport;
33
+
34
+ constructor(report: DesignSystemConformanceReport) {
35
+ const failures = report.results
36
+ .filter((result) => !result.passed)
37
+ .map((result) => `${result.id}: ${result.message ?? "failed"}`)
38
+ .join("\n");
39
+ super(
40
+ `Design system conformance failed for ${report.adapterName}:\n${failures}`,
41
+ );
42
+ this.name = "DesignSystemConformanceError";
43
+ this.report = report;
44
+ }
45
+ }
@@ -0,0 +1,22 @@
1
+ import { DESIGN_SYSTEM_CONTRACT_VERSION } from "../design-system/types.js";
2
+
3
+ export const DESIGN_SYSTEM_CONTRACT_EVOLUTION_POLICY = {
4
+ minor: "New components and optional props are backward-compatible.",
5
+ major:
6
+ "Required props, removed components or props, and behavioral contract changes require a new contract major.",
7
+ } as const;
8
+
9
+ export function assertDesignSystemContractVersion(
10
+ adapterContractVersion: number,
11
+ ): void {
12
+ if (!Number.isInteger(adapterContractVersion) || adapterContractVersion < 1) {
13
+ throw new TypeError(
14
+ "Design system contractVersion must be a positive integer.",
15
+ );
16
+ }
17
+ if (adapterContractVersion !== DESIGN_SYSTEM_CONTRACT_VERSION) {
18
+ throw new RangeError(
19
+ `Design system contract major ${adapterContractVersion} is incompatible with Toolkit contract major ${DESIGN_SYSTEM_CONTRACT_VERSION}.`,
20
+ );
21
+ }
22
+ }
@@ -0,0 +1,146 @@
1
+ import type { ComponentType } from "react";
2
+
3
+ import { useDesignSystemComponent } from "./context.js";
4
+ import { defaultDesignSystemComponents } from "./default-adapter.js";
5
+ import { DesignSystemErrorBoundary } from "./error-boundary.js";
6
+ import type {
7
+ ActionButtonProps,
8
+ AvatarProps,
9
+ CheckboxProps,
10
+ DesignSystemComponentName,
11
+ DesignSystemComponents,
12
+ DesignSystemKey,
13
+ DialogProps,
14
+ IconButtonProps,
15
+ MenuProps,
16
+ PickerProps,
17
+ PopoverProps,
18
+ SkeletonProps,
19
+ SpinnerProps,
20
+ StatusProps,
21
+ SurfaceProps,
22
+ SwitchProps,
23
+ TabsProps,
24
+ TextAreaProps,
25
+ TextFieldProps,
26
+ TooltipProps,
27
+ } from "./types.js";
28
+
29
+ function createComponent<Props extends object>(
30
+ name: DesignSystemComponentName,
31
+ DefaultComponent: ComponentType<Props>,
32
+ ) {
33
+ function DesignSystemComponent(props: Props) {
34
+ const CustomComponent = useDesignSystemComponent(name) as
35
+ | ComponentType<Props>
36
+ | undefined;
37
+ const fallback = <DefaultComponent {...props} />;
38
+ if (
39
+ !CustomComponent ||
40
+ CustomComponent === DefaultComponent ||
41
+ CustomComponent === DesignSystemComponent
42
+ ) {
43
+ return fallback;
44
+ }
45
+ return (
46
+ <DesignSystemErrorBoundary component={name} fallback={fallback}>
47
+ <CustomComponent {...props} />
48
+ </DesignSystemErrorBoundary>
49
+ );
50
+ }
51
+ DesignSystemComponent.displayName = `DesignSystem.${name}`;
52
+ return DesignSystemComponent;
53
+ }
54
+
55
+ export const ActionButton = createComponent<ActionButtonProps>(
56
+ "ActionButton",
57
+ defaultDesignSystemComponents.ActionButton,
58
+ );
59
+ export const IconButton = createComponent<IconButtonProps>(
60
+ "IconButton",
61
+ defaultDesignSystemComponents.IconButton,
62
+ );
63
+ export const TextField = createComponent<TextFieldProps>(
64
+ "TextField",
65
+ defaultDesignSystemComponents.TextField,
66
+ );
67
+ export const TextArea = createComponent<TextAreaProps>(
68
+ "TextArea",
69
+ defaultDesignSystemComponents.TextArea,
70
+ );
71
+ export const Spinner = createComponent<SpinnerProps>(
72
+ "Spinner",
73
+ defaultDesignSystemComponents.Spinner,
74
+ );
75
+ export const Skeleton = createComponent<SkeletonProps>(
76
+ "Skeleton",
77
+ defaultDesignSystemComponents.Skeleton,
78
+ );
79
+ export const Status = createComponent<StatusProps>(
80
+ "Status",
81
+ defaultDesignSystemComponents.Status,
82
+ );
83
+ export const Surface = createComponent<SurfaceProps>(
84
+ "Surface",
85
+ defaultDesignSystemComponents.Surface,
86
+ );
87
+ export const Avatar = createComponent<AvatarProps>(
88
+ "Avatar",
89
+ defaultDesignSystemComponents.Avatar,
90
+ );
91
+ export const Tooltip = createComponent<TooltipProps>(
92
+ "Tooltip",
93
+ defaultDesignSystemComponents.Tooltip,
94
+ );
95
+ export const Menu = createComponent<MenuProps>(
96
+ "Menu",
97
+ defaultDesignSystemComponents.Menu,
98
+ );
99
+ export const Popover = createComponent<PopoverProps>(
100
+ "Popover",
101
+ defaultDesignSystemComponents.Popover,
102
+ );
103
+ export const Dialog = createComponent<DialogProps>(
104
+ "Dialog",
105
+ defaultDesignSystemComponents.Dialog,
106
+ );
107
+ export const Checkbox = createComponent<CheckboxProps>(
108
+ "Checkbox",
109
+ defaultDesignSystemComponents.Checkbox,
110
+ );
111
+ export const Switch = createComponent<SwitchProps>(
112
+ "Switch",
113
+ defaultDesignSystemComponents.Switch,
114
+ );
115
+
116
+ export function Picker<Value extends DesignSystemKey = string>(
117
+ props: PickerProps<Value>,
118
+ ) {
119
+ const CustomComponent = useDesignSystemComponent("Picker") as
120
+ | DesignSystemComponents["Picker"]
121
+ | undefined;
122
+ const DefaultComponent = defaultDesignSystemComponents.Picker;
123
+ const fallback = <DefaultComponent {...props} />;
124
+ if (!CustomComponent || CustomComponent === DefaultComponent) return fallback;
125
+ return (
126
+ <DesignSystemErrorBoundary component="Picker" fallback={fallback}>
127
+ <CustomComponent {...props} />
128
+ </DesignSystemErrorBoundary>
129
+ );
130
+ }
131
+
132
+ export function Tabs<Value extends DesignSystemKey = string>(
133
+ props: TabsProps<Value>,
134
+ ) {
135
+ const CustomComponent = useDesignSystemComponent("Tabs") as
136
+ | DesignSystemComponents["Tabs"]
137
+ | undefined;
138
+ const DefaultComponent = defaultDesignSystemComponents.Tabs;
139
+ const fallback = <DefaultComponent {...props} />;
140
+ if (!CustomComponent || CustomComponent === DefaultComponent) return fallback;
141
+ return (
142
+ <DesignSystemErrorBoundary component="Tabs" fallback={fallback}>
143
+ <CustomComponent {...props} />
144
+ </DesignSystemErrorBoundary>
145
+ );
146
+ }
@@ -0,0 +1,31 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ import type { DesignSystemDefinition } from "./definition.js";
4
+ import type {
5
+ DesignSystemComponentName,
6
+ DesignSystemComponents,
7
+ } from "./types.js";
8
+
9
+ export interface DesignSystemContextValue {
10
+ definition?: DesignSystemDefinition;
11
+ legacyActionButton?: DesignSystemComponents["ActionButton"];
12
+ }
13
+
14
+ export const DesignSystemContext = createContext<DesignSystemContextValue>({});
15
+ export const LegacyButtonRenderContext = createContext(false);
16
+
17
+ export function useDesignSystem(): DesignSystemDefinition | undefined {
18
+ return useContext(DesignSystemContext).definition;
19
+ }
20
+
21
+ export function useDesignSystemComponent<
22
+ Name extends DesignSystemComponentName,
23
+ >(name: Name): DesignSystemComponents[Name] | undefined {
24
+ const context = useContext(DesignSystemContext);
25
+ const component = context.definition?.components?.[name];
26
+ if (component) return component as DesignSystemComponents[Name];
27
+ if (name === "ActionButton" && context.legacyActionButton) {
28
+ return context.legacyActionButton as DesignSystemComponents[Name];
29
+ }
30
+ return undefined;
31
+ }
@@ -0,0 +1,143 @@
1
+ // @vitest-environment happy-dom
2
+
3
+ import {
4
+ Children,
5
+ isValidElement,
6
+ type ReactElement,
7
+ type ReactNode,
8
+ } from "react";
9
+ import { describe, expect, it, vi } from "vitest";
10
+
11
+ import { defaultDesignSystemComponents } from "./default-adapter.js";
12
+
13
+ type TestElement = ReactElement<Record<string, unknown>>;
14
+
15
+ function findElement(
16
+ node: ReactNode,
17
+ predicate: (element: TestElement) => boolean,
18
+ ): TestElement | undefined {
19
+ if (Array.isArray(node)) {
20
+ for (const child of node) {
21
+ const match = findElement(child, predicate);
22
+ if (match) return match;
23
+ }
24
+ return undefined;
25
+ }
26
+ if (!isValidElement(node)) return undefined;
27
+ const element = node as TestElement;
28
+ if (predicate(element)) return element;
29
+ for (const child of Children.toArray(element.props.children as ReactNode)) {
30
+ const match = findElement(child, predicate);
31
+ if (match) return match;
32
+ }
33
+ return undefined;
34
+ }
35
+
36
+ function renderComponent(
37
+ component: unknown,
38
+ props: Record<string, unknown>,
39
+ ): TestElement {
40
+ return (component as (props: Record<string, unknown>) => ReactNode)(
41
+ props,
42
+ ) as TestElement;
43
+ }
44
+
45
+ describe("default design system adapter", () => {
46
+ it("maps visual size and shape props to default styles", () => {
47
+ const iconButton = renderComponent(
48
+ defaultDesignSystemComponents.IconButton,
49
+ {
50
+ label: "More",
51
+ icon: <span />,
52
+ size: "large",
53
+ },
54
+ );
55
+ const spinner = renderComponent(defaultDesignSystemComponents.Spinner, {
56
+ size: "compact",
57
+ });
58
+ const skeleton = renderComponent(defaultDesignSystemComponents.Skeleton, {
59
+ shape: "circle",
60
+ });
61
+ const avatar = renderComponent(defaultDesignSystemComponents.Avatar, {
62
+ name: "Ada Lovelace",
63
+ size: "compact",
64
+ status: "online",
65
+ });
66
+
67
+ expect(iconButton.props.className).toContain("h-12");
68
+ expect(spinner.props.className).toContain("size-3");
69
+ expect(skeleton.props.className).toContain("rounded-full");
70
+ expect(
71
+ findElement(avatar, (element) => element.props.role === "img")?.props
72
+ .className,
73
+ ).toContain("bg-green-500");
74
+ });
75
+
76
+ it("prevents outside dismissal when a dialog is not dismissible", () => {
77
+ const dialog = renderComponent(defaultDesignSystemComponents.Dialog, {
78
+ open: true,
79
+ onOpenChange: vi.fn(),
80
+ title: "Confirm",
81
+ children: <p>Confirm this action</p>,
82
+ dismissible: false,
83
+ });
84
+ const content = findElement(
85
+ dialog,
86
+ (element) => typeof element.props.onInteractOutside === "function",
87
+ );
88
+ const preventDefault = vi.fn();
89
+
90
+ (
91
+ content?.props.onInteractOutside as
92
+ | ((event: { preventDefault: () => void }) => void)
93
+ | undefined
94
+ )?.({ preventDefault });
95
+
96
+ expect(preventDefault).toHaveBeenCalledOnce();
97
+ });
98
+
99
+ it("honors menu selection state and closeOnAction", () => {
100
+ const onAction = vi.fn();
101
+ const menu = renderComponent(defaultDesignSystemComponents.Menu, {
102
+ trigger: <button type="button">Open</button>,
103
+ items: [{ id: "selected", label: "Selected", selected: true }],
104
+ onAction,
105
+ closeOnAction: false,
106
+ });
107
+ const content = (menu.props.children as TestElement[])[1];
108
+ const items = content.props.children as TestElement;
109
+ const renderedItems = (
110
+ items.type as (props: Record<string, unknown>) => ReactNode
111
+ )(items.props);
112
+ const item = findElement(
113
+ renderedItems,
114
+ (element) => element.props.checked === true,
115
+ );
116
+ const preventDefault = vi.fn();
117
+
118
+ (
119
+ item?.props.onSelect as
120
+ | ((event: { preventDefault: () => void }) => void)
121
+ | undefined
122
+ )?.({ preventDefault });
123
+
124
+ expect(item?.props.checked).toBe(true);
125
+ expect(preventDefault).toHaveBeenCalledOnce();
126
+ expect(onAction).toHaveBeenCalledWith("selected");
127
+ });
128
+
129
+ it("maps checkbox invalid state to aria-invalid", () => {
130
+ const checkbox = renderComponent(defaultDesignSystemComponents.Checkbox, {
131
+ checked: false,
132
+ onChange: vi.fn(),
133
+ invalid: true,
134
+ });
135
+ const input = findElement(
136
+ checkbox,
137
+ (element) => element.props["aria-invalid"] === true,
138
+ );
139
+
140
+ expect(input?.props["aria-invalid"]).toBe(true);
141
+ expect(input?.props.invalid).toBeUndefined();
142
+ });
143
+ });