inline-chat-kit 0.59.2 → 0.61.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/theming.md CHANGED
@@ -245,6 +245,204 @@ paper and one acid yellow. Six tokens turn that into a palette:
245
245
  The markdown gaps are in `em` rather than pixels, so they scale with whatever
246
246
  size the answer is set at instead of drifting away from it.
247
247
 
248
+ ## Buttons
249
+
250
+ Every button the kit draws is one of five variants, and each variant is painted
251
+ from its own `--ick-btn-<variant>-*` tokens — so a host's primary is set once,
252
+ in its own stylesheet, rather than matched by a hashed class name:
253
+
254
+ ```css
255
+ :root {
256
+ --ick-btn-radius: 10px;
257
+ --ick-btn-primary-bg: #1d4ed8;
258
+ --ick-btn-primary-ink: #fff;
259
+ --ick-btn-primary-border: transparent;
260
+ --ick-btn-primary-shadow: none;
261
+ --ick-btn-primary-shadow-hover: 0 2px 6px rgb(29 78 216 / 0.35);
262
+ --ick-btn-primary-shadow-press: none;
263
+ }
264
+ ```
265
+
266
+ | Variant | Tokens |
267
+ | --- | --- |
268
+ | `primary` | `-bg` `-ink` `-border` `-shadow` `-shadow-hover` `-shadow-press` |
269
+ | `secondary` | `-bg` `-ink` `-bg-hover` `-border-hover` `-shadow-hover` `-shadow-press` |
270
+ | `outline` | `-bg` `-ink` `-border` `-bg-hover` `-border-hover` `-bg-press` |
271
+ | `ghost` | `-ink` `-ink-hover` `-bg-hover` `-bg-press` |
272
+ | `glass` | `-bg` `-ink` `-bg-hover` `-ink-hover` `-bg-press` — its rim and shadows are the glass tokens |
273
+
274
+ A state that does not change a property by default has no token for it, and
275
+ keeps the resting value: set `--ick-btn-primary-bg` and the hover is that
276
+ colour too, rather than turning back into glass.
277
+
278
+ **Every button also says what it is for**, in `data-ick-role`, and what it is
279
+ in `data-ick-variant`. Set the same tokens on a role and only that role
280
+ changes:
281
+
282
+ ```css
283
+ [data-ick-role="stop"] { --ick-btn-primary-bg: #dc2626; }
284
+ ```
285
+
286
+ | Role | Where |
287
+ | --- | --- |
288
+ | `send`, `stop`, `save` | The composer's glyph — three roles, not one button with three labels |
289
+ | `add`, `dictate`, `cancel-edit`, `add-close` | The composer's other controls |
290
+ | `read-more`, `message-action` | On a sent message (`data-ick-action`: `copy`, `edit`) |
291
+ | `answer-action` | Under an answer (`data-ick-action`: `copy`, `regenerate`, `up`, `down`) |
292
+ | `suggestion` | The openers in an empty conversation |
293
+ | `back`, `header-action`, `header-more`, `header-menu-item` | The header; an action carries its `id` as `data-ick-action` |
294
+ | `approval-once`, `approval-always`, `approval-deny` | An approval |
295
+ | `question-next` | A question card |
296
+ | `highlight-action` | The highlight menu (`data-ick-action`: `reply`, `remove`) |
297
+ | `thread-save`, `thread-close` | A thread |
298
+ | `pane-expand`, `pane-close` | The artifact pane |
299
+ | `remove-attachment` | An attachment's X |
300
+
301
+ A header action can be drawn as a primary with `variant: "primary"` on it.
302
+
303
+ **Bigger buttons on a phone.** Heights are `--ick-control-xs` … `-xl`. On a
304
+ coarse pointer the kit already raises them a step and gives every control an
305
+ invisible 44px hit area, so a 38px header button already answers to a 44px
306
+ thumb. A product that wants the buttons themselves drawn at 44 says so:
307
+
308
+ ```css
309
+ @media (pointer: coarse) {
310
+ :root { --ick-control-m: 44px; }
311
+ }
312
+ ```
313
+
314
+ The composer's own controls — the send / stop / save glyph, the "+", the
315
+ microphone — are `--ick-composer-control`, which is `--ick-control-s`: 28 on a
316
+ pointer, 32 on a touch screen. Its own token so the composer's row can move
317
+ without every other `s` button moving with it:
318
+
319
+ ```css
320
+ @media (pointer: coarse) {
321
+ :root { --ick-composer-control: var(--ick-control-l); }
322
+ }
323
+ ```
324
+
325
+ ## Bring your own button
326
+
327
+ Three levels, each one further than the last. Stop at the first that is
328
+ enough.
329
+
330
+ **1. Tokens.** The `--ick-btn-<variant>-*` tokens above, `--ick-btn-radius`,
331
+ `--ick-btn-weight` and the `--ick-control-*` heights. Every button the kit
332
+ draws reads them, the composer's glyph included. Most hosts need nothing else.
333
+
334
+ **2. Per role, in CSS.** The same tokens on a `[data-ick-role]`, or your own
335
+ rules on it — the role table above is what to select on. A role is what the
336
+ button is for, so it survives a translation; a class name is hashed and a
337
+ label is not yours to match on.
338
+
339
+ **3. Your component.** Give `ChatExperience` your button and it draws it in
340
+ place of its own, everywhere but one place:
341
+
342
+ ```tsx
343
+ <ChatExperience components={{ Button: MyButton }} onSend={send} />
344
+ ```
345
+
346
+ Pieces assembled by hand — `ChatTurnRow`, `ChatHeader`, `Approval`,
347
+ `ArtifactPane` — take it from `ComponentsProvider`, as they take words from
348
+ `LabelsProvider`:
349
+
350
+ ```tsx
351
+ <ComponentsProvider components={{ Button: MyButton }}>
352
+ <ChatHeader title="Chat" actions={actions} />
353
+ {turns.map((turn) => <ChatTurnRow key={turn.id} turn={turn} />)}
354
+ </ComponentsProvider>
355
+ ```
356
+
357
+ Declare `MyButton` outside a render. A component made inside one is a new
358
+ component every time, and every button in the chat remounts with it.
359
+
360
+ ### Who owns what
361
+
362
+ The kit owns **layout and behaviour**: the box each button sits in, its height
363
+ from `--ick-control-*` (and on an icon-only button its width), where it goes,
364
+ how it arrives and leaves, the 44px it answers to under a finger, focus moving
365
+ to it, and what pressing it does. Your button **paints**: colour, border,
366
+ radius, font, shadow, what hover and press look like, its icons, and the focus
367
+ ring.
368
+
369
+ So your button fills the box it is given — the kit sets its height over yours,
370
+ a `h-9` included, and its width when it is an icon on its own; its padding,
371
+ radius and everything it paints are left alone — and it never animates or
372
+ positions itself.
373
+
374
+ ### The contract
375
+
376
+ Your component is called with `KitButtonProps`:
377
+
378
+ | Prop | |
379
+ | --- | --- |
380
+ | `kitRole` | What it is for — a role from the table above. Switch on it to pick your own variant |
381
+ | `variant` | What the kit would have drawn: `primary`, `secondary`, `outline`, `ghost`, `glass`. A hint |
382
+ | `size` | `xs` … `xl`: the step of `--ick-control-*` the box already is |
383
+ | `shape` | `square` (an icon on its own), `pill` (a chip: an opener, "Read more", a highlight's action) or `default` (a text button among others). A hint |
384
+ | `icon`, `iconRight`, `children` | The content. An icon-only button is named by its `aria-label` |
385
+ | `disabled`, `loading`, `pressed` | `loading` also sets `disabled` and `aria-busy`; `pressed` also sets `aria-pressed` |
386
+ | `type` | Always `"button"` |
387
+ | `onClick` | And every other handler the kit needs |
388
+ | `aria-*`, `title`, `role`, `tabIndex` | A menu's items arrive with `role="menuitem"` and a roving `tabIndex` |
389
+ | `data-ick-role`, `data-ick-variant`, `data-ick-action` | So the CSS above still reaches your button |
390
+ | `ref` | The `<button>` itself. The kit focuses it and anchors the header's menu to it |
391
+
392
+ Three rules, and the words in the first column of the table are the kit's,
393
+ not attributes — take them out before spreading the rest:
394
+
395
+ 1. **Forward the ref** — `forwardRef`, or in React 19 pass `ref` through.
396
+ 2. **Render a `<button>`.** The keyboard behaviour is the button's.
397
+ 3. **Spread what you do not use** onto it: the `aria-*`, `data-*`, `role`,
398
+ `tabIndex`, `title` and handlers.
399
+
400
+ ```tsx
401
+ const MyButton = forwardRef<HTMLButtonElement, KitButtonProps>(function MyButton(
402
+ { kitRole, variant, size, shape, icon, iconRight, loading, pressed, children, ...rest },
403
+ ref
404
+ ) {
405
+ const look = kitRole === "approval-once" ? "default" : variant === "primary" ? "secondary" : "ghost";
406
+ return (
407
+ <Button ref={ref} variant={look} size={shape === "square" ? "icon" : "sm"} {...rest}>
408
+ {loading ? <Spinner /> : icon}
409
+ {children}
410
+ {iconRight}
411
+ </Button>
412
+ );
413
+ });
414
+ ```
415
+
416
+ In development the kit checks each role's button once and says so in the
417
+ console when it does not forward its ref, is not a `<button>`, drops the
418
+ `aria-*` or `data-ick-*` it was given, or looks no different with keyboard
419
+ focus. One warning per role; none in a production build.
420
+
421
+ ### The one exception: the send glyph
422
+
423
+ The composer's send / stop / save button is always the kit's. It is one button
424
+ whose glyph morphs between the three as the composer changes state, and that
425
+ animation lives inside the button — a host component would have to take it on
426
+ to stand in for it. It follows the tokens instead: `--ick-btn-radius`,
427
+ `--ick-btn-primary-*` (on `[data-ick-role="send"]`, `"stop"` or `"save"` to
428
+ tell them apart) and `--ick-composer-control`.
429
+
430
+ Two more stay the kit's for a different reason: the header's back control and
431
+ a header action given an `href` are links, not buttons, and draw as `<a>`.
432
+
433
+ ### One radius
434
+
435
+ Set `--ick-btn-radius` to your buttons' corner even when you bring your own
436
+ button. It is how the kit's own glyph matches yours, and how the surfaces
437
+ around buttons match them: the composer's corner is the button's plus the
438
+ composer's 8px padding — concentric — up to its own ceiling of
439
+ `--ick-radius-xl`. A 6px button sits in a 14px composer; the default pill sits
440
+ in the 24px composer it always has.
441
+
442
+ ```css
443
+ :root { --ick-btn-radius: 6px; }
444
+ ```
445
+
248
446
  ## Motion
249
447
 
250
448
  `--ick-ease`, `--ick-ease-overshoot`, and the `--ick-duration-*` scale. The kit