tw-shimmer 0.2.2 → 0.4.1
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 +251 -11
- package/package.json +16 -2
- package/src/index.css +132 -30
package/README.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Tailwind CSS v4 plugin for shimmer effects.
|
|
4
4
|
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Zero-dependency, CSS-only shimmer effects
|
|
8
|
+
- **Sine-eased gradients** for buttery-smooth highlights with no banding
|
|
9
|
+
- OKLCH color space for perceptually uniform color mixing
|
|
10
|
+
- Text shimmer and skeleton/background shimmer variants
|
|
11
|
+
- Fully customizable speed, spread, angle, and colors
|
|
12
|
+
|
|
13
|
+
## Why Sine-Eased Gradients?
|
|
14
|
+
|
|
15
|
+
Most shimmer effects use simple linear gradients that create visible "banding" - harsh edges where the highlight meets the background. We use [eased gradients](https://www.joshwcomeau.com/css/make-beautiful-gradients/) with **13-17 carefully calculated stops** following a sine ease-in-out curve.
|
|
16
|
+
|
|
17
|
+
This produces gradual transitions at both the center (peak brightness) and edges (fade to transparent), eliminating the banding that plagues typical shimmer implementations. The result is a shimmer that feels organic and polished.
|
|
18
|
+
|
|
19
|
+
Any performance impact is negligible given the gradient is rendered and accelerated as a texture on the GPU.
|
|
20
|
+
|
|
5
21
|
## Installation
|
|
6
22
|
|
|
7
23
|
```bash
|
|
@@ -39,31 +55,84 @@ Base utility. Apply to any element with a text color.
|
|
|
39
55
|
|
|
40
56
|
### `shimmer-speed-{value}`
|
|
41
57
|
|
|
42
|
-
Animation speed in pixels per second. Default: `
|
|
58
|
+
Animation speed in pixels per second. Default: `150`px/s for text, `1000`px/s for background.
|
|
59
|
+
|
|
60
|
+
`--shimmer-speed` is inheritable:
|
|
61
|
+
|
|
62
|
+
- If you set `--shimmer-speed` (or use `shimmer-speed-{value}`) on a parent container, both `shimmer` and `shimmer-bg` children will use that value unless they override it.
|
|
63
|
+
- If no value is set anywhere, text shimmer falls back to `150` and background shimmer falls back to `1000`.
|
|
64
|
+
|
|
65
|
+
> **How speed is calculated:** For text shimmer, duration is `(2 × width) / speed`, where width is the shimmer track width in pixels (from `--shimmer-width`). For background shimmer we use the same idea but include an angle-aware overshoot so the stripe starts and ends fully off-screen at shallow angles. At 90deg this reduces to the same `(2 × width) / speed` formula; at more extreme angles the pass time is slightly longer to account for the extra travel. Spread does not affect timing; it only controls how thick the highlight appears.
|
|
66
|
+
|
|
67
|
+
When `shimmer-bg` is used inside a `shimmer-container`, the plugin derives `--shimmer-speed` automatically from the container width so that each shimmer pass takes roughly 1.1–1.6 seconds, depending on container size. Smaller containers run slightly faster, larger containers slightly slower, which feels more consistent than a perfectly flat duration. Text shimmer in containers uses a slightly slower multiplier (~2.2–3.2 second passes) for a more subtle effect. You can still override this by setting `--shimmer-speed` (or using `shimmer-speed-{value}`) on any ancestor or the element itself.
|
|
43
68
|
|
|
44
69
|
```html
|
|
45
70
|
<span class="shimmer shimmer-speed-200 text-foreground/40">Fast (200px/s)</span>
|
|
46
71
|
```
|
|
47
72
|
|
|
48
|
-
###
|
|
73
|
+
### `shimmer-width-{value}`
|
|
74
|
+
|
|
75
|
+
Container width in pixels for animation timing. Default: `200`px for text shimmer, `800`px for background shimmer.
|
|
49
76
|
|
|
50
|
-
|
|
77
|
+
`--shimmer-width` is inheritable:
|
|
51
78
|
|
|
52
|
-
|
|
79
|
+
- If you set `--shimmer-width` (or use `shimmer-width-{value}`) on a parent container, both `shimmer` and `shimmer-bg` children will use that value unless they override it.
|
|
80
|
+
- If no value is set anywhere, text shimmer falls back to `200` and background shimmer falls back to `800`.
|
|
81
|
+
|
|
82
|
+
Set this to match your container width for consistent animation speed across different element sizes.
|
|
83
|
+
|
|
84
|
+
When used inside `shimmer-container`, the plugin sets an auto track width based on the container's width; this auto value is used only if you haven't explicitly set `--shimmer-width` yourself. Any explicit `--shimmer-width` (or `shimmer-width-{value}`) still wins and will be used to compute timing.
|
|
53
85
|
|
|
54
86
|
```tsx
|
|
55
|
-
<span class="shimmer
|
|
87
|
+
<span class="shimmer shimmer-width-300 text-foreground/40">Wide container</span>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Or set via CSS variable at runtime:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<span class="shimmer" style={{ ["--shimmer-width" as string]: "300" }}>
|
|
56
94
|
Wide container
|
|
57
95
|
</span>
|
|
58
96
|
```
|
|
59
97
|
|
|
60
|
-
|
|
98
|
+
#### CSS-only Auto-Width with `shimmer-container`
|
|
99
|
+
|
|
100
|
+
In modern browsers that support CSS container queries and container units (Chrome 111+, Safari 16.4+, Firefox 110+), you can use the `shimmer-container` helper class to automatically set `--shimmer-width` based on the container's width:
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<div class="shimmer-container flex gap-3">
|
|
104
|
+
<div class="shimmer-bg bg-muted size-10 rounded-full" />
|
|
105
|
+
<div class="flex-1 space-y-2">
|
|
106
|
+
<div class="shimmer-bg bg-muted h-4 w-24 rounded" />
|
|
107
|
+
<div class="shimmer-bg bg-muted h-4 w-full rounded" />
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Inside `shimmer-container`, tw-shimmer automatically:
|
|
113
|
+
|
|
114
|
+
- Sets the shimmer track width based on the container width (`--shimmer-width` auto).
|
|
115
|
+
- Derives the animation speed from the container width so that one shimmer pass takes roughly 1.1–1.6 seconds, depending on container size. Small containers feel snappier, larger containers a bit slower, while keeping the motion perceptually consistent.
|
|
116
|
+
- For `shimmer-bg`, adjusts the highlight spread based on the container width, clamping it between a sensible minimum (about 200px, or the track width if smaller) and maximum (about 300px) so it looks good at any size.
|
|
117
|
+
|
|
118
|
+
These container-based values act as smart defaults. Any explicit `--shimmer-width`, `--shimmer-speed`, or `--shimmer-bg-spread` that you set (for example via `shimmer-width-*`, `shimmer-speed-*`, or `shimmer-bg-spread-*`) will override them, even inside `shimmer-container`.
|
|
119
|
+
|
|
120
|
+
This is primarily useful for **skeleton/background shimmer layouts** where the container already has a stable width defined by its parent or layout context.
|
|
121
|
+
|
|
122
|
+
> **Note:** `shimmer-container` sets `container-type: inline-size`, which prevents the container from sizing based on its contents. This means it's **not recommended for text-only containers** that rely on shrink-to-fit behavior. For those cases, continue using JS or the `shimmer-width-*` utility.
|
|
123
|
+
|
|
124
|
+
In older browsers, `shimmer-container` has no effect and shimmers fall back to their default widths or manually configured values.
|
|
61
125
|
|
|
62
126
|
### `shimmer-color-{color}`
|
|
63
127
|
|
|
64
|
-
Shimmer highlight color. Default: `
|
|
128
|
+
Shimmer highlight color. Default: `black` for text (white in dark mode), `white` for bg.
|
|
65
129
|
|
|
66
|
-
|
|
130
|
+
`--shimmer-color` is shared and inheritable:
|
|
131
|
+
|
|
132
|
+
- If you set `--shimmer-color` (or use `shimmer-color-{color}`) on a parent container, any `shimmer` or `shimmer-bg` elements inside will use that color unless they define their own.
|
|
133
|
+
- If no value is set anywhere, text shimmer falls back to black in light mode (and white in dark mode), and background shimmer falls back to white (with a subtler default in dark mode).
|
|
134
|
+
|
|
135
|
+
Uses the Tailwind color palette.
|
|
67
136
|
|
|
68
137
|
```html
|
|
69
138
|
<span class="shimmer shimmer-color-blue-500 text-blue-500/40"
|
|
@@ -73,9 +142,14 @@ Uses Tailwind color palette.
|
|
|
73
142
|
|
|
74
143
|
### `shimmer-spread-{spacing}`
|
|
75
144
|
|
|
76
|
-
Width of the shimmer highlight. Default: `6`ch.
|
|
145
|
+
Width of the shimmer highlight for text shimmer. Default: `6`ch.
|
|
146
|
+
|
|
147
|
+
`--shimmer-spread` is inheritable:
|
|
148
|
+
|
|
149
|
+
- If you set `--shimmer-spread` (or use `shimmer-spread-{spacing}`) on a parent container, any `shimmer` elements inside will use that value unless they override it.
|
|
150
|
+
- If no value is set anywhere, text shimmer falls back to `6ch`.
|
|
77
151
|
|
|
78
|
-
Uses Tailwind spacing scale.
|
|
152
|
+
Uses the Tailwind spacing scale.
|
|
79
153
|
|
|
80
154
|
```html
|
|
81
155
|
<span class="shimmer shimmer-spread-24 text-foreground/40">Wide highlight</span>
|
|
@@ -83,7 +157,14 @@ Uses Tailwind spacing scale.
|
|
|
83
157
|
|
|
84
158
|
### `shimmer-angle-{degrees}`
|
|
85
159
|
|
|
86
|
-
Shimmer direction. Default: `90`deg.
|
|
160
|
+
Shimmer direction. Default: `90`deg. Shared with `shimmer-bg`.
|
|
161
|
+
|
|
162
|
+
`--shimmer-angle` is inheritable:
|
|
163
|
+
|
|
164
|
+
- If you set `--shimmer-angle` (or use `shimmer-angle-{degrees}`) on a parent container, any `shimmer` or `shimmer-bg` elements inside will use that angle unless they define their own.
|
|
165
|
+
- If no value is set anywhere, both text and background shimmer fall back to `90deg`.
|
|
166
|
+
|
|
167
|
+
> **Note on angle values:** Avoid exactly `0deg` and `180deg`, as these create extreme values in the animation delay formula (which uses tangent). For diagonal sweeps, use angles in a "safe" range such as 15–75° or 105–165°. Extreme angles can cause very large delays and may visually desync the animation.
|
|
87
168
|
|
|
88
169
|
```html
|
|
89
170
|
<span class="shimmer shimmer-angle-45 text-foreground/40"
|
|
@@ -91,6 +172,165 @@ Shimmer direction. Default: `90`deg.
|
|
|
91
172
|
>
|
|
92
173
|
```
|
|
93
174
|
|
|
175
|
+
## Background Shimmer (Skeletons)
|
|
176
|
+
|
|
177
|
+
For skeleton loaders and non-text elements, use `shimmer-bg` instead:
|
|
178
|
+
|
|
179
|
+
### `shimmer-bg`
|
|
180
|
+
|
|
181
|
+
Background shimmer for skeleton loaders and non-text elements. Use standard Tailwind `bg-*` for base color. Standalone default: 800px width, 1000px/s speed.
|
|
182
|
+
|
|
183
|
+
```html
|
|
184
|
+
<div class="shimmer-bg bg-muted h-4 w-48 rounded" />
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Skeleton Example
|
|
188
|
+
|
|
189
|
+
To sync shimmer timing across all skeleton children, you have two options:
|
|
190
|
+
|
|
191
|
+
**Option 1: CSS-only with `shimmer-container` (recommended for modern browsers)**
|
|
192
|
+
|
|
193
|
+
Wrap skeleton elements in `shimmer-container` for consistent timing. The container auto-derives speed so each pass takes roughly 1.1–1.6 seconds depending on width, and clamps the highlight spread to a width-aware band (roughly 200–300px, or the track width if smaller). All `shimmer-bg` children sync to the same animation. Older browsers fall back to standalone defaults.
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<div class="shimmer-container flex gap-3">
|
|
197
|
+
<div class="shimmer-bg bg-muted size-10 rounded-full" />
|
|
198
|
+
<div class="flex-1 space-y-2">
|
|
199
|
+
<div class="shimmer-bg bg-muted h-4 w-24 rounded" />
|
|
200
|
+
<div class="shimmer-bg bg-muted h-4 w-full rounded" />
|
|
201
|
+
<div class="shimmer-bg bg-muted h-4 w-4/5 rounded" />
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Option 2: Manual width with CSS variable or JS**
|
|
207
|
+
|
|
208
|
+
Set `--shimmer-width` on the container manually. Any `shimmer-bg` or `shimmer` elements inside will inherit this width unless they define their own `shimmer-width-{value}`:
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
<div class="flex gap-3" style={{ ["--shimmer-width" as string]: "600" }}>
|
|
212
|
+
<div class="shimmer-bg bg-muted size-10 rounded-full" />
|
|
213
|
+
<div class="flex-1 space-y-2">
|
|
214
|
+
<div class="shimmer-bg bg-muted h-4 w-24 rounded" />
|
|
215
|
+
<div class="shimmer-bg bg-muted h-4 w-full rounded" />
|
|
216
|
+
<div class="shimmer-bg bg-muted h-4 w-4/5 rounded" />
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
You can also set `--shimmer-speed`, `--shimmer-angle`, and `--shimmer-color` on the same container to keep both text shimmer and background shimmer moving in the same direction, at the same speed, and with the same highlight color. You can also use `shimmer-bg-spread-*` or set `--shimmer-bg-spread` on the container (or individual skeleton elements) to override the container's auto spread and manually control the background highlight band width.
|
|
222
|
+
|
|
223
|
+
### `shimmer-color-{color}` (with shimmer-bg)
|
|
224
|
+
|
|
225
|
+
The same `shimmer-color-*` utility works for both text and bg shimmer:
|
|
226
|
+
|
|
227
|
+
```html
|
|
228
|
+
<div class="shimmer-bg shimmer-color-blue-100 h-4 w-48 rounded bg-blue-300" />
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Angled Skeleton Shimmer
|
|
232
|
+
|
|
233
|
+
Use `shimmer-angle-{degrees}` (shared with text shimmer) for diagonal sweeps. This works with both `shimmer-container` and manual width configuration:
|
|
234
|
+
|
|
235
|
+
```html
|
|
236
|
+
<div class="shimmer-container shimmer-angle-15 flex gap-3">
|
|
237
|
+
<div class="shimmer-bg bg-muted size-10 rounded-full" />
|
|
238
|
+
<div class="shimmer-bg bg-muted h-4 w-full rounded" />
|
|
239
|
+
</div>
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Advanced: Position-Based Sync
|
|
243
|
+
|
|
244
|
+
> **Note:** These utilities are **optional** and only relevant for angled shimmers (`shimmer-angle-*` ≠ 90°). Most users can skip this section.
|
|
245
|
+
|
|
246
|
+
### `shimmer-x-{value}` / `shimmer-y-{value}`
|
|
247
|
+
|
|
248
|
+
Manual position hints for syncing angled shimmer animations across multiple elements. When using diagonal shimmers on layouts with multiple skeleton elements (e.g., avatar + text lines), the highlights may appear slightly out of sync because each element animates independently.
|
|
249
|
+
|
|
250
|
+
These utilities let you specify each element's approximate position (in pixels) relative to a shared container. The plugin uses these values to calculate animation delays, aligning the diagonal sweep across elements.
|
|
251
|
+
|
|
252
|
+
- `shimmer-x-*`: Horizontal offset from container left (unitless, interpreted as pixels)
|
|
253
|
+
- `shimmer-y-*`: Vertical offset from container top (unitless, interpreted as pixels)
|
|
254
|
+
|
|
255
|
+
**How it works:** The x/y values feed into an animation-delay formula that accounts for the shimmer angle. This creates the illusion of a single diagonal highlight passing through all elements.
|
|
256
|
+
|
|
257
|
+
> **Tip:** For larger or rounded elements (like avatars), use the element's approximate center rather than its top-left corner. The sync math treats each element as a single reference point, so using the center better matches where the shimmer visually "passes through" the element. Finding good offsets may still require some trial and error.
|
|
258
|
+
>
|
|
259
|
+
> For example, a 40×40 avatar at the left edge of the container would often look better with `shimmer-x-20 shimmer-y-20` than `shimmer-x-0 shimmer-y-0`.
|
|
260
|
+
|
|
261
|
+
> **Angle caveat:** Position sync works best with moderate angles (15–75° or 105–165°). Avoid exactly 0° and 180° as these cause extreme delay values. See the `shimmer-angle-*` section for details.
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<div class="shimmer-container shimmer-angle-15">
|
|
265
|
+
<div
|
|
266
|
+
class="shimmer-bg shimmer-x-20 shimmer-y-20 bg-muted size-10 rounded-full"
|
|
267
|
+
/>
|
|
268
|
+
<div class="shimmer-bg shimmer-x-52 shimmer-y-0 bg-muted h-4 w-24 rounded" />
|
|
269
|
+
<div
|
|
270
|
+
class="shimmer-bg shimmer-x-52 shimmer-y-24 bg-muted h-4 w-full rounded"
|
|
271
|
+
/>
|
|
272
|
+
</div>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Advanced: Offscreen Overshoot (background shimmer)
|
|
276
|
+
|
|
277
|
+
For angled background shimmers (`shimmer-bg` with `shimmer-angle-*`), the plugin automatically adjusts how far the shimmer stripe starts and ends off-screen based on the angle. This helps avoid the highlight being visible at the left edge at the very start of the animation, especially at shallow angles (e.g. 15–30°).
|
|
278
|
+
|
|
279
|
+
Internally, this uses an angle-aware overshoot multiplier:
|
|
280
|
+
|
|
281
|
+
- Steep angles (~90°) → multiplier ≈ 1 (no extra overshoot)
|
|
282
|
+
- Moderate angles (e.g. 45°) → multiplier ≈ 1.3
|
|
283
|
+
- Shallow angles (e.g. 15° or 165°) → multiplier up to ≈ 3 (clamped)
|
|
284
|
+
|
|
285
|
+
You can override this behavior per element or per container using the CSS variable:
|
|
286
|
+
|
|
287
|
+
```css
|
|
288
|
+
--shimmer-offscreen-multiplier: 1.5; /* or any positive value */
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
For example:
|
|
292
|
+
|
|
293
|
+
```html
|
|
294
|
+
<div
|
|
295
|
+
class="shimmer-container"
|
|
296
|
+
style="--shimmer-angle: 20deg; --shimmer-offscreen-multiplier: 2;"
|
|
297
|
+
>
|
|
298
|
+
<div class="shimmer-bg bg-muted h-4 w-full rounded"></div>
|
|
299
|
+
</div>
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Most users never need to set this manually; it exists for power users who are tuning very shallow angles or unusual aspect ratios.
|
|
303
|
+
|
|
304
|
+
## Browser Support & Accessibility
|
|
305
|
+
|
|
306
|
+
### Modern CSS Requirements
|
|
307
|
+
|
|
308
|
+
`tw-shimmer` uses modern CSS features for the best visual quality:
|
|
309
|
+
|
|
310
|
+
- `oklch` and `color-mix` for perceptually uniform color mixing
|
|
311
|
+
- `translate` as an independent transform property
|
|
312
|
+
- `overflow: clip` for precise clipping (with `overflow: hidden` fallback)
|
|
313
|
+
|
|
314
|
+
These features are supported in all modern browsers (Chrome 111+, Firefox 113+, Safari 16.4+). Older browsers will degrade gracefully but may not render the full effect.
|
|
315
|
+
|
|
316
|
+
## Limitations
|
|
317
|
+
|
|
318
|
+
`tw-shimmer` is intentionally **zero-dependency and CSS-only**. This keeps it lightweight and framework-agnostic, but it comes with trade-offs:
|
|
319
|
+
|
|
320
|
+
- **`shimmer-container` auto-width/auto-speed/auto-spread are progressive enhancements:** The `shimmer-container` helper uses modern CSS container units (`cqw`) and is gated by `@supports (width: 1cqw)`. In unsupported browsers, `shimmer-container` has no effect and shimmer elements fall back to their default widths or manually configured values.
|
|
321
|
+
|
|
322
|
+
- **`shimmer-container` prevents shrink-to-fit sizing:** Because it sets `container-type: inline-size`, the container cannot size itself based on its contents. This makes it unsuitable for text-only containers that rely on intrinsic sizing.
|
|
323
|
+
|
|
324
|
+
- **No automatic layout detection:** CSS cannot access runtime element positions, so perfectly unified diagonal shimmer across arbitrarily positioned elements cannot be fully automated.
|
|
325
|
+
|
|
326
|
+
- **Vertical shimmers just work:** For `shimmer-angle-90` (the default), all elements naturally sync without any extra configuration.
|
|
327
|
+
|
|
328
|
+
- **Angled shimmers are best-effort:** The `shimmer-x-*` / `shimmer-y-*` utilities enable manual sync tuning, but some minor desync or visual artifacts may still occur—especially at shallow angles or with large rounded shapes.
|
|
329
|
+
|
|
330
|
+
- **Complex layouts may need JavaScript:** If your application requires truly "physically correct" shimmer alignment across a complex layout, that would require measuring element positions at runtime and setting CSS variables via JavaScript. `tw-shimmer` intentionally does not do this.
|
|
331
|
+
|
|
332
|
+
For most skeleton loaders and text shimmer use cases, the defaults work well. The advanced position utilities are there for power users who want fine-grained control over angled animations.
|
|
333
|
+
|
|
94
334
|
## License
|
|
95
335
|
|
|
96
336
|
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tw-shimmer",
|
|
3
3
|
"description": "Tailwind CSS v4 plugin for shimmer effects",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -14,7 +14,18 @@
|
|
|
14
14
|
"src",
|
|
15
15
|
"README.md"
|
|
16
16
|
],
|
|
17
|
-
"sideEffects":
|
|
17
|
+
"sideEffects": [
|
|
18
|
+
"./src/index.css"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"tailwindcss",
|
|
22
|
+
"tailwind",
|
|
23
|
+
"shimmer",
|
|
24
|
+
"skeleton",
|
|
25
|
+
"loading",
|
|
26
|
+
"animation",
|
|
27
|
+
"css"
|
|
28
|
+
],
|
|
18
29
|
"publishConfig": {
|
|
19
30
|
"access": "public",
|
|
20
31
|
"provenance": true
|
|
@@ -26,5 +37,8 @@
|
|
|
26
37
|
},
|
|
27
38
|
"bugs": {
|
|
28
39
|
"url": "https://github.com/assistant-ui/assistant-ui/issues"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"tailwindcss": ">=4.0.0-0"
|
|
29
43
|
}
|
|
30
44
|
}
|
package/src/index.css
CHANGED
|
@@ -1,53 +1,155 @@
|
|
|
1
|
+
@property --shimmer-track-height {
|
|
2
|
+
syntax: '<length>';
|
|
3
|
+
inherits: true;
|
|
4
|
+
initial-value: 200px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@property --shimmer-angle {
|
|
8
|
+
syntax: '<angle>';
|
|
9
|
+
inherits: true;
|
|
10
|
+
initial-value: 15deg;
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
@theme inline {
|
|
2
|
-
@keyframes shimmer {
|
|
3
|
-
|
|
4
|
-
background-position:
|
|
5
|
-
}
|
|
6
|
-
100% {
|
|
7
|
-
background-position: -50% 0;
|
|
14
|
+
@keyframes tw-shimmer {
|
|
15
|
+
from {
|
|
16
|
+
background-position: 100% 0;
|
|
8
17
|
}
|
|
9
18
|
}
|
|
10
19
|
}
|
|
11
20
|
|
|
12
21
|
@utility shimmer {
|
|
13
|
-
--
|
|
14
|
-
--shimmer-width-
|
|
15
|
-
--shimmer-
|
|
16
|
-
--
|
|
17
|
-
--
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
--_gradient-width: calc(var(--_spread) + var(--shimmer-track-height) * tan(var(--shimmer-angle)));
|
|
23
|
+
--_active-distance: calc(var(--shimmer-track-width, 200px) + var(--_gradient-width));
|
|
24
|
+
--_duration: var(--shimmer-duration, calc(var(--_active-distance) / var(--_speed) / 1px * 1000));
|
|
25
|
+
--_repeat-delay: var(--shimmer-repeat-delay, calc(20000 / var(--_speed)));
|
|
26
|
+
--_repeat-delay-px: calc(var(--_repeat-delay) * var(--_active-distance) / var(--_duration));
|
|
27
|
+
--_xy-offset-px: calc((var(--shimmer-x, 0) + var(--shimmer-y, 0) * tan(var(--shimmer-angle))) * 1px);
|
|
28
|
+
|
|
29
|
+
--_bg-width: calc(
|
|
30
|
+
100% +
|
|
31
|
+
var(--shimmer-track-width, 100%) +
|
|
32
|
+
var(--_gradient-width) +
|
|
33
|
+
var(--_repeat-delay-px)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
--_position: calc(
|
|
37
|
+
var(--shimmer-track-width, (100% - var(--_gradient-width) - var(--_repeat-delay-px)) / 2)
|
|
38
|
+
+ var(--_gradient-width) / 2
|
|
39
|
+
+ var(--_repeat-delay-px)
|
|
40
|
+
- var(--_xy-offset-px)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
&:not(.shimmer-bg) {
|
|
44
|
+
--_speed: var(--shimmer-speed, 200);
|
|
45
|
+
--_spread: var(--shimmer-spread, calc(4ch + 80px));
|
|
46
|
+
--_bg: currentColor;
|
|
47
|
+
--_fg: var(--shimmer-color, oklch(from currentColor l c h / calc(alpha * 0.2)));
|
|
48
|
+
|
|
49
|
+
background-clip: text;
|
|
50
|
+
-webkit-text-fill-color: transparent;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&.shimmer-bg {
|
|
54
|
+
--_speed: var(--shimmer-speed, 1000);
|
|
55
|
+
--_spread: var(--shimmer-spread, 480px);
|
|
56
|
+
--_bg: transparent;
|
|
57
|
+
--_fg: var(--shimmer-color, oklch(from currentColor 0 c h / 0.06));
|
|
58
|
+
}
|
|
33
59
|
|
|
34
60
|
@variant dark {
|
|
35
|
-
|
|
61
|
+
&:not(.shimmer-bg) {
|
|
62
|
+
--_fg: var(--shimmer-color, oklch(from currentColor max(0.8, calc(l + 0.4)) c h / calc(alpha + 0.4)));
|
|
63
|
+
}
|
|
64
|
+
&.shimmer-bg {
|
|
65
|
+
--_fg: var(--shimmer-color, oklch(from currentColor 0 c h / 0.30));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@-moz-document url-prefix() {
|
|
70
|
+
& {
|
|
71
|
+
--_duration: var(--shimmer-duration, calc(375000 / var(--_speed)));
|
|
72
|
+
}
|
|
36
73
|
}
|
|
74
|
+
|
|
75
|
+
/* Use a sine ease-in-out curve (17 stops) for smooth falloff */
|
|
76
|
+
--_mix-96: color-mix(in oklch, var(--_fg), var(--_bg) 96%);
|
|
77
|
+
--_mix-83: color-mix(in oklch, var(--_fg), var(--_bg) 83%);
|
|
78
|
+
--_mix-67: color-mix(in oklch, var(--_fg), var(--_bg) 67%);
|
|
79
|
+
--_mix-50: color-mix(in oklch, var(--_fg), var(--_bg) 50%);
|
|
80
|
+
--_mix-33: color-mix(in oklch, var(--_fg), var(--_bg) 33%);
|
|
81
|
+
--_mix-17: color-mix(in oklch, var(--_fg), var(--_bg) 17%);
|
|
82
|
+
--_mix-4: color-mix(in oklch, var(--_fg), var(--_bg) 4%);
|
|
83
|
+
|
|
84
|
+
background:
|
|
85
|
+
linear-gradient(
|
|
86
|
+
calc(90deg + var(--shimmer-angle)),
|
|
87
|
+
var(--_bg) calc(var(--_position) - var(--_spread) * 0.5),
|
|
88
|
+
var(--_mix-96) calc(var(--_position) - var(--_spread) * 0.44),
|
|
89
|
+
var(--_mix-83) calc(var(--_position) - var(--_spread) * 0.37),
|
|
90
|
+
var(--_mix-67) calc(var(--_position) - var(--_spread) * 0.31),
|
|
91
|
+
var(--_mix-50) calc(var(--_position) - var(--_spread) * 0.25),
|
|
92
|
+
var(--_mix-33) calc(var(--_position) - var(--_spread) * 0.19),
|
|
93
|
+
var(--_mix-17) calc(var(--_position) - var(--_spread) * 0.12),
|
|
94
|
+
var(--_mix-4) calc(var(--_position) - var(--_spread) * 0.06),
|
|
95
|
+
var(--_fg) var(--_position),
|
|
96
|
+
var(--_mix-4) calc(var(--_position) + var(--_spread) * 0.06),
|
|
97
|
+
var(--_mix-17) calc(var(--_position) + var(--_spread) * 0.12),
|
|
98
|
+
var(--_mix-33) calc(var(--_position) + var(--_spread) * 0.19),
|
|
99
|
+
var(--_mix-50) calc(var(--_position) + var(--_spread) * 0.25),
|
|
100
|
+
var(--_mix-67) calc(var(--_position) + var(--_spread) * 0.31),
|
|
101
|
+
var(--_mix-83) calc(var(--_position) + var(--_spread) * 0.37),
|
|
102
|
+
var(--_mix-96) calc(var(--_position) + var(--_spread) * 0.44),
|
|
103
|
+
var(--_bg) calc(var(--_position) + var(--_spread) * 0.5)
|
|
104
|
+
)
|
|
105
|
+
0 0 / var(--_bg-width) 100%
|
|
106
|
+
no-repeat;
|
|
107
|
+
|
|
108
|
+
animation: tw-shimmer 1s linear 0s infinite backwards;
|
|
109
|
+
animation-duration: calc((var(--_duration) + var(--_repeat-delay)) * 1ms);
|
|
37
110
|
}
|
|
38
111
|
|
|
39
112
|
@utility shimmer-speed-* {
|
|
40
113
|
--shimmer-speed: --value(number);
|
|
41
114
|
}
|
|
42
115
|
|
|
116
|
+
@utility shimmer-duration-* {
|
|
117
|
+
--shimmer-duration: --value(integer);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@utility shimmer-repeat-delay-* {
|
|
121
|
+
--shimmer-repeat-delay: --value(integer);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@utility shimmer-invert {
|
|
125
|
+
&:not(.shimmer-bg) {
|
|
126
|
+
--shimmer-color: oklch(from currentColor min(calc(l - 0.4), 0.2) c h / calc(alpha + 0.4));
|
|
127
|
+
|
|
128
|
+
@variant dark {
|
|
129
|
+
--shimmer-color: oklch(from currentColor l c h / calc(alpha * 0.2));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
43
134
|
@utility shimmer-color-* {
|
|
44
|
-
--
|
|
135
|
+
--alpha: 100%;
|
|
136
|
+
--alpha: calc(--modifier(integer) * 1%);
|
|
137
|
+
--shimmer-color: --alpha(--value(--color, [color]) / var(--alpha, 100%));
|
|
45
138
|
}
|
|
46
139
|
|
|
47
140
|
@utility shimmer-spread-* {
|
|
48
|
-
--shimmer-spread:
|
|
141
|
+
--shimmer-spread: calc(--value(integer) * 1px);
|
|
49
142
|
}
|
|
50
143
|
|
|
51
144
|
@utility shimmer-angle-* {
|
|
52
|
-
--shimmer-angle: calc(--value(
|
|
145
|
+
--shimmer-angle: calc(--value(integer) * 1deg);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@utility shimmer-container {
|
|
149
|
+
container-type: inline-size;
|
|
150
|
+
|
|
151
|
+
& .shimmer {
|
|
152
|
+
--shimmer-track-width: 100cqw;
|
|
153
|
+
--shimmer-track-height: max(100cqh, 50cqw, 200px);
|
|
154
|
+
}
|
|
53
155
|
}
|