@optiaxiom/proteus 1.0.0 → 1.1.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 (64) hide show
  1. package/dist/esm/_virtual/_openai-shim-script.js +3 -2
  2. package/dist/esm/assets/src/proteus-chart/{ProteusChart.css.ts.vanilla-BeRNNwBj.css → ProteusChart.css.ts.vanilla-yGx8JdKz.css} +2 -2
  3. package/dist/esm/assets/src/proteus-chart/{ProteusChartTooltipContent.css.ts.vanilla-Df_IhL_i.css → ProteusChartTooltipContent.css.ts.vanilla-HapBe2oo.css} +2 -2
  4. package/dist/esm/assets/src/proteus-document/{ProteusDocumentShell.css.ts.vanilla-CyMtrn1n.css → ProteusDocumentShell.css.ts.vanilla-BPytQ9pT.css} +2 -2
  5. package/dist/esm/assets/src/proteus-image-carousel/{ProteusImageCarousel.css.ts.vanilla-Dbf7yRF1.css → ProteusImageCarousel.css.ts.vanilla-DnlXoyv1.css} +2 -2
  6. package/dist/esm/assets/src/proteus-question/{ProteusQuestion.css.ts.vanilla-cmHZWqNR.css → ProteusQuestion.css.ts.vanilla-CpDgoW0l.css} +2 -2
  7. package/dist/esm/hooks/useEffectEvent.js +11 -10
  8. package/dist/esm/hooks/useObserveValue.js +24 -30
  9. package/dist/esm/icons/IconAngleLeft.js +13 -19
  10. package/dist/esm/icons/IconAngleRight.js +13 -19
  11. package/dist/esm/icons/IconX.js +10 -18
  12. package/dist/esm/icons/withIcon.js +17 -28
  13. package/dist/esm/index.js +22 -17
  14. package/dist/esm/proteus-action/ProteusAction.js +44 -39
  15. package/dist/esm/proteus-bridge/ProteusBridge.js +71 -85
  16. package/dist/esm/proteus-card-link/ProteusCardLink.js +24 -37
  17. package/dist/esm/proteus-chart/ProteusChart-css.js +14 -5
  18. package/dist/esm/proteus-chart/ProteusChart.js +86 -84
  19. package/dist/esm/proteus-chart/ProteusChartContext.js +3 -3
  20. package/dist/esm/proteus-chart/ProteusChartTooltipContent-css.js +23 -6
  21. package/dist/esm/proteus-chart/ProteusChartTooltipContent.js +52 -66
  22. package/dist/esm/proteus-data-table/ProteusDataTable.js +28 -29
  23. package/dist/esm/proteus-date-input/ProteusDateInput.js +23 -0
  24. package/dist/esm/proteus-document/ProteusDocumentContext.js +4 -3
  25. package/dist/esm/proteus-document/ProteusDocumentPathContext.js +6 -5
  26. package/dist/esm/proteus-document/ProteusDocumentRenderer.js +25 -33
  27. package/dist/esm/proteus-document/ProteusDocumentShell-css.js +32 -6
  28. package/dist/esm/proteus-document/ProteusDocumentShell.js +226 -219
  29. package/dist/esm/proteus-document/getProteusValue.js +28 -42
  30. package/dist/esm/proteus-document/resolveProteusProp.js +31 -49
  31. package/dist/esm/proteus-document/resolveProteusValue.js +73 -136
  32. package/dist/esm/proteus-document/schemas.js +42 -45
  33. package/dist/esm/proteus-document/useResolveProteusValues.js +10 -16
  34. package/dist/esm/proteus-element/ProteusElement.js +114 -180
  35. package/dist/esm/proteus-federated/ProteusFederated.js +51 -52
  36. package/dist/esm/proteus-file-icon/ProteusFileIcon.js +29 -38
  37. package/dist/esm/proteus-file-upload/ProteusFileUpload.js +107 -133
  38. package/dist/esm/proteus-image/ProteusImage.js +99 -106
  39. package/dist/esm/proteus-image/downloadFile.js +3 -2
  40. package/dist/esm/proteus-image-carousel/ProteusImageCarousel-css.js +49 -11
  41. package/dist/esm/proteus-image-carousel/ProteusImageCarousel.js +151 -163
  42. package/dist/esm/proteus-input/ProteusInput.js +19 -27
  43. package/dist/esm/proteus-length/ProteusLength.js +10 -0
  44. package/dist/esm/proteus-map/ProteusMap.js +18 -31
  45. package/dist/esm/proteus-map-index/ProteusMapIndex.js +11 -0
  46. package/dist/esm/proteus-pill-menu/ProteusPillMenu.js +65 -0
  47. package/dist/esm/proteus-pill-menu/useInputValueChangeInteraction.js +36 -0
  48. package/dist/esm/proteus-question/ProteusQuestion-css.js +40 -8
  49. package/dist/esm/proteus-question/ProteusQuestion.js +324 -400
  50. package/dist/esm/proteus-select/ProteusSelect.js +25 -40
  51. package/dist/esm/proteus-show/ProteusShow.js +10 -18
  52. package/dist/esm/proteus-switch/ProteusSwitch.js +33 -36
  53. package/dist/esm/proteus-textarea/ProteusTextarea.js +18 -27
  54. package/dist/esm/proteus-value/ProteusValue.js +4 -4
  55. package/dist/esm/schema/public-schema.js +4537 -0
  56. package/dist/esm/schema/runtime-schema.js +4460 -0
  57. package/dist/esm/spec.js +5 -1
  58. package/dist/esm/use-proteus-value/useProteusValue.js +8 -12
  59. package/dist/index.d.ts +516 -347
  60. package/dist/spec.d.ts +5 -9952
  61. package/package.json +4 -4
  62. package/dist/esm/icons/IconCalendar.js +0 -20
  63. package/dist/esm/schema/public-schema.json.js +0 -9026
  64. package/dist/esm/schema/runtime-schema.json.js +0 -8959
@@ -1,405 +1,329 @@
1
1
  "use client";
2
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
- import { IconArrowRight, IconPen } from '@optiaxiom/icons';
4
- import { Group, Text, Button, Box, Checkbox } from '@optiaxiom/react';
5
- import { InlineInput } from '@optiaxiom/react/unstable';
6
- import * as RovingFocus from '@radix-ui/react-roving-focus';
7
- import { useState, useCallback, useRef, useEffect } from 'react';
8
- import { IconAngleLeft } from '../icons/IconAngleLeft.js';
9
- import { IconAngleRight } from '../icons/IconAngleRight.js';
10
- import { IconX } from '../icons/IconX.js';
11
- import { useProteusDocumentContext } from '../proteus-document/ProteusDocumentContext.js';
12
- import { addon, choice, choiceGroup, question } from './ProteusQuestion-css.js';
13
-
2
+ import { useProteusDocumentContext } from "../proteus-document/ProteusDocumentContext.js";
3
+ import { IconAngleLeft } from "../icons/IconAngleLeft.js";
4
+ import { IconAngleRight } from "../icons/IconAngleRight.js";
5
+ import { IconX } from "../icons/IconX.js";
6
+ import { addon, choice, choiceGroup, question } from "./ProteusQuestion-css.js";
7
+ import { Box, Button, Checkbox, Group, Text } from "@optiaxiom/react";
8
+ import { useCallback, useEffect, useRef, useState } from "react";
9
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
+ import { InlineInput } from "@optiaxiom/react/unstable";
11
+ import { IconArrowRight, IconPen } from "@optiaxiom/icons";
12
+ import * as RovingFocus from "@radix-ui/react-roving-focus";
13
+ //#region src/proteus-question/ProteusQuestion.tsx
14
14
  function ProteusQuestion({ questions }) {
15
- const { onEvent, onTrack } = useProteusDocumentContext(
16
- "@optiaxiom/proteus/ProteusQuestion"
17
- );
18
- const [answers, setAnswers] = useState([]);
19
- const [currentIndex, setCurrentIndex] = useState(0);
20
- const value = answers[currentIndex];
21
- const valid = Array.isArray(value) && value.length > 0 && value.every(Boolean);
22
- const goBack = useCallback(() => {
23
- onTrack?.("Ask User Question Back", {
24
- fromIndex: String(currentIndex),
25
- toIndex: String(currentIndex - 1)
26
- });
27
- setCurrentIndex((i) => i - 1);
28
- }, [currentIndex, onTrack]);
29
- const onDismiss = useCallback(() => {
30
- onTrack?.("Ask User Question Dismissed", {
31
- questionIndex: String(currentIndex)
32
- });
33
- void onEvent({
34
- message: "[User declined to answer the question]"
35
- });
36
- }, [currentIndex, onEvent, onTrack]);
37
- const questionRef = useRef(null);
38
- const lastIndexRef = useRef(currentIndex);
39
- useEffect(() => {
40
- if (lastIndexRef.current !== currentIndex) {
41
- questionRef.current?.animate(
42
- [
43
- {
44
- opacity: 0,
45
- translate: currentIndex > lastIndexRef.current ? "8px" : "-8px"
46
- },
47
- {
48
- opacity: 1,
49
- translate: "0px"
50
- }
51
- ],
52
- {
53
- duration: 150
54
- }
55
- );
56
- lastIndexRef.current = currentIndex;
57
- }
58
- const item = questionRef.current?.querySelector("[data-selected]") ?? questionRef.current?.querySelector("[tabindex]");
59
- item?.focus();
60
- }, [currentIndex]);
61
- const otherInputRef = useRef(null);
62
- const otherItemRef = useRef(null);
63
- if (currentIndex >= questions.length) {
64
- return null;
65
- }
66
- const { options, question: question$1, type } = questions[currentIndex];
67
- const isLast = currentIndex === questions.length - 1;
68
- const otherValue = value?.find((v) => !options.includes(v));
69
- const otherChecked = otherValue !== void 0;
70
- const onComplete = () => {
71
- const answeredCount = answers.filter(
72
- (answer) => Array.isArray(answer) && answer.length > 0
73
- ).length;
74
- onTrack?.("Ask User Question Submitted", {
75
- answeredCount: String(answeredCount),
76
- skippedCount: String(questions.length - answeredCount),
77
- totalQuestions: String(questions.length)
78
- });
79
- return onEvent({
80
- message: answers.map(
81
- (value2, index) => `Q: ${questions[index].question}
82
- A: ${value2 || "[Not specified]"}`
83
- ).join("\n\n")
84
- });
85
- };
86
- const onValueChange = (value2) => {
87
- answers[currentIndex] = value2;
88
- setAnswers([...answers]);
89
- };
90
- const onSkip = () => {
91
- onTrack?.("Ask User Question Skipped", {
92
- questionIndex: String(currentIndex)
93
- });
94
- answers[currentIndex] = null;
95
- setAnswers([...answers]);
96
- if (isLast) {
97
- void onComplete();
98
- } else {
99
- setCurrentIndex((i) => i + 1);
100
- }
101
- };
102
- const onSubmit = () => {
103
- const currentValue = answers[currentIndex];
104
- if (currentValue) {
105
- const firstIndex = options.indexOf(currentValue[0]);
106
- onTrack?.("Ask User Question Option Selected", {
107
- isCustomText: String(currentValue.some((v) => !options.includes(v))),
108
- optionIndex: String(firstIndex),
109
- questionIndex: String(currentIndex)
110
- });
111
- }
112
- if (isLast) {
113
- void onComplete();
114
- } else {
115
- setCurrentIndex((i) => i + 1);
116
- }
117
- };
118
- return /* @__PURE__ */ jsxs(
119
- Group,
120
- {
121
- onKeyDown: (event) => {
122
- if (event.key === "Escape") {
123
- event.preventDefault();
124
- if (type === "multi_select" && valid) {
125
- onValueChange(null);
126
- } else {
127
- onSkip();
128
- }
129
- }
130
- if ((event.key === "ArrowLeft" || event.key === "ArrowRight") && !(event.target instanceof HTMLInputElement) && !event.target.isContentEditable) {
131
- event.preventDefault();
132
- if (event.key === "ArrowLeft" && currentIndex > 0) {
133
- goBack();
134
- } else if (event.key === "ArrowRight" && !isLast) {
135
- setCurrentIndex((i) => i + 1);
136
- }
137
- }
138
- },
139
- tabIndex: -1,
140
- ...question(),
141
- children: [
142
- /* @__PURE__ */ jsxs(Group, { flexDirection: "column", gap: "16", children: [
143
- /* @__PURE__ */ jsxs(Group, { pl: "16", children: [
144
- /* @__PURE__ */ jsx(Text, { flex: "1", fontWeight: "500", children: question$1 }),
145
- /* @__PURE__ */ jsxs(Group, { gap: "6", children: [
146
- questions.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
147
- /* @__PURE__ */ jsx(
148
- Button,
149
- {
150
- appearance: "subtle",
151
- "aria-label": "Previous",
152
- disabled: currentIndex === 0,
153
- icon: /* @__PURE__ */ jsx(IconAngleLeft, {}),
154
- onClick: (event) => {
155
- event.preventDefault();
156
- goBack();
157
- },
158
- size: "sm"
159
- }
160
- ),
161
- /* @__PURE__ */ jsxs(Text, { color: "fg.tertiary", fontSize: "sm", children: [
162
- currentIndex + 1,
163
- " of ",
164
- questions.length
165
- ] }),
166
- /* @__PURE__ */ jsx(
167
- Button,
168
- {
169
- appearance: "subtle",
170
- "aria-label": "Next",
171
- disabled: isLast,
172
- icon: /* @__PURE__ */ jsx(IconAngleRight, {}),
173
- onClick: (event) => {
174
- event.preventDefault();
175
- setCurrentIndex((i) => i + 1);
176
- },
177
- size: "sm"
178
- }
179
- )
180
- ] }),
181
- /* @__PURE__ */ jsx(
182
- Button,
183
- {
184
- appearance: "subtle",
185
- "aria-label": "Dismiss",
186
- icon: /* @__PURE__ */ jsx(IconX, {}),
187
- onClick: (event) => {
188
- event.preventDefault();
189
- onDismiss();
190
- },
191
- size: "sm"
192
- }
193
- )
194
- ] })
195
- ] }),
196
- /* @__PURE__ */ jsx(RovingFocus.Root, { asChild: true, loop: true, orientation: "vertical", ref: questionRef, children: /* @__PURE__ */ jsxs(
197
- Group,
198
- {
199
- role: type === "single_select" ? "radiogroup" : "listbox",
200
- ...choiceGroup(),
201
- children: [
202
- options.map((option, index) => {
203
- const checked = type === "single_select" ? value?.[0] === option : value?.includes(option);
204
- const disabled = type === "single_select" && otherChecked && !!otherValue;
205
- return /* @__PURE__ */ jsx(RovingFocus.Item, { asChild: true, children: /* @__PURE__ */ jsx(
206
- Box,
207
- {
208
- "aria-checked": type === "single_select" ? checked : void 0,
209
- "data-disabled": disabled ? "" : void 0,
210
- "data-selected": checked && type === "single_select" ? "" : void 0,
211
- onClick: () => {
212
- if (type === "single_select") {
213
- onValueChange([option]);
214
- onSubmit();
215
- } else {
216
- const current = value ?? [];
217
- onValueChange(
218
- checked ? current.filter((v) => v !== option) : [...current, option]
219
- );
220
- }
221
- },
222
- onFocus: () => {
223
- if (type === "single_select") {
224
- onValueChange([option]);
225
- }
226
- },
227
- onKeyDown: (event) => {
228
- if (type === "single_select" && event.key === "Enter") {
229
- event.preventDefault();
230
- onSubmit();
231
- } else if (type === "multi_select" && (event.key === "Enter" || event.key === " ")) {
232
- event.preventDefault();
233
- const current = value ?? [];
234
- onValueChange(
235
- checked ? current.filter((v) => v !== option) : [...current, option]
236
- );
237
- }
238
- },
239
- role: type === "single_select" ? "radio" : "option",
240
- tabIndex: 0,
241
- ...choice({ cursor: "pointer" }),
242
- children: /* @__PURE__ */ jsxs(Group, { gap: "12", children: [
243
- type === "single_select" ? /* @__PURE__ */ jsx(Box, { ...addon(), children: index + 1 }) : /* @__PURE__ */ jsx(
244
- Checkbox,
245
- {
246
- checked,
247
- hidden: true,
248
- pointerEvents: "none",
249
- tabIndex: -1
250
- }
251
- ),
252
- /* @__PURE__ */ jsx(Group, { flex: "1", flexDirection: "column", gap: "2", children: /* @__PURE__ */ jsx(Text, { children: option }) }),
253
- type === "single_select" && checked && /* @__PURE__ */ jsx(
254
- Box,
255
- {
256
- asChild: true,
257
- color: "fg.tertiary",
258
- h: "24",
259
- ml: "auto",
260
- w: "24",
261
- children: /* @__PURE__ */ jsx(IconArrowRight, {})
262
- }
263
- )
264
- ] })
265
- }
266
- ) }, option);
267
- }),
268
- /* @__PURE__ */ jsx(
269
- Box,
270
- {
271
- "aria-label": "Something else",
272
- "data-selected": otherChecked ? "" : void 0,
273
- role: "group",
274
- ...choice({ cursor: "text" }),
275
- children: /* @__PURE__ */ jsxs(Group, { gap: "12", children: [
276
- type === "single_select" ? /* @__PURE__ */ jsx(Box, { ...addon({ cursor: "pointer" }), children: /* @__PURE__ */ jsx(IconPen, {}) }) : /* @__PURE__ */ jsx(
277
- Checkbox,
278
- {
279
- checked: otherChecked,
280
- hidden: true,
281
- pointerEvents: "none",
282
- tabIndex: -1
283
- }
284
- ),
285
- /* @__PURE__ */ jsx(RovingFocus.Item, { asChild: true, children: /* @__PURE__ */ jsx(
286
- Group,
287
- {
288
- flex: "1",
289
- flexDirection: "column",
290
- gap: "2",
291
- onFocus: () => {
292
- if (type === "single_select" && !otherValue) {
293
- onValueChange([""]);
294
- }
295
- otherInputRef.current?.focus();
296
- },
297
- ref: otherItemRef,
298
- children: /* @__PURE__ */ jsx(
299
- InlineInput,
300
- {
301
- label: "Something else",
302
- onKeyDown: (event) => {
303
- if (event.key === "ArrowUp" || event.key === "ArrowDown") {
304
- event.preventDefault();
305
- otherItemRef.current?.focus();
306
- otherItemRef.current?.dispatchEvent(
307
- new KeyboardEvent("keydown", {
308
- bubbles: true,
309
- key: event.key
310
- })
311
- );
312
- } else if (event.key === "Enter") {
313
- onSubmit();
314
- }
315
- },
316
- onValueChange: (text) => {
317
- if (type === "single_select") {
318
- onValueChange([text]);
319
- } else {
320
- const current = value ?? [];
321
- onValueChange([
322
- ...current.filter((v) => options.includes(v)),
323
- ...text ? [text] : []
324
- ]);
325
- }
326
- },
327
- ref: otherInputRef,
328
- value: otherValue ?? ""
329
- }
330
- )
331
- }
332
- ) }),
333
- type === "single_select" && /* @__PURE__ */ jsx(
334
- Button,
335
- {
336
- appearance: otherValue ? "primary-opal" : "default",
337
- "aria-label": otherValue && (isLast ? "Submit" : "Next"),
338
- icon: otherValue && /* @__PURE__ */ jsx(IconArrowRight, {}),
339
- ml: "auto",
340
- onClick: (event) => {
341
- event.preventDefault();
342
- if (otherValue) {
343
- onSubmit();
344
- } else {
345
- onSkip();
346
- }
347
- },
348
- children: !otherValue && "Skip"
349
- }
350
- )
351
- ] })
352
- },
353
- "other"
354
- )
355
- ]
356
- }
357
- ) })
358
- ] }),
359
- type === "multi_select" && /* @__PURE__ */ jsxs(
360
- Group,
361
- {
362
- borderColor: "border.secondary",
363
- borderT: "1",
364
- gap: "8",
365
- pt: "16",
366
- px: "16",
367
- children: [
368
- /* @__PURE__ */ jsxs(Text, { children: [
369
- value?.length || 0,
370
- " selected"
371
- ] }),
372
- /* @__PURE__ */ jsx(
373
- Button,
374
- {
375
- ml: "auto",
376
- onClick: (event) => {
377
- event.preventDefault();
378
- onSkip();
379
- },
380
- children: "Skip"
381
- }
382
- ),
383
- /* @__PURE__ */ jsx(
384
- Button,
385
- {
386
- appearance: valid ? "primary-opal" : "default",
387
- "aria-label": isLast ? "Submit" : "Next",
388
- disabled: !valid,
389
- icon: /* @__PURE__ */ jsx(IconArrowRight, {}),
390
- onClick: (event) => {
391
- event.preventDefault();
392
- onSubmit();
393
- }
394
- }
395
- )
396
- ]
397
- }
398
- )
399
- ]
400
- }
401
- );
15
+ const { onEvent, onTrack } = useProteusDocumentContext("@optiaxiom/proteus/ProteusQuestion");
16
+ const [answers, setAnswers] = useState([]);
17
+ const [currentIndex, setCurrentIndex] = useState(0);
18
+ const value = answers[currentIndex];
19
+ const valid = Array.isArray(value) && value.length > 0 && value.every(Boolean);
20
+ const goBack = useCallback(() => {
21
+ onTrack?.("Ask User Question Back", {
22
+ fromIndex: String(currentIndex),
23
+ toIndex: String(currentIndex - 1)
24
+ });
25
+ setCurrentIndex((i) => i - 1);
26
+ }, [currentIndex, onTrack]);
27
+ const onDismiss = useCallback(() => {
28
+ onTrack?.("Ask User Question Dismissed", { questionIndex: String(currentIndex) });
29
+ onEvent({ message: "[User declined to answer the question]" });
30
+ }, [
31
+ currentIndex,
32
+ onEvent,
33
+ onTrack
34
+ ]);
35
+ const questionRef = useRef(null);
36
+ const lastIndexRef = useRef(currentIndex);
37
+ useEffect(() => {
38
+ if (lastIndexRef.current !== currentIndex) {
39
+ questionRef.current?.animate([{
40
+ opacity: 0,
41
+ translate: currentIndex > lastIndexRef.current ? "8px" : "-8px"
42
+ }, {
43
+ opacity: 1,
44
+ translate: "0px"
45
+ }], { duration: 150 });
46
+ lastIndexRef.current = currentIndex;
47
+ }
48
+ (questionRef.current?.querySelector("[data-selected]") ?? questionRef.current?.querySelector("[tabindex]"))?.focus();
49
+ }, [currentIndex]);
50
+ const otherInputRef = useRef(null);
51
+ const otherItemRef = useRef(null);
52
+ if (currentIndex >= questions.length) return null;
53
+ const { options, question: question$1, type } = questions[currentIndex];
54
+ const isLast = currentIndex === questions.length - 1;
55
+ const otherValue = value?.find((v) => !options.includes(v));
56
+ const otherChecked = otherValue !== void 0;
57
+ const onComplete = () => {
58
+ const answeredCount = answers.filter((answer) => Array.isArray(answer) && answer.length > 0).length;
59
+ onTrack?.("Ask User Question Submitted", {
60
+ answeredCount: String(answeredCount),
61
+ skippedCount: String(questions.length - answeredCount),
62
+ totalQuestions: String(questions.length)
63
+ });
64
+ return onEvent({ message: answers.map((value, index) => `Q: ${questions[index].question}\nA: ${value || "[Not specified]"}`).join("\n\n") });
65
+ };
66
+ const onValueChange = (value) => {
67
+ answers[currentIndex] = value;
68
+ setAnswers([...answers]);
69
+ };
70
+ const onSkip = () => {
71
+ onTrack?.("Ask User Question Skipped", { questionIndex: String(currentIndex) });
72
+ answers[currentIndex] = null;
73
+ setAnswers([...answers]);
74
+ if (isLast) onComplete();
75
+ else setCurrentIndex((i) => i + 1);
76
+ };
77
+ const onSubmit = () => {
78
+ const currentValue = answers[currentIndex];
79
+ if (currentValue) {
80
+ const firstIndex = options.indexOf(currentValue[0]);
81
+ onTrack?.("Ask User Question Option Selected", {
82
+ isCustomText: String(currentValue.some((v) => !options.includes(v))),
83
+ optionIndex: String(firstIndex),
84
+ questionIndex: String(currentIndex)
85
+ });
86
+ }
87
+ if (isLast) onComplete();
88
+ else setCurrentIndex((i) => i + 1);
89
+ };
90
+ return /* @__PURE__ */ jsxs(Group, {
91
+ onKeyDown: (event) => {
92
+ if (event.key === "Escape") {
93
+ event.preventDefault();
94
+ if (type === "multi_select" && valid) onValueChange(null);
95
+ else onSkip();
96
+ }
97
+ if ((event.key === "ArrowLeft" || event.key === "ArrowRight") && !(event.target instanceof HTMLInputElement) && !event.target.isContentEditable) {
98
+ event.preventDefault();
99
+ if (event.key === "ArrowLeft" && currentIndex > 0) goBack();
100
+ else if (event.key === "ArrowRight" && !isLast) setCurrentIndex((i) => i + 1);
101
+ }
102
+ },
103
+ tabIndex: -1,
104
+ ...question(),
105
+ children: [/* @__PURE__ */ jsxs(Group, {
106
+ flexDirection: "column",
107
+ gap: "16",
108
+ children: [/* @__PURE__ */ jsxs(Group, {
109
+ pl: "16",
110
+ children: [/* @__PURE__ */ jsx(Text, {
111
+ flex: "1",
112
+ fontWeight: "500",
113
+ children: question$1
114
+ }), /* @__PURE__ */ jsxs(Group, {
115
+ gap: "6",
116
+ children: [questions.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
117
+ /* @__PURE__ */ jsx(Button, {
118
+ appearance: "subtle",
119
+ "aria-label": "Previous",
120
+ disabled: currentIndex === 0,
121
+ icon: /* @__PURE__ */ jsx(IconAngleLeft, {}),
122
+ onClick: (event) => {
123
+ event.preventDefault();
124
+ goBack();
125
+ },
126
+ size: "sm"
127
+ }),
128
+ /* @__PURE__ */ jsxs(Text, {
129
+ color: "fg.tertiary",
130
+ fontSize: "sm",
131
+ children: [
132
+ currentIndex + 1,
133
+ " of ",
134
+ questions.length
135
+ ]
136
+ }),
137
+ /* @__PURE__ */ jsx(Button, {
138
+ appearance: "subtle",
139
+ "aria-label": "Next",
140
+ disabled: isLast,
141
+ icon: /* @__PURE__ */ jsx(IconAngleRight, {}),
142
+ onClick: (event) => {
143
+ event.preventDefault();
144
+ setCurrentIndex((i) => i + 1);
145
+ },
146
+ size: "sm"
147
+ })
148
+ ] }), /* @__PURE__ */ jsx(Button, {
149
+ appearance: "subtle",
150
+ "aria-label": "Dismiss",
151
+ icon: /* @__PURE__ */ jsx(IconX, {}),
152
+ onClick: (event) => {
153
+ event.preventDefault();
154
+ onDismiss();
155
+ },
156
+ size: "sm"
157
+ })]
158
+ })]
159
+ }), /* @__PURE__ */ jsx(RovingFocus.Root, {
160
+ asChild: true,
161
+ loop: true,
162
+ orientation: "vertical",
163
+ ref: questionRef,
164
+ children: /* @__PURE__ */ jsxs(Group, {
165
+ role: type === "single_select" ? "radiogroup" : "listbox",
166
+ ...choiceGroup(),
167
+ children: [options.map((option, index) => {
168
+ const checked = type === "single_select" ? value?.[0] === option : value?.includes(option);
169
+ const disabled = type === "single_select" && otherChecked && !!otherValue;
170
+ return /* @__PURE__ */ jsx(RovingFocus.Item, {
171
+ asChild: true,
172
+ children: /* @__PURE__ */ jsx(Box, {
173
+ "aria-checked": type === "single_select" ? checked : void 0,
174
+ "data-disabled": disabled ? "" : void 0,
175
+ "data-selected": checked && type === "single_select" ? "" : void 0,
176
+ onClick: () => {
177
+ if (type === "single_select") {
178
+ onValueChange([option]);
179
+ onSubmit();
180
+ } else {
181
+ const current = value ?? [];
182
+ onValueChange(checked ? current.filter((v) => v !== option) : [...current, option]);
183
+ }
184
+ },
185
+ onFocus: () => {
186
+ if (type === "single_select") onValueChange([option]);
187
+ },
188
+ onKeyDown: (event) => {
189
+ if (type === "single_select" && event.key === "Enter") {
190
+ event.preventDefault();
191
+ onSubmit();
192
+ } else if (type === "multi_select" && (event.key === "Enter" || event.key === " ")) {
193
+ event.preventDefault();
194
+ const current = value ?? [];
195
+ onValueChange(checked ? current.filter((v) => v !== option) : [...current, option]);
196
+ }
197
+ },
198
+ role: type === "single_select" ? "radio" : "option",
199
+ tabIndex: 0,
200
+ ...choice({ cursor: "pointer" }),
201
+ children: /* @__PURE__ */ jsxs(Group, {
202
+ gap: "12",
203
+ children: [
204
+ type === "single_select" ? /* @__PURE__ */ jsx(Box, {
205
+ ...addon(),
206
+ children: index + 1
207
+ }) : /* @__PURE__ */ jsx(Checkbox, {
208
+ checked,
209
+ hidden: true,
210
+ pointerEvents: "none",
211
+ tabIndex: -1
212
+ }),
213
+ /* @__PURE__ */ jsx(Group, {
214
+ flex: "1",
215
+ flexDirection: "column",
216
+ gap: "2",
217
+ children: /* @__PURE__ */ jsx(Text, { children: option })
218
+ }),
219
+ type === "single_select" && checked && /* @__PURE__ */ jsx(Box, {
220
+ asChild: true,
221
+ color: "fg.tertiary",
222
+ h: "24",
223
+ ml: "auto",
224
+ w: "24",
225
+ children: /* @__PURE__ */ jsx(IconArrowRight, {})
226
+ })
227
+ ]
228
+ })
229
+ })
230
+ }, option);
231
+ }), /* @__PURE__ */ jsx(Box, {
232
+ "aria-label": "Something else",
233
+ "data-selected": otherChecked ? "" : void 0,
234
+ role: "group",
235
+ ...choice({ cursor: "text" }),
236
+ children: /* @__PURE__ */ jsxs(Group, {
237
+ gap: "12",
238
+ children: [
239
+ type === "single_select" ? /* @__PURE__ */ jsx(Box, {
240
+ ...addon({ cursor: "pointer" }),
241
+ children: /* @__PURE__ */ jsx(IconPen, {})
242
+ }) : /* @__PURE__ */ jsx(Checkbox, {
243
+ checked: otherChecked,
244
+ hidden: true,
245
+ pointerEvents: "none",
246
+ tabIndex: -1
247
+ }),
248
+ /* @__PURE__ */ jsx(RovingFocus.Item, {
249
+ asChild: true,
250
+ children: /* @__PURE__ */ jsx(Group, {
251
+ flex: "1",
252
+ flexDirection: "column",
253
+ gap: "2",
254
+ onFocus: () => {
255
+ if (type === "single_select" && !otherValue) onValueChange([""]);
256
+ otherInputRef.current?.focus();
257
+ },
258
+ ref: otherItemRef,
259
+ children: /* @__PURE__ */ jsx(InlineInput, {
260
+ label: "Something else",
261
+ onKeyDown: (event) => {
262
+ if (event.key === "ArrowUp" || event.key === "ArrowDown") {
263
+ event.preventDefault();
264
+ otherItemRef.current?.focus();
265
+ otherItemRef.current?.dispatchEvent(new KeyboardEvent("keydown", {
266
+ bubbles: true,
267
+ key: event.key
268
+ }));
269
+ } else if (event.key === "Enter") onSubmit();
270
+ },
271
+ onValueChange: (text) => {
272
+ if (type === "single_select") onValueChange([text]);
273
+ else onValueChange([...(value ?? []).filter((v) => options.includes(v)), ...text ? [text] : []]);
274
+ },
275
+ ref: otherInputRef,
276
+ value: otherValue ?? ""
277
+ })
278
+ })
279
+ }),
280
+ type === "single_select" && /* @__PURE__ */ jsx(Button, {
281
+ appearance: otherValue ? "primary-opal" : "default",
282
+ "aria-label": otherValue && (isLast ? "Submit" : "Next"),
283
+ icon: otherValue && /* @__PURE__ */ jsx(IconArrowRight, {}),
284
+ ml: "auto",
285
+ onClick: (event) => {
286
+ event.preventDefault();
287
+ if (otherValue) onSubmit();
288
+ else onSkip();
289
+ },
290
+ children: !otherValue && "Skip"
291
+ })
292
+ ]
293
+ })
294
+ }, "other")]
295
+ })
296
+ })]
297
+ }), type === "multi_select" && /* @__PURE__ */ jsxs(Group, {
298
+ borderColor: "border.secondary",
299
+ borderT: "1",
300
+ gap: "8",
301
+ pt: "16",
302
+ px: "16",
303
+ children: [
304
+ /* @__PURE__ */ jsxs(Text, { children: [value?.length || 0, " selected"] }),
305
+ /* @__PURE__ */ jsx(Button, {
306
+ ml: "auto",
307
+ onClick: (event) => {
308
+ event.preventDefault();
309
+ onSkip();
310
+ },
311
+ children: "Skip"
312
+ }),
313
+ /* @__PURE__ */ jsx(Button, {
314
+ appearance: valid ? "primary-opal" : "default",
315
+ "aria-label": isLast ? "Submit" : "Next",
316
+ disabled: !valid,
317
+ icon: /* @__PURE__ */ jsx(IconArrowRight, {}),
318
+ onClick: (event) => {
319
+ event.preventDefault();
320
+ onSubmit();
321
+ }
322
+ })
323
+ ]
324
+ })]
325
+ });
402
326
  }
403
327
  ProteusQuestion.displayName = "@optiaxiom/proteus/ProteusQuestion";
404
-
328
+ //#endregion
405
329
  export { ProteusQuestion };