modern-loaders 1.2.1 → 1.2.3
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/README.md +300 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,42 +1,41 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<h1>modern-loaders</h1>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<p><b>212 ready-made loading animations for React.</b><br/>
|
|
6
|
+
One component, pure CSS motion, zero runtime dependencies.</p>
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
[](https://www.npmjs.com/package/modern-loaders)
|
|
9
|
+
[](https://www.npmjs.com/package/modern-loaders)
|
|
10
|
+
[](https://bundlephobia.com/package/modern-loaders)
|
|
11
|
+
[](https://www.npmjs.com/package/modern-loaders)
|
|
12
|
+
[](./LICENSE)
|
|
13
|
+
[](https://github.com/Suman1999-hub/modern-loaders-package)
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
[](./LICENSE)
|
|
13
|
-
[](https://modern-loaders.netlify.app/)
|
|
14
|
-
|
|
15
|
-
### [**→ Browse all 212 loaders live**](https://modern-loaders.netlify.app/)
|
|
15
|
+
```bash
|
|
16
|
+
npm install modern-loaders
|
|
17
|
+
```
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
[](https://modern-loaders.netlify.app/)
|
|
18
20
|
|
|
19
21
|
</div>
|
|
20
22
|
|
|
21
23
|
---
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
npm i modern-loaders
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
```tsx
|
|
28
|
-
import { Loader } from "modern-loaders";
|
|
25
|
+
## What is modern-loaders?
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
```
|
|
27
|
+
A library of **212 loading animations** for React, all behind a single
|
|
28
|
+
`<Loader />` component.
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
**The problem.** Every app needs loading states. Building them by hand means
|
|
31
|
+
writing CSS keyframes again and again. Most loader packages give you a handful
|
|
32
|
+
of spinners, or pull in a JavaScript animation runtime you did not ask for.
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
**This package.** Pick a loader by name, set the size, speed and colours if you
|
|
35
|
+
want, and ship. Every animation is plain CSS, so nothing runs on the main
|
|
36
|
+
thread and there is nothing to install alongside it.
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
### Why developers use it
|
|
40
39
|
|
|
41
40
|
- **212 variants across 20 families** — spinners, dots, bars, shapes, progress, grids, pulses, organic, skeletons, dimensional, neon, liquid, glitch, particles, futuristic, elastic, minimal, gradient, kinetic, and premium.
|
|
42
41
|
- **Three props to learn.** `size`, `speed`, `colors`. Everything else has a sensible default.
|
|
@@ -45,21 +44,89 @@ remember, nothing to configure in Vite, Next.js, CRA, or Tailwind.
|
|
|
45
44
|
- **Accessible by default.** Each loader is a labelled `role="status"` and honours `prefers-reduced-motion`.
|
|
46
45
|
- **Themeable without a build step.** Every value is a CSS custom property you can override.
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
---
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
## Installation
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
51
|
+
```bash
|
|
52
|
+
npm install modern-loaders
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
<details>
|
|
56
|
+
<summary>Using yarn or pnpm?</summary>
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
yarn add modern-loaders
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pnpm add modern-loaders
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
</details>
|
|
67
|
+
|
|
68
|
+
**No CSS import needed.** The stylesheet is bundled and injects itself — nothing
|
|
69
|
+
to configure in Vite, Next.js, CRA, or Tailwind.
|
|
70
|
+
|
|
71
|
+
<sub>If your bundler strips side-effect imports, add
|
|
72
|
+
<code>import "modern-loaders/styles.css"</code>.</sub>
|
|
59
73
|
|
|
60
|
-
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quick Start
|
|
77
|
+
|
|
78
|
+
### 1. Render a loader
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { Loader } from "modern-loaders";
|
|
82
|
+
|
|
83
|
+
export default function App() {
|
|
84
|
+
return <Loader />;
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. Pick a variant
|
|
89
|
+
|
|
90
|
+
Every loader has a name. Pass it as `variant`:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Loader variant="wave" />
|
|
94
|
+
```
|
|
61
95
|
|
|
62
|
-
###
|
|
96
|
+
### 3. Customise it
|
|
97
|
+
|
|
98
|
+
Set the size, speed and colours:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
<Loader
|
|
102
|
+
variant="wave"
|
|
103
|
+
size={72}
|
|
104
|
+
speed={0.8}
|
|
105
|
+
colors={["#f97316", "#ef4444", "#a855f7"]}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Not sure which one to pick?
|
|
110
|
+
[**Browse all 212 in the live gallery →**](https://modern-loaders.netlify.app/)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Contents
|
|
115
|
+
|
|
116
|
+
- [Choosing a loader](#choosing-a-loader)
|
|
117
|
+
- [Recipes](#recipes)
|
|
118
|
+
- [Customization](#customization)
|
|
119
|
+
- [API](#api)
|
|
120
|
+
- [All 212 variants](#all-212-variants)
|
|
121
|
+
- [Accessibility](#accessibility)
|
|
122
|
+
- [Bundle size](#bundle-size)
|
|
123
|
+
- [Browser support](#browser-support)
|
|
124
|
+
- [Contributing](#contributing)
|
|
125
|
+
- [License](#license)
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Choosing a loader
|
|
63
130
|
|
|
64
131
|
| situation | reach for | why |
|
|
65
132
|
|---|---|---|
|
|
@@ -73,49 +140,181 @@ Every other `div` prop — `className`, `style`, `id`, `onClick`, `data-*` — p
|
|
|
73
140
|
| Games, launch screens, dev tools | **Neon**, **Futuristic**, **Glitch** | Loud on purpose. Best on a dark surface. |
|
|
74
141
|
| Playful or brand-forward moments | **Liquid**, **Particles**, **Elastic**, **Kinetic** | Physical motion people actually watch. |
|
|
75
142
|
|
|
76
|
-
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Recipes
|
|
77
146
|
|
|
78
|
-
|
|
147
|
+
### A button that keeps its width while loading
|
|
79
148
|
|
|
80
149
|
```tsx
|
|
81
150
|
<button disabled={busy}>
|
|
82
|
-
{busy
|
|
83
|
-
|
|
84
|
-
|
|
151
|
+
{busy ? (
|
|
152
|
+
<Loader
|
|
153
|
+
variant="pulse-dots"
|
|
154
|
+
size={16}
|
|
155
|
+
colors={["currentColor"]}
|
|
156
|
+
label={null}
|
|
157
|
+
/>
|
|
158
|
+
) : (
|
|
159
|
+
"Save"
|
|
160
|
+
)}
|
|
85
161
|
</button>
|
|
86
162
|
```
|
|
87
163
|
|
|
88
|
-
`colors={["currentColor"]}` inherits the button's own text
|
|
89
|
-
readers announcing "Loading" twice when the button
|
|
164
|
+
`colors={["currentColor"]}` inherits the button's own text colour.
|
|
165
|
+
`label={null}` stops screen readers announcing "Loading" twice when the button
|
|
166
|
+
already conveys it.
|
|
90
167
|
|
|
91
|
-
|
|
168
|
+
### A skeleton shaped like the thing you're waiting for
|
|
92
169
|
|
|
93
170
|
```tsx
|
|
94
|
-
{isLoading ?
|
|
171
|
+
{isLoading ? (
|
|
172
|
+
<Loader
|
|
173
|
+
variant="sk-card"
|
|
174
|
+
size={64}
|
|
175
|
+
/>
|
|
176
|
+
) : (
|
|
177
|
+
<ArticleCard {...article} />
|
|
178
|
+
)}
|
|
95
179
|
```
|
|
96
180
|
|
|
97
|
-
|
|
181
|
+
### A full-page overlay
|
|
98
182
|
|
|
99
183
|
```tsx
|
|
100
|
-
<div
|
|
101
|
-
|
|
184
|
+
<div
|
|
185
|
+
style={{
|
|
186
|
+
position: "fixed",
|
|
187
|
+
inset: 0,
|
|
188
|
+
display: "grid",
|
|
189
|
+
placeItems: "center",
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
<Loader
|
|
193
|
+
variant="aurora"
|
|
194
|
+
size={80}
|
|
195
|
+
label="Loading your dashboard"
|
|
196
|
+
/>
|
|
102
197
|
</div>
|
|
103
198
|
```
|
|
104
199
|
|
|
105
|
-
|
|
200
|
+
### Build your own picker
|
|
201
|
+
|
|
202
|
+
The manifest is exported, so you can map over it:
|
|
106
203
|
|
|
107
204
|
```tsx
|
|
108
205
|
import { VARIANTS, Loader } from "modern-loaders";
|
|
109
206
|
|
|
110
|
-
VARIANTS
|
|
111
|
-
|
|
207
|
+
VARIANTS
|
|
208
|
+
.filter((variant) => variant.group === "Skeletons")
|
|
209
|
+
.map((variant) => (
|
|
210
|
+
<Loader
|
|
211
|
+
key={variant.id}
|
|
212
|
+
variant={variant.id}
|
|
213
|
+
/>
|
|
214
|
+
));
|
|
112
215
|
```
|
|
113
216
|
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Customization
|
|
220
|
+
|
|
221
|
+
The `colors` prop covers most cases. For anything else, override the CSS custom
|
|
222
|
+
properties — they cascade, so one rule themes a whole subtree:
|
|
223
|
+
|
|
224
|
+
```css
|
|
225
|
+
.dashboard {
|
|
226
|
+
/* palette */
|
|
227
|
+
--c1: #6366f1;
|
|
228
|
+
--c2: #ec4899;
|
|
229
|
+
--c3: #22d3ee;
|
|
230
|
+
|
|
231
|
+
/* size and timing */
|
|
232
|
+
--size: 64px;
|
|
233
|
+
--speed: .9s;
|
|
234
|
+
|
|
235
|
+
/* rail behind progress bars */
|
|
236
|
+
--track: #1e1e2e;
|
|
237
|
+
|
|
238
|
+
/* shared gradient */
|
|
239
|
+
--grad: linear-gradient(
|
|
240
|
+
90deg,
|
|
241
|
+
var(--c1),
|
|
242
|
+
var(--c3)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`--track` and `--grad` derive from `--c1`–`--c3` automatically; set them
|
|
248
|
+
directly for finer control.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## API
|
|
253
|
+
|
|
254
|
+
### Props
|
|
255
|
+
|
|
256
|
+
| prop | type | default | description |
|
|
257
|
+
|---|---|---|---|
|
|
258
|
+
| `variant` | `LoaderVariant` | `"aurora"` | Which loader to render — any of the 212 ids below. |
|
|
259
|
+
| `size` | `number \| string` | `48` | Overall size. A number means pixels; strings pass through (`"3rem"`). |
|
|
260
|
+
| `speed` | `number \| string` | `1` | Base duration. A number means seconds; lower is faster. |
|
|
261
|
+
| `colors` | `string[]` | indigo / pink / cyan | One to three colours. Fewer are cycled, so a single colour gives a clean monochrome loader. |
|
|
262
|
+
| `label` | `string \| null` | `"Loading"` | Screen-reader text. Pass `null` to mark the loader decorative. |
|
|
263
|
+
|
|
264
|
+
Every other `div` prop — `className`, `style`, `id`, `onClick`, `data-*` —
|
|
265
|
+
passes straight through.
|
|
266
|
+
|
|
267
|
+
### Exports
|
|
268
|
+
|
|
269
|
+
| export | what it is |
|
|
270
|
+
|---|---|
|
|
271
|
+
| `Loader` | The component. |
|
|
272
|
+
| `VARIANTS` | Manifest of all 212: `{ id, label, group, cells }`. |
|
|
273
|
+
| `LOADER_VARIANTS` | Just the 212 ids, in display order. |
|
|
274
|
+
| `GROUPS` | The 20 families: `{ name, description }`. |
|
|
275
|
+
|
|
276
|
+
`Loader` is the main export. The original ten also have named wrappers, kept for
|
|
277
|
+
backward compatibility with 1.0.x:
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
import {
|
|
281
|
+
Aurora, Orbit, Rings, Wave, Bars,
|
|
282
|
+
Blob, Cube, Spiral, Bar, Grid,
|
|
283
|
+
} from "modern-loaders";
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Everything else is reached with `<Loader variant="…" />`. Two hundred named
|
|
287
|
+
exports would bloat the API surface for no real gain, and `variant`
|
|
288
|
+
autocompletes just as well.
|
|
289
|
+
|
|
290
|
+
### TypeScript
|
|
291
|
+
|
|
292
|
+
Types ship with the package — no `@types` install:
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
import type {
|
|
296
|
+
LoaderProps,
|
|
297
|
+
LoaderVariant,
|
|
298
|
+
LoaderGroup,
|
|
299
|
+
VariantMeta,
|
|
300
|
+
} from "modern-loaders";
|
|
301
|
+
|
|
302
|
+
// a union of all 212 ids; typos fail to compile
|
|
303
|
+
const variant: LoaderVariant = "aurora";
|
|
304
|
+
|
|
305
|
+
// wrap Loader without re-declaring its props
|
|
306
|
+
function Busy(props: LoaderProps) {
|
|
307
|
+
return <Loader {...props} />;
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
114
313
|
## All 212 variants
|
|
115
314
|
|
|
116
|
-
Every id maps to a `.ldr--<id>` CSS class. The tables below are the full
|
|
117
|
-
moving, use the [live gallery](https://modern-loaders.netlify.app/) — it renders
|
|
118
|
-
your own size, speed
|
|
315
|
+
Every id maps to a `.ldr--<id>` CSS class. The tables below are the full
|
|
316
|
+
reference; to *see* them moving, use the [live gallery](https://modern-loaders.netlify.app/) — it renders
|
|
317
|
+
every variant with your own size, speed and colours, and copies the JSX for you.
|
|
119
318
|
|
|
120
319
|
<details>
|
|
121
320
|
<summary><b>Spinners</b> · 10 — Rings and arcs — the classic shape, modernised.</summary>
|
|
@@ -489,33 +688,15 @@ your own size, speed, and colours, and copies the JSX for you.
|
|
|
489
688
|
|
|
490
689
|
</details>
|
|
491
690
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
The `colors` prop covers most cases. For anything else, override the custom properties — they
|
|
495
|
-
cascade, so one rule themes a whole subtree:
|
|
496
|
-
|
|
497
|
-
```css
|
|
498
|
-
.dashboard {
|
|
499
|
-
--c1: #6366f1; /* primary */
|
|
500
|
-
--c2: #ec4899; /* secondary */
|
|
501
|
-
--c3: #22d3ee; /* tertiary */
|
|
502
|
-
--size: 64px; /* box size */
|
|
503
|
-
--speed: .9s; /* base duration */
|
|
504
|
-
|
|
505
|
-
--track: #1e1e2e; /* rail behind progress bars */
|
|
506
|
-
--grad: linear-gradient(90deg, var(--c1), var(--c3)); /* shared gradient */
|
|
507
|
-
}
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
`--track` and `--grad` derive from `--c1`–`--c3` automatically; set them directly for finer control.
|
|
691
|
+
---
|
|
511
692
|
|
|
512
693
|
## Accessibility
|
|
513
694
|
|
|
514
695
|
- Each loader renders as `role="status"` with `aria-label`, so assistive tech announces it once.
|
|
515
|
-
- A decorative loader — one sitting beside visible "Loading…" text — should take `label={null}`,
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
696
|
+
- A decorative loader — one sitting beside visible "Loading…" text — should take `label={null}`, which switches it to `aria-hidden` and prevents a double announcement.
|
|
697
|
+
- Under `prefers-reduced-motion: reduce`, every animation slows to a single calm 4s linear cycle rather than stopping. A frozen loader reads as a crashed app, which is worse than gentle motion.
|
|
698
|
+
|
|
699
|
+
---
|
|
519
700
|
|
|
520
701
|
## Bundle size
|
|
521
702
|
|
|
@@ -524,52 +705,64 @@ cascade, so one rule themes a whole subtree:
|
|
|
524
705
|
| JS | ~18 kB | **~4 kB** |
|
|
525
706
|
| CSS (all 212 variants) | ~166 kB | **~24 kB** |
|
|
526
707
|
|
|
527
|
-
One caveat, stated plainly: **the CSS is not tree-shakeable.** Class-based
|
|
528
|
-
dead-code eliminated, so importing a single variant still ships
|
|
529
|
-
gzipped that is a fair trade for most apps, but
|
|
530
|
-
|
|
531
|
-
|
|
708
|
+
One caveat, stated plainly: **the CSS is not tree-shakeable.** Class-based
|
|
709
|
+
styles cannot be dead-code eliminated, so importing a single variant still ships
|
|
710
|
+
the sheet for all 212. At ~24 kB gzipped that is a fair trade for most apps, but
|
|
711
|
+
it is real weight. If you need only a handful and every kilobyte counts, copy
|
|
712
|
+
the specific `.ldr--*` blocks out of [`src/styles/`](./src/styles) into your own
|
|
713
|
+
CSS and skip the package — each block is self-contained apart from the shared
|
|
532
714
|
keyframes in [`00-base.css`](./src/styles/00-base.css).
|
|
533
715
|
|
|
534
|
-
|
|
716
|
+
---
|
|
535
717
|
|
|
536
|
-
|
|
537
|
-
with 1.0.x:
|
|
718
|
+
## Browser support
|
|
538
719
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
720
|
+
Chrome 111+ · Safari 16.4+ · Firefox 113+ — the floor is set by `color-mix()`,
|
|
721
|
+
alongside `mask`, `aspect-ratio`, `clip-path`, and the individual `translate` /
|
|
722
|
+
`rotate` / `scale` properties. Older browsers degrade to solid shapes rather
|
|
723
|
+
than breaking.
|
|
542
724
|
|
|
543
|
-
|
|
544
|
-
|
|
725
|
+
Five variants — `neon-arc`, `pie`, `progress-ring`, `gradient-border`,
|
|
726
|
+
`color-cycle` — animate a registered custom property via `@property`
|
|
727
|
+
(Firefox 128+). Every use passes a fallback, so below that they render a
|
|
728
|
+
sensible static frame instead of disappearing.
|
|
545
729
|
|
|
546
|
-
|
|
730
|
+
---
|
|
547
731
|
|
|
548
|
-
|
|
549
|
-
`aspect-ratio`, `clip-path`, and the individual `translate` / `rotate` / `scale` properties. Older
|
|
550
|
-
browsers degrade to solid shapes rather than breaking.
|
|
732
|
+
## Contributing
|
|
551
733
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
734
|
+
```bash
|
|
735
|
+
# Live showcase with search and filters
|
|
736
|
+
npm run dev
|
|
555
737
|
|
|
556
|
-
|
|
738
|
+
# Typecheck, then build dist/
|
|
739
|
+
npm run build
|
|
557
740
|
|
|
558
|
-
|
|
559
|
-
npm run
|
|
560
|
-
npm run build # typecheck, then emit dist/ (ESM + CJS + .d.ts + CSS)
|
|
561
|
-
npm run build:demo # static showcase → dist-demo/ (deployed to modern-loaders.netlify.app)
|
|
741
|
+
# Build the static showcase
|
|
742
|
+
npm run build:demo
|
|
562
743
|
```
|
|
563
744
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
745
|
+
`build` emits ESM + CJS + `.d.ts` + CSS into `dist/`. `build:demo` writes the
|
|
746
|
+
static showcase to `dist-demo/`, which is what gets deployed to
|
|
747
|
+
[modern-loaders.netlify.app](https://modern-loaders.netlify.app/).
|
|
748
|
+
|
|
749
|
+
Adding a variant takes two edits: a `.ldr--<id>` block in `src/styles/`, and a
|
|
750
|
+
row in [`src/variants.ts`](./src/variants.ts). The component, the types, the
|
|
751
|
+
README catalogue and the showcase all read from that one manifest — `cells` is
|
|
752
|
+
how many `<span>` children the CSS expects.
|
|
567
753
|
|
|
568
754
|
Two rules keep the motion composable inside a variant: put a whole radial chain
|
|
569
|
-
(`rotate(…) translateY(…)`) in a single `transform` so the offset happens in the
|
|
570
|
-
and reach for the standalone `translate` / `rotate` / `scale`
|
|
571
|
-
animates `transform` — they compose instead
|
|
755
|
+
(`rotate(…) translateY(…)`) in a single `transform` so the offset happens in the
|
|
756
|
+
rotated frame, and reach for the standalone `translate` / `rotate` / `scale`
|
|
757
|
+
properties when an element already animates `transform` — they compose instead
|
|
758
|
+
of overwriting it.
|
|
759
|
+
|
|
760
|
+
---
|
|
572
761
|
|
|
573
762
|
## License
|
|
574
763
|
|
|
575
764
|
ISC © suman
|
|
765
|
+
|
|
766
|
+
<div align="center">
|
|
767
|
+
<sub><a href="https://modern-loaders.netlify.app/">Live gallery</a> · <a href="https://www.npmjs.com/package/modern-loaders">npm</a> · <a href="https://github.com/Suman1999-hub/modern-loaders-package">GitHub</a></sub>
|
|
768
|
+
</div>
|
package/package.json
CHANGED