polymorph-ui-components-mcp 0.3.1 → 0.4.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.
@@ -2,9 +2,14 @@
2
2
  based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
3
3
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
- ## [Unreleased](https://github.com/sinha-sahil/polymorph-ui-components/compare/0.6.0...HEAD)
5
+ ## [Unreleased](https://github.com/sinha-sahil/polymorph-ui-components/compare/0.6.2...HEAD)
6
6
 
7
- - Added repo url to run oidc
7
+ - include build:wc in build script so publint finds dist-wc
8
+ - add --modal-flex-direction css variable
9
+
10
+ ## [0.6.2](https://github.com/sinha-sahil/polymorph-ui-components/compare/0.6.1...0.6.2) - 11 August 2026
11
+
12
+ ## [0.6.1](https://github.com/sinha-sahil/polymorph-ui-components/compare/0.6.0...0.6.1) - 5 August 2026
8
13
 
9
14
  ## [0.6.0](https://github.com/sinha-sahil/polymorph-ui-components/compare/0.5.0...0.6.0) - 5 August 2026
10
15
 
@@ -77,6 +77,24 @@ Markdown is intentionally not bundled: pass pre-sanitized HTML on a message's `h
77
77
 
78
78
  **Roles.** Messages use the two-party primitive `role` — `sender` / `responder` (see `ChatMessage`). The controller emits those, and `partyOf(role)` resolves any role (including the `user`/`assistant`/`system` extensions) to its party. Map the primitive to your provider's roles inside the transport, where the API-specific terms belong: `history.map((m) => ({ role: partyOf(m.role) === 'sender' ? 'user' : 'assistant', content: m.content }))`.
79
79
 
80
+ ## Your own UI inside a message
81
+
82
+ Two snippets, and the difference matters. `message` replaces the whole message — you own the bubble, alignment, streaming indicator, and you lose the built-in copy / retry / feedback wiring. `messageAttachments` renders **below** the bubble and keeps all of that, so reach for it first.
83
+
84
+ It receives the whole `ChatMessageData`, so render on whatever field you like — a custom field of your own, or `attachments`, which `ChatController` fills from a transport's `handlers.onAttachment(...)`:
85
+
86
+ ```svelte
87
+ <Chat {messages} bind:value allowCopy onretry={() => chat.retry()} {onsend}>
88
+ {#snippet messageAttachments(msg)}
89
+ {#each msg.attachments ?? [] as item, index (index)}
90
+ <YourComponent data={item} />
91
+ {/each}
92
+ {/snippet}
93
+ </Chat>
94
+ ```
95
+
96
+ The snippet is invoked for every message, so branch inside it to target specific ones. Rendering nothing costs no layout — the container collapses when empty.
97
+
80
98
  ## Layout — fullscreen & floating
81
99
 
82
100
  `Chat` is position- and size-agnostic: its root fills its container (`--chat-height` / `--chat-width` default to `100%`), with the message list on `flex: 1` and the composer pinned to the bottom. The only requirement is a **bounded-height parent** — the flexing list needs something to fill. Positioning (fixed, floating, modal) is the consumer's job; the component never assumes a layout context.
@@ -163,7 +181,8 @@ The fixed-height `.chat-panel` gives `Chat` its bounds; add a slide/scale transi
163
181
  | headerAvatar | `Snippet` | No | `-` | Brand/avatar mark in the header (takes precedence over `image`). |
164
182
  | headerActions | `Snippet` | No | `-` | Extra inline header actions. |
165
183
  | headerContent | `Snippet` | No | `-` | Extra content as a full-width second row in the header (toolbar, status…). |
166
- | message | `Snippet<[ChatMessageData]>` | No | `-` | Custom per-message rendering. |
184
+ | message | `Snippet<[ChatMessageData]>` | No | `-` | Custom per-message rendering. Replaces the default bubble entirely. |
185
+ | messageAttachments | `Snippet<[ChatMessageData]>` | No | `-` | Your own UI rendered below each bubble, keeping the default bubble and its actions. |
167
186
  | empty | `Snippet` | No | `-` | Empty-state content. |
168
187
  | composerLeading | `Snippet` | No | `-` | Content before the composer input. |
169
188
  | sendIcon / stopIcon / voiceIcon / attachIcon | `Snippet` | No | `-` | Custom composer icons; each falls back to a built-in asset. |
@@ -29,7 +29,7 @@ A single chat bubble. The primitive is the **party** — every message is from o
29
29
  | status | `'sending' \| 'sent' \| 'error'` | No | `-` | `error` tints the bubble with the error color. |
30
30
  | avatar | `Snippet` | No | `-` | Avatar shown beside the bubble. |
31
31
  | header | `Snippet` | No | `-` | Header row above the bubble (author name, timestamp, etc.). |
32
- | attachments | `Snippet` | No | `-` | Content rendered below the bubble. |
32
+ | attachments | `Snippet \| null` | No | `-` | Content rendered below the bubble. Collapses to no layout when it renders nothing. |
33
33
  | allowCopy | `boolean` | No | `false` | Show a built-in copy button in the hover actions row. |
34
34
  | actions | `Snippet` | No | `-` | Extra custom actions appended to the actions row. |
35
35
  | copyLabel / retryLabel / feedbackUpLabel / feedbackDownLabel | `string` | No | `…` | Aria-labels for the action buttons. |
@@ -1,6 +1,6 @@
1
1
  # ChatMessageList
2
2
 
3
- A scrollable, auto-scrolling container for a conversation. It renders each message with `ChatMessage` by default, or a fully custom `message` snippet (use this to add avatars, attachments, or timestamps). When there are no messages, the `empty` snippet is shown. **Smart auto-scroll** keeps the latest content in view only while you're already near the bottom — if you scroll up to read history it won't yank you down, and a **jump-to-latest** button appears instead. Opt-in message actions (`allowCopy`, `onretry`, `onfeedback`) are applied to the default-rendered messages: copy and feedback on assistant messages, retry on the most recent assistant message. Implemented with a Svelte action (no effects), respecting `prefers-reduced-motion`.
3
+ A scrollable, auto-scrolling container for a conversation. It renders each message with `ChatMessage` by default. To add your own UI below a bubble, pass `messageAttachments` — it receives each `ChatMessageData` and keeps the default bubble along with its copy/retry/feedback actions. Use the `message` snippet only when you want to replace a message entirely, which forgoes that default rendering. When there are no messages, the `empty` snippet is shown. **Smart auto-scroll** keeps the latest content in view only while you're already near the bottom — if you scroll up to read history it won't yank you down, and a **jump-to-latest** button appears instead. Opt-in message actions (`allowCopy`, `onretry`, `onfeedback`) are applied to the default-rendered messages: copy and feedback on assistant messages, retry on the most recent assistant message. Implemented with a Svelte action (no effects), respecting `prefers-reduced-motion`.
4
4
 
5
5
  ## Usage
6
6
 
@@ -24,6 +24,7 @@ A scrollable, auto-scrolling container for a conversation. It renders each messa
24
24
  | messages | `ChatMessageData[]` | Yes | `-` | Messages to render. |
25
25
  | autoscroll | `boolean` | No | `true` | Auto-scroll to the latest message as content changes. |
26
26
  | message | `Snippet<[ChatMessageData]>` | No | `-` | Custom per-message rendering; overrides the default bubble. |
27
+ | messageAttachments | `Snippet<[ChatMessageData]>` | No | `-` | Own UI below each bubble; keeps the default bubble and actions. |
27
28
  | empty | `Snippet` | No | `-` | Shown when there are no messages. |
28
29
  | jumpLabel | `string` | No | `'Jump to latest'` | Aria-label for the jump-to-latest button. |
29
30
  | jumpIcon | `Snippet` | No | `-` | Custom jump-to-latest icon. Falls back to a built-in asset. |
@@ -1,6 +1,6 @@
1
1
  # Gallery
2
2
 
3
- An image gallery with grid and list views and a built-in lightbox viewer. Clicking an item (or pressing Enter/Space on it) opens the image full-screen in a modal lightbox with previous/next navigation, keyboard support (Escape closes, ArrowLeft/ArrowRight navigate, Home/End jump to first/last), a focus trap, a fade transition, and focus return to the originating item on close. Body scroll is locked for exactly as long as the lightbox is rendered. The lightbox state is also exposed as bindable `open` / `activeIndex` props, so consumers can observe it or open the lightbox programmatically. The `view` prop switches between a `grid` of image tiles and a `list` of rows showing the thumbnail, the `alt` text as title, and the `caption` as subtitle. When an `oneditclick` and/or `ondeleteclick` handler is provided, each item renders the corresponding edit/delete action buttons (grid: overlaid top-right; list: at the row end) that fire the handler without opening the lightbox. Items only become buttons when the lightbox is enabled or an `onimageclick` handler is provided; otherwise they render as plain content. Reuses the `Img` component for error-based fallback rendering, the `Button` component for lightbox and edit controls, and the `Icon` component for the built-in control icons.
3
+ An image gallery with grid and list views and a built-in lightbox viewer. Clicking an item (or pressing Enter/Space on it) opens the image full-screen in a modal lightbox with previous/next navigation, keyboard support (Escape closes, ArrowLeft/ArrowRight navigate, Home/End jump to first/last), a focus trap, a fade transition, and focus return to the originating item on close. Body scroll is locked for exactly as long as the lightbox is rendered. The lightbox state is also exposed as bindable `open` / `activeIndex` props, so consumers can observe it or open the lightbox programmatically. The `view` prop switches between a `grid` of image tiles and a `list` of rows showing the thumbnail, the `alt` text as title, and the `caption` as subtitle. In `grid` view, a `itemFooter` snippet lets a consumer render arbitrary content (title, metadata, whatever markup they need) below each tile's image — Gallery only owns the image portion and hands the rest to the snippet, the same way `Table`'s `cell` snippet works. When an `oneditclick` and/or `ondeleteclick` handler is provided, each item renders the corresponding edit/delete action buttons (grid: overlaid top-right; list: at the row end) that fire the handler without opening the lightbox. Items only become buttons when the lightbox is enabled or an `onimageclick` handler is provided; otherwise they render as plain content. Reuses the `Img` component for error-based fallback rendering, the `Button` component for lightbox and edit controls, and the `Icon` component for the built-in control icons.
4
4
 
5
5
  ## Usage
6
6
 
@@ -27,127 +27,145 @@ An image gallery with grid and list views and a built-in lightbox viewer. Clicki
27
27
 
28
28
  <!-- Programmatic lightbox control via bindable props -->
29
29
  <Gallery {images} bind:open={lightboxOpen} bind:activeIndex={lightboxIndex} />
30
- <Button text="Show third image" onclick={() => { lightboxIndex = 2; lightboxOpen = true; }} />
30
+ <Button
31
+ text="Show third image"
32
+ onclick={() => {
33
+ lightboxIndex = 2;
34
+ lightboxOpen = true;
35
+ }}
36
+ />
37
+
38
+ <!-- Grid view with per-tile info rendered by the consumer -->
39
+ <Gallery {images} view="grid" {itemFooter} oneditclick={(index) => openEditor(index)} />
40
+
41
+ {#snippet itemFooter(image, index)}
42
+ <div class="tile-info">
43
+ <strong>{image.alt}</strong>
44
+ <span>{image.caption}</span>
45
+ </div>
46
+ {/snippet}
31
47
  ```
32
48
 
33
49
  ## Props
34
50
 
35
- | Prop | Type | Required | Default | Description |
36
- | -------------- | ---------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
- | images | `GalleryImage[]` | Yes | `-` | Array of images to display. Each entry has a full-size `src`, required `alt` text, and optional `thumbnail` (shown in the grid/list), `fallback` (shown when the image fails to load), and `caption` (shown in the lightbox and as the list-row subtitle). |
38
- | view | `GalleryView` | No | `grid` | Layout of the gallery items: `grid` renders image tiles; `list` renders rows with the thumbnail, `alt` text as title, and `caption` as subtitle. |
39
- | open | `boolean` | No | `false` | Whether the lightbox is open. Bindable — the component sets it to `false` when the lightbox is closed, and consumers can set it to `true` (with `activeIndex`) to open the lightbox programmatically. |
40
- | activeIndex | `number` | No | `0` | Index of the image shown in the lightbox. Bindable — updated by lightbox navigation; set it together with `open` for programmatic control. |
41
- | enableLightbox | `boolean` | No | `true` | When true, clicking an item opens the image in the lightbox. When false, items are non-interactive unless `onimageclick` is provided. |
42
- | loop | `boolean` | No | `false` | When true, lightbox navigation wraps around from the last image to the first and vice versa. |
43
- | showCounter | `boolean` | No | `true` | When true, shows a "current / total" position counter at the bottom of the lightbox. |
44
- | showCaption | `boolean` | No | `true` | When true, shows the active image's `caption` below it in the lightbox (only when the image has one). |
45
- | previousIcon | `Snippet` | No | `-` | Snippet rendering a custom previous-navigation icon. Falls back to the built-in chevron asset when omitted. |
46
- | nextIcon | `Snippet` | No | `-` | Snippet rendering a custom next-navigation icon. Falls back to the built-in chevron asset when omitted. |
47
- | closeIcon | `Snippet` | No | `-` | Snippet rendering a custom close icon. Falls back to the built-in close asset when omitted. |
48
- | editIcon | `Snippet` | No | `-` | Snippet rendering a custom edit icon. Falls back to the built-in pencil asset when omitted. Only rendered when `oneditclick` is provided. |
49
- | deleteIcon | `Snippet` | No | `-` | Snippet rendering a custom delete icon. Falls back to the built-in trash asset when omitted. Only rendered when `ondeleteclick` is provided. |
50
- | testId | `string` | No | `-` | Test selector value applied as `data-pw` on the grid container. |
51
- | classes | `string` | No | `-` | CSS class string applied to the component's top-level element. Useful for theming — define classes with CSS variable overrides (e.g., `.btn-primary { --button-color: #0070f3; }`) and pass them to create variant styles. |
51
+ | Prop | Type | Required | Default | Description |
52
+ | -------------- | --------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
53
+ | images | `GalleryImage[]` | Yes | `-` | Array of images to display. Each entry has a full-size `src`, required `alt` text, and optional `thumbnail` (shown in the grid/list), `fallback` (shown when the image fails to load), and `caption` (shown in the lightbox and as the list-row subtitle). |
54
+ | view | `GalleryView` | No | `grid` | Layout of the gallery items: `grid` renders image tiles; `list` renders rows with the thumbnail, `alt` text as title, and `caption` as subtitle. |
55
+ | open | `boolean` | No | `false` | Whether the lightbox is open. Bindable — the component sets it to `false` when the lightbox is closed, and consumers can set it to `true` (with `activeIndex`) to open the lightbox programmatically. |
56
+ | activeIndex | `number` | No | `0` | Index of the image shown in the lightbox. Bindable — updated by lightbox navigation; set it together with `open` for programmatic control. |
57
+ | enableLightbox | `boolean` | No | `true` | When true, clicking an item opens the image in the lightbox. When false, items are non-interactive unless `onimageclick` is provided. |
58
+ | loop | `boolean` | No | `false` | When true, lightbox navigation wraps around from the last image to the first and vice versa. |
59
+ | showCounter | `boolean` | No | `true` | When true, shows a "current / total" position counter at the bottom of the lightbox. |
60
+ | showCaption | `boolean` | No | `true` | When true, shows the active image's `caption` below it in the lightbox (only when the image has one). |
61
+ | previousIcon | `Snippet` | No | `-` | Snippet rendering a custom previous-navigation icon. Falls back to the built-in chevron asset when omitted. |
62
+ | nextIcon | `Snippet` | No | `-` | Snippet rendering a custom next-navigation icon. Falls back to the built-in chevron asset when omitted. |
63
+ | closeIcon | `Snippet` | No | `-` | Snippet rendering a custom close icon. Falls back to the built-in close asset when omitted. |
64
+ | editIcon | `Snippet` | No | `-` | Snippet rendering a custom edit icon. Falls back to the built-in pencil asset when omitted. Only rendered when `oneditclick` is provided. |
65
+ | deleteIcon | `Snippet` | No | `-` | Snippet rendering a custom delete icon. Falls back to the built-in trash asset when omitted. Only rendered when `ondeleteclick` is provided. |
66
+ | itemFooter | `Snippet<[GalleryImage, number]>` | No | `-` | Only applies to `view="grid"`. When provided, renders below each tile's image (in `.grid-image-wrap`), receiving the image and its index — the consumer owns the markup, styling, and which `GalleryImage` fields it uses. Omitted → grid tiles render as bare image tiles, same as today. |
67
+ | testId | `string` | No | `-` | Test selector value applied as `data-pw` on the grid container. |
68
+ | classes | `string` | No | `-` | CSS class string applied to the component's top-level element. Useful for theming — define classes with CSS variable overrides (e.g., `.btn-primary { --button-color: #0070f3; }`) and pass them to create variant styles. |
52
69
 
53
70
  ## Events
54
71
 
55
- | Event | Type | Description |
56
- | ------------ | --------------------------------------- | ------------------------------------------------------------------------------------------- |
57
- | onimageclick | `(index: number, event: MouseEvent) => void` | Fires when a gallery item is clicked, before the lightbox opens. |
58
- | oneditclick | `(index: number, event: MouseEvent) => void` | Fires when an item's edit button is clicked. Providing this handler is what makes the edit buttons render; the click does not open the lightbox. |
59
- | ondeleteclick | `(index: number, event: MouseEvent) => void` | Fires when an item's delete button is clicked. Providing this handler is what makes the delete buttons render; the click does not open the lightbox. |
60
- | onopen | `(index: number) => void` | Fires when the lightbox opens, with the index of the opened image. |
61
- | onclose | `() => void` | Fires when the component closes the lightbox (close button, Escape key, or backdrop click). Not fired when the consumer closes it by writing `open = false`. |
62
- | onchange | `(index: number) => void` | Fires when the active lightbox image changes via navigation buttons or keyboard. |
63
- | onkeydown | `(event: KeyboardEvent) => void` | Fires for key presses while the lightbox is open, before the built-in keyboard handling. |
72
+ | Event | Type | Description |
73
+ | ------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
74
+ | onimageclick | `(index: number, event: MouseEvent) => void` | Fires when a gallery item is clicked, before the lightbox opens. |
75
+ | oneditclick | `(index: number, event: MouseEvent) => void` | Fires when an item's edit button is clicked. Providing this handler is what makes the edit buttons render; the click does not open the lightbox. |
76
+ | ondeleteclick | `(index: number, event: MouseEvent) => void` | Fires when an item's delete button is clicked. Providing this handler is what makes the delete buttons render; the click does not open the lightbox. |
77
+ | onopen | `(index: number) => void` | Fires when the lightbox opens, with the index of the opened image. |
78
+ | onclose | `() => void` | Fires when the component closes the lightbox (close button, Escape key, or backdrop click). Not fired when the consumer closes it by writing `open = false`. |
79
+ | onchange | `(index: number) => void` | Fires when the active lightbox image changes via navigation buttons or keyboard. |
80
+ | onkeydown | `(event: KeyboardEvent) => void` | Fires for key presses while the lightbox is open, before the built-in keyboard handling. |
64
81
 
65
82
  ## Keyboard Interactions
66
83
 
67
- | Key | Context | Action |
68
- | --------------------- | -------------- | ---------------------------------------- |
69
- | `Enter` / `Space` | Gallery item | Opens the lightbox for that image. |
70
- | `Enter` / `Space` | Edit button | Fires `oneditclick` for that image. |
71
- | `Enter` / `Space` | Delete button | Fires `ondeleteclick` for that image. |
72
- | `Escape` | Lightbox open | Closes the lightbox. |
73
- | `ArrowLeft` | Lightbox open | Shows the previous image. |
74
- | `ArrowRight` | Lightbox open | Shows the next image. |
75
- | `Home` / `End` | Lightbox open | Jumps to the first / last image. |
76
- | `Tab` / `Shift+Tab` | Lightbox open | Cycles focus between lightbox controls (focus is trapped). |
84
+ | Key | Context | Action |
85
+ | ------------------- | ------------- | ---------------------------------------------------------- |
86
+ | `Enter` / `Space` | Gallery item | Opens the lightbox for that image. |
87
+ | `Enter` / `Space` | Edit button | Fires `oneditclick` for that image. |
88
+ | `Enter` / `Space` | Delete button | Fires `ondeleteclick` for that image. |
89
+ | `Escape` | Lightbox open | Closes the lightbox. |
90
+ | `ArrowLeft` | Lightbox open | Shows the previous image. |
91
+ | `ArrowRight` | Lightbox open | Shows the next image. |
92
+ | `Home` / `End` | Lightbox open | Jumps to the first / last image. |
93
+ | `Tab` / `Shift+Tab` | Lightbox open | Cycles focus between lightbox controls (focus is trapped). |
77
94
 
78
95
  ## CSS Variables
79
96
 
80
97
  Override these custom properties to theme the component.
81
98
 
82
- | Variable | Default | CSS Property | Description |
83
- | -------------------------------------------- | -------------- | --------------------- | ------------------------------------------------------------------------------ |
84
- | `--gallery-columns` | `3` | grid-template-columns | Number of columns in the grid (used as `repeat(N, 1fr)`). |
85
- | `--gallery-gap` | `8px` | gap | Gap between grid tiles. |
86
- | `--gallery-width` | `100%` | width | Width of the grid container. |
87
- | `--gallery-padding` | `0px` | padding | Padding of the grid container. |
88
- | `--gallery-margin` | `0px` | margin | Margin of the grid container. |
89
- | `--gallery-background` | `transparent` | background | Background of the grid container. |
90
- | `--gallery-item-aspect-ratio` | `1` | aspect-ratio | Aspect ratio of each grid tile. |
91
- | `--gallery-item-border-radius` | `0px` | border-radius | Corner rounding of each grid tile and its image. |
92
- | `--gallery-item-border` | `none` | border | Border of each interactive item (grid tile or list row open-button). |
93
- | `--gallery-item-image-fit` | `cover` | object-fit | Object fit of the image inside each grid tile. |
94
- | `--gallery-item-image-transition` | `-` | transition | Transition applied to the image inside each grid tile. |
95
- | `--gallery-item-cursor` | `pointer` | cursor | Cursor over interactive items (grid tiles or list rows). |
96
- | `--gallery-item-transition` | `-` | transition | Transition applied to interactive items (grid tiles or list rows). |
97
- | `--gallery-item-hover-opacity` | `1` | opacity | Opacity of an interactive grid tile on hover. |
98
- | `--gallery-item-hover-transform` | `-` | transform | Transform of an interactive grid tile on hover. |
99
- | `--gallery-item-focus-outline` | `2px solid currentColor` | outline | Focus-visible outline of an interactive item. Wraps the grid tile, or the full list row including its action buttons. |
100
- | `--gallery-item-focus-outline-offset` | `2px` | outline-offset | Focus-visible outline offset of an interactive item. |
101
- | `--gallery-list-item-gap` | `12px` | gap | Gap between the thumbnail and text block in a list row. |
102
- | `--gallery-list-item-padding` | `8px` | padding | Padding of each list row. |
103
- | `--gallery-list-item-background` | `transparent` | background | Background of each list row. |
104
- | `--gallery-list-item-hover-background` | `transparent` | background | Hover background of an interactive list row. Covers the full row, action buttons included; static rows are not highlighted. |
105
- | `--gallery-list-item-border-radius` | `0px` | border-radius | Corner rounding of each list row. |
106
- | `--gallery-list-thumbnail-width` | `56px` | width | Width of the thumbnail in a list row. |
107
- | `--gallery-list-thumbnail-height` | `56px` | height | Height of the thumbnail in a list row. |
108
- | `--gallery-list-thumbnail-fit` | `cover` | object-fit | Object fit of the thumbnail in a list row. |
109
- | `--gallery-list-thumbnail-border-radius` | `0px` | border-radius | Corner rounding of the thumbnail in a list row. |
110
- | `--gallery-list-text-gap` | `2px` | gap | Gap between the title and caption in a list row. |
111
- | `--gallery-list-title-color` | `inherit` | color | Text color of the list-row title (the image `alt`). |
112
- | `--gallery-list-title-font-size` | `14px` | font-size | Font size of the list-row title. |
113
- | `--gallery-list-title-font-weight` | `500` | font-weight | Font weight of the list-row title. |
114
- | `--gallery-list-title-font-family` | `-` | font-family | Font family of the list-row title. |
115
- | `--gallery-list-caption-color` | `inherit` | color | Text color of the list-row caption. |
116
- | `--gallery-list-caption-font-size` | `12px` | font-size | Font size of the list-row caption. |
117
- | `--gallery-list-caption-font-family` | `-` | font-family | Font family of the list-row caption. |
118
- | `--gallery-item-actions-top` | `8px` | top | Distance of the action-button cluster from the top of a grid tile. |
119
- | `--gallery-item-actions-right` | `8px` | right / padding-right | Distance of the action-button cluster from the right edge of an item. |
120
- | `--gallery-item-actions-gap` | `4px` | gap | Gap between the edit and delete buttons. |
121
- | `--gallery-item-action-background` | grid: `#00000066`, list: `transparent` | background | Background of the edit/delete action buttons. Grid tiles get a frosted-glass scrim over the image; list rows stay transparent. |
122
- | `--gallery-item-action-backdrop-filter` | grid: `blur(8px)` | backdrop-filter | Backdrop filter behind the action buttons in grid view (frosted-glass effect). |
123
- | `--gallery-item-action-color` | grid: `#ffffff`, list: `currentColor` | color | Icon color of the action buttons. |
124
- | `--gallery-item-action-hover-background` | grid: `#00000099`, list: `#80808026` | background | Hover background of the action buttons. |
125
- | `--gallery-item-action-padding` | `6px` | padding | Padding of the action buttons. |
126
- | `--gallery-item-action-border-radius` | `8px` | border-radius | Corner rounding of the action buttons. |
127
- | `--gallery-item-action-icon-size` | `16px` | width / height | Size of the built-in icons inside the action buttons (bridged to the inner `Icon`'s `--icon-width`/`--icon-height`; custom icon snippets size themselves). |
128
- | `--gallery-lightbox-z-index` | `15` | z-index | Stacking order of the lightbox overlay. |
129
- | `--gallery-lightbox-background` | `#000000e6` | background | Backdrop color of the lightbox overlay. |
130
- | `--gallery-lightbox-image-width` | `85vw` | width | Width of the lightbox image box (image letterboxes inside via object-fit). |
131
- | `--gallery-lightbox-image-height` | `75vh` | height | Height of the lightbox image box. |
132
- | `--gallery-lightbox-image-fit` | `contain` | object-fit | Object fit of the lightbox image. |
133
- | `--gallery-lightbox-image-border-radius` | `0px` | border-radius | Corner rounding of the lightbox image. |
134
- | `--gallery-lightbox-caption-gap` | `12px` | gap | Gap between the lightbox image and its caption. |
135
- | `--gallery-lightbox-caption-color` | `#ffffff` | color | Text color of the lightbox caption. |
136
- | `--gallery-lightbox-caption-font-size` | `14px` | font-size | Font size of the lightbox caption. |
137
- | `--gallery-lightbox-caption-font-family` | `-` | font-family | Font family of the lightbox caption. |
138
- | `--gallery-lightbox-counter-bottom` | `16px` | bottom | Distance of the position counter from the bottom of the lightbox. |
139
- | `--gallery-lightbox-counter-color` | `#ffffff` | color | Text color of the position counter. |
140
- | `--gallery-lightbox-counter-font-size` | `13px` | font-size | Font size of the position counter. |
141
- | `--gallery-lightbox-counter-font-family` | `-` | font-family | Font family of the position counter. |
142
- | `--gallery-lightbox-close-top` | `16px` | top | Distance of the close button from the top of the lightbox. |
143
- | `--gallery-lightbox-close-right` | `16px` | right | Distance of the close button from the right of the lightbox. |
144
- | `--gallery-lightbox-nav-inset` | `16px` | left / right | Distance of the previous/next buttons from the lightbox edges. |
145
- | `--gallery-lightbox-control-background` | `transparent` | background-color | Background of the lightbox close and navigation buttons. |
146
- | `--gallery-lightbox-control-color` | `#ffffff` | color | Icon color of the lightbox close and navigation buttons. |
147
- | `--gallery-lightbox-control-hover-background`| `#ffffff1f` | background | Hover background of the lightbox close and navigation buttons. |
148
- | `--gallery-lightbox-control-padding` | `8px` | padding | Padding of the lightbox close and navigation buttons. |
149
- | `--gallery-lightbox-control-border-radius` | `50%` | border-radius | Corner rounding of the lightbox close and navigation buttons. |
150
- | `--gallery-lightbox-control-icon-size` | `24px` | width / height | Size of the built-in icons inside the lightbox close and navigation buttons (bridged to the inner `Icon`'s `--icon-width`/`--icon-height`; custom icon snippets size themselves). |
99
+ | Variable | Default | CSS Property | Description |
100
+ | --------------------------------------------- | -------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
101
+ | `--gallery-columns` | `3` | grid-template-columns | Number of columns in the grid (used as `repeat(N, 1fr)`). Ignored when `--gallery-grid-template-columns` is set. |
102
+ | `--gallery-grid-template-columns` | `-` | grid-template-columns | Full override of the grid's column tracks, e.g. `repeat(auto-fill, minmax(180px, 1fr))` for a responsive grid instead of a fixed `--gallery-columns` count. |
103
+ | `--gallery-gap` | `8px` | gap | Gap between grid tiles. |
104
+ | `--gallery-width` | `100%` | width | Width of the grid container. |
105
+ | `--gallery-padding` | `0px` | padding | Padding of the grid container. |
106
+ | `--gallery-margin` | `0px` | margin | Margin of the grid container. |
107
+ | `--gallery-background` | `transparent` | background | Background of the grid container. |
108
+ | `--gallery-item-aspect-ratio` | `1` | aspect-ratio | Aspect ratio of each grid tile. |
109
+ | `--gallery-item-border-radius` | `0px` | border-radius | Corner rounding of each grid tile and its image. When `itemFooter` is used, applies to the whole tile (image + snippet content), not just the image. |
110
+ | `--gallery-item-border` | `none` | border | Border of each interactive item (grid tile or list row open-button). Wraps the whole tile, snippet content included, when `itemFooter` is used. |
111
+ | `--gallery-item-image-fit` | `cover` | object-fit | Object fit of the image inside each grid tile. |
112
+ | `--gallery-item-image-transition` | `-` | transition | Transition applied to the image inside each grid tile. |
113
+ | `--gallery-item-cursor` | `pointer` | cursor | Cursor over interactive items (grid tiles or list rows). |
114
+ | `--gallery-item-transition` | `-` | transition | Transition applied to interactive items (grid tiles or list rows). |
115
+ | `--gallery-item-hover-opacity` | `1` | opacity | Opacity of an interactive grid tile on hover. |
116
+ | `--gallery-item-hover-transform` | `-` | transform | Transform of an interactive grid tile on hover. |
117
+ | `--gallery-item-focus-outline` | `2px solid currentColor` | outline | Focus-visible outline of an interactive item. Wraps the grid tile, or the full list row including its action buttons. |
118
+ | `--gallery-item-focus-outline-offset` | `2px` | outline-offset | Focus-visible outline offset of an interactive item. |
119
+ | `--gallery-list-item-gap` | `12px` | gap | Gap between the thumbnail and text block in a list row. |
120
+ | `--gallery-list-item-padding` | `8px` | padding | Padding of each list row. |
121
+ | `--gallery-list-item-background` | `transparent` | background | Background of each list row. |
122
+ | `--gallery-list-item-hover-background` | `transparent` | background | Hover background of an interactive list row. Covers the full row, action buttons included; static rows are not highlighted. |
123
+ | `--gallery-list-item-border-radius` | `0px` | border-radius | Corner rounding of each list row. |
124
+ | `--gallery-list-thumbnail-width` | `56px` | width | Width of the thumbnail in a list row. |
125
+ | `--gallery-list-thumbnail-height` | `56px` | height | Height of the thumbnail in a list row. |
126
+ | `--gallery-list-thumbnail-fit` | `cover` | object-fit | Object fit of the thumbnail in a list row. |
127
+ | `--gallery-list-thumbnail-border-radius` | `0px` | border-radius | Corner rounding of the thumbnail in a list row. |
128
+ | `--gallery-list-text-gap` | `2px` | gap | Gap between the title and caption in a list row. |
129
+ | `--gallery-list-title-color` | `inherit` | color | Text color of the list-row title (the image `alt`). |
130
+ | `--gallery-list-title-font-size` | `14px` | font-size | Font size of the list-row title. |
131
+ | `--gallery-list-title-font-weight` | `500` | font-weight | Font weight of the list-row title. |
132
+ | `--gallery-list-title-font-family` | `-` | font-family | Font family of the list-row title. |
133
+ | `--gallery-list-caption-color` | `inherit` | color | Text color of the list-row caption. |
134
+ | `--gallery-list-caption-font-size` | `12px` | font-size | Font size of the list-row caption. |
135
+ | `--gallery-list-caption-font-family` | `-` | font-family | Font family of the list-row caption. |
136
+ | `--gallery-item-actions-top` | `8px` | top | Distance of the action-button cluster from the top of a grid tile. |
137
+ | `--gallery-item-actions-right` | `8px` | right / padding-right | Distance of the action-button cluster from the right edge of an item. |
138
+ | `--gallery-item-actions-gap` | `4px` | gap | Gap between the edit and delete buttons. |
139
+ | `--gallery-item-action-background` | grid: `#00000066`, list: `transparent` | background | Background of the edit/delete action buttons. Grid tiles get a frosted-glass scrim over the image; list rows stay transparent. |
140
+ | `--gallery-item-action-backdrop-filter` | grid: `blur(8px)` | backdrop-filter | Backdrop filter behind the action buttons in grid view (frosted-glass effect). |
141
+ | `--gallery-item-action-color` | grid: `#ffffff`, list: `currentColor` | color | Icon color of the action buttons. |
142
+ | `--gallery-item-action-hover-background` | grid: `#00000099`, list: `#80808026` | background | Hover background of the action buttons. |
143
+ | `--gallery-item-action-padding` | `6px` | padding | Padding of the action buttons. |
144
+ | `--gallery-item-action-border-radius` | `8px` | border-radius | Corner rounding of the action buttons. |
145
+ | `--gallery-item-action-icon-size` | `16px` | width / height | Size of the built-in icons inside the action buttons (bridged to the inner `Icon`'s `--icon-width`/`--icon-height`; custom icon snippets size themselves). |
146
+ | `--gallery-lightbox-z-index` | `15` | z-index | Stacking order of the lightbox overlay. |
147
+ | `--gallery-lightbox-background` | `#000000e6` | background | Backdrop color of the lightbox overlay. |
148
+ | `--gallery-lightbox-image-width` | `85vw` | width | Width of the lightbox image box (image letterboxes inside via object-fit). |
149
+ | `--gallery-lightbox-image-height` | `75vh` | height | Height of the lightbox image box. |
150
+ | `--gallery-lightbox-image-fit` | `contain` | object-fit | Object fit of the lightbox image. |
151
+ | `--gallery-lightbox-image-border-radius` | `0px` | border-radius | Corner rounding of the lightbox image. |
152
+ | `--gallery-lightbox-caption-gap` | `12px` | gap | Gap between the lightbox image and its caption. |
153
+ | `--gallery-lightbox-caption-color` | `#ffffff` | color | Text color of the lightbox caption. |
154
+ | `--gallery-lightbox-caption-font-size` | `14px` | font-size | Font size of the lightbox caption. |
155
+ | `--gallery-lightbox-caption-font-family` | `-` | font-family | Font family of the lightbox caption. |
156
+ | `--gallery-lightbox-counter-bottom` | `16px` | bottom | Distance of the position counter from the bottom of the lightbox. |
157
+ | `--gallery-lightbox-counter-color` | `#ffffff` | color | Text color of the position counter. |
158
+ | `--gallery-lightbox-counter-font-size` | `13px` | font-size | Font size of the position counter. |
159
+ | `--gallery-lightbox-counter-font-family` | `-` | font-family | Font family of the position counter. |
160
+ | `--gallery-lightbox-close-top` | `16px` | top | Distance of the close button from the top of the lightbox. |
161
+ | `--gallery-lightbox-close-right` | `16px` | right | Distance of the close button from the right of the lightbox. |
162
+ | `--gallery-lightbox-nav-inset` | `16px` | left / right | Distance of the previous/next buttons from the lightbox edges. |
163
+ | `--gallery-lightbox-control-background` | `transparent` | background-color | Background of the lightbox close and navigation buttons. |
164
+ | `--gallery-lightbox-control-color` | `#ffffff` | color | Icon color of the lightbox close and navigation buttons. |
165
+ | `--gallery-lightbox-control-hover-background` | `#ffffff1f` | background | Hover background of the lightbox close and navigation buttons. |
166
+ | `--gallery-lightbox-control-padding` | `8px` | padding | Padding of the lightbox close and navigation buttons. |
167
+ | `--gallery-lightbox-control-border-radius` | `50%` | border-radius | Corner rounding of the lightbox close and navigation buttons. |
168
+ | `--gallery-lightbox-control-icon-size` | `24px` | width / height | Size of the built-in icons inside the lightbox close and navigation buttons (bridged to the inner `Icon`'s `--icon-width`/`--icon-height`; custom icon snippets size themselves). |
151
169
 
152
170
  ## Type Reference
153
171
 
@@ -165,6 +183,10 @@ type GalleryImage = {
165
183
  };
166
184
  ```
167
185
 
186
+ `caption` is shown in the lightbox (when `showCaption` is true) and as the list-row subtitle in `view="list"`. It has no built-in meaning in `view="grid"` — read it (or any other field on your own `GalleryImage`-shaped data) yourself inside a `itemFooter` snippet if you need it there.
187
+
188
+ In `view="grid"`, Gallery only lays out and clips the image itself, inside an internal `.grid-image-wrap` element sized by `--gallery-item-aspect-ratio`/`--gallery-item-image-fit`. Content rendered by `itemFooter` sits below that wrap, inside the same bordered tile (see `--gallery-item-border`/`--gallery-item-border-radius` above) — bring your own class names and CSS for its layout and typography.
189
+
168
190
  ### GalleryView
169
191
 
170
192
  ```typescript
@@ -179,4 +201,4 @@ Tag: `<pui-gallery>`
179
201
  <pui-gallery view="list" loop show-counter active-index="2"></pui-gallery>
180
202
  ```
181
203
 
182
- > **Note:** The `images` prop is an array — set it via JavaScript property, as are the `onimageclick`/`oneditclick`/`ondeleteclick` handlers. Icon snippet props (`previousIcon`, `nextIcon`, `closeIcon`, `editIcon`, `deleteIcon`) are not attribute-serializable; custom-element consumers fall back to the built-in icon assets.
204
+ > **Note:** The `images` prop is an array — set it via JavaScript property, as are the `onimageclick`/`oneditclick`/`ondeleteclick` handlers. Icon snippet props (`previousIcon`, `nextIcon`, `closeIcon`, `editIcon`, `deleteIcon`) and `itemFooter` are not attribute-serializable; custom-element consumers fall back to the built-in icon assets, and `itemFooter` has no effect (grid tiles render as bare images).
@@ -69,6 +69,7 @@ Override these custom properties to theme the component.
69
69
  | `--modal-content-overflow` | `auto` | overflow | Overflow behavior of the modal content panel. |
70
70
  | `--modal-content-border-top` | `-` | border-top | Top border of the modal content panel. |
71
71
  | `--modal-display` | `flex` | display | Display property of the scrollable content area. |
72
+ | `--modal-flex-direction` | `row` | flex-direction | Flex direction of the scrollable content area (when `--modal-display` is `flex`). |
72
73
  | `--modal-overflow-y` | `scroll` | overflow-y | Vertical overflow behavior of the content area. |
73
74
  | `--modal-scrollbar-width` | `none` | scrollbar-width | Scrollbar width for the content area (set 'none' to hide). |
74
75
  | `--modal-center-justify-content` | `center` | justify-content | Vertical positioning of the modal when align='center'. |
@@ -37,7 +37,7 @@
37
37
  },
38
38
  {
39
39
  "name": "Chat",
40
- "description": "A full chat surface composing ChatHeader, ChatMessageList, ChatSuggestions, ChatToolStatus, and ChatComposer. Fully controlled (pass `messages`, handle `onsend`) with no baked-in transport. Opt-in features: header image, stop-generation, voice mic, file attachments, prompt suggestions, smart autoscroll, and per-message copy/retry/feedback. Pair with the decoupled `ChatController` runes class — message state, streaming, typewriter reveal, retry, and session threading — which delegates the network call to a pluggable `ChatTransport` (adapt SSE, WebSocket, or polling). Markdown is not bundled — pass pre-sanitized HTML on a message's `html` field."
40
+ "description": "A full chat surface composing ChatHeader, ChatMessageList, ChatSuggestions, ChatToolStatus, and ChatComposer. Fully controlled (pass `messages`, handle `onsend`) with no baked-in transport. Opt-in features: header image, stop-generation, voice mic, file attachments, prompt suggestions, smart autoscroll, and per-message copy/retry/feedback. Render your own UI below any bubble with the `messageAttachments` snippet. Pair with the decoupled `ChatController` runes class — message state, streaming, typewriter reveal, retry, and session threading — which delegates the network call to a pluggable `ChatTransport` (adapt SSE, WebSocket, or polling). Markdown is not bundled — pass pre-sanitized HTML on a message's `html` field."
41
41
  },
42
42
  {
43
43
  "name": "ChatBubble",
@@ -57,7 +57,7 @@
57
57
  },
58
58
  {
59
59
  "name": "ChatMessageList",
60
- "description": "A scrollable conversation container with smart auto-scroll: it sticks to the bottom only while you're already near it, and shows a jump-to-latest button when you've scrolled up. Renders each message with ChatMessage by default or a custom `message` snippet, shows an `empty` snippet when there are no messages, and forwards opt-in message actions (allowCopy, onretry, onfeedback). Uses a Svelte action (no effects), respecting reduced-motion."
60
+ "description": "A scrollable conversation container with smart auto-scroll: it sticks to the bottom only while you're already near it, and shows a jump-to-latest button when you've scrolled up. Renders each message with ChatMessage by default, adds your own UI below any bubble via the per-message `messageAttachments` snippet, or replaces a message entirely with the `message` snippet, shows an `empty` snippet when there are no messages, and forwards opt-in message actions (allowCopy, onretry, onfeedback). Uses a Svelte action (no effects), respecting reduced-motion."
61
61
  },
62
62
  {
63
63
  "name": "ChatSuggestions",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polymorph-ui-components-mcp",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "MCP server for polymorph-ui-components - provides structured access to component props, CSS variables, and usage patterns",
5
5
  "type": "module",
6
6
  "repository": {