nanosplash 4.0.0 → 4.0.2
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/.github/workflows/ci.yml +1 -0
- package/docs/.vitepress/config.ts +0 -3
- package/docs/.vitepress/theme/vue/PlayGround.vue +4 -0
- package/package.json +5 -6
- package/src/ts/Nanosplash.ts +152 -184
- package/src/ts/main.ts +3 -1
- package/src/ts/types/Types.ts +0 -13
- package/tests/Nanosplash.spec.ts +5 -15
- package/dist/cjs/ns.cjs +0 -1
- package/dist/es/ns.js +0 -44
- package/dist/iife/ns.iife.js +0 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -6,9 +6,6 @@ export default defineConfig({
|
|
|
6
6
|
description: 'The tiny loading screen for web artisans',
|
|
7
7
|
base: '/nanosplash/',
|
|
8
8
|
appearance: 'dark',
|
|
9
|
-
head: [
|
|
10
|
-
['script', { src: 'https://unpkg.com/nanosplash/dist/iife/ns.iife.js' }],
|
|
11
|
-
],
|
|
12
9
|
themeConfig: {
|
|
13
10
|
nav: [
|
|
14
11
|
{ text: 'Home', link: '/' },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nanosplash",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.2",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Isak K. Hauge",
|
|
6
6
|
"email": "isakhauge@icloud.com",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/jsdom": "^21.1.6",
|
|
17
17
|
"@types/node": "^20.11.30",
|
|
18
|
-
"@types/rollup": "^0.54.0",
|
|
19
18
|
"@vitest/coverage-v8": "^1.4.0",
|
|
20
19
|
"@vitest/ui": "^1.4.0",
|
|
21
20
|
"cross-env": "^7.0.3",
|
|
@@ -25,10 +24,10 @@
|
|
|
25
24
|
"jsdom": "^24.0.0",
|
|
26
25
|
"sass": "^1.72.0",
|
|
27
26
|
"stylelint-prettier": "^5.0.0",
|
|
28
|
-
"typescript": "5.4.
|
|
29
|
-
"typescript-eslint": "^7.
|
|
30
|
-
"vite": "^5.
|
|
31
|
-
"vitepress": "1.0.
|
|
27
|
+
"typescript": "5.4.3",
|
|
28
|
+
"typescript-eslint": "^7.3.1",
|
|
29
|
+
"vite": "^5.2.6",
|
|
30
|
+
"vitepress": "1.0.1",
|
|
32
31
|
"vitest": "^1.4.0"
|
|
33
32
|
},
|
|
34
33
|
"exports": {
|
package/src/ts/Nanosplash.ts
CHANGED
|
@@ -1,206 +1,174 @@
|
|
|
1
1
|
// @ts-strict
|
|
2
2
|
import style from '../style/ns.sass?inline'
|
|
3
3
|
import { NanosplashInterface } from './types/NanosplashInterface'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
ElementReference,
|
|
7
|
-
NSElement,
|
|
8
|
-
ScopedSelectors,
|
|
9
|
-
} from './types/Types'
|
|
4
|
+
import { ElementReference, NSElement } from './types/Types'
|
|
5
|
+
import type { DOMWindow } from 'jsdom'
|
|
10
6
|
import { version } from '../../package.json'
|
|
11
7
|
|
|
12
|
-
const styleId: string = 'ns'
|
|
13
|
-
const doc: Document = document
|
|
14
|
-
const bod: HTMLElement = doc.body
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* # Scope
|
|
18
|
-
* Creates scoped selectors.
|
|
19
|
-
* @param node Node to query.
|
|
20
|
-
* @returns An object containing two, slightly different functions that
|
|
21
|
-
* retrieves elements from the DOM.
|
|
22
|
-
*/
|
|
23
|
-
const scope = (node: ParentNode): ScopedSelectors =>
|
|
24
|
-
(all => ({
|
|
25
|
-
all,
|
|
26
|
-
first: (ref: string) => all(ref)[0] ?? null,
|
|
27
|
-
}))((ref: string) => Array.from(node.querySelectorAll(ref)))
|
|
28
|
-
|
|
29
8
|
/**
|
|
30
|
-
* #
|
|
31
|
-
* @
|
|
32
|
-
* @returns An array of Element nodes.
|
|
33
|
-
*/
|
|
34
|
-
const getAll = (selector: DOMSelector): Element[] => scope(doc).all(selector)
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* # Get
|
|
38
|
-
* @param selector CSS selector used to match nodes in the DOM.
|
|
39
|
-
* @returns Firs Element node from the DOM matching the selector.
|
|
40
|
-
*/
|
|
41
|
-
const get = (selector: DOMSelector): Element | null =>
|
|
42
|
-
scope(doc).first(selector)
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* # Get All Nanosplashes
|
|
46
|
-
* @returns An array of all Nanosplash elements in the DOM.
|
|
47
|
-
*/
|
|
48
|
-
const getAllNs = (): NSElement[] => getAll('.ns') as NSElement[]
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* # Parse Ref
|
|
52
|
-
* @param ref Element reference which could be a selector or an Element.
|
|
53
|
-
* @returns The Element node or null.
|
|
54
|
-
*/
|
|
55
|
-
const parseRef = (ref: ElementReference): Element | null =>
|
|
56
|
-
ref instanceof Element ? ref : get(ref)
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* # Create HTMLDivElement
|
|
60
|
-
* @param className Optional string containing class names.
|
|
61
|
-
* @param children Optional list of Nodes or strings.
|
|
62
|
-
* @returns The newly created HTMLDivElement.
|
|
63
|
-
*/
|
|
64
|
-
const div = (
|
|
65
|
-
className?: string,
|
|
66
|
-
...children: (Node | string)[]
|
|
67
|
-
): HTMLDivElement => {
|
|
68
|
-
const node: HTMLDivElement = doc.createElement('div')
|
|
69
|
-
if (className) node.classList.add(className)
|
|
70
|
-
node.append(...children)
|
|
71
|
-
return node
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* # Parse
|
|
76
|
-
* @param html HTML string.
|
|
77
|
-
* @returns Parsed node.
|
|
78
|
-
*/
|
|
79
|
-
const parse = (html: string): Node => {
|
|
80
|
-
const node: HTMLDivElement = div()
|
|
81
|
-
node.innerHTML = html
|
|
82
|
-
return node.firstChild as Node
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* # Make Nanosplash Element
|
|
87
|
-
* @returns Nanpslash DOM element.
|
|
9
|
+
* # Use Nanosplash
|
|
10
|
+
* @returns Nanosplash API.
|
|
88
11
|
*/
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
12
|
+
export const useNs = (
|
|
13
|
+
win?: (Window | (Window & typeof globalThis)) | DOMWindow
|
|
14
|
+
): NanosplashInterface => {
|
|
15
|
+
const doc = (win ?? window).document
|
|
16
|
+
const bod = doc.body
|
|
17
|
+
|
|
18
|
+
const all = (node: ParentNode, ref: string) =>
|
|
19
|
+
Array.from(node.querySelectorAll(ref))
|
|
20
|
+
const first = (node: ParentNode, ref: string) => all(node, ref)[0] ?? null
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* # Get All Nanosplashes
|
|
24
|
+
* @returns An array of all Nanosplash elements in the DOM.
|
|
25
|
+
*/
|
|
26
|
+
const getAllNs = (): NSElement[] => all(doc, '.ns') as NSElement[]
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* # Parse Ref
|
|
30
|
+
* @param ref Element reference which could be a selector or an Element.
|
|
31
|
+
* @returns The Element node or null.
|
|
32
|
+
*/
|
|
33
|
+
const parseRef = (ref: ElementReference): Element | null =>
|
|
34
|
+
ref instanceof Element ? ref : first(doc, ref)
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* # Create HTMLDivElement
|
|
38
|
+
* @param className Optional string containing class names.
|
|
39
|
+
* @param children Optional list of Nodes or strings.
|
|
40
|
+
* @returns The newly created HTMLDivElement.
|
|
41
|
+
*/
|
|
42
|
+
const div = (
|
|
43
|
+
className?: string,
|
|
44
|
+
...children: (Node | string)[]
|
|
45
|
+
): HTMLDivElement => {
|
|
46
|
+
const node: HTMLDivElement = doc.createElement('div')
|
|
47
|
+
if (className) node.classList.add(className)
|
|
48
|
+
node.append(...children)
|
|
49
|
+
return node
|
|
50
|
+
}
|
|
96
51
|
|
|
97
|
-
/**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
52
|
+
/**
|
|
53
|
+
* # Parse
|
|
54
|
+
* @param html HTML string.
|
|
55
|
+
* @returns Parsed node.
|
|
56
|
+
*/
|
|
57
|
+
const parse = (html: string): Node => {
|
|
58
|
+
const node: HTMLDivElement = div()
|
|
59
|
+
node.innerHTML = html
|
|
60
|
+
return node.firstChild as Node
|
|
61
|
+
}
|
|
105
62
|
|
|
106
|
-
/**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const newNsText = div('nst', text)
|
|
117
|
-
if (oldNsText) {
|
|
118
|
-
oldNsText.replaceWith(newNsText)
|
|
119
|
-
} else {
|
|
120
|
-
ns.insertBefore(newNsText, ns.firstChild)
|
|
63
|
+
/**
|
|
64
|
+
* # Make Nanosplash Element
|
|
65
|
+
* @returns Nanpslash DOM element.
|
|
66
|
+
*/
|
|
67
|
+
const makeNs = (): NSElement => {
|
|
68
|
+
const circle: string = '<circle class=path cx=25 cy=25 r=20 fill=none />'
|
|
69
|
+
const svg = parse(`<svg viewBox="0 0 50 50">${circle}</svg>`) as Element
|
|
70
|
+
const node = div('ns', div('nst'), div('nss', svg)) as NSElement
|
|
71
|
+
node.nsId = Date.now()
|
|
72
|
+
return node
|
|
121
73
|
}
|
|
122
|
-
}
|
|
123
74
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
75
|
+
/**
|
|
76
|
+
* # Peek Nanosplash Queue
|
|
77
|
+
* Collect all Nanosplash elements in the DOM, sort them by their NS ID
|
|
78
|
+
* in ascending order, and return the first element.
|
|
79
|
+
* @returns The front of the queue.
|
|
80
|
+
*/
|
|
81
|
+
const peekNsQueue = (): NSElement | null =>
|
|
82
|
+
getAllNs().sort((a: NSElement, b: NSElement) => a.nsId - b.nsId)[0] ?? null
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* # Set Nanosplash Text
|
|
86
|
+
* Replace the text node to trigger the animation which in turn is invoked
|
|
87
|
+
* by the connected callback in the DOM.
|
|
88
|
+
* @param ns Nanosplash element.
|
|
89
|
+
* @param text Text to display adjacent to spinner.
|
|
90
|
+
*/
|
|
91
|
+
const setNsText = (ns: NSElement, text: string): void => {
|
|
92
|
+
const oldNsText = first(ns, '.nst') as Element | null
|
|
93
|
+
if (!text) return oldNsText?.remove()
|
|
94
|
+
const newNsText = div('nst', text)
|
|
95
|
+
if (oldNsText) {
|
|
96
|
+
oldNsText.replaceWith(newNsText)
|
|
97
|
+
} else {
|
|
98
|
+
ns.insertBefore(newNsText, ns.firstChild)
|
|
99
|
+
}
|
|
134
100
|
}
|
|
135
|
-
parent.append(ns)
|
|
136
|
-
parent.classList.add('nsh')
|
|
137
|
-
}
|
|
138
101
|
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
ns = recycledNs as NSElement
|
|
153
|
-
} else {
|
|
154
|
-
ns = makeNs()
|
|
155
|
-
setNsParent(ns, parent as Element)
|
|
102
|
+
/**
|
|
103
|
+
* # Set Nanosplash Parent
|
|
104
|
+
* Define where inside the DOM to spawn the Nansoplash.
|
|
105
|
+
* @param ns Nanosplash element.
|
|
106
|
+
* @param parent NS element's parent to be.
|
|
107
|
+
*/
|
|
108
|
+
const setNsParent = (ns: NSElement, parent: Element): void => {
|
|
109
|
+
const child = parent.firstElementChild
|
|
110
|
+
if (child) {
|
|
111
|
+
parent.insertBefore(ns, child)
|
|
112
|
+
}
|
|
113
|
+
parent.append(ns)
|
|
114
|
+
parent.classList.add('nsh')
|
|
156
115
|
}
|
|
157
|
-
setNsText(ns, text ?? '')
|
|
158
|
-
const top: string = scrollY + 'px'
|
|
159
|
-
bod.style.setProperty('--ns-top', top)
|
|
160
|
-
return ns.nsId
|
|
161
|
-
}
|
|
162
116
|
|
|
163
|
-
/**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
117
|
+
/**
|
|
118
|
+
* # Show Nanosplash
|
|
119
|
+
* @param text Text to display adjacent to spinner.
|
|
120
|
+
* @param inside Selector or element in which the NS element will be spawned.
|
|
121
|
+
* @returns The ID if the NS element — which is a UTC integer.
|
|
122
|
+
*/
|
|
123
|
+
const show = (text?: string, inside?: string | Element): number | null => {
|
|
124
|
+
const parent: Element | null = (
|
|
125
|
+
inside ? parseRef(inside) : bod
|
|
126
|
+
) as Element | null
|
|
127
|
+
let ns: NSElement
|
|
128
|
+
const recycledNs = first(parent ?? bod, '& > .ns')
|
|
129
|
+
if (recycledNs) {
|
|
130
|
+
ns = recycledNs as NSElement
|
|
131
|
+
} else {
|
|
132
|
+
ns = makeNs()
|
|
133
|
+
setNsParent(ns, parent as Element)
|
|
134
|
+
}
|
|
135
|
+
setNsText(ns, text ?? '')
|
|
136
|
+
const top: string = scrollY + 'px'
|
|
137
|
+
bod.style.setProperty('--ns-top', top)
|
|
138
|
+
return ns.nsId
|
|
139
|
+
}
|
|
171
140
|
|
|
172
|
-
/**
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
141
|
+
/**
|
|
142
|
+
* # Remove Nanosplash
|
|
143
|
+
* @param ns Nanosplash elememnt.
|
|
144
|
+
*/
|
|
145
|
+
const removeNs = (ns?: Element | null): void => {
|
|
146
|
+
ns?.parentElement?.classList.remove('nsh')
|
|
147
|
+
ns?.remove()
|
|
148
|
+
}
|
|
178
149
|
|
|
179
|
-
/**
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
150
|
+
/**
|
|
151
|
+
* # Find Nanosplash
|
|
152
|
+
* @param id The UTC integer returned from the `show` function.
|
|
153
|
+
* @returns Null or the corresponding Nanosplash element.
|
|
154
|
+
*/
|
|
155
|
+
const findNs = (id: number) => getAllNs().find(v => v.nsId === id) ?? null
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* # Hide Nanosplash
|
|
159
|
+
* Hide agnostically in FIFO order, specifically by ID, or all by the asterisk
|
|
160
|
+
* which will delete all Nanosplashes.
|
|
161
|
+
* @param id Optional ID of a Nanosplash element or '*' .
|
|
162
|
+
*/
|
|
163
|
+
const hide = (id?: number | '*'): void => {
|
|
164
|
+
if (id === '*') all(doc, '.ns').forEach(removeNs)
|
|
165
|
+
else removeNs(typeof id === 'number' ? findNs(id) : peekNsQueue())
|
|
166
|
+
}
|
|
189
167
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const addCssToBody = (): void => {
|
|
194
|
-
get('#' + styleId)?.remove()
|
|
195
|
-
bod.append(parse(`<style id=${styleId}>${style}</style>`))
|
|
196
|
-
}
|
|
168
|
+
// Add CSS to window
|
|
169
|
+
first(doc, '#ns')?.remove()
|
|
170
|
+
bod.append(parse(`<style id="ns">${style}</style>`))
|
|
197
171
|
|
|
198
|
-
/**
|
|
199
|
-
* # Use Nanosplash
|
|
200
|
-
* @returns Nanosplash API.
|
|
201
|
-
*/
|
|
202
|
-
export const useNs = (): NanosplashInterface => {
|
|
203
|
-
addCssToBody()
|
|
204
172
|
return {
|
|
205
173
|
show,
|
|
206
174
|
hide,
|
package/src/ts/main.ts
CHANGED
package/src/ts/types/Types.ts
CHANGED
|
@@ -5,19 +5,6 @@ export type UTCInteger = Integer
|
|
|
5
5
|
export type DOMSelector = string
|
|
6
6
|
export type ElementReference = DOMSelector | Element
|
|
7
7
|
|
|
8
|
-
export interface ScopedSelectors {
|
|
9
|
-
/**
|
|
10
|
-
* @param selector Selector to match with a DOM element.
|
|
11
|
-
* @returns An array of elements matching with the selector.
|
|
12
|
-
*/
|
|
13
|
-
all: (selector: DOMSelector) => Element[]
|
|
14
|
-
/**
|
|
15
|
-
* @param selector Selector to match with a DOM element.
|
|
16
|
-
* @returns Null or the first element in the DOM to match the selector.
|
|
17
|
-
*/
|
|
18
|
-
first: (selector: DOMSelector) => Element | null
|
|
19
|
-
}
|
|
20
|
-
|
|
21
8
|
export interface NSElement extends HTMLDivElement {
|
|
22
9
|
nsId: number
|
|
23
10
|
}
|
package/tests/Nanosplash.spec.ts
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
import { describe, it,
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
2
2
|
import { JSDOM } from 'jsdom'
|
|
3
|
-
import {
|
|
3
|
+
import { useNs } from '../src/ts/Nanosplash'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
async function updateGlobals() {
|
|
10
|
-
dom = new JSDOM()
|
|
11
|
-
// @ts-ignore
|
|
12
|
-
globalThis.window = dom.window
|
|
13
|
-
document = globalThis.document = dom.window.document
|
|
14
|
-
ns = globalThis.window.ns = (await import('../src/ts/Nanosplash')).useNs()
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
beforeEach(updateGlobals)
|
|
5
|
+
const dom = new JSDOM()
|
|
6
|
+
var window = dom.window
|
|
7
|
+
const ns = (window.ns = useNs(window))
|
|
18
8
|
|
|
19
9
|
describe('Nanosplash API', () => {
|
|
20
10
|
it('should be defined', () => {
|
package/dist/cjs/ns.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const b='@keyframes nsRotate{to{transform:rotate(360deg)}}@keyframes nsDash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes nsFade{0%{opacity:0}to{opacity:1}}@keyframes nsAscend{0%{opacity:0;transform:translateY(13px)}to{opacity:1;transform:translateY(0)}}:root{--ns-top: 0px}.ns,body.nsh,body.nsh:before,.nsh:before{width:100%;height:100%}.ns,.nsh:before{bottom:0;right:0}.ns{display:flex;justify-content:center;align-items:center}.nsh{--color: DarkSlateGray;--size: 20px;--relSize: calc(var(--size) * .9);--font: "Helvetica", "Arial", sans-serif;--weight: 400;--bg: rgba(255, 255, 255, .9);--zIdx: 999999999;--blur: blur(5px)}.nsh{position:relative;z-index:var(--zIdx)}.nsh:before{position:absolute;background-color:var(--bg);content:"";backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);z-index:calc(var(--zIdx) + 1);border-radius:inherit}body.nsh,body.nsh:before{position:fixed;top:var(--ns-top);left:0}.ns{position:absolute;z-index:calc(var(--zIdx) + 2);animation:nsFade 2s;gap:var(--relSize)}.nst{color:var(--color);font-size:var(--size);font-family:var(--font);font-weight:var(--weight);max-width:80dvw;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-shadow:0 0 .06rem rgba(47,79,79,.25);filter:drop-shadow(0 0 .07rem rgba(0,0,0,.25));animation:nsAscend .5s}.nss{display:block;width:var(--relSize);height:var(--relSize);animation:nsAscend .5s}.nss>svg{animation:nsRotate 2s linear infinite;position:relative;width:inherit;height:inherit;stroke-width:8}.nss .path{stroke:var(--color);stroke-linecap:round;animation:nsDash 1.5s ease-in-out infinite}',m="4.0.0",l="ns",i=document,r=i.body,a=e=>(s=>({all:s,first:t=>s(t)[0]??null}))(s=>Array.from(e.querySelectorAll(s))),f=e=>a(i).all(e),h=e=>a(i).first(e),p=()=>f(".ns"),u=e=>e instanceof Element?e:h(e),n=(e,...s)=>{const t=i.createElement("div");return e&&t.classList.add(e),t.append(...s),t},v=e=>{const s=n();return s.innerHTML=e,s.firstChild},g=()=>{const s=v('<svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none /></svg>'),t=n("ns",n("nst"),n("nss",s));return t.nsId=Date.now(),t},k=()=>p().sort((e,s)=>e.nsId-s.nsId)[0]??null,w=(e,s)=>{const t=a(e).first(".nst");if(!s)return t==null?void 0:t.remove();const o=n("nst",s);t?t.replaceWith(o):e.insertBefore(o,e.firstChild)},x=(e,s)=>{const t=s.firstElementChild;t&&s.insertBefore(e,t),s.append(e),s.classList.add("nsh")},z=(e,s)=>{const t=s?u(s):r;let o;const c=a(t??r).first("& > .ns");c?o=c:(o=g(),x(o,t)),w(o,e??"");const y=scrollY+"px";return r.style.setProperty("--ns-top",y),o.nsId},d=e=>{var s;(s=e==null?void 0:e.parentElement)==null||s.classList.remove("nsh"),e==null||e.remove()},I=e=>p().find(s=>s.nsId===e)??null,N=e=>{e==="*"?f(".ns").forEach(d):d(typeof e=="number"?I(e):k())},A=()=>{var e;(e=h("#"+l))==null||e.remove(),r.append(v(`<style id=${l}>${b}</style>`))},S=()=>(A(),{show:z,hide:N,version:m});exports.useNs=S;
|
package/dist/es/ns.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
const b = '@keyframes nsRotate{to{transform:rotate(360deg)}}@keyframes nsDash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes nsFade{0%{opacity:0}to{opacity:1}}@keyframes nsAscend{0%{opacity:0;transform:translateY(13px)}to{opacity:1;transform:translateY(0)}}:root{--ns-top: 0px}.ns,body.nsh,body.nsh:before,.nsh:before{width:100%;height:100%}.ns,.nsh:before{bottom:0;right:0}.ns{display:flex;justify-content:center;align-items:center}.nsh{--color: DarkSlateGray;--size: 20px;--relSize: calc(var(--size) * .9);--font: "Helvetica", "Arial", sans-serif;--weight: 400;--bg: rgba(255, 255, 255, .9);--zIdx: 999999999;--blur: blur(5px)}.nsh{position:relative;z-index:var(--zIdx)}.nsh:before{position:absolute;background-color:var(--bg);content:"";backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);z-index:calc(var(--zIdx) + 1);border-radius:inherit}body.nsh,body.nsh:before{position:fixed;top:var(--ns-top);left:0}.ns{position:absolute;z-index:calc(var(--zIdx) + 2);animation:nsFade 2s;gap:var(--relSize)}.nst{color:var(--color);font-size:var(--size);font-family:var(--font);font-weight:var(--weight);max-width:80dvw;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-shadow:0 0 .06rem rgba(47,79,79,.25);filter:drop-shadow(0 0 .07rem rgba(0,0,0,.25));animation:nsAscend .5s}.nss{display:block;width:var(--relSize);height:var(--relSize);animation:nsAscend .5s}.nss>svg{animation:nsRotate 2s linear infinite;position:relative;width:inherit;height:inherit;stroke-width:8}.nss .path{stroke:var(--color);stroke-linecap:round;animation:nsDash 1.5s ease-in-out infinite}', m = "4.0.0", l = "ns", i = document, r = i.body, a = (e) => /* @__PURE__ */ ((s) => ({
|
|
2
|
-
all: s,
|
|
3
|
-
first: (t) => s(t)[0] ?? null
|
|
4
|
-
}))((s) => Array.from(e.querySelectorAll(s))), f = (e) => a(i).all(e), h = (e) => a(i).first(e), p = () => f(".ns"), u = (e) => e instanceof Element ? e : h(e), n = (e, ...s) => {
|
|
5
|
-
const t = i.createElement("div");
|
|
6
|
-
return e && t.classList.add(e), t.append(...s), t;
|
|
7
|
-
}, v = (e) => {
|
|
8
|
-
const s = n();
|
|
9
|
-
return s.innerHTML = e, s.firstChild;
|
|
10
|
-
}, g = () => {
|
|
11
|
-
const s = v('<svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none /></svg>'), t = n("ns", n("nst"), n("nss", s));
|
|
12
|
-
return t.nsId = Date.now(), t;
|
|
13
|
-
}, k = () => p().sort((e, s) => e.nsId - s.nsId)[0] ?? null, w = (e, s) => {
|
|
14
|
-
const t = a(e).first(".nst");
|
|
15
|
-
if (!s)
|
|
16
|
-
return t == null ? void 0 : t.remove();
|
|
17
|
-
const o = n("nst", s);
|
|
18
|
-
t ? t.replaceWith(o) : e.insertBefore(o, e.firstChild);
|
|
19
|
-
}, x = (e, s) => {
|
|
20
|
-
const t = s.firstElementChild;
|
|
21
|
-
t && s.insertBefore(e, t), s.append(e), s.classList.add("nsh");
|
|
22
|
-
}, z = (e, s) => {
|
|
23
|
-
const t = s ? u(s) : r;
|
|
24
|
-
let o;
|
|
25
|
-
const c = a(t ?? r).first("& > .ns");
|
|
26
|
-
c ? o = c : (o = g(), x(o, t)), w(o, e ?? "");
|
|
27
|
-
const y = scrollY + "px";
|
|
28
|
-
return r.style.setProperty("--ns-top", y), o.nsId;
|
|
29
|
-
}, d = (e) => {
|
|
30
|
-
var s;
|
|
31
|
-
(s = e == null ? void 0 : e.parentElement) == null || s.classList.remove("nsh"), e == null || e.remove();
|
|
32
|
-
}, I = (e) => p().find((s) => s.nsId === e) ?? null, A = (e) => {
|
|
33
|
-
e === "*" ? f(".ns").forEach(d) : d(typeof e == "number" ? I(e) : k());
|
|
34
|
-
}, N = () => {
|
|
35
|
-
var e;
|
|
36
|
-
(e = h("#" + l)) == null || e.remove(), r.append(v(`<style id=${l}>${b}</style>`));
|
|
37
|
-
}, S = () => (N(), {
|
|
38
|
-
show: z,
|
|
39
|
-
hide: A,
|
|
40
|
-
version: m
|
|
41
|
-
});
|
|
42
|
-
export {
|
|
43
|
-
S as useNs
|
|
44
|
-
};
|
package/dist/iife/ns.iife.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(function(){"use strict";const y='@keyframes nsRotate{to{transform:rotate(360deg)}}@keyframes nsDash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}to{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes nsFade{0%{opacity:0}to{opacity:1}}@keyframes nsAscend{0%{opacity:0;transform:translateY(13px)}to{opacity:1;transform:translateY(0)}}:root{--ns-top: 0px}.ns,body.nsh,body.nsh:before,.nsh:before{width:100%;height:100%}.ns,.nsh:before{bottom:0;right:0}.ns{display:flex;justify-content:center;align-items:center}.nsh{--color: DarkSlateGray;--size: 20px;--relSize: calc(var(--size) * .9);--font: "Helvetica", "Arial", sans-serif;--weight: 400;--bg: rgba(255, 255, 255, .9);--zIdx: 999999999;--blur: blur(5px)}.nsh{position:relative;z-index:var(--zIdx)}.nsh:before{position:absolute;background-color:var(--bg);content:"";backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);z-index:calc(var(--zIdx) + 1);border-radius:inherit}body.nsh,body.nsh:before{position:fixed;top:var(--ns-top);left:0}.ns{position:absolute;z-index:calc(var(--zIdx) + 2);animation:nsFade 2s;gap:var(--relSize)}.nst{color:var(--color);font-size:var(--size);font-family:var(--font);font-weight:var(--weight);max-width:80dvw;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-shadow:0 0 .06rem rgba(47,79,79,.25);filter:drop-shadow(0 0 .07rem rgba(0,0,0,.25));animation:nsAscend .5s}.nss{display:block;width:var(--relSize);height:var(--relSize);animation:nsAscend .5s}.nss>svg{animation:nsRotate 2s linear infinite;position:relative;width:inherit;height:inherit;stroke-width:8}.nss .path{stroke:var(--color);stroke-linecap:round;animation:nsDash 1.5s ease-in-out infinite}',b="4.0.0",c="ns",r=document,i=r.body,a=e=>(s=>({all:s,first:t=>s(t)[0]??null}))(s=>Array.from(e.querySelectorAll(s))),l=e=>a(r).all(e),d=e=>a(r).first(e),f=()=>l(".ns"),m=e=>e instanceof Element?e:d(e),o=(e,...s)=>{const t=r.createElement("div");return e&&t.classList.add(e),t.append(...s),t},h=e=>{const s=o();return s.innerHTML=e,s.firstChild},u=()=>{const s=h('<svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none /></svg>'),t=o("ns",o("nst"),o("nss",s));return t.nsId=Date.now(),t},g=()=>f().sort((e,s)=>e.nsId-s.nsId)[0]??null,w=(e,s)=>{const t=a(e).first(".nst");if(!s)return t==null?void 0:t.remove();const n=o("nst",s);t?t.replaceWith(n):e.insertBefore(n,e.firstChild)},k=(e,s)=>{const t=s.firstElementChild;t&&s.insertBefore(e,t),s.append(e),s.classList.add("nsh")},x=(e,s)=>{const t=s?m(s):i;let n;const v=a(t??i).first("& > .ns");v?n=v:(n=u(),k(n,t)),w(n,e??"");const S=scrollY+"px";return i.style.setProperty("--ns-top",S),n.nsId},p=e=>{var s;(s=e==null?void 0:e.parentElement)==null||s.classList.remove("nsh"),e==null||e.remove()},z=e=>f().find(s=>s.nsId===e)??null,I=e=>{e==="*"?l(".ns").forEach(p):p(typeof e=="number"?z(e):g())},A=()=>{var e;(e=d("#"+c))==null||e.remove(),i.append(h(`<style id=${c}>${y}</style>`))},N=()=>(A(),{show:x,hide:I,version:b});window.ns=N()})();
|