@flamingo-stack/openframe-frontend-core 0.0.510 → 0.0.511-snapshot.20260804140004
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/dist/chat-protocol/decode.d.ts.map +1 -1
- package/dist/chat-protocol/frames.d.ts +26 -1
- package/dist/chat-protocol/frames.d.ts.map +1 -1
- package/dist/chat-protocol/index.cjs +24 -0
- package/dist/chat-protocol/index.cjs.map +1 -1
- package/dist/chat-protocol/index.js +24 -0
- package/dist/chat-protocol/index.js.map +1 -1
- package/dist/{chunk-GE3JUTW2.js → chunk-27OKD7ZV.js} +44 -14
- package/dist/chunk-27OKD7ZV.js.map +1 -0
- package/dist/{chunk-RHQ7BJKK.cjs → chunk-2WWDZR4D.cjs} +73 -73
- package/dist/{chunk-RHQ7BJKK.cjs.map → chunk-2WWDZR4D.cjs.map} +1 -1
- package/dist/{chunk-J2JUAS4C.cjs → chunk-2XL7UK5Y.cjs} +11 -11
- package/dist/{chunk-J2JUAS4C.cjs.map → chunk-2XL7UK5Y.cjs.map} +1 -1
- package/dist/{chunk-Q4K3TGNP.cjs → chunk-3NECEXDF.cjs} +74 -44
- package/dist/chunk-3NECEXDF.cjs.map +1 -0
- package/dist/{chunk-JOCFPAS6.js → chunk-4NFDSMB5.js} +6 -6
- package/dist/{chunk-SYZFFRVD.cjs → chunk-5BAGE7AI.cjs} +13 -13
- package/dist/{chunk-SYZFFRVD.cjs.map → chunk-5BAGE7AI.cjs.map} +1 -1
- package/dist/{chunk-53JKCFFE.cjs → chunk-5JBDT2MQ.cjs} +12 -12
- package/dist/{chunk-53JKCFFE.cjs.map → chunk-5JBDT2MQ.cjs.map} +1 -1
- package/dist/{chunk-XJVRAKEX.cjs → chunk-67YDSTH7.cjs} +56 -33
- package/dist/chunk-67YDSTH7.cjs.map +1 -0
- package/dist/{chunk-WNOGR5AA.js → chunk-6LMTBNLN.js} +3 -3
- package/dist/{chunk-6FIDTXYC.js → chunk-7AQSXQEL.js} +3 -3
- package/dist/{chunk-JMBIGH4H.cjs → chunk-7VBEOGCR.cjs} +83 -83
- package/dist/{chunk-JMBIGH4H.cjs.map → chunk-7VBEOGCR.cjs.map} +1 -1
- package/dist/{chunk-5AZZQQYS.cjs → chunk-AWLFJMOJ.cjs} +40 -40
- package/dist/{chunk-5AZZQQYS.cjs.map → chunk-AWLFJMOJ.cjs.map} +1 -1
- package/dist/{chunk-RJ3D3PE2.cjs → chunk-DQDPDUI3.cjs} +9 -9
- package/dist/{chunk-RJ3D3PE2.cjs.map → chunk-DQDPDUI3.cjs.map} +1 -1
- package/dist/{chunk-2RLI5XVI.cjs → chunk-F2YI5N7E.cjs} +16 -16
- package/dist/{chunk-2RLI5XVI.cjs.map → chunk-F2YI5N7E.cjs.map} +1 -1
- package/dist/{chunk-LBOWSKGM.js → chunk-FI35LJ3L.js} +5 -5
- package/dist/{chunk-BTUHMCYW.js → chunk-FS3YSNSU.js} +193 -6
- package/dist/chunk-FS3YSNSU.js.map +1 -0
- package/dist/{chunk-RB2EW6IZ.cjs → chunk-GOFTC2HV.cjs} +3690 -3472
- package/dist/chunk-GOFTC2HV.cjs.map +1 -0
- package/dist/{chunk-CTMLY2GN.js → chunk-HGZPH7S5.js} +5 -5
- package/dist/{chunk-7VUKIWF6.cjs → chunk-HIV2GIFP.cjs} +3 -3
- package/dist/{chunk-7VUKIWF6.cjs.map → chunk-HIV2GIFP.cjs.map} +1 -1
- package/dist/{chunk-DBR5JLX3.js → chunk-IHNUMRMU.js} +46 -23
- package/dist/chunk-IHNUMRMU.js.map +1 -0
- package/dist/{chunk-R4HKB3YD.cjs → chunk-IIPBTWQR.cjs} +22 -22
- package/dist/{chunk-R4HKB3YD.cjs.map → chunk-IIPBTWQR.cjs.map} +1 -1
- package/dist/{chunk-TBGSQTJK.js → chunk-IK2WRYVA.js} +6 -6
- package/dist/{chunk-WSAPKKDU.cjs → chunk-JIW5JI3E.cjs} +9 -9
- package/dist/{chunk-WSAPKKDU.cjs.map → chunk-JIW5JI3E.cjs.map} +1 -1
- package/dist/{chunk-MLGGF24T.js → chunk-JKAX5K7C.js} +8 -8
- package/dist/{chunk-UWPT23SA.js → chunk-JO3NPEK6.js} +3 -3
- package/dist/{chunk-HCZJZMU7.js → chunk-JOFGJYIT.js} +3 -3
- package/dist/{chunk-A62C4C4V.cjs → chunk-KI4EGKNV.cjs} +3 -2
- package/dist/chunk-KI4EGKNV.cjs.map +1 -0
- package/dist/{chunk-OB7YDOTK.cjs → chunk-NJADHL2G.cjs} +8 -8
- package/dist/{chunk-OB7YDOTK.cjs.map → chunk-NJADHL2G.cjs.map} +1 -1
- package/dist/{chunk-EYTXD62B.cjs → chunk-OGVIGAMZ.cjs} +232 -45
- package/dist/chunk-OGVIGAMZ.cjs.map +1 -0
- package/dist/{chunk-HX4CJYXL.js → chunk-OT4RV6WY.js} +10 -10
- package/dist/{chunk-Z35QWWJH.cjs → chunk-RJXI25TJ.cjs} +34 -34
- package/dist/{chunk-Z35QWWJH.cjs.map → chunk-RJXI25TJ.cjs.map} +1 -1
- package/dist/{chunk-6TL5XIAW.cjs → chunk-SG25J6LV.cjs} +119 -119
- package/dist/{chunk-6TL5XIAW.cjs.map → chunk-SG25J6LV.cjs.map} +1 -1
- package/dist/{chunk-M4MKQKFF.js → chunk-UBTOOE55.js} +2 -2
- package/dist/{chunk-FEGEC6FY.js → chunk-V5WLIFKN.js} +5660 -5442
- package/dist/chunk-V5WLIFKN.js.map +1 -0
- package/dist/{chunk-EJ3EBYNV.cjs → chunk-VVXUUBML.cjs} +32 -32
- package/dist/{chunk-EJ3EBYNV.cjs.map → chunk-VVXUUBML.cjs.map} +1 -1
- package/dist/{chunk-SRYV4H3M.js → chunk-VZX3SSFL.js} +3 -3
- package/dist/{chunk-5CDPRCPS.cjs → chunk-WVZHCDB5.cjs} +23 -23
- package/dist/{chunk-5CDPRCPS.cjs.map → chunk-WVZHCDB5.cjs.map} +1 -1
- package/dist/{chunk-VDJF4ZAU.js → chunk-XG7FLAKQ.js} +3 -3
- package/dist/{chunk-SZMA65OW.js → chunk-XURRAFIB.js} +2 -2
- package/dist/{chunk-RG2WRBPT.js → chunk-Z3ADCYC5.js} +2 -2
- package/dist/{chunk-2AASLY6D.js → chunk-ZIQMVAGA.js} +3 -3
- package/dist/{chunk-4GPWLGKT.js → chunk-ZRILYK5U.js} +2 -1
- package/dist/components/calendar.cjs +4 -4
- package/dist/components/calendar.js +3 -3
- package/dist/components/case-studies/index.cjs +17 -17
- package/dist/components/case-studies/index.js +7 -7
- package/dist/components/chat/approval-batch-message.d.ts +2 -2
- package/dist/components/chat/approval-batch-message.d.ts.map +1 -1
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/entity-cards/deleted-data-card.d.ts +27 -0
- package/dist/components/chat/entity-cards/deleted-data-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat-card-item.d.ts +3 -0
- package/dist/components/chat/hooks/use-chat-card-item.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +13 -7
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +12 -6
- package/dist/components/chat/remark-mention-chips.d.ts +5 -2
- package/dist/components/chat/remark-mention-chips.d.ts.map +1 -1
- package/dist/components/chat/remark-strip-citations.d.ts +22 -0
- package/dist/components/chat/remark-strip-citations.d.ts.map +1 -0
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
- package/dist/components/chat/stream/message-mutations.d.ts +49 -5
- package/dist/components/chat/stream/message-mutations.d.ts.map +1 -1
- package/dist/components/chat/types/component.types.d.ts +7 -7
- package/dist/components/chat/types/component.types.d.ts.map +1 -1
- package/dist/components/chat/types/message.types.d.ts +11 -4
- package/dist/components/chat/types/message.types.d.ts.map +1 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts +4 -1
- package/dist/components/chat/types/unified-chat-state.types.d.ts.map +1 -1
- package/dist/components/chat/utils/discuss-ref-prompt.d.ts +48 -0
- package/dist/components/chat/utils/discuss-ref-prompt.d.ts.map +1 -0
- package/dist/components/chat/utils/index.d.ts +2 -0
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/message-segment-accumulator.d.ts +5 -3
- package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
- package/dist/components/chat/utils/resolve-fetched-card-href.d.ts +63 -0
- package/dist/components/chat/utils/resolve-fetched-card-href.d.ts.map +1 -0
- package/dist/components/chat/utils/source-row-cta.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +8 -8
- package/dist/components/contact/index.js +7 -7
- package/dist/components/docs/index.cjs +10 -10
- package/dist/components/docs/index.js +9 -9
- package/dist/components/embeds/index.cjs +8 -8
- package/dist/components/embeds/index.js +7 -7
- package/dist/components/faq/index.cjs +9 -9
- package/dist/components/faq/index.js +8 -8
- package/dist/components/features/index.cjs +7 -7
- package/dist/components/features/index.js +6 -6
- package/dist/components/help-center-pages/index.cjs +28 -28
- package/dist/components/help-center-pages/index.js +19 -19
- package/dist/components/icons/index.cjs +3 -3
- package/dist/components/icons/index.js +2 -2
- package/dist/components/index.cjs +253 -247
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +23 -17
- package/dist/components/index.js.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +92 -92
- package/dist/components/meeting-scheduler/index.js +9 -9
- package/dist/components/navigation/index.cjs +7 -7
- package/dist/components/navigation/index.js +6 -6
- package/dist/components/onboarding-guides/index.cjs +11 -11
- package/dist/components/onboarding-guides/index.js +10 -10
- package/dist/components/related-content/index.cjs +9 -9
- package/dist/components/related-content/index.js +8 -8
- package/dist/components/shared/doc-search/resolve-search-result-action.d.ts +11 -3
- package/dist/components/shared/doc-search/resolve-search-result-action.d.ts.map +1 -1
- package/dist/components/shared/doc-search/use-doc-search.d.ts +7 -0
- package/dist/components/shared/doc-search/use-doc-search.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +11 -11
- package/dist/components/tickets/index.js +10 -10
- package/dist/components/ui/actions-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/file-manager/index.cjs +70 -70
- package/dist/components/ui/file-manager/index.js +3 -3
- package/dist/components/ui/index.cjs +13 -7
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +12 -6
- package/dist/components/ui/markdown/base-components.d.ts.map +1 -1
- package/dist/components/ui/overlay-open-registry.d.ts +50 -0
- package/dist/components/ui/overlay-open-registry.d.ts.map +1 -0
- package/dist/components/ui/portal-container.d.ts +24 -0
- package/dist/components/ui/portal-container.d.ts.map +1 -1
- package/dist/hooks/index.cjs +4 -4
- package/dist/hooks/index.js +3 -3
- package/dist/index.cjs +20 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +24 -14
- package/dist/utils/anchor-id.d.ts +32 -0
- package/dist/utils/anchor-id.d.ts.map +1 -0
- package/dist/utils/content-href.d.ts +27 -6
- package/dist/utils/content-href.d.ts.map +1 -1
- package/dist/utils/index.cjs +213 -152
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +212 -153
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/list-url.d.ts.map +1 -1
- package/dist/utils/same-page-hash-nav.d.ts +17 -6
- package/dist/utils/same-page-hash-nav.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/chat-protocol/decode.ts +43 -0
- package/src/chat-protocol/frames.ts +27 -0
- package/src/components/chat/__tests__/remark-mention-chips.test.ts +67 -0
- package/src/components/chat/approval-batch-message.tsx +2 -2
- package/src/components/chat/chat-message-enhanced.tsx +5 -3
- package/src/components/chat/chat-message-list.tsx +49 -5
- package/src/components/chat/embeddable-chat.tsx +19 -2
- package/src/components/chat/entity-cards/deleted-data-card.tsx +61 -0
- package/src/components/chat/entity-cards/dispatch.tsx +205 -102
- package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +1 -1
- package/src/components/chat/hooks/use-chat-card-item.ts +15 -1
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +28 -4
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +57 -32
- package/src/components/chat/remark-mention-chips.ts +6 -3
- package/src/components/chat/remark-strip-citations.ts +39 -0
- package/src/components/chat/stream/__tests__/chat-stream-reducer-approval-batch.test.ts +196 -0
- package/src/components/chat/stream/chat-stream-reducer.ts +67 -2
- package/src/components/chat/stream/message-mutations.ts +170 -40
- package/src/components/chat/types/component.types.ts +9 -7
- package/src/components/chat/types/message.types.ts +14 -4
- package/src/components/chat/types/unified-chat-state.types.ts +4 -1
- package/src/components/chat/utils/__tests__/discuss-ref-prompt.test.ts +67 -0
- package/src/components/chat/utils/__tests__/resolve-fetched-card-href.test.ts +156 -0
- package/src/components/chat/utils/discuss-ref-prompt.ts +63 -0
- package/src/components/chat/utils/index.ts +16 -0
- package/src/components/chat/utils/message-segment-accumulator.ts +24 -29
- package/src/components/chat/utils/resolve-fetched-card-href.ts +104 -0
- package/src/components/chat/utils/source-row-cta.ts +5 -1
- package/src/components/shared/doc-search/__tests__/resolve-search-result-action.test.ts +145 -0
- package/src/components/shared/doc-search/resolve-search-result-action.ts +46 -10
- package/src/components/shared/doc-search/use-doc-search.ts +50 -14
- package/src/components/ui/__tests__/overlay-open-registry.test.tsx +87 -0
- package/src/components/ui/actions-menu.tsx +65 -2
- package/src/components/ui/dropdown-menu.tsx +62 -12
- package/src/components/ui/markdown/base-components.tsx +26 -0
- package/src/components/ui/overlay-open-registry.tsx +99 -0
- package/src/components/ui/portal-container.tsx +31 -0
- package/src/utils/__tests__/anchor-id.test.ts +139 -0
- package/src/utils/__tests__/content-href.test.ts +74 -0
- package/src/utils/__tests__/list-url.test.ts +11 -1
- package/src/utils/anchor-id.ts +106 -0
- package/src/utils/content-href.ts +113 -13
- package/src/utils/index.ts +8 -0
- package/src/utils/list-url.ts +6 -1
- package/src/utils/same-page-hash-nav.ts +28 -9
- package/dist/chunk-A62C4C4V.cjs.map +0 -1
- package/dist/chunk-BTUHMCYW.js.map +0 -1
- package/dist/chunk-DBR5JLX3.js.map +0 -1
- package/dist/chunk-EYTXD62B.cjs.map +0 -1
- package/dist/chunk-FEGEC6FY.js.map +0 -1
- package/dist/chunk-GE3JUTW2.js.map +0 -1
- package/dist/chunk-Q4K3TGNP.cjs.map +0 -1
- package/dist/chunk-RB2EW6IZ.cjs.map +0 -1
- package/dist/chunk-XJVRAKEX.cjs.map +0 -1
- /package/dist/{chunk-JOCFPAS6.js.map → chunk-4NFDSMB5.js.map} +0 -0
- /package/dist/{chunk-WNOGR5AA.js.map → chunk-6LMTBNLN.js.map} +0 -0
- /package/dist/{chunk-6FIDTXYC.js.map → chunk-7AQSXQEL.js.map} +0 -0
- /package/dist/{chunk-LBOWSKGM.js.map → chunk-FI35LJ3L.js.map} +0 -0
- /package/dist/{chunk-CTMLY2GN.js.map → chunk-HGZPH7S5.js.map} +0 -0
- /package/dist/{chunk-TBGSQTJK.js.map → chunk-IK2WRYVA.js.map} +0 -0
- /package/dist/{chunk-MLGGF24T.js.map → chunk-JKAX5K7C.js.map} +0 -0
- /package/dist/{chunk-UWPT23SA.js.map → chunk-JO3NPEK6.js.map} +0 -0
- /package/dist/{chunk-HCZJZMU7.js.map → chunk-JOFGJYIT.js.map} +0 -0
- /package/dist/{chunk-HX4CJYXL.js.map → chunk-OT4RV6WY.js.map} +0 -0
- /package/dist/{chunk-M4MKQKFF.js.map → chunk-UBTOOE55.js.map} +0 -0
- /package/dist/{chunk-SRYV4H3M.js.map → chunk-VZX3SSFL.js.map} +0 -0
- /package/dist/{chunk-VDJF4ZAU.js.map → chunk-XG7FLAKQ.js.map} +0 -0
- /package/dist/{chunk-SZMA65OW.js.map → chunk-XURRAFIB.js.map} +0 -0
- /package/dist/{chunk-RG2WRBPT.js.map → chunk-Z3ADCYC5.js.map} +0 -0
- /package/dist/{chunk-2AASLY6D.js.map → chunk-ZIQMVAGA.js.map} +0 -0
- /package/dist/{chunk-4GPWLGKT.js.map → chunk-ZRILYK5U.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-url.d.ts","sourceRoot":"","sources":["../../src/utils/list-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAWH;;;;iEAIiE;AACjE,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"list-url.d.ts","sourceRoot":"","sources":["../../src/utils/list-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAWH;;;;iEAIiE;AACjE,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAOtE;AA6BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,SAAK,GAAG,MAAM,GAAG,IAAI,CAa5F"}
|
|
@@ -15,12 +15,23 @@ export declare const HUB_HEADER_OFFSET_PX = 80;
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function normalizeHashFragment(hash: string): string;
|
|
17
17
|
/**
|
|
18
|
-
* Resolve the DOM element a hash fragment id points at
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
18
|
+
* Resolve the DOM element a hash fragment id points at — THE hash resolver;
|
|
19
|
+
* `navigateSamePageHash`, `useScrollToHash` and the markdown link renderer
|
|
20
|
+
* all go through this one, so a fragment that resolves for a deep link
|
|
21
|
+
* resolves for an in-body click too.
|
|
22
|
+
*
|
|
23
|
+
* Three passes, cheapest first:
|
|
24
|
+
* 1. the raw id (ordinary anchors — the overwhelming common case);
|
|
25
|
+
* 2. the percent-decoded form — href composers like `buildTicketOpenHref`
|
|
26
|
+
* encode the id into the fragment while rows render the raw id, so
|
|
27
|
+
* `#ticket-a%2Fb` must still find `id="ticket-a/b"`. A malformed escape
|
|
28
|
+
* sequence just falls through;
|
|
29
|
+
* 3. a NORMALIZED match against the document's headings — doc bodies are
|
|
30
|
+
* authored on GitHub, whose slugger keeps the hyphen left behind by a
|
|
31
|
+
* stripped emoji (`## 📚 Table of Contents` → `#-table-of-contents`)
|
|
32
|
+
* while our ids trim it. Without this every in-body TOC link in every
|
|
33
|
+
* GitHub-authored doc resolves to nothing and clicking one does nothing.
|
|
34
|
+
* See `utils/anchor-id`.
|
|
24
35
|
*/
|
|
25
36
|
export declare function getHashTargetElement(id: string): HTMLElement | null;
|
|
26
37
|
export interface NavigateSamePageHashOptions {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"same-page-hash-nav.d.ts","sourceRoot":"","sources":["../../src/utils/same-page-hash-nav.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"same-page-hash-nav.d.ts","sourceRoot":"","sources":["../../src/utils/same-page-hash-nav.ts"],"names":[],"mappings":"AAGA;;sCAEsC;AACtC,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC;yCACyC;AACzC,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAkBnE;AAED,MAAM,WAAW,2BAA2B;IAC1C,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;gEAC4D;IAC5D,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAkET"}
|
package/package.json
CHANGED
|
@@ -100,6 +100,49 @@ function mapLeadingFrame(meta: any, out: ChatStreamEvent[]): void {
|
|
|
100
100
|
...(typeof meta.receiptText === 'string' ? { receiptText: meta.receiptText } : {}),
|
|
101
101
|
requestId: typeof meta.proposalId === 'string' ? meta.proposalId : undefined,
|
|
102
102
|
})
|
|
103
|
+
} else if (meta.kind === 'approval_batch' && meta.batchId && Array.isArray(meta.proposals)) {
|
|
104
|
+
// Server-grouped multi-proposal turn → ONE batch event carrying a
|
|
105
|
+
// tool-call row per proposal. `toolExecutionRequestId` is the row's
|
|
106
|
+
// PROPOSAL id (each row resolves through its own per-proposal
|
|
107
|
+
// confirm); the batch's `requestId` is the stable anchor the shell
|
|
108
|
+
// uses for status flips. Field rows ride as the row's expandable
|
|
109
|
+
// args so per-proposal detail stays reachable inside the batch.
|
|
110
|
+
const toolCalls = (meta.proposals as Array<Record<string, any>>)
|
|
111
|
+
.filter((p) => p && typeof p.proposalId === 'string')
|
|
112
|
+
.map((p) => {
|
|
113
|
+
const rawFields = Array.isArray(p.fields)
|
|
114
|
+
? (p.fields as Array<{ label?: string; value?: string }>).filter(
|
|
115
|
+
(f) => f && f.label && f.value,
|
|
116
|
+
)
|
|
117
|
+
: []
|
|
118
|
+
// Prefer human-readable identity labels for the row's
|
|
119
|
+
// disambiguator; opaque-id labels ("Task", "Ticket") only as
|
|
120
|
+
// the last-resort first field.
|
|
121
|
+
const detail =
|
|
122
|
+
rawFields.find((f) => /^(title|subject|name)$/i.test(String(f.label))) ??
|
|
123
|
+
rawFields[0]
|
|
124
|
+
const base =
|
|
125
|
+
typeof p.title === 'string' && p.title.length > 0 ? p.title : String(p.toolName ?? 'Tool call')
|
|
126
|
+
return {
|
|
127
|
+
toolExecutionRequestId: String(p.proposalId),
|
|
128
|
+
toolName: String(p.toolName ?? 'tool'),
|
|
129
|
+
toolTitle: detail ? `${base} — ${detail.value}` : base,
|
|
130
|
+
requiresApproval: true,
|
|
131
|
+
toolCallArguments:
|
|
132
|
+
rawFields.length > 0
|
|
133
|
+
? Object.fromEntries(rawFields.map((f) => [String(f.label), String(f.value)]))
|
|
134
|
+
: null,
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
if (toolCalls.length > 0) {
|
|
138
|
+
out.push({
|
|
139
|
+
type: 'approval-request',
|
|
140
|
+
requestId: String(meta.batchId),
|
|
141
|
+
approvalType: 'chat',
|
|
142
|
+
toolCalls,
|
|
143
|
+
status: 'pending',
|
|
144
|
+
})
|
|
145
|
+
}
|
|
103
146
|
} else if (meta.kind === 'approval_request' && meta.proposalId) {
|
|
104
147
|
const proposalId = String(meta.proposalId)
|
|
105
148
|
const toolName = String(meta.toolName ?? 'tool')
|
|
@@ -165,6 +165,32 @@ export interface ApprovalRequestFrame {
|
|
|
165
165
|
ttlSeconds?: number
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
/** A single write-tool turn produced MULTIPLE proposals (batch
|
|
169
|
+
* operations — "delete both", "close all three"). The SERVER is the
|
|
170
|
+
* authority on the grouping: it collects the turn's proposals and
|
|
171
|
+
* ships ONE batch frame instead of N `approval_request` frames, so
|
|
172
|
+
* clients render the bulk-approval component without any adjacency
|
|
173
|
+
* heuristics. Single-proposal turns keep the classic
|
|
174
|
+
* `approval_request` frame. */
|
|
175
|
+
export interface ApprovalBatchFrame {
|
|
176
|
+
kind: 'approval_batch'
|
|
177
|
+
/** Stable batch anchor — client-side only (locates the batch segment
|
|
178
|
+
* for status flips). MUST NOT equal any row's `proposalId`: the
|
|
179
|
+
* click-time optimistic status flip keys on this id, and an anchor
|
|
180
|
+
* that doubles as a row id would falsely tick that row's execution
|
|
181
|
+
* as succeeded before its confirm ran (masking a failed write). The
|
|
182
|
+
* server emits `batch:<first proposalId>`. */
|
|
183
|
+
batchId: string
|
|
184
|
+
proposals: Array<{
|
|
185
|
+
proposalId: string
|
|
186
|
+
toolName: string
|
|
187
|
+
title?: string
|
|
188
|
+
fields?: ApprovalRequestField[]
|
|
189
|
+
expiresAt?: string
|
|
190
|
+
ttlSeconds?: number
|
|
191
|
+
}>
|
|
192
|
+
}
|
|
193
|
+
|
|
168
194
|
/** Server-driven post-approve / post-reject frame (confirm-tool route).
|
|
169
195
|
* Mirror of the hub's `DecisionResolvedFrame` in
|
|
170
196
|
* `lib/data/chat-agent-utils.ts` (tool_name widened to string — the
|
|
@@ -205,6 +231,7 @@ export type SseLeadingFrame =
|
|
|
205
231
|
| TextLeadingFrame
|
|
206
232
|
| ToolErrorFrame
|
|
207
233
|
| ApprovalRequestFrame
|
|
234
|
+
| ApprovalBatchFrame
|
|
208
235
|
| DecisionResolvedFrame
|
|
209
236
|
|
|
210
237
|
// =============================================================================
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import type { Root, Text, Link, Paragraph } from 'mdast'
|
|
3
|
+
import { remarkMentionChips } from '../remark-mention-chips'
|
|
4
|
+
|
|
5
|
+
/** One-paragraph tree holding a single text leaf — what the plugin walks. */
|
|
6
|
+
function treeOf(text: string): Root {
|
|
7
|
+
return { type: 'root', children: [{ type: 'paragraph', children: [{ type: 'text', value: text }] }] }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* unified's `Plugin` type declares a `this: Processor` parameter, so calling the
|
|
12
|
+
* attacher bare (outside a pipeline) is a TS2684 — cast the attacher itself, not
|
|
13
|
+
* just its return value, to drop that `this`.
|
|
14
|
+
*/
|
|
15
|
+
const attach = remarkMentionChips as unknown as () => (t: Root) => void
|
|
16
|
+
|
|
17
|
+
function run(text: string): Array<Text | Link> {
|
|
18
|
+
const tree = treeOf(text)
|
|
19
|
+
attach()(tree)
|
|
20
|
+
return (tree.children[0] as Paragraph).children as Array<Text | Link>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** `mention://marker:id` urls the plugin emitted, in order. */
|
|
24
|
+
function mentions(text: string): string[] {
|
|
25
|
+
return run(text).flatMap((n) => (n.type === 'link' ? [n.url] : []))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe('remarkMentionChips markers', () => {
|
|
29
|
+
it('parses the lowercase markers', () => {
|
|
30
|
+
expect(mentions('see @device:64f0a1 and @kb:5')).toEqual([
|
|
31
|
+
'mention://device:64f0a1',
|
|
32
|
+
'mention://kb:5',
|
|
33
|
+
])
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('parses a camelCase marker', () => {
|
|
37
|
+
// Regression: `ContextItemType.SCHEDULED_SCRIPT` ships as `scheduledScript`,
|
|
38
|
+
// and a lowercase-only grammar matched NOTHING in the token — the mention
|
|
39
|
+
// silently stayed raw text in the bubble instead of becoming a chip.
|
|
40
|
+
expect(mentions('run @scheduledScript:6a6c9342f8e10b2477900c08 now')).toEqual([
|
|
41
|
+
'mention://scheduledScript:6a6c9342f8e10b2477900c08',
|
|
42
|
+
])
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('keeps the surrounding text intact around a camelCase mention', () => {
|
|
46
|
+
const parts = run('run @scheduledScript:6a6c9342f8e10b2477900c08 now')
|
|
47
|
+
expect(parts.map((n) => (n.type === 'text' ? n.value : `[${(n as Link).url}]`))).toEqual([
|
|
48
|
+
'run ',
|
|
49
|
+
'[mention://scheduledScript:6a6c9342f8e10b2477900c08]',
|
|
50
|
+
' now',
|
|
51
|
+
])
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('fires inside punctuation but never mid-word', () => {
|
|
55
|
+
expect(mentions('(@scheduledScript:6a6c9342f8e10b2477900c08)')).toEqual([
|
|
56
|
+
'mention://scheduledScript:6a6c9342f8e10b2477900c08',
|
|
57
|
+
])
|
|
58
|
+
// An email-shaped host:port is not a mention — the `@` is preceded by a word char.
|
|
59
|
+
expect(mentions('mail user@Host:1234 stays text')).toEqual([])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('leaves a trailing sentence period out of the id', () => {
|
|
63
|
+
expect(mentions('ran @scheduledScript:6a6c9342f8e10b2477900c08.')).toEqual([
|
|
64
|
+
'mention://scheduledScript:6a6c9342f8e10b2477900c08',
|
|
65
|
+
])
|
|
66
|
+
})
|
|
67
|
+
})
|
|
@@ -25,8 +25,8 @@ import {
|
|
|
25
25
|
export interface ApprovalBatchMessageProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
26
26
|
data: ApprovalBatchSegment["data"]
|
|
27
27
|
status?: ApprovalBatchSegment["status"]
|
|
28
|
-
onApprove?: (requestId?: string) => void | Promise<void>
|
|
29
|
-
onReject?: (requestId?: string) => void | Promise<void>
|
|
28
|
+
onApprove?: (requestId?: string) => void | boolean | Promise<void | boolean>
|
|
29
|
+
onReject?: (requestId?: string) => void | boolean | Promise<void | boolean>
|
|
30
30
|
/**
|
|
31
31
|
* Cap the tool-call list height so it scrolls internally while the footer
|
|
32
32
|
* (explanations + Approve/Reject) stays pinned below. Omit for the default
|
|
@@ -15,6 +15,7 @@ import { GuideDisplay } from "./guide-display"
|
|
|
15
15
|
import { SimpleMarkdownRenderer } from "../ui/markdown/simple-markdown-renderer"
|
|
16
16
|
import type { ChatRef } from "./chat-ref.types"
|
|
17
17
|
import { remarkCardLinks } from "./remark-card-links"
|
|
18
|
+
import { remarkStripCitations } from "./remark-strip-citations"
|
|
18
19
|
import { remarkMentionChips } from "./remark-mention-chips"
|
|
19
20
|
import { BlockCard, type BlockCardProps } from "./entity-cards/block-card"
|
|
20
21
|
import { ChatContextChipStrip } from "./chat-context-picker"
|
|
@@ -27,8 +28,9 @@ import type { MessageSegment, MessageContent, ChatMessageEnhancedProps } from ".
|
|
|
27
28
|
* (e.g. it matches `x@device:1` mid-word, which the plugin skips), so a context
|
|
28
29
|
* item would be stripped from the chip strip yet never rendered inline — lost
|
|
29
30
|
* from display entirely. The id is capture group 2 (group 1 is the boundary).
|
|
30
|
-
* Marker lowercase
|
|
31
|
-
|
|
31
|
+
* Marker `[a-zA-Z]+` (markers are mostly lowercase but not all — e.g.
|
|
32
|
+
* `scheduledScript`); id is the mention-token charset. */
|
|
33
|
+
const MENTION_MARKER_REGEX = /(^|[^\w@])@[a-zA-Z]+:([A-Za-z0-9_.+/=-]*[A-Za-z0-9_+/=])/g
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Same regex shape as `remarkCardLinks` — kept in lockstep so the
|
|
@@ -109,7 +111,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
109
111
|
// (user). Each is gated independently so neither fires without its data.
|
|
110
112
|
const cardRemarkPlugins = useMemo(
|
|
111
113
|
() => [
|
|
112
|
-
...(hasMarkerSupport ? [remarkCardLinks] : []),
|
|
114
|
+
...(hasMarkerSupport ? [remarkCardLinks, remarkStripCitations] : []),
|
|
113
115
|
...(hasMentionSupport ? [remarkMentionChips] : []),
|
|
114
116
|
],
|
|
115
117
|
[hasMarkerSupport, hasMentionSupport],
|
|
@@ -6,6 +6,7 @@ import { cn } from "../../utils/cn"
|
|
|
6
6
|
import { ChatMessageEnhanced } from "./chat-message-enhanced"
|
|
7
7
|
import { ChatMessageListSkeleton } from "./chat-message-skeleton"
|
|
8
8
|
import { DotsLoaderIcon, Arrow02DownIcon } from "../icons-v2-generated"
|
|
9
|
+
import { OverlayOpenRegistryProvider } from "../ui/overlay-open-registry"
|
|
9
10
|
import { CyclingPhrase } from "./cycling-phrase"
|
|
10
11
|
import type { ChatMessageListProps } from "./types"
|
|
11
12
|
import { SCROLL_ANCHOR } from "./types/message.types"
|
|
@@ -141,10 +142,44 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
141
142
|
// effect below owns first-paint positioning so re-opening a chat
|
|
142
143
|
// with prior history lands at the bottom without a smooth-scroll
|
|
143
144
|
// animation playing over the cold-paint.
|
|
144
|
-
const { scrollRef, contentRef, scrollToBottom, stopScroll } =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
const { scrollRef, contentRef, scrollToBottom, stopScroll, isAtBottom } =
|
|
146
|
+
useStickToBottom({
|
|
147
|
+
resize: 'smooth',
|
|
148
|
+
initial: false,
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// ---- Overlay guard: don't move the ground under an open menu -------
|
|
152
|
+
// A ⋯ menu inside a bubble stays anchored to its trigger. While a reply
|
|
153
|
+
// streams in, the follow-the-bottom scroll carries that trigger upward and
|
|
154
|
+
// drags the menu with it, until the menu sits at the panel edge detached
|
|
155
|
+
// from its card. So: while any overlay in this thread is open, stop
|
|
156
|
+
// chasing the bottom (the same thing ChatGPT/Claude do once you interact
|
|
157
|
+
// with the transcript), then catch up on close if we were at the bottom
|
|
158
|
+
// when it opened. New content still renders — we simply stop scrolling to
|
|
159
|
+
// it, and the existing "scroll to bottom" affordance stays available.
|
|
160
|
+
const overlayOpenRef = useRef(false)
|
|
161
|
+
const wasAtBottomOnOpenRef = useRef(false)
|
|
162
|
+
const isAtBottomRef = useRef(isAtBottom)
|
|
163
|
+
isAtBottomRef.current = isAtBottom
|
|
164
|
+
const handleOverlayOpenChange = useCallback(
|
|
165
|
+
(hasOpenOverlay: boolean) => {
|
|
166
|
+
overlayOpenRef.current = hasOpenOverlay
|
|
167
|
+
if (hasOpenOverlay) {
|
|
168
|
+
wasAtBottomOnOpenRef.current = isAtBottomRef.current
|
|
169
|
+
// Cancel any in-flight spring so the thread settles immediately
|
|
170
|
+
// instead of drifting for another few hundred ms under the menu.
|
|
171
|
+
stopScroll()
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
// Closed again: resume only if the reader was pinned to the bottom
|
|
175
|
+
// before opening it. Someone who had scrolled up to read history keeps
|
|
176
|
+
// their position.
|
|
177
|
+
if (wasAtBottomOnOpenRef.current) {
|
|
178
|
+
void scrollToBottom({ animation: 'smooth' })
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
[scrollToBottom, stopScroll],
|
|
182
|
+
)
|
|
148
183
|
|
|
149
184
|
// ---- Prepend / load-more state (NOT owned by the library) --------
|
|
150
185
|
const sentinelRef = useRef<HTMLDivElement>(null)
|
|
@@ -263,7 +298,12 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
263
298
|
const prevLastIdx = prevLastId ? messages.findIndex((m) => m.id === prevLastId) : -1
|
|
264
299
|
const newSlice = prevLastIdx >= 0 ? messages.slice(prevLastIdx + 1) : messages.slice(prevCount)
|
|
265
300
|
const hasNewUser = newSlice.some((m) => m.role === 'user')
|
|
266
|
-
|
|
301
|
+
// An open overlay suppresses even this one: `ignoreEscapes` would yank
|
|
302
|
+
// the thread out from under it — and with it the follow intent, which
|
|
303
|
+
// would re-assert the jump on every later resize. A user who just sent
|
|
304
|
+
// a message with a menu open is rare; a menu jumping away mid-click is
|
|
305
|
+
// not worth it.
|
|
306
|
+
if (hasNewUser && !overlayOpenRef.current) {
|
|
267
307
|
// Arms the follow intent for the WHOLE turn: the answer's
|
|
268
308
|
// async growth (attachment images, streamed tokens, entity
|
|
269
309
|
// cards resolving out of their skeletons long after the
|
|
@@ -657,6 +697,8 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
657
697
|
|
|
658
698
|
useLayoutEffect(() => {
|
|
659
699
|
if (!autoScroll) return
|
|
700
|
+
// Top-anchored display turns also move the ground — same guard.
|
|
701
|
+
if (overlayOpenRef.current) return
|
|
660
702
|
const last = messages[messages.length - 1]
|
|
661
703
|
if (!last || last.role !== 'assistant' || last.scrollAnchor !== SCROLL_ANCHOR.TOP) return
|
|
662
704
|
// Metadata frame arrives BEFORE body. Wait for content so we don't
|
|
@@ -847,6 +889,7 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
847
889
|
!(pendingApprovals && pendingApprovals.length > 0)
|
|
848
890
|
|
|
849
891
|
return (
|
|
892
|
+
<OverlayOpenRegistryProvider onOpenChange={handleOverlayOpenChange}>
|
|
850
893
|
<div className="flex-1 min-h-0 flex flex-col">
|
|
851
894
|
{/* Positioning box for the jump-to-bottom button: it wraps ONLY the
|
|
852
895
|
scroller, so `absolute bottom-…` really is the scroller's lower
|
|
@@ -1029,6 +1072,7 @@ const ChatMessageList = forwardRef<HTMLDivElement, ChatMessageListProps>(
|
|
|
1029
1072
|
</div>
|
|
1030
1073
|
)}
|
|
1031
1074
|
</div>
|
|
1075
|
+
</OverlayOpenRegistryProvider>
|
|
1032
1076
|
)
|
|
1033
1077
|
},
|
|
1034
1078
|
)
|
|
@@ -52,7 +52,7 @@ import { MingoHistoryRail } from './mingo-history-rail'
|
|
|
52
52
|
import { GuideWelcome, type GuideWelcomeProps } from './guide-welcome'
|
|
53
53
|
import { accentFromIdentityIcon, getAgentAccent } from './quick-action-chip'
|
|
54
54
|
import { GuideModeBanner } from './guide-mode-banner'
|
|
55
|
-
import { PortalContainerContext } from '../ui/portal-container'
|
|
55
|
+
import { CollisionBoundaryContext, PortalContainerContext } from '../ui/portal-container'
|
|
56
56
|
import { ChatPanelHeader, type ChatPanelHeaderProps } from './chat-panel-header'
|
|
57
57
|
import { SquareAvatar } from '../ui/square-avatar'
|
|
58
58
|
import { ChatHeaderIconButton } from './chat-header-icon-button'
|
|
@@ -1795,6 +1795,13 @@ function EmbeddableChatInner({
|
|
|
1795
1795
|
|
|
1796
1796
|
// Host node for in-panel Radix portals (see the body wrapper below).
|
|
1797
1797
|
const [portalHost, setPortalHost] = useState<HTMLDivElement | null>(null)
|
|
1798
|
+
// The panel element itself, published as the COLLISION boundary for overlays
|
|
1799
|
+
// opened inside it. Radix otherwise collides against the viewport, so a ⋯ menu
|
|
1800
|
+
// near the top of the thread flips upward past the panel and renders over the
|
|
1801
|
+
// app header (reported: an entity card's menu landing in the top-right corner,
|
|
1802
|
+
// detached from its card). `portalHost` can't serve here — it is
|
|
1803
|
+
// `display: contents` and has no box to measure.
|
|
1804
|
+
const [panelBoundary, setPanelBoundary] = useState<HTMLDivElement | null>(null)
|
|
1798
1805
|
|
|
1799
1806
|
// ── Split (wide) Mingo layout ─────────────────────────────────────────────
|
|
1800
1807
|
// The panel measures its own width and, in Mingo mode, promotes the inline
|
|
@@ -1817,6 +1824,14 @@ function EmbeddableChatInner({
|
|
|
1817
1824
|
return () => ro.disconnect()
|
|
1818
1825
|
}, [])
|
|
1819
1826
|
|
|
1827
|
+
// One ref for two consumers: the width measurement above (a plain ref, read
|
|
1828
|
+
// once on mount) and the collision-boundary context (state, so provider
|
|
1829
|
+
// consumers re-render once the node exists).
|
|
1830
|
+
const setPanelNode = useCallback((node: HTMLDivElement | null) => {
|
|
1831
|
+
panelMeasureRef.current = node
|
|
1832
|
+
setPanelBoundary(node)
|
|
1833
|
+
}, [])
|
|
1834
|
+
|
|
1820
1835
|
// Rail collapse toggle (Figma ⟶| control), persisted so it survives the
|
|
1821
1836
|
// drawer remounting on close.
|
|
1822
1837
|
const [railCollapsed, setRailCollapsed] = useState(false)
|
|
@@ -2003,6 +2018,7 @@ function EmbeddableChatInner({
|
|
|
2003
2018
|
// document root. See `PortalContainerContext`.
|
|
2004
2019
|
const body = (
|
|
2005
2020
|
<PortalContainerContext.Provider value={portalHost}>
|
|
2021
|
+
<CollisionBoundaryContext.Provider value={panelBoundary}>
|
|
2006
2022
|
{/* Panel surface depends on state (Figma):
|
|
2007
2023
|
• Narrow "Current Chats" LIST + FULL-PANEL archive page → grey
|
|
2008
2024
|
`ods-card` (#212121) — matching the grey rail those lists live
|
|
@@ -2017,7 +2033,7 @@ function EmbeddableChatInner({
|
|
|
2017
2033
|
grey), so the chat block on the right must keep the conversation's
|
|
2018
2034
|
dark surface instead of following the archive. */}
|
|
2019
2035
|
<div
|
|
2020
|
-
ref={
|
|
2036
|
+
ref={setPanelNode}
|
|
2021
2037
|
className={`flex h-full flex-col overflow-hidden transition-colors duration-200 ${
|
|
2022
2038
|
(archiveOpen && !splitActive) || stackedListView
|
|
2023
2039
|
? 'bg-ods-card'
|
|
@@ -2587,6 +2603,7 @@ function EmbeddableChatInner({
|
|
|
2587
2603
|
{/* Portal target for in-panel Radix overlays — `display: contents`
|
|
2588
2604
|
so it adds no box; content is positioned `fixed` by Radix. */}
|
|
2589
2605
|
<div ref={setPortalHost} style={{ display: 'contents' }} />
|
|
2606
|
+
</CollisionBoundaryContext.Provider>
|
|
2590
2607
|
</PortalContainerContext.Provider>
|
|
2591
2608
|
)
|
|
2592
2609
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Deleted Data Card — generic TOMBSTONE placeholder for an entity a chat
|
|
5
|
+
* action removed (ClickUp task today; any deletable entity tomorrow).
|
|
6
|
+
*
|
|
7
|
+
* Follows the established tombstone pattern (Teams / Slack "This message
|
|
8
|
+
* was deleted"): keep a visible, muted placeholder so the conversation
|
|
9
|
+
* thread's integrity holds — the reader sees WHAT was removed and that
|
|
10
|
+
* it may be recoverable, instead of a dead link or a silent gap.
|
|
11
|
+
*
|
|
12
|
+
* PURE PRESENTATION from the ChatRef — no fetch, no navigation (the
|
|
13
|
+
* underlying entity no longer resolves anywhere). Ref contract:
|
|
14
|
+
* - `title` — the deleted entity's display title
|
|
15
|
+
* - `metadata.entity_label` — what kind of thing it was ("ClickUp task")
|
|
16
|
+
* - `metadata.recovery_note` — optional recoverability copy
|
|
17
|
+
* ("Recoverable from the ClickUp Trash for 30 days")
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import React from 'react'
|
|
21
|
+
import { Trash2 } from 'lucide-react'
|
|
22
|
+
import {
|
|
23
|
+
COMPACT_CARD_ICON_SLOT,
|
|
24
|
+
COMPACT_CARD_META_ROW,
|
|
25
|
+
COMPACT_CARD_OUTER_STATIC,
|
|
26
|
+
COMPACT_CARD_TEXT_COL,
|
|
27
|
+
COMPACT_CARD_TITLE,
|
|
28
|
+
COMPACT_CARD_TITLE_ROW,
|
|
29
|
+
} from '../utils/compact-card-classes'
|
|
30
|
+
|
|
31
|
+
export interface DeletedDataCardProps {
|
|
32
|
+
title?: string | null
|
|
33
|
+
/** What kind of entity was deleted ("ClickUp task", "HubSpot ticket"). */
|
|
34
|
+
entityLabel?: string | null
|
|
35
|
+
/** Recoverability copy ("Recoverable from the ClickUp Trash for 30 days"). */
|
|
36
|
+
recoveryNote?: string | null
|
|
37
|
+
className?: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function DeletedDataCard({ title, entityLabel, recoveryNote, className }: DeletedDataCardProps) {
|
|
41
|
+
const label = entityLabel || 'Item'
|
|
42
|
+
return (
|
|
43
|
+
<div className={`${COMPACT_CARD_OUTER_STATIC} opacity-70 ${className ?? ''}`}>
|
|
44
|
+
<div className={COMPACT_CARD_ICON_SLOT}>
|
|
45
|
+
<Trash2 className="h-4 w-4 text-ods-text-secondary" />
|
|
46
|
+
</div>
|
|
47
|
+
<div className={COMPACT_CARD_TEXT_COL}>
|
|
48
|
+
<div className={COMPACT_CARD_TITLE_ROW}>
|
|
49
|
+
<span className={`${COMPACT_CARD_TITLE} line-through text-ods-text-secondary`}>
|
|
50
|
+
{title || `Deleted ${label.toLowerCase()}`}
|
|
51
|
+
</span>
|
|
52
|
+
</div>
|
|
53
|
+
<div className={COMPACT_CARD_META_ROW}>
|
|
54
|
+
<span className="text-ods-text-secondary">
|
|
55
|
+
{label} deleted{recoveryNote ? ` · ${recoveryNote}` : ''}
|
|
56
|
+
</span>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
)
|
|
61
|
+
}
|