feat: expandable pills and tool workflow styling from Ozwell widget#294
feat: expandable pills and tool workflow styling from Ozwell widget#294aditya-damerla128 wants to merge 12 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR brings Ozwell-style “pill” UI patterns into @mieweb/ui by introducing a reusable collapsible pill primitive, a new expandable PillSelect component, and updating AI message/tool-call UI to use pill-based presentation consistent with the widget.
Changes:
- Added
PillSelectcomponent (with Storybook stories) and exported it from the package. - Introduced
CollapsiblePillprimitive and exported it from the AI barrel. - Restyled
MCPToolCallDisplayand replaced the AI “thinking” block UI with a pill-basedThinkingBlock.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/index.ts | Exports the new PillSelect component from the package entrypoint. |
| src/components/PillSelect/PillSelect.tsx | Adds the expandable pill selector component with click-outside/Escape collapse behavior. |
| src/components/PillSelect/PillSelect.stories.tsx | Adds Storybook coverage for default/controlled/disabled/many-options states. |
| src/components/PillSelect/index.ts | Adds the barrel export for PillSelect types + component. |
| src/components/AI/MCPToolCall.tsx | Refactors tool-call UI into a status pill header + details box with animated parameter reveal. |
| src/components/AI/index.ts | Exports the new CollapsiblePill primitive from the AI module. |
| src/components/AI/CollapsiblePill.tsx | Introduces a shared collapsible pill primitive for thinking/tool displays. |
| src/components/AI/AIMessage.tsx | Adds the new ThinkingBlock pill behavior and swaps out the old reasoning block UI. |
| src/components/AI/AIMessage.stories.tsx | Updates stories to cover thinking pill states (active/complete/expanded). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
23736c9 to
45407e5
Compare
45407e5 to
be25404
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/components/PillSelect/PillSelect.tsx:49
- When the collapsed trigger is clicked, the focused
<button>is unmounted and replaced by the expanded option buttons. Without moving focus, keyboard users can lose focus (often ending up ondocument.body) and have to tab around to find the options. Add a small effect to focus the selected (or first enabled) option when expanding.
useClickOutside(ref, () => setExpanded(false), expanded);
useEscapeKey(() => setExpanded(false), expanded);
4ec868f to
d7f5718
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/components/PillSelect/PillSelect.tsx:50
- When the collapsed trigger button is activated, it’s immediately removed from the DOM and replaced with the expanded button list. This causes focus to be lost (especially for keyboard users), making the control hard to use without a mouse. Consider moving focus into the expanded options on open, and restoring focus to the collapsed trigger on close (without focusing anything on initial mount).
const [expanded, setExpanded] = React.useState(false);
const ref = React.useRef<HTMLDivElement>(null);
const value = controlledValue !== undefined ? controlledValue : internalValue;
const selectedOption = options.find((o) => o.value === value);
useClickOutside(ref, () => setExpanded(false), expanded);
useEscapeKey(() => setExpanded(false), expanded);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
src/components/PillSelect/PillSelect.tsx:50
- When the control expands, the collapsed trigger unmounts and is replaced by a different set of s. That typically causes keyboard focus to be lost (focused element is removed from the DOM), which is a UX/accessibility issue for keyboard and screen-reader users. Consider explicitly moving focus into the expanded option buttons on open, and restoring focus back to the collapsed pill on close (including when closing via click-outside / Escape).
const [expanded, setExpanded] = React.useState(false);
const ref = React.useRef<HTMLDivElement>(null);
const value = controlledValue !== undefined ? controlledValue : internalValue;
const selectedOption = options.find((o) => o.value === value);
useClickOutside(ref, () => setExpanded(false), expanded);
useEscapeKey(() => setExpanded(false), expanded);
src/tailwind-preset.ts:418
- New AI pill components introduce additional Tailwind utility classes for icon/dot sizing (
h-1.5 w-1.5in ThinkingBlock andh-2.5 w-2.5/h-3 w-3in CollapsiblePill’s chevron). Since this file is the Tailwind CSS 3 safelist for @mieweb/ui, these new class strings should also be added so consumers that don’t scan node_modules don’t lose the sizing styles.
// AI pills — CollapsiblePill / MCPToolCall arbitrary utilities
'rounded-[8px]',
'rounded-[10px]',
'px-[11px]',
'max-h-0',
'max-h-[500px]',
'transition-[max-height,opacity]',
'overflow-y-auto',
'focus-visible:ring-ring',
'focus-visible:ring-offset-1',
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
src/components/PillSelect/PillSelect.tsx:50
- When the pill expands, the collapsed trigger is unmounted and replaced by the option buttons. If the trigger had focus (keyboard activation), focus will typically drop to the document/body, forcing keyboard users to Tab again to reach the options. Consider moving focus into the expanded control (prefer the selected enabled option, otherwise the first enabled option) when
expandedbecomes true.
useClickOutside(ref, () => setExpanded(false), expanded);
useEscapeKey(() => setExpanded(false), expanded);
Addresses mieweb#290. Brings the Ozwell chat widget's pill patterns into the UI package as themeable components: - PillSelect: collapsible option selector (the reasoning-mode capsule -> segmented control). Any number of options, fully themeable via tokens. - ThinkingBlock: reasoning pill that shows "Thinking" with a pulsing dot while streaming, then "Thought for Xs" when done. Click to expand/collapse. - MCPToolCall: status pill header (green success / red error kept the same) with friendly tool names (underscores stripped, tense-shifted), result and resource links in a capped-width box, and toggleable raw params with a smooth expand/collapse animation. - CollapsiblePill: shared primitive behind the thinking + tool pills.
- MCPToolCall: default shows only the status pill; clicking it reveals the
whole box (result, links, raw params) in one click with a "Show details"
tooltip. Input summary now rides in the pill while running
("Creating patient · John Smith"); success shows duration instead.
- Add `hidden` prop to turn the tool-call display off entirely (mirrors the
Ozwell widget debug flag).
- tailwind-preset: safelist the AI pill arbitrary utilities, the violet
thinking-pill classes, and the green/red status pill colors so Tailwind 3
consumers get them.
- CollapsiblePill: don't mutate internal state when controlled; add optional
title (tooltip).
- PillSelect: no trailing colon when empty; disable the pill when there are
no options.
- Stories: add PillOnly and Hidden; refresh control docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
f2e4237 to
07b3be0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
src/components/PillSelect/PillSelect.tsx:49
- When PillSelect expands, the previously focused collapsed is removed from the DOM and focus can fall back to , which breaks keyboard flow (Space/Enter to open, then Tab starts from the top of the page). Consider moving focus into the expanded options when
expandedbecomes true (e.g., focus the selected option if enabled, otherwise the first enabled option).
const [expanded, setExpanded] = React.useState(false);
const ref = React.useRef<HTMLDivElement>(null);
const value = controlledValue !== undefined ? controlledValue : internalValue;
const selectedOption = options.find((o) => o.value === value);
useClickOutside(ref, () => setExpanded(false), expanded);
useEscapeKey(() => setExpanded(false), expanded);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
src/components/PillSelect/PillSelect.tsx:49
- When PillSelect expands, the collapsed trigger button is removed from the DOM and there’s no focus handoff to the expanded option buttons. For keyboard users this can drop focus to , making the expanded options hard to reach/understand. Add focus management so expanding focuses the selected (or first enabled) option, and collapsing restores focus to the collapsed trigger when focus was inside the component.
const value = controlledValue !== undefined ? controlledValue : internalValue;
const selectedOption = options.find((o) => o.value === value);
const close = React.useCallback(() => setExpanded(false), []);
useClickOutside(ref, close, expanded);
Closes #290.
Brings the Ozwell chat widget's pill patterns into the UI package as themeable components.
What's added
src/components/PillSelect/) — the expandable option selector (the reasoning-mode capsule that expands into a segmented control). Collapsed pill → click → options → pick → collapses back. Any number of options, fully themeable via design tokens. Closes on click-outside / Escape.AIMessage) — reasoning pill showing "Thinking" with a pulsing dot while streaming, then "Thought for Xs" once done. Click to expand/collapse the reasoning text.create_patient→ "Creating patient" → "Created patient").src/components/AI/CollapsiblePill.tsx) — shared primitive behind the thinking + tool pills.Checks
All components use mieweb/ui design tokens (light + dark mode).