@bettercms-ai/kit 2.0.0-next.0 → 2.0.0-next.2

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 (90) hide show
  1. package/dist/adapters/lossy.d.ts +9 -1
  2. package/dist/adapters/lossy.js +16 -5
  3. package/dist/adapters/lossy.js.map +1 -1
  4. package/dist/adapters/prod-types.d.ts +9 -22
  5. package/dist/adapters/prod-types.js +36 -35
  6. package/dist/adapters/prod-types.js.map +1 -1
  7. package/dist/adapters/schema.js +84 -39
  8. package/dist/adapters/schema.js.map +1 -1
  9. package/dist/context.d.ts +39 -0
  10. package/dist/context.js +40 -1
  11. package/dist/context.js.map +1 -1
  12. package/dist/controls/link.js +112 -196
  13. package/dist/controls/link.js.map +1 -1
  14. package/dist/controls/location.js +3 -8
  15. package/dist/controls/location.js.map +1 -1
  16. package/dist/controls/media.d.ts +0 -14
  17. package/dist/controls/media.js +52 -95
  18. package/dist/controls/media.js.map +1 -1
  19. package/dist/controls/rich-text/article-shell.d.ts +145 -0
  20. package/dist/controls/rich-text/article-shell.js +510 -0
  21. package/dist/controls/rich-text/article-shell.js.map +1 -0
  22. package/dist/controls/rich-text/author.d.ts +25 -0
  23. package/dist/controls/rich-text/author.js +104 -0
  24. package/dist/controls/rich-text/author.js.map +1 -0
  25. package/dist/controls/rich-text/blocks.d.ts +19 -2
  26. package/dist/controls/rich-text/blocks.js +273 -638
  27. package/dist/controls/rich-text/blocks.js.map +1 -1
  28. package/dist/controls/rich-text/button.d.ts +23 -0
  29. package/dist/controls/rich-text/button.js +85 -0
  30. package/dist/controls/rich-text/button.js.map +1 -0
  31. package/dist/controls/rich-text/catalog.d.ts +2 -5
  32. package/dist/controls/rich-text/catalog.js +120 -6
  33. package/dist/controls/rich-text/catalog.js.map +1 -1
  34. package/dist/controls/rich-text/checklist.d.ts +24 -0
  35. package/dist/controls/rich-text/checklist.js +115 -0
  36. package/dist/controls/rich-text/checklist.js.map +1 -0
  37. package/dist/controls/rich-text/codec.d.ts +10 -1
  38. package/dist/controls/rich-text/codec.js +11 -1
  39. package/dist/controls/rich-text/codec.js.map +1 -1
  40. package/dist/controls/rich-text/columns.d.ts +41 -0
  41. package/dist/controls/rich-text/columns.js +181 -0
  42. package/dist/controls/rich-text/columns.js.map +1 -0
  43. package/dist/controls/rich-text/control.js +1 -0
  44. package/dist/controls/rich-text/control.js.map +1 -1
  45. package/dist/controls/rich-text/dom.d.ts +84 -4
  46. package/dist/controls/rich-text/dom.js +171 -10
  47. package/dist/controls/rich-text/dom.js.map +1 -1
  48. package/dist/controls/rich-text/editor.d.ts +4 -2
  49. package/dist/controls/rich-text/editor.js +184 -12
  50. package/dist/controls/rich-text/editor.js.map +1 -1
  51. package/dist/controls/rich-text/embed.d.ts +28 -0
  52. package/dist/controls/rich-text/embed.js +210 -0
  53. package/dist/controls/rich-text/embed.js.map +1 -0
  54. package/dist/controls/rich-text/footnote.d.ts +41 -0
  55. package/dist/controls/rich-text/footnote.js +185 -0
  56. package/dist/controls/rich-text/footnote.js.map +1 -0
  57. package/dist/controls/rich-text/gallery.d.ts +28 -0
  58. package/dist/controls/rich-text/gallery.js +167 -0
  59. package/dist/controls/rich-text/gallery.js.map +1 -0
  60. package/dist/controls/rich-text/link-form.d.ts +3 -1
  61. package/dist/controls/rich-text/link-form.js +2 -2
  62. package/dist/controls/rich-text/link-form.js.map +1 -1
  63. package/dist/controls/rich-text/ops.js +6 -0
  64. package/dist/controls/rich-text/ops.js.map +1 -1
  65. package/dist/controls/rich-text/related.d.ts +36 -0
  66. package/dist/controls/rich-text/related.js +213 -0
  67. package/dist/controls/rich-text/related.js.map +1 -0
  68. package/dist/controls/rich-text/toc.d.ts +47 -0
  69. package/dist/controls/rich-text/toc.js +160 -0
  70. package/dist/controls/rich-text/toc.js.map +1 -0
  71. package/dist/core/core.d.ts +11 -3
  72. package/dist/core/core.js +24 -6
  73. package/dist/core/core.js.map +1 -1
  74. package/dist/core/facets.d.ts +16 -0
  75. package/dist/core/facets.js +17 -1
  76. package/dist/core/facets.js.map +1 -1
  77. package/dist/core/index.js +2 -2
  78. package/dist/index.js +4 -4
  79. package/dist/library/kit-catalog.json +47 -44
  80. package/dist/schema/types.d.ts +15 -0
  81. package/dist/schema/types.js.map +1 -1
  82. package/dist/styles.css +1 -1
  83. package/dist/ui/autocomplete.d.ts +29 -1
  84. package/dist/ui/autocomplete.js +102 -47
  85. package/dist/ui/autocomplete.js.map +1 -1
  86. package/dist/ui/button.js +3 -5
  87. package/dist/ui/button.js.map +1 -1
  88. package/dist/ui/index.js +2 -2
  89. package/dist/ui/toast.js +1 -1
  90. package/package.json +3 -1
@@ -18,13 +18,41 @@ export interface AutocompleteProps {
18
18
  filter?: ((options: SelectOption[], query: string) => SelectOption[]) | null;
19
19
  placeholder?: string;
20
20
  size?: "sm" | "md" | "lg";
21
+ /** decorative icon before the input */
21
22
  leading?: React.ReactNode;
23
+ /** an interactive control inside the field before the input (the link-type menu); rendered as is */
24
+ leadingSlot?: React.ReactNode;
22
25
  loading?: boolean;
23
26
  invalid?: boolean;
24
27
  disabled?: boolean;
25
28
  /** open the suggestions when the field takes focus (default true, as V2) */
26
29
  openOnFocus?: boolean;
30
+ /** controlled open; the list shows while open and it has rows or a note */
31
+ open?: boolean;
32
+ onOpenChange?: (open: boolean) => void;
33
+ /** render the list in the flow under the field instead of a floating popup (panels, popovers) */
34
+ inlineList?: boolean;
35
+ /** a status row shown, with the list kept open, when no row matches */
36
+ emptyNote?: React.ReactNode;
37
+ /** a status row under the rows when there are rows (a partial-load error) */
38
+ listNote?: React.ReactNode;
39
+ /** highlight row 0 on every keystroke that leaves text, so Enter picks it; empty text highlights nothing */
40
+ highlightFirst?: boolean;
41
+ /** emphasise the query inside row labels (default true; V2's link rows draw the plain title) */
42
+ highlightMatches?: boolean;
43
+ /** the listbox's accessible name */
44
+ listLabel?: string;
45
+ /** a pick also writes the row's label into the text (default true); false = a pick only calls onSelect */
46
+ fillOnSelect?: boolean;
47
+ /** replaces the built-in clear (setText("")) on the X */
48
+ onClear?: () => void;
49
+ /** a control inside the field after the clear button (the file-library button) */
50
+ trailingSlot?: React.ReactNode;
51
+ /** data-* attributes on the list's layer (the floating positioner, or the inline wrapper) */
52
+ listAttrs?: Record<`data-${string}`, string>;
53
+ inputRef?: React.Ref<HTMLInputElement>;
54
+ onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;
27
55
  className?: string;
28
56
  menuClassName?: string;
29
57
  }
30
- export declare function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, value, defaultValue, onValueChange, options, onSelect, onEnter, filter, placeholder, size, leading, loading, invalid, disabled, openOnFocus, className, menuClassName, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
58
+ export declare function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, value, defaultValue, onValueChange, options, onSelect, onEnter, filter, placeholder, size, leading, leadingSlot, loading, invalid, disabled, openOnFocus, open: openProp, onOpenChange, inlineList, emptyNote, listNote, highlightFirst, highlightMatches, listLabel, fillOnSelect, onClear, trailingSlot, listAttrs, inputRef, onBlur, className, menuClassName, }: AutocompleteProps): import("react/jsx-runtime").JSX.Element;
@@ -1,11 +1,11 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { useFieldDescribedBy, useFieldId, useFieldLabelledBy, useLabelFor } from "./field-context.js";
3
+ import { Spinner } from "./spinner.js";
3
4
  import { KIT_SCOPE } from "./surfaces.js";
4
5
  import { IconButton } from "./button.js";
5
6
  import { Highlight, filterOptions, nodeText } from "./select.js";
6
- import { Spinner } from "./spinner.js";
7
7
  import * as React from "react";
8
- import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { IconX } from "@tabler/icons-react";
10
10
  import { Autocomplete as Autocomplete$1 } from "@base-ui/react/autocomplete";
11
11
  //#region src/ui/autocomplete.tsx
@@ -14,7 +14,8 @@ var H = {
14
14
  md: "h-8",
15
15
  lg: "h-9"
16
16
  };
17
- function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, value, defaultValue = "", onValueChange, options, onSelect, onEnter, filter = filterOptions, placeholder, size = "md", leading, loading, invalid, disabled, openOnFocus = true, className, menuClassName }) {
17
+ var NOTE = "px-2 py-1.5 text-kit-xs text-kit-fg-3";
18
+ function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, value, defaultValue = "", onValueChange, options, onSelect, onEnter, filter = filterOptions, placeholder, size = "md", leading, leadingSlot, loading, invalid, disabled, openOnFocus = true, open: openProp, onOpenChange, inlineList = false, emptyNote, listNote, highlightFirst = false, highlightMatches = true, listLabel, fillOnSelect = true, onClear, trailingSlot, listAttrs, inputRef, onBlur, className, menuClassName }) {
18
19
  const fieldId = useFieldId();
19
20
  const labelledBy = useFieldLabelledBy();
20
21
  const labelFor = useLabelFor(id ?? fieldId);
@@ -25,36 +26,105 @@ function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDes
25
26
  if (value === void 0) setInner(t);
26
27
  onValueChange?.(t);
27
28
  };
28
- const [open, setOpen] = React.useState(false);
29
- const highlighted = React.useRef(void 0);
29
+ const [innerOpen, setInnerOpen] = React.useState(false);
30
+ const open = openProp ?? innerOpen;
31
+ const setOpen = (o) => {
32
+ if (openProp === void 0) setInnerOpen(o);
33
+ onOpenChange?.(o);
34
+ };
35
+ const [highlighted, setHighlighted] = React.useState(void 0);
30
36
  const shown = React.useMemo(() => filter ? filter(options, text) : options, [
31
37
  filter,
32
38
  options,
33
39
  text
34
40
  ]);
41
+ const hasEmptyNote = emptyNote != null && emptyNote !== false;
42
+ const visible = open && (shown.length > 0 || hasEmptyNote);
43
+ const firstStandsIn = highlightFirst && visible && text.trim() !== "" && !highlighted && shown.length > 0 && !shown[0].disabled;
44
+ const pick = (o) => {
45
+ onSelect?.(o);
46
+ if (fillOnSelect) setText(nodeText(o.label));
47
+ setOpen(false);
48
+ };
35
49
  const named = id ?? fieldId ?? ariaLabel;
50
+ const rows = /* @__PURE__ */ jsxs(Fragment, { children: [
51
+ /* @__PURE__ */ jsx(Autocomplete$1.List, {
52
+ "aria-label": listLabel,
53
+ className: "max-h-72 overflow-y-auto overscroll-contain empty:hidden",
54
+ children: shown.map((o, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [o.group && (i === 0 || shown[i - 1].group !== o.group) ? /* @__PURE__ */ jsx("div", {
55
+ role: "presentation",
56
+ className: "px-2 pb-1 pt-2 text-kit-xs font-medium text-kit-fg-3 first:pt-1",
57
+ children: o.group
58
+ }) : null, /* @__PURE__ */ jsxs(Autocomplete$1.Item, {
59
+ value: o,
60
+ disabled: o.disabled,
61
+ onClick: () => onSelect?.(o),
62
+ "data-first-active": firstStandsIn && i === 0 ? "" : void 0,
63
+ className: "flex h-8 cursor-pointer select-none items-center gap-2 rounded-kit-md px-2 text-kit-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-40 data-[highlighted]:bg-kit-hover data-[first-active]:bg-kit-hover",
64
+ children: [
65
+ o.icon ? /* @__PURE__ */ jsx("span", {
66
+ "aria-hidden": true,
67
+ className: "flex shrink-0 text-kit-fg-3 [&_svg]:size-4",
68
+ children: o.icon
69
+ }) : null,
70
+ /* @__PURE__ */ jsx("span", {
71
+ className: "min-w-0 shrink truncate text-kit-fg",
72
+ children: highlightMatches && typeof o.label === "string" ? /* @__PURE__ */ jsx(Highlight, {
73
+ text: o.label,
74
+ query: text
75
+ }) : o.label
76
+ }),
77
+ o.description ? /* @__PURE__ */ jsx("span", {
78
+ className: "min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3",
79
+ children: o.description
80
+ }) : /* @__PURE__ */ jsx("span", { className: "flex-1" }),
81
+ o.meta ? /* @__PURE__ */ jsx("span", {
82
+ className: "shrink-0 text-kit-2xs text-kit-fg-3",
83
+ children: o.meta
84
+ }) : null
85
+ ]
86
+ })] }, o.value))
87
+ }),
88
+ shown.length === 0 && hasEmptyNote ? /* @__PURE__ */ jsx("p", {
89
+ role: "status",
90
+ className: NOTE,
91
+ children: emptyNote
92
+ }) : null,
93
+ shown.length > 0 && listNote != null && listNote !== false ? /* @__PURE__ */ jsx("p", {
94
+ role: "status",
95
+ className: NOTE,
96
+ children: listNote
97
+ }) : null
98
+ ] });
36
99
  return /* @__PURE__ */ jsxs(Autocomplete$1.Root, {
37
100
  items: shown,
38
101
  filter: null,
39
102
  mode: "list",
40
103
  value: text,
41
- onValueChange: (t) => setText(t),
104
+ onValueChange: (t, details) => {
105
+ if (!fillOnSelect && details.reason === "item-press") return;
106
+ setText(t);
107
+ },
42
108
  itemToStringValue: (o) => nodeText(o.label),
43
- open: open && shown.length > 0,
109
+ open: visible,
44
110
  onOpenChange: setOpen,
45
- onItemHighlighted: (o) => highlighted.current = o,
111
+ inline: inlineList,
112
+ autoHighlight: highlightFirst,
113
+ onItemHighlighted: (o) => setHighlighted(o),
46
114
  openOnInputClick: true,
47
115
  loopFocus: true,
48
116
  disabled,
49
117
  children: [/* @__PURE__ */ jsxs("div", {
50
118
  className: cn("flex min-w-0 items-center rounded-kit-md border border-kit-field-border bg-kit-field-bg shadow-kit-field transition-[border-color,box-shadow] duration-150 hover:border-kit-field-border-hover focus-within:border-kit-field-border-focus focus-within:shadow-kit-ring-field", invalid && "border-[var(--kit-field-invalid)] hover:border-[var(--kit-field-invalid)]", disabled && "cursor-not-allowed bg-kit-subtle opacity-60", H[size], className),
51
119
  children: [
120
+ leadingSlot,
52
121
  leading ? /* @__PURE__ */ jsx("span", {
53
122
  "aria-hidden": true,
54
123
  className: "ml-2.5 flex shrink-0 text-kit-fg-3 [&_svg]:size-4",
55
124
  children: leading
56
125
  }) : null,
57
126
  /* @__PURE__ */ jsx(Autocomplete$1.Input, {
127
+ ref: inputRef,
58
128
  id: id ?? fieldId,
59
129
  "aria-label": ariaLabel,
60
130
  "aria-labelledby": ariaLabel ? void 0 : labelFor ?? (named ? void 0 : labelledBy),
@@ -64,8 +134,20 @@ function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDes
64
134
  autoComplete: "off",
65
135
  spellCheck: false,
66
136
  onFocus: () => openOnFocus && setOpen(true),
137
+ onBlur,
138
+ onKeyDownCapture: (e) => {
139
+ if (e.key === "Escape" && visible) {
140
+ e.preventDefault();
141
+ e.stopPropagation();
142
+ setOpen(false);
143
+ }
144
+ },
67
145
  onKeyDown: (e) => {
68
- if (e.key === "Enter" && !highlighted.current) onEnter?.(text);
146
+ if (e.key !== "Enter") return;
147
+ if (firstStandsIn) {
148
+ e.preventDefault();
149
+ pick(shown[0]);
150
+ } else if (!highlighted || !visible) onEnter?.(text);
69
151
  },
70
152
  className: "h-full min-w-0 flex-1 bg-transparent px-2 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3 disabled:cursor-not-allowed"
71
153
  }),
@@ -80,11 +162,17 @@ function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDes
80
162
  variant: "ghost",
81
163
  className: "mr-1",
82
164
  onMouseDown: (e) => e.preventDefault(),
83
- onClick: () => setText(""),
165
+ onClick: () => onClear ? onClear() : setText(""),
84
166
  children: /* @__PURE__ */ jsx(IconX, { stroke: 1.5 })
85
- }) : null
167
+ }) : null,
168
+ trailingSlot
86
169
  ]
87
- }), /* @__PURE__ */ jsx(Autocomplete$1.Portal, { children: /* @__PURE__ */ jsx(Autocomplete$1.Positioner, {
170
+ }), inlineList ? visible ? /* @__PURE__ */ jsx("div", {
171
+ ...listAttrs,
172
+ className: cn("mt-1 rounded-kit-md border border-kit-line bg-kit-surface p-1", menuClassName),
173
+ onMouseDown: (e) => e.preventDefault(),
174
+ children: rows
175
+ }) : null : /* @__PURE__ */ jsx(Autocomplete$1.Portal, { children: /* @__PURE__ */ jsx(Autocomplete$1.Positioner, {
88
176
  align: "start",
89
177
  side: "bottom",
90
178
  sideOffset: 4,
@@ -92,43 +180,10 @@ function Autocomplete({ id, "aria-label": ariaLabel, "aria-describedby": ariaDes
92
180
  className: "z-[var(--kit-z-menu,80)]",
93
181
  "data-floating-layer": "",
94
182
  ...KIT_SCOPE,
183
+ ...listAttrs,
95
184
  children: /* @__PURE__ */ jsx(Autocomplete$1.Popup, {
96
185
  className: cn("w-[max(var(--anchor-width),280px)] max-w-[min(420px,calc(100vw-24px))] rounded-kit-lg border bg-kit-surface p-1 text-kit-fg shadow-lg outline-none data-[open]:animate-kit-pop-in", menuClassName),
97
- children: /* @__PURE__ */ jsx(Autocomplete$1.List, {
98
- className: "max-h-72 overflow-y-auto overscroll-contain",
99
- children: shown.map((o, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [o.group && (i === 0 || shown[i - 1].group !== o.group) ? /* @__PURE__ */ jsx("div", {
100
- role: "presentation",
101
- className: "px-2 pb-1 pt-2 text-kit-xs font-medium text-kit-fg-3 first:pt-1",
102
- children: o.group
103
- }) : null, /* @__PURE__ */ jsxs(Autocomplete$1.Item, {
104
- value: o,
105
- disabled: o.disabled,
106
- onClick: () => onSelect?.(o),
107
- className: "flex h-8 cursor-pointer select-none items-center gap-2 rounded-kit-md px-2 text-kit-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-40 data-[highlighted]:bg-kit-hover",
108
- children: [
109
- o.icon ? /* @__PURE__ */ jsx("span", {
110
- "aria-hidden": true,
111
- className: "flex shrink-0 text-kit-fg-3 [&_svg]:size-4",
112
- children: o.icon
113
- }) : null,
114
- /* @__PURE__ */ jsx("span", {
115
- className: "min-w-0 shrink truncate text-kit-fg",
116
- children: typeof o.label === "string" ? /* @__PURE__ */ jsx(Highlight, {
117
- text: o.label,
118
- query: text
119
- }) : o.label
120
- }),
121
- o.description ? /* @__PURE__ */ jsx("span", {
122
- className: "min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3",
123
- children: o.description
124
- }) : /* @__PURE__ */ jsx("span", { className: "flex-1" }),
125
- o.meta ? /* @__PURE__ */ jsx("span", {
126
- className: "shrink-0 text-kit-2xs text-kit-fg-3",
127
- children: o.meta
128
- }) : null
129
- ]
130
- })] }, o.value))
131
- })
186
+ children: rows
132
187
  })
133
188
  }) })]
134
189
  });
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/ui/autocomplete.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Autocomplete as AutocompletePrimitive } from \"@base-ui/react/autocomplete\";\nimport { IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { IconButton } from \"./button\";\nimport { useFieldDescribedBy, useFieldId, useFieldLabelledBy, useLabelFor } from \"./field-context\";\nimport { filterOptions, Highlight, nodeText, type SelectOption } from \"./select\";\nimport { Spinner } from \"./spinner\";\nimport { KIT_SCOPE } from \"./surfaces\";\n\n/* ── Autocomplete ────────────────────────────────────────────────────────\n Free text with suggestions: the value is whatever is typed; a suggestion fills it in. Select only picks fixed options.\n V2 has no component, only the pattern (kit controls link.tsx:504-650, invite-flow.tsx:197); kit-ports-spec.md §2.\n Field = the Input look; the list opens on focus or typing, only while it has rows (free text is a valid value, so\n there is no \"No matches\"); nothing is highlighted until the arrows move, so Enter commits the typed text (onEnter).\n Ranking is Select's filterOptions + Highlight. */\n\nexport interface AutocompleteProps {\n id?: string;\n \"aria-label\"?: string;\n \"aria-describedby\"?: string;\n /** the text (controlled) */\n value?: string;\n defaultValue?: string;\n /** every keystroke, and the label of a picked suggestion */\n onValueChange?: (text: string) => void;\n options: SelectOption[];\n /** a suggestion was picked (click, or Enter on a highlighted row) */\n onSelect?: (option: SelectOption) => void;\n /** Enter with no suggestion highlighted: commit the typed text */\n onEnter?: (text: string) => void;\n /** default: Select's ranking; null = the caller already filtered (async options) */\n filter?: ((options: SelectOption[], query: string) => SelectOption[]) | null;\n placeholder?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n leading?: React.ReactNode;\n loading?: boolean;\n invalid?: boolean;\n disabled?: boolean;\n /** open the suggestions when the field takes focus (default true, as V2) */\n openOnFocus?: boolean;\n className?: string;\n menuClassName?: string;\n}\n\nconst H = { sm: \"h-7\", md: \"h-8\", lg: \"h-9\" } as const;\n\nexport function Autocomplete({\n id,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n value,\n defaultValue = \"\",\n onValueChange,\n options,\n onSelect,\n onEnter,\n filter = filterOptions,\n placeholder,\n size = \"md\",\n leading,\n loading,\n invalid,\n disabled,\n openOnFocus = true,\n className,\n menuClassName,\n}: AutocompleteProps) {\n const fieldId = useFieldId();\n const labelledBy = useFieldLabelledBy();\n const labelFor = useLabelFor(id ?? fieldId);\n const describedBy = useFieldDescribedBy();\n const [inner, setInner] = React.useState(defaultValue);\n const text = value ?? inner;\n const setText = (t: string) => {\n if (value === undefined) setInner(t);\n onValueChange?.(t);\n };\n const [open, setOpen] = React.useState(false);\n const highlighted = React.useRef<SelectOption | undefined>(undefined);\n const shown = React.useMemo(() => (filter ? filter(options, text) : options), [filter, options, text]);\n const named = id ?? fieldId ?? ariaLabel;\n\n return (\n <AutocompletePrimitive.Root\n items={shown}\n filter={null}\n mode=\"list\"\n value={text}\n onValueChange={(t) => setText(t)}\n itemToStringValue={(o: SelectOption) => nodeText(o.label)}\n open={open && shown.length > 0}\n onOpenChange={setOpen}\n onItemHighlighted={(o) => (highlighted.current = o as SelectOption | undefined)}\n openOnInputClick\n loopFocus\n disabled={disabled}\n >\n <div\n className={cn(\n \"flex min-w-0 items-center rounded-kit-md border border-kit-field-border bg-kit-field-bg shadow-kit-field transition-[border-color,box-shadow] duration-150 hover:border-kit-field-border-hover focus-within:border-kit-field-border-focus focus-within:shadow-kit-ring-field\",\n invalid && \"border-[var(--kit-field-invalid)] hover:border-[var(--kit-field-invalid)]\",\n disabled && \"cursor-not-allowed bg-kit-subtle opacity-60\",\n H[size],\n className,\n )}\n >\n {leading ? (\n <span aria-hidden className=\"ml-2.5 flex shrink-0 text-kit-fg-3 [&_svg]:size-4\">\n {leading}\n </span>\n ) : null}\n <AutocompletePrimitive.Input\n id={id ?? fieldId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabel ? undefined : (labelFor ?? (named ? undefined : labelledBy))}\n aria-describedby={[ariaDescribedBy, describedBy].filter(Boolean).join(\" \") || undefined}\n aria-invalid={invalid || undefined}\n placeholder={placeholder}\n autoComplete=\"off\"\n spellCheck={false}\n onFocus={() => openOnFocus && setOpen(true)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !highlighted.current) onEnter?.(text);\n }}\n className=\"h-full min-w-0 flex-1 bg-transparent px-2 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3 disabled:cursor-not-allowed\"\n />\n {loading ? (\n <Spinner size=\"sm\" tone=\"muted\" label=\"Loading suggestions\" className=\"mr-2\" />\n ) : text && !disabled ? (\n <IconButton label=\"Clear\" size=\"xs\" variant=\"ghost\" className=\"mr-1\" onMouseDown={(e) => e.preventDefault()} onClick={() => setText(\"\")}>\n <IconX stroke={1.5} />\n </IconButton>\n ) : null}\n </div>\n <AutocompletePrimitive.Portal>\n <AutocompletePrimitive.Positioner align=\"start\" side=\"bottom\" sideOffset={4} collisionPadding={12} className=\"z-[var(--kit-z-menu,80)]\" data-floating-layer=\"\" {...KIT_SCOPE}>\n <AutocompletePrimitive.Popup\n className={cn(\n \"w-[max(var(--anchor-width),280px)] max-w-[min(420px,calc(100vw-24px))] rounded-kit-lg border bg-kit-surface p-1 text-kit-fg shadow-lg outline-none data-[open]:animate-kit-pop-in\",\n menuClassName,\n )}\n >\n <AutocompletePrimitive.List className=\"max-h-72 overflow-y-auto overscroll-contain\">\n {shown.map((o, i) => (\n <React.Fragment key={o.value}>\n {o.group && (i === 0 || shown[i - 1].group !== o.group) ? (\n <div role=\"presentation\" className=\"px-2 pb-1 pt-2 text-kit-xs font-medium text-kit-fg-3 first:pt-1\">\n {o.group}\n </div>\n ) : null}\n <AutocompletePrimitive.Item\n value={o}\n disabled={o.disabled}\n onClick={() => onSelect?.(o)}\n className=\"flex h-8 cursor-pointer select-none items-center gap-2 rounded-kit-md px-2 text-kit-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-40 data-[highlighted]:bg-kit-hover\"\n >\n {o.icon ? (\n <span aria-hidden className=\"flex shrink-0 text-kit-fg-3 [&_svg]:size-4\">\n {o.icon}\n </span>\n ) : null}\n <span className=\"min-w-0 shrink truncate text-kit-fg\">\n {typeof o.label === \"string\" ? <Highlight text={o.label} query={text} /> : o.label}\n </span>\n {o.description ? <span className=\"min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3\">{o.description}</span> : <span className=\"flex-1\" />}\n {o.meta ? <span className=\"shrink-0 text-kit-2xs text-kit-fg-3\">{o.meta}</span> : null}\n </AutocompletePrimitive.Item>\n </React.Fragment>\n ))}\n </AutocompletePrimitive.List>\n </AutocompletePrimitive.Popup>\n </AutocompletePrimitive.Positioner>\n </AutocompletePrimitive.Portal>\n </AutocompletePrimitive.Root>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"autocomplete.js","names":[],"sources":["../../src/ui/autocomplete.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Autocomplete as AutocompletePrimitive } from \"@base-ui/react/autocomplete\";\nimport { IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { IconButton } from \"./button\";\nimport { useFieldDescribedBy, useFieldId, useFieldLabelledBy, useLabelFor } from \"./field-context\";\nimport { filterOptions, Highlight, nodeText, type SelectOption } from \"./select\";\nimport { Spinner } from \"./spinner\";\nimport { KIT_SCOPE } from \"./surfaces\";\n\n/* ── Autocomplete ────────────────────────────────────────────────────────\n Free text with suggestions: the value is whatever is typed; a suggestion fills it in. Select only picks fixed options.\n V2 has no component, only the pattern (kit controls link.tsx:504-650, invite-flow.tsx:197); kit-ports-spec.md §2.\n Field = the Input look; the list opens on focus or typing, only while it has rows (free text is a valid value, so\n there is no \"No matches\"); nothing is highlighted until the arrows move, so Enter commits the typed text (onEnter).\n Ranking is Select's filterOptions + Highlight.\n The link field (LinkPicker) opts into V2 link.tsx's extras: an in-flow list (inlineList), a status note when nothing\n matches (emptyNote) or under the rows (listNote), the link-type menu inside the field (leadingSlot), row 0 highlighted\n while typing (highlightFirst), a controlled open, plain row titles (highlightMatches={false}), and Escape that closes\n only the list while it is open (link.tsx:603-618). */\n\nexport interface AutocompleteProps {\n id?: string;\n \"aria-label\"?: string;\n \"aria-describedby\"?: string;\n /** the text (controlled) */\n value?: string;\n defaultValue?: string;\n /** every keystroke, and the label of a picked suggestion */\n onValueChange?: (text: string) => void;\n options: SelectOption[];\n /** a suggestion was picked (click, or Enter on a highlighted row) */\n onSelect?: (option: SelectOption) => void;\n /** Enter with no suggestion highlighted: commit the typed text */\n onEnter?: (text: string) => void;\n /** default: Select's ranking; null = the caller already filtered (async options) */\n filter?: ((options: SelectOption[], query: string) => SelectOption[]) | null;\n placeholder?: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /** decorative icon before the input */\n leading?: React.ReactNode;\n /** an interactive control inside the field before the input (the link-type menu); rendered as is */\n leadingSlot?: React.ReactNode;\n loading?: boolean;\n invalid?: boolean;\n disabled?: boolean;\n /** open the suggestions when the field takes focus (default true, as V2) */\n openOnFocus?: boolean;\n /** controlled open; the list shows while open and it has rows or a note */\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** render the list in the flow under the field instead of a floating popup (panels, popovers) */\n inlineList?: boolean;\n /** a status row shown, with the list kept open, when no row matches */\n emptyNote?: React.ReactNode;\n /** a status row under the rows when there are rows (a partial-load error) */\n listNote?: React.ReactNode;\n /** highlight row 0 on every keystroke that leaves text, so Enter picks it; empty text highlights nothing */\n highlightFirst?: boolean;\n /** emphasise the query inside row labels (default true; V2's link rows draw the plain title) */\n highlightMatches?: boolean;\n /** the listbox's accessible name */\n listLabel?: string;\n /** a pick also writes the row's label into the text (default true); false = a pick only calls onSelect */\n fillOnSelect?: boolean;\n /** replaces the built-in clear (setText(\"\")) on the X */\n onClear?: () => void;\n /** a control inside the field after the clear button (the file-library button) */\n trailingSlot?: React.ReactNode;\n /** data-* attributes on the list's layer (the floating positioner, or the inline wrapper) */\n listAttrs?: Record<`data-${string}`, string>;\n inputRef?: React.Ref<HTMLInputElement>;\n onBlur?: (e: React.FocusEvent<HTMLInputElement>) => void;\n className?: string;\n menuClassName?: string;\n}\n\nconst H = { sm: \"h-7\", md: \"h-8\", lg: \"h-9\" } as const;\n/* V2 link.tsx:507-509 */\nconst NOTE = \"px-2 py-1.5 text-kit-xs text-kit-fg-3\";\n\nexport function Autocomplete({\n id,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n value,\n defaultValue = \"\",\n onValueChange,\n options,\n onSelect,\n onEnter,\n filter = filterOptions,\n placeholder,\n size = \"md\",\n leading,\n leadingSlot,\n loading,\n invalid,\n disabled,\n openOnFocus = true,\n open: openProp,\n onOpenChange,\n inlineList = false,\n emptyNote,\n listNote,\n highlightFirst = false,\n highlightMatches = true,\n listLabel,\n fillOnSelect = true,\n onClear,\n trailingSlot,\n listAttrs,\n inputRef,\n onBlur,\n className,\n menuClassName,\n}: AutocompleteProps) {\n const fieldId = useFieldId();\n const labelledBy = useFieldLabelledBy();\n const labelFor = useLabelFor(id ?? fieldId);\n const describedBy = useFieldDescribedBy();\n const [inner, setInner] = React.useState(defaultValue);\n const text = value ?? inner;\n const setText = (t: string) => {\n if (value === undefined) setInner(t);\n onValueChange?.(t);\n };\n const [innerOpen, setInnerOpen] = React.useState(false);\n const open = openProp ?? innerOpen;\n const setOpen = (o: boolean) => {\n if (openProp === undefined) setInnerOpen(o);\n onOpenChange?.(o);\n };\n const [highlighted, setHighlighted] = React.useState<SelectOption | undefined>(undefined);\n const shown = React.useMemo(() => (filter ? filter(options, text) : options), [filter, options, text]);\n const hasEmptyNote = emptyNote != null && emptyNote !== false;\n const visible = open && (shown.length > 0 || hasEmptyNote);\n /* highlightFirst: row 0 stands in as the active row while text is typed and nothing else is highlighted (V2\n link.tsx sets its own active index to 0 on each keystroke); Base UI's autoHighlight normally does the same. */\n const firstStandsIn = highlightFirst && visible && text.trim() !== \"\" && !highlighted && shown.length > 0 && !shown[0].disabled;\n const pick = (o: SelectOption) => {\n onSelect?.(o);\n if (fillOnSelect) setText(nodeText(o.label));\n setOpen(false);\n };\n const named = id ?? fieldId ?? ariaLabel;\n\n const rows = (\n <>\n <AutocompletePrimitive.List aria-label={listLabel} className=\"max-h-72 overflow-y-auto overscroll-contain empty:hidden\">\n {shown.map((o, i) => (\n <React.Fragment key={o.value}>\n {o.group && (i === 0 || shown[i - 1].group !== o.group) ? (\n <div role=\"presentation\" className=\"px-2 pb-1 pt-2 text-kit-xs font-medium text-kit-fg-3 first:pt-1\">\n {o.group}\n </div>\n ) : null}\n <AutocompletePrimitive.Item\n value={o}\n disabled={o.disabled}\n onClick={() => onSelect?.(o)}\n data-first-active={firstStandsIn && i === 0 ? \"\" : undefined}\n className=\"flex h-8 cursor-pointer select-none items-center gap-2 rounded-kit-md px-2 text-kit-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-40 data-[highlighted]:bg-kit-hover data-[first-active]:bg-kit-hover\"\n >\n {o.icon ? (\n <span aria-hidden className=\"flex shrink-0 text-kit-fg-3 [&_svg]:size-4\">\n {o.icon}\n </span>\n ) : null}\n <span className=\"min-w-0 shrink truncate text-kit-fg\">\n {highlightMatches && typeof o.label === \"string\" ? <Highlight text={o.label} query={text} /> : o.label}\n </span>\n {o.description ? <span className=\"min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3\">{o.description}</span> : <span className=\"flex-1\" />}\n {o.meta ? <span className=\"shrink-0 text-kit-2xs text-kit-fg-3\">{o.meta}</span> : null}\n </AutocompletePrimitive.Item>\n </React.Fragment>\n ))}\n </AutocompletePrimitive.List>\n {shown.length === 0 && hasEmptyNote ? (\n <p role=\"status\" className={NOTE}>\n {emptyNote}\n </p>\n ) : null}\n {shown.length > 0 && listNote != null && listNote !== false ? (\n <p role=\"status\" className={NOTE}>\n {listNote}\n </p>\n ) : null}\n </>\n );\n\n return (\n <AutocompletePrimitive.Root\n items={shown}\n filter={null}\n mode=\"list\"\n value={text}\n onValueChange={(t, details) => {\n // Base UI writes a pressed row's label into the input; a host that swaps the field for a chip opts out\n if (!fillOnSelect && details.reason === \"item-press\") return;\n setText(t);\n }}\n itemToStringValue={(o: SelectOption) => nodeText(o.label)}\n open={visible}\n onOpenChange={setOpen}\n inline={inlineList}\n // highlight row 0 while typing; Base UI highlights nothing for empty text, so Enter there commits it (onEnter)\n autoHighlight={highlightFirst}\n onItemHighlighted={(o) => setHighlighted(o as SelectOption | undefined)}\n openOnInputClick\n loopFocus\n disabled={disabled}\n >\n <div\n className={cn(\n \"flex min-w-0 items-center rounded-kit-md border border-kit-field-border bg-kit-field-bg shadow-kit-field transition-[border-color,box-shadow] duration-150 hover:border-kit-field-border-hover focus-within:border-kit-field-border-focus focus-within:shadow-kit-ring-field\",\n invalid && \"border-[var(--kit-field-invalid)] hover:border-[var(--kit-field-invalid)]\",\n disabled && \"cursor-not-allowed bg-kit-subtle opacity-60\",\n H[size],\n className,\n )}\n >\n {leadingSlot}\n {leading ? (\n <span aria-hidden className=\"ml-2.5 flex shrink-0 text-kit-fg-3 [&_svg]:size-4\">\n {leading}\n </span>\n ) : null}\n <AutocompletePrimitive.Input\n ref={inputRef}\n id={id ?? fieldId}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabel ? undefined : (labelFor ?? (named ? undefined : labelledBy))}\n aria-describedby={[ariaDescribedBy, describedBy].filter(Boolean).join(\" \") || undefined}\n aria-invalid={invalid || undefined}\n placeholder={placeholder}\n autoComplete=\"off\"\n spellCheck={false}\n onFocus={() => openOnFocus && setOpen(true)}\n onBlur={onBlur}\n onKeyDownCapture={(e) => {\n // V2 link.tsx:603-618: while the list shows, Escape closes only the list; the next one reaches the panel\n if (e.key === \"Escape\" && visible) {\n e.preventDefault();\n e.stopPropagation();\n setOpen(false);\n }\n }}\n onKeyDown={(e) => {\n if (e.key !== \"Enter\") return;\n if (firstStandsIn) {\n e.preventDefault();\n pick(shown[0]);\n } else if (!highlighted || !visible) onEnter?.(text);\n }}\n className=\"h-full min-w-0 flex-1 bg-transparent px-2 text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3 disabled:cursor-not-allowed\"\n />\n {loading ? (\n <Spinner size=\"sm\" tone=\"muted\" label=\"Loading suggestions\" className=\"mr-2\" />\n ) : text && !disabled ? (\n <IconButton label=\"Clear\" size=\"xs\" variant=\"ghost\" className=\"mr-1\" onMouseDown={(e) => e.preventDefault()} onClick={() => (onClear ? onClear() : setText(\"\"))}>\n <IconX stroke={1.5} />\n </IconButton>\n ) : null}\n {trailingSlot}\n </div>\n {inlineList ? (\n visible ? (\n /* V2 link.tsx:646-649: the in-flow list under the field */\n <div {...listAttrs} className={cn(\"mt-1 rounded-kit-md border border-kit-line bg-kit-surface p-1\", menuClassName)} onMouseDown={(e) => e.preventDefault()}>\n {rows}\n </div>\n ) : null\n ) : (\n <AutocompletePrimitive.Portal>\n <AutocompletePrimitive.Positioner align=\"start\" side=\"bottom\" sideOffset={4} collisionPadding={12} className=\"z-[var(--kit-z-menu,80)]\" data-floating-layer=\"\" {...KIT_SCOPE} {...listAttrs}>\n <AutocompletePrimitive.Popup\n className={cn(\n \"w-[max(var(--anchor-width),280px)] max-w-[min(420px,calc(100vw-24px))] rounded-kit-lg border bg-kit-surface p-1 text-kit-fg shadow-lg outline-none data-[open]:animate-kit-pop-in\",\n menuClassName,\n )}\n >\n {rows}\n </AutocompletePrimitive.Popup>\n </AutocompletePrimitive.Positioner>\n </AutocompletePrimitive.Portal>\n )}\n </AutocompletePrimitive.Root>\n );\n}\n"],"mappings":"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"}
package/dist/ui/button.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { SPARKLE_PATH } from "../brand/logo.js";
3
+ import { Spinner } from "./spinner.js";
3
4
  import { TooltipLayer, TooltipRoot } from "./tooltip-root.js";
4
5
  import { variants } from "./variants.js";
5
6
  import * as React from "react";
6
7
  import { jsx, jsxs } from "react/jsx-runtime";
7
- import { IconLoader2, IconPlus } from "@tabler/icons-react";
8
+ import { IconPlus } from "@tabler/icons-react";
8
9
  import { Tooltip } from "@base-ui/react/tooltip";
9
10
  //#region src/ui/button.tsx
10
11
  /**
@@ -69,10 +70,7 @@ var Button = React.forwardRef(({ className, variant, size, asChild, loading, lef
69
70
  className: classes,
70
71
  ...props,
71
72
  children: [
72
- loading ? /* @__PURE__ */ jsx(IconLoader2, {
73
- className: "animate-spin",
74
- "aria-hidden": true
75
- }) : leftIcon,
73
+ loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
76
74
  variant === "ai" && !leftIcon && !loading ? /* @__PURE__ */ jsx(Sparkle, {}) : null,
77
75
  children,
78
76
  rightIcon
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../../src/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { IconLoader2, IconPlus } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { SPARKLE_PATH } from \"../brand/logo\";\nimport { TooltipLayer, TooltipRoot } from \"./tooltip-root\";\nimport { variants, type VariantProps } from \"./variants\";\n\n/**\n * Button: the only button in the kit.\n * Heights: xs 24 · sm 28 · md 32 (default) · lg 36 · xl 40. Radius 6.\n * Variants: primary (ink) · accent (violet, reserved for the ONE create action per screen)\n * secondary (bordered) · ghost · soft · danger · danger-ghost · link · ai (gradient sparkle)\n * The keyboard focus ring is the global :focus-visible outline, suppressed under pointer modality (DESIGN.md 3.7).\n */\nexport const buttonVariants = variants(\n \"relative inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium tracking-[-0.01em] select-none transition-[background-color,border-color,color,box-shadow,opacity] duration-150 ease-out disabled:pointer-events-none disabled:opacity-45 [&_svg]:shrink-0 [&_svg]:opacity-90\",\n {\n variants: {\n variant: {\n // .btn-solid: in dark a disabled primary/accent takes the solid --kit-disabled-bg / --kit-disabled-fg pair; light keeps the opacity dim.\n primary: \"bg-kit-inverse text-kit-fg-inverse shadow-kit-button-primary hover:bg-kit-inverse-hover active:bg-kit-inverse btn-solid\",\n accent: \"bg-kit-accent text-kit-accent-on shadow-kit-xs hover:bg-kit-accent-hover btn-solid\",\n secondary: \"border border-kit-line-strong bg-kit-control-bg text-kit-fg shadow-kit-xs hover:bg-kit-subtle active:bg-kit-hover\",\n ghost: \"text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg active:bg-kit-selected\",\n soft: \"bg-kit-muted text-kit-fg hover:bg-kit-selected\",\n danger: \"bg-kit-danger text-kit-danger-on shadow-kit-xs hover:brightness-95\",\n \"danger-ghost\": \"text-kit-danger-fg hover:bg-kit-danger-soft\",\n link: \"text-kit-accent-fg underline-offset-4 hover:underline px-0 h-auto active:scale-100\",\n ai: \"border border-kit-line bg-kit-control-bg text-kit-fg shadow-kit-xs hover:border-kit-accent-line hover:bg-kit-accent-softer\",\n },\n size: {\n xs: \"h-6 rounded-kit-md px-2 text-kit-xs [&_svg]:size-3.5\",\n sm: \"h-7 rounded-kit-md px-2.5 text-kit-sm [&_svg]:size-3.5\",\n md: \"h-8 rounded-kit-md px-3 text-kit-sm [&_svg]:size-4\",\n lg: \"h-9 rounded-kit-md px-3.5 text-kit-base [&_svg]:size-4\",\n xl: \"h-10 rounded-kit-md px-4 text-kit-base [&_svg]:size-[18px]\",\n },\n },\n compoundVariants: [{ variant: \"link\", className: \"h-auto px-0\" }],\n defaultVariants: { variant: \"secondary\", size: \"md\" },\n },\n);\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {\n /** Render the single child element (a link, say) with the button's classes and props. */\n asChild?: boolean;\n loading?: boolean;\n leftIcon?: React.ReactNode;\n rightIcon?: React.ReactNode;\n}\n\ntype ChildProps = { className?: string; ref?: React.Ref<unknown> };\n\nfunction mergeRefs<T>(...refs: (React.Ref<T> | undefined)[]) {\n return (node: T | null) => {\n for (const ref of refs) {\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.RefObject<T | null>).current = node;\n }\n };\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild, loading, leftIcon, rightIcon, children, disabled, ...props }, ref) => {\n const classes = cn(buttonVariants({ variant, size }), className);\n if (asChild && React.isValidElement<ChildProps>(children)) {\n return React.cloneElement(children, {\n ...props,\n ...children.props,\n className: cn(classes, children.props.className),\n ref: mergeRefs(ref as React.Ref<unknown>, children.props.ref),\n });\n }\n return (\n <button ref={ref} type={props.type ?? \"button\"} disabled={disabled || loading} aria-busy={loading || undefined} className={classes} {...props}>\n {loading ? <IconLoader2 className=\"animate-spin\" aria-hidden /> : leftIcon}\n {variant === \"ai\" && !leftIcon && !loading ? <Sparkle /> : null}\n {children}\n {rightIcon}\n </button>\n );\n },\n);\nButton.displayName = \"Button\";\n\n/** Square icon-only button. Always pass `label` (used for aria-label + tooltip). */\nexport const iconButtonVariants = variants(\n \"relative inline-flex items-center justify-center shrink-0 text-kit-fg-2 transition-colors duration-150 hover:bg-kit-hover hover:text-kit-fg active:scale-[0.96] disabled:opacity-40 disabled:pointer-events-none data-[active=true]:bg-kit-selected data-[active=true]:text-kit-fg\",\n {\n variants: {\n size: {\n xs: \"size-6 rounded-kit-md [&_svg]:size-3.5\",\n sm: \"size-7 rounded-kit-md [&_svg]:size-4\",\n md: \"size-8 rounded-kit-md [&_svg]:size-4\",\n lg: \"size-9 rounded-kit-md [&_svg]:size-[18px]\",\n },\n variant: {\n ghost: \"\",\n outline: \"border border-kit-line bg-kit-control-bg shadow-kit-xs hover:border-kit-line-strong\",\n soft: \"bg-kit-muted\",\n },\n },\n defaultVariants: { size: \"md\", variant: \"ghost\" },\n },\n);\n\n/**\n * a11y: true while rendering inside a tooltip (or a surface that manages its own hints), so an IconButton nested\n * there doesn't add a second tooltip. Provided by HintTooltip and overlay.tsx's <Tooltip>.\n */\nexport const TooltipScope = React.createContext(false);\n\n/**\n * The plain ink hint (DESIGN.md 8.23: top, 6px offset, 8px collision padding, portalled, z 90, 350ms). The child\n * element is the trigger and must take a ref and DOM props. input, display and action-tray use it so they never\n * import overlay.tsx; overlay's <Tooltip> adds the shortcut slot on top of the same layer.\n */\nexport function HintTooltip({\n content,\n side = \"top\",\n delay = 350,\n children,\n}: {\n content: React.ReactNode;\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n delay?: number;\n children: React.ReactElement;\n}) {\n return (\n <TooltipScope.Provider value>\n <TooltipRoot>\n <TooltipPrimitive.Trigger delay={delay} render={children} />\n <TooltipLayer side={side}>\n <span className=\"line-clamp-[8] min-w-0 whitespace-normal [overflow-wrap:anywhere]\">{content}</span>\n </TooltipLayer>\n </TooltipRoot>\n </TooltipScope.Provider>\n );\n}\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof iconButtonVariants> {\n label: string;\n active?: boolean;\n /** Hover/focus hint. Defaults to `label`; pass `false` to opt out, or a node to customise. */\n tooltip?: React.ReactNode | false;\n tooltipSide?: \"top\" | \"bottom\" | \"left\" | \"right\";\n}\n\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ className, size, variant, label, active, children, tooltip, tooltipSide = \"top\", ...props }, ref) => {\n const inTooltip = React.useContext(TooltipScope);\n const btn = (\n <button\n ref={ref}\n type=\"button\"\n aria-label={label}\n data-active={active ? \"true\" : undefined}\n className={cn(iconButtonVariants({ size, variant }), className)}\n {...props}\n >\n {children}\n </button>\n );\n // Every icon-only button gets a visible hint on hover AND keyboard focus (brief §11), unless a\n // parent tooltip already provides one or the caller opted out.\n if (inTooltip || tooltip === false || !label) return btn;\n return (\n <HintTooltip content={tooltip ?? label} side={tooltipSide}>\n {btn}\n </HintTooltip>\n );\n },\n);\nIconButton.displayName = \"IconButton\";\n\n/** The AI sparkle in the official brand gradient. Used everywhere AI appears. */\nexport function Sparkle({ className, size = 16 }: { className?: string; size?: number }) {\n const id = React.useId().replace(/:/g, \"\");\n return (\n <svg width={size} height={size} viewBox=\"2 2 16 16\" className={cn(\"shrink-0\", className)} aria-hidden>\n <defs>\n <linearGradient id={`sp${id}`} x1=\"6.89\" y1=\"4.59\" x2=\"18\" y2=\"23.67\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0.0817\" style={{ stopColor: \"var(--kit-brand-violet)\" }} />\n <stop offset=\"0.4667\" style={{ stopColor: \"var(--kit-brand-coral)\" }} />\n <stop offset=\"1\" style={{ stopColor: \"var(--kit-brand-rose)\" }} />\n </linearGradient>\n </defs>\n <path d={SPARKLE_PATH} fill={`url(#sp${id})`} />\n </svg>\n );\n}\n\n/** D15 progressive disclosure: \"+ Add a message\" / \"+ Limit to specific sites\": reveals an optional input. */\nexport function RevealLink({ className, children, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"inline-flex h-7 items-center gap-1 rounded-kit-md text-kit-sm font-medium text-kit-fg-2 transition-colors hover:text-kit-fg [&_svg]:size-3.5\",\n className,\n )}\n {...props}\n >\n <IconPlus stroke={2} aria-hidden />\n {children}\n </button>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,IAAa,iBAAiB,SAC5B,wSACA;CACE,UAAU;EACR,SAAS;GAEP,SAAS;GACT,QAAQ;GACR,WAAW;GACX,OAAO;GACP,MAAM;GACN,QAAQ;GACR,gBAAgB;GAChB,MAAM;GACN,IAAI;EACN;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;CACF;CACA,kBAAkB,CAAC;EAAE,SAAS;EAAQ,WAAW;CAAc,CAAC;CAChE,iBAAiB;EAAE,SAAS;EAAa,MAAM;CAAK;AACtD,CACF;AAYA,SAAS,UAAa,GAAG,MAAoC;CAC3D,QAAQ,SAAmB;EACzB,KAAK,MAAM,OAAO,MAChB,IAAI,OAAO,QAAQ,YAAY,IAAI,IAAI;OAClC,IAAI,KAAK,IAAmC,UAAU;CAE/D;AACF;AAEA,IAAa,SAAS,MAAM,YACzB,EAAE,WAAW,SAAS,MAAM,SAAS,SAAS,UAAU,WAAW,UAAU,UAAU,GAAG,SAAS,QAAQ;CAC1G,MAAM,UAAU,GAAG,eAAe;EAAE;EAAS;CAAK,CAAC,GAAG,SAAS;CAC/D,IAAI,WAAW,MAAM,eAA2B,QAAQ,GACtD,OAAO,MAAM,aAAa,UAAU;EAClC,GAAG;EACH,GAAG,SAAS;EACZ,WAAW,GAAG,SAAS,SAAS,MAAM,SAAS;EAC/C,KAAK,UAAU,KAA2B,SAAS,MAAM,GAAG;CAC9D,CAAC;CAEH,OACE,qBAAC,UAAD;EAAa;EAAK,MAAM,MAAM,QAAQ;EAAU,UAAU,YAAY;EAAS,aAAW,WAAW,KAAA;EAAW,WAAW;EAAS,GAAI;EAAxI,UAAA;GACG,UAAU,oBAAC,aAAD;IAAa,WAAU;IAAe,eAAA;GAAa,CAAA,IAAI;GACjE,YAAY,QAAQ,CAAC,YAAY,CAAC,UAAU,oBAAC,SAAD,CAAU,CAAA,IAAI;GAC1D;GACA;EACK;;AAEZ,CACF;AACA,OAAO,cAAc;;AAGrB,IAAa,qBAAqB,SAChC,sRACA;CACE,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EACA,SAAS;GACP,OAAO;GACP,SAAS;GACT,MAAM;EACR;CACF;CACA,iBAAiB;EAAE,MAAM;EAAM,SAAS;CAAQ;AAClD,CACF;;;;;AAMA,IAAa,eAAe,MAAM,cAAc,KAAK;;;;;;AAOrD,SAAgB,YAAY,EAC1B,SACA,OAAO,OACP,QAAQ,KACR,YAMC;CACD,OACE,oBAAC,aAAa,UAAd;EAAuB,OAAA;EACrB,UAAA,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,QAAiB,SAAlB;GAAiC;GAAO,QAAQ;EAAW,CAAA,GAC3D,oBAAC,cAAD;GAAoB;GAClB,UAAA,oBAAC,QAAD;IAAM,WAAU;IAAqE,UAAA;GAAc,CAAA;EACvF,CAAA,CACH,EAAA,CAAA;CACQ,CAAA;AAE3B;AAUA,IAAa,aAAa,MAAM,YAC7B,EAAE,WAAW,MAAM,SAAS,OAAO,QAAQ,UAAU,SAAS,cAAc,OAAO,GAAG,SAAS,QAAQ;CACtG,MAAM,YAAY,MAAM,WAAW,YAAY;CAC/C,MAAM,MACJ,oBAAC,UAAD;EACO;EACL,MAAK;EACL,cAAY;EACZ,eAAa,SAAS,SAAS,KAAA;EAC/B,WAAW,GAAG,mBAAmB;GAAE;GAAM;EAAQ,CAAC,GAAG,SAAS;EAC9D,GAAI;EAEH;CACK,CAAA;CAIV,IAAI,aAAa,YAAY,SAAS,CAAC,OAAO,OAAO;CACrD,OACE,oBAAC,aAAD;EAAa,SAAS,WAAW;EAAO,MAAM;EAC3C,UAAA;CACU,CAAA;AAEjB,CACF;AACA,WAAW,cAAc;;AAGzB,SAAgB,QAAQ,EAAE,WAAW,OAAO,MAA6C;CACvF,MAAM,KAAK,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM,EAAE;CACzC,OACE,qBAAC,OAAD;EAAK,OAAO;EAAM,QAAQ;EAAM,SAAQ;EAAY,WAAW,GAAG,YAAY,SAAS;EAAG,eAAA;EAA1F,UAAA,CACE,oBAAC,QAAD,EAAA,UACE,qBAAC,kBAAD;GAAgB,IAAI,KAAK;GAAM,IAAG;GAAO,IAAG;GAAO,IAAG;GAAK,IAAG;GAAQ,eAAc;GAApF,UAAA;IACE,oBAAC,QAAD;KAAM,QAAO;KAAS,OAAO,EAAE,WAAW,0BAA0B;IAAI,CAAA;IACxE,oBAAC,QAAD;KAAM,QAAO;KAAS,OAAO,EAAE,WAAW,yBAAyB;IAAI,CAAA;IACvE,oBAAC,QAAD;KAAM,QAAO;KAAI,OAAO,EAAE,WAAW,wBAAwB;IAAI,CAAA;GACnD;EACZ,CAAA,EAAA,CAAA,GACN,oBAAC,QAAD;GAAM,GAAG;GAAc,MAAM,UAAU,GAAG;EAAK,CAAA,CAC5C;;AAET;;AAGA,SAAgB,WAAW,EAAE,WAAW,UAAU,GAAG,SAAwD;CAC3G,OACE,qBAAC,UAAD;EACE,MAAK;EACL,WAAW,GACT,gJACA,SACF;EACA,GAAI;EANN,UAAA,CAQE,oBAAC,UAAD;GAAU,QAAQ;GAAG,eAAA;EAAa,CAAA,GACjC,QACK;;AAEZ"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../src/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { IconPlus } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { SPARKLE_PATH } from \"../brand/logo\";\nimport { Spinner } from \"./spinner\";\nimport { TooltipLayer, TooltipRoot } from \"./tooltip-root\";\nimport { variants, type VariantProps } from \"./variants\";\n\n/**\n * Button: the only button in the kit.\n * Heights: xs 24 · sm 28 · md 32 (default) · lg 36 · xl 40. Radius 6.\n * Variants: primary (ink) · accent (violet, reserved for the ONE create action per screen)\n * secondary (bordered) · ghost · soft · danger · danger-ghost · link · ai (gradient sparkle)\n * The keyboard focus ring is the global :focus-visible outline, suppressed under pointer modality (DESIGN.md 3.7).\n */\nexport const buttonVariants = variants(\n \"relative inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium tracking-[-0.01em] select-none transition-[background-color,border-color,color,box-shadow,opacity] duration-150 ease-out disabled:pointer-events-none disabled:opacity-45 [&_svg]:shrink-0 [&_svg]:opacity-90\",\n {\n variants: {\n variant: {\n // .btn-solid: in dark a disabled primary/accent takes the solid --kit-disabled-bg / --kit-disabled-fg pair; light keeps the opacity dim.\n primary: \"bg-kit-inverse text-kit-fg-inverse shadow-kit-button-primary hover:bg-kit-inverse-hover active:bg-kit-inverse btn-solid\",\n accent: \"bg-kit-accent text-kit-accent-on shadow-kit-xs hover:bg-kit-accent-hover btn-solid\",\n secondary: \"border border-kit-line-strong bg-kit-control-bg text-kit-fg shadow-kit-xs hover:bg-kit-subtle active:bg-kit-hover\",\n ghost: \"text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg active:bg-kit-selected\",\n soft: \"bg-kit-muted text-kit-fg hover:bg-kit-selected\",\n danger: \"bg-kit-danger text-kit-danger-on shadow-kit-xs hover:brightness-95\",\n \"danger-ghost\": \"text-kit-danger-fg hover:bg-kit-danger-soft\",\n link: \"text-kit-accent-fg underline-offset-4 hover:underline px-0 h-auto active:scale-100\",\n ai: \"border border-kit-line bg-kit-control-bg text-kit-fg shadow-kit-xs hover:border-kit-accent-line hover:bg-kit-accent-softer\",\n },\n size: {\n xs: \"h-6 rounded-kit-md px-2 text-kit-xs [&_svg]:size-3.5\",\n sm: \"h-7 rounded-kit-md px-2.5 text-kit-sm [&_svg]:size-3.5\",\n md: \"h-8 rounded-kit-md px-3 text-kit-sm [&_svg]:size-4\",\n lg: \"h-9 rounded-kit-md px-3.5 text-kit-base [&_svg]:size-4\",\n xl: \"h-10 rounded-kit-md px-4 text-kit-base [&_svg]:size-[18px]\",\n },\n },\n compoundVariants: [{ variant: \"link\", className: \"h-auto px-0\" }],\n defaultVariants: { variant: \"secondary\", size: \"md\" },\n },\n);\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {\n /** Render the single child element (a link, say) with the button's classes and props. */\n asChild?: boolean;\n loading?: boolean;\n leftIcon?: React.ReactNode;\n rightIcon?: React.ReactNode;\n}\n\ntype ChildProps = { className?: string; ref?: React.Ref<unknown> };\n\nfunction mergeRefs<T>(...refs: (React.Ref<T> | undefined)[]) {\n return (node: T | null) => {\n for (const ref of refs) {\n if (typeof ref === \"function\") ref(node);\n else if (ref) (ref as React.RefObject<T | null>).current = node;\n }\n };\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild, loading, leftIcon, rightIcon, children, disabled, ...props }, ref) => {\n const classes = cn(buttonVariants({ variant, size }), className);\n if (asChild && React.isValidElement<ChildProps>(children)) {\n return React.cloneElement(children, {\n ...props,\n ...children.props,\n className: cn(classes, children.props.className),\n ref: mergeRefs(ref as React.Ref<unknown>, children.props.ref),\n });\n }\n return (\n <button ref={ref} type={props.type ?? \"button\"} disabled={disabled || loading} aria-busy={loading || undefined} className={classes} {...props}>\n {/* the kit Spinner (decorative: the button says it is busy); the size variant's [&_svg] rule sizes its glyph */}\n {loading ? <Spinner /> : leftIcon}\n {variant === \"ai\" && !leftIcon && !loading ? <Sparkle /> : null}\n {children}\n {rightIcon}\n </button>\n );\n },\n);\nButton.displayName = \"Button\";\n\n/** Square icon-only button. Always pass `label` (used for aria-label + tooltip). */\nexport const iconButtonVariants = variants(\n \"relative inline-flex items-center justify-center shrink-0 text-kit-fg-2 transition-colors duration-150 hover:bg-kit-hover hover:text-kit-fg active:scale-[0.96] disabled:opacity-40 disabled:pointer-events-none data-[active=true]:bg-kit-selected data-[active=true]:text-kit-fg\",\n {\n variants: {\n size: {\n xs: \"size-6 rounded-kit-md [&_svg]:size-3.5\",\n sm: \"size-7 rounded-kit-md [&_svg]:size-4\",\n md: \"size-8 rounded-kit-md [&_svg]:size-4\",\n lg: \"size-9 rounded-kit-md [&_svg]:size-[18px]\",\n },\n variant: {\n ghost: \"\",\n outline: \"border border-kit-line bg-kit-control-bg shadow-kit-xs hover:border-kit-line-strong\",\n soft: \"bg-kit-muted\",\n },\n },\n defaultVariants: { size: \"md\", variant: \"ghost\" },\n },\n);\n\n/**\n * a11y: true while rendering inside a tooltip (or a surface that manages its own hints), so an IconButton nested\n * there doesn't add a second tooltip. Provided by HintTooltip and overlay.tsx's <Tooltip>.\n */\nexport const TooltipScope = React.createContext(false);\n\n/**\n * The plain ink hint (DESIGN.md 8.23: top, 6px offset, 8px collision padding, portalled, z 90, 350ms). The child\n * element is the trigger and must take a ref and DOM props. input, display and action-tray use it so they never\n * import overlay.tsx; overlay's <Tooltip> adds the shortcut slot on top of the same layer.\n */\nexport function HintTooltip({\n content,\n side = \"top\",\n delay = 350,\n children,\n}: {\n content: React.ReactNode;\n side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n delay?: number;\n children: React.ReactElement;\n}) {\n return (\n <TooltipScope.Provider value>\n <TooltipRoot>\n <TooltipPrimitive.Trigger delay={delay} render={children} />\n <TooltipLayer side={side}>\n <span className=\"line-clamp-[8] min-w-0 whitespace-normal [overflow-wrap:anywhere]\">{content}</span>\n </TooltipLayer>\n </TooltipRoot>\n </TooltipScope.Provider>\n );\n}\n\nexport interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof iconButtonVariants> {\n label: string;\n active?: boolean;\n /** Hover/focus hint. Defaults to `label`; pass `false` to opt out, or a node to customise. */\n tooltip?: React.ReactNode | false;\n tooltipSide?: \"top\" | \"bottom\" | \"left\" | \"right\";\n}\n\nexport const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ className, size, variant, label, active, children, tooltip, tooltipSide = \"top\", ...props }, ref) => {\n const inTooltip = React.useContext(TooltipScope);\n const btn = (\n <button\n ref={ref}\n type=\"button\"\n aria-label={label}\n data-active={active ? \"true\" : undefined}\n className={cn(iconButtonVariants({ size, variant }), className)}\n {...props}\n >\n {children}\n </button>\n );\n // Every icon-only button gets a visible hint on hover AND keyboard focus (brief §11), unless a\n // parent tooltip already provides one or the caller opted out.\n if (inTooltip || tooltip === false || !label) return btn;\n return (\n <HintTooltip content={tooltip ?? label} side={tooltipSide}>\n {btn}\n </HintTooltip>\n );\n },\n);\nIconButton.displayName = \"IconButton\";\n\n/** The AI sparkle in the official brand gradient. Used everywhere AI appears. */\nexport function Sparkle({ className, size = 16 }: { className?: string; size?: number }) {\n const id = React.useId().replace(/:/g, \"\");\n return (\n <svg width={size} height={size} viewBox=\"2 2 16 16\" className={cn(\"shrink-0\", className)} aria-hidden>\n <defs>\n <linearGradient id={`sp${id}`} x1=\"6.89\" y1=\"4.59\" x2=\"18\" y2=\"23.67\" gradientUnits=\"userSpaceOnUse\">\n <stop offset=\"0.0817\" style={{ stopColor: \"var(--kit-brand-violet)\" }} />\n <stop offset=\"0.4667\" style={{ stopColor: \"var(--kit-brand-coral)\" }} />\n <stop offset=\"1\" style={{ stopColor: \"var(--kit-brand-rose)\" }} />\n </linearGradient>\n </defs>\n <path d={SPARKLE_PATH} fill={`url(#sp${id})`} />\n </svg>\n );\n}\n\n/** D15 progressive disclosure: \"+ Add a message\" / \"+ Limit to specific sites\": reveals an optional input. */\nexport function RevealLink({ className, children, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"inline-flex h-7 items-center gap-1 rounded-kit-md text-kit-sm font-medium text-kit-fg-2 transition-colors hover:text-kit-fg [&_svg]:size-3.5\",\n className,\n )}\n {...props}\n >\n <IconPlus stroke={2} aria-hidden />\n {children}\n </button>\n );\n}\n"],"mappings":"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"}
package/dist/ui/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { FieldDescribedByContext, FieldLabelledByContext, useFieldDescribedBy, useFieldId, useFieldLabelledBy } from "./field-context.js";
2
+ import { Spinner } from "./spinner.js";
2
3
  import { Button, HintTooltip, IconButton, RevealLink, Sparkle, TooltipScope, buttonVariants, iconButtonVariants } from "./button.js";
3
4
  import { ShortcutHint, ShortcutHintsProvider, shortcutHintsOn, useShortcutHints } from "./shortcut-hint.js";
4
5
  import { Checkbox, ChoiceCard, ChoiceList, Progress, Radio, RadioGroup, Segmented, Slider, Switch, ToggleGroup, ToggleItem } from "./controls.js";
@@ -7,12 +8,11 @@ import { Avatar, AvatarStack, Badge, Card, CardHeader, Dot, EmptyState, Kbd, Pag
7
8
  import { AGENT_PRESENCE, presenceColor, presenceSlot, registerPresenceRoster } from "./presence.js";
8
9
  import { Field, HelpMore, Input, Label, SearchInput, Textarea } from "./input.js";
9
10
  import { Highlight, SEARCH_THRESHOLD, Select, filterOptions, matchPositions, matchScore, nodeText, selectTriggerClass } from "./select.js";
11
+ import { Autocomplete } from "./autocomplete.js";
10
12
  import { ExpandedEditorModal } from "./expanded-editor-modal.js";
11
13
  import { ChoiceSwitch, SEGMENTED_MAX, SEGMENTED_MAX_LABEL, fitsSegmented } from "./choice-switch.js";
12
14
  import { ActionTray, TrayMeta, TrayMore, actionTrayClass, relTime } from "./action-tray.js";
13
15
  import { ModeBar, ModeBarDot, ModeBarLink } from "./mode-bar.js";
14
- import { Spinner } from "./spinner.js";
15
16
  import { Tab, TabList, TabPanel, Tabs } from "./tab.js";
16
17
  import { KitToaster, kitToast, kitToastManager } from "./toast.js";
17
- import { Autocomplete } from "./autocomplete.js";
18
18
  export { AGENT_PRESENCE, ActionTray, Autocomplete, Avatar, AvatarStack, Badge, Button, Card, CardHeader, Checkbox, ChoiceCard, ChoiceList, ChoiceSwitch, Dot, EmptyState, ExpandedEditorModal, FLOATING_LAYER, Field, FieldDescribedByContext, FieldLabelledByContext, FlowBody, FlowClose, FlowFooter, FlowHeader, FlowLabel, FlowModal, HeaderStatus, HelpMore, Highlight, HintTooltip, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, Input, Kbd, KitToaster, Label, Menu, MenuCheckItem, MenuContent, MenuGroup, MenuItem, MenuLabel, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Modal, ModalBody, ModalClose, ModalContent, ModalFooter, ModalHeader, ModalTrigger, ModeBar, ModeBarDot, ModeBarLink, MoreOptions, OptionRow, PageHeader, Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger, Progress, Radio, RadioGroup, RevealLink, SEARCH_THRESHOLD, SEGMENTED_MAX, SEGMENTED_MAX_LABEL, SearchInput, Segmented, Select, Separator, SettingsSection, Sheet, SheetClose, SheetContent, SheetTrigger, ShortcutHint, ShortcutHintsProvider, Skeleton, Slider, Sparkle, Spinner, Stat, StatusMark, StatusPill, Switch, Tab, TabList, TabPanel, Table, Tabs, Td, Textarea, Th, ToggleGroup, ToggleItem, Tooltip, TooltipProvider, TooltipScope, Tr, TrayMeta, TrayMore, actionTrayClass, avatarRingSpread, badgeVariants, buttonVariants, colorFor, filterOptions, fitsSegmented, iconButtonVariants, initials, kitToast, kitToastManager, matchPositions, matchScore, nodeText, presenceColor, presenceSlot, registerPresenceRoster, relTime, selectTriggerClass, shortcutHintsOn, statusMap, useFieldDescribedBy, useFieldId, useFieldLabelledBy, useFocusReturn, useShortcutHints };
package/dist/ui/toast.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { cn } from "../lib/cn.js";
2
- import { KIT_SCOPE } from "./surfaces.js";
3
2
  import { Spinner } from "./spinner.js";
3
+ import { KIT_SCOPE } from "./surfaces.js";
4
4
  import "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Toast } from "@base-ui/react/toast";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/kit",
3
- "version": "2.0.0-next.0",
3
+ "version": "2.0.0-next.2",
4
4
  "description": "The BetterCMS V2 Block Kit: schema language, form engine, controls and design tokens.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -73,6 +73,7 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@base-ui/react": "^1.4.1",
76
+ "@bettercms-ai/types": "^1.56.0",
76
77
  "@tabler/icons-react": "^3.48.0",
77
78
  "framer-motion": "^12.40.0",
78
79
  "react": "^19.2.0",
@@ -80,6 +81,7 @@
80
81
  },
81
82
  "devDependencies": {
82
83
  "@base-ui/react": "^1.4.1",
84
+ "@bettercms-ai/types": "workspace:*",
83
85
  "@tabler/icons-react": "3.48.0",
84
86
  "@tailwindcss/node": "^4.2.2",
85
87
  "@tailwindcss/postcss": "^4.2.2",