@knpkv/rly 0.13.0 → 0.15.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.
Files changed (51) hide show
  1. package/README.md +73 -1
  2. package/dist/{Dialog-B9Ub_gMT.js → Dialog-CU66FqWD.js} +325 -257
  3. package/dist/Dialog-CU66FqWD.js.map +1 -0
  4. package/dist/{PortalProvider-CN_81Fy3.js → PortalProvider-op07u8na.js} +20 -18
  5. package/dist/PortalProvider-op07u8na.js.map +1 -0
  6. package/dist/assets/relay-mark.svg +9 -0
  7. package/dist/components.css +1 -1
  8. package/dist/dts/foundations/Icon.d.ts +1 -1
  9. package/dist/dts/foundations/Icon.d.ts.map +1 -1
  10. package/dist/dts/internal/composedFocus.d.ts +11 -0
  11. package/dist/dts/internal/composedFocus.d.ts.map +1 -0
  12. package/dist/dts/internal/relaySummon.d.ts +50 -0
  13. package/dist/dts/internal/relaySummon.d.ts.map +1 -0
  14. package/dist/dts/patterns/Region.d.ts +2 -2
  15. package/dist/dts/patterns/Region.d.ts.map +1 -1
  16. package/dist/dts/patterns/RelayComposer.d.ts +65 -0
  17. package/dist/dts/patterns/RelayComposer.d.ts.map +1 -0
  18. package/dist/dts/patterns/RelayDock.d.ts.map +1 -1
  19. package/dist/dts/patterns/RelayLauncher.d.ts +67 -0
  20. package/dist/dts/patterns/RelayLauncher.d.ts.map +1 -0
  21. package/dist/dts/patterns/RelayMark.d.ts +35 -0
  22. package/dist/dts/patterns/RelayMark.d.ts.map +1 -0
  23. package/dist/dts/patterns/RelayPanel.d.ts +91 -0
  24. package/dist/dts/patterns/RelayPanel.d.ts.map +1 -0
  25. package/dist/dts/patterns/index.d.ts +8 -0
  26. package/dist/dts/patterns/index.d.ts.map +1 -1
  27. package/dist/dts/tokens/fonts.d.ts +13 -0
  28. package/dist/dts/tokens/fonts.d.ts.map +1 -0
  29. package/dist/dts/tokens/index.d.ts +2 -0
  30. package/dist/dts/tokens/index.d.ts.map +1 -1
  31. package/dist/fonts.css +83 -2
  32. package/dist/foundations/index.js +1 -1
  33. package/dist/generated-tokens.css +2 -2
  34. package/dist/index.js +6 -6
  35. package/dist/patterns/index.js +2 -2
  36. package/dist/{patterns-DPd5YlSW.js → patterns-CDBnXTUD.js} +1258 -756
  37. package/dist/patterns-CDBnXTUD.js.map +1 -0
  38. package/dist/primitives/index.js +3 -3
  39. package/dist/{primitives-Bd6WhE78.js → primitives-DgQybTyq.js} +254 -322
  40. package/dist/primitives-DgQybTyq.js.map +1 -0
  41. package/dist/tokens/index.js +2 -2
  42. package/dist/{tokens-B075JP3Z.js → tokens-Cf0jXIRg.js} +14 -8
  43. package/dist/tokens-Cf0jXIRg.js.map +1 -0
  44. package/package.json +2 -1
  45. package/registry/components.json +373 -0
  46. package/registry/search.json +88 -0
  47. package/dist/Dialog-B9Ub_gMT.js.map +0 -1
  48. package/dist/PortalProvider-CN_81Fy3.js.map +0 -1
  49. package/dist/patterns-DPd5YlSW.js.map +0 -1
  50. package/dist/primitives-Bd6WhE78.js.map +0 -1
  51. package/dist/tokens-B075JP3Z.js.map +0 -1
package/README.md CHANGED
@@ -31,7 +31,10 @@ Import the global layers once at the application boundary:
31
31
  @import "@knpkv/rly/styles.css";
32
32
  ```
33
33
 
34
- The stylesheet contains self-hosted Geist and Geist Mono variable fonts,
34
+ The stylesheet contains self-hosted Geist and Geist Mono variable fonts (with
35
+ `font-display: optional`: preload each file in `RLY_FONT_FACES` from your own
36
+ origin with `crossorigin`, and Geist renders from first paint; a late face keeps
37
+ the metric-matched fallback for that page view rather than swapping),
35
38
  semantic `light-dark()` color pairs, typography, spacing, shape, motion, a
36
39
  scoped reset, and base styles. Set `data-theme="light|dark|system"` on the rly
37
40
  root; system is the default. Forced colors and reduced motion are handled
@@ -448,6 +451,75 @@ target, expected revision, impact, and evidence beside a named human reviewer.
448
451
  Its owned authorization button stays disabled until the controlled exact-action
449
452
  confirmation is checked, and terminal outcomes remain visible after review.
450
453
 
454
+ `RelayMark` is Relay's mark, the baton: two open hooks with a stroke passed between
455
+ them. The bare mark is drawn in the current colour, so it follows its host's text in
456
+ every theme and in forced colours; sizes are 16, 20 (default), 24 and 32px, and 16px
457
+ stays legible in one colour. `RelayMark.Tile` sets it on the agent colour (20, 24 or
458
+ 32px); in forced colours the tile becomes an outline in its context's colour
459
+ (LinkText in a link, ButtonText in a button). Both are decorative
460
+ unless given a `label`. The same mark on its tile ships as `@knpkv/rly/relay-mark.svg`
461
+ for a host's favicon.
462
+
463
+ `RelayLauncher` is the header button that opens and closes Relay: the mark, a label
464
+ ("Relay" unless the host names it) and the Ctrl/⌘+J hint. It sits in the host's header
465
+ like any other control, never fixed over the page. `expanded` drives `aria-expanded`,
466
+ and `aria-keyshortcuts` names the shortcut while the visible hint stays hidden from
467
+ assistive technology. `shortcut` is required: pass `useRelayShortcut()` (Ctrl/⌘+J for
468
+ the platform) only when the host binds that key and prevents the browser's own Ctrl+J,
469
+ or `null` where it binds none, such as a live terminal that keeps its chords.
470
+ The hint hides at 40rem and below, and the button is 32px tall, 44px for a coarse pointer.
471
+
472
+ `RelayComposer` is Relay's message box: it grows with its text up to 12 lines or 40%
473
+ of the viewport, Enter adds a line and Ctrl/⌘+Enter sends (said beside Send), and an
474
+ IME composition never sends. Context refs are removable chips. One `preset` slot holds
475
+ the run preset. Stop appears only when the host passes `onStop`. While `busyReason` is
476
+ set, Send stays focusable and announces why it is unavailable. `useRelayDraft(objectKey, { newRequestId })`
477
+ keeps the draft per object (the JSON ObjectRef) for the page, so closing, reopening or
478
+ resizing Relay keeps it and one object's draft never sends as another's; pass
479
+ `storage: () => sessionStorage` to survive a reload (never localStorage). Its
480
+ `submission()` reuses one request id until the text changes, so a retry after an
481
+ uncertain outcome is deduplicated; call `accepted(requestId)` once the server accepts
482
+ that request, which clears the draft unless the user has typed since.
483
+
484
+ `RelayPanel` is Relay's frame: header (mark, title, exact scope with the revision in
485
+ mono, an optional pin, options, close), tabs whose counts are part of their names, a
486
+ freshness line, a body, and a footer for the composer. Only the body scrolls, so the
487
+ composer never leaves the screen. `overlay` floats over the right of the page with
488
+ no backdrop and no focus trap; render it right after the launcher so Tab order
489
+ follows. `pinned` is a sticky column for the host's grid, and `fullscreen` is a modal
490
+ dialog with the page inert. Escape and the close button call `onClose` and return
491
+ focus to the launcher; closing hides Relay in every presentation, and whether it was
492
+ pinned stays the host's remembered preference. `useRelayPresentation({ pinned,
493
+ minHostWidth })` picks the presentation: full screen at 640 CSS px and narrower,
494
+ pinned only when the user pinned it at 1440 and up with the host's minimum beside the
495
+ 440px column, otherwise the overlay. Hosts set `--rly-relay-panel-offset` to their
496
+ sticky header's height and `--app-bottom-inset` to any bar docked at the bottom.
497
+ Full screen portals through `PortalProvider`, so render Relay inside one, and set
498
+ `interactive-widget=resizes-content` in the viewport meta so the full-screen footer
499
+ stays above a phone's on-screen keyboard.
500
+
501
+ `useRelaySummon` binds that shortcut. From the page it opens Relay and focuses the composer (or, if
502
+ Relay is already open, moves focus to the composer); from inside Relay it takes focus back to where it
503
+ came from, and Relay stays open. Full screen, it closes Relay. Escape closes Relay when focus is inside
504
+ it or Relay is full screen, and returns focus. Only the exact chord is handled and prevented, so Ctrl+K,
505
+ `?`, g-sequences and Alt keys reach the host. On a non-Latin layout the physical J key works; a Latin
506
+ layout uses the J the user sees. Escape is left to an IME composition and to a dialog, listbox or menu
507
+ open inside or opened from Relay, including inside shadow roots. When the element Relay came from is
508
+ gone, focus returns to the `launcher`; after a close, focus returns once Relay has actually closed.
509
+ Attach the returned `regionRef` to Relay's region and `composerRef` to the composer, which is focused
510
+ as soon as it mounts. The hook follows Relay into another document (an iframe portal). Pass the same
511
+ `shortcut` the launcher advertises, or `null` while the host's own surface owns the key; Escape inside
512
+ Relay works either way.
513
+
514
+ ```tsx
515
+ import { RelayLauncher, useRelayShortcut, useRelaySummon } from "@knpkv/rly/patterns"
516
+
517
+ ;const shortcut = useRelayShortcut()
518
+ const { composerRef, regionRef } = useRelaySummon({ fullscreen: false, launcher, onOpenChange: setOpen, open, shortcut })
519
+
520
+ <RelayLauncher expanded={open} onClick={() => setOpen((value) => !value)} ref={launcher} shortcut={shortcut} />
521
+ ```
522
+
451
523
  `RelayDock` is the shared product frame for one adapter-owned Relay thread. It
452
524
  starts collapsed, keeps context plus profile and model selection visible above
453
525
  the scrolling thread, and accepts explicit ready, loading, empty, error, and