modern-loaders 1.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/README.md +115 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @sumanrana/modern-loaders
|
|
2
|
+
|
|
3
|
+
10 modern, colorful, animated loaders for React. Pure CSS animations behind a typed
|
|
4
|
+
component API — **zero runtime dependencies**, ~2 kB JS + ~1.7 kB CSS gzipped.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm i @sumanrana/modern-loaders
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { Loader } from "@sumanrana/modern-loaders";
|
|
12
|
+
|
|
13
|
+
<Loader />
|
|
14
|
+
<Loader variant="wave" size={72} speed={0.8} colors={["#f97316", "#ef4444", "#a855f7"]} />
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The CSS ships inside the bundle and injects itself — there is no separate stylesheet import.
|
|
18
|
+
(If your setup strips side-effect imports, `import "@sumanrana/modern-loaders/styles.css"`.)
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
| prop | type | default | notes |
|
|
23
|
+
|-----------|--------------------|-------------|--------------------------------------------------------------|
|
|
24
|
+
| `variant` | `LoaderVariant` | `"aurora"` | one of the 10 below |
|
|
25
|
+
| `size` | `number \| string` | `48` | a number means pixels |
|
|
26
|
+
| `speed` | `number \| string` | `1` | a number means seconds |
|
|
27
|
+
| `colors` | `string[]` | Nebula | 1–3 colors; fewer are cycled, so one color gives a monochrome loader |
|
|
28
|
+
| `label` | `string \| null` | `"Loading"` | screen-reader text; `null` marks the loader decorative (`aria-hidden`) |
|
|
29
|
+
|
|
30
|
+
Any other `div` prop (`className`, `style`, `id`, data-attributes…) passes straight through.
|
|
31
|
+
|
|
32
|
+
## The 10 variants
|
|
33
|
+
|
|
34
|
+
| variant | look |
|
|
35
|
+
|------------|-----------------------------------------------|
|
|
36
|
+
| `aurora` | multi-color conic sweep with a soft glow |
|
|
37
|
+
| `orbit` | three-color comet trail |
|
|
38
|
+
| `rings` | sonar pulses in three hues |
|
|
39
|
+
| `wave` | rainbow dots riding a sine |
|
|
40
|
+
| `bars` | gradient equalizer |
|
|
41
|
+
| `blob` | morphing gradient squircle |
|
|
42
|
+
| `cube` | 3D flip, a gradient per face |
|
|
43
|
+
| `spiral` | two arcs spinning opposite directions |
|
|
44
|
+
| `bar` | indeterminate gradient progress track |
|
|
45
|
+
| `grid` | 3×3 cells pulsing on a diagonal |
|
|
46
|
+
|
|
47
|
+
Each also has a named export, so `<Aurora size={64} />` works as well as
|
|
48
|
+
`<Loader variant="aurora" size={64} />`. `LOADER_VARIANTS` is exported as a readonly
|
|
49
|
+
tuple if you want to map over them.
|
|
50
|
+
|
|
51
|
+
## Styling
|
|
52
|
+
|
|
53
|
+
Everything is driven by CSS custom properties, so you can theme without the `colors` prop:
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
.my-loader { --c1: #6366f1; --c2: #ec4899; --c3: #22d3ee; --size: 64px; --speed: .9s; }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`--track` (the muted rail behind `bar`) derives from `--c1` via `color-mix()`; override it
|
|
60
|
+
for a different tint. Under `prefers-reduced-motion: reduce` every animation slows to one
|
|
61
|
+
calm 4s linear cycle rather than freezing — a stopped loader reads as a broken app.
|
|
62
|
+
|
|
63
|
+
## Development
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run dev # demo playground at localhost:5173
|
|
67
|
+
npm run build # typecheck + emit dist/ (ESM + CJS + .d.ts + CSS)
|
|
68
|
+
npm run typecheck
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Publishing the package
|
|
72
|
+
|
|
73
|
+
The scope in `name` must be one your npm account owns. Check first:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm whoami # your username
|
|
77
|
+
npm view @sumanrana/modern-loaders # 404 = the name is free
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If the scope isn't yours, change `name` to `@<your-npm-user>/react-modern-loaders`
|
|
81
|
+
(or an unscoped name that's still free), then:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm login
|
|
85
|
+
npm publish --access public # required for scoped packages
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`prepublishOnly` runs the build, and `files` limits the tarball to `dist/` + this README.
|
|
89
|
+
|
|
90
|
+
## Deploying the demo
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm run build:demo # → dist-demo/
|
|
94
|
+
npm run preview:demo # check it locally
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Then push `dist-demo/` to any static host:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npx vercel deploy dist-demo --prod
|
|
101
|
+
npx netlify-cli deploy --dir dist-demo --prod
|
|
102
|
+
npx wrangler pages deploy dist-demo
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For GitHub Pages the site lives under `/<repo>/`, so build with a matching base:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
DEMO_BASE=/loader/ npm run build:demo
|
|
109
|
+
npx gh-pages -d dist-demo # or push dist-demo to a gh-pages branch
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Browser support
|
|
113
|
+
|
|
114
|
+
Uses `mask`, `color-mix()`, and `aspect-ratio`: Chrome 111+, Safari 16.2+, Firefox 113+.
|
|
115
|
+
Older browsers degrade to solid shapes rather than breaking.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require('./index.css');const r=require("react/jsx-runtime"),g=["aurora","orbit","rings","wave","bars","blob","cube","spiral","bar","grid"],j={aurora:0,orbit:3,rings:3,wave:5,bars:5,blob:0,cube:2,spiral:0,bar:0,grid:9},o=(a,s)=>typeof a=="number"?`${a}${s}`:a;function t({variant:a="aurora",size:s=48,speed:b=1,colors:i,label:e="Loading",className:u,style:d,...c}){const n={"--size":o(s,"px"),"--speed":o(b,"s")};i!=null&&i.length&&(n["--c1"]=i[0],n["--c2"]=i[1%i.length],n["--c3"]=i[2%i.length]);const v=j[a];return r.jsx("div",{...c,className:["ldr",`ldr--${a}`,u].filter(Boolean).join(" "),style:{...n,...d},role:e?"status":void 0,"aria-label":e??void 0,"aria-hidden":e?void 0:!0,children:Array.from({length:v},(y,l)=>r.jsx("span",{},l))})}const x=a=>r.jsx(t,{variant:"aurora",...a}),p=a=>r.jsx(t,{variant:"orbit",...a}),A=a=>r.jsx(t,{variant:"rings",...a}),B=a=>r.jsx(t,{variant:"wave",...a}),L=a=>r.jsx(t,{variant:"bars",...a}),R=a=>r.jsx(t,{variant:"blob",...a}),S=a=>r.jsx(t,{variant:"cube",...a}),f=a=>r.jsx(t,{variant:"spiral",...a}),h=a=>r.jsx(t,{variant:"bar",...a}),m=a=>r.jsx(t,{variant:"grid",...a});exports.Aurora=x;exports.Bar=h;exports.Bars=L;exports.Blob=R;exports.Cube=S;exports.Grid=m;exports.LOADER_VARIANTS=g;exports.Loader=t;exports.Orbit=p;exports.Rings=A;exports.Spiral=f;exports.Wave=B;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/Loader.tsx"],"sourcesContent":["import type { CSSProperties, HTMLAttributes } from \"react\";\nimport \"./loaders.css\";\n\nexport const LOADER_VARIANTS = [\n \"aurora\",\n \"orbit\",\n \"rings\",\n \"wave\",\n \"bars\",\n \"blob\",\n \"cube\",\n \"spiral\",\n \"bar\",\n \"grid\",\n] as const;\n\nexport type LoaderVariant = (typeof LOADER_VARIANTS)[number];\n\n/** How many <span> children each variant's CSS expects. */\nconst CELLS: Record<LoaderVariant, number> = {\n aurora: 0,\n orbit: 3,\n rings: 3,\n wave: 5,\n bars: 5,\n blob: 0,\n cube: 2,\n spiral: 0,\n bar: 0,\n grid: 9,\n};\n\nexport interface LoaderProps extends Omit<HTMLAttributes<HTMLDivElement>, \"color\"> {\n /** Which loader to render. @default \"aurora\" */\n variant?: LoaderVariant;\n /** Box size. A number is treated as pixels. @default 48 */\n size?: number | string;\n /** Base animation duration. A number is treated as seconds. @default 1 */\n speed?: number | string;\n /**\n * One to three colors. Fewer than three are cycled, so a single color still\n * produces a coherent (monochrome) loader.\n */\n colors?: string[];\n /** Announced to screen readers. Pass `null` to render the loader as decorative. */\n label?: string | null;\n}\n\nconst unit = (v: number | string | undefined, suffix: string) =>\n typeof v === \"number\" ? `${v}${suffix}` : v;\n\nexport function Loader({\n variant = \"aurora\",\n size = 48,\n speed = 1,\n colors,\n label = \"Loading\",\n className,\n style,\n ...rest\n}: LoaderProps) {\n const vars: CSSProperties & Record<string, string | undefined> = {\n \"--size\": unit(size, \"px\"),\n \"--speed\": unit(speed, \"s\"),\n };\n\n if (colors?.length) {\n // Cycle whatever was given across the three slots the CSS reads.\n vars[\"--c1\"] = colors[0];\n vars[\"--c2\"] = colors[1 % colors.length];\n vars[\"--c3\"] = colors[2 % colors.length];\n }\n\n const cells = CELLS[variant];\n\n return (\n <div\n {...rest}\n className={[\"ldr\", `ldr--${variant}`, className].filter(Boolean).join(\" \")}\n style={{ ...vars, ...style }}\n role={label ? \"status\" : undefined}\n aria-label={label ?? undefined}\n aria-hidden={label ? undefined : true}\n >\n {Array.from({ length: cells }, (_, i) => (\n <span key={i} />\n ))}\n </div>\n );\n}\n\n/** Convenience wrappers, so `<Aurora />` works as well as `<Loader variant=\"aurora\" />`. */\ntype VariantProps = Omit<LoaderProps, \"variant\">;\n\nexport const Aurora = (p: VariantProps) => <Loader variant=\"aurora\" {...p} />;\nexport const Orbit = (p: VariantProps) => <Loader variant=\"orbit\" {...p} />;\nexport const Rings = (p: VariantProps) => <Loader variant=\"rings\" {...p} />;\nexport const Wave = (p: VariantProps) => <Loader variant=\"wave\" {...p} />;\nexport const Bars = (p: VariantProps) => <Loader variant=\"bars\" {...p} />;\nexport const Blob = (p: VariantProps) => <Loader variant=\"blob\" {...p} />;\nexport const Cube = (p: VariantProps) => <Loader variant=\"cube\" {...p} />;\nexport const Spiral = (p: VariantProps) => <Loader variant=\"spiral\" {...p} />;\nexport const Bar = (p: VariantProps) => <Loader variant=\"bar\" {...p} />;\nexport const Grid = (p: VariantProps) => <Loader variant=\"grid\" {...p} />;\n"],"names":["LOADER_VARIANTS","CELLS","unit","v","suffix","Loader","variant","size","speed","colors","label","className","style","rest","vars","cells","jsx","_","i","Aurora","p","Orbit","Rings","Wave","Bars","Blob","Cube","Spiral","Bar","Grid"],"mappings":"qHAGaA,EAAkB,CAC7B,SACA,QACA,QACA,OACA,OACA,OACA,OACA,SACA,MACA,MACF,EAKMC,EAAuC,CAC3C,OAAQ,EACR,MAAO,EACP,MAAO,EACP,KAAM,EACN,KAAM,EACN,KAAM,EACN,KAAM,EACN,OAAQ,EACR,IAAK,EACL,KAAM,CACR,EAkBMC,EAAO,CAACC,EAAgCC,IAC5C,OAAOD,GAAM,SAAW,GAAGA,CAAC,GAAGC,CAAM,GAAKD,EAErC,SAASE,EAAO,CACrB,QAAAC,EAAU,SACV,KAAAC,EAAO,GACP,MAAAC,EAAQ,EACR,OAAAC,EACA,MAAAC,EAAQ,UACR,UAAAC,EACA,MAAAC,EACA,GAAGC,CACL,EAAgB,CACd,MAAMC,EAA2D,CAC/D,SAAUZ,EAAKK,EAAM,IAAI,EACzB,UAAWL,EAAKM,EAAO,GAAG,CAAA,EAGxBC,GAAA,MAAAA,EAAQ,SAEVK,EAAK,MAAM,EAAIL,EAAO,CAAC,EACvBK,EAAK,MAAM,EAAIL,EAAO,EAAIA,EAAO,MAAM,EACvCK,EAAK,MAAM,EAAIL,EAAO,EAAIA,EAAO,MAAM,GAGzC,MAAMM,EAAQd,EAAMK,CAAO,EAE3B,OACEU,EAAAA,IAAC,MAAA,CACE,GAAGH,EACJ,UAAW,CAAC,MAAO,QAAQP,CAAO,GAAIK,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EACzE,MAAO,CAAE,GAAGG,EAAM,GAAGF,CAAA,EACrB,KAAMF,EAAQ,SAAW,OACzB,aAAYA,GAAS,OACrB,cAAaA,EAAQ,OAAY,GAEhC,SAAA,MAAM,KAAK,CAAE,OAAQK,CAAA,EAAS,CAACE,EAAGC,IACjCF,EAAAA,IAAC,OAAA,CAAA,EAAUE,CAAG,CACf,CAAA,CAAA,CAGP,CAKO,MAAMC,EAAUC,GAAoBJ,MAACX,GAAO,QAAQ,SAAU,GAAGe,CAAA,CAAG,EAC9DC,EAAUD,GAAoBJ,MAACX,GAAO,QAAQ,QAAU,GAAGe,CAAA,CAAG,EAC9DE,EAAUF,GAAoBJ,MAACX,GAAO,QAAQ,QAAU,GAAGe,CAAA,CAAG,EAC9DG,EAAUH,GAAoBJ,MAACX,GAAO,QAAQ,OAAU,GAAGe,CAAA,CAAG,EAC9DI,EAAUJ,GAAoBJ,MAACX,GAAO,QAAQ,OAAU,GAAGe,CAAA,CAAG,EAC9DK,EAAUL,GAAoBJ,MAACX,GAAO,QAAQ,OAAU,GAAGe,CAAA,CAAG,EAC9DM,EAAUN,GAAoBJ,MAACX,GAAO,QAAQ,OAAU,GAAGe,CAAA,CAAG,EAC9DO,EAAUP,GAAoBJ,MAACX,GAAO,QAAQ,SAAU,GAAGe,CAAA,CAAG,EAC9DQ,EAAUR,GAAoBJ,MAACX,GAAO,QAAQ,MAAU,GAAGe,CAAA,CAAG,EAC9DS,EAAUT,GAAoBJ,MAACX,GAAO,QAAQ,OAAU,GAAGe,CAAA,CAAG"}
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.ldr{--size: 48px;--speed: 1s;--c1: #6366f1;--c2: #ec4899;--c3: #22d3ee;--track: color-mix(in oklab, var(--c1) 18%, transparent);width:var(--size);height:var(--size);flex:none;display:inline-block;position:relative;box-sizing:border-box}.ldr *,.ldr *:before,.ldr *:after{box-sizing:border-box}.ldr--aurora{border-radius:50%;background:conic-gradient(from 0turn,var(--c1),var(--c2),var(--c3),var(--c1));-webkit-mask:radial-gradient(farthest-side,#0000 85%,#000 86%);mask:radial-gradient(farthest-side,#0000 85%,#000 86%);animation:ldr-spin var(--speed) linear infinite}.ldr--aurora:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:inherit;filter:blur(calc(var(--size) / 8));opacity:.55;animation:ldr-breathe calc(var(--speed) * 2) ease-in-out infinite}.ldr--orbit span{position:absolute;top:0;left:50%;width:24%;height:24%;margin-left:-12%;border-radius:50%;transform-origin:50% calc(var(--size) / 2);animation:ldr-spin var(--speed) cubic-bezier(.6,.1,.4,.9) infinite}.ldr--orbit span:nth-child(1){background:var(--c1)}.ldr--orbit span:nth-child(2){background:var(--c2);animation-delay:calc(var(--speed) * -.08);opacity:.75;scale:.8}.ldr--orbit span:nth-child(3){background:var(--c3);animation-delay:calc(var(--speed) * -.16);opacity:.5;scale:.6}.ldr--rings span{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;border:calc(var(--size) / 16) solid;animation:ldr-ripple calc(var(--speed) * 1.8) cubic-bezier(0,.2,.8,1) infinite}.ldr--rings span:nth-child(1){border-color:var(--c1)}.ldr--rings span:nth-child(2){border-color:var(--c2);animation-delay:calc(var(--speed) * -.6)}.ldr--rings span:nth-child(3){border-color:var(--c3);animation-delay:calc(var(--speed) * -1.2)}.ldr--wave{display:inline-flex;align-items:center;justify-content:space-between;width:calc(var(--size) * 1.6)}.ldr--wave span{width:15%;aspect-ratio:1;border-radius:50%;animation:ldr-wave calc(var(--speed) * 1.1) cubic-bezier(.4,0,.6,1) infinite}.ldr--wave span:nth-child(1){background:var(--c1)}.ldr--wave span:nth-child(2){background:color-mix(in oklab,var(--c1),var(--c2));animation-delay:calc(var(--speed) * .1)}.ldr--wave span:nth-child(3){background:var(--c2);animation-delay:calc(var(--speed) * .2)}.ldr--wave span:nth-child(4){background:color-mix(in oklab,var(--c2),var(--c3));animation-delay:calc(var(--speed) * .3)}.ldr--wave span:nth-child(5){background:var(--c3);animation-delay:calc(var(--speed) * .4)}.ldr--bars{display:inline-flex;align-items:center;width:calc(var(--size) * 1.25);gap:calc(var(--size) / 11)}.ldr--bars span{flex:1;height:100%;border-radius:99px;background:linear-gradient(var(--c1),var(--c2),var(--c3));animation:ldr-eq calc(var(--speed) * 1.2) ease-in-out infinite}.ldr--bars span:nth-child(2){animation-delay:calc(var(--speed) * -1)}.ldr--bars span:nth-child(3){animation-delay:calc(var(--speed) * -.85)}.ldr--bars span:nth-child(4){animation-delay:calc(var(--speed) * -.7)}.ldr--bars span:nth-child(5){animation-delay:calc(var(--speed) * -.55)}.ldr--blob{background:linear-gradient(135deg,var(--c1),var(--c2) 50%,var(--c3));background-size:200% 200%;animation:ldr-morph calc(var(--speed) * 2.4) ease-in-out infinite,ldr-spin calc(var(--speed) * 3) ease-in-out infinite,ldr-shift calc(var(--speed) * 2) ease-in-out infinite}.ldr--cube{perspective:calc(var(--size) * 4)}.ldr--cube span{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:calc(var(--size) / 7);backface-visibility:hidden;animation:ldr-flip calc(var(--speed) * 2) cubic-bezier(.6,.05,.4,.95) infinite}.ldr--cube span:nth-child(1){background:linear-gradient(135deg,var(--c1),var(--c2))}.ldr--cube span:nth-child(2){background:linear-gradient(135deg,var(--c2),var(--c3));transform:rotateY(180deg)}.ldr--spiral:before,.ldr--spiral:after{content:"";position:absolute;border-radius:50%;border:calc(var(--size) / 14) solid transparent}.ldr--spiral:before{top:0;right:0;bottom:0;left:0;border-top-color:var(--c1);border-right-color:var(--c2);animation:ldr-spin var(--speed) cubic-bezier(.5,.1,.5,.9) infinite}.ldr--spiral:after{top:28%;right:28%;bottom:28%;left:28%;border-bottom-color:var(--c3);border-left-color:var(--c2);animation:ldr-spin calc(var(--speed) * .75) linear infinite reverse}.ldr--bar{width:calc(var(--size) * 3.4);height:calc(var(--size) / 6);border-radius:99px;background:var(--track);overflow:hidden}.ldr--bar:after{content:"";position:absolute;inset:0 auto 0 0;width:40%;border-radius:inherit;background:linear-gradient(90deg,var(--c1),var(--c2),var(--c3));animation:ldr-slide calc(var(--speed) * 1.5) cubic-bezier(.65,.05,.35,.95) infinite}.ldr--grid{display:grid;grid-template-columns:repeat(3,1fr);gap:calc(var(--size) / 12)}.ldr--grid span{border-radius:calc(var(--size) / 10);animation:ldr-pop calc(var(--speed) * 1.3) ease-in-out infinite}.ldr--grid span:nth-child(1){background:var(--c1);animation-delay:calc(var(--speed) * 0)}.ldr--grid span:nth-child(2),.ldr--grid span:nth-child(4){background:color-mix(in oklab,var(--c1),var(--c2));animation-delay:calc(var(--speed) * .1)}.ldr--grid span:nth-child(3),.ldr--grid span:nth-child(5),.ldr--grid span:nth-child(7){background:var(--c2);animation-delay:calc(var(--speed) * .2)}.ldr--grid span:nth-child(6),.ldr--grid span:nth-child(8){background:color-mix(in oklab,var(--c2),var(--c3));animation-delay:calc(var(--speed) * .3)}.ldr--grid span:nth-child(9){background:var(--c3);animation-delay:calc(var(--speed) * .4)}@keyframes ldr-spin{to{transform:rotate(1turn)}}@keyframes ldr-breathe{0%,to{opacity:.35}50%{opacity:.7}}@keyframes ldr-ripple{0%{transform:scale(.15);opacity:1}to{transform:scale(1);opacity:0}}@keyframes ldr-wave{0%,60%,to{transform:translateY(0);opacity:.55}30%{transform:translateY(-80%);opacity:1}}@keyframes ldr-eq{0%,to{transform:scaleY(.22);opacity:.55}50%{transform:scaleY(1);opacity:1}}@keyframes ldr-morph{0%,to{border-radius:50%}25%{border-radius:62% 38% 46% 54%/60% 55% 45% 40%}50%{border-radius:24%}75%{border-radius:38% 62% 60% 40%/42% 38% 62% 58%}}@keyframes ldr-shift{0%,to{background-position:0% 50%}50%{background-position:100% 50%}}@keyframes ldr-flip{0%{transform:rotateY(0) rotateX(0)}50%{transform:rotateY(180deg) rotateX(0)}to{transform:rotateY(180deg) rotateX(180deg)}}@keyframes ldr-slide{0%{left:-40%;width:40%}50%{left:25%;width:55%}to{left:100%;width:40%}}@keyframes ldr-pop{0%,70%,to{transform:scale(.62);opacity:.5}35%{transform:scale(1);opacity:1}}@media(prefers-reduced-motion:reduce){.ldr,.ldr:before,.ldr:after,.ldr span{animation-duration:4s!important;animation-timing-function:linear!important}}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { JSX as JSX_2 } from 'react';
|
|
3
|
+
|
|
4
|
+
export declare const Aurora: (p: VariantProps) => JSX_2.Element;
|
|
5
|
+
|
|
6
|
+
export declare const Bar: (p: VariantProps) => JSX_2.Element;
|
|
7
|
+
|
|
8
|
+
export declare const Bars: (p: VariantProps) => JSX_2.Element;
|
|
9
|
+
|
|
10
|
+
declare const Blob_2: (p: VariantProps) => JSX_2.Element;
|
|
11
|
+
export { Blob_2 as Blob }
|
|
12
|
+
|
|
13
|
+
export declare const Cube: (p: VariantProps) => JSX_2.Element;
|
|
14
|
+
|
|
15
|
+
export declare const Grid: (p: VariantProps) => JSX_2.Element;
|
|
16
|
+
|
|
17
|
+
export declare function Loader({ variant, size, speed, colors, label, className, style, ...rest }: LoaderProps): JSX_2.Element;
|
|
18
|
+
|
|
19
|
+
export declare const LOADER_VARIANTS: readonly ["aurora", "orbit", "rings", "wave", "bars", "blob", "cube", "spiral", "bar", "grid"];
|
|
20
|
+
|
|
21
|
+
export declare interface LoaderProps extends Omit<HTMLAttributes<HTMLDivElement>, "color"> {
|
|
22
|
+
/** Which loader to render. @default "aurora" */
|
|
23
|
+
variant?: LoaderVariant;
|
|
24
|
+
/** Box size. A number is treated as pixels. @default 48 */
|
|
25
|
+
size?: number | string;
|
|
26
|
+
/** Base animation duration. A number is treated as seconds. @default 1 */
|
|
27
|
+
speed?: number | string;
|
|
28
|
+
/**
|
|
29
|
+
* One to three colors. Fewer than three are cycled, so a single color still
|
|
30
|
+
* produces a coherent (monochrome) loader.
|
|
31
|
+
*/
|
|
32
|
+
colors?: string[];
|
|
33
|
+
/** Announced to screen readers. Pass `null` to render the loader as decorative. */
|
|
34
|
+
label?: string | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export declare type LoaderVariant = (typeof LOADER_VARIANTS)[number];
|
|
38
|
+
|
|
39
|
+
export declare const Orbit: (p: VariantProps) => JSX_2.Element;
|
|
40
|
+
|
|
41
|
+
export declare const Rings: (p: VariantProps) => JSX_2.Element;
|
|
42
|
+
|
|
43
|
+
export declare const Spiral: (p: VariantProps) => JSX_2.Element;
|
|
44
|
+
|
|
45
|
+
/** Convenience wrappers, so `<Aurora />` works as well as `<Loader variant="aurora" />`. */
|
|
46
|
+
declare type VariantProps = Omit<LoaderProps, "variant">;
|
|
47
|
+
|
|
48
|
+
export declare const Wave: (p: VariantProps) => JSX_2.Element;
|
|
49
|
+
|
|
50
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import './index.css';const h = [
|
|
3
|
+
"aurora",
|
|
4
|
+
"orbit",
|
|
5
|
+
"rings",
|
|
6
|
+
"wave",
|
|
7
|
+
"bars",
|
|
8
|
+
"blob",
|
|
9
|
+
"cube",
|
|
10
|
+
"spiral",
|
|
11
|
+
"bar",
|
|
12
|
+
"grid"
|
|
13
|
+
], l = {
|
|
14
|
+
aurora: 0,
|
|
15
|
+
orbit: 3,
|
|
16
|
+
rings: 3,
|
|
17
|
+
wave: 5,
|
|
18
|
+
bars: 5,
|
|
19
|
+
blob: 0,
|
|
20
|
+
cube: 2,
|
|
21
|
+
spiral: 0,
|
|
22
|
+
bar: 0,
|
|
23
|
+
grid: 9
|
|
24
|
+
}, o = (a, s) => typeof a == "number" ? `${a}${s}` : a;
|
|
25
|
+
function n({
|
|
26
|
+
variant: a = "aurora",
|
|
27
|
+
size: s = 48,
|
|
28
|
+
speed: b = 1,
|
|
29
|
+
colors: t,
|
|
30
|
+
label: e = "Loading",
|
|
31
|
+
className: c,
|
|
32
|
+
style: d,
|
|
33
|
+
...v
|
|
34
|
+
}) {
|
|
35
|
+
const i = {
|
|
36
|
+
"--size": o(s, "px"),
|
|
37
|
+
"--speed": o(b, "s")
|
|
38
|
+
};
|
|
39
|
+
t != null && t.length && (i["--c1"] = t[0], i["--c2"] = t[1 % t.length], i["--c3"] = t[2 % t.length]);
|
|
40
|
+
const u = l[a];
|
|
41
|
+
return /* @__PURE__ */ r(
|
|
42
|
+
"div",
|
|
43
|
+
{
|
|
44
|
+
...v,
|
|
45
|
+
className: ["ldr", `ldr--${a}`, c].filter(Boolean).join(" "),
|
|
46
|
+
style: { ...i, ...d },
|
|
47
|
+
role: e ? "status" : void 0,
|
|
48
|
+
"aria-label": e ?? void 0,
|
|
49
|
+
"aria-hidden": e ? void 0 : !0,
|
|
50
|
+
children: Array.from({ length: u }, (p, g) => /* @__PURE__ */ r("span", {}, g))
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
const m = (a) => /* @__PURE__ */ r(n, { variant: "aurora", ...a }), A = (a) => /* @__PURE__ */ r(n, { variant: "orbit", ...a }), L = (a) => /* @__PURE__ */ r(n, { variant: "rings", ...a }), B = (a) => /* @__PURE__ */ r(n, { variant: "wave", ...a }), w = (a) => /* @__PURE__ */ r(n, { variant: "bars", ...a }), x = (a) => /* @__PURE__ */ r(n, { variant: "blob", ...a }), y = (a) => /* @__PURE__ */ r(n, { variant: "cube", ...a }), R = (a) => /* @__PURE__ */ r(n, { variant: "spiral", ...a }), S = (a) => /* @__PURE__ */ r(n, { variant: "bar", ...a }), $ = (a) => /* @__PURE__ */ r(n, { variant: "grid", ...a });
|
|
55
|
+
export {
|
|
56
|
+
m as Aurora,
|
|
57
|
+
S as Bar,
|
|
58
|
+
w as Bars,
|
|
59
|
+
x as Blob,
|
|
60
|
+
y as Cube,
|
|
61
|
+
$ as Grid,
|
|
62
|
+
h as LOADER_VARIANTS,
|
|
63
|
+
n as Loader,
|
|
64
|
+
A as Orbit,
|
|
65
|
+
L as Rings,
|
|
66
|
+
R as Spiral,
|
|
67
|
+
B as Wave
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/Loader.tsx"],"sourcesContent":["import type { CSSProperties, HTMLAttributes } from \"react\";\nimport \"./loaders.css\";\n\nexport const LOADER_VARIANTS = [\n \"aurora\",\n \"orbit\",\n \"rings\",\n \"wave\",\n \"bars\",\n \"blob\",\n \"cube\",\n \"spiral\",\n \"bar\",\n \"grid\",\n] as const;\n\nexport type LoaderVariant = (typeof LOADER_VARIANTS)[number];\n\n/** How many <span> children each variant's CSS expects. */\nconst CELLS: Record<LoaderVariant, number> = {\n aurora: 0,\n orbit: 3,\n rings: 3,\n wave: 5,\n bars: 5,\n blob: 0,\n cube: 2,\n spiral: 0,\n bar: 0,\n grid: 9,\n};\n\nexport interface LoaderProps extends Omit<HTMLAttributes<HTMLDivElement>, \"color\"> {\n /** Which loader to render. @default \"aurora\" */\n variant?: LoaderVariant;\n /** Box size. A number is treated as pixels. @default 48 */\n size?: number | string;\n /** Base animation duration. A number is treated as seconds. @default 1 */\n speed?: number | string;\n /**\n * One to three colors. Fewer than three are cycled, so a single color still\n * produces a coherent (monochrome) loader.\n */\n colors?: string[];\n /** Announced to screen readers. Pass `null` to render the loader as decorative. */\n label?: string | null;\n}\n\nconst unit = (v: number | string | undefined, suffix: string) =>\n typeof v === \"number\" ? `${v}${suffix}` : v;\n\nexport function Loader({\n variant = \"aurora\",\n size = 48,\n speed = 1,\n colors,\n label = \"Loading\",\n className,\n style,\n ...rest\n}: LoaderProps) {\n const vars: CSSProperties & Record<string, string | undefined> = {\n \"--size\": unit(size, \"px\"),\n \"--speed\": unit(speed, \"s\"),\n };\n\n if (colors?.length) {\n // Cycle whatever was given across the three slots the CSS reads.\n vars[\"--c1\"] = colors[0];\n vars[\"--c2\"] = colors[1 % colors.length];\n vars[\"--c3\"] = colors[2 % colors.length];\n }\n\n const cells = CELLS[variant];\n\n return (\n <div\n {...rest}\n className={[\"ldr\", `ldr--${variant}`, className].filter(Boolean).join(\" \")}\n style={{ ...vars, ...style }}\n role={label ? \"status\" : undefined}\n aria-label={label ?? undefined}\n aria-hidden={label ? undefined : true}\n >\n {Array.from({ length: cells }, (_, i) => (\n <span key={i} />\n ))}\n </div>\n );\n}\n\n/** Convenience wrappers, so `<Aurora />` works as well as `<Loader variant=\"aurora\" />`. */\ntype VariantProps = Omit<LoaderProps, \"variant\">;\n\nexport const Aurora = (p: VariantProps) => <Loader variant=\"aurora\" {...p} />;\nexport const Orbit = (p: VariantProps) => <Loader variant=\"orbit\" {...p} />;\nexport const Rings = (p: VariantProps) => <Loader variant=\"rings\" {...p} />;\nexport const Wave = (p: VariantProps) => <Loader variant=\"wave\" {...p} />;\nexport const Bars = (p: VariantProps) => <Loader variant=\"bars\" {...p} />;\nexport const Blob = (p: VariantProps) => <Loader variant=\"blob\" {...p} />;\nexport const Cube = (p: VariantProps) => <Loader variant=\"cube\" {...p} />;\nexport const Spiral = (p: VariantProps) => <Loader variant=\"spiral\" {...p} />;\nexport const Bar = (p: VariantProps) => <Loader variant=\"bar\" {...p} />;\nexport const Grid = (p: VariantProps) => <Loader variant=\"grid\" {...p} />;\n"],"names":["LOADER_VARIANTS","CELLS","unit","v","suffix","Loader","variant","size","speed","colors","label","className","style","rest","vars","cells","jsx","_","i","Aurora","p","Orbit","Rings","Wave","Bars","Blob","Cube","Spiral","Bar","Grid"],"mappings":";AAGO,MAAMA,IAAkB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKMC,IAAuC;AAAA,EAC3C,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AACR,GAkBMC,IAAO,CAACC,GAAgCC,MAC5C,OAAOD,KAAM,WAAW,GAAGA,CAAC,GAAGC,CAAM,KAAKD;AAErC,SAASE,EAAO;AAAA,EACrB,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,OAAAC,IAAQ;AAAA,EACR,QAAAC;AAAA,EACA,OAAAC,IAAQ;AAAA,EACR,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,GAAGC;AACL,GAAgB;AACd,QAAMC,IAA2D;AAAA,IAC/D,UAAUZ,EAAKK,GAAM,IAAI;AAAA,IACzB,WAAWL,EAAKM,GAAO,GAAG;AAAA,EAAA;AAG5B,EAAIC,KAAA,QAAAA,EAAQ,WAEVK,EAAK,MAAM,IAAIL,EAAO,CAAC,GACvBK,EAAK,MAAM,IAAIL,EAAO,IAAIA,EAAO,MAAM,GACvCK,EAAK,MAAM,IAAIL,EAAO,IAAIA,EAAO,MAAM;AAGzC,QAAMM,IAAQd,EAAMK,CAAO;AAE3B,SACE,gBAAAU;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAGH;AAAA,MACJ,WAAW,CAAC,OAAO,QAAQP,CAAO,IAAIK,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,MACzE,OAAO,EAAE,GAAGG,GAAM,GAAGF,EAAA;AAAA,MACrB,MAAMF,IAAQ,WAAW;AAAA,MACzB,cAAYA,KAAS;AAAA,MACrB,eAAaA,IAAQ,SAAY;AAAA,MAEhC,UAAA,MAAM,KAAK,EAAE,QAAQK,EAAA,GAAS,CAACE,GAAGC,MACjC,gBAAAF,EAAC,QAAA,CAAA,GAAUE,CAAG,CACf;AAAA,IAAA;AAAA,EAAA;AAGP;AAKO,MAAMC,IAAS,CAACC,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,UAAU,GAAGe,EAAA,CAAG,GAC9DC,IAAS,CAACD,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,SAAU,GAAGe,EAAA,CAAG,GAC9DE,IAAS,CAACF,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,SAAU,GAAGe,EAAA,CAAG,GAC9DG,IAAS,CAACH,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,QAAU,GAAGe,EAAA,CAAG,GAC9DI,IAAS,CAACJ,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,QAAU,GAAGe,EAAA,CAAG,GAC9DK,IAAS,CAACL,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,QAAU,GAAGe,EAAA,CAAG,GAC9DM,IAAS,CAACN,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,QAAU,GAAGe,EAAA,CAAG,GAC9DO,IAAS,CAACP,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,UAAU,GAAGe,EAAA,CAAG,GAC9DQ,IAAS,CAACR,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,OAAU,GAAGe,EAAA,CAAG,GAC9DS,IAAS,CAACT,MAAoB,gBAAAJ,EAACX,KAAO,SAAQ,QAAU,GAAGe,EAAA,CAAG;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "modern-loaders",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "10 modern, colorful, animated React loaders — pure CSS, zero runtime dependencies",
|
|
5
|
+
"author": "suman",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": [
|
|
9
|
+
"**/*.css"
|
|
10
|
+
],
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"module": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./styles.css": "./dist/index.css"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"react",
|
|
28
|
+
"loader",
|
|
29
|
+
"spinner",
|
|
30
|
+
"loading",
|
|
31
|
+
"css",
|
|
32
|
+
"animation",
|
|
33
|
+
"skeleton"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"dev": "vite",
|
|
37
|
+
"build": "tsc --noEmit && vite build",
|
|
38
|
+
"preview": "vite preview",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"prepublishOnly": "npm run build",
|
|
41
|
+
"build:demo": "vite build --config vite.demo.config.ts",
|
|
42
|
+
"preview:demo": "vite preview --config vite.demo.config.ts"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"react": ">=17",
|
|
46
|
+
"react-dom": ">=17"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.10.2",
|
|
50
|
+
"@types/react": "^18.3.12",
|
|
51
|
+
"@types/react-dom": "^18.3.1",
|
|
52
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
53
|
+
"react": "^18.3.1",
|
|
54
|
+
"react-dom": "^18.3.1",
|
|
55
|
+
"typescript": "^5.7.2",
|
|
56
|
+
"vite": "^6.0.5",
|
|
57
|
+
"vite-plugin-dts": "^4.4.0",
|
|
58
|
+
"vite-plugin-lib-inject-css": "^2.2.0"
|
|
59
|
+
}
|
|
60
|
+
}
|