ionbase-ui 0.59.0 → 0.70.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 (114) hide show
  1. package/dist/components/AgentActivity.d.ts +2 -1
  2. package/dist/components/AgentActivity.d.ts.map +1 -1
  3. package/dist/components/AgentActivity.js +4 -17
  4. package/dist/components/AgentActivity.js.map +1 -1
  5. package/dist/components/Calendar.d.ts +20 -0
  6. package/dist/components/Calendar.d.ts.map +1 -0
  7. package/dist/components/Calendar.js +151 -0
  8. package/dist/components/Calendar.js.map +1 -0
  9. package/dist/components/CalendarPopover.d.ts +26 -0
  10. package/dist/components/CalendarPopover.d.ts.map +1 -0
  11. package/dist/components/CalendarPopover.js +45 -0
  12. package/dist/components/CalendarPopover.js.map +1 -0
  13. package/dist/components/DateField.d.ts +15 -0
  14. package/dist/components/DateField.d.ts.map +1 -0
  15. package/dist/components/DateField.js +74 -0
  16. package/dist/components/DateField.js.map +1 -0
  17. package/dist/components/DatePicker.d.ts +81 -0
  18. package/dist/components/DatePicker.d.ts.map +1 -0
  19. package/dist/components/DatePicker.js +102 -0
  20. package/dist/components/DatePicker.js.map +1 -0
  21. package/dist/components/DateRangePicker.d.ts +117 -0
  22. package/dist/components/DateRangePicker.d.ts.map +1 -0
  23. package/dist/components/DateRangePicker.js +152 -0
  24. package/dist/components/DateRangePicker.js.map +1 -0
  25. package/dist/components/Header.d.ts +10 -0
  26. package/dist/components/Header.d.ts.map +1 -1
  27. package/dist/components/Header.js +18 -3
  28. package/dist/components/Header.js.map +1 -1
  29. package/dist/components/NumberInput.d.ts +63 -0
  30. package/dist/components/NumberInput.d.ts.map +1 -0
  31. package/dist/components/NumberInput.js +102 -0
  32. package/dist/components/NumberInput.js.map +1 -0
  33. package/dist/components/PromptInput.d.ts +89 -0
  34. package/dist/components/PromptInput.d.ts.map +1 -0
  35. package/dist/components/PromptInput.js +130 -0
  36. package/dist/components/PromptInput.js.map +1 -0
  37. package/dist/components/ScrollProgress.d.ts +6 -0
  38. package/dist/components/ScrollProgress.d.ts.map +1 -1
  39. package/dist/components/ScrollProgress.js +2 -2
  40. package/dist/components/ScrollProgress.js.map +1 -1
  41. package/dist/components/SegmentedControl.d.ts +63 -0
  42. package/dist/components/SegmentedControl.d.ts.map +1 -0
  43. package/dist/components/SegmentedControl.js +79 -0
  44. package/dist/components/SegmentedControl.js.map +1 -0
  45. package/dist/components/Sidebar.d.ts +109 -0
  46. package/dist/components/Sidebar.d.ts.map +1 -0
  47. package/dist/components/Sidebar.js +106 -0
  48. package/dist/components/Sidebar.js.map +1 -0
  49. package/dist/components/Stepper.d.ts +73 -0
  50. package/dist/components/Stepper.d.ts.map +1 -0
  51. package/dist/components/Stepper.js +82 -0
  52. package/dist/components/Stepper.js.map +1 -0
  53. package/dist/components/Toast.d.ts +8 -1
  54. package/dist/components/Toast.d.ts.map +1 -1
  55. package/dist/components/Toast.js +2 -2
  56. package/dist/components/Toast.js.map +1 -1
  57. package/dist/components/ToolCall.d.ts +66 -0
  58. package/dist/components/ToolCall.d.ts.map +1 -0
  59. package/dist/components/ToolCall.js +78 -0
  60. package/dist/components/ToolCall.js.map +1 -0
  61. package/dist/components/agent-status.d.ts +14 -0
  62. package/dist/components/agent-status.d.ts.map +1 -0
  63. package/dist/components/agent-status.js +16 -0
  64. package/dist/components/agent-status.js.map +1 -0
  65. package/dist/components/index.d.ts +18 -1
  66. package/dist/components/index.d.ts.map +1 -1
  67. package/dist/components/index.js +8 -0
  68. package/dist/components/index.js.map +1 -1
  69. package/dist/components/iso-date.d.ts +53 -0
  70. package/dist/components/iso-date.d.ts.map +1 -0
  71. package/dist/components/iso-date.js +102 -0
  72. package/dist/components/iso-date.js.map +1 -0
  73. package/dist/figma-descriptions.json +107 -52
  74. package/dist/figma-map.json +735 -2
  75. package/dist/meta/AgentActivityStep.json +2 -2
  76. package/dist/meta/DatePicker.json +270 -0
  77. package/dist/meta/DateRangePicker.json +284 -0
  78. package/dist/meta/Header.json +32 -2
  79. package/dist/meta/NumberInput.json +407 -0
  80. package/dist/meta/PromptInput.json +212 -0
  81. package/dist/meta/ScrollProgress.json +26 -1
  82. package/dist/meta/SegmentedControl.json +217 -0
  83. package/dist/meta/SegmentedControlItem.json +122 -0
  84. package/dist/meta/Sidebar.json +150 -0
  85. package/dist/meta/SidebarItem.json +184 -0
  86. package/dist/meta/SidebarSection.json +131 -0
  87. package/dist/meta/Stepper.json +135 -0
  88. package/dist/meta/StepperStep.json +148 -0
  89. package/dist/meta/Tabs.json +5 -0
  90. package/dist/meta/ToastProvider.json +9 -2
  91. package/dist/meta/ToolCall.json +192 -0
  92. package/dist/meta/components.json +5812 -3293
  93. package/dist/meta/contrast.json +7776 -2478
  94. package/dist/meta/index.json +145 -3
  95. package/dist/meta/patterns/AgentRun.json +27 -0
  96. package/dist/meta/patterns/Form.json +9 -0
  97. package/dist/meta/patterns/PageShell.json +43 -3
  98. package/dist/meta/patterns/Wizard.json +20 -1
  99. package/dist/meta/patterns/index.json +10 -1
  100. package/dist/styles/date-picker.css +420 -0
  101. package/dist/styles/date-range-picker.css +280 -0
  102. package/dist/styles/header.css +26 -0
  103. package/dist/styles/index.css +15 -0
  104. package/dist/styles/number-input.css +83 -0
  105. package/dist/styles/prompt-input.css +127 -0
  106. package/dist/styles/scroll-progress.css +42 -4
  107. package/dist/styles/segmented-control.css +182 -0
  108. package/dist/styles/sidebar.css +307 -0
  109. package/dist/styles/stepper.css +250 -0
  110. package/dist/styles/table.css +9 -0
  111. package/dist/styles/tool-call.css +202 -0
  112. package/llms.txt +2 -2
  113. package/package.json +20 -19
  114. package/LICENSE +0 -21
@@ -0,0 +1,102 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef, useImperativeHandle, useRef } from 'react';
4
+ import { mergeProps, useButton, useFocusRing, useHover, useLocale, useNumberField, } from 'react-aria';
5
+ import { useNumberFieldState } from 'react-stately';
6
+ import { ARIA_TEXT_FIELD_NON_DOM_PROPS, omitProps } from './dom-props.js';
7
+ /* Props this component or the number-field hook consume, on top of a text field's. */
8
+ const NUMBER_FIELD_NON_DOM_PROPS = [
9
+ ...ARIA_TEXT_FIELD_NON_DOM_PROPS,
10
+ 'minValue',
11
+ 'maxValue',
12
+ 'step',
13
+ 'formatOptions',
14
+ 'commitBehavior',
15
+ 'isWheelDisabled',
16
+ 'incrementAriaLabel',
17
+ 'decrementAriaLabel',
18
+ ];
19
+ const Minus = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M6 12h12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
20
+ const Plus = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M12 6v12M6 12h12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
21
+ function StepButton({ children, ...props }) {
22
+ const ref = useRef(null);
23
+ const { buttonProps } = useButton(props, ref);
24
+ return (_jsx("button", { ...buttonProps, ref: ref, className: "ion-number-input__step", children: children }));
25
+ }
26
+ const toHook = (v) => (v === null ? NaN : v);
27
+ /**
28
+ * NumberInput — a quantity, with formatting, bounds and steps.
29
+ *
30
+ * NOT `<input type="number">`, and the list of reasons is the component:
31
+ *
32
+ * It scrolls. A focused `type="number"` changes value under the mouse wheel,
33
+ * so a user scrolling the page past a price field edits the price. The wheel
34
+ * is OFF here by default (`isWheelDisabled`), and a caller has to ask for it.
35
+ *
36
+ * It cannot format. "1,234.50", "€12", "15%" are text to the browser's number
37
+ * input, which rejects them. `formatOptions` takes `Intl.NumberFormatOptions`,
38
+ * so currency, percent and units display and parse in the user's locale —
39
+ * including "1.234,50" for a German user.
40
+ *
41
+ * It is not a number to the browser's validation either. `type="text"` with
42
+ * the right `inputMode` gets the numeric keyboard on a phone without
43
+ * Firefox letting letters in and Chrome silently reporting an empty value.
44
+ *
45
+ * EMPTY IS `null`, NOT `NaN`. React Aria reports an empty field as `NaN`, and
46
+ * `NaN === NaN` is false — so every "is it empty" check a caller writes is
47
+ * wrong. This converts at the boundary, both ways.
48
+ *
49
+ * − AND + SIT SIDE BY SIDE, NOT STACKED. Stacked chevrons split the field's
50
+ * height in two, which puts a Small field's targets at 16px — under the 24px
51
+ * WCAG 2.5.8 asks. Side by side, every size clears it. They are out of the tab
52
+ * order, as React Aria sets them: the arrow keys do the same job from the field,
53
+ * and two extra tab stops per number on a form is a tax on every keyboard user.
54
+ *
55
+ * The box is Input's, class for class, so every state — hover, focus, invalid,
56
+ * read-only, disabled — is Input's and cannot drift from it.
57
+ */
58
+ export const NumberInput = forwardRef((props, forwardedRef) => {
59
+ const { size = 'md', showStepper = true, isWheelDisabled = true, value, defaultValue, onChange, label, description, errorMessage, isDisabled, isReadOnly, className, wrapperClassName, ...rest } = props;
60
+ const { locale } = useLocale();
61
+ const hookProps = {
62
+ ...props,
63
+ isWheelDisabled,
64
+ value: value === undefined ? undefined : toHook(value),
65
+ defaultValue: defaultValue === undefined ? undefined : toHook(defaultValue),
66
+ onChange: onChange
67
+ ? (n) => onChange(Number.isNaN(n) ? null : n)
68
+ : undefined,
69
+ };
70
+ const state = useNumberFieldState({ ...hookProps, locale });
71
+ const ref = useRef(null);
72
+ useImperativeHandle(forwardedRef, () => ref.current);
73
+ const { labelProps, groupProps, inputProps, incrementButtonProps, decrementButtonProps, descriptionProps, errorMessageProps, isInvalid, } = useNumberField(hookProps, state, ref);
74
+ const { hoverProps, isHovered } = useHover({ isDisabled });
75
+ const { focusProps, isFocusVisible } = useFocusRing({ isTextInput: true });
76
+ const domProps = omitProps(rest, NUMBER_FIELD_NON_DOM_PROPS);
77
+ const box = (_jsxs("div", { ...mergeProps(groupProps, hoverProps), "data-hovered": isHovered || undefined, "data-focused": isFocusVisible || undefined, "data-invalid": isInvalid || undefined, "data-readonly": isReadOnly || undefined, "data-disabled": isDisabled || undefined, className: [
78
+ 'ion-input',
79
+ 'ion-number-input',
80
+ size !== 'md' ? `ion-input--${size}` : '',
81
+ showStepper ? 'ion-number-input--stepper' : '',
82
+ isInvalid ? 'ion-input--invalid' : '',
83
+ isReadOnly ? 'ion-input--readonly' : '',
84
+ isDisabled ? 'ion-input--disabled' : '',
85
+ className || '',
86
+ ]
87
+ .filter(Boolean)
88
+ .join(' '), children: [_jsx("input", { ...domProps, ...mergeProps(inputProps, focusProps), ref: ref, className: "ion-input__field ion-number-input__field" }), showStepper && (_jsxs("span", { className: "ion-number-input__steps", children: [_jsx(StepButton, { ...decrementButtonProps, children: _jsx(Minus, {}) }), _jsx(StepButton, { ...incrementButtonProps, children: _jsx(Plus, {}) })] }))] }));
89
+ const helper = isInvalid && errorMessage ? errorMessage : description;
90
+ const helperProps = isInvalid && errorMessage ? errorMessageProps : descriptionProps;
91
+ if (!label && !helper)
92
+ return box;
93
+ return (_jsxs("div", { className: [
94
+ 'ion-field',
95
+ isInvalid ? 'ion-field--error' : '',
96
+ wrapperClassName || '',
97
+ ]
98
+ .filter(Boolean)
99
+ .join(' '), children: [label && (_jsx("label", { ...labelProps, className: "ion-field__label", children: label })), box, helper && (_jsx("span", { ...helperProps, className: "ion-field__helper", children: helper }))] }));
100
+ });
101
+ NumberInput.displayName = 'NumberInput';
102
+ //# sourceMappingURL=NumberInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberInput.js","sourceRoot":"","sources":["../../src/components/NumberInput.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import React from 'react';
2
+ export type PromptInputSubmitKey = 'enter' | 'mod-enter';
3
+ export interface PromptInputProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'value' | 'defaultValue' | 'onChange' | 'onSubmit' | 'rows' | 'disabled' | 'children'> {
4
+ /**
5
+ * The accessible name of the text field. Required, and not a placeholder:
6
+ * placeholder text disappears the moment the user types, and is not reliably
7
+ * announced as a name.
8
+ */
9
+ label: string;
10
+ /** Controlled text. Pass `onChange` with it. */
11
+ value?: string;
12
+ /** Uncontrolled starting text. */
13
+ defaultValue?: string;
14
+ onChange?: (value: string) => void;
15
+ /**
16
+ * Fires with the text as typed. Uncontrolled, the field clears straight away;
17
+ * if the returned promise rejects, the text is put back — a prompt lost to a
18
+ * network error is the one thing a composer must never do.
19
+ */
20
+ onSubmit?: (value: string) => void | Promise<unknown>;
21
+ /**
22
+ * Which key sends. `enter` sends on Enter with Shift+Enter for a new line —
23
+ * a chat. `mod-enter` sends on Cmd/Ctrl+Enter and leaves Enter for new lines —
24
+ * a composer where messages are long and a stray Enter is expensive.
25
+ */
26
+ submitKey?: PromptInputSubmitKey;
27
+ /**
28
+ * A run is in progress. The send control becomes an `AgentStop` in the same
29
+ * place, and submitting is refused. The field stays editable, so the user can
30
+ * draft the next message while the agent works.
31
+ */
32
+ isRunning?: boolean;
33
+ /** Called by the stop control while `isRunning`. */
34
+ onStop?: () => void;
35
+ /** Passed to the stop control once the stop has been requested. */
36
+ isStopping?: boolean;
37
+ isDisabled?: boolean;
38
+ /** Rows the field starts at. */
39
+ minRows?: number;
40
+ /** Rows the field grows to before it scrolls. */
41
+ maxRows?: number;
42
+ /**
43
+ * Controls at the start of the toolbar — attach, a model picker, a tool
44
+ * toggle. Icon-only controls here need their own `aria-label`.
45
+ */
46
+ actions?: React.ReactNode;
47
+ /** Rendered above the text — attached files, a quoted message. */
48
+ attachments?: React.ReactNode;
49
+ /** Accessible name of the send control. */
50
+ sendLabel?: string;
51
+ /** Class names for the outer box. */
52
+ className?: string;
53
+ }
54
+ /**
55
+ * PromptInput — where a person writes to an agent.
56
+ *
57
+ * WHY IT IS NOT A TEXTAREA AND A BUTTON
58
+ *
59
+ * Every composer is assembled that way, and every one re-implements the same
60
+ * four bugs:
61
+ *
62
+ * Enter during IME composition sends half a word. Japanese, Chinese and
63
+ * Korean input confirm a candidate with Enter; a handler that does not check
64
+ * `isComposing` sends the message mid-character. That excludes whole
65
+ * languages from the product, silently, and nobody on an English keyboard
66
+ * ever sees it.
67
+ *
68
+ * The prompt is lost when sending fails. Clearing on submit is right —
69
+ * waiting for the server makes the composer feel broken — but clearing and
70
+ * never restoring destroys what may have been a long message. Uncontrolled,
71
+ * a rejected `onSubmit` promise puts the text back.
72
+ *
73
+ * The stop control lives somewhere else. While a run is going, the send
74
+ * button's place is exactly where the user's pointer and attention already
75
+ * are, so that is where `AgentStop` goes — the same control, the same
76
+ * guarantees, not a second stop button with different ones.
77
+ *
78
+ * The keyboard contract is invisible. "Enter sends, Shift+Enter for a new
79
+ * line" is announced through `aria-describedby`, because a screen-reader
80
+ * user who presses Enter expecting a newline has just sent a message.
81
+ *
82
+ * WHAT IT DOES NOT DO
83
+ *
84
+ * It does not upload, pick models or render messages. `attachments` and
85
+ * `actions` are slots, because what a product attaches and which tools it
86
+ * offers are the product's decisions.
87
+ */
88
+ export declare const PromptInput: React.ForwardRefExoticComponent<PromptInputProps & React.RefAttributes<HTMLTextAreaElement>>;
89
+ //# sourceMappingURL=PromptInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAQN,MAAM,OAAO,CAAC;AAIf,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,WAAW,CAAC;AAEzD,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,KAAK,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAC/C,OAAO,GACP,cAAc,GACd,UAAU,GACV,UAAU,GACV,MAAM,GACN,UAAU,GACV,UAAU,CACb;IACC;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD;;;;OAIG;IACH,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gCAAgC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,WAAW,8FAkKvB,CAAC"}
@@ -0,0 +1,130 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef, useEffect, useId, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
4
+ import { Button } from './Button.js';
5
+ import { AgentStop } from './AgentStop.js';
6
+ const SendGlyph = () => (_jsx("svg", { viewBox: "0 0 24 24", width: "16", height: "16", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M12 19V5m0 0-6 6m6-6 6 6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
7
+ /* useLayoutEffect warns during server rendering; the resize only matters in a browser. */
8
+ const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
9
+ /**
10
+ * PromptInput — where a person writes to an agent.
11
+ *
12
+ * WHY IT IS NOT A TEXTAREA AND A BUTTON
13
+ *
14
+ * Every composer is assembled that way, and every one re-implements the same
15
+ * four bugs:
16
+ *
17
+ * Enter during IME composition sends half a word. Japanese, Chinese and
18
+ * Korean input confirm a candidate with Enter; a handler that does not check
19
+ * `isComposing` sends the message mid-character. That excludes whole
20
+ * languages from the product, silently, and nobody on an English keyboard
21
+ * ever sees it.
22
+ *
23
+ * The prompt is lost when sending fails. Clearing on submit is right —
24
+ * waiting for the server makes the composer feel broken — but clearing and
25
+ * never restoring destroys what may have been a long message. Uncontrolled,
26
+ * a rejected `onSubmit` promise puts the text back.
27
+ *
28
+ * The stop control lives somewhere else. While a run is going, the send
29
+ * button's place is exactly where the user's pointer and attention already
30
+ * are, so that is where `AgentStop` goes — the same control, the same
31
+ * guarantees, not a second stop button with different ones.
32
+ *
33
+ * The keyboard contract is invisible. "Enter sends, Shift+Enter for a new
34
+ * line" is announced through `aria-describedby`, because a screen-reader
35
+ * user who presses Enter expecting a newline has just sent a message.
36
+ *
37
+ * WHAT IT DOES NOT DO
38
+ *
39
+ * It does not upload, pick models or render messages. `attachments` and
40
+ * `actions` are slots, because what a product attaches and which tools it
41
+ * offers are the product's decisions.
42
+ */
43
+ export const PromptInput = forwardRef(({ label, value: valueProp, defaultValue = '', onChange, onSubmit, submitKey = 'enter', isRunning = false, onStop, isStopping = false, isDisabled = false, minRows = 1, maxRows = 8, actions, attachments, sendLabel = 'Send', placeholder, className, onKeyDown, ...rest }, forwardedRef) => {
44
+ const ref = useRef(null);
45
+ useImperativeHandle(forwardedRef, () => ref.current);
46
+ const [internal, setInternal] = useState(defaultValue);
47
+ const isControlled = valueProp !== undefined;
48
+ const value = isControlled ? valueProp : internal;
49
+ const setValue = (next) => {
50
+ if (!isControlled)
51
+ setInternal(next);
52
+ onChange?.(next);
53
+ };
54
+ const hintId = useId();
55
+ const canSubmit = !isDisabled && !isRunning && value.trim().length > 0 && !!onSubmit;
56
+ /*
57
+ * Grow with the text up to `maxRows`, then scroll. Measured from the
58
+ * rendered line-height rather than a token, so it stays right inside a
59
+ * caller's own type scale.
60
+ */
61
+ useIsomorphicLayoutEffect(() => {
62
+ const el = ref.current;
63
+ if (!el)
64
+ return;
65
+ const style = window.getComputedStyle(el);
66
+ const line = parseFloat(style.lineHeight) || 24;
67
+ const padding = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
68
+ el.style.height = 'auto';
69
+ const min = line * minRows + padding;
70
+ const max = line * maxRows + padding;
71
+ const next = Math.min(Math.max(el.scrollHeight, min), max);
72
+ el.style.height = `${next}px`;
73
+ el.style.overflowY = el.scrollHeight > max ? 'auto' : 'hidden';
74
+ }, [value, minRows, maxRows]);
75
+ const submit = () => {
76
+ if (!canSubmit || !onSubmit)
77
+ return;
78
+ const sent = value;
79
+ const result = onSubmit(sent);
80
+ if (isControlled)
81
+ return;
82
+ setInternal('');
83
+ if (result && typeof result.then === 'function') {
84
+ result.then(undefined, () => {
85
+ // Put it back only if the user has not started typing something new.
86
+ setInternal((current) => (current === '' ? sent : current));
87
+ });
88
+ }
89
+ };
90
+ const handleKeyDown = (event) => {
91
+ onKeyDown?.(event);
92
+ if (event.defaultPrevented || event.key !== 'Enter')
93
+ return;
94
+ // An IME confirming a candidate also presses Enter. 229 covers Safari,
95
+ // which reports the keydown before setting isComposing.
96
+ if (event.nativeEvent.isComposing || event.keyCode === 229)
97
+ return;
98
+ const wantsSubmit = submitKey === 'enter'
99
+ ? !event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey
100
+ : event.metaKey || event.ctrlKey;
101
+ if (!wantsSubmit)
102
+ return;
103
+ event.preventDefault();
104
+ submit();
105
+ };
106
+ const hint = submitKey === 'enter'
107
+ ? 'Press Enter to send, Shift and Enter for a new line.'
108
+ : 'Press Command or Control and Enter to send.';
109
+ return (_jsxs("div", { className: [
110
+ 'ion-prompt-input',
111
+ isDisabled ? 'ion-prompt-input--disabled' : '',
112
+ className || '',
113
+ ]
114
+ .filter(Boolean)
115
+ .join(' '),
116
+ /*
117
+ * The whole box looks like the field, so a click on its padding should
118
+ * behave like a click on the field. Controls inside keep their own
119
+ * clicks.
120
+ */
121
+ onMouseDown: (event) => {
122
+ if (event.target === event.currentTarget) {
123
+ event.preventDefault();
124
+ ref.current?.focus();
125
+ }
126
+ }, children: [attachments && (_jsx("div", { className: "ion-prompt-input__attachments", children: attachments })), _jsx("textarea", { ...rest, ref: ref, rows: minRows, value: value, placeholder: placeholder, "aria-label": label, "aria-describedby": [rest['aria-describedby'], hintId].filter(Boolean).join(' ') ||
127
+ undefined, disabled: isDisabled, className: "ion-prompt-input__field", onChange: (event) => setValue(event.target.value), onKeyDown: handleKeyDown }), _jsxs("div", { className: "ion-prompt-input__toolbar", children: [_jsx("div", { className: "ion-prompt-input__actions", children: actions }), isRunning && onStop ? (_jsx(AgentStop, { size: "sm", onStop: onStop, isStopping: isStopping, className: "ion-prompt-input__stop" })) : (_jsx(Button, { variant: "primary-brand", size: "sm", "aria-label": sendLabel, startIcon: _jsx(SendGlyph, {}), isDisabled: !canSubmit, onPress: submit, className: "ion-prompt-input__send" }))] }), _jsx("span", { id: hintId, className: "ion-visually-hidden", children: hint })] }));
128
+ });
129
+ PromptInput.displayName = 'PromptInput';
130
+ //# sourceMappingURL=PromptInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromptInput.js","sourceRoot":"","sources":["../../src/components/PromptInput.tsx"],"names":[],"mappings":"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"}
@@ -3,6 +3,8 @@ export interface ScrollProgressSection {
3
3
  id: string;
4
4
  label: string;
5
5
  }
6
+ /** Which side of the rail the section list opens toward. */
7
+ export type ScrollProgressPlacement = 'right' | 'left';
6
8
  export interface ScrollProgressProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
7
9
  /** 0-100. The caller computes this from whatever it is tracking — a
8
10
  * window scroll fraction, a custom scroll container, a reading-time
@@ -16,6 +18,10 @@ export interface ScrollProgressProps extends Omit<React.HTMLAttributes<HTMLDivEl
16
18
  * itself; matching Menu, it reports the choice and lets the caller decide
17
19
  * what "select this section" means for their page. */
18
20
  onSelect?: (id: string) => void;
21
+ /** Which way the section list opens. `right` suits a rail on the left of the
22
+ * content; a rail against the right edge of the page needs `left`, or the
23
+ * open list runs off the screen. */
24
+ placement?: ScrollProgressPlacement;
19
25
  }
20
26
  /**
21
27
  * The compact rail is the disclosure trigger. It is a real `<button>`, so a
@@ -1 +1 @@
1
- {"version":3,"file":"ScrollProgress.d.ts","sourceRoot":"","sources":["../../src/components/ScrollProgress.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAC/C,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,UAAU,CACX;IACC;;iEAE6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC;6DACyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;2DAEuD;IACvD,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,4FAoK1B,CAAC"}
1
+ {"version":3,"file":"ScrollProgress.d.ts","sourceRoot":"","sources":["../../src/components/ScrollProgress.tsx"],"names":[],"mappings":"AAEA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4DAA4D;AAC5D,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAC/C,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,UAAU,CACX;IACC;;iEAE6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC;6DACyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;2DAEuD;IACvD,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC;;yCAEqC;IACrC,SAAS,CAAC,EAAE,uBAAuB,CAAC;CACrC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,4FA4K1B,CAAC"}
@@ -14,7 +14,7 @@ import { useHover } from 'react-aria';
14
14
  * needs to not trap the page once opened, not a full popover/focus-trap
15
15
  * implementation.
16
16
  */
17
- export const ScrollProgress = forwardRef(({ progress, sections, activeId, onSelect, className, ...rest }, forwardedRef) => {
17
+ export const ScrollProgress = forwardRef(({ progress, sections, activeId, onSelect, placement = 'right', className, ...rest }, forwardedRef) => {
18
18
  const [isOpen, setIsOpen] = useState(false);
19
19
  const isTriggerHovered = useRef(false);
20
20
  const isPanelHovered = useRef(false);
@@ -100,7 +100,7 @@ export const ScrollProgress = forwardRef(({ progress, sections, activeId, onSele
100
100
  : '',
101
101
  ]
102
102
  .filter(Boolean)
103
- .join(' ') }, section.id))) })] }), _jsx("div", { ...panelHoverProps, id: panelId, className: "ion-scroll-progress__panel", "data-open": isOpen || undefined, children: sections.map((section) => (_jsx("button", { type: "button", className: [
103
+ .join(' ') }, section.id))) })] }), _jsx("div", { ...panelHoverProps, id: panelId, className: `ion-scroll-progress__panel ion-scroll-progress__panel--${placement}`, "data-open": isOpen || undefined, children: sections.map((section) => (_jsx("button", { type: "button", className: [
104
104
  'ion-scroll-progress__heading',
105
105
  section.id === activeId
106
106
  ? 'ion-scroll-progress__heading--selected'
@@ -1 +1 @@
1
- {"version":3,"file":"ScrollProgress.js","sourceRoot":"","sources":["../../src/components/ScrollProgress.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScrollProgress.js","sourceRoot":"","sources":["../../src/components/ScrollProgress.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ export type SegmentedControlSize = 'sm' | 'md' | 'lg';
3
+ export interface SegmentedControlProps {
4
+ /**
5
+ * The accessible name of the group. Required: "List, Board, Calendar" means
6
+ * nothing until something says they are views.
7
+ */
8
+ label: string;
9
+ /** Show `label` above the control, as a form field does. Hidden by default. */
10
+ showLabel?: boolean;
11
+ /** Controlled selected value. Pass `onChange` with it. */
12
+ value?: string;
13
+ /**
14
+ * Uncontrolled starting value. One option should always be selected — a
15
+ * segmented control with nothing chosen reads as broken, not as "no choice".
16
+ */
17
+ defaultValue?: string;
18
+ onChange?: (value: string) => void;
19
+ size?: SegmentedControlSize;
20
+ /** Stretch to the container, with equal-width segments. */
21
+ isFullWidth?: boolean;
22
+ isDisabled?: boolean;
23
+ /** Submitted with a form under this name. */
24
+ name?: string;
25
+ /** `SegmentedControlItem` elements. Two to five of them. */
26
+ children?: React.ReactNode;
27
+ className?: string;
28
+ }
29
+ export interface SegmentedControlItemProps {
30
+ /** The value this segment selects. */
31
+ value: string;
32
+ /** Icon before the label. `aria-hidden` is applied for you. */
33
+ icon?: React.ReactNode;
34
+ /**
35
+ * Required when the segment has no visible text — an icon-only segment is
36
+ * otherwise announced as an unnamed radio button.
37
+ */
38
+ 'aria-label'?: string;
39
+ isDisabled?: boolean;
40
+ children?: React.ReactNode;
41
+ className?: string;
42
+ }
43
+ /**
44
+ * SegmentedControl — pick one of a few options, and see all of them.
45
+ *
46
+ * NOT TABS, ALTHOUGH IT LOOKS LIKE THE PILL TYPE, and the difference is the
47
+ * contract. Tabs switch between panels: `tablist`, `tab`, `tabpanel`, and each
48
+ * tab controls a region. This sets a VALUE — a view mode, a time range, a
49
+ * unit — and controls no panel. It is a `radiogroup`, so it has one tab stop,
50
+ * arrow keys move and select, and it submits with a form like any radio.
51
+ *
52
+ * Built from real radio inputs, visually hidden, not from buttons with
53
+ * `aria-pressed`. A row of toggle buttons is a tab stop per option and no
54
+ * mutual exclusion that assistive tech can announce; radios give "2 of 3,
55
+ * selected" for free.
56
+ *
57
+ * The look is Tabs' pill track, token for token, so the two cannot drift
58
+ * apart visually — which is exactly why the intent file spends its words on
59
+ * when to use which.
60
+ */
61
+ export declare const SegmentedControl: React.ForwardRefExoticComponent<SegmentedControlProps & React.RefAttributes<HTMLDivElement>>;
62
+ export declare const SegmentedControlItem: React.ForwardRefExoticComponent<SegmentedControlItemProps & React.RefAttributes<HTMLLabelElement>>;
63
+ //# sourceMappingURL=SegmentedControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../src/components/SegmentedControl.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAwD,MAAM,OAAO,CAAC;AAU7E,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAItD,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,2DAA2D;IAC3D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,8FAoE3B,CAAC;AAIH,eAAO,MAAM,oBAAoB,oGAkD/B,CAAC"}
@@ -0,0 +1,79 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { createContext, forwardRef, useContext, useRef } from 'react';
4
+ import { useFocusRing, useRadio, useRadioGroup, VisuallyHidden, } from 'react-aria';
5
+ import { useRadioGroupState } from 'react-stately';
6
+ const SegmentedContext = createContext(null);
7
+ /**
8
+ * SegmentedControl — pick one of a few options, and see all of them.
9
+ *
10
+ * NOT TABS, ALTHOUGH IT LOOKS LIKE THE PILL TYPE, and the difference is the
11
+ * contract. Tabs switch between panels: `tablist`, `tab`, `tabpanel`, and each
12
+ * tab controls a region. This sets a VALUE — a view mode, a time range, a
13
+ * unit — and controls no panel. It is a `radiogroup`, so it has one tab stop,
14
+ * arrow keys move and select, and it submits with a form like any radio.
15
+ *
16
+ * Built from real radio inputs, visually hidden, not from buttons with
17
+ * `aria-pressed`. A row of toggle buttons is a tab stop per option and no
18
+ * mutual exclusion that assistive tech can announce; radios give "2 of 3,
19
+ * selected" for free.
20
+ *
21
+ * The look is Tabs' pill track, token for token, so the two cannot drift
22
+ * apart visually — which is exactly why the intent file spends its words on
23
+ * when to use which.
24
+ */
25
+ export const SegmentedControl = forwardRef((props, ref) => {
26
+ const { label, showLabel = false, size = 'md', isFullWidth = false, isDisabled = false, children, className, } = props;
27
+ const state = useRadioGroupState({ ...props, isDisabled });
28
+ /*
29
+ * A hidden label is an `aria-label`, not a visually hidden element inside
30
+ * the group: a label node inside the radiogroup is read again as part of
31
+ * its content.
32
+ */
33
+ const { radioGroupProps, labelProps } = useRadioGroup({
34
+ ...props,
35
+ isDisabled,
36
+ orientation: 'horizontal',
37
+ label: showLabel ? label : undefined,
38
+ 'aria-label': showLabel ? undefined : label,
39
+ }, state);
40
+ const track = (_jsx("div", { ...radioGroupProps, ref: ref, className: [
41
+ 'ion-segmented-control',
42
+ size !== 'md' ? `ion-segmented-control--${size}` : '',
43
+ isFullWidth ? 'ion-segmented-control--full-width' : '',
44
+ className || '',
45
+ ]
46
+ .filter(Boolean)
47
+ .join(' '), children: _jsx(SegmentedContext.Provider, { value: state, children: children }) }));
48
+ if (!showLabel)
49
+ return track;
50
+ return (_jsxs("div", { className: [
51
+ 'ion-field',
52
+ 'ion-segmented-control-field',
53
+ isFullWidth ? 'ion-segmented-control-field--full-width' : '',
54
+ ]
55
+ .filter(Boolean)
56
+ .join(' '), children: [_jsx("span", { ...labelProps, className: "ion-field__label", children: label }), track] }));
57
+ });
58
+ SegmentedControl.displayName = 'SegmentedControl';
59
+ export const SegmentedControlItem = forwardRef((props, ref) => {
60
+ const { value, icon, isDisabled = false, children, className } = props;
61
+ const state = useContext(SegmentedContext);
62
+ if (!state) {
63
+ throw new Error('SegmentedControlItem must be rendered inside a SegmentedControl');
64
+ }
65
+ const inputRef = useRef(null);
66
+ const { inputProps, isSelected, isDisabled: disabled, } = useRadio({ value, isDisabled, children, 'aria-label': props['aria-label'] }, state, inputRef);
67
+ const { focusProps, isFocusVisible } = useFocusRing();
68
+ return (_jsxs("label", { ref: ref, className: [
69
+ 'ion-segmented-control__item',
70
+ isSelected ? 'ion-segmented-control__item--selected' : '',
71
+ disabled ? 'ion-segmented-control__item--disabled' : '',
72
+ isFocusVisible ? 'ion-segmented-control__item--focus-visible' : '',
73
+ className || '',
74
+ ]
75
+ .filter(Boolean)
76
+ .join(' '), children: [_jsx(VisuallyHidden, { children: _jsx("input", { ...inputProps, ...focusProps, ref: inputRef }) }), icon && (_jsx("span", { className: "ion-segmented-control__icon", "aria-hidden": "true", children: icon })), children && (_jsx("span", { className: "ion-segmented-control__label", children: children }))] }));
77
+ });
78
+ SegmentedControlItem.displayName = 'SegmentedControlItem';
79
+ //# sourceMappingURL=SegmentedControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../../src/components/SegmentedControl.tsx"],"names":[],"mappings":"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"}