@flamingo-stack/openframe-frontend-core 0.0.568 → 0.0.569
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/{chunk-P7QGTNEW.cjs → chunk-2DSDGWWU.cjs} +101 -101
- package/dist/{chunk-P7QGTNEW.cjs.map → chunk-2DSDGWWU.cjs.map} +1 -1
- package/dist/{chunk-ZARYIFCI.js → chunk-3UPQAOES.js} +5 -3
- package/dist/{chunk-ZARYIFCI.js.map → chunk-3UPQAOES.js.map} +1 -1
- package/dist/{chunk-KL6ZDLDF.js → chunk-4NN7V443.js} +2 -2
- package/dist/{chunk-G2PAUMV6.js → chunk-6STF67EF.js} +4 -4
- package/dist/{chunk-6RSKK4E7.cjs → chunk-74DB5H5T.cjs} +1258 -1162
- package/dist/chunk-74DB5H5T.cjs.map +1 -0
- package/dist/{chunk-6TDWCBQM.js → chunk-A2T266F3.js} +7 -7
- package/dist/{chunk-HKG7BZON.cjs → chunk-AAROYQ4O.cjs} +14 -14
- package/dist/{chunk-HKG7BZON.cjs.map → chunk-AAROYQ4O.cjs.map} +1 -1
- package/dist/{chunk-CEAAOVCV.cjs → chunk-AJPGQCZ2.cjs} +1 -1
- package/dist/chunk-AJPGQCZ2.cjs.map +1 -0
- package/dist/{chunk-ZXASQL3E.js → chunk-C5GKBUT7.js} +4 -4
- package/dist/{chunk-RBYMJF2V.cjs → chunk-D6SBYELJ.cjs} +35 -35
- package/dist/{chunk-RBYMJF2V.cjs.map → chunk-D6SBYELJ.cjs.map} +1 -1
- package/dist/{chunk-LNUXUOPN.cjs → chunk-EBE22KOQ.cjs} +4 -4
- package/dist/{chunk-LNUXUOPN.cjs.map → chunk-EBE22KOQ.cjs.map} +1 -1
- package/dist/{chunk-EYXZF46V.js → chunk-FE5QR7PT.js} +995 -899
- package/dist/chunk-FE5QR7PT.js.map +1 -0
- package/dist/{chunk-6PWUUWCO.cjs → chunk-FMWIA5IH.cjs} +42 -42
- package/dist/{chunk-6PWUUWCO.cjs.map → chunk-FMWIA5IH.cjs.map} +1 -1
- package/dist/{chunk-DHTT77AG.cjs → chunk-GY22CIEF.cjs} +78 -78
- package/dist/{chunk-DHTT77AG.cjs.map → chunk-GY22CIEF.cjs.map} +1 -1
- package/dist/{chunk-O3JCKEVG.js → chunk-HOMYI5RR.js} +2 -2
- package/dist/{chunk-BZ7B255K.js → chunk-KCAGMTJ6.js} +9 -9
- package/dist/{chunk-DZ2Z7HRF.js → chunk-KO333Q2B.js} +3 -3
- package/dist/{chunk-MQQM4NCN.js → chunk-LJBNHO6B.js} +3 -3
- package/dist/{chunk-KZS2DFC2.cjs → chunk-ME346OJF.cjs} +42 -42
- package/dist/{chunk-KZS2DFC2.cjs.map → chunk-ME346OJF.cjs.map} +1 -1
- package/dist/{chunk-UWY722RH.js → chunk-MR6RRXSD.js} +1 -1
- package/dist/chunk-MR6RRXSD.js.map +1 -0
- package/dist/{chunk-ZIZJDXUI.js → chunk-MZG3QQUR.js} +2 -2
- package/dist/{chunk-HB3IG2MC.js → chunk-OS5RFMW5.js} +3 -3
- package/dist/{chunk-VEXTUGUA.js → chunk-OWCN3BM6.js} +7 -7
- package/dist/{chunk-QVQLNKFS.js → chunk-P7ZENKIA.js} +2 -2
- package/dist/{chunk-T7AE7CKV.cjs → chunk-PCL6WYYT.cjs} +7 -7
- package/dist/{chunk-T7AE7CKV.cjs.map → chunk-PCL6WYYT.cjs.map} +1 -1
- package/dist/{chunk-2LKVYI7H.js → chunk-PLJAOZYZ.js} +6 -6
- package/dist/{chunk-L22CSZZU.cjs → chunk-QY3VTOB6.cjs} +18 -18
- package/dist/{chunk-L22CSZZU.cjs.map → chunk-QY3VTOB6.cjs.map} +1 -1
- package/dist/{chunk-Y2BYHTEN.cjs → chunk-SMW5Z4NW.cjs} +23 -23
- package/dist/{chunk-Y2BYHTEN.cjs.map → chunk-SMW5Z4NW.cjs.map} +1 -1
- package/dist/{chunk-LXWQLUBR.cjs → chunk-SW3K3JSP.cjs} +9 -7
- package/dist/chunk-SW3K3JSP.cjs.map +1 -0
- package/dist/{chunk-NKEOD2AD.cjs → chunk-TDYTAED2.cjs} +3 -3
- package/dist/{chunk-NKEOD2AD.cjs.map → chunk-TDYTAED2.cjs.map} +1 -1
- package/dist/{chunk-ZNEVGXMU.js → chunk-TXEI4PES.js} +112 -4
- package/dist/chunk-TXEI4PES.js.map +1 -0
- package/dist/{chunk-KZ3PIUCH.cjs → chunk-VNE2EHCD.cjs} +14 -14
- package/dist/{chunk-KZ3PIUCH.cjs.map → chunk-VNE2EHCD.cjs.map} +1 -1
- package/dist/{chunk-6I76UK2Z.cjs → chunk-XMECOGLY.cjs} +3 -3
- package/dist/{chunk-6I76UK2Z.cjs.map → chunk-XMECOGLY.cjs.map} +1 -1
- package/dist/{chunk-NK3M6F5A.cjs → chunk-Z3SRMLMK.cjs} +121 -13
- package/dist/chunk-Z3SRMLMK.cjs.map +1 -0
- package/dist/components/case-studies/index.cjs +10 -10
- package/dist/components/case-studies/index.js +4 -4
- package/dist/components/chat/index.cjs +4 -17
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +3 -16
- package/dist/components/chat/utils/index.d.ts +0 -2
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +5 -5
- package/dist/components/contact/index.js +4 -4
- package/dist/components/docs/index.cjs +7 -7
- package/dist/components/docs/index.js +6 -6
- package/dist/components/embeds/claude-embed.d.ts +15 -8
- package/dist/components/embeds/claude-embed.d.ts.map +1 -1
- package/dist/components/embeds/embed-viewer-frame.d.ts +8 -1
- package/dist/components/embeds/embed-viewer-frame.d.ts.map +1 -1
- package/dist/components/embeds/index.cjs +5 -5
- package/dist/components/embeds/index.js +4 -4
- package/dist/components/faq/index.cjs +6 -6
- package/dist/components/faq/index.js +5 -5
- package/dist/components/features/index.cjs +4 -4
- package/dist/components/features/index.js +3 -3
- package/dist/components/help-center-pages/index.cjs +25 -25
- package/dist/components/help-center-pages/index.js +16 -16
- package/dist/components/index.cjs +142 -154
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +14 -26
- package/dist/components/index.js.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +36 -36
- package/dist/components/meeting-scheduler/index.js +5 -5
- package/dist/components/navigation/index.cjs +4 -4
- package/dist/components/navigation/index.js +3 -3
- package/dist/components/onboarding-guides/index.cjs +8 -8
- package/dist/components/onboarding-guides/index.js +7 -7
- package/dist/components/related-content/index.cjs +6 -6
- package/dist/components/related-content/index.js +5 -5
- package/dist/components/tickets/index.cjs +8 -8
- package/dist/components/tickets/index.js +7 -7
- package/dist/components/ui/index.cjs +4 -16
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +3 -15
- package/dist/components/ui/markdown/sanitize.d.ts.map +1 -1
- package/dist/components/ui/table/table.d.ts +1 -1
- package/dist/components/ui/table/table.d.ts.map +1 -1
- package/dist/components/ui/table/types.d.ts +9 -0
- package/dist/components/ui/table/types.d.ts.map +1 -1
- package/dist/contexts/endpoints-runtime-context.d.ts +6 -0
- package/dist/contexts/endpoints-runtime-context.d.ts.map +1 -1
- package/dist/contexts/index.cjs +2 -2
- package/dist/contexts/index.js +1 -1
- package/dist/hooks/index.cjs +5 -3
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +4 -2
- package/dist/hooks/use-claude-mirror-src.d.ts +17 -0
- package/dist/hooks/use-claude-mirror-src.d.ts.map +1 -0
- package/dist/index.cjs +10 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +15 -13
- package/dist/utils/embed-proxy-auth-storage.d.ts.map +1 -1
- package/dist/utils/embed-url-converters.d.ts +20 -0
- package/dist/utils/embed-url-converters.d.ts.map +1 -1
- package/dist/utils/fullscreen-switch.d.ts +85 -0
- package/dist/utils/fullscreen-switch.d.ts.map +1 -0
- package/dist/utils/index.cjs +114 -0
- 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 +113 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/hooks/use-chat-attachments.ts +3 -3
- package/src/components/chat/hooks/use-chat-history-hydration.ts +2 -2
- package/src/components/chat/hooks/use-chat-identity.ts +5 -5
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +3 -3
- package/src/components/chat/utils/.index.md +1 -2
- package/src/components/chat/utils/chat-conversation-storage.ts +2 -2
- package/src/components/chat/utils/index.ts +3 -10
- package/src/components/embeds/claude-embed.tsx +41 -14
- package/src/components/embeds/embed-viewer-frame.tsx +77 -4
- package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +30 -0
- package/src/components/ui/markdown/rich/__tests__/shortcodes.test.ts +8 -0
- package/src/components/ui/markdown/sanitize.ts +4 -0
- package/src/components/ui/table/table.tsx +7 -2
- package/src/components/ui/table/types.ts +9 -0
- package/src/contexts/endpoints-runtime-context.tsx +6 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/use-claude-mirror-src.ts +43 -0
- package/src/utils/.embed-proxy-auth-storage.md +2 -2
- package/src/utils/embed-proxy-auth-storage.ts +19 -14
- package/src/utils/embed-url-converters.ts +45 -0
- package/src/utils/fullscreen-switch.ts +180 -0
- package/src/utils/index.ts +8 -6
- package/dist/chunk-6RSKK4E7.cjs.map +0 -1
- package/dist/chunk-CEAAOVCV.cjs.map +0 -1
- package/dist/chunk-EYXZF46V.js.map +0 -1
- package/dist/chunk-LXWQLUBR.cjs.map +0 -1
- package/dist/chunk-NK3M6F5A.cjs.map +0 -1
- package/dist/chunk-UWY722RH.js.map +0 -1
- package/dist/chunk-ZNEVGXMU.js.map +0 -1
- package/dist/components/chat/utils/chat-authed-fetch.d.ts +0 -15
- package/dist/components/chat/utils/chat-authed-fetch.d.ts.map +0 -1
- package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts +0 -16
- package/dist/components/chat/utils/chat-proxy-auth-storage.d.ts.map +0 -1
- package/src/components/chat/utils/.chat-authed-fetch.md +0 -25
- package/src/components/chat/utils/.chat-proxy-auth-storage.md +0 -38
- package/src/components/chat/utils/chat-authed-fetch.ts +0 -17
- package/src/components/chat/utils/chat-proxy-auth-storage.ts +0 -25
- /package/dist/{chunk-KL6ZDLDF.js.map → chunk-4NN7V443.js.map} +0 -0
- /package/dist/{chunk-G2PAUMV6.js.map → chunk-6STF67EF.js.map} +0 -0
- /package/dist/{chunk-6TDWCBQM.js.map → chunk-A2T266F3.js.map} +0 -0
- /package/dist/{chunk-ZXASQL3E.js.map → chunk-C5GKBUT7.js.map} +0 -0
- /package/dist/{chunk-O3JCKEVG.js.map → chunk-HOMYI5RR.js.map} +0 -0
- /package/dist/{chunk-BZ7B255K.js.map → chunk-KCAGMTJ6.js.map} +0 -0
- /package/dist/{chunk-DZ2Z7HRF.js.map → chunk-KO333Q2B.js.map} +0 -0
- /package/dist/{chunk-MQQM4NCN.js.map → chunk-LJBNHO6B.js.map} +0 -0
- /package/dist/{chunk-ZIZJDXUI.js.map → chunk-MZG3QQUR.js.map} +0 -0
- /package/dist/{chunk-HB3IG2MC.js.map → chunk-OS5RFMW5.js.map} +0 -0
- /package/dist/{chunk-VEXTUGUA.js.map → chunk-OWCN3BM6.js.map} +0 -0
- /package/dist/{chunk-QVQLNKFS.js.map → chunk-P7ZENKIA.js.map} +0 -0
- /package/dist/{chunk-2LKVYI7H.js.map → chunk-PLJAOZYZ.js.map} +0 -0
|
@@ -76,6 +76,51 @@ export function toFigmaOriginalUrl(url: string): string {
|
|
|
76
76
|
return url.replace(/\?.*$/, '')
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* The self-hosted MIRROR url for a claude artifact url — the whole
|
|
81
|
+
* mirror mechanism is UNDER THE HOOD: the viewer detects a claude url,
|
|
82
|
+
* DERIVES the mirror location from the artifact's own id under the
|
|
83
|
+
* host's configured storage-view proxy base, and frames the downloaded
|
|
84
|
+
* copy from there. No per-link data, no props, no shortcode changes —
|
|
85
|
+
* 100% transparent to every consumer.
|
|
86
|
+
*
|
|
87
|
+
* `storageViewBaseUrl` comes from `EndpointsRuntime` — the SAME
|
|
88
|
+
* host-overridable proxy-path mechanism every other lib→API call uses
|
|
89
|
+
* (a reverse-proxied embedder remaps it; a host without the proxy omits
|
|
90
|
+
* it and gets `null` here, i.e. no mirror leg at all).
|
|
91
|
+
*
|
|
92
|
+
* `null` when the base is absent or the url carries no artifact id. The
|
|
93
|
+
* derived url is the configured base + a validated uuid — safe as a
|
|
94
|
+
* frame source without further checks. KEEP THE OBJECT NAMING IN SYNC
|
|
95
|
+
* with the hub's `lib/data/design-brief-mirror.cjs` (bucket +
|
|
96
|
+
* `<uuid>.html`) — that module owns the ingest/audit half.
|
|
97
|
+
*/
|
|
98
|
+
export function toClaudeMirrorPath(
|
|
99
|
+
url: string | null | undefined,
|
|
100
|
+
storageViewBaseUrl: string | null | undefined,
|
|
101
|
+
): string | null {
|
|
102
|
+
if (!url || !storageViewBaseUrl) return null
|
|
103
|
+
try {
|
|
104
|
+
const u = new URL(url)
|
|
105
|
+
const host = u.hostname.toLowerCase()
|
|
106
|
+
const id =
|
|
107
|
+
(host === 'claude.ai' &&
|
|
108
|
+
/^\/(?:code\/artifact|public\/artifacts)\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:[/?#]|$)/i.exec(
|
|
109
|
+
u.pathname,
|
|
110
|
+
)?.[1]) ||
|
|
111
|
+
(host === 'claude.site' &&
|
|
112
|
+
/^\/artifacts\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:[/?#]|$)/i.exec(
|
|
113
|
+
u.pathname,
|
|
114
|
+
)?.[1]) ||
|
|
115
|
+
null
|
|
116
|
+
return id
|
|
117
|
+
? `${storageViewBaseUrl.replace(/\/$/, '')}/design-briefs/${id.toLowerCase()}.html`
|
|
118
|
+
: null
|
|
119
|
+
} catch {
|
|
120
|
+
return null
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
79
124
|
/**
|
|
80
125
|
* The EMBED url for a published Claude artifact, or `null` when the link is not
|
|
81
126
|
* one we can frame — the Claude counterpart of `toFigmaEmbedUrl`.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FullscreenSwitchController — the ONE place fullscreen enter/exit lives.
|
|
3
|
+
*
|
|
4
|
+
* Framework-agnostic (no React): the consumer passes callbacks (and, for
|
|
5
|
+
* page-level surfaces, the <html> mask classes); the controller owns the
|
|
6
|
+
* Fullscreen API calls, webkit fallbacks, and the flicker-free switch
|
|
7
|
+
* choreography. Originally extracted from the hub's company-hub deck (PR
|
|
8
|
+
* #737); moved into the lib so EVERY fullscreen surface — the deck, the
|
|
9
|
+
* embed viewers — shares one implementation instead of re-deriving the
|
|
10
|
+
* event-ordering lessons below. The hub's `lib/utils/fullscreen-switch.ts`
|
|
11
|
+
* re-exports from here (extractItems shim precedent).
|
|
12
|
+
*
|
|
13
|
+
* Two shapes of consumer:
|
|
14
|
+
* - PAGE-LEVEL (the deck): no `target` — fullscreens
|
|
15
|
+
* `document.documentElement`, uses the mask classes + geometry pulses.
|
|
16
|
+
* - ELEMENT-LEVEL (embed viewers): pass `target` — fullscreens one
|
|
17
|
+
* element; classes/pulses are optional and simply skipped when absent.
|
|
18
|
+
*
|
|
19
|
+
* Invariants (each guards a bug found while building the deck's fullscreen):
|
|
20
|
+
* - Fullscreen STATE follows the fullscreenchange event exclusively (never
|
|
21
|
+
* set optimistically): Esc, keyboard shortcuts, buttons and browser
|
|
22
|
+
* chrome all converge on one listener.
|
|
23
|
+
* - The switching mask (when configured) goes up PRE-EMPTIVELY:
|
|
24
|
+
* Chrome/Safari PAINT resized frames BEFORE fullscreenchange fires
|
|
25
|
+
* (whatwg/fullscreen#74), so masking inside the change event is already
|
|
26
|
+
* too late. `toggle()` masks before requesting; an Escape keydown
|
|
27
|
+
* listener (capture) masks the one exit path that skips toggle(); the
|
|
28
|
+
* change event remains the fallback for browser-chrome-initiated
|
|
29
|
+
* transitions.
|
|
30
|
+
* - The swap is a multi-frame viewport animation (macOS especially): one
|
|
31
|
+
* rAF re-anchor is NOT enough. While masked, every resize fires
|
|
32
|
+
* onGeometryPulse (re-measure + re-anchor under a constant scrollY);
|
|
33
|
+
* quiet resizes for `quietMs` (or the `capMs` hard cap — a rejected
|
|
34
|
+
* fullscreen request after a pre-emptive mask must never wedge the mask
|
|
35
|
+
* up) end the switch.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/** Webkit-prefixed Fullscreen API fallbacks (Safari < 16.4 desktop, older
|
|
39
|
+
* iPadOS; iOS 26+ ships the standard API — isSupported() gates elsewhere). */
|
|
40
|
+
type FsDocument = Document & {
|
|
41
|
+
webkitFullscreenElement?: Element | null
|
|
42
|
+
webkitFullscreenEnabled?: boolean
|
|
43
|
+
webkitExitFullscreen?: () => void
|
|
44
|
+
}
|
|
45
|
+
type FsElement = HTMLElement & { webkitRequestFullscreen?: () => void }
|
|
46
|
+
|
|
47
|
+
const fullscreenElementOf = (doc: FsDocument) => doc.fullscreenElement ?? doc.webkitFullscreenElement ?? null
|
|
48
|
+
|
|
49
|
+
export interface FullscreenSwitchOptions {
|
|
50
|
+
/** The element to fullscreen. Omit for page-level surfaces (the deck):
|
|
51
|
+
* `document.documentElement` — window scrolling survives, which
|
|
52
|
+
* element-level fullscreen would freeze. A callback so refs resolve at
|
|
53
|
+
* toggle time, not construction time. */
|
|
54
|
+
target?: () => HTMLElement | null
|
|
55
|
+
/** Held on <html> while fullscreen is ACTIVE (steady-state styling).
|
|
56
|
+
* Optional — element-level consumers style off their own state. */
|
|
57
|
+
activeClass?: string
|
|
58
|
+
/** Held on <html> for the DURATION of an enter/exit swap (the
|
|
59
|
+
* mask/curtain). Optional — see `activeClass`. */
|
|
60
|
+
switchingClass?: string
|
|
61
|
+
/** New fullscreen state, straight from the change event. For a `target`
|
|
62
|
+
* consumer this is "MY element is the fullscreen element". */
|
|
63
|
+
onFullscreenChange: (isFullscreen: boolean) => void
|
|
64
|
+
/** Geometry moved under a constant scrollY — re-measure + re-anchor.
|
|
65
|
+
* Optional; fired once per resize during the swap and once more when
|
|
66
|
+
* the switch ends. */
|
|
67
|
+
onGeometryPulse?: () => void
|
|
68
|
+
/** Switch ends after resizes have been quiet this long (default 200ms). */
|
|
69
|
+
quietMs?: number
|
|
70
|
+
/** Hard cap on a switch, mask-wedge failsafe (default 1000ms). */
|
|
71
|
+
capMs?: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const DEFAULT_QUIET_MS = 200
|
|
75
|
+
const DEFAULT_CAP_MS = 1000
|
|
76
|
+
|
|
77
|
+
export class FullscreenSwitchController {
|
|
78
|
+
private quietTimer = 0
|
|
79
|
+
private capTimer = 0
|
|
80
|
+
private attached = false
|
|
81
|
+
|
|
82
|
+
constructor(private readonly opts: FullscreenSwitchOptions) {}
|
|
83
|
+
|
|
84
|
+
/** SSR-safe feature detection — call post-mount to gate the affordance. */
|
|
85
|
+
static isSupported(): boolean {
|
|
86
|
+
if (typeof document === 'undefined') return false
|
|
87
|
+
const doc = document as FsDocument
|
|
88
|
+
const el = document.documentElement as FsElement
|
|
89
|
+
return (
|
|
90
|
+
Boolean(el.requestFullscreen || el.webkitRequestFullscreen) &&
|
|
91
|
+
(doc.fullscreenEnabled ?? doc.webkitFullscreenEnabled ?? true) !== false
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get isFullscreen(): boolean {
|
|
96
|
+
const fs = fullscreenElementOf(document as FsDocument)
|
|
97
|
+
const target = this.opts.target?.()
|
|
98
|
+
return target ? fs === target : Boolean(fs)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
attach(): void {
|
|
102
|
+
if (this.attached) return
|
|
103
|
+
this.attached = true
|
|
104
|
+
const doc = document as FsDocument
|
|
105
|
+
doc.addEventListener('fullscreenchange', this.onChange)
|
|
106
|
+
doc.addEventListener('webkitfullscreenchange', this.onChange)
|
|
107
|
+
window.addEventListener('keydown', this.onEscape, true)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
detach(): void {
|
|
111
|
+
if (!this.attached) return
|
|
112
|
+
this.attached = false
|
|
113
|
+
const doc = document as FsDocument
|
|
114
|
+
doc.removeEventListener('fullscreenchange', this.onChange)
|
|
115
|
+
doc.removeEventListener('webkitfullscreenchange', this.onChange)
|
|
116
|
+
window.removeEventListener('keydown', this.onEscape, true)
|
|
117
|
+
window.removeEventListener('resize', this.onResize)
|
|
118
|
+
window.clearTimeout(this.quietTimer)
|
|
119
|
+
window.clearTimeout(this.capTimer)
|
|
120
|
+
if (this.opts.activeClass) doc.documentElement.classList.remove(this.opts.activeClass)
|
|
121
|
+
if (this.opts.switchingClass) doc.documentElement.classList.remove(this.opts.switchingClass)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Mask first (pre-emptive — see header), then request/exit. */
|
|
125
|
+
toggle = (): void => {
|
|
126
|
+
const doc = document as FsDocument
|
|
127
|
+
this.beginSwitch()
|
|
128
|
+
if (fullscreenElementOf(doc)) {
|
|
129
|
+
if (doc.exitFullscreen) doc.exitFullscreen().catch(() => {})
|
|
130
|
+
else doc.webkitExitFullscreen?.()
|
|
131
|
+
} else {
|
|
132
|
+
const el = (this.opts.target?.() ?? document.documentElement) as FsElement
|
|
133
|
+
// navigationUI:'hide' = prefer screen space over browser nav chrome.
|
|
134
|
+
if (el.requestFullscreen) el.requestFullscreen({ navigationUI: 'hide' }).catch(() => {})
|
|
135
|
+
else el.webkitRequestFullscreen?.()
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Raise the mask + start tracking. Idempotent — safe from the pre-emptive
|
|
140
|
+
* paths (toggle, Escape) AND again from the change event. */
|
|
141
|
+
private beginSwitch = (): void => {
|
|
142
|
+
if (this.opts.switchingClass) document.documentElement.classList.add(this.opts.switchingClass)
|
|
143
|
+
window.addEventListener('resize', this.onResize)
|
|
144
|
+
window.clearTimeout(this.capTimer)
|
|
145
|
+
this.capTimer = window.setTimeout(this.endSwitch, this.opts.capMs ?? DEFAULT_CAP_MS)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private endSwitch = (): void => {
|
|
149
|
+
window.clearTimeout(this.quietTimer)
|
|
150
|
+
window.clearTimeout(this.capTimer)
|
|
151
|
+
window.removeEventListener('resize', this.onResize)
|
|
152
|
+
this.opts.onGeometryPulse?.()
|
|
153
|
+
if (this.opts.switchingClass) document.documentElement.classList.remove(this.opts.switchingClass)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private armQuiet = (): void => {
|
|
157
|
+
window.clearTimeout(this.quietTimer)
|
|
158
|
+
this.quietTimer = window.setTimeout(this.endSwitch, this.opts.quietMs ?? DEFAULT_QUIET_MS)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private onResize = (): void => {
|
|
162
|
+
this.opts.onGeometryPulse?.()
|
|
163
|
+
this.armQuiet()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Escape is the one exit path that skips toggle() — pre-mask on the
|
|
167
|
+
* keydown (capture phase), before the browser begins the swap. */
|
|
168
|
+
private onEscape = (e: KeyboardEvent): void => {
|
|
169
|
+
if (e.key === 'Escape' && this.isFullscreen) this.beginSwitch()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private onChange = (): void => {
|
|
173
|
+
const fs = this.isFullscreen
|
|
174
|
+
if (this.opts.activeClass) document.documentElement.classList.toggle(this.opts.activeClass, fs)
|
|
175
|
+
this.beginSwitch()
|
|
176
|
+
requestAnimationFrame(() => this.opts.onGeometryPulse?.())
|
|
177
|
+
this.armQuiet()
|
|
178
|
+
this.opts.onFullscreenChange(fs)
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -172,12 +172,13 @@ export {
|
|
|
172
172
|
|
|
173
173
|
// Embed-surface auth — generic across chat AND ticket center (and any
|
|
174
174
|
// future embedded React component that needs to identify as the proxied
|
|
175
|
-
// customer).
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
175
|
+
// customer). The bearer is a PLATFORM API KEY (minted in the hub's
|
|
176
|
+
// /admin/api-keys; the old shared CHAT_PROXY_SECRET env is removed
|
|
177
|
+
// hub-side). Wire headers / storage key are unchanged (`X-Chat-*`,
|
|
178
|
+
// `chat.proxy-auth.v1`) — those are server / deployment contracts. The
|
|
179
|
+
// CLIENT-side rename frees non-chat surfaces from importing a
|
|
180
|
+
// chat-prefixed symbol; the old chat-prefixed aliases are DELETED —
|
|
181
|
+
// these Embed* exports are the only names.
|
|
181
182
|
export {
|
|
182
183
|
embedAuthedFetch,
|
|
183
184
|
setEmbedAuthAdapter,
|
|
@@ -334,6 +335,7 @@ export {
|
|
|
334
335
|
type ContentRefGridSize,
|
|
335
336
|
} from './content-ref-groups'
|
|
336
337
|
export { extractItems, extractItemId } from './extract-items'
|
|
338
|
+
export { FullscreenSwitchController, type FullscreenSwitchOptions } from './fullscreen-switch'
|
|
337
339
|
export { buildSuggestionUrl, type SuggestionUrlOptions } from './suggestion-url'
|
|
338
340
|
|
|
339
341
|
// Embedder-configurable content-URL composer for the existing
|