nanosplash 2.3.3 → 2.4.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.
@@ -4,6 +4,10 @@ import {addClass, mk, move, setAttr} from "../utilities/dom";
4
4
  import {IdentityInterface} from "../Interfaces/IdentityInterface";
5
5
  import {NanosplashRepository} from "../repositories/NanosplashRepository";
6
6
 
7
+ /**
8
+ * SplashInstance
9
+ * @author Isak K. Hauge <isakhauge@gmail.com>
10
+ */
7
11
  export class SplashInstance implements IdentityInterface {
8
12
  private readonly id: string
9
13
  private imgSrc: string | undefined
@@ -11,11 +15,18 @@ export class SplashInstance implements IdentityInterface {
11
15
  private destinationNode: HTMLElement | undefined
12
16
  private readonly nsRootElement: HTMLDivElement = mk('div') as HTMLDivElement
13
17
  private readonly nsTextElement: HTMLDivElement = mk('div') as HTMLDivElement
18
+ private readonly nsTextContainerElement: HTMLDivElement = mk('div') as HTMLDivElement
19
+ private readonly nsSpinnerElement: HTMLDivElement = NanosplashRepository.createNanosplashSpinnerElement()
14
20
  private readonly nsWindowElement: HTMLDivElement = mk('div') as HTMLDivElement
15
21
  private readonly nsWrapperElement: HTMLDivElement = mk('div') as HTMLDivElement
16
22
  private readonly nsContentElement: HTMLDivElement = mk('div') as HTMLDivElement
17
23
  private readonly nsImageElement: HTMLImageElement = mk('img') as HTMLImageElement
18
24
 
25
+ /**
26
+ * @param {Nanosplash} ns Nanosplash instance
27
+ * @param {string} text Text
28
+ * @param {string|undefined} imgSrc Image source URL
29
+ */
19
30
  public constructor(ns: Nanosplash, text: string, imgSrc?: string) {
20
31
  this.id = Math.random().toString(36).substring(2)
21
32
  this.nsInstance = ns
@@ -25,27 +36,48 @@ export class SplashInstance implements IdentityInterface {
25
36
  this.nsImageElement.src = this.imgSrc ?? ''
26
37
  this.nsImageElement.alt = Nanosplash.APP_NAME
27
38
 
39
+ this.nsRootElement.style.fontSize = ns.fontSize
40
+ this.nsSpinnerElement.style.display = ns.showSpinner ? 'flex' : 'none'
41
+
28
42
  this.assembleNSComponent()
29
43
  this.setImgSrc(imgSrc)
30
44
  }
31
45
 
46
+ /**
47
+ * # Assign CSS Classes
48
+ * Assigns CSS class names to all elements connected to this splash instance.
49
+ * @private
50
+ */
32
51
  private assignCSSClasses(): void
33
52
  {
34
53
  addClass(this.nsContentElement, 'ns-container')
35
54
  addClass(this.nsWrapperElement, 'ns-blur')
36
55
  addClass(this.nsImageElement, 'ns-img')
37
56
  addClass(this.nsTextElement, 'ns-text')
57
+ addClass(this.nsTextContainerElement, 'ns-text-container')
58
+ addClass(this.nsSpinnerElement, 'ns-spinner')
38
59
  addClass(this.nsWindowElement, 'ns', 'ns-window')
39
60
  addClass(this.nsRootElement, 'ns-wrapper')
40
61
  }
41
62
 
63
+ /**
64
+ * # Assemble Element Structure
65
+ * Assembles all elements connected to this splash instance in a fixed structure.
66
+ * @private
67
+ */
42
68
  private assembleElementStructure(): void
43
69
  {
44
- this.nsContentElement.append(this.nsImageElement, this.nsTextElement)
70
+ this.nsTextContainerElement.append(this.nsTextElement, this.nsSpinnerElement)
71
+ this.nsContentElement.append(this.nsImageElement, this.nsTextContainerElement)
45
72
  this.nsWindowElement.append(this.nsContentElement)
46
73
  this.nsRootElement.append(this.nsWrapperElement, this.nsWindowElement)
47
74
  }
48
75
 
76
+ /**
77
+ * # Assemble Nanosplash Component
78
+ * Assembles all elements into one component that represents the Nanosplash component.
79
+ * @private
80
+ */
49
81
  private assembleNSComponent(): void {
50
82
  this.nsRootElement.id = this.getId()
51
83
  setAttr(this.nsRootElement, 'data-ctx', 'nanosplash')
@@ -53,26 +85,48 @@ export class SplashInstance implements IdentityInterface {
53
85
  this.assignCSSClasses()
54
86
  }
55
87
 
88
+ /**
89
+ * # Get ID
90
+ * @return string
91
+ */
56
92
  public getId(): string
57
93
  {
58
94
  return this.id
59
95
  }
60
96
 
97
+ /**
98
+ * Get Text
99
+ * @return string
100
+ */
61
101
  public getText(): string
62
102
  {
63
103
  return this.nsTextElement.innerText
64
104
  }
65
105
 
106
+ /**
107
+ * # Set Text
108
+ * @param {string} text Text
109
+ * @return SplashInstance
110
+ */
66
111
  public setText(text: string): SplashInstance {
67
112
  this.nsTextElement.innerText = text
68
113
  return this
69
114
  }
70
115
 
116
+ /**
117
+ * # Get Image Source
118
+ * @return string | undefined
119
+ */
71
120
  public getImgSrc(): string | undefined
72
121
  {
73
122
  return this.imgSrc
74
123
  }
75
124
 
125
+ /**
126
+ * # Set Image Source
127
+ * @param {string|undefined} src Source URL
128
+ * @return SplashInstance
129
+ */
76
130
  public setImgSrc(src?: string): SplashInstance
77
131
  {
78
132
  this.nsImageElement.src = src ?? ''
@@ -81,11 +135,20 @@ export class SplashInstance implements IdentityInterface {
81
135
  return this
82
136
  }
83
137
 
138
+ /**
139
+ * # Get Destination
140
+ * @return HTMLElement | undefined
141
+ */
84
142
  public getDestination(): HTMLElement | undefined
85
143
  {
86
144
  return this.destinationNode
87
145
  }
88
146
 
147
+ /**
148
+ * # Clean And Restore
149
+ * Cleans and restore the DOM structure.
150
+ * @private
151
+ */
89
152
  private cleanAndRestore(): void
90
153
  {
91
154
  const currentParent = this.nsRootElement.parentElement
@@ -94,12 +157,24 @@ export class SplashInstance implements IdentityInterface {
94
157
  }
95
158
  }
96
159
 
160
+ /**
161
+ * # Reset Fullscreen Attributes
162
+ * Removes the fullscreen attributes and CSS class names.
163
+ * @private
164
+ */
97
165
  private resetFullscreenAttributes(): void
98
166
  {
99
167
  setAttr(this.nsRootElement, 'style', '')
100
168
  this.nsRootElement.classList.remove('ns-fs')
101
169
  }
102
170
 
171
+ /**
172
+ * # Move with Regular Strategy
173
+ * Moves the Nanosplash root element to the target node's position and essentially wraps the target node with the
174
+ * Nanosplash root element.
175
+ * @param {Node} targetNode
176
+ * @private
177
+ */
103
178
  private moveWithRegularStrategy(targetNode: Node): void
104
179
  {
105
180
  const targetParentNode = targetNode.parentNode
@@ -110,12 +185,23 @@ export class SplashInstance implements IdentityInterface {
110
185
  }
111
186
  }
112
187
 
188
+ /**
189
+ * # Move With Fullscreen Strategy
190
+ * Moves the Nanosplash root element inside the body element.
191
+ * @private
192
+ */
113
193
  private moveWithFullscreenStrategy(): void
114
194
  {
115
195
  this.nsRootElement.classList.add('ns-fs')
116
196
  move(this.nsRootElement, document.body, true)
117
197
  }
118
198
 
199
+ /**
200
+ * # Replace Splash Instances Having Same Destination
201
+ * Delete all Splash instances residing inside the same destination node.
202
+ * @param {HTMLElement} destinationNode
203
+ * @private
204
+ */
119
205
  private replaceSplashInstancesHavingSameDestination(destinationNode: HTMLElement): void
120
206
  {
121
207
  const fnNotSameInstance = (v: SplashInstance) => v.getId() !== this.getId()
@@ -123,6 +209,11 @@ export class SplashInstance implements IdentityInterface {
123
209
  this.nsInstance.getSplashesWithDestinationNode(destinationNode).filter(fnNotSameInstance).forEach(fnDelete)
124
210
  }
125
211
 
212
+ /**
213
+ * # Move To
214
+ * This function moves the Nanosplash root element to a destination.
215
+ * @param {Destination} destination
216
+ */
126
217
  public moveTo(destination: Destination): void
127
218
  {
128
219
  // Clean up and restore previous location if any.
@@ -149,20 +240,38 @@ export class SplashInstance implements IdentityInterface {
149
240
  this.assembleNSComponent()
150
241
  }
151
242
 
243
+ /**
244
+ * # For Each Wrapped Node
245
+ * Invokes a callback for each wrapped node.
246
+ * @param {(node: Node) => void} callback
247
+ * @private
248
+ */
152
249
  private forEachWrappedNode(callback: (node: Node) => void): void
153
250
  {
154
251
  Array.from(this.nsWrapperElement.childNodes).forEach(callback)
155
252
  }
156
253
 
254
+ /**
255
+ * # Restore DOM Structure
256
+ * Undo the node wrapping and restore the wrapped nodes' original DOM position.
257
+ * @param {Node} parentNode
258
+ * @private
259
+ */
157
260
  private restoreDOMStructure(parentNode: Node): void
158
261
  {
159
262
  this.forEachWrappedNode((child: Node) => parentNode.insertBefore(child, this.nsRootElement))
160
263
  }
161
264
 
265
+ /**
266
+ * # Remove Elements From DOM
267
+ * @private
268
+ */
162
269
  private removeElementsFromDOM(): void
163
270
  {
164
271
  [
165
272
  this.nsTextElement,
273
+ this.nsSpinnerElement,
274
+ this.nsTextContainerElement,
166
275
  this.nsImageElement,
167
276
  this.nsContentElement,
168
277
  this.nsWrapperElement,
@@ -171,6 +280,10 @@ export class SplashInstance implements IdentityInterface {
171
280
  ].forEach(v => v.remove())
172
281
  }
173
282
 
283
+ /**
284
+ * # Delete
285
+ * Gracefully delete Splash instance and connected elements from DOM.
286
+ */
174
287
  public delete(): void {
175
288
  this.cleanAndRestore()
176
289
  this.removeElementsFromDOM()
@@ -1,4 +1,4 @@
1
- import {ImgFunction, ProgressFunction, ShowFunction, SplashJob, WhileFunction} from "../types";
1
+ import {ProgressFunction, ShowFunction, SplashJob, WhileFunction} from "../types";
2
2
  import {Nanosplash} from "../Core/Nanosplash";
3
3
  import {SplashInstance} from "../Core/SplashInstance";
4
4
  import {NanosplashRepository} from "../repositories/NanosplashRepository";
@@ -17,18 +17,6 @@ export class NanosplashFactory {
17
17
  return splash.setText(text).setImgSrc(splash.getImgSrc() ?? imgSrc)
18
18
  }
19
19
 
20
- public static createImgFunction(ns: Nanosplash, splash: SplashInstance | null): ImgFunction
21
- {
22
- return (src: string) => {
23
- splash = NanosplashFactory.ensureInstance(splash, ns, '', src)
24
- return {
25
- show: NanosplashFactory.createShowFunction(ns, splash),
26
- progress: NanosplashFactory.createProgressFunction(ns, splash),
27
- while: NanosplashFactory.createWhileFunction(ns, splash)
28
- }
29
- }
30
- }
31
-
32
20
  public static createShowFunction(ns: Nanosplash, splash: SplashInstance | null): ShowFunction
33
21
  {
34
22
  return (text: string) => {
@@ -1,4 +1,3 @@
1
1
  import {StrategyObject} from "../types";
2
- import {ImageInterface} from "./ImageInterface";
3
2
 
4
- export interface NanosplashInterface extends StrategyObject, ImageInterface {}
3
+ export interface NanosplashInterface extends StrategyObject {}
package/src/main.ts CHANGED
@@ -1,2 +1,8 @@
1
1
  import {Nanosplash} from "./Core/Nanosplash";
2
- window.addEventListener('load', () => window.ns = new Nanosplash())
2
+ import {NanosplashOptions} from "./types";
3
+ window.addEventListener('load', () => {
4
+ window.Nanosplash = Nanosplash
5
+ window.installNanosplash = (options?: NanosplashOptions) => {
6
+ window.ns = new Nanosplash(options)
7
+ }
8
+ })
@@ -1,4 +1,4 @@
1
- import {get} from "../utilities/dom";
1
+ import {addClass, get, mk} from "../utilities/dom";
2
2
  import {SplashInstance} from "../Core/SplashInstance";
3
3
  import {ContextualAPIObject, Destination} from "../types";
4
4
 
@@ -36,4 +36,16 @@ export class NanosplashRepository {
36
36
  },
37
37
  }
38
38
  }
39
+
40
+ public static createNanosplashSpinnerElement(): HTMLDivElement
41
+ {
42
+ const div = mk('div') as HTMLDivElement
43
+ addClass(div, 'ns-spinner')
44
+ div.innerHTML = `
45
+ <svg viewBox="0 0 50 50">
46
+ <circle class="path" cx="25" cy="25" r="20" fill="none"></circle>
47
+ </svg>
48
+ `
49
+ return div
50
+ }
39
51
  }
package/src/style.sass CHANGED
@@ -1,14 +1,17 @@
1
1
  $z-index-regular: 1
2
2
  $z-index-fullscreen: 2
3
+ $text-color: #5a6685
3
4
  $bg-color: rgba(White, 0.8)
4
5
 
5
6
  %blur
6
7
  overflow: hidden
7
8
  filter: blur(5px)
8
9
 
10
+ // Wraps the content replaced by Nanosplash
9
11
  .ns-wrapper
10
12
  position: relative
11
13
 
14
+ // Only active while in fullscreen mode
12
15
  .ns-fs
13
16
  top: 0
14
17
  left: 0
@@ -17,10 +20,11 @@ $bg-color: rgba(White, 0.8)
17
20
  min-height: 100vh
18
21
  z-index: $z-index-fullscreen
19
22
 
20
- // Fullscreen content blur
23
+ // Blurs the wrapped content
21
24
  body .ns-fs ~ *, .ns-blur
22
25
  @extend %blur
23
26
 
27
+ // Nanosplash window containing image and text
24
28
  .ns-window
25
29
  top: 0
26
30
  left: 0
@@ -33,26 +37,52 @@ body .ns-fs ~ *, .ns-blur
33
37
  z-index: $z-index-regular
34
38
  background-color: $bg-color
35
39
 
40
+ // Image
36
41
  .ns-img
37
- max-width: 9rem
42
+ width: 9rem
38
43
  max-height: 9rem
39
- margin-bottom: 1rem
44
+ margin-bottom: 2em
40
45
 
46
+ // Text container containing text and spinner
47
+ .ns-text-container
48
+ display: flex
49
+ justify-content: center
50
+ align-items: center
51
+
52
+ // Text node
41
53
  .ns-text
42
- color: #333
43
54
  display: flex
44
- text-align: center
45
- &::after
46
- margin-left: 0.25em
47
- content: '\00a0\00a0\00a0'
48
- animation: anim 1s infinite
55
+ justify-content: center
56
+ color: $text-color
57
+
58
+ // Spinner node
59
+ .ns-spinner
60
+ display: flex
61
+ margin-left: 1em
62
+ width: 1em
63
+ height: 1em
64
+ & > svg
65
+ animation: Rotate 2s linear infinite
66
+ position: relative
67
+ width: inherit
68
+ height: inherit
69
+ stroke-width: 8
70
+ & .path
71
+ stroke: $text-color
72
+ stroke-linecap: round
73
+ animation: Dash 1.5s ease-in-out infinite
49
74
 
50
- @keyframes anim
75
+ // Spinner animations:
76
+ @keyframes Rotate
77
+ 100%
78
+ transform: rotate(360deg)
79
+ @keyframes Dash
51
80
  0%
52
- content: '\00a0\00a0\00a0'
53
- 30%
54
- content: '.\00a0\00a0'
55
- 60%
56
- content: '..\00a0'
57
- 90%
58
- content: '...'
81
+ stroke-dasharray: 1, 150
82
+ stroke-dashoffset: 0
83
+ 50%
84
+ stroke-dasharray: 90, 150
85
+ stroke-dashoffset: -35
86
+ 100%
87
+ stroke-dasharray: 90, 150
88
+ stroke-dashoffset: -124
package/src/types.d.ts CHANGED
@@ -5,6 +5,8 @@ import {ContextualAPIInterface} from "./Interfaces/ContextualAPIInterface";
5
5
 
6
6
  declare global {
7
7
  interface Window {
8
+ Nanosplash: typeof Nanosplash
9
+ installNanosplash: (options?: NanosplashOptions) => void
8
10
  ns: Nanosplash
9
11
  }
10
12
  }
@@ -15,7 +17,7 @@ type SplashJob = [Promise<any>, string]
15
17
  /**
16
18
  * @internal
17
19
  */
18
- export type HTMLElementTag = keyof HTMLElementTagNameMap
20
+ export type ElementTag = keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap
19
21
 
20
22
  /**
21
23
  * @internal
@@ -42,8 +44,10 @@ type ContextualAPIObject = {
42
44
  getImgSrc: () => string | undefined,
43
45
  setImgSrc: (src?: string) => SplashInstance
44
46
  }
47
+ type InstanceIterationCallback = (id: string, splashInstance: SplashInstance, i: number) => boolean
45
48
 
46
- declare module 'nanosplash' {
47
- class Nanosplash {}
48
- class SplashInstance {}
49
+ type NanosplashOptions = {
50
+ imgSrc?: string,
51
+ spinner?: boolean,
52
+ fontSize?: string
49
53
  }
@@ -1,4 +1,4 @@
1
- import {HTMLElementTag} from "../types";
1
+ import {ElementTag} from "../types";
2
2
 
3
3
  export function get<T>(selector: string): HTMLElement | T | null {
4
4
  return document.querySelector(selector) as HTMLElement | T | null
@@ -13,7 +13,7 @@ export function move(source: Node, destination: Node, asFirstChild: boolean = fa
13
13
  }
14
14
  }
15
15
 
16
- export const mk = (tag: HTMLElementTag) => document.createElement(tag)
16
+ export const mk = (tag: ElementTag) => document.createElement(tag)
17
17
 
18
18
  export function addClass(node: HTMLElement, ...classes: string[]): void
19
19
  {
@@ -1,5 +0,0 @@
1
- import {ImgFunction} from "../types";
2
-
3
- export interface ImageInterface {
4
- img: ImgFunction
5
- }