@flamingo-stack/openframe-frontend-core 0.0.556 → 0.0.557-snapshot.20260818183037
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-Q5SZ2QTZ.cjs → chunk-3TKG7SW6.cjs} +42 -42
- package/dist/{chunk-Q5SZ2QTZ.cjs.map → chunk-3TKG7SW6.cjs.map} +1 -1
- package/dist/{chunk-5JWLZJK5.js → chunk-4VLGJEKQ.js} +2 -2
- package/dist/{chunk-7Q7GFIFB.cjs → chunk-53GNFRVQ.cjs} +7 -7
- package/dist/{chunk-7Q7GFIFB.cjs.map → chunk-53GNFRVQ.cjs.map} +1 -1
- package/dist/{chunk-VF4DCOPD.js → chunk-5JHJX7OX.js} +5 -5
- package/dist/{chunk-Z3R3LOC5.cjs → chunk-5WQPOH27.cjs} +5 -5
- package/dist/{chunk-Z3R3LOC5.cjs.map → chunk-5WQPOH27.cjs.map} +1 -1
- package/dist/{chunk-VXNMOGRP.js → chunk-C5HQCF4R.js} +6 -6
- package/dist/{chunk-SXMJLNOF.cjs → chunk-CWQSUYVV.cjs} +3 -3
- package/dist/{chunk-SXMJLNOF.cjs.map → chunk-CWQSUYVV.cjs.map} +1 -1
- package/dist/{chunk-JDUPAHJR.cjs → chunk-DHSIAIFG.cjs} +18 -18
- package/dist/{chunk-JDUPAHJR.cjs.map → chunk-DHSIAIFG.cjs.map} +1 -1
- package/dist/{chunk-YM2WHYYK.js → chunk-DNPQ2U7P.js} +4 -4
- package/dist/{chunk-JXJ4FTKN.js → chunk-DV4CSNZD.js} +3 -3
- package/dist/{chunk-5756Q6UN.js → chunk-E26KVZJM.js} +3 -3
- package/dist/{chunk-C74PZU6M.cjs → chunk-FCCSHC3H.cjs} +32 -32
- package/dist/{chunk-C74PZU6M.cjs.map → chunk-FCCSHC3H.cjs.map} +1 -1
- package/dist/{chunk-JRWOHH7K.js → chunk-FVHFBEXH.js} +2 -2
- package/dist/{chunk-BZKUID4R.cjs → chunk-GYQHUJWR.cjs} +14 -14
- package/dist/{chunk-BZKUID4R.cjs.map → chunk-GYQHUJWR.cjs.map} +1 -1
- package/dist/{chunk-XGBVHQP7.js → chunk-IHXUZBBV.js} +3249 -2558
- package/dist/chunk-IHXUZBBV.js.map +1 -0
- package/dist/{chunk-WBQ3NOH7.js → chunk-KL6ZDLDF.js} +2 -2
- package/dist/{chunk-FZT7BYNF.js → chunk-LM6NDYGD.js} +2 -2
- package/dist/{chunk-LZD3VSPS.cjs → chunk-N3OGB543.cjs} +12 -12
- package/dist/{chunk-LZD3VSPS.cjs.map → chunk-N3OGB543.cjs.map} +1 -1
- package/dist/{chunk-VJTD2DGF.cjs → chunk-NK3M6F5A.cjs} +39 -30
- package/dist/chunk-NK3M6F5A.cjs.map +1 -0
- package/dist/{chunk-DFJ7TWH6.cjs → chunk-NKEOD2AD.cjs} +3 -3
- package/dist/{chunk-DFJ7TWH6.cjs.map → chunk-NKEOD2AD.cjs.map} +1 -1
- package/dist/{chunk-HYABNMBN.cjs → chunk-R3OCP4A7.cjs} +76 -76
- package/dist/{chunk-HYABNMBN.cjs.map → chunk-R3OCP4A7.cjs.map} +1 -1
- package/dist/{chunk-S4LL6QI6.cjs → chunk-R3TXAMMB.cjs} +1768 -1077
- package/dist/chunk-R3TXAMMB.cjs.map +1 -0
- package/dist/{chunk-5M4PS3XX.js → chunk-S3NZZKNU.js} +3 -3
- package/dist/{chunk-ICG7JRYT.cjs → chunk-SI64DC72.cjs} +40 -40
- package/dist/{chunk-ICG7JRYT.cjs.map → chunk-SI64DC72.cjs.map} +1 -1
- package/dist/{chunk-CGUSNV6R.js → chunk-UVGFICZT.js} +8 -8
- package/dist/{chunk-CRGIXNUE.cjs → chunk-VNWGXQJD.cjs} +23 -23
- package/dist/{chunk-CRGIXNUE.cjs.map → chunk-VNWGXQJD.cjs.map} +1 -1
- package/dist/{chunk-HOEOGFQM.cjs → chunk-XDMRN3SG.cjs} +97 -97
- package/dist/{chunk-HOEOGFQM.cjs.map → chunk-XDMRN3SG.cjs.map} +1 -1
- package/dist/{chunk-BNMKHG2L.cjs → chunk-XL2G2HHJ.cjs} +4 -4
- package/dist/{chunk-BNMKHG2L.cjs.map → chunk-XL2G2HHJ.cjs.map} +1 -1
- package/dist/{chunk-5EES5HD4.js → chunk-YUVCH2LX.js} +6 -6
- package/dist/{chunk-FLSEJSTN.js → chunk-Z5FN5VTC.js} +2 -2
- package/dist/{chunk-VRX6Y6A7.js → chunk-ZNEVGXMU.js} +23 -14
- package/dist/chunk-ZNEVGXMU.js.map +1 -0
- package/dist/{chunk-WX5UCLL7.js → chunk-ZSZ24UY6.js} +2 -2
- package/dist/components/case-studies/index.cjs +9 -9
- package/dist/components/case-studies/index.js +3 -3
- package/dist/components/chat/index.cjs +3 -3
- package/dist/components/chat/index.js +2 -2
- package/dist/components/contact/index.cjs +4 -4
- package/dist/components/contact/index.js +3 -3
- package/dist/components/docs/index.cjs +6 -6
- package/dist/components/docs/index.js +5 -5
- package/dist/components/embeds/index.cjs +4 -4
- package/dist/components/embeds/index.js +3 -3
- package/dist/components/faq/index.cjs +5 -5
- package/dist/components/faq/index.js +4 -4
- package/dist/components/features/board/aim.d.ts +57 -0
- package/dist/components/features/board/aim.d.ts.map +1 -0
- package/dist/components/features/board/board-column-header.d.ts.map +1 -1
- package/dist/components/features/board/board-column.d.ts +8 -4
- package/dist/components/features/board/board-column.d.ts.map +1 -1
- package/dist/components/features/board/board.d.ts +15 -4
- package/dist/components/features/board/board.d.ts.map +1 -1
- package/dist/components/features/board/drop-aim.d.ts +34 -0
- package/dist/components/features/board/drop-aim.d.ts.map +1 -0
- package/dist/components/features/board/lane-geometry.d.ts +22 -0
- package/dist/components/features/board/lane-geometry.d.ts.map +1 -0
- package/dist/components/features/board/pending-move.d.ts +77 -0
- package/dist/components/features/board/pending-move.d.ts.map +1 -0
- package/dist/components/features/board/resolve-drop.d.ts +19 -0
- package/dist/components/features/board/resolve-drop.d.ts.map +1 -0
- package/dist/components/features/board/ticket-card.d.ts +25 -9
- package/dist/components/features/board/ticket-card.d.ts.map +1 -1
- package/dist/components/features/board/use-board-collapse.d.ts.map +1 -1
- package/dist/components/features/board/use-lane-scroll-anchor.d.ts +27 -0
- package/dist/components/features/board/use-lane-scroll-anchor.d.ts.map +1 -0
- package/dist/components/features/index.cjs +9 -3
- package/dist/components/features/index.cjs.map +1 -1
- package/dist/components/features/index.d.ts +1 -0
- package/dist/components/features/index.d.ts.map +1 -1
- package/dist/components/features/index.js +8 -2
- package/dist/components/features/sortable-list/index.d.ts +4 -0
- package/dist/components/features/sortable-list/index.d.ts.map +1 -0
- package/dist/components/features/sortable-list/slot-geometry.d.ts +57 -0
- package/dist/components/features/sortable-list/slot-geometry.d.ts.map +1 -0
- package/dist/components/features/sortable-list/sortable-list.d.ts +50 -0
- package/dist/components/features/sortable-list/sortable-list.d.ts.map +1 -0
- package/dist/components/features/sortable-list/use-sortable-item.d.ts +29 -0
- package/dist/components/features/sortable-list/use-sortable-item.d.ts.map +1 -0
- package/dist/components/features/video.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.cjs +24 -24
- package/dist/components/help-center-pages/index.js +15 -15
- package/dist/components/index.cjs +143 -137
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +19 -13
- package/dist/components/index.js.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +34 -34
- package/dist/components/meeting-scheduler/index.js +4 -4
- package/dist/components/navigation/index.cjs +3 -3
- package/dist/components/navigation/index.js +2 -2
- package/dist/components/onboarding-guides/index.cjs +7 -7
- package/dist/components/onboarding-guides/index.js +6 -6
- package/dist/components/related-content/index.cjs +5 -5
- package/dist/components/related-content/index.js +4 -4
- package/dist/components/tickets/index.cjs +7 -7
- package/dist/components/tickets/index.js +6 -6
- package/dist/components/ui/index.cjs +3 -3
- package/dist/components/ui/index.js +2 -2
- package/dist/components/ui/square-avatar.d.ts.map +1 -1
- package/dist/hooks/index.cjs +6 -2
- 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 +5 -1
- package/dist/hooks/use-authed-asset-src.d.ts +16 -0
- package/dist/hooks/use-authed-asset-src.d.ts.map +1 -0
- package/dist/hooks/use-authed-image-src.d.ts +15 -6
- package/dist/hooks/use-authed-image-src.d.ts.map +1 -1
- package/dist/index.cjs +13 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +12 -2
- package/dist/utils/auto-scroll-ancestors.d.ts +43 -0
- package/dist/utils/auto-scroll-ancestors.d.ts.map +1 -0
- package/dist/utils/drag-effect.d.ts +21 -0
- package/dist/utils/drag-effect.d.ts.map +1 -0
- package/dist/utils/embed-authed-fetch.d.ts +24 -10
- package/dist/utils/embed-authed-fetch.d.ts.map +1 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/scroll-parent.d.ts +11 -0
- package/dist/utils/scroll-parent.d.ts.map +1 -0
- package/package.json +6 -3
- package/src/__tests__/board-aim.test.ts +152 -0
- package/src/__tests__/board-pending-move.test.ts +113 -0
- package/src/__tests__/board-resolve-drop.test.ts +68 -0
- package/src/__tests__/sortable-slot-geometry.test.ts +105 -0
- package/src/components/features/board/.board-column.md +17 -4
- package/src/components/features/board/.board.md +11 -7
- package/src/components/features/board/.ticket-card.md +27 -5
- package/src/components/features/board/aim.ts +131 -0
- package/src/components/features/board/board-column-header.tsx +2 -9
- package/src/components/features/board/board-column.tsx +137 -66
- package/src/components/features/board/board.tsx +501 -258
- package/src/components/features/board/drop-aim.ts +50 -0
- package/src/components/features/board/lane-geometry.ts +44 -0
- package/src/components/features/board/pending-move.ts +116 -0
- package/src/components/features/board/resolve-drop.ts +28 -0
- package/src/components/features/board/ticket-card.tsx +256 -47
- package/src/components/features/board/use-board-collapse.ts +16 -14
- package/src/components/features/board/use-lane-scroll-anchor.ts +79 -0
- package/src/components/features/index.ts +1 -0
- package/src/components/features/sortable-list/.sortable-list.md +82 -0
- package/src/components/features/sortable-list/index.ts +3 -0
- package/src/components/features/sortable-list/slot-geometry.ts +100 -0
- package/src/components/features/sortable-list/sortable-list.tsx +270 -0
- package/src/components/features/sortable-list/use-sortable-item.ts +92 -0
- package/src/components/features/video.tsx +13 -2
- package/src/components/ui/square-avatar.tsx +5 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-authed-asset-src.ts +98 -0
- package/src/hooks/use-authed-image-src.ts +15 -84
- package/src/stories/.TicketCard.stories.md +6 -12
- package/src/stories/Board.stories.tsx +16 -7
- package/src/stories/TicketCard.stories.tsx +38 -76
- package/src/utils/__tests__/embed-authed-fetch.test.ts +50 -1
- package/src/utils/auto-scroll-ancestors.ts +90 -0
- package/src/utils/drag-effect.ts +26 -0
- package/src/utils/embed-authed-fetch.ts +31 -14
- package/src/utils/scroll-parent.ts +23 -0
- package/dist/chunk-S4LL6QI6.cjs.map +0 -1
- package/dist/chunk-VJTD2DGF.cjs.map +0 -1
- package/dist/chunk-VRX6Y6A7.js.map +0 -1
- package/dist/chunk-XGBVHQP7.js.map +0 -1
- /package/dist/{chunk-5JWLZJK5.js.map → chunk-4VLGJEKQ.js.map} +0 -0
- /package/dist/{chunk-VF4DCOPD.js.map → chunk-5JHJX7OX.js.map} +0 -0
- /package/dist/{chunk-VXNMOGRP.js.map → chunk-C5HQCF4R.js.map} +0 -0
- /package/dist/{chunk-YM2WHYYK.js.map → chunk-DNPQ2U7P.js.map} +0 -0
- /package/dist/{chunk-JXJ4FTKN.js.map → chunk-DV4CSNZD.js.map} +0 -0
- /package/dist/{chunk-5756Q6UN.js.map → chunk-E26KVZJM.js.map} +0 -0
- /package/dist/{chunk-JRWOHH7K.js.map → chunk-FVHFBEXH.js.map} +0 -0
- /package/dist/{chunk-WBQ3NOH7.js.map → chunk-KL6ZDLDF.js.map} +0 -0
- /package/dist/{chunk-FZT7BYNF.js.map → chunk-LM6NDYGD.js.map} +0 -0
- /package/dist/{chunk-5M4PS3XX.js.map → chunk-S3NZZKNU.js.map} +0 -0
- /package/dist/{chunk-CGUSNV6R.js.map → chunk-UVGFICZT.js.map} +0 -0
- /package/dist/{chunk-5EES5HD4.js.map → chunk-YUVCH2LX.js.map} +0 -0
- /package/dist/{chunk-FLSEJSTN.js.map → chunk-Z5FN5VTC.js.map} +0 -0
- /package/dist/{chunk-WX5UCLL7.js.map → chunk-ZSZ24UY6.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
-
import { embedAuthedFetch, setEmbedAuthAdapter } from '../embed-authed-fetch'
|
|
2
|
+
import { embedAuthedFetch, needsBearerAssetFetch, setEmbedAuthAdapter } from '../embed-authed-fetch'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Tests focus on the same-origin guard rather than the proxy-auth
|
|
@@ -205,3 +205,52 @@ describe('embedAuthedFetch adapter.allowedOrigins (native-shell cross-origin san
|
|
|
205
205
|
expect(() => embedAuthedFetch('javascript:alert(1)')).toThrow(/non-http\(s\)/i)
|
|
206
206
|
})
|
|
207
207
|
})
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* `needsBearerAssetFetch` decides whether a `<img>` / `<track>` URL has to be
|
|
211
|
+
* blob-fetched (see `useAuthedAssetSrc`). The signal is the adapter's
|
|
212
|
+
* `Authorization` header — i.e. the host authenticates by HEADER, so nothing
|
|
213
|
+
* the browser fetches on its own carries auth, same-origin included.
|
|
214
|
+
*/
|
|
215
|
+
describe('needsBearerAssetFetch (native subresources that cannot carry a header)', () => {
|
|
216
|
+
const bearer = { getHeaders: () => ({ Authorization: 'Bearer t' }) }
|
|
217
|
+
|
|
218
|
+
afterEach(() => {
|
|
219
|
+
setEmbedAuthAdapter(null)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('is false with no adapter registered (the hub — cookies or nothing)', () => {
|
|
223
|
+
expect(needsBearerAssetFetch('/content/api/captions/release/1')).toBe(false)
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('is false in cookie mode (adapter supplies no Authorization)', () => {
|
|
227
|
+
setEmbedAuthAdapter({ getHeaders: () => ({}) })
|
|
228
|
+
expect(needsBearerAssetFetch('/content/api/captions/release/1')).toBe(false)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it('is TRUE for a relative proxy path in header-auth mode (dev-ticket web)', () => {
|
|
232
|
+
setEmbedAuthAdapter(bearer)
|
|
233
|
+
expect(needsBearerAssetFetch('/content/api/captions/release/1')).toBe(true)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('is TRUE for an absolute same-origin URL in header-auth mode', () => {
|
|
237
|
+
setEmbedAuthAdapter(bearer)
|
|
238
|
+
expect(needsBearerAssetFetch('http://localhost:3000/content/api/image-proxy?u=x')).toBe(true)
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
it('is TRUE for a cross-origin gateway the adapter sanctions (native shell)', () => {
|
|
242
|
+
setEmbedAuthAdapter({ ...bearer, allowedOrigins: ['https://gateway.example'] })
|
|
243
|
+
expect(needsBearerAssetFetch('https://gateway.example/content/api/captions/release/1')).toBe(true)
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('is false for a third-party origin the bearer does not belong to', () => {
|
|
247
|
+
setEmbedAuthAdapter({ ...bearer, allowedOrigins: ['https://gateway.example'] })
|
|
248
|
+
expect(needsBearerAssetFetch('https://cdn.example.com/pic.png')).toBe(false)
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('is false for non-http(s) schemes (data:/blob: assets load natively)', () => {
|
|
252
|
+
setEmbedAuthAdapter(bearer)
|
|
253
|
+
expect(needsBearerAssetFetch('data:image/png;base64,AAAA')).toBe(false)
|
|
254
|
+
expect(needsBearerAssetFetch('blob:http://localhost:3000/abc')).toBe(false)
|
|
255
|
+
})
|
|
256
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine'
|
|
2
|
+
import {
|
|
3
|
+
autoScrollForElements,
|
|
4
|
+
autoScrollWindowForElements,
|
|
5
|
+
} from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element'
|
|
6
|
+
import { unsafeOverflowAutoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/unsafe-overflow/element'
|
|
7
|
+
import { scrollableAncestorsOf } from './scroll-parent'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* How far past a scroller's edge a drag still counts as "scroll this".
|
|
11
|
+
*
|
|
12
|
+
* Big on purpose: past the edge there is nothing else to hit, so the only
|
|
13
|
+
* question is whether the intent is obvious, and dragging beyond a container is
|
|
14
|
+
* about as obvious as intent gets.
|
|
15
|
+
*/
|
|
16
|
+
const OVERFLOW_REACH = 5000
|
|
17
|
+
|
|
18
|
+
const overflow = () => ({
|
|
19
|
+
forTopEdge: { top: OVERFLOW_REACH, left: OVERFLOW_REACH, right: OVERFLOW_REACH },
|
|
20
|
+
forBottomEdge: { bottom: OVERFLOW_REACH, left: OVERFLOW_REACH, right: OVERFLOW_REACH },
|
|
21
|
+
forLeftEdge: { left: OVERFLOW_REACH, top: OVERFLOW_REACH, bottom: OVERFLOW_REACH },
|
|
22
|
+
forRightEdge: { right: OVERFLOW_REACH, top: OVERFLOW_REACH, bottom: OVERFLOW_REACH },
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
/** Straight up and straight down only — no sideways reach at all. */
|
|
26
|
+
const verticalOverflow = () => ({
|
|
27
|
+
forTopEdge: { top: OVERFLOW_REACH },
|
|
28
|
+
forBottomEdge: { bottom: OVERFLOW_REACH },
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Registers drag auto-scroll for one scroller, both **inside** its edges and
|
|
33
|
+
* **past** them.
|
|
34
|
+
*
|
|
35
|
+
* Pragmatic's over-element scrolling only engages in a band just inside the
|
|
36
|
+
* edge, so a drag that has already left the container stops scrolling it — you
|
|
37
|
+
* have to hunt for the strip where it works. dnd-kit kept scrolling however far
|
|
38
|
+
* out you went, and `unsafeOverflowAutoScrollForElements` is Pragmatic's own
|
|
39
|
+
* answer for that; "unsafe" here only means it can reach a container the pointer
|
|
40
|
+
* is not over, which is exactly what is wanted.
|
|
41
|
+
*/
|
|
42
|
+
export function autoScrollBothWays(element: HTMLElement): () => void {
|
|
43
|
+
return combine(
|
|
44
|
+
autoScrollForElements({ element }),
|
|
45
|
+
unsafeOverflowAutoScrollForElements({ element, getOverflow: overflow }),
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Auto-scroll for one of several scrollers standing side by side — a board lane.
|
|
51
|
+
*
|
|
52
|
+
* Same as {@link autoScrollBothWays} except that its reach past the edges is
|
|
53
|
+
* vertical only, and that is the whole point. Lanes sit shoulder to shoulder, so
|
|
54
|
+
* a reach that also spreads sideways puts a pointer below the board inside
|
|
55
|
+
* EVERY lane's overflow region at once and scrolls all of them together. Keeping
|
|
56
|
+
* the region to the lane's own width means the pointer is below exactly one
|
|
57
|
+
* lane, and only that lane moves — which is what a board is expected to do.
|
|
58
|
+
*/
|
|
59
|
+
export function autoScrollColumn(element: HTMLElement): () => void {
|
|
60
|
+
return combine(
|
|
61
|
+
autoScrollForElements({ element }),
|
|
62
|
+
unsafeOverflowAutoScrollForElements({ element, getOverflow: verticalOverflow }),
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Registers auto-scroll on every scrollable ancestor of `element`, and on the
|
|
68
|
+
* window.
|
|
69
|
+
*
|
|
70
|
+
* dnd-kit walked the ancestor chain for you; Pragmatic makes each scroller opt
|
|
71
|
+
* in by name, which is why dragging towards the edge of the screen stopped
|
|
72
|
+
* scrolling anything after the migration. Registering the window alone would
|
|
73
|
+
* have fixed nothing either: the app's real scroller is the layout's `<main>`,
|
|
74
|
+
* not the document — so the chain has to be walked.
|
|
75
|
+
*
|
|
76
|
+
* Registration is passive; a scroller only moves while a drag is actually near
|
|
77
|
+
* its edge, so it is safe to call this once on mount.
|
|
78
|
+
*
|
|
79
|
+
* Register this ONCE per page region, not once per thing that can be dragged:
|
|
80
|
+
* Pragmatic keeps one entry per registration and each entry scrolls on its own,
|
|
81
|
+
* so registering the same `<main>` from five lanes scrolls it five times as
|
|
82
|
+
* fast.
|
|
83
|
+
*/
|
|
84
|
+
export function autoScrollAncestors(element: HTMLElement): () => void {
|
|
85
|
+
const cleanups = scrollableAncestorsOf(element).map(autoScrollBothWays)
|
|
86
|
+
// Cheap and harmless when the document itself does not scroll, and the only
|
|
87
|
+
// thing that works when it does.
|
|
88
|
+
cleanups.push(autoScrollWindowForElements())
|
|
89
|
+
return combine(...cleanups)
|
|
90
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holds a native drag started from `element` to the "move" effect, from its very
|
|
3
|
+
* first frame.
|
|
4
|
+
*
|
|
5
|
+
* The browser picks the drag cursor from `dataTransfer.dropEffect`, and the
|
|
6
|
+
* value it starts each drag with comes from `effectAllowed`. Pragmatic never
|
|
7
|
+
* writes `effectAllowed`, so it stays `uninitialized` — which the browser reads
|
|
8
|
+
* as "all", whose initial `dropEffect` is `copy`. That is the green plus cursor
|
|
9
|
+
* flashing for one frame at the start of every drag, before the first `dragover`
|
|
10
|
+
* has had a chance to say otherwise.
|
|
11
|
+
*
|
|
12
|
+
* This is a raw listener rather than a Pragmatic callback because `effectAllowed`
|
|
13
|
+
* can only be written during the `dragstart` event itself, and none of
|
|
14
|
+
* Pragmatic's callbacks are handed the event.
|
|
15
|
+
*
|
|
16
|
+
* Distinct from `preventUnhandled`, which answers the other half of the same
|
|
17
|
+
* question: this sets what the drag starts as, that keeps it from falling back
|
|
18
|
+
* to "no drop" over everything that is not a drop target.
|
|
19
|
+
*/
|
|
20
|
+
export function holdMoveDragEffect(element: HTMLElement): () => void {
|
|
21
|
+
const onDragStart = (event: DragEvent) => {
|
|
22
|
+
if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move'
|
|
23
|
+
}
|
|
24
|
+
element.addEventListener('dragstart', onDragStart)
|
|
25
|
+
return () => element.removeEventListener('dragstart', onDragStart)
|
|
26
|
+
}
|
|
@@ -158,32 +158,49 @@ export function hasEmbedAuthAdapter(): boolean {
|
|
|
158
158
|
|
|
159
159
|
/**
|
|
160
160
|
* Whether `url` is an asset the browser CANNOT load natively because its
|
|
161
|
-
* auth rides in request headers
|
|
162
|
-
* supplying an `Authorization` header AND the URL's origin is one the
|
|
163
|
-
* adapter explicitly sanctions for that bearer (`allowedOrigins` — the
|
|
164
|
-
* host's gateway, cross-origin by construction in native shells).
|
|
161
|
+
* auth rides in request headers.
|
|
165
162
|
*
|
|
166
|
-
* Native asset loads (`<img src>`, CSS `background-image`)
|
|
167
|
-
* custom headers, so a URL this returns `true` for must go
|
|
168
|
-
* `embedAuthedFetch` → blob object-URL instead (see
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
163
|
+
* Native asset loads (`<img src>`, `<track src>`, CSS `background-image`)
|
|
164
|
+
* can't carry custom headers, so a URL this returns `true` for must go
|
|
165
|
+
* through `embedAuthedFetch` → blob object-URL instead (see
|
|
166
|
+
* `useAuthedAssetSrc` / `useAuthedImageSrc`).
|
|
167
|
+
*
|
|
168
|
+
* The single signal is the registered adapter: when it supplies an
|
|
169
|
+
* `Authorization` header, the host authenticates by HEADER, so nothing the
|
|
170
|
+
* browser fetches on its own is authenticated. That holds for BOTH shapes a
|
|
171
|
+
* header-auth host takes:
|
|
172
|
+
*
|
|
173
|
+
* - a cross-origin gateway URL — sanctioned via `allowedOrigins` (native
|
|
174
|
+
* shells, whose page origin is `capacitor://` / `tauri://`);
|
|
175
|
+
* - a same-origin / relative reverse-proxy path (`/content/api/...`) —
|
|
176
|
+
* dev-ticket web, where the token lives in localStorage and there is NO
|
|
177
|
+
* session cookie to fall back on. This case used to be excluded on the
|
|
178
|
+
* assumption that same-origin implies "cookies work"; true for a cookie
|
|
179
|
+
* session, false for every header-auth host, which is exactly when this
|
|
180
|
+
* predicate is consulted at all.
|
|
181
|
+
*
|
|
182
|
+
* Everything else loads natively, unchanged: cookie-auth web (the adapter
|
|
183
|
+
* supplies no `Authorization`), no adapter at all (the hub), and third-party
|
|
184
|
+
* origins the bearer does NOT belong to (public images) — those stay out of
|
|
185
|
+
* reach of the token by the same origin rules `embedAuthedFetch` enforces.
|
|
172
186
|
*/
|
|
173
187
|
export function needsBearerAssetFetch(url: string): boolean {
|
|
174
188
|
if (typeof window === 'undefined') return false
|
|
175
189
|
const adapter = getRegisteredAuthAdapter()
|
|
176
|
-
if (!adapter
|
|
177
|
-
return false
|
|
178
|
-
}
|
|
190
|
+
if (!adapter || adapter.getHeaders?.().Authorization === undefined) return false
|
|
179
191
|
let target: URL
|
|
192
|
+
let pageOrigin: string
|
|
180
193
|
try {
|
|
181
194
|
target = new URL(url, window.location.href)
|
|
195
|
+
// Same reason `assertSameOrigin` derives it this way: test environments
|
|
196
|
+
// mock `window.location` as a plain object with no `origin` field.
|
|
197
|
+
pageOrigin = new URL(window.location.href).origin
|
|
182
198
|
} catch {
|
|
183
199
|
return false
|
|
184
200
|
}
|
|
185
201
|
if (target.protocol !== 'http:' && target.protocol !== 'https:') return false
|
|
186
|
-
|
|
202
|
+
if (target.origin === pageOrigin) return true
|
|
203
|
+
return adapter.allowedOrigins?.includes(target.origin) ?? false
|
|
187
204
|
}
|
|
188
205
|
|
|
189
206
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Anything the browser can scroll. */
|
|
2
|
+
const SCROLLABLE = /(auto|scroll|overlay)/
|
|
3
|
+
|
|
4
|
+
/** Every scrollable ancestor of `element`, innermost first. */
|
|
5
|
+
export function scrollableAncestorsOf(element: HTMLElement): HTMLElement[] {
|
|
6
|
+
const found: HTMLElement[] = []
|
|
7
|
+
for (let node = element.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
8
|
+
const style = getComputedStyle(node)
|
|
9
|
+
if (SCROLLABLE.test(style.overflowY) || SCROLLABLE.test(style.overflowX)) found.push(node)
|
|
10
|
+
}
|
|
11
|
+
return found
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The nearest scrollable ancestor, or `null`.
|
|
16
|
+
*
|
|
17
|
+
* Stands in for "the working area this thing lives in": in an app whose layout
|
|
18
|
+
* scrolls a `<main>` rather than the document, that element is exactly the
|
|
19
|
+
* region a user considers to be the page.
|
|
20
|
+
*/
|
|
21
|
+
export function nearestScrollableAncestor(element: HTMLElement): HTMLElement | null {
|
|
22
|
+
return scrollableAncestorsOf(element)[0] ?? null
|
|
23
|
+
}
|