11import canUseDom from './canUseDom' ;
22
3+ const APPEND_ORDER = '_rc_util_order' ;
34const MARK_KEY = `rc-util-key` ;
45
6+ const containerCache = new Map < Element , Node & ParentNode > ( ) ;
7+
8+ export type Prepend = boolean | 'queue' ;
9+ export type AppendType = 'prependQueue' | 'append' | 'prepend' ;
10+
511interface Options {
612 attachTo ?: Element ;
713 csp ?: { nonce ?: string } ;
8- prepend ?: boolean ;
14+ prepend ?: Prepend ;
915 mark ?: string ;
1016}
1117
@@ -25,25 +31,60 @@ function getContainer(option: Options) {
2531 return head || document . body ;
2632}
2733
34+ function getOrder ( prepend ?: Prepend ) : AppendType {
35+ if ( prepend === 'queue' ) {
36+ return 'prependQueue' ;
37+ }
38+
39+ return prepend ? 'prepend' : 'append' ;
40+ }
41+
42+ /**
43+ * Find style which inject by rc-util
44+ */
45+ function findStyles ( container : Element ) {
46+ return Array . from (
47+ ( containerCache . get ( container ) || container ) . children ,
48+ ) . filter (
49+ node => node . tagName === 'STYLE' && node [ APPEND_ORDER ] ,
50+ ) as HTMLStyleElement [ ] ;
51+ }
52+
2853export function injectCSS ( css : string , option : Options = { } ) {
2954 if ( ! canUseDom ( ) ) {
3055 return null ;
3156 }
3257
58+ const { csp, prepend } = option ;
59+
3360 const styleNode = document . createElement ( 'style' ) ;
34- if ( option . csp ?. nonce ) {
35- styleNode . nonce = option . csp ?. nonce ;
61+ styleNode [ APPEND_ORDER ] = getOrder ( prepend ) ;
62+
63+ if ( csp ?. nonce ) {
64+ styleNode . nonce = csp ?. nonce ;
3665 }
3766 styleNode . innerHTML = css ;
3867
3968 const container = getContainer ( option ) ;
4069 const { firstChild } = container ;
4170
42- if ( option . prepend && container . prepend ) {
43- // Use `prepend` first
44- container . prepend ( styleNode ) ;
45- } else if ( option . prepend && firstChild ) {
46- // Fallback to `insertBefore` like IE not support `prepend`
71+ if ( prepend ) {
72+ // If is queue `prepend`, it will prepend first style and then append rest style
73+ if ( prepend === 'queue' ) {
74+ const existStyle = findStyles ( container ) . filter ( node =>
75+ [ 'prepend' , 'prependQueue' ] . includes ( node [ APPEND_ORDER ] ) ,
76+ ) ;
77+ if ( existStyle . length ) {
78+ container . insertBefore (
79+ styleNode ,
80+ existStyle [ existStyle . length - 1 ] . nextSibling ,
81+ ) ;
82+
83+ return styleNode ;
84+ }
85+ }
86+
87+ // Use `insertBefore` as `prepend`
4788 container . insertBefore ( styleNode , firstChild ) ;
4889 } else {
4990 container . appendChild ( styleNode ) ;
@@ -52,15 +93,12 @@ export function injectCSS(css: string, option: Options = {}) {
5293 return styleNode ;
5394}
5495
55- const containerCache = new Map < Element , Node & ParentNode > ( ) ;
56-
5796function findExistNode ( key : string , option : Options = { } ) {
5897 const container = getContainer ( option ) ;
5998
60- return Array . from ( containerCache . get ( container ) . children ) . find (
61- node =>
62- node . tagName === 'STYLE' && node . getAttribute ( getMark ( option ) ) === key ,
63- ) as HTMLStyleElement ;
99+ return findStyles ( container ) . find (
100+ node => node . getAttribute ( getMark ( option ) ) === key ,
101+ ) ;
64102}
65103
66104export function removeCSS ( key : string , option : Options = { } ) {
0 commit comments