FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
FluentRead/userscript/shadow-root.ts at main · FluentRead/FluentRead · GitHub
FluentRead
/
FluentRead
Public
Notifications
You must be signed in to change notification settings
Fork
422
Star
8.2k
Code
Issues
11
Pull requests
5
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
FluentRead
/
userscript
/
shadow-root.ts
Copy path
More file actions
More file actions
Latest commit
History
History
History
98 lines (92 loc) · 3.98 KB
Breadcrumbs
FluentRead
/
userscript
/
shadow-root.ts
Copy path
File metadata and controls
98 lines (92 loc) · 3.98 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
type
ShadowRootUiOptions
<
T
>
=
{
name
:
string
;
position
?:
string
;
alignment
?:
string
;
zIndex
?:
number
;
mode
?:
ShadowRootMode
;
inheritStyles
?:
boolean
;
isolateEvents
?:
string
[
]
;
css
?:
string
;
viewport
?:
boolean
;
scopeRoot
?:
boolean
;
onMount
(
container
:
HTMLElement
)
:
T
;
onRemove
?
(
mounted
?:
T
)
:
void
;
}
;
export
interface
ShadowRootContentScriptUi
<
T
>
{
shadowHost
:
HTMLElement
;
shadow
:
ShadowRoot
;
uiContainer
:
HTMLElement
;
mounted
?:
T
;
mount
(
)
:
void
;
remove
(
)
:
void
;
}
function
installStyles
(
shadow
:
ShadowRoot
,
localCss
=
''
,
scopeRoot
=
false
)
:
void
{
// 构建时汇总的全局 CSS 与当前组件 CSS 只写入 ShadowRoot,避免污染宿主网页样式。
const
css
=
[
globalThis
.
__fluentReadUserscriptCss
||
''
,
localCss
]
.
filter
(
Boolean
)
.
join
(
'\n'
)
;
if
(
!
css
)
return
;
const
style
=
document
.
createElement
(
'style'
)
;
style
.
setAttribute
(
'data-fluent-read-userscript-styles'
,
'true'
)
;
// Options 的共享样式以 :root / :root.dark 为页面根选择器;在 ShadowRoot 中需要
// 映射到 host,才能保留同一套皮肤变量和暗色选择器,同时不触碰宿主 document。
style
.
textContent
=
scopeRoot
?
css
.
replace
(
/
:
r
o
o
t
(
(?:
(?:
\.
[
\w
-
]
+
)
|
(?:
\[
[
^
\]
]
+
\]
)
)
*
)
/
gu
,
(
_match
,
suffix
:
string
)
=>
(
suffix
?
`:host(
${
suffix
}
)`
:
':host'
)
)
:
css
;
shadow
.
appendChild
(
style
)
;
}
/** 为单页 userscript runtime 提供兼容 WXT 契约的最小 Shadow UI 宿主。 */
export
async
function
createShadowRootUi
<
T
>
(
_ctx
:
unknown
,
options
:
ShadowRootUiOptions
<
T
>
,
)
:
Promise
<
ShadowRootContentScriptUi
<
T
>
>
{
const
shadowHost
=
document
.
createElement
(
'div'
)
;
shadowHost
.
setAttribute
(
'data-fluent-read-userscript-host'
,
options
.
name
)
;
// 用零尺寸固定宿主隔离网页布局;实际浮层由 ShadowRoot 子节点定位并接收事件。
shadowHost
.
style
.
cssText
=
[
'all: initial !important'
,
'display: block !important'
,
'position: fixed !important'
,
'left: 0 !important'
,
'top: 0 !important'
,
options
.
viewport
?
'width: 100vw !important'
:
'width: 0 !important'
,
options
.
viewport
?
'height: 100vh !important'
:
'height: 0 !important'
,
options
.
viewport
?
'overflow: hidden !important'
:
'overflow: visible !important'
,
'pointer-events: auto !important'
,
`z-index:
${
options
.
zIndex
??
2_147_483_647
}
!important`
,
]
.
join
(
';'
)
;
const
shadow
=
shadowHost
.
attachShadow
(
{
mode
:
options
.
mode
||
'open'
}
)
;
installStyles
(
shadow
,
options
.
css
,
options
.
scopeRoot
)
;
const
container
=
document
.
createElement
(
'div'
)
;
container
.
setAttribute
(
'data-fluent-read-userscript-container'
,
options
.
name
)
;
container
.
style
.
cssText
=
options
.
viewport
?
'all: initial; width: 100%; height: 100%; overflow: hidden; pointer-events: auto;'
:
'all: initial; width: 0; height: 0; overflow: visible; pointer-events: auto;'
;
shadow
.
appendChild
(
container
)
;
// 在 ShadowRoot 冒泡阶段阻断明确要求隔离的事件:先让内部控件(例如
// Element Plus select)完成自己的键盘处理,再阻止事件穿过 Shadow DOM
// 边界影响宿主页面。若在捕获阶段拦截,事件会在到达内部控件前就被截断。
for
(
const
eventName
of
options
.
isolateEvents
||
[
]
)
{
shadow
.
addEventListener
(
eventName
,
(
event
)
=>
event
.
stopPropagation
(
)
)
;
}
let
isMounted
=
false
;
const
ui
:
ShadowRootContentScriptUi
<
T
>
=
{
shadowHost
,
shadow
,
uiContainer
:
container
,
mount
(
)
{
if
(
isMounted
)
return
;
isMounted
=
true
;
(
document
.
documentElement
||
document
.
body
)
.
appendChild
(
shadowHost
)
;
ui
.
mounted
=
options
.
onMount
(
container
)
;
}
,
remove
(
)
{
if
(
!
isMounted
)
return
;
isMounted
=
false
;
options
.
onRemove
?.
(
ui
.
mounted
)
;
ui
.
mounted
=
undefined
;
shadowHost
.
remove
(
)
;
}
,
}
;
return
ui
;
}
Back
|
FazBrowse Home
|
New Git URL