import Stylis from "@dash-ui/stylis" ; import type { Context , Plugable , Plugin } from "@dash-ui/stylis" ; import { noop } from "./utils" ; param options export function createDash ( options = { } ) { let { key = "ui" , nonce , speedy , stylisPlugins , prefix = true , container = typeof document !== "undefined" ? document . head : void 0 , } = options ; const stylis = new Stylis ( { prefix } ) ; speedy = speedy === void 0 || speedy === null ? ! ( typeof process !== "undefined" && process . env . NODE_ENV !== "production" ) : speedy ; const inserted = new Set < string > ( ) ; const cache = new Map ( ) ; const sheetsCache = new Map < string , DashSheet > ( ) ; const sheet = styleSheet ( { key , container , nonce , speedy , } ) ; if ( typeof document !== "undefined" ) { let nodes = document . querySelectorAll ( 'style[data-cache="' + key + '"]' ) ; let i = 0 ; let attr ; let node ; const insert = inserted . add . bind ( inserted ) ; for ( ; i < nodes . length ; i ++ ) { if ( ( attr = ( node = nodes [ i ] ) . getAttribute ( `data-dash` ) ) === null ) continue ; attr . split ( " " ) . forEach ( insert ) ; container && node . parentNode !== container && container . appendChild ( node ) ; } stylis . use ( stylisPlugins ) ( ruleSheet as Plugin ) ; } if ( typeof process !== "undefined" && process . env . NODE_ENV !== "production" ) { const commentStart = /\/\*/g ; const commentEnd = /\*\//g ; stylis . use ( ( context , content ) => { if ( context === - 1 ) { while ( commentStart . test ( content ) ) { commentEnd . lastIndex = commentStart . lastIndex ; if ( commentEnd . test ( content ) ) { commentStart . lastIndex = commentEnd . lastIndex ; continue ; } throw new Error ( 'Your styles have an unterminated comment ("/*" without ' + 'corresponding "*/").' ) ; } commentStart . lastIndex = 0 ; } } ) ; } let insert = function ( key , selector , styles , styleSheet ) { if ( inserted . has ( key ) ) return ; inserted . add ( key ) ; Sheet . x = styleSheet === void 0 ? sheet : styleSheet ; stylis ( selector , styles ) ; } ; if ( typeof document === "undefined" ) { insert = function ( key , selector , styles , styleSheet ) { if ( inserted . has ( key ) ) return ; inserted . add ( key ) ; Sheet . x = styleSheet === void 0 ? sheet : styleSheet ; cache . set ( key , stylis ( selector , styles ) ) ; } ; } return { key , sheet , sheets : { add ( name ) { const sheetRef = sheetsCache . get ( name ) || { n : 0 , s : styleSheet ( sheet ) , } ; sheetsCache . set ( name , sheetRef ) ; sheetRef . n ++ ; return sheetRef . s ; } , delete ( name ) { const sheetRef = sheetsCache . get ( name ) ; if ( ! sheetRef ) return - 1 ; if ( sheetRef . n === 1 ) { sheetsCache . delete ( name ) ; sheetRef . s . flush ( ) ; } return -- sheetRef . n ; } , keys : sheetsCache . keys . bind ( sheetsCache ) , } , stylis , insert , inserted , cache , } ; } export interface CreateDashOptions { default readonly key ? : string ; /**
     * For security policies. A nonce is an arbitrary number that can be used just
     * once in a cryptographic communication.
     */ readonly nonce ? : string ; /**
     * An array of stylis plugins
     * See: https://www.npmjs.com/package/stylis
     */ readonly stylisPlugins ? : Plugable [ ] ; default readonly prefix ? : boolean | ( ( key : string , value : any , context : any ) => boolean ) ; default readonly container ? : HTMLElement ; default readonly speedy ? : boolean ; } export type Dash = { /**
     * The sheet key
     */ readonly key : string ; /**
     * The default style sheet used by this instance of Dash
     */ readonly sheet : DashStyleSheet ; /**
     * Used for tracking external sheets. You can safely add/delete new
     * custom sheets using this. Those sheets can be used in the `insert()`
     * method. The primary reason you'd want to use this is so that you can
     * create independently flushable styles/sheets.
     */ readonly sheets : DashSheets ; /**
     * The instance of Stylis used by this Dash instance
     */ readonly stylis : typeof Stylis ; /**
     * A cache of Stylis rules saved by their keys. This is only used
     * on the server for generating CSS files and strings from the keys
     * used in the cache.
     */ readonly cache : Map < string , string > ; param key param selector param styles param styleSheet insert ( key , selector , styles , styleSheet ? ) : void ; /**
     * An insertion cache. This tracks which keys have already been inserted into
     * the DOM to prevent duplicates.
     */ readonly inserted : Set < string > ; } ; /**
 * A stylesheet cache that tracks references to the keys in it.
 * When there are no more references to a sheet, it will be flushed
 * from the DOM.
 */ export interface DashSheets { param key add ( key ) : DashStyleSheet ; param key delete ( key ) : number ; /**
     * Returns an iterator containing all of the keys in the cache.
     */ keys ( ) : ReturnType < Map < string , DashSheet > [ "keys" ] > ; } interface DashSheet { /**
     * The number of references to the sheet
     */ n : number ; /**
     * A dash style sheet.
     */ s : DashStyleSheet ; } export function styleSheet ( options ) { const { key , container , nonce , speedy = false } = options ; const tags = [ ] ; let size = 0 ; return { key , nonce , container , speedy , insert ( rule ) { if ( size % ( speedy ? 65000 : 1 ) === 0 ) { const tag = document . createElement ( "style" ) ; tag . setAttribute ( `data-dash` , key ) ; if ( nonce ) tag . setAttribute ( "nonce" , nonce ) ; tag . textContent = "" ; container && container . insertBefore ( tag , ! tags . length ? null : tags [ tags . length - 1 ] . nextSibling ) ; tags . push ( tag ) ; } const tag = tags [ tags . length - 1 ] ; if ( ! speedy ) { tag . textContent += rule ; } else { let sheet = tag . sheet ; let i = 0 ; if ( ! sheet ) { const { styleSheets } = document ; for ( ; i < styleSheets . length ; i ++ ) if ( styleSheets [ i ] . ownerNode === tag ) { sheet = styleSheets [ i ] ; break ; } } try { const isImportRule = rule . charCodeAt ( 1 ) === 105 && rule . charCodeAt ( 0 ) === 64 ; ( sheet as CSSStyleSheet ) . insertRule ( rule , isImportRule ? 0 : ( sheet as CSSStyleSheet ) . cssRules . length ) ; } catch ( e ) { if ( typeof process !== "undefined" && process . env . NODE_ENV !== "production" ) { console . warn ( 'There was a problem inserting the following rule: "' + rule + '"' , e ) ; } } } size ++ ; } , flush ( ) { tags . forEach ( ( tag ) => ( tag . parentNode as HTMLElement ) . removeChild ( tag ) ) ; tags . length = 0 ; size = 0 ; } , } ; } export interface DashStyleSheetOptions { /**
     * Keys in sheets used to associate style sheets with
     * specific `dash` instances
     */ readonly key : string ; /**
     * The element to insert `<style>` tags into. For example,
     * `document.head`.
     */ readonly container ? : HTMLElement ; /**
     * For security policies. A nonce is an arbitrary number that can be used just
     * once in a cryptographic communication.
     */ readonly nonce ? : string ; default readonly speedy ? : boolean ; } export interface DashStyleSheet { /**
     * The sheet key
     */ readonly key : string ; /**
     * The sheet nonce
     */ readonly nonce ? : string ; /**
     * The sheet container
     */ readonly container ? : HTMLElement ; /**
     * `true` if speedy mode is turned on
     */ readonly speedy : boolean ; param rule insert ( rule ) : void ; /**
     * Removes all style rules from the sheet.
     */ flush ( ) : void ; } const RULE_DELIMITER = "/*|*/" ; const RULE_NEEDLE = RULE_DELIMITER + "}" ; function ruleSheet ( context , content , selectors , parents , line , column , length , ns , depth , at ) { if ( context === 1 ) { if ( content . charCodeAt ( 0 ) === 64 ) { Sheet . x . insert ( content + ";" ) ; return "" ; } } else if ( context === 2 ) { if ( ns === 0 ) return content + RULE_DELIMITER ; } else if ( context === 3 ) { if ( ns === 102 || ns === 112 ) { Sheet . x . insert ( selectors [ 0 ] + content ) ; return "" ; } else { return content + ( at === 0 ? RULE_DELIMITER : "" ) ; } } else if ( context === - 2 ) { content . split ( RULE_NEEDLE ) . forEach ( ( block ) => { block && Sheet . x . insert ( block + "}" ) ; } ) ; } } const Sheet = { x : { insert : noop , } , } ;