@efolusi/meridian 1.5.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 (231) hide show
  1. package/README.md +12 -0
  2. package/ai/AgentRun.d.ts +20 -0
  3. package/ai/AgentRun.js +100 -0
  4. package/ai/ChatMessage.d.ts +19 -0
  5. package/ai/ChatMessage.js +81 -0
  6. package/ai/Citation.d.ts +23 -0
  7. package/ai/Citation.js +146 -0
  8. package/ai/Confirmation.d.ts +26 -0
  9. package/ai/Confirmation.js +84 -0
  10. package/ai/Conversation.d.ts +15 -0
  11. package/ai/Conversation.js +81 -0
  12. package/ai/DocumentCard.d.ts +17 -0
  13. package/ai/DocumentCard.js +101 -0
  14. package/ai/FeedbackBar.d.ts +14 -0
  15. package/ai/FeedbackBar.js +84 -0
  16. package/ai/GeneratedImage.d.ts +22 -0
  17. package/ai/GeneratedImage.js +100 -0
  18. package/ai/ModelSelector.d.ts +21 -0
  19. package/ai/ModelSelector.js +112 -0
  20. package/ai/Player.d.ts +18 -0
  21. package/ai/Player.js +201 -0
  22. package/ai/PromptComposer.d.ts +28 -0
  23. package/ai/PromptComposer.js +111 -0
  24. package/ai/PromptSteps.d.ts +18 -0
  25. package/ai/PromptSteps.js +167 -0
  26. package/ai/Reasoning.d.ts +17 -0
  27. package/ai/Reasoning.js +57 -0
  28. package/ai/RichComposer.d.ts +25 -0
  29. package/ai/RichComposer.js +247 -0
  30. package/ai/Sandbox.d.ts +20 -0
  31. package/ai/Sandbox.js +96 -0
  32. package/ai/SelectionQuote.d.ts +15 -0
  33. package/ai/SelectionQuote.js +123 -0
  34. package/ai/SourceCard.d.ts +17 -0
  35. package/ai/SourceCard.js +57 -0
  36. package/ai/Suggestions.d.ts +10 -0
  37. package/ai/Suggestions.js +38 -0
  38. package/ai/Task.d.ts +15 -0
  39. package/ai/Task.js +49 -0
  40. package/ai/Todo.d.ts +13 -0
  41. package/ai/Todo.js +87 -0
  42. package/ai/ToolCall.d.ts +30 -0
  43. package/ai/ToolCall.js +147 -0
  44. package/ai/Transcript.d.ts +27 -0
  45. package/ai/Transcript.js +96 -0
  46. package/ai/UsageMeter.d.ts +21 -0
  47. package/ai/UsageMeter.js +81 -0
  48. package/ai/WebPreview.d.ts +19 -0
  49. package/ai/WebPreview.js +179 -0
  50. package/assets/fonts/BricolageGrotesque-Variable.ttf +0 -0
  51. package/assets/fonts/Figtree-Italic-Variable.ttf +0 -0
  52. package/assets/fonts/Figtree-Variable.ttf +0 -0
  53. package/assets/fonts/JetBrainsMono-Italic-Variable.ttf +0 -0
  54. package/assets/fonts/JetBrainsMono-Variable.ttf +0 -0
  55. package/assets/fonts/OFL-BricolageGrotesque.txt +93 -0
  56. package/assets/fonts/OFL-Figtree.txt +93 -0
  57. package/assets/fonts/OFL-JetBrainsMono.txt +93 -0
  58. package/code/CodeBlock.d.ts +17 -0
  59. package/code/CodeBlock.js +99 -0
  60. package/code/Console.d.ts +19 -0
  61. package/code/Console.js +124 -0
  62. package/code/CopyField.d.ts +10 -0
  63. package/code/CopyField.js +54 -0
  64. package/code/Diff.d.ts +26 -0
  65. package/code/Diff.js +358 -0
  66. package/code/EnvList.d.ts +14 -0
  67. package/code/EnvList.js +89 -0
  68. package/code/Exception.d.ts +25 -0
  69. package/code/Exception.js +90 -0
  70. package/code/Terminal.d.ts +20 -0
  71. package/code/Terminal.js +58 -0
  72. package/data/BarChart.d.ts +14 -0
  73. package/data/BarChart.js +44 -0
  74. package/data/DonutChart.d.ts +17 -0
  75. package/data/DonutChart.js +114 -0
  76. package/data/EmptyState.d.ts +13 -0
  77. package/data/EmptyState.js +39 -0
  78. package/data/KeyValueList.d.ts +14 -0
  79. package/data/KeyValueList.js +34 -0
  80. package/data/LineChart.d.ts +15 -0
  81. package/data/LineChart.js +85 -0
  82. package/data/Skeleton.d.ts +11 -0
  83. package/data/Skeleton.js +49 -0
  84. package/data/Sparkline.d.ts +14 -0
  85. package/data/Sparkline.js +42 -0
  86. package/data/Stat.d.ts +14 -0
  87. package/data/Stat.js +40 -0
  88. package/data/StatusDot.d.ts +10 -0
  89. package/data/StatusDot.js +34 -0
  90. package/data/Table.d.ts +53 -0
  91. package/data/Table.js +174 -0
  92. package/dates/Calendar.d.ts +8 -0
  93. package/dates/Calendar.js +143 -0
  94. package/dates/DatePicker.d.ts +12 -0
  95. package/dates/DatePicker.js +118 -0
  96. package/display/Accordion.d.ts +15 -0
  97. package/display/Accordion.js +52 -0
  98. package/display/AspectRatio.d.ts +8 -0
  99. package/display/AspectRatio.js +24 -0
  100. package/display/Avatar.d.ts +17 -0
  101. package/display/Avatar.js +52 -0
  102. package/display/Badge.d.ts +10 -0
  103. package/display/Badge.js +34 -0
  104. package/display/Card.d.ts +17 -0
  105. package/display/Card.js +51 -0
  106. package/display/Carousel.d.ts +16 -0
  107. package/display/Carousel.js +97 -0
  108. package/display/Collapsible.d.ts +12 -0
  109. package/display/Collapsible.js +46 -0
  110. package/display/Divider.d.ts +9 -0
  111. package/display/Divider.js +33 -0
  112. package/display/Kbd.d.ts +7 -0
  113. package/display/Kbd.js +18 -0
  114. package/display/Link.d.ts +12 -0
  115. package/display/Link.js +41 -0
  116. package/display/ListItem.d.ts +19 -0
  117. package/display/ListItem.js +61 -0
  118. package/display/Resizable.d.ts +16 -0
  119. package/display/Resizable.js +90 -0
  120. package/display/ScrollArea.d.ts +8 -0
  121. package/display/ScrollArea.js +28 -0
  122. package/display/Tag.d.ts +9 -0
  123. package/display/Tag.js +41 -0
  124. package/display/Toolbar.d.ts +22 -0
  125. package/display/Toolbar.js +55 -0
  126. package/display/TreeList.d.ts +20 -0
  127. package/display/TreeList.js +101 -0
  128. package/feedback/Alert.d.ts +14 -0
  129. package/feedback/Alert.js +56 -0
  130. package/feedback/Banner.d.ts +15 -0
  131. package/feedback/Banner.js +49 -0
  132. package/feedback/ConfirmDialog.d.ts +18 -0
  133. package/feedback/ConfirmDialog.js +49 -0
  134. package/feedback/Dialog.d.ts +13 -0
  135. package/feedback/Dialog.js +107 -0
  136. package/feedback/Loader.d.ts +12 -0
  137. package/feedback/Loader.js +41 -0
  138. package/feedback/Progress.d.ts +15 -0
  139. package/feedback/Progress.js +48 -0
  140. package/feedback/Spinner.d.ts +9 -0
  141. package/feedback/Spinner.js +38 -0
  142. package/feedback/Toast.d.ts +70 -0
  143. package/feedback/Toast.js +216 -0
  144. package/feedback/Tooltip.d.ts +12 -0
  145. package/feedback/Tooltip.js +86 -0
  146. package/files/FileDrop.d.ts +15 -0
  147. package/files/FileDrop.js +75 -0
  148. package/files/FileTile.d.ts +19 -0
  149. package/files/FileTile.js +96 -0
  150. package/files/FileTypeIcon.d.ts +11 -0
  151. package/files/FileTypeIcon.js +121 -0
  152. package/finance/PaymentCard.d.ts +17 -0
  153. package/finance/PaymentCard.js +109 -0
  154. package/forms/Button.d.ts +15 -0
  155. package/forms/Button.js +82 -0
  156. package/forms/ButtonGroup.d.ts +5 -0
  157. package/forms/ButtonGroup.js +22 -0
  158. package/forms/ButtonTile.d.ts +21 -0
  159. package/forms/ButtonTile.js +69 -0
  160. package/forms/Checkbox.d.ts +6 -0
  161. package/forms/Checkbox.js +52 -0
  162. package/forms/Combobox.d.ts +17 -0
  163. package/forms/Combobox.js +162 -0
  164. package/forms/DigitEntry.d.ts +15 -0
  165. package/forms/DigitEntry.js +88 -0
  166. package/forms/FormField.d.ts +39 -0
  167. package/forms/FormField.js +127 -0
  168. package/forms/IconButton.d.ts +11 -0
  169. package/forms/IconButton.js +41 -0
  170. package/forms/Input.d.ts +14 -0
  171. package/forms/Input.js +75 -0
  172. package/forms/InputGroup.d.ts +15 -0
  173. package/forms/InputGroup.js +59 -0
  174. package/forms/Label.d.ts +11 -0
  175. package/forms/Label.js +29 -0
  176. package/forms/Radio.d.ts +6 -0
  177. package/forms/Radio.js +46 -0
  178. package/forms/Select.d.ts +10 -0
  179. package/forms/Select.js +68 -0
  180. package/forms/Slider.d.ts +18 -0
  181. package/forms/Slider.js +75 -0
  182. package/forms/Switch.d.ts +6 -0
  183. package/forms/Switch.js +46 -0
  184. package/forms/Textarea.d.ts +8 -0
  185. package/forms/Textarea.js +58 -0
  186. package/forms/Toggle.d.ts +26 -0
  187. package/forms/Toggle.js +85 -0
  188. package/icons/Icon.d.ts +13 -0
  189. package/icons/Icon.js +54 -0
  190. package/index.d.ts +106 -0
  191. package/index.js +106 -0
  192. package/navigation/Breadcrumbs.d.ts +12 -0
  193. package/navigation/Breadcrumbs.js +41 -0
  194. package/navigation/Menubar.d.ts +10 -0
  195. package/navigation/Menubar.js +173 -0
  196. package/navigation/PageControl.d.ts +11 -0
  197. package/navigation/PageControl.js +36 -0
  198. package/navigation/Pagination.d.ts +9 -0
  199. package/navigation/Pagination.js +68 -0
  200. package/navigation/SegmentedControl.d.ts +17 -0
  201. package/navigation/SegmentedControl.js +42 -0
  202. package/navigation/SideNav.d.ts +18 -0
  203. package/navigation/SideNav.js +87 -0
  204. package/navigation/Steps.d.ts +15 -0
  205. package/navigation/Steps.js +61 -0
  206. package/navigation/Tabs.d.ts +17 -0
  207. package/navigation/Tabs.js +76 -0
  208. package/navigation/TopNav.d.ts +10 -0
  209. package/navigation/TopNav.js +26 -0
  210. package/overlay/CommandPalette.d.ts +21 -0
  211. package/overlay/CommandPalette.js +164 -0
  212. package/overlay/ContextMenu.d.ts +11 -0
  213. package/overlay/ContextMenu.js +140 -0
  214. package/overlay/Drawer.d.ts +14 -0
  215. package/overlay/Drawer.js +99 -0
  216. package/overlay/HoverCard.d.ts +17 -0
  217. package/overlay/HoverCard.js +74 -0
  218. package/overlay/Menu.d.ts +24 -0
  219. package/overlay/Menu.js +153 -0
  220. package/overlay/Popover.d.ts +16 -0
  221. package/overlay/Popover.js +96 -0
  222. package/overlay/Portal.d.ts +10 -0
  223. package/overlay/Portal.js +127 -0
  224. package/package.json +41 -0
  225. package/styles.css +6 -0
  226. package/tokens/base.css +10 -0
  227. package/tokens/colors.css +38 -0
  228. package/tokens/effects.css +22 -0
  229. package/tokens/fonts.css +5 -0
  230. package/tokens/spacing.css +12 -0
  231. package/tokens/typography.css +9 -0
@@ -0,0 +1,69 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React from 'react';
3
+ import { Icon } from "../icons/Icon.js";
4
+ import { injectEfCss } from "./Button.js";
5
+ const CSS = `
6
+ .ef-tilegroup{display:grid;gap:10px}
7
+ .ef-tile{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:8px;padding:16px;border:1px solid var(--border-strong);border-radius:var(--radius-md);background:var(--surface-card);cursor:pointer;text-align:left;font-family:var(--font-sans);color:var(--text-primary);transition:border-color var(--dur-fast) var(--ease-out),background var(--dur-fast) var(--ease-out)}
8
+ .ef-tile:hover:not(:disabled){border-color:var(--sand-400)}
9
+ .ef-tile:focus-visible{outline:none;box-shadow:var(--focus-ring)}
10
+ .ef-tile:disabled{opacity:.45;cursor:not-allowed}
11
+ .ef-tile--on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
12
+ .ef-tile__icon{display:inline-flex;color:var(--text-secondary)}
13
+ .ef-tile--on .ef-tile__icon{color:var(--text-primary)}
14
+ .ef-tile__title{font-size:var(--text-md);font-weight:var(--weight-semibold)}
15
+ .ef-tile__desc{font-size:var(--text-sm);color:var(--text-muted);line-height:1.45}
16
+ .ef-tile__check{position:absolute;top:12px;right:12px;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:var(--radius-full);background:var(--accent);color:var(--accent-contrast);opacity:0;transform:scale(.6);transition:opacity var(--dur-fast) var(--ease-out),transform var(--dur-med) var(--ease-spring)}
17
+ .ef-tile--on .ef-tile__check{opacity:1;transform:scale(1)}
18
+ `;
19
+ export function ButtonTile({
20
+ icon,
21
+ title,
22
+ description,
23
+ selected,
24
+ disabled,
25
+ onClick,
26
+ style,
27
+ className,
28
+ ...rest
29
+ }) {
30
+ injectEfCss('ef-css-tile', CSS);
31
+ return /*#__PURE__*/React.createElement("button", _extends({}, rest, {
32
+ className: `ef-tile${selected ? ' ef-tile--on' : ''}${className ? ' ' + className : ''}`,
33
+ disabled: disabled,
34
+ "aria-pressed": !!selected,
35
+ onClick: onClick,
36
+ style: style
37
+ }), icon ? /*#__PURE__*/React.createElement("span", {
38
+ className: "ef-tile__icon"
39
+ }, /*#__PURE__*/React.createElement(Icon, {
40
+ name: icon,
41
+ size: 20
42
+ })) : null, /*#__PURE__*/React.createElement("span", {
43
+ className: "ef-tile__title"
44
+ }, title), description ? /*#__PURE__*/React.createElement("span", {
45
+ className: "ef-tile__desc"
46
+ }, description) : null, /*#__PURE__*/React.createElement("span", {
47
+ className: "ef-tile__check"
48
+ }, /*#__PURE__*/React.createElement(Icon, {
49
+ name: "check",
50
+ size: 11,
51
+ strokeWidth: 3
52
+ })));
53
+ }
54
+ export function ButtonTileGroup({
55
+ columns = 3,
56
+ children,
57
+ style,
58
+ className,
59
+ ...rest
60
+ }) {
61
+ injectEfCss('ef-css-tile', CSS);
62
+ return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
63
+ className: `ef-tilegroup${className ? ' ' + className : ''}`,
64
+ style: {
65
+ gridTemplateColumns: `repeat(${columns},1fr)`,
66
+ ...style
67
+ }
68
+ }), children);
69
+ }
@@ -0,0 +1,6 @@
1
+ export interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
2
+ label?: React.ReactNode;
3
+ /** Muted second line under the label */
4
+ description?: string;
5
+ }
6
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,52 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React from 'react';
3
+ import { Icon } from "../icons/Icon.js";
4
+ import { injectEfCss } from "./Button.js";
5
+ import { useFieldProps } from "./FormField.js";
6
+ const CSS = `
7
+ .ef-check{display:inline-flex;align-items:flex-start;gap:10px;cursor:pointer;user-select:none}
8
+ .ef-check--disabled{opacity:.45;cursor:not-allowed}
9
+ .ef-check__input{position:absolute;opacity:0;width:0;height:0}
10
+ .ef-check__box{display:inline-flex;align-items:center;justify-content:center;flex:none;width:18px;height:18px;margin-top:1px;border:1.5px solid var(--border-strong);border-radius:var(--radius-sm);background:var(--surface-card);color:var(--accent-contrast);transition:background var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out),transform var(--dur-med) var(--ease-spring)}
11
+ .ef-check__box svg{opacity:0;transform:scale(.5);transition:opacity var(--dur-fast) var(--ease-out),transform var(--dur-med) var(--ease-spring)}
12
+ .ef-check__input:checked+.ef-check__box{background:var(--accent);border-color:var(--accent)}
13
+ .ef-check__input:checked+.ef-check__box svg{opacity:1;transform:scale(1)}
14
+ .ef-check:active .ef-check__box{transform:scale(.95)}
15
+ .ef-check__input:focus-visible+.ef-check__box{box-shadow:var(--focus-ring)}
16
+ .ef-check__label{font-size:var(--text-md);color:var(--text-primary);line-height:1.4}
17
+ .ef-check__desc{display:block;font-size:var(--text-sm);color:var(--text-muted)}
18
+ `;
19
+ export const Checkbox = /*#__PURE__*/React.forwardRef(function Checkbox({
20
+ label,
21
+ description,
22
+ disabled,
23
+ style,
24
+ className,
25
+ ...rest
26
+ }, ref) {
27
+ injectEfCss('ef-css-check', CSS);
28
+ // Picks up id / aria wiring when nested in a FormField; standalone this is a no-op.
29
+ const field = useFieldProps({
30
+ id: rest.id,
31
+ 'aria-describedby': rest['aria-describedby']
32
+ });
33
+ return /*#__PURE__*/React.createElement("label", {
34
+ className: `ef-check${disabled ? ' ef-check--disabled' : ''}${className ? ' ' + className : ''}`,
35
+ style: style
36
+ }, /*#__PURE__*/React.createElement("input", _extends({
37
+ ref: ref,
38
+ type: "checkbox",
39
+ className: "ef-check__input",
40
+ disabled: disabled
41
+ }, rest, field.controlProps)), /*#__PURE__*/React.createElement("span", {
42
+ className: "ef-check__box"
43
+ }, /*#__PURE__*/React.createElement(Icon, {
44
+ name: "check",
45
+ size: 13,
46
+ strokeWidth: 3
47
+ })), label ? /*#__PURE__*/React.createElement("span", {
48
+ className: "ef-check__label"
49
+ }, label, description ? /*#__PURE__*/React.createElement("span", {
50
+ className: "ef-check__desc"
51
+ }, description) : null) : null);
52
+ });
@@ -0,0 +1,17 @@
1
+ export interface ComboOption { value: string; label: string; icon?: string; }
2
+ export interface ComboboxProps {
3
+ label?: string;
4
+ hint?: string;
5
+ /** Options as strings or {value,label,icon} */
6
+ options: Array<string | ComboOption>;
7
+ /** Selected value (single) or values (multiple) */
8
+ value?: string | string[] | null;
9
+ onChange?: (value: any) => void;
10
+ /** Multi-select with removable chips */
11
+ multiple?: boolean;
12
+ /** @default 'Search…' */
13
+ placeholder?: string;
14
+ style?: React.CSSProperties;
15
+ className?: string;
16
+ }
17
+ export declare function Combobox(props: ComboboxProps): React.JSX.Element;
@@ -0,0 +1,162 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React from 'react';
3
+ import { Icon } from "../icons/Icon.js";
4
+ import { Tag } from "../display/Tag.js";
5
+ import { injectEfCss } from "./Button.js";
6
+ import { useFieldProps } from "./FormField.js";
7
+ import { Portal, useAnchoredStyle } from "../overlay/Portal.js";
8
+ const CSS = `
9
+ .ef-combo{position:relative}
10
+ .ef-combo__control{display:flex;align-items:center;flex-wrap:wrap;gap:6px;min-height:var(--control-h-md);padding:4px 32px 4px 8px;border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:var(--surface-card);cursor:text;transition:border-color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
11
+ .ef-combo__control:hover{border-color:var(--sand-400)}
12
+ .ef-combo--open .ef-combo__control{border-color:var(--accent);box-shadow:var(--focus-ring)}
13
+ .ef-combo__input{flex:1;min-width:80px;border:none;outline:none;background:none;font-family:var(--font-sans);font-size:var(--text-md);color:var(--text-primary);height:26px;padding:0 4px}
14
+ .ef-combo__input::placeholder{color:var(--text-muted)}
15
+ .ef-combo__chevron{position:absolute;right:10px;top:50%;transform:translateY(-50%);color:var(--text-muted);display:inline-flex;pointer-events:none}
16
+ .ef-combo__panel{position:absolute;top:calc(100% + 6px);left:0;right:0;max-height:240px;overflow-y:auto;background:var(--surface-card);border:1px solid var(--border-strong);border-radius:var(--radius-md);box-shadow:var(--shadow-md);padding:4px;z-index:var(--z-dropdown);animation:ef-combo-in var(--dur-fast) var(--ease-out)}
17
+ @keyframes ef-combo-in{from{opacity:0;transform:translateY(-3px)}}
18
+ .ef-combo__opt{display:flex;align-items:center;gap:9px;width:100%;padding:7px 10px;border:none;border-radius:var(--radius-sm);background:none;cursor:pointer;text-align:left;font-family:var(--font-sans);font-size:var(--text-sm);color:var(--text-primary)}
19
+ .ef-combo__opt--hi{background:var(--surface-sunken)}
20
+ .ef-combo__opt__check{margin-left:auto;color:var(--accent);display:inline-flex}
21
+ .ef-combo__empty{padding:14px 10px;font-size:var(--text-sm);color:var(--text-muted);text-align:center}
22
+ `;
23
+ export function Combobox({
24
+ label,
25
+ hint,
26
+ options,
27
+ value,
28
+ onChange,
29
+ multiple,
30
+ placeholder = 'Search…',
31
+ style,
32
+ className,
33
+ ...rest
34
+ }) {
35
+ injectEfCss('ef-css-combo', CSS);
36
+ // Picks up id / aria wiring when nested in a FormField; standalone this is a no-op.
37
+ const field = useFieldProps({
38
+ id: rest.id,
39
+ 'aria-describedby': rest['aria-describedby']
40
+ });
41
+ const [open, setOpen] = React.useState(false);
42
+ const [q, setQ] = React.useState('');
43
+ const [hi, setHi] = React.useState(0);
44
+ const ref = React.useRef(null);
45
+ const panelRef = React.useRef(null);
46
+ const {
47
+ style: anchored
48
+ } = useAnchoredStyle(ref, panelRef, {
49
+ open,
50
+ placement: 'bottom',
51
+ align: 'start',
52
+ matchWidth: true
53
+ });
54
+ const sel = multiple ? value || [] : value != null ? [value] : [];
55
+ const opts = options.map(o => typeof o === 'string' ? {
56
+ value: o,
57
+ label: o
58
+ } : o);
59
+ const shown = opts.filter(o => o.label.toLowerCase().includes(q.toLowerCase()) && (!multiple || !sel.includes(o.value)));
60
+ React.useEffect(() => {
61
+ if (!open) return;
62
+ const away = e => {
63
+ const inControl = ref.current && ref.current.contains(e.target);
64
+ const inPanel = panelRef.current && panelRef.current.contains(e.target);
65
+ if (!inControl && !inPanel) setOpen(false);
66
+ };
67
+ document.addEventListener('mousedown', away);
68
+ return () => document.removeEventListener('mousedown', away);
69
+ }, [open]);
70
+ const pick = v => {
71
+ if (multiple) {
72
+ onChange && onChange([...sel, v]);
73
+ setQ('');
74
+ } else {
75
+ onChange && onChange(v);
76
+ setQ('');
77
+ setOpen(false);
78
+ }
79
+ };
80
+ const unpick = v => onChange && onChange(multiple ? sel.filter(x => x !== v) : null);
81
+ const key = e => {
82
+ if (e.key === 'ArrowDown') {
83
+ e.preventDefault();
84
+ setHi(h => Math.min(h + 1, shown.length - 1));
85
+ setOpen(true);
86
+ } else if (e.key === 'ArrowUp') {
87
+ e.preventDefault();
88
+ setHi(h => Math.max(h - 1, 0));
89
+ } else if (e.key === 'Enter' && open && shown[hi]) {
90
+ e.preventDefault();
91
+ pick(shown[hi].value);
92
+ } else if (e.key === 'Escape') setOpen(false);else if (e.key === 'Backspace' && !q && multiple && sel.length) unpick(sel[sel.length - 1]);
93
+ };
94
+ const control = /*#__PURE__*/React.createElement("div", {
95
+ ref: ref,
96
+ className: `ef-combo${open ? ' ef-combo--open' : ''}`
97
+ }, /*#__PURE__*/React.createElement("div", {
98
+ className: "ef-combo__control",
99
+ onClick: () => {
100
+ setOpen(true);
101
+ ref.current.querySelector('input').focus();
102
+ }
103
+ }, multiple && sel.map(v => {
104
+ const o = opts.find(x => x.value === v);
105
+ return /*#__PURE__*/React.createElement(Tag, {
106
+ key: v,
107
+ onRemove: () => unpick(v)
108
+ }, o ? o.label : v);
109
+ }), /*#__PURE__*/React.createElement("input", _extends({}, field.controlProps, {
110
+ className: "ef-combo__input",
111
+ role: "combobox",
112
+ "aria-expanded": open,
113
+ placeholder: sel.length && multiple ? '' : !multiple && sel.length ? (opts.find(x => x.value === sel[0]) || {}).label : placeholder,
114
+ value: q,
115
+ onChange: e => {
116
+ setQ(e.target.value);
117
+ setOpen(true);
118
+ setHi(0);
119
+ },
120
+ onFocus: () => setOpen(true),
121
+ onKeyDown: key
122
+ })), /*#__PURE__*/React.createElement("span", {
123
+ className: "ef-combo__chevron"
124
+ }, /*#__PURE__*/React.createElement(Icon, {
125
+ name: "chevron-down",
126
+ size: 16
127
+ }))), open && /*#__PURE__*/React.createElement(Portal, null, /*#__PURE__*/React.createElement("div", {
128
+ ref: panelRef,
129
+ className: "ef-combo__panel",
130
+ role: "listbox",
131
+ style: anchored
132
+ }, shown.length === 0 && /*#__PURE__*/React.createElement("div", {
133
+ className: "ef-combo__empty"
134
+ }, "Nothing matches \u201C", q, "\u201D."), shown.map((o, i) => /*#__PURE__*/React.createElement("button", {
135
+ key: o.value,
136
+ role: "option",
137
+ "aria-selected": !multiple && sel.includes(o.value),
138
+ className: `ef-combo__opt${i === hi ? ' ef-combo__opt--hi' : ''}`,
139
+ onMouseEnter: () => setHi(i),
140
+ onClick: () => pick(o.value)
141
+ }, o.icon ? /*#__PURE__*/React.createElement(Icon, {
142
+ name: o.icon,
143
+ size: 15
144
+ }) : null, o.label, !multiple && sel.includes(o.value) ? /*#__PURE__*/React.createElement("span", {
145
+ className: "ef-combo__opt__check"
146
+ }, /*#__PURE__*/React.createElement(Icon, {
147
+ name: "check",
148
+ size: 15
149
+ })) : null)))));
150
+ if (!label && !hint) return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
151
+ className: className,
152
+ style: style
153
+ }), control);
154
+ return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
155
+ className: `ef-field${className ? ' ' + className : ''}`,
156
+ style: style
157
+ }), label ? /*#__PURE__*/React.createElement("span", {
158
+ className: "ef-field__label"
159
+ }, label) : null, control, hint ? /*#__PURE__*/React.createElement("span", {
160
+ className: "ef-field__hint"
161
+ }, hint) : null);
162
+ }
@@ -0,0 +1,15 @@
1
+ export interface DigitEntryProps {
2
+ /** Number of cells @default 6 */
3
+ length?: number;
4
+ /** Controlled value (digits only) */
5
+ value?: string;
6
+ onChange?: (value: string) => void;
7
+ /** Fires when all cells are filled */
8
+ onComplete?: (value: string) => void;
9
+ label?: string;
10
+ invalid?: boolean;
11
+ disabled?: boolean;
12
+ style?: React.CSSProperties;
13
+ className?: string;
14
+ }
15
+ export declare function DigitEntry(props: DigitEntryProps): React.JSX.Element;
@@ -0,0 +1,88 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React from 'react';
3
+ import { injectEfCss } from "./Button.js";
4
+ import { useFieldProps } from "./FormField.js";
5
+ const CSS = `
6
+ .ef-digits{display:flex;gap:8px}
7
+ .ef-digits__cell{width:44px;height:52px;border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:var(--surface-card);color:var(--text-primary);font-family:var(--font-mono);font-size:22px;font-weight:600;text-align:center;transition:border-color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out)}
8
+ .ef-digits__cell:hover:not(:disabled){border-color:var(--sand-400)}
9
+ .ef-digits__cell:focus{outline:none;border-color:var(--accent);box-shadow:var(--focus-ring)}
10
+ .ef-digits__cell:disabled{background:var(--surface-sunken);cursor:not-allowed}
11
+ .ef-digits--invalid .ef-digits__cell{border-color:var(--danger-600)}
12
+ `;
13
+ export function DigitEntry({
14
+ length = 6,
15
+ value,
16
+ onChange,
17
+ onComplete,
18
+ label,
19
+ invalid,
20
+ disabled,
21
+ style,
22
+ className,
23
+ ...rest
24
+ }) {
25
+ injectEfCss('ef-css-digits', CSS);
26
+ // Picks up id / aria wiring when nested in a FormField; standalone this is a no-op.
27
+ const field = useFieldProps({
28
+ invalid,
29
+ id: rest.id,
30
+ 'aria-describedby': rest['aria-describedby']
31
+ });
32
+ const [inner, setInner] = React.useState('');
33
+ const v = value != null ? value : inner;
34
+ const refs = React.useRef([]);
35
+ const set = next => {
36
+ next = next.replace(/\D/g, '').slice(0, length);
37
+ if (value == null) setInner(next);
38
+ if (onChange) onChange(next);
39
+ if (next.length === length && onComplete) onComplete(next);
40
+ };
41
+ const keyAt = (i, e) => {
42
+ if (e.key === 'Backspace') {
43
+ e.preventDefault();
44
+ if (v[i]) set(v.slice(0, i) + v.slice(i + 1));else if (i > 0) {
45
+ set(v.slice(0, i - 1) + v.slice(i));
46
+ refs.current[i - 1] && refs.current[i - 1].focus();
47
+ }
48
+ } else if (e.key === 'ArrowLeft' && i > 0) refs.current[i - 1].focus();else if (e.key === 'ArrowRight' && i < length - 1) refs.current[i + 1].focus();
49
+ };
50
+ const inputAt = (i, e) => {
51
+ const ch = e.target.value.replace(/\D/g, '');
52
+ if (!ch) return;
53
+ const next = (v.slice(0, i) + ch + v.slice(i + ch.length)).slice(0, length);
54
+ set(next);
55
+ const to = Math.min(i + ch.length, length - 1);
56
+ refs.current[to] && refs.current[to].focus();
57
+ };
58
+ const cells = Array.from({
59
+ length
60
+ }, (_, i) => /*#__PURE__*/React.createElement("input", _extends({
61
+ key: i
62
+ }, i === 0 ? field.controlProps : null, {
63
+ ref: el => refs.current[i] = el,
64
+ className: "ef-digits__cell",
65
+ inputMode: "numeric",
66
+ autoComplete: i === 0 ? 'one-time-code' : 'off',
67
+ maxLength: length,
68
+ value: v[i] || '',
69
+ disabled: disabled,
70
+ "aria-label": `Digit ${i + 1} of ${length}`,
71
+ onChange: e => inputAt(i, e),
72
+ onKeyDown: e => keyAt(i, e),
73
+ onFocus: e => e.target.select()
74
+ })));
75
+ const group = /*#__PURE__*/React.createElement("div", {
76
+ className: `ef-digits${invalid ? ' ef-digits--invalid' : ''}`
77
+ }, cells);
78
+ if (!label) return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
79
+ className: className,
80
+ style: style
81
+ }), group);
82
+ return /*#__PURE__*/React.createElement("div", {
83
+ className: `ef-field${className ? ' ' + className : ''}`,
84
+ style: style
85
+ }, /*#__PURE__*/React.createElement("span", {
86
+ className: "ef-field__label"
87
+ }, label), group);
88
+ }
@@ -0,0 +1,39 @@
1
+ export interface FieldWiring {
2
+ /** The control's id. `null` in `group` mode, where no single child owns it. */
3
+ id: string | null;
4
+ invalid: boolean;
5
+ required: boolean;
6
+ /** Spread on the real control element, after `{...rest}`. */
7
+ controlProps: {
8
+ id?: string;
9
+ 'aria-describedby'?: string;
10
+ 'aria-invalid'?: true;
11
+ 'aria-required'?: true;
12
+ };
13
+ }
14
+ export interface FormFieldProps {
15
+ /** Rendered as `<label htmlFor>`, or a `<span id>` when `group`. */
16
+ label?: React.ReactNode;
17
+ /** Muted helper text below the control. Hidden while `error` is set. */
18
+ hint?: React.ReactNode;
19
+ /** Error message below the control. Truthy implies invalid. */
20
+ error?: React.ReactNode;
21
+ /** Invalid state with no message. @default false */
22
+ invalid?: boolean;
23
+ /** Red asterisk plus aria-required on the control. @default false */
24
+ required?: boolean;
25
+ /** Label a set of controls: role="group" + aria-labelledby. @default false */
26
+ group?: boolean;
27
+ /** The control's id. Generated with React.useId() when omitted. */
28
+ id?: string;
29
+ /** A control, or a function receiving the wiring to spread yourself. */
30
+ children?: React.ReactNode | ((field: FieldWiring) => React.ReactNode);
31
+ style?: React.CSSProperties;
32
+ className?: string;
33
+ }
34
+ /**
35
+ * Label / hint / error / required chrome around a control, and the owner of the
36
+ * id linking them. Design-system controls pick the wiring up from context; for
37
+ * anything else, pass a function and spread `controlProps` on the control.
38
+ */
39
+ export declare function FormField(props: FormFieldProps): React.JSX.Element;
@@ -0,0 +1,127 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React from 'react';
3
+ import { Icon } from "../icons/Icon.js";
4
+ import { injectEfCss } from "./Button.js";
5
+ const CSS = `
6
+ .ef-field{display:flex;flex-direction:column;gap:6px}
7
+ .ef-field__label{font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--text-primary)}
8
+ .ef-field__req{color:var(--danger-600);margin-left:2px}
9
+ .ef-field__hint{font-size:var(--text-xs);color:var(--text-muted)}
10
+ .ef-field__error{font-size:var(--text-xs);color:var(--danger-600);display:flex;align-items:center;gap:4px}
11
+ `;
12
+
13
+ // Module-private, never exported: a control outside a FormField simply sees
14
+ // null and behaves standalone. Same shape as GroupCtx in Toggle.jsx.
15
+ const FieldCtx = /*#__PURE__*/React.createContext(null);
16
+
17
+ /**
18
+ * How a control joins an enclosing FormField.
19
+ *
20
+ * Lowercase, so it stays off the public namespace. That is deliberate: no
21
+ * consumer needs it — design-system controls are wired by their own props, and
22
+ * anything else is wired through FormField's render prop — and keeping it
23
+ * unreachable stops a seventh field dialect being invented in a showcase.
24
+ */
25
+ export function useFieldProps(own = {}) {
26
+ const ctx = React.useContext(FieldCtx);
27
+ const invalid = !!(own.invalid || own.error || ctx && ctx.invalid);
28
+ const required = own.required != null ? !!own.required : !!(ctx && ctx.required);
29
+ const describedBy = [own['aria-describedby'], ctx && ctx.describedBy].filter(Boolean).join(' ');
30
+ const id = own.id || ctx && ctx.id || undefined;
31
+ // Keys are added conditionally, never assigned undefined: a control spreads
32
+ // {...rest} and then {...controlProps}, and an always-present key would reset
33
+ // a caller's own aria-invalid back to absent.
34
+ const controlProps = {};
35
+ if (id) controlProps.id = id;
36
+ if (describedBy) controlProps['aria-describedby'] = describedBy;
37
+ if (invalid) controlProps['aria-invalid'] = true;
38
+ if (required) controlProps['aria-required'] = true;
39
+ return {
40
+ inField: !!ctx,
41
+ id: id || null,
42
+ invalid,
43
+ required,
44
+ controlProps
45
+ };
46
+ }
47
+
48
+ /**
49
+ * Label, hint, error and required chrome around any control, and the owner of
50
+ * the id that ties them together.
51
+ *
52
+ * Wrap a control as children and design-system controls pick the wiring up
53
+ * automatically. For anything else — a third-party input, a control with no
54
+ * label prop — pass a function and spread the wiring yourself.
55
+ */
56
+ export function FormField({
57
+ label,
58
+ hint,
59
+ error,
60
+ invalid,
61
+ required,
62
+ group,
63
+ id,
64
+ children,
65
+ style,
66
+ className,
67
+ ...rest
68
+ }) {
69
+ injectEfCss('ef-css-field', CSS);
70
+ const uid = React.useId();
71
+ const controlId = id || uid + 'c';
72
+ const labelId = uid + 'l';
73
+ const noteId = uid + 'n';
74
+ const hasError = error != null && error !== false && error !== '';
75
+ const hasHint = !hasError && hint != null && hint !== false && hint !== '';
76
+ const note = hasError ? 'error' : hasHint ? 'hint' : null;
77
+ const bad = !!(invalid || hasError);
78
+ const ctx = React.useMemo(() => ({
79
+ // In group mode no single child owns the id — five radios cannot share one —
80
+ // so the group element carries the label and description instead.
81
+ id: group ? null : controlId,
82
+ describedBy: note && !group ? noteId : undefined,
83
+ invalid: bad,
84
+ required: !!required
85
+ }), [group, controlId, note, noteId, bad, required]);
86
+ const wiring = React.useMemo(() => {
87
+ const p = {};
88
+ if (ctx.id) p.id = ctx.id;
89
+ if (ctx.describedBy) p['aria-describedby'] = ctx.describedBy;
90
+ if (bad) p['aria-invalid'] = true;
91
+ if (required) p['aria-required'] = true;
92
+ return {
93
+ id: ctx.id,
94
+ invalid: bad,
95
+ required: !!required,
96
+ controlProps: p
97
+ };
98
+ }, [ctx, bad, required]);
99
+ const star = required ? /*#__PURE__*/React.createElement("span", {
100
+ className: "ef-field__req",
101
+ "aria-hidden": "true"
102
+ }, "*") : null;
103
+ return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
104
+ role: group ? 'group' : undefined,
105
+ "aria-labelledby": group && label ? labelId : undefined,
106
+ "aria-describedby": group && note ? noteId : undefined,
107
+ className: `ef-field${className ? ' ' + className : ''}`,
108
+ style: style
109
+ }), label ? group ? /*#__PURE__*/React.createElement("span", {
110
+ id: labelId,
111
+ className: "ef-field__label"
112
+ }, label, star) : /*#__PURE__*/React.createElement("label", {
113
+ htmlFor: controlId,
114
+ className: "ef-field__label"
115
+ }, label, star) : null, /*#__PURE__*/React.createElement(FieldCtx.Provider, {
116
+ value: ctx
117
+ }, typeof children === 'function' ? children(wiring) : children), hasError ? /*#__PURE__*/React.createElement("span", {
118
+ id: noteId,
119
+ className: "ef-field__error"
120
+ }, /*#__PURE__*/React.createElement(Icon, {
121
+ name: "circle-alert",
122
+ size: 13
123
+ }), error) : hasHint ? /*#__PURE__*/React.createElement("span", {
124
+ id: noteId,
125
+ className: "ef-field__hint"
126
+ }, hint) : null);
127
+ }
@@ -0,0 +1,11 @@
1
+ export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
2
+ /** Lucide icon name */
3
+ icon: string;
4
+ /** Accessible label (required — rendered as aria-label + title) */
5
+ label: string;
6
+ /** @default 'quiet' */
7
+ variant?: 'quiet' | 'outline' | 'solid';
8
+ /** @default 'md' */
9
+ size?: 'sm' | 'md' | 'lg';
10
+ }
11
+ export declare function IconButton(props: IconButtonProps): React.JSX.Element;
@@ -0,0 +1,41 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React from 'react';
3
+ import { Icon } from "../icons/Icon.js";
4
+ import { injectEfCss } from "./Button.js";
5
+ const CSS = `
6
+ .ef-iconbtn{display:inline-flex;align-items:center;justify-content:center;flex:none;border:1px solid transparent;border-radius:var(--radius-sm);background:transparent;color:var(--text-secondary);cursor:pointer;transition:background var(--dur-fast) var(--ease-out),color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out),transform var(--dur-med) var(--ease-spring)}
7
+ .ef-iconbtn:focus-visible{outline:none;box-shadow:var(--focus-ring)}
8
+ .ef-iconbtn:active:not(:disabled){transform:scale(.96)}
9
+ .ef-iconbtn:disabled{opacity:.45;cursor:not-allowed}
10
+ .ef-iconbtn--sm{width:var(--control-h-sm);height:var(--control-h-sm)}
11
+ .ef-iconbtn--md{width:var(--control-h-md);height:var(--control-h-md)}
12
+ .ef-iconbtn--lg{width:var(--control-h-lg);height:var(--control-h-lg)}
13
+ .ef-iconbtn--quiet:hover:not(:disabled){background:var(--surface-sunken);color:var(--text-primary)}
14
+ .ef-iconbtn--outline{border-color:var(--border-strong);background:transparent;color:var(--text-primary)}
15
+ .ef-iconbtn--outline:hover:not(:disabled){background:var(--surface-sunken)}
16
+ .ef-iconbtn--solid{background:var(--accent);color:var(--accent-contrast)}
17
+ .ef-iconbtn--solid:hover:not(:disabled){background:var(--accent-hover)}
18
+ `;
19
+ export function IconButton({
20
+ icon,
21
+ label,
22
+ variant = 'quiet',
23
+ size = 'md',
24
+ disabled,
25
+ style,
26
+ className,
27
+ ...rest
28
+ }) {
29
+ injectEfCss('ef-css-iconbtn', CSS);
30
+ const isz = size === 'sm' ? 16 : size === 'lg' ? 20 : 18;
31
+ return /*#__PURE__*/React.createElement("button", _extends({
32
+ "aria-label": label,
33
+ title: label,
34
+ className: `ef-iconbtn ef-iconbtn--${variant} ef-iconbtn--${size}${className ? ' ' + className : ''}`,
35
+ disabled: disabled,
36
+ style: style
37
+ }, rest), /*#__PURE__*/React.createElement(Icon, {
38
+ name: icon,
39
+ size: isz
40
+ }));
41
+ }
@@ -0,0 +1,14 @@
1
+ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
2
+ /** Field label rendered above */
3
+ label?: string;
4
+ /** Muted helper text below */
5
+ hint?: string;
6
+ /** Error message below — also sets invalid styling */
7
+ error?: string;
8
+ /** Lucide icon name inside the field, left */
9
+ iconLeft?: string;
10
+ /** @default 'md' */
11
+ size?: 'sm' | 'md' | 'lg';
12
+ invalid?: boolean;
13
+ }
14
+ export declare function Input(props: InputProps): React.JSX.Element;