@hachej/boring-ui-kit 0.2.4 → 0.3.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/r/registry.json CHANGED
@@ -107,8 +107,8 @@
107
107
  "lucide-react@^1.51.0"
108
108
  ],
109
109
  "registryDependencies": [
110
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/theme.json",
111
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json"
110
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/theme.json",
111
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json"
112
112
  ],
113
113
  "files": [
114
114
  {
@@ -129,8 +129,8 @@
129
129
  "title": "Markdown editor",
130
130
  "description": "A host-owned styled wrapper over the concrete borrowed Markdown controller.",
131
131
  "dependencies": [
132
- "@hachej/boring-ui-kit@^0.2.4",
133
- "@hachej/boring-files@^0.2.4",
132
+ "@hachej/boring-ui-kit@^0.3.0",
133
+ "@hachej/boring-files@^0.3.0",
134
134
  "react@^19.0.0",
135
135
  "react-dom@^19.0.0",
136
136
  "marked@^17.0.6",
@@ -343,8 +343,8 @@
343
343
  "title": "HTML source and passive preview",
344
344
  "description": "Exact HTML source editing with a reconstructed passive preview and borrowed controller. Browser security qualification remains separate.",
345
345
  "dependencies": [
346
- "@hachej/boring-ui-kit@^0.2.4",
347
- "@hachej/boring-files@^0.2.4",
346
+ "@hachej/boring-ui-kit@^0.3.0",
347
+ "@hachej/boring-files@^0.3.0",
348
348
  "react@^19.0.0",
349
349
  "react-dom@^19.0.0"
350
350
  ],
@@ -435,23 +435,23 @@
435
435
  "title": "Pi chat",
436
436
  "description": "A complete Tailwind chat over the borrowed native chat controller: composer, messages, one collapsible activity block per turn (tool calls and reasoning), message queue, history, a human-in-the-loop question card, an Approve / Deny card for host tools wrapped with requireApproval optional artifact cards that open generated content in the host's panel, and feedback cards for the opt-in feedback tool (lists, and Show offers that the host page resolves). Chat only: no layout. Owned, editable source; no AI SDK. The optional pi-ambient and pi-workspace blocks build on it.",
437
437
  "dependencies": [
438
- "@hachej/boring-ui-kit@^0.2.4",
439
- "@hachej/boring-files@^0.2.4",
438
+ "@hachej/boring-ui-kit@^0.3.0",
439
+ "@hachej/boring-files@^0.3.0",
440
440
  "react@^19.0.0",
441
441
  "react-dom@^19.0.0",
442
442
  "marked@^17.0.6",
443
443
  "entities@^8.1.0",
444
- "@earendil-works/pi-durable@~1.1.0",
445
- "@earendil-works/chord@~1.1.0",
446
- "@earendil-works/pi-ai@~1.1.0",
444
+ "@earendil-works/pi-durable@~1.2.0",
445
+ "@earendil-works/chord@~1.2.0",
446
+ "@earendil-works/pi-ai@~1.2.0",
447
447
  "@modelcontextprotocol/sdk@^1.32.0",
448
448
  "lucide-react@^1.51.0",
449
449
  "use-stick-to-bottom@^1.1.6"
450
450
  ],
451
451
  "registryDependencies": [
452
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/theme.json",
453
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json",
454
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/button.json"
452
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/theme.json",
453
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json",
454
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/button.json"
455
455
  ],
456
456
  "files": [
457
457
  {
@@ -574,6 +574,11 @@
574
574
  "type": "registry:hook",
575
575
  "target": "components/pi-chat/use-remote-chat.ts"
576
576
  },
577
+ {
578
+ "path": "registry/pi-chat/use-chat-draft.ts",
579
+ "type": "registry:hook",
580
+ "target": "components/pi-chat/use-chat-draft.ts"
581
+ },
577
582
  {
578
583
  "path": "registry/pi-chat/labels.ts",
579
584
  "type": "registry:lib",
@@ -671,18 +676,18 @@
671
676
  "title": "Pi ambient agent",
672
677
  "description": "AmbientChat, a compact floating agent bar that grows into a chat window over an existing page, and AgentNotifications, toasts for finished, failed and waiting tasks (with the one guarded browser Notification helper). A block over the pi-chat item; its in-window artifact panel uses the pi-workspace layout.",
673
678
  "dependencies": [
674
- "@hachej/boring-ui-kit@^0.2.4",
679
+ "@hachej/boring-ui-kit@^0.3.0",
675
680
  "react@^19.0.0",
676
681
  "react-dom@^19.0.0",
677
- "@earendil-works/pi-durable@~1.1.0",
678
- "@earendil-works/pi-ai@~1.1.0",
682
+ "@earendil-works/pi-durable@~1.2.0",
683
+ "@earendil-works/pi-ai@~1.2.0",
679
684
  "lucide-react@^1.51.0"
680
685
  ],
681
686
  "registryDependencies": [
682
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-chat.json",
683
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-workspace.json",
684
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json",
685
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/button.json"
687
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-chat.json",
688
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-workspace.json",
689
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json",
690
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/button.json"
686
691
  ],
687
692
  "files": [
688
693
  {
@@ -712,8 +717,8 @@
712
717
  "react-dom@^19.0.0"
713
718
  ],
714
719
  "registryDependencies": [
715
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-chat.json",
716
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json"
720
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-chat.json",
721
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json"
717
722
  ],
718
723
  "files": [
719
724
  {
@@ -734,19 +739,19 @@
734
739
  "title": "Pi agent app",
735
740
  "description": "AgentWorkspace: a whole agent page in one component. Left: the sessions pane (search, New, rename, archive, delete; collapsible, a drawer on a narrow screen). Center: PiChat. Right: the artifact viewers (artifact panel with versions, file viewer, auto-open of new artifacts) in the ArtifactWorkspace panel, a full-screen sheet on a phone. Props are data and callbacks; hooks for the conversations handler (useConversations), the chat transport (useRemoteChat) and saved resources (useSaved).",
736
741
  "dependencies": [
737
- "@hachej/boring-ui-kit@^0.2.4",
738
- "@hachej/boring-files@^0.2.4",
742
+ "@hachej/boring-ui-kit@^0.3.0",
743
+ "@hachej/boring-files@^0.3.0",
739
744
  "react@^19.0.0",
740
745
  "react-dom@^19.0.0",
741
746
  "lucide-react@^1.51.0",
742
747
  "radix-ui@^1.8.0"
743
748
  ],
744
749
  "registryDependencies": [
745
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-chat.json",
746
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-workspace.json",
747
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/viewers.json",
748
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json",
749
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/button.json"
750
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-chat.json",
751
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-workspace.json",
752
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/viewers.json",
753
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json",
754
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/button.json"
750
755
  ],
751
756
  "files": [
752
757
  {
@@ -808,27 +813,32 @@
808
813
  "path": "registry/pi-app/app-labels-fr.ts",
809
814
  "type": "registry:lib",
810
815
  "target": "components/pi-app/app-labels-fr.ts"
816
+ },
817
+ {
818
+ "path": "registry/pi-app/use-revision-attachments.ts",
819
+ "type": "registry:hook",
820
+ "target": "components/pi-app/use-revision-attachments.ts"
811
821
  }
812
822
  ]
813
823
  },
814
824
  {
815
825
  "name": "app-shell",
816
826
  "type": "registry:block",
817
- "title": "App shell: screen layout and agent layer",
818
- "description": "AppShell layout \"screen\": one screen at a time, every screen kept mounted. On a phone bottom tabs (at most four; more give three plus a « Plus » sheet) and an avatar button that opens the account sheet; on a wide screen the shadcn sidebar (icon rail, NavUser). One header per screen through useScreenHeader (title, subtitle, back, up to two actions, the rest behind « … »). The account menu holds « Améliorer l'app » (the improve agent), the app's own entries and sign out. AppSheet is the one bottom sheet (one open at a time, Back closes it). It mounts the AgentLayer: one agent's PiChat above the app (phone: a drawer with peek, half and full snap points; wide: a right panel), the improve agent in the same layer, optional push-to-talk and point mode. Also useAgentContext and readAgentContext (the screen on show travels as `context` with each submit) and useBackLayer, the one Back manager. Built on the shadcn drawer, sidebar, avatar and dropdown-menu of the host's own style (Base UI variants).",
827
+ "title": "App shell: layouts, list/detail and agent layer",
828
+ "description": "AppShell with three layouts. B \"workspace\" puts a ListDetail on a screen (phone: the list, then the detail as a stack step with Back; wide: a 20rem list and the detail side by side, sidebar as an icon rail). C \"chat\" wraps the app's own AgentWorkspace (untouched, passed as the nav item's render; install the pi-app item yourself) in the same sidebar, account menu and header; it takes no shell agent. A \"screen\": one screen at a time, every screen kept mounted. On a phone bottom tabs (at most four; more give three plus a « Plus » sheet) and an avatar button that opens the account sheet; on a wide screen the shadcn sidebar (icon rail, NavUser). One header per screen through useScreenHeader (title, subtitle, back, up to two actions, the rest behind « … »). The account menu holds « Améliorer l'app » (the improve agent), the app's own entries and sign out. AppSheet is the one bottom sheet (one open at a time, Back closes it). It mounts the AgentLayer: one agent's PiChat above the app (phone: a drawer with peek, half and full snap points; wide: a right panel), the improve agent in the same layer, optional push-to-talk and point mode. Also useAgentContext and readAgentContext (the screen on show travels as `context` with each submit) and useBackLayer, the one Back manager. Built on the shadcn drawer, sidebar, avatar and dropdown-menu of the host's own style (Base UI variants).",
819
829
  "dependencies": [
820
- "@hachej/boring-feedback@^0.2.4",
821
- "@hachej/boring-ui-kit@^0.2.4",
830
+ "@hachej/boring-feedback@^0.3.0",
831
+ "@hachej/boring-ui-kit@^0.3.0",
822
832
  "@base-ui/react@^1.8.0",
823
833
  "react@^19.0.0",
824
834
  "react-dom@^19.0.0",
825
835
  "lucide-react@^1.51.0"
826
836
  ],
827
837
  "registryDependencies": [
828
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-chat.json",
829
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/feedback.json",
830
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json",
831
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/button.json",
838
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-chat.json",
839
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/feedback.json",
840
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json",
841
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/button.json",
832
842
  "drawer",
833
843
  "sidebar",
834
844
  "avatar",
@@ -882,6 +892,11 @@
882
892
  "type": "registry:component",
883
893
  "target": "components/app-shell/app-shell.tsx"
884
894
  },
895
+ {
896
+ "path": "registry/app-shell/list-detail.tsx",
897
+ "type": "registry:component",
898
+ "target": "components/app-shell/list-detail.tsx"
899
+ },
885
900
  {
886
901
  "path": "registry/app-shell/header.tsx",
887
902
  "type": "registry:component",
@@ -920,8 +935,8 @@
920
935
  "title": "Viewers",
921
936
  "description": "The standard viewer top bar (title, status, viewer controls, Refresh, Share, Copy, Download, Open in new tab, Close, overflow menu) with Tailwind panes over it: the Markdown editor with a formatting toolbar and prose styling, the passive HTML preview and source editor, an image viewer with zoom and pan, and a PDF viewer. Owned, editable source over the borrowed controllers; no AI SDK.",
922
937
  "dependencies": [
923
- "@hachej/boring-ui-kit@^0.2.4",
924
- "@hachej/boring-files@^0.2.4",
938
+ "@hachej/boring-ui-kit@^0.3.0",
939
+ "@hachej/boring-files@^0.3.0",
925
940
  "react@^19.0.0",
926
941
  "react-dom@^19.0.0",
927
942
  "marked@^17.0.6",
@@ -940,9 +955,9 @@
940
955
  "lucide-react@^1.51.0"
941
956
  ],
942
957
  "registryDependencies": [
943
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/theme.json",
944
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json",
945
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/button.json"
958
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/theme.json",
959
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json",
960
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/button.json"
946
961
  ],
947
962
  "files": [
948
963
  {
@@ -1565,8 +1580,8 @@
1565
1580
  "lucide-react@^1.51.0"
1566
1581
  ],
1567
1582
  "registryDependencies": [
1568
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/theme.json",
1569
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json"
1583
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/theme.json",
1584
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json"
1570
1585
  ],
1571
1586
  "files": [
1572
1587
  {
@@ -1582,9 +1597,9 @@
1582
1597
  "title": "Feedback",
1583
1598
  "description": "Feedback from the chat composer: one Feedback button starts feedback mode on the application page (hover, click to pin a numbered note, hold ⌥ to use the app, optional voice), and one chip carries the notes to the next message. FeedbackBar, NoteBubble, FeedbackChip with its review, useComposerFeedback for the pi-chat composer, and PickerOverlay styles. Optional, not mounted by default: PointButton, AnnotateSheet, FeedbackList and FeedbackReport. Picking, masking, anchoring and placement stay in @hachej/boring-feedback/page and /ui, so restyling cannot weaken them.",
1584
1599
  "dependencies": [
1585
- "@hachej/boring-feedback@^0.2.4",
1586
- "@hachej/boring-ui-kit@^0.2.4",
1587
- "@hachej/boring-files@^0.2.4",
1600
+ "@hachej/boring-feedback@^0.3.0",
1601
+ "@hachej/boring-ui-kit@^0.3.0",
1602
+ "@hachej/boring-files@^0.3.0",
1588
1603
  "react@^19.0.0",
1589
1604
  "react-dom@^19.0.0",
1590
1605
  "lucide-react@^1.51.0"
@@ -2307,13 +2322,56 @@
2307
2322
  "color": "var(--boring-feedback-text)",
2308
2323
  "font": "inherit"
2309
2324
  },
2325
+ "[data-boring=\"feedback\"] .boring-feedback-pin-field": {
2326
+ "display": "grid"
2327
+ },
2328
+ "[data-boring=\"feedback\"] .boring-feedback-pin-field > *": {
2329
+ "grid-column": "1"
2330
+ },
2331
+ "[data-boring=\"feedback\"] .boring-feedback-pin-field > textarea, [data-boring=\"feedback\"] .boring-feedback-pin-field > .boring-feedback-pin-mic": {
2332
+ "grid-row": "1"
2333
+ },
2334
+ "[data-boring=\"feedback\"] .boring-feedback-pin-field > .boring-feedback-voice-problem": {
2335
+ "grid-row": "2"
2336
+ },
2337
+ "[data-boring=\"feedback\"] .boring-feedback-pin-field textarea": {
2338
+ "display": "block",
2339
+ "box-sizing": "border-box",
2340
+ "width": "100%",
2341
+ "padding-right": "3.25rem"
2342
+ },
2343
+ "[data-boring=\"feedback\"] .boring-feedback-pin-mic": {
2344
+ "justify-self": "end",
2345
+ "align-self": "end",
2346
+ "display": "inline-flex",
2347
+ "align-items": "center",
2348
+ "justify-content": "center",
2349
+ "width": "2.75rem",
2350
+ "height": "2.75rem",
2351
+ "padding": "0",
2352
+ "border": "0",
2353
+ "border-radius": "var(--boring-feedback-radius-md)",
2354
+ "background": "transparent",
2355
+ "color": "var(--boring-feedback-muted)",
2356
+ "cursor": "pointer"
2357
+ },
2358
+ "[data-boring=\"feedback\"] .boring-feedback-pin-mic:hover": {
2359
+ "color": "var(--boring-feedback-text, inherit)"
2360
+ },
2361
+ "[data-boring=\"feedback\"] .boring-feedback-pin-mic[aria-pressed=\"true\"]": {
2362
+ "color": "var(--boring-feedback-accent)"
2363
+ },
2364
+ "[data-boring=\"feedback\"] .boring-feedback-pin-mic:disabled": {
2365
+ "opacity": "0.6",
2366
+ "cursor": "default"
2367
+ },
2310
2368
  "[data-boring=\"feedback\"] .boring-feedback-bubble-actions": {
2311
2369
  "display": "flex",
2312
2370
  "flex-wrap": "wrap",
2313
2371
  "gap": "0.375rem"
2314
2372
  },
2315
2373
  "[data-boring=\"feedback\"] .boring-feedback-bubble-actions .boring-feedback-button": {
2316
- "min-height": "2rem",
2374
+ "min-height": "2.75rem",
2317
2375
  "padding": "0 0.625rem",
2318
2376
  "font-size": "var(--text-sm, 0.875rem)"
2319
2377
  },
@@ -2324,8 +2382,8 @@
2324
2382
  }
2325
2383
  },
2326
2384
  "registryDependencies": [
2327
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/pi-chat.json",
2328
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json"
2385
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/pi-chat.json",
2386
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json"
2329
2387
  ]
2330
2388
  },
2331
2389
  {
@@ -2334,8 +2392,8 @@
2334
2392
  "title": "Feedback preview",
2335
2393
  "description": "PreviewBanner: a live, reversible preview of a change in the page (Approve / Discard) over `@hachej/boring-feedback/preview`, whose subagent calls models through a host gateway. Separate from `feedback` so annotation-only apps do not install the model SDK; install `feedback` first (its styles cover the banner).",
2336
2394
  "dependencies": [
2337
- "@hachej/boring-feedback@^0.2.4",
2338
- "@earendil-works/pi-ai@~1.1.0",
2395
+ "@hachej/boring-feedback@^0.3.0",
2396
+ "@earendil-works/pi-ai@~1.2.0",
2339
2397
  "react@^19.0.0"
2340
2398
  ],
2341
2399
  "files": [
@@ -2352,8 +2410,8 @@
2352
2410
  "title": "Consumer task-list viewer",
2353
2411
  "description": "A consumer-defined task-list schema and controller over the shared text buffer, with a restylable borrowed React renderer.",
2354
2412
  "dependencies": [
2355
- "@hachej/boring-ui-kit@^0.2.4",
2356
- "@hachej/boring-files@^0.2.4",
2413
+ "@hachej/boring-ui-kit@^0.3.0",
2414
+ "@hachej/boring-files@^0.3.0",
2357
2415
  "react@^19.0.0",
2358
2416
  "react-dom@^19.0.0",
2359
2417
  "zod@^4.6.5"
@@ -2419,14 +2477,14 @@
2419
2477
  "title": "File tree",
2420
2478
  "description": "Browse, search, upload and inspect retained versions through one revisionProvider binding.",
2421
2479
  "dependencies": [
2422
- "@hachej/boring-ui-kit@^0.2.4",
2423
- "@hachej/boring-files@^0.2.4",
2480
+ "@hachej/boring-ui-kit@^0.3.0",
2481
+ "@hachej/boring-files@^0.3.0",
2424
2482
  "react@^19.0.0",
2425
2483
  "radix-ui@^1.8.0",
2426
2484
  "lucide-react@^1.51.0"
2427
2485
  ],
2428
2486
  "registryDependencies": [
2429
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/theme.json"
2487
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/theme.json"
2430
2488
  ],
2431
2489
  "files": [
2432
2490
  {
@@ -4,8 +4,8 @@
4
4
  "title": "Consumer task-list viewer",
5
5
  "description": "A consumer-defined task-list schema and controller over the shared text buffer, with a restylable borrowed React renderer.",
6
6
  "dependencies": [
7
- "@hachej/boring-ui-kit@^0.2.4",
8
- "@hachej/boring-files@^0.2.4",
7
+ "@hachej/boring-ui-kit@^0.3.0",
8
+ "@hachej/boring-files@^0.3.0",
9
9
  "react@^19.0.0",
10
10
  "react-dom@^19.0.0",
11
11
  "zod@^4.6.5"
package/r/utils.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "files": [
11
11
  {
12
12
  "path": "registry/utils/utils.ts",
13
- "content": "import { clsx } from 'clsx';\nimport type { ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string { return twMerge(clsx(inputs)); }\n\n/** Thrown when no automatic copy worked; `text` is what the person must copy by hand (a viewer shows it selected). */\nexport class ManualCopyError extends Error {\n constructor(readonly text: string) { super('Copy the text by hand'); this.name = 'ManualCopyError'; }\n}\n\n/**\n * Copies `text` using the host's callback when given, else the async Clipboard API (secure contexts only), else a hidden\n * textarea and `document.execCommand('copy')` (works over plain HTTP). Throws `ManualCopyError` when none worked.\n * This is the one place this item touches the clipboard; `npm run check` keeps it that way.\n */\nexport async function copyText(text: string, onCopy?: (text: string) => Promise<void>): Promise<void> {\n if (onCopy) return onCopy(text);\n try { const clipboard = globalThis.navigator?.clipboard; if (clipboard) { await clipboard.writeText(text); return; } }\n catch { /* denied or unfocused: use the selection route */ }\n const doc = globalThis.document;\n if (doc?.body && typeof doc.execCommand === 'function') {\n const area = doc.createElement('textarea');\n area.value = text;\n area.setAttribute('readonly', '');\n area.style.cssText = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none';\n const focus = doc.activeElement instanceof HTMLElement ? doc.activeElement : undefined;\n doc.body.append(area);\n try { area.select(); area.setSelectionRange(0, text.length); if (doc.execCommand('copy')) return; }\n catch { /* fall through */ }\n finally { area.remove(); focus?.focus({ preventScroll: true }); }\n }\n throw new ManualCopyError(text);\n}\n\n/**\n * A block's `labels` or `icons`: `defaults` with each partial override on top, later ones winning. A key an override leaves `undefined`\n * keeps the value below it, so a host can pass `{ title: maybe }` safely.\n */\nexport function withDefaults<T extends object>(defaults: T, ...overrides: readonly (Partial<T> | undefined)[]): T {\n const merged: Record<string, unknown> = { ...defaults as Record<string, unknown> };\n for (const override of overrides) for (const [key, value] of Object.entries(override ?? {})) if (value !== undefined) merged[key] = value;\n return merged as T;\n}\n",
13
+ "content": "import { clsx } from 'clsx';\nimport type { ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string { return twMerge(clsx(inputs)); }\n\n/** Thrown when no automatic copy worked; `text` is what the person must copy by hand (a viewer shows it selected). */\nexport class ManualCopyError extends Error {\n readonly text: string;\n constructor(text: string) { super('Copy the text by hand'); this.name = 'ManualCopyError'; this.text = text; }\n}\n\n/**\n * Copies `text` using the host's callback when given, else the async Clipboard API (secure contexts only), else a hidden\n * textarea and `document.execCommand('copy')` (works over plain HTTP). Throws `ManualCopyError` when none worked.\n * This is the one place this item touches the clipboard; `npm run check` keeps it that way.\n */\nexport async function copyText(text: string, onCopy?: (text: string) => Promise<void>): Promise<void> {\n if (onCopy) return onCopy(text);\n try { const clipboard = globalThis.navigator?.clipboard; if (clipboard) { await clipboard.writeText(text); return; } }\n catch { /* denied or unfocused: use the selection route */ }\n const doc = globalThis.document;\n if (doc?.body && typeof doc.execCommand === 'function') {\n const area = doc.createElement('textarea');\n area.value = text;\n area.setAttribute('readonly', '');\n area.style.cssText = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none';\n const focus = doc.activeElement instanceof HTMLElement ? doc.activeElement : undefined;\n doc.body.append(area);\n try { area.select(); area.setSelectionRange(0, text.length); if (doc.execCommand('copy')) return; }\n catch { /* fall through */ }\n finally { area.remove(); focus?.focus({ preventScroll: true }); }\n }\n throw new ManualCopyError(text);\n}\n\n/**\n * A block's `labels` or `icons`: `defaults` with each partial override on top, later ones winning. A key an override leaves `undefined`\n * keeps the value below it, so a host can pass `{ title: maybe }` safely.\n */\nexport function withDefaults<T extends object>(defaults: T, ...overrides: readonly (Partial<T> | undefined)[]): T {\n const merged: Record<string, unknown> = { ...defaults as Record<string, unknown> };\n for (const override of overrides) for (const [key, value] of Object.entries(override ?? {})) if (value !== undefined) merged[key] = value;\n return merged as T;\n}\n",
14
14
  "type": "registry:lib",
15
15
  "target": "components/utils/utils.ts"
16
16
  }
package/r/viewers.json CHANGED
@@ -4,8 +4,8 @@
4
4
  "title": "Viewers",
5
5
  "description": "The standard viewer top bar (title, status, viewer controls, Refresh, Share, Copy, Download, Open in new tab, Close, overflow menu) with Tailwind panes over it: the Markdown editor with a formatting toolbar and prose styling, the passive HTML preview and source editor, an image viewer with zoom and pan, and a PDF viewer. Owned, editable source over the borrowed controllers; no AI SDK.",
6
6
  "dependencies": [
7
- "@hachej/boring-ui-kit@^0.2.4",
8
- "@hachej/boring-files@^0.2.4",
7
+ "@hachej/boring-ui-kit@^0.3.0",
8
+ "@hachej/boring-files@^0.3.0",
9
9
  "react@^19.0.0",
10
10
  "react-dom@^19.0.0",
11
11
  "marked@^17.0.6",
@@ -24,9 +24,9 @@
24
24
  "lucide-react@^1.51.0"
25
25
  ],
26
26
  "registryDependencies": [
27
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/theme.json",
28
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/utils.json",
29
- "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.2.4/r/button.json"
27
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/theme.json",
28
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/utils.json",
29
+ "https://cdn.jsdelivr.net/npm/@hachej/boring-ui-kit@0.3.0/r/button.json"
30
30
  ],
31
31
  "files": [
32
32
  {