@cosxai/ui 0.21.0 → 0.23.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosxai/ui",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "COSX design system \u2014 React 19 component primitives shared across product-meta and other consumers",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -67,6 +67,12 @@ export interface ComboboxProps {
67
67
  // Async search. Called after `debounceMs` of quiet with a non-empty
68
68
  // trimmed query; the AbortSignal cancels superseded requests.
69
69
  search: (query: string, signal: AbortSignal) => Promise<ComboboxOption[]>;
70
+ // Select-with-search mode: run `search("")` the moment the input
71
+ // focuses, so clicking the field presents the option list before
72
+ // any typing — the picker pattern for small, known sets. Off by
73
+ // default (async person/document searches would fire on every
74
+ // focus for no gain).
75
+ searchOnFocus?: boolean | undefined;
70
76
  debounceMs?: number | undefined;
71
77
  // Free-entry gate: return true when the raw text is committable on
72
78
  // its own (e.g. a syntactically valid email). Omit to disable free
@@ -109,6 +115,7 @@ export function Combobox({
109
115
  autoFocus,
110
116
  disabled,
111
117
  search,
118
+ searchOnFocus,
112
119
  debounceMs = DEFAULT_DEBOUNCE_MS,
113
120
  allowFreeEntry,
114
121
  freeEntryLabel,
@@ -138,7 +145,9 @@ export function Combobox({
138
145
  if (debounceRef.current) clearTimeout(debounceRef.current);
139
146
  // Search is suspended while a commit is displayed — the input
140
147
  // still holds the committed text but shouldn't re-open the list.
141
- if (!query.trim() || isCommitted) {
148
+ // searchOnFocus lifts the non-empty-query requirement while the
149
+ // field is focused: clicking presents the list, typing narrows.
150
+ if (isCommitted || (!query.trim() && !(searchOnFocus && focused))) {
142
151
  setResults([]);
143
152
  setLoading(false);
144
153
  return;
@@ -168,7 +177,7 @@ export function Combobox({
168
177
  if (debounceRef.current) clearTimeout(debounceRef.current);
169
178
  abortRef.current?.abort();
170
179
  };
171
- }, [query, isCommitted, search, debounceMs]);
180
+ }, [query, isCommitted, search, debounceMs, searchOnFocus, focused]);
172
181
 
173
182
  const trimmed = query.trim();
174
183
  const freeEntryOk = !!allowFreeEntry && trimmed.length > 0 && allowFreeEntry(trimmed);
@@ -67,6 +67,12 @@ export function SegmentedControl<V extends string = string>({
67
67
  aria-label={ariaLabel}
68
68
  className={cn("ck-segmented", className)}
69
69
  data-testid={testId}
70
+ // The track is deliberately unfilled (owner feedback,
71
+ // 2026-08-19): a muted-filled track reads as a heavy block on
72
+ // warm canvases — the hairline border delimits the group and
73
+ // the raised selected segment carries ALL the contrast. This
74
+ // also makes the control look right on any surface (canvas,
75
+ // card, modal) without per-context tuning.
70
76
  style={{
71
77
  display: fit === "full" ? "flex" : "inline-flex",
72
78
  alignItems: "stretch",
@@ -74,7 +80,7 @@ export function SegmentedControl<V extends string = string>({
74
80
  padding: 2,
75
81
  borderRadius: 8,
76
82
  border: "1px solid var(--ck-border-subtle)",
77
- background: "var(--ck-bg-muted)",
83
+ background: "transparent",
78
84
  opacity: disabled ? 0.5 : 1,
79
85
  }}
80
86
  >
@@ -112,7 +118,7 @@ export function SegmentedControl<V extends string = string>({
112
118
  ? "var(--ck-text-primary)"
113
119
  : "var(--ck-text-secondary)",
114
120
  background: selected ? "var(--ck-bg-surface)" : "transparent",
115
- boxShadow: selected ? "0 1px 2px rgba(0,0,0,0.08)" : "none",
121
+ boxShadow: selected ? "0 1px 2px rgba(0,0,0,0.06)" : "none",
116
122
  borderColor: selected ? "var(--ck-border-subtle)" : "transparent",
117
123
  cursor: optDisabled ? "not-allowed" : "pointer",
118
124
  opacity: opt.disabled && !disabled ? 0.45 : 1,