nanosplash 4.0.2 → 4.0.4

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.
Files changed (67) hide show
  1. package/.github/workflows/ci.prod.yml +68 -0
  2. package/.prettierrc +9 -10
  3. package/README.md +118 -51
  4. package/bun.lock +635 -0
  5. package/coverage/lcov-report/base.css +224 -0
  6. package/coverage/lcov-report/block-navigation.js +87 -0
  7. package/coverage/lcov-report/favicon.png +0 -0
  8. package/coverage/lcov-report/index.html +176 -0
  9. package/coverage/lcov-report/prettify.css +1 -0
  10. package/coverage/lcov-report/prettify.js +2 -0
  11. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  12. package/coverage/lcov-report/sorter.js +196 -0
  13. package/coverage/lcov-report/src/composables/index.html +116 -0
  14. package/coverage/lcov-report/src/composables/ns.ts.html +547 -0
  15. package/coverage/lcov-report/src/constants/index.html +116 -0
  16. package/coverage/lcov-report/src/constants/ns.ts.html +124 -0
  17. package/coverage/lcov-report/src/iife.ts.html +100 -0
  18. package/coverage/lcov-report/src/index.html +116 -0
  19. package/coverage/lcov-report/src/interfaces/INSElement.ts.html +100 -0
  20. package/coverage/lcov-report/src/interfaces/INanosplash.ts.html +304 -0
  21. package/coverage/lcov-report/src/interfaces/index.html +131 -0
  22. package/coverage/lcov-report/src/utils/dom-utils.ts.html +289 -0
  23. package/coverage/lcov-report/src/utils/index.html +116 -0
  24. package/coverage/lcov.info +271 -0
  25. package/eslint.config.js +7 -2
  26. package/package.json +74 -88
  27. package/src/composables/ns.ts +154 -0
  28. package/src/constants/ns.ts +13 -0
  29. package/src/iife.ts +5 -0
  30. package/src/interfaces/INSElement.ts +5 -0
  31. package/src/interfaces/INanosplash.ts +73 -0
  32. package/src/style/ns.css +134 -0
  33. package/src/types/dom.d.ts +3 -0
  34. package/src/types/generic/function.d.ts +1 -0
  35. package/src/types/global.d.ts +26 -0
  36. package/src/types/semantic/number.d.ts +1 -0
  37. package/src/types/semantic/string.d.ts +2 -0
  38. package/src/utils/dom-utils.ts +68 -0
  39. package/tests/ns.spec.ts +124 -0
  40. package/tsconfig.json +29 -21
  41. package/vite.config.ts +18 -10
  42. package/vitest.config.ts +20 -0
  43. package/.github/workflows/ci.yml +0 -62
  44. package/.github/workflows/vitepress.yml +0 -68
  45. package/LICENSE +0 -21
  46. package/docs/.vitepress/config.ts +0 -78
  47. package/docs/.vitepress/theme/css/style.css +0 -258
  48. package/docs/.vitepress/theme/index.ts +0 -16
  49. package/docs/.vitepress/theme/vue/Card.vue +0 -31
  50. package/docs/.vitepress/theme/vue/CardGrid.vue +0 -17
  51. package/docs/.vitepress/theme/vue/PlayGround.vue +0 -36
  52. package/docs/api/doc/hide.md +0 -48
  53. package/docs/api/doc/show.md +0 -46
  54. package/docs/api/start/customize.md +0 -30
  55. package/docs/api/start/features.md +0 -17
  56. package/docs/api/start/install.md +0 -61
  57. package/docs/api/start/playground.md +0 -16
  58. package/docs/api/start/usage.md +0 -22
  59. package/docs/index.md +0 -33
  60. package/docs/public/macos.jpg +0 -0
  61. package/src/style/ns.sass +0 -120
  62. package/src/ts/Nanosplash.ts +0 -177
  63. package/src/ts/main.ts +0 -5
  64. package/src/ts/types/NanosplashInterface.ts +0 -26
  65. package/src/ts/types/Types.ts +0 -16
  66. package/src/ts/types/global.d.ts +0 -14
  67. package/tests/Nanosplash.spec.ts +0 -25
package/package.json CHANGED
@@ -1,90 +1,76 @@
1
1
  {
2
- "name": "nanosplash",
3
- "version": "4.0.2",
4
- "author": {
5
- "name": "Isak K. Hauge",
6
- "email": "isakhauge@icloud.com",
7
- "url": "https://no.linkedin.com/in/isakhauge"
8
- },
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/isakhauge/nanosplash.git"
12
- },
13
- "main": "./dist/es/ns.js",
14
- "module": "./dist/es/ns.js",
15
- "devDependencies": {
16
- "@types/jsdom": "^21.1.6",
17
- "@types/node": "^20.11.30",
18
- "@vitest/coverage-v8": "^1.4.0",
19
- "@vitest/ui": "^1.4.0",
20
- "cross-env": "^7.0.3",
21
- "eslint": "^8.57.0",
22
- "eslint-config-prettier": "^9.1.0",
23
- "eslint-plugin-prettier": "^5.1.3",
24
- "jsdom": "^24.0.0",
25
- "sass": "^1.72.0",
26
- "stylelint-prettier": "^5.0.0",
27
- "typescript": "5.4.3",
28
- "typescript-eslint": "^7.3.1",
29
- "vite": "^5.2.6",
30
- "vitepress": "1.0.1",
31
- "vitest": "^1.4.0"
32
- },
33
- "exports": {
34
- ".": {
35
- "types": {
36
- "require": "./src/ts/types/global.d.ts",
37
- "default": "./src/ts/types/global.d.ts"
38
- },
39
- "browser": {
40
- "require": "./dist/cjs/ns.cjs",
41
- "default": "./dist/es/ns.js"
42
- },
43
- "default": {
44
- "require": "./dist/cjs/ns.cjs",
45
- "default": "./dist/es/ns.js"
46
- }
47
- }
48
- },
49
- "description": "The tiny loading screen for web artisans",
50
- "homepage": "https://isakhauge.github.io/nanosplash",
51
- "keywords": [
52
- "loading",
53
- "loader",
54
- "screen",
55
- "splash",
56
- "nano",
57
- "nanosplash",
58
- "small",
59
- "tiny",
60
- "es",
61
- "esm",
62
- "ts",
63
- "typescript",
64
- "iife",
65
- "cdn",
66
- "vite"
67
- ],
68
- "license": "MIT",
69
- "private": false,
70
- "scripts": {
71
- "build": "pnpm build:all && pnpm build:docs",
72
- "build:es": "tsc && cross-env entry=./src/ts/Nanosplash.ts format=es vite build -m production --c vite.config.ts",
73
- "build:cjs": "tsc && cross-env entry=./src/ts/Nanosplash.ts format=cjs vite build -m production --c vite.config.ts",
74
- "build:iife": "tsc && cross-env entry=./src/ts/main.ts format=iife vite build -m production --c vite.config.ts",
75
- "build:all": "pnpm build:es && pnpm build:cjs && pnpm build:iife",
76
- "build:docs": "pnpm docs:build",
77
- "preview": "vite preview",
78
- "test": "vitest",
79
- "test:ui": "vitest --ui",
80
- "lint": "eslint src/ts/**/*.ts --fix",
81
- "coverage": "vitest --coverage",
82
- "docs:dev": "pnpm exec vitepress dev docs",
83
- "docs:build": "pnpm exec vitepress build docs",
84
- "docs:preview": "pnpm exec vitepress preview docs"
85
- },
86
- "source": "./src/main.ts",
87
- "type": "module",
88
- "types": "./src/ts/types/global.d.ts",
89
- "unpkg": "./dist/iife/ns.iife.js"
2
+ "name": "nanosplash",
3
+ "private": false,
4
+ "version": "4.0.4",
5
+ "type": "module",
6
+ "author": {
7
+ "name": "Isak K. Hauge",
8
+ "email": "isakhauge@icloud.com",
9
+ "url": "https://no.linkedin.com/in/isakhauge"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/isakhauge/nanosplash.git"
14
+ },
15
+ "description": "The tiny loading screen for web artisans",
16
+ "homepage": "https://github.com/isakhauge/nanosplash",
17
+ "keywords": [
18
+ "loading",
19
+ "loader",
20
+ "screen",
21
+ "splash",
22
+ "nano",
23
+ "nanosplash",
24
+ "small",
25
+ "tiny",
26
+ "es",
27
+ "esm",
28
+ "ts",
29
+ "typescript",
30
+ "iife",
31
+ "cdn",
32
+ "vite"
33
+ ],
34
+ "scripts": {
35
+ "dev": "vite",
36
+ "build": "bun run build:es && bun run build:cjs && bun run build:iife",
37
+ "build:es": "tsc && cross-env entry=./src/composables/ns.ts format=es vite build -m production --outDir dist/es",
38
+ "build:cjs": "tsc && cross-env entry=./src/composables/ns.ts format=cjs vite build -m production --outDir dist/cjs",
39
+ "build:iife": "tsc && cross-env entry=./src/iife.ts format=iife vite build -m production --outDir dist/iife",
40
+ "preview": "vite preview",
41
+ "lint": "eslint . --fix",
42
+ "format": "prettier --write \"src/**/*.ts\" \"vite.config.ts\"",
43
+ "test": "bun run vitest"
44
+ },
45
+ "types": "./src/types/global.d.ts",
46
+ "exports": {
47
+ ".": {
48
+ "types": "./src/types/global.d.ts",
49
+ "import": "./dist/es/ns.es.js",
50
+ "require": "./dist/cjs/ns.cjs.js",
51
+ "default": "./dist/es/ns.es.js"
52
+ }
53
+ },
54
+ "source": "./src/composables/ns.ts",
55
+ "unpkg": "./dist/iife/ns.iife.js",
56
+ "devDependencies": {
57
+ "@eslint/js": "^9.28.0",
58
+ "@types/node": "^22.15.29",
59
+ "@typescript-eslint/eslint-plugin": "^8.33.0",
60
+ "@typescript-eslint/parser": "^8.33.0",
61
+ "@vitest/coverage-v8": "3.1.4",
62
+ "cross-env": "^7.0.3",
63
+ "dotenv": "^16.5.0",
64
+ "eslint": "^9.28.0",
65
+ "eslint-config-prettier": "^10.1.5",
66
+ "globals": "^16.2.0",
67
+ "jsdom": "^26.1.0",
68
+ "prettier": "3.5.3",
69
+ "typescript": "^5.8.3",
70
+ "typescript-eslint": "^8.33.0",
71
+ "vite": "^6.3.5"
72
+ },
73
+ "dependencies": {
74
+ "vitest": "^3.1.4"
75
+ }
90
76
  }
@@ -0,0 +1,154 @@
1
+ import style from '@/style/ns.css?raw'
2
+ import type { INanosplash } from '@/interfaces/INanosplash.ts'
3
+ import type { Func } from '@/types/generic/function.ts'
4
+ import type { INSElement } from '@/interfaces/INSElement.ts'
5
+ import {
6
+ all,
7
+ bod,
8
+ div,
9
+ doc,
10
+ first,
11
+ parseHtml,
12
+ parseRef,
13
+ toArray,
14
+ } from '@/utils/dom-utils.ts'
15
+ import { ClassNames, Selectors } from '@/constants/ns.ts'
16
+ import type { HTMLString } from '@/types/semantic/string.ts'
17
+ import type { ElementRef } from '@/types/dom.ts'
18
+ import type { int } from '@/types/semantic/number.ts'
19
+ import { version } from '@/../package.json'
20
+
21
+ export const useNs: Func<INanosplash> = (): INanosplash => {
22
+ /**
23
+ * Retrieve all NS elements from the DOM
24
+ */
25
+ const getAllNs: Func<INSElement[]> = () =>
26
+ all(doc(), Selectors.ns) as INSElement[]
27
+
28
+ /**
29
+ * Create an NS element
30
+ */
31
+ const makeNs: Func<INSElement> = () => {
32
+ const circle: HTMLString =
33
+ '<circle class=path cx=25 cy=25 r=20 fill=none />'
34
+ const svg = parseHtml(`<svg viewBox="0 0 50 50">${circle}</svg>`) as Element
35
+ const node = div(
36
+ ClassNames.ns,
37
+ div(ClassNames.nsText),
38
+ div(ClassNames.nsSpinner, svg)
39
+ ) as INSElement
40
+ node.nsId = Date.now()
41
+ return node
42
+ }
43
+
44
+ /**
45
+ * Get all NS elements from DOM in a FIFO sequence
46
+ */
47
+ const nsQueue: Func<INSElement[]> = () =>
48
+ getAllNs().sort((a, b) => a.nsId - b.nsId)
49
+
50
+ /**
51
+ * Peek at the first NS element in the queue
52
+ */
53
+ const peekNsQueue: Func<INSElement | null> = () => nsQueue()[0] ?? null
54
+
55
+ /**
56
+ * Set the text of the NS element.
57
+ * @param ns Nanosplash element.
58
+ * @param text The text to display adjacent to the spinner.
59
+ */
60
+ const setNsText = (ns: INSElement, text?: string): void => {
61
+ first(ns, Selectors.nsText)?.remove()
62
+ if (!text) return
63
+ const newNsText: Element = div(ClassNames.nsText, text)
64
+ ns.insertBefore(newNsText, ns.firstChild)
65
+ }
66
+
67
+ /**
68
+ * Set the parent element of the NS element.
69
+ * @param ns Nanosplash element.
70
+ * @param parent An element to be a parent of the Nanosplash element.
71
+ */
72
+ const setNsParent = (ns: INSElement, parent: Element): void => {
73
+ const child = parent.firstElementChild
74
+ if (child) parent.insertBefore(ns, child)
75
+ parent.append(ns)
76
+ parent.classList.add(ClassNames.nsHost)
77
+ }
78
+
79
+ const getNsInside = (parent: Element): INSElement | undefined => {
80
+ const children = toArray(parent.children) as INSElement[]
81
+ return children.find((v: Element): boolean =>
82
+ v.classList.contains(ClassNames.ns)
83
+ )
84
+ }
85
+
86
+ /**
87
+ * Show the Nanosplash in the window
88
+ * @param text The text that will appear adjacent to the spinner. Enter false to only show the spinner.
89
+ * @param inside Element or selector to an element wherein the Nanosplash element should reside.
90
+ */
91
+ const show = (text?: string, inside?: ElementRef): int | null => {
92
+ const parent: Element = inside ? (parseRef(inside) ?? bod()) : bod()
93
+ let ns: INSElement
94
+ const recycled = getNsInside(parent)
95
+ if (recycled) {
96
+ ns = recycled as INSElement
97
+ } else {
98
+ ns = makeNs()
99
+ setNsParent(ns, parent)
100
+ }
101
+ setNsText(ns, text ?? '')
102
+ if (parent === bod()) {
103
+ const top: string = scrollY + 'px'
104
+ bod().style.setProperty('--ns-top', top)
105
+ }
106
+ return ns.nsId
107
+ }
108
+
109
+ /**
110
+ * Remove a Nanosplash element from the DOM
111
+ * @param ns The Nanosplash element
112
+ */
113
+ const removeNs = (ns?: Element | INSElement | null): void => {
114
+ ns?.parentElement?.classList.remove(ClassNames.nsHost)
115
+ ns?.remove()
116
+ }
117
+
118
+ /**
119
+ * Find a Nanosplash element with a given ID
120
+ * @param id The Nanosplash ID
121
+ */
122
+ const findNs = (id: int): INSElement | null =>
123
+ getAllNs().find(x => x.nsId === id) ?? null
124
+
125
+ /**
126
+ * Hide agnostically in FIFO order, specifically by ID, or all, by the asterisk symbol.
127
+ * The latter will delete all Nanosplash elements in the DOM.
128
+ * @param id Optional ID of a Nanosplash element or '*'.
129
+ */
130
+ const hide = (id?: int | '*'): void => {
131
+ const selectAll = id === '*'
132
+ if (selectAll) getAllNs().forEach(removeNs)
133
+ else removeNs(typeof id === 'number' ? findNs(id) : peekNsQueue())
134
+ }
135
+
136
+ /**
137
+ * Remove old Nanosplash styles and insert new ones.
138
+ */
139
+ const injectStyle = () => {
140
+ first(doc(), '#ns')?.remove()
141
+ const styleElement: HTMLStyleElement = parseHtml(
142
+ `<style id="ns">${style}</style>`
143
+ )
144
+ bod().append(styleElement)
145
+ }
146
+
147
+ injectStyle() // Run everytime the hook is invoked.
148
+
149
+ return {
150
+ show,
151
+ hide,
152
+ version,
153
+ }
154
+ }
@@ -0,0 +1,13 @@
1
+ export const ClassNames = {
2
+ ns: 'ns',
3
+ nsHost: 'nsh',
4
+ nsText: 'nst',
5
+ nsSpinner: 'nss',
6
+ }
7
+
8
+ export const Selectors = {
9
+ ns: '.' + ClassNames.ns,
10
+ nsHost: '.' + ClassNames.nsHost,
11
+ nsText: '.' + ClassNames.nsText,
12
+ nsSpinner: '.' + ClassNames.nsSpinner,
13
+ }
package/src/iife.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { useNs } from '@/composables/ns.ts'
2
+
3
+ window.addEventListener('load', function () {
4
+ this.ns = useNs()
5
+ })
@@ -0,0 +1,5 @@
1
+ import type { int } from '@/types/semantic/number.ts'
2
+
3
+ export interface INSElement extends HTMLDivElement {
4
+ nsId: int
5
+ }
@@ -0,0 +1,73 @@
1
+ import type { ElementRef } from '@/types/dom.ts'
2
+ import type { int } from '@/types/semantic/number.ts'
3
+
4
+ /**
5
+ * # Nanosplash
6
+ * @author Isak Hauge <isakhauge@icloud.com>
7
+ */
8
+ export interface INanosplash {
9
+ /**
10
+ * # Show
11
+ * Display Nanosplash inside the window.
12
+ * @param {string | null | undefined} text Optional text. Pass falsy to display spinner only.
13
+ * @param {string | Element | undefined} inside Optional element reference
14
+ * @returns {number | null} The internal ID of the created Nanosplash.
15
+ * @example
16
+ * // Show spinner only
17
+ * ns.show()
18
+ * @example
19
+ * // Show spinner and text
20
+ * ns.show('Loading ...')
21
+ * @example
22
+ * // Show spinner and text inside element
23
+ * const div = document.createElement('div')
24
+ * div.id = 'my-div'
25
+ * document.body.append(div)
26
+ *
27
+ * // Alternative 1: Using node
28
+ * ns.show('Loading ...', div)
29
+ *
30
+ * // Alternative 2: Using selector
31
+ * ns.show('Loading ...', '#my-div')
32
+ * @example
33
+ * // Show spinner only, inside element
34
+ * const div = document.createElement('div')
35
+ * div.id = 'my-div'
36
+ * document.body.append(div)
37
+ *
38
+ * // Alternative 1: Using node
39
+ * ns.show(null, div)
40
+ *
41
+ * // Alternative 2: Using selector
42
+ * ns.show(null, '#my-div')
43
+ */
44
+ show(
45
+ text?: string | null | undefined,
46
+ inside?: ElementRef | HTMLElement
47
+ ): int | null
48
+ /**
49
+ * # Hide
50
+ * Remove Nanosplash in multiple ways depending on the passed argument.
51
+ * - Pass ID: Remove specific.
52
+ * - Pass '*': Remove all in window.
53
+ * - Pass nothing: Remove in FIFO order.
54
+ * @param id The internal ID, an asterisk, or nothing.
55
+ * @example
56
+ * // Remove the first Nanosplash in the queue (FIFO)
57
+ * ns.hide()
58
+ * @example
59
+ * // Remove specific Nanosplash in case you have multiple
60
+ * const idA: number = ns.show(null, '#div-a') // 1700000000000
61
+ * const idB: number = ns.show(null, '#div-b') // 1800000000000
62
+ * ns.hide(idB) // Only hides Nanosplash inside the element with ID div-b
63
+ * @example
64
+ * // Hide all Nanosplash elements in the DOM
65
+ * ns.hide('*')
66
+ */
67
+ hide(id?: int | '*'): void
68
+ /**
69
+ * # Version
70
+ * The current version of Nanosplash.
71
+ */
72
+ version: string
73
+ }
@@ -0,0 +1,134 @@
1
+ @keyframes nsRotate {
2
+ 100% {
3
+ transform: rotate(360deg);
4
+ }
5
+ }
6
+
7
+ @keyframes nsDash {
8
+ 0% {
9
+ stroke-dasharray: 1, 150;
10
+ stroke-dashoffset: 0;
11
+ }
12
+ 50% {
13
+ stroke-dasharray: 90, 150;
14
+ stroke-dashoffset: -35;
15
+ }
16
+ 100% {
17
+ stroke-dasharray: 90, 150;
18
+ stroke-dashoffset: -124;
19
+ }
20
+ }
21
+
22
+ @keyframes nsFade {
23
+ from {
24
+ opacity: 0;
25
+ }
26
+ to {
27
+ opacity: 1;
28
+ }
29
+ }
30
+
31
+ @keyframes nsAscend {
32
+ from {
33
+ opacity: 0;
34
+ transform: translateY(13px);
35
+ }
36
+ to {
37
+ opacity: 1;
38
+ transform: translateY(0);
39
+ }
40
+ }
41
+
42
+ :root {
43
+ --ns-top: 0;
44
+ }
45
+
46
+ /* Nanosplash host */
47
+ .nsh {
48
+ --color: DarkSlateGray;
49
+ --size: 20px;
50
+ --relSize: calc(var(--size) * 0.9);
51
+ --font: 'Inter', 'Helvetica', 'Arial';
52
+ --weight: 400;
53
+ --bg: rgba(255, 255, 255, 0.9);
54
+ --zIdx: 9999999999;
55
+ --blur: blur(5px);
56
+
57
+ position: relative;
58
+ z-index: var(--zIdx);
59
+ &::before {
60
+ width: 100%;
61
+ height: 100%;
62
+ bottom: 0; /* Not sure why */
63
+ right: 0; /* Not sure why */
64
+ position: absolute;
65
+ content: '';
66
+ background-color: var(--bg);
67
+ backdrop-filter: var(--blur);
68
+ -webkit-backdrop-filter: var(--blur);
69
+ z-index: calc(var(--zIdx) + 1);
70
+ border-radius: var(--size);
71
+ }
72
+ }
73
+
74
+ /* For when the Nanosplash host is the document body */
75
+ body.nsh {
76
+ &,
77
+ &::before {
78
+ width: 100%;
79
+ height: 100%;
80
+ position: fixed;
81
+ top: var(--ns-top);
82
+ left: 0;
83
+ }
84
+ }
85
+
86
+ /* Nanosplash main element */
87
+ .ns {
88
+ width: 100%;
89
+ height: 100%;
90
+ bottom: 0; /* Not sure why */
91
+ right: 0; /* Not sure why */
92
+ display: flex;
93
+ justify-content: center;
94
+ align-items: center;
95
+ position: absolute;
96
+ z-index: calc(var(--zIdx) + 2);
97
+ animation: nsFade 2s;
98
+ gap: var(--relSize);
99
+ }
100
+
101
+ /* Nanosplash text */
102
+ .nst {
103
+ color: var(--color);
104
+ font-size: var(--size);
105
+ font-family: var(--font), sans-serif;
106
+ font-weight: var(--weight);
107
+ max-width: 80dvw;
108
+ white-space: nowrap;
109
+ text-overflow: ellipsis;
110
+ overflow: hidden;
111
+ text-shadow: 0 0 0.06rem rgba(0, 0, 0, 0.25);
112
+ filter: drop-shadow(0 0 0.07rem rgba(0, 0, 0, 0.25));
113
+ animation: nsAscend 0.5s;
114
+ }
115
+
116
+ /* Nanosplash spinner */
117
+ .nss {
118
+ display: block;
119
+ width: var(--relSize);
120
+ height: var(--relSize);
121
+ animation: nsAscend 0.5s;
122
+ & > svg {
123
+ animation: nsRotate 2s linear infinite;
124
+ position: relative;
125
+ width: inherit;
126
+ height: inherit;
127
+ stroke-width: 8;
128
+ }
129
+ & .path {
130
+ stroke: var(--color);
131
+ stroke-linecap: round;
132
+ animation: nsDash 1.5s ease-in-out infinite;
133
+ }
134
+ }
@@ -0,0 +1,3 @@
1
+ import type { NodeSelector } from './semantic/string.ts'
2
+
3
+ export type ElementRef = Element | NodeSelector
@@ -0,0 +1 @@
1
+ export type Func<T> = (...args: unknown[]) => T
@@ -0,0 +1,26 @@
1
+ import type { INanosplash } from '../interfaces/INanosplash.ts'
2
+
3
+ declare global {
4
+ interface Window {
5
+ ns: INanosplash
6
+ }
7
+ }
8
+
9
+ /**
10
+ * # Nanosplash
11
+ *
12
+ * **The tiny loading screen for web artisans**
13
+ *
14
+ * `useNs` is the main hook, which will inject the style into the DOM and return
15
+ * an instance of the Nanosplash API.
16
+ * We recommend that you add Nanosplash to the Window.
17
+ * @returns Instance of Nanosplash API
18
+ * @example The short and easy way.
19
+ * window.ns = useNs()
20
+ * @example The safe way.
21
+ * window.addEventListener('load', function() {
22
+ * this.ns = useNs()
23
+ * })
24
+ * @author Isak Hauge <https://www.linkedin.com/in/isakhauge/>
25
+ */
26
+ export const useNs: () => INanosplash
@@ -0,0 +1 @@
1
+ export type int = number
@@ -0,0 +1,2 @@
1
+ export type NodeSelector = string
2
+ export type HTMLString = string
@@ -0,0 +1,68 @@
1
+ import type { Func } from '@/types/generic/function.ts'
2
+ import type { HTMLString, NodeSelector } from '@/types/semantic/string.ts'
3
+ import type { ElementRef } from '@/types/dom.ts'
4
+
5
+ /**
6
+ * Shortened Document getter
7
+ */
8
+ export const doc: Func<Document> = (): Document => globalThis.document
9
+
10
+ /**
11
+ * Shortened Body getter
12
+ */
13
+ export const bod: Func<HTMLElement> = (): HTMLElement =>
14
+ globalThis.document.body
15
+
16
+ /**
17
+ * Convert iterables and array-like structures into an array
18
+ * @param x
19
+ */
20
+ export const toArray = <T>(x: Iterable<T> | ArrayLike<T>) => Array.from(x)
21
+
22
+ /**
23
+ * Scoped node selector
24
+ * @param node Current scope
25
+ * @param ref Selector
26
+ */
27
+ export const all = (node: ParentNode, ref: NodeSelector) =>
28
+ toArray(node.querySelectorAll(ref))
29
+
30
+ /**
31
+ * Scoped node selector returning the first match
32
+ * @param node Current scope
33
+ * @param ref Selector
34
+ */
35
+ export const first = (node: ParentNode, ref: NodeSelector): Element | null =>
36
+ all(node, ref)[0] ?? null
37
+
38
+ /**
39
+ * Parse an ambiguous element reference into an actual element
40
+ * @param ref Element reference
41
+ */
42
+ export const parseRef = <T extends Element>(ref: ElementRef): T | null =>
43
+ ref instanceof Element ? (ref as T) : (first(doc(), ref) as T)
44
+
45
+ /**
46
+ * Create div
47
+ * @param className Optional CSS class name
48
+ * @param children Optional children
49
+ */
50
+ export const div = (
51
+ className?: string,
52
+ ...children: (Node | HTMLString)[]
53
+ ): HTMLDivElement => {
54
+ const node: HTMLDivElement = doc().createElement('div')
55
+ if (className) node.classList.add(className)
56
+ node.append(...children)
57
+ return node
58
+ }
59
+
60
+ /**
61
+ * Parse HTML code into HTML elements
62
+ * @param html
63
+ */
64
+ export const parseHtml = <T extends HTMLElement>(html: HTMLString): T => {
65
+ const node: HTMLDivElement = div()
66
+ node.innerHTML = html
67
+ return node.firstChild as T
68
+ }