Skip to content

Commit 42171c8

Browse files
feat: add cloneStyleSheets optional fetch (#70)
1 parent 1506ad8 commit 42171c8

File tree

1 file changed

+71
-21
lines changed

1 file changed

+71
-21
lines changed

src/dom.ts

Lines changed: 71 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,35 @@ export const restoreScroll = ( target: HTMLElement = document.documentElement )
3131

3232
}
3333

34+
35+
/**
36+
* Represents a URL stylesheet as a simple URL input, URL object or as an object
37+
* with URL and fetch configuration options.
38+
*/
39+
export type UrlStylesheet = UrlInput | {
40+
/**
41+
* The URL string or a URL object of the stylesheet to load.
42+
*
43+
*/
44+
url: UrlInput
45+
/**
46+
* Indicates whether to fetch the given URL.
47+
*
48+
* @default false
49+
*/
50+
fetch?: boolean
51+
}
52+
53+
3454
/**
3555
* Represents a style input.
3656
*
37-
*
38-
* @property {UrlInput} - A URL string or input pointing to an external stylesheet
39-
* @property {HTMLStyleElement} - An HTML style element containing CSS rules
40-
* @property {CSSStyleSheet} - A CSS stylesheet object
41-
* @property {StyleSheetList} - A collection of CSS stylesheets
57+
* @property {UrlStylesheet} - A URL string or input pointing to a stylesheet file URL.
58+
* @property {HTMLStyleElement} - An HTML style element containing CSS rules.
59+
* @property {CSSStyleSheet} - A CSS stylesheet object.
60+
* @property {StyleSheetList} - A collection of CSS stylesheets.
4261
*/
43-
export type Style = UrlInput | HTMLStyleElement | CSSStyleSheet | StyleSheetList
62+
export type Style = UrlStylesheet | HTMLStyleElement | CSSStyleSheet | StyleSheetList
4463

4564

4665
/**
@@ -50,6 +69,8 @@ export type Style = UrlInput | HTMLStyleElement | CSSStyleSheet | StyleSheetList
5069
*/
5170
export type Styles = Style | Style[]
5271

72+
export type CloneStyleSheetsReturn = ( HTMLStyleElement | HTMLLinkElement )[]
73+
5374

5475
/**
5576
* Clones a StyleSheetList or array of CSSStyleSheets into an array of `HTMLStyleElement` objects.
@@ -70,8 +91,8 @@ export type Styles = Style | Style[]
7091
* styles.forEach( style => shadowRoot.appendChild( style ) )
7192
* ```
7293
*/
73-
export const cloneStyleSheetList = ( styles: StyleSheetList | CSSStyleSheet[] ) => (
74-
[ ...styles ].map( ( { cssRules } ) => {
94+
const cloneStyleSheetList = ( styleSheets: StyleSheetList | CSSStyleSheet[] ) => (
95+
[ ...styleSheets ].map( ( { cssRules } ) => {
7596
try {
7697

7798
const style = document.createElement( 'style' )
@@ -91,35 +112,43 @@ export const cloneStyleSheetList = ( styles: StyleSheetList | CSSStyleSheet[] )
91112
} catch ( error ) {
92113

93114
console.error( 'Error while cloning styles.', error )
94-
115+
95116
}
96117
} ).filter( Boolean ) as HTMLStyleElement[]
97118
)
98119

99120

100121
/**
101-
* Clones style sheets from various sources into new `HTMLStyleElement` instances.
122+
* Clones style sheets from various sources into new HTMLStyleElement nodes.
102123
*
103-
* @param styles A single style source or array of style sources. Can be:
104-
* - `StyleSheetList`: A list of stylesheets
105-
* - `CSSStyleSheet`: A single stylesheet object
106-
* - `HTMLStyleElement`: A style DOM element
107-
* - `UrlInput`: A URL string or object pointing to a stylesheet
124+
* @param styles A style source or array of style sources. Style source an be:
125+
* - `StyleSheetList`: A list of stylesheets.
126+
* - `CSSStyleSheet` A single stylesheet object.
127+
* - `HTMLStyleElement`: A style DOM element.
128+
* - `UrlStylesheet`: A URL stylesheet as a simple URL input, URL object or as an object with URL and fetch configuration options.
108129
*
109-
* @returns A promise that resolves to an array of cloned `HTMLStyleElement` nodes.
110-
* Each element is a new style element containing the CSS rules from the source.
130+
* @returns A promise that resolves to an array of cloned HTMLStyleElement and HTMLLinkElement nodes.
131+
* For inline styles and StyleSheetLists, returns HTMLStyleElement nodes.
132+
* For URL-based stylesheets, returns HTMLLinkElement nodes (or HTMLStyleElement if fetch is true).
133+
* Failed operations are silently ignored.
134+
*
135+
* @remarks
136+
* - When a URL stylesheet has `fetch: true`, the stylesheet content is fetched and embedded as inline CSS.
137+
* - When `fetch: false` (default), a link element is created instead.
138+
* - URL parsing is handled through the Url utility with support for both string and `UrlInput` object formats.
111139
*/
112-
export const cloneStyleSheets = async ( styles: Styles ): Promise<HTMLStyleElement[]> => {
140+
export const cloneStyleSheets = async ( styles: Styles ): Promise<CloneStyleSheetsReturn> => {
113141

114142
if ( ! Array.isArray( styles ) ) {
115143
return cloneStyleSheets( [ styles ] )
116144
}
117145

118-
const styleNodes: HTMLStyleElement[] = []
146+
const styleNodes: CloneStyleSheetsReturn = []
147+
119148
const styleSheetList: StyleSheetList[] = []
120149
const styleSheets: CSSStyleSheet[] = []
121150
const styleElements: HTMLStyleElement[] = []
122-
const styleUrls: UrlInput[] = []
151+
const styleUrls: UrlStylesheet[] = []
123152

124153
styles.forEach( style => {
125154
if ( style instanceof StyleSheetList ) {
@@ -161,7 +190,28 @@ export const cloneStyleSheets = async ( styles: Styles ): Promise<HTMLStyleEleme
161190
await Promise.allSettled(
162191
styleUrls.map( async urlInput => {
163192

164-
const { data, error } = await fetch<string>( Url.format( urlInput ) )
193+
const isUrlString = typeof urlInput === 'string'
194+
195+
const url = (
196+
! isUrlString && 'url' in urlInput && Url.format( urlInput.url )
197+
) || Url.format( urlInput as UrlInput )
198+
199+
const fetchUrl = (
200+
! isUrlString && 'fetch' in urlInput && urlInput.fetch
201+
) ?? false
202+
203+
if ( ! fetchUrl ) {
204+
const link = document.createElement( 'link' )
205+
link.rel = 'stylesheet'
206+
link.href = url
207+
208+
styleNodes.push( link )
209+
210+
return link
211+
}
212+
213+
214+
const { data, error } = await fetch<string>( url )
165215

166216
if ( error ) throw error
167217

0 commit comments

Comments
 (0)