nanosplash 2.5.2 → 3.0.0
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 +48 -0
- package/.prettierrc +10 -9
- package/README.md +22 -89
- package/dist/main.css +1 -0
- package/dist/ns.cjs.js +1 -0
- package/dist/ns.es.js +330 -0
- package/dist/ns.iife.js +2 -0
- package/index.html +41 -122
- package/package.json +27 -34
- package/src/main.ts +8 -5
- package/src/sass/ns.sass +86 -0
- package/src/ts/core/Nanosplash/Nanosplash.ts +97 -0
- package/src/ts/core/Nanosplash/interfaces/NanosplashAPI.ts +50 -0
- package/src/ts/core/Nanosplash/interfaces/NanosplashInterface.ts +42 -0
- package/src/ts/core/Nanosplash/repositories/NanosplashRepository.ts +178 -0
- package/src/ts/core/Nanosplash/services/NanosplashService.ts +222 -0
- package/src/ts/types/Alias.d.ts +1 -0
- package/src/ts/types/Nanosplash.d.ts +18 -0
- package/src/ts/types/NanosplashService.d.ts +1 -0
- package/src/ts/util/Guid.ts +13 -0
- package/src/ts/util/Stack.ts +73 -0
- package/src/vite-env.d.ts +8 -0
- package/tests/Guid.spec.ts +21 -0
- package/tests/Nanosplash.spec.ts +64 -0
- package/tests/NanosplashRepository.spec.ts +91 -0
- package/tests/NanosplashService.spec.ts +119 -0
- package/tests/Stack.spec.ts +56 -0
- package/tsconfig.json +9 -5
- package/vite.config.ts +22 -14
- package/.github/workflows/production.yml +0 -60
- package/.github/workflows/release.yml +0 -61
- package/LICENSE +0 -21
- package/_config.yml +0 -1
- package/dist/iife/manifest.json +0 -7
- package/dist/iife/nanosplash.iife.js +0 -1
- package/dist/module/manifest.json +0 -7
- package/dist/module/nanosplash.cjs.js +0 -1
- package/dist/module/nanosplash.es.js +0 -371
- package/dist/module/style.css +0 -1
- package/docs/index.html +0 -131
- package/docs/nanosplash.iife.js +0 -6
- package/docs/style.css +0 -1
- package/docs/typedoc/.nojekyll +0 -1
- package/docs/typedoc/assets/highlight.css +0 -22
- package/docs/typedoc/assets/icons.css +0 -1043
- package/docs/typedoc/assets/icons.png +0 -0
- package/docs/typedoc/assets/icons@2x.png +0 -0
- package/docs/typedoc/assets/main.js +0 -52
- package/docs/typedoc/assets/search.js +0 -1
- package/docs/typedoc/assets/style.css +0 -1414
- package/docs/typedoc/assets/widgets.png +0 -0
- package/docs/typedoc/assets/widgets@2x.png +0 -0
- package/docs/typedoc/classes/Core_Nanosplash.default.html +0 -133
- package/docs/typedoc/index.html +0 -1
- package/docs/typedoc/modules/Core_Nanosplash.html +0 -1
- package/docs/typedoc/modules/types.html +0 -1
- package/favicon.svg +0 -15
- package/postcss.config.js +0 -8
- package/src/Core/Nanosplash.ts +0 -257
- package/src/Core/SplashInstance.ts +0 -298
- package/src/Exceptions/DestinationException.ts +0 -13
- package/src/Exceptions/Exception.ts +0 -9
- package/src/Exceptions/IllegalArgumentException.ts +0 -11
- package/src/Factory/NanosplashFactory.ts +0 -93
- package/src/Interfaces/ContextualAPIInterface.ts +0 -8
- package/src/Interfaces/IdentityInterface.ts +0 -3
- package/src/Interfaces/InsideInterface.ts +0 -5
- package/src/Interfaces/NanosplashInterface.ts +0 -8
- package/src/Interfaces/ProgressInterface.ts +0 -5
- package/src/Interfaces/ShowInterface.ts +0 -5
- package/src/Interfaces/WhileInterface.ts +0 -5
- package/src/Repositories/NanosplashRepository.ts +0 -82
- package/src/Tests/dom.spec.ts +0 -72
- package/src/Utilities/dom.ts +0 -49
- package/src/style.sass +0 -88
- package/src/types.d.ts +0 -59
- package/update-all.sh +0 -3
- package/vite.iife.config.js +0 -72
- package/vite.mod.config.js +0 -71
- package/vite.site.config.js +0 -22
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// @ts-strict
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* # Nanosplash Repository
|
|
5
|
+
* A repository of functions that are used by the Nanosplash classes.
|
|
6
|
+
* @see Nanosplash
|
|
7
|
+
* @see NanosplashService
|
|
8
|
+
* @author Isak K. Hauge <isakhauge@icloud.com>
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { GUIDString } from '../../../types/Alias'
|
|
12
|
+
import type { Destination, DestinationNode } from '../../../types/Nanosplash'
|
|
13
|
+
import Nanosplash from '../Nanosplash'
|
|
14
|
+
import NanosplashService from '../services/NanosplashService'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* # Create
|
|
18
|
+
* Return the main Nanosplash element.
|
|
19
|
+
*/
|
|
20
|
+
export function createElement(): HTMLDivElement {
|
|
21
|
+
return new DOMParser().parseFromString(
|
|
22
|
+
'<div class=ns><div class=ns-content><div class=ns-text></div><div class=ns-spinner><svg viewBox="0 0 50 50"><circle class=path cx=25 cy=25 r=20 fill=none></circle></svg></div></div></div>',
|
|
23
|
+
'text/html'
|
|
24
|
+
).body.firstChild as HTMLDivElement
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* # Inject as First Child
|
|
29
|
+
* Insert the `node` into the `destinationNode` as its first child.
|
|
30
|
+
* @param node Node to inject.
|
|
31
|
+
* @param destinationNode Node in which the first node is to be injected.
|
|
32
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes
|
|
33
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
|
|
34
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild
|
|
35
|
+
* @see https://developer.mozilla.org/docs/Web/API/NodeList/item
|
|
36
|
+
*/
|
|
37
|
+
export function injectAsFirstChild(
|
|
38
|
+
node: Element,
|
|
39
|
+
destinationNode: Element
|
|
40
|
+
): void {
|
|
41
|
+
const destinationNodeHasChildren = destinationNode.children.length > 0
|
|
42
|
+
if (destinationNodeHasChildren) {
|
|
43
|
+
destinationNode.insertBefore(node, destinationNode.children.item(0))
|
|
44
|
+
} else {
|
|
45
|
+
destinationNode.append(node)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* # Set NS Host Class
|
|
51
|
+
* Add or remove the `nsHostClassName` class to the `element`.
|
|
52
|
+
* @param element Element to which the `nsHostClassName` class will be added or removed.
|
|
53
|
+
* @param action Action to perform ('add' or 'remove').
|
|
54
|
+
*/
|
|
55
|
+
export function setNSHostClass(
|
|
56
|
+
element: Element | null,
|
|
57
|
+
action: 'add' | 'remove'
|
|
58
|
+
): void {
|
|
59
|
+
element?.classList[action](Nanosplash.nsHostClassName)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* # Prepare Parent
|
|
64
|
+
* Add the `nsHostClassName` class to the parent of the `ns` element.
|
|
65
|
+
* @param ns Nanosplash instance.
|
|
66
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/parentElement
|
|
67
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/add
|
|
68
|
+
*/
|
|
69
|
+
export function prepareParentOf(ns: Nanosplash): void {
|
|
70
|
+
setNSHostClass(ns.getNSElement().parentElement, 'add')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* # Clean Parent
|
|
75
|
+
* Remove the `nsHostClassName` class from the parent of the `ns` element.
|
|
76
|
+
* @param ns Nanosplash instance.
|
|
77
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/parentElement
|
|
78
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/remove
|
|
79
|
+
*/
|
|
80
|
+
export function cleanNSParentOf(ns: Nanosplash): void {
|
|
81
|
+
setNSHostClass(ns.getNSElement().parentElement, 'remove')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* # Show Element
|
|
86
|
+
* Set the `display` property of the `element` to `flex`.
|
|
87
|
+
* @param element Element to show.
|
|
88
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/display
|
|
89
|
+
*/
|
|
90
|
+
export function showElement(element: HTMLElement): void {
|
|
91
|
+
element.style.display = 'flex'
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* # Hide Element
|
|
96
|
+
* Set the `display` property of the `element` to `none`.
|
|
97
|
+
* @param element Element to hide.
|
|
98
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/display
|
|
99
|
+
*/
|
|
100
|
+
export function hideElement(element: HTMLElement): void {
|
|
101
|
+
element.style.display = 'none'
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* # Node From
|
|
106
|
+
* Convert the `destination` to a HTMLElement, Element, Node or null.
|
|
107
|
+
* @param destination Destination of the node.
|
|
108
|
+
* @returns Node from the `destination`.
|
|
109
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement
|
|
110
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element
|
|
111
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Node
|
|
112
|
+
*/
|
|
113
|
+
export function nodeFrom(destination: Destination): DestinationNode | null {
|
|
114
|
+
let elem: HTMLElement | null
|
|
115
|
+
|
|
116
|
+
if (typeof destination === 'string') {
|
|
117
|
+
elem = document.querySelector(destination)
|
|
118
|
+
} else if (destination instanceof Node) {
|
|
119
|
+
return destination
|
|
120
|
+
} else if (typeof destination === 'function') {
|
|
121
|
+
elem = <HTMLElement>destination()
|
|
122
|
+
if (!(elem instanceof Node)) {
|
|
123
|
+
return null
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
elem = null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return elem
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* # Element Is NS
|
|
134
|
+
* Check if the element is Nanosplash element.
|
|
135
|
+
* This is determined by the presence of the `ns` class on the element.
|
|
136
|
+
* @param element Element to check.
|
|
137
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/contains
|
|
138
|
+
*/
|
|
139
|
+
export function elementIsNS(element: Element): boolean {
|
|
140
|
+
return element?.classList?.contains('ns')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* # Move
|
|
145
|
+
* Move an Element to another Element.
|
|
146
|
+
* @param element Element to move
|
|
147
|
+
* @param destinationElement Target element
|
|
148
|
+
*/
|
|
149
|
+
export function move(element: Element, destinationElement: Element): void {
|
|
150
|
+
// Clean the current NS host element.
|
|
151
|
+
setNSHostClass(element.parentElement, 'remove')
|
|
152
|
+
// Assign new NS host element.
|
|
153
|
+
setNSHostClass(destinationElement, 'add')
|
|
154
|
+
injectAsFirstChild(element, destinationElement)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* # Get Recycled NS
|
|
159
|
+
* Return the Nanosplash instance inside the `destination` if it exists.
|
|
160
|
+
* @param destination Destination of the Nanosplash instance.
|
|
161
|
+
* @returns { Nanosplash | null } Nanosplash instance or null.
|
|
162
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Node/firstChild
|
|
163
|
+
*/
|
|
164
|
+
export function getRecycledNS(destination: Destination): Nanosplash | null {
|
|
165
|
+
const destinationNode = nodeFrom(destination)
|
|
166
|
+
if (!destinationNode) return null
|
|
167
|
+
const firstChild = <Element>destinationNode.firstChild
|
|
168
|
+
const hasChild = firstChild !== null
|
|
169
|
+
const destinationAlreadyHasNS = hasChild && elementIsNS(firstChild)
|
|
170
|
+
|
|
171
|
+
if (destinationAlreadyHasNS) {
|
|
172
|
+
const id: GUIDString = firstChild.id
|
|
173
|
+
const nss = NanosplashService.getInstance()
|
|
174
|
+
return nss.nsStack.items.find((ns: Nanosplash) => ns.getId() === id) ?? null
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// @ts-strict
|
|
2
|
+
|
|
3
|
+
import Nanosplash from '../Nanosplash'
|
|
4
|
+
import Stack from '../../../util/Stack'
|
|
5
|
+
import {
|
|
6
|
+
cleanNSParentOf,
|
|
7
|
+
getRecycledNS,
|
|
8
|
+
move,
|
|
9
|
+
nodeFrom,
|
|
10
|
+
} from '../repositories/NanosplashRepository'
|
|
11
|
+
import type { Destination, DestinationNode } from '../../../types/Nanosplash'
|
|
12
|
+
import type { GUIDString } from '../../../types/Alias'
|
|
13
|
+
import { FindCallback } from '../../../types/NanosplashService'
|
|
14
|
+
import { NanosplashAPI } from '../interfaces/NanosplashAPI'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* # Nanosplash Service
|
|
18
|
+
* A service class that handles Nanosplash instances.
|
|
19
|
+
* It's a singleton class and it's instance resides in the Window object and
|
|
20
|
+
* serves the public API of the Nanosplash library.
|
|
21
|
+
* @see Nanosplash
|
|
22
|
+
* @author Isak K. Hauge <isakhauge@icloud.com>
|
|
23
|
+
*/
|
|
24
|
+
class NanosplashService implements NanosplashAPI {
|
|
25
|
+
private static readonly WindowAccessorKey = 'ns'
|
|
26
|
+
private static instance: NanosplashService
|
|
27
|
+
|
|
28
|
+
public readonly nsStack: Stack<Nanosplash>
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* # Constructor
|
|
32
|
+
* Private constructor to prevent multiple instances.
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
private constructor() {
|
|
36
|
+
this.nsStack = new Stack<Nanosplash>()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* # Find Index
|
|
41
|
+
* Find Nanosplash stack index by callback.
|
|
42
|
+
* @param callback Callback function that returns a boolean.
|
|
43
|
+
* @returns {number} Index of Nanosplash instance in the stack or -1.
|
|
44
|
+
*/
|
|
45
|
+
private findIndex(callback: FindCallback): number | -1 {
|
|
46
|
+
return this.nsStack.items.findIndex(callback)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* # Find
|
|
51
|
+
* Find Nanosplash in the stack by callback.
|
|
52
|
+
* @param callback Callback function that returns a boolean.
|
|
53
|
+
* @returns {Nanosplash | undefined} Nanosplash instance or undefined
|
|
54
|
+
*/
|
|
55
|
+
private find(callback: FindCallback): Nanosplash | undefined {
|
|
56
|
+
return this.nsStack.items.find(callback)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* # Get Instance
|
|
61
|
+
* Singleton instance accessor
|
|
62
|
+
* @returns {NanosplashService} NanosplashService instance
|
|
63
|
+
*/
|
|
64
|
+
public static getInstance(): NanosplashService {
|
|
65
|
+
if (!NanosplashService.instance) {
|
|
66
|
+
NanosplashService.instance = new NanosplashService()
|
|
67
|
+
}
|
|
68
|
+
return NanosplashService.instance
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* # Assign To Window
|
|
73
|
+
* Assign Nanosplash service instance to Window object.
|
|
74
|
+
* The NanosplashService instance can be accessed in the window object
|
|
75
|
+
* using the key window accessor key.
|
|
76
|
+
* @see WindowAccessorKey
|
|
77
|
+
*/
|
|
78
|
+
private static assignToWindow(): void {
|
|
79
|
+
Object.defineProperty(window, NanosplashService.WindowAccessorKey, {
|
|
80
|
+
value: NanosplashService.getInstance(),
|
|
81
|
+
writable: false,
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* # Start
|
|
87
|
+
* Initialize Nanosplash Service instance in Window when it's loaded.
|
|
88
|
+
*/
|
|
89
|
+
public static start(): void {
|
|
90
|
+
NanosplashService.assignToWindow()
|
|
91
|
+
window.addEventListener('load', () => {
|
|
92
|
+
const nss = window[NanosplashService.WindowAccessorKey]
|
|
93
|
+
const nssAssigned = nss instanceof NanosplashService
|
|
94
|
+
if (!nssAssigned) {
|
|
95
|
+
NanosplashService.assignToWindow()
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* # Create Nanosplash
|
|
102
|
+
* Return new Nanosplash instance and push it to the stack.
|
|
103
|
+
* @param text Text to display.
|
|
104
|
+
* @returns {Nanosplash} Nanosplash instance.
|
|
105
|
+
*/
|
|
106
|
+
private createNS(text?: string): Nanosplash {
|
|
107
|
+
const ns = new Nanosplash()
|
|
108
|
+
ns.setText(text || '')
|
|
109
|
+
this.nsStack.push(ns)
|
|
110
|
+
return ns
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* # Clean And Remove
|
|
115
|
+
* Remove Nanosplash from DOM and clean its parent.
|
|
116
|
+
* @param ns Nanosplash instance.
|
|
117
|
+
* @returns {GUIDString} Nanosplash ID.
|
|
118
|
+
*/
|
|
119
|
+
private cleanAndRemove(ns: Nanosplash): GUIDString {
|
|
120
|
+
cleanNSParentOf(ns)
|
|
121
|
+
ns.remove()
|
|
122
|
+
return ns.getId()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* # Stack Delete At
|
|
127
|
+
* Remove Nanosplash instance from the stack.
|
|
128
|
+
* @param ns Nanosplash instance.
|
|
129
|
+
* @returns {GUIDString | null} Nanosplash ID or null if it doesn't exist.
|
|
130
|
+
*/
|
|
131
|
+
private stackDelete(ns: Nanosplash): GUIDString | null {
|
|
132
|
+
let index = this.findIndex((o: Nanosplash) => o.getId() === ns.getId())
|
|
133
|
+
if (index < 0) return null
|
|
134
|
+
this.nsStack.items.splice(index, 1)
|
|
135
|
+
return ns.getId()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* # Delete NS
|
|
140
|
+
* Remove Nanosplash instance from both the stack and the DOM.
|
|
141
|
+
* @param callback Callback function.
|
|
142
|
+
* @returns {GUIDString | null} Nanosplash ID or null if it doesn't exist.
|
|
143
|
+
*/
|
|
144
|
+
private deleteNS(callback: FindCallback): GUIDString | null {
|
|
145
|
+
const ns = this.find(callback)
|
|
146
|
+
if (ns) {
|
|
147
|
+
this.cleanAndRemove(ns)
|
|
148
|
+
return this.stackDelete(ns)
|
|
149
|
+
}
|
|
150
|
+
return null
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @inheritDoc
|
|
155
|
+
*/
|
|
156
|
+
public show(text?: string): GUIDString {
|
|
157
|
+
let ns = getRecycledNS(document.body)
|
|
158
|
+
if (!ns) {
|
|
159
|
+
ns = this.createNS()
|
|
160
|
+
move(ns.getNSElement(), document.body)
|
|
161
|
+
}
|
|
162
|
+
ns.setText(text || '')
|
|
163
|
+
return ns.getId()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @inheritDoc
|
|
168
|
+
*/
|
|
169
|
+
public showInside(
|
|
170
|
+
destination: Destination,
|
|
171
|
+
text?: string
|
|
172
|
+
): GUIDString | null {
|
|
173
|
+
const destinationNode: DestinationNode | null = nodeFrom(destination)
|
|
174
|
+
if (destinationNode) {
|
|
175
|
+
let ns = getRecycledNS(destinationNode)
|
|
176
|
+
if (!ns) {
|
|
177
|
+
ns = this.createNS()
|
|
178
|
+
}
|
|
179
|
+
ns.setText(text || '')
|
|
180
|
+
move(ns.getNSElement(), <Element>destinationNode)
|
|
181
|
+
return ns.getId()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @inheritDoc
|
|
189
|
+
*/
|
|
190
|
+
public hideAll(): void {
|
|
191
|
+
this.nsStack.items.forEach((ns: Nanosplash) => {
|
|
192
|
+
this.cleanAndRemove(ns)
|
|
193
|
+
})
|
|
194
|
+
this.nsStack.clear()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* @inheritDoc
|
|
199
|
+
*/
|
|
200
|
+
public hide(): GUIDString | null {
|
|
201
|
+
const ns = this.nsStack.pop()
|
|
202
|
+
return ns ? this.cleanAndRemove(ns) : null
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @inheritDoc
|
|
207
|
+
*/
|
|
208
|
+
public hideId(id: GUIDString): GUIDString | null {
|
|
209
|
+
return this.deleteNS((ns: Nanosplash) => ns.getId() === id)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @inheritDoc
|
|
214
|
+
*/
|
|
215
|
+
public hideInside(destination: Destination): GUIDString | null {
|
|
216
|
+
const node = nodeFrom(destination)
|
|
217
|
+
const cb = (ns: Nanosplash) => ns.getNSElement().parentElement === node
|
|
218
|
+
return node ? this.deleteNS(cb) : null
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export default NanosplashService
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type GUIDString = string
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type DestinationSelector = string
|
|
2
|
+
|
|
3
|
+
export type DestinationNode = Node | Element | HTMLElement
|
|
4
|
+
|
|
5
|
+
export type DestinationCallback = () =>
|
|
6
|
+
| DestinationNode
|
|
7
|
+
| Promise<DestinationNode>
|
|
8
|
+
|
|
9
|
+
export type Destination =
|
|
10
|
+
| DestinationSelector
|
|
11
|
+
| DestinationNode
|
|
12
|
+
| DestinationCallback
|
|
13
|
+
|
|
14
|
+
declare global {
|
|
15
|
+
interface Window {
|
|
16
|
+
ns: NanosplashService
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type FindCallback = (ns: Nanosplash, index: number) => boolean
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { GUIDString } from '../types/Alias'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* # GUID
|
|
5
|
+
* @returns {GUIDString} A GUID string.
|
|
6
|
+
*/
|
|
7
|
+
export function guid(): GUIDString {
|
|
8
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
|
9
|
+
const r = (Math.random() * 16) | 0
|
|
10
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
|
11
|
+
return v.toString(16)
|
|
12
|
+
})
|
|
13
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// @ts-strict
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A stack data structure.
|
|
5
|
+
* @template T The type of item stored in the stack.
|
|
6
|
+
* @author Isak K. Hauge <isakhauge@icloud.com>
|
|
7
|
+
*/
|
|
8
|
+
class Stack<T> {
|
|
9
|
+
private _items: T[]
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new stack.
|
|
13
|
+
*/
|
|
14
|
+
constructor() {
|
|
15
|
+
this._items = []
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns the items in the stack.
|
|
20
|
+
*/
|
|
21
|
+
public get items(): T[] {
|
|
22
|
+
return this._items
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Adds an item to the top of the stack.
|
|
27
|
+
* @param item The item to add to the stack.
|
|
28
|
+
*/
|
|
29
|
+
public push(item: T): void {
|
|
30
|
+
this._items.push(item)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Removes and returns the item at the top of the stack.
|
|
35
|
+
* @returns The item at the top of the stack, or undefined if the stack is empty.
|
|
36
|
+
*/
|
|
37
|
+
public pop(): T | undefined {
|
|
38
|
+
return this._items.pop()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns the item at the top of the stack without removing it.
|
|
43
|
+
* @returns The item at the top of the stack, or undefined if the stack is empty.
|
|
44
|
+
*/
|
|
45
|
+
public peek(): T | undefined {
|
|
46
|
+
return this._items[this._items.length - 1]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns true if the stack is empty, false otherwise.
|
|
51
|
+
* @returns True if the stack is empty, false otherwise.
|
|
52
|
+
*/
|
|
53
|
+
public isEmpty(): boolean {
|
|
54
|
+
return this._items.length === 0
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns the number of items in the stack.
|
|
59
|
+
* @returns The number of items in the stack.
|
|
60
|
+
*/
|
|
61
|
+
public size(): number {
|
|
62
|
+
return this._items.length
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Removes all items from the stack.
|
|
67
|
+
*/
|
|
68
|
+
public clear(): void {
|
|
69
|
+
this._items = []
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default Stack
|
package/src/vite-env.d.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest'
|
|
2
|
+
import Nanosplash from '../src/ts/core/Nanosplash/Nanosplash'
|
|
3
|
+
import { JSDOM } from 'jsdom'
|
|
4
|
+
|
|
5
|
+
describe('Guid', () => {
|
|
6
|
+
// Reset the DOM before each test
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
const dom = new JSDOM()
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
globalThis.window = dom.window
|
|
11
|
+
globalThis.document = dom.window.document
|
|
12
|
+
globalThis.DOMParser = dom.window.DOMParser
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('Should generate a valid GUID', () => {
|
|
16
|
+
const guidRegex =
|
|
17
|
+
/^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$/
|
|
18
|
+
const value = new Nanosplash().getId()
|
|
19
|
+
expect(value).toMatch(guidRegex)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @ts-strict
|
|
2
|
+
|
|
3
|
+
import { describe, it, expect, beforeEach } from 'vitest'
|
|
4
|
+
import Nanosplash from '../src/ts/core/Nanosplash/Nanosplash'
|
|
5
|
+
import { JSDOM } from 'jsdom'
|
|
6
|
+
|
|
7
|
+
describe('Nanosplash', () => {
|
|
8
|
+
// Reset the DOM before each test
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
const dom = new JSDOM()
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
globalThis.window = dom.window
|
|
13
|
+
globalThis.document = dom.window.document
|
|
14
|
+
globalThis.DOMParser = dom.window.DOMParser
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('Should be a valid Nanosplash', () => {
|
|
18
|
+
const ns = new Nanosplash()
|
|
19
|
+
const element = ns.getNSElement()
|
|
20
|
+
|
|
21
|
+
expect(element).not.toBeUndefined()
|
|
22
|
+
expect(element.id).toBe(ns.getId())
|
|
23
|
+
expect(element.classList.contains(Nanosplash.nsClassName)).toBe(true)
|
|
24
|
+
|
|
25
|
+
const contentElement = ns.getNSContentElement()
|
|
26
|
+
expect(contentElement).not.toBeUndefined()
|
|
27
|
+
|
|
28
|
+
const textElement = ns.getNSTextElement()
|
|
29
|
+
expect(textElement).not.toBeUndefined()
|
|
30
|
+
|
|
31
|
+
const spinnerElement = <HTMLElement>textElement.nextElementSibling
|
|
32
|
+
expect(spinnerElement).not.toBeUndefined()
|
|
33
|
+
|
|
34
|
+
const spinnerSVGElement = <HTMLElement>spinnerElement.firstElementChild
|
|
35
|
+
expect(spinnerSVGElement).not.toBeUndefined()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('Should be able to set text', () => {
|
|
39
|
+
const ns = new Nanosplash()
|
|
40
|
+
const text = 'Hello World!'
|
|
41
|
+
ns.setText(text)
|
|
42
|
+
expect(ns.getNSTextElement().innerText).toBe(text)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('Should be able to hide text', () => {
|
|
46
|
+
const ns = new Nanosplash()
|
|
47
|
+
ns.hideText()
|
|
48
|
+
expect(ns.getNSTextElement().style.display).toBe('none')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('Should be able to show text', () => {
|
|
52
|
+
const ns = new Nanosplash()
|
|
53
|
+
ns.setText('Hello World!')
|
|
54
|
+
ns.hideText()
|
|
55
|
+
ns.showText()
|
|
56
|
+
expect(ns.getNSTextElement().style.display).toBe('flex')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('Should be able to remove itself from DOM', () => {
|
|
60
|
+
const ns = new Nanosplash()
|
|
61
|
+
ns.remove()
|
|
62
|
+
expect(ns.getNSElement()).toBeUndefined()
|
|
63
|
+
})
|
|
64
|
+
})
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// @ts-strict
|
|
2
|
+
|
|
3
|
+
import { JSDOM } from 'jsdom'
|
|
4
|
+
import { beforeEach, describe, expect, it } from 'vitest'
|
|
5
|
+
import Nanosplash from '../src/ts/core/Nanosplash/Nanosplash'
|
|
6
|
+
import {
|
|
7
|
+
createElement,
|
|
8
|
+
injectAsFirstChild,
|
|
9
|
+
prepareParentOf,
|
|
10
|
+
cleanNSParentOf,
|
|
11
|
+
showElement,
|
|
12
|
+
hideElement,
|
|
13
|
+
setNSHostClass,
|
|
14
|
+
move,
|
|
15
|
+
} from '../src/ts/core/Nanosplash/repositories/NanosplashRepository'
|
|
16
|
+
|
|
17
|
+
describe('NanosplashRepository', () => {
|
|
18
|
+
// Reset the DOM before each test
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
const dom = new JSDOM()
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
globalThis.window = dom.window
|
|
23
|
+
globalThis.document = dom.window.document
|
|
24
|
+
globalThis.DOMParser = dom.window.DOMParser
|
|
25
|
+
globalThis.Node = dom.window.Node
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('Should be able to create a Nanosplash component', () => {
|
|
29
|
+
const getClass = (element: Element) => element.classList[0]
|
|
30
|
+
const element = createElement()
|
|
31
|
+
const contentElement = <Element>element.firstElementChild
|
|
32
|
+
const textElement = <Element>contentElement.firstElementChild
|
|
33
|
+
const spinnerElement = <Element>textElement.nextElementSibling
|
|
34
|
+
|
|
35
|
+
expect(getClass(element)).toBe('ns')
|
|
36
|
+
expect(getClass(contentElement)).toBe('ns-content')
|
|
37
|
+
expect(getClass(textElement)).toBe('ns-text')
|
|
38
|
+
expect(getClass(spinnerElement)).toBe('ns-spinner')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('Should be able to inject a Nanosplash component', () => {
|
|
42
|
+
const element = createElement()
|
|
43
|
+
const destinationElement = document.createElement('div')
|
|
44
|
+
injectAsFirstChild(element, destinationElement)
|
|
45
|
+
expect(destinationElement.firstElementChild).toBe(element)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('Should be able to prepare the parent of a Nanosplash component', () => {
|
|
49
|
+
const ns = new Nanosplash()
|
|
50
|
+
const parent = document.createElement('div')
|
|
51
|
+
parent.appendChild(ns.getNSElement())
|
|
52
|
+
prepareParentOf(ns)
|
|
53
|
+
expect(parent.classList.contains(Nanosplash.nsHostClassName)).toBe(true)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('Should be able to clean the parent of a Nanosplash component', () => {
|
|
57
|
+
const ns = new Nanosplash()
|
|
58
|
+
const parent = document.createElement('div')
|
|
59
|
+
parent.appendChild(ns.getNSElement())
|
|
60
|
+
parent.classList.add(Nanosplash.nsHostClassName)
|
|
61
|
+
cleanNSParentOf(ns)
|
|
62
|
+
expect(parent.classList.contains(Nanosplash.nsHostClassName)).toBe(false)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('Should be able to show an element', () => {
|
|
66
|
+
const element = document.createElement('div')
|
|
67
|
+
showElement(element)
|
|
68
|
+
expect(element.style.display).toBe('flex')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('Should be able to hide an element', () => {
|
|
72
|
+
const element = document.createElement('div')
|
|
73
|
+
hideElement(element)
|
|
74
|
+
expect(element.style.display).toBe('none')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('Should be able to alter the class of a Nanosplash host', () => {
|
|
78
|
+
const div = document.createElement('div')
|
|
79
|
+
setNSHostClass(div, 'add')
|
|
80
|
+
expect(div.classList.contains(Nanosplash.nsHostClassName)).toBe(true)
|
|
81
|
+
setNSHostClass(div, 'remove')
|
|
82
|
+
expect(div.classList.contains(Nanosplash.nsHostClassName)).toBe(false)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('Should be able to move a Nanosplash component', () => {
|
|
86
|
+
const ns = new Nanosplash()
|
|
87
|
+
const destination = document.createElement('div')
|
|
88
|
+
move(ns.getNSElement(), destination)
|
|
89
|
+
expect(destination.firstElementChild).toBe(ns.getNSElement())
|
|
90
|
+
})
|
|
91
|
+
})
|