@flux-ui/visuals 0.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 +32 -0
- package/dist/component/FluxVisualAnimatedColors.vue.d.ts +10 -0
- package/dist/component/FluxVisualAttention.vue.d.ts +40 -0
- package/dist/component/FluxVisualBorderBeam.vue.d.ts +31 -0
- package/dist/component/FluxVisualBorderShine.vue.d.ts +53 -0
- package/dist/component/FluxVisualDotPattern.vue.d.ts +11 -0
- package/dist/component/FluxVisualFlickeringGrid.vue.d.ts +10 -0
- package/dist/component/FluxVisualGridPattern.vue.d.ts +10 -0
- package/dist/component/FluxVisualHighlighter.vue.d.ts +36 -0
- package/dist/component/FluxVisualHighlighterGroup.vue.d.ts +13 -0
- package/dist/component/FluxVisualNoise.vue.d.ts +9 -0
- package/dist/component/FluxVisualNumberFlow.vue.d.ts +14 -0
- package/dist/component/FluxVisualPing.vue.d.ts +8 -0
- package/dist/component/FluxVisualSlotText.vue.d.ts +41 -0
- package/dist/component/FluxVisualTextScramble.vue.d.ts +20 -0
- package/dist/component/FluxVisualTextShimmer.vue.d.ts +18 -0
- package/dist/component/index.d.ts +15 -0
- package/dist/composable/private/index.d.ts +2 -0
- package/dist/composable/private/useBorderBeamPulse.d.ts +21 -0
- package/dist/composable/private/useHighlighterGroup.d.ts +51 -0
- package/dist/index.css +1110 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12320 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +13 -0
- package/package.json +71 -0
- package/src/component/FluxVisualAnimatedColors.vue +187 -0
- package/src/component/FluxVisualAttention.vue +86 -0
- package/src/component/FluxVisualBorderBeam.vue +171 -0
- package/src/component/FluxVisualBorderShine.vue +36 -0
- package/src/component/FluxVisualDotPattern.vue +119 -0
- package/src/component/FluxVisualFlickeringGrid.vue +159 -0
- package/src/component/FluxVisualGridPattern.vue +128 -0
- package/src/component/FluxVisualHighlighter.vue +217 -0
- package/src/component/FluxVisualHighlighterGroup.vue +20 -0
- package/src/component/FluxVisualNoise.vue +31 -0
- package/src/component/FluxVisualNumberFlow.vue +235 -0
- package/src/component/FluxVisualPing.vue +26 -0
- package/src/component/FluxVisualSlotText.vue +457 -0
- package/src/component/FluxVisualTextScramble.vue +168 -0
- package/src/component/FluxVisualTextShimmer.vue +34 -0
- package/src/component/index.ts +15 -0
- package/src/composable/private/index.ts +2 -0
- package/src/composable/private/useBorderBeamPulse.ts +203 -0
- package/src/composable/private/useHighlighterGroup.ts +162 -0
- package/src/css/component/Attention.module.scss +104 -0
- package/src/css/component/BorderBeam.module.scss +1178 -0
- package/src/css/component/Highlighter.module.scss +7 -0
- package/src/css/component/Noise.module.scss +80 -0
- package/src/css/component/NumberFlow.module.scss +5 -0
- package/src/css/component/PatternGlow.module.scss +19 -0
- package/src/css/component/Ping.module.scss +44 -0
- package/src/css/component/SlotText.module.scss +43 -0
- package/src/css/component/TextScramble.module.scss +5 -0
- package/src/css/component/TextShimmer.module.scss +54 -0
- package/src/css/component/Visual.module.scss +71 -0
- package/src/index.ts +1 -0
- package/src/types.d.ts +13 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
.noise {
|
|
2
|
+
position: absolute;
|
|
3
|
+
inset: 0;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
pointer-events: none;
|
|
7
|
+
opacity: var(--noise-opacity, .05);
|
|
8
|
+
// Raw feTurbulence emits four independent noise channels, so the alpha is
|
|
9
|
+
// also noise and the grain is a faint, half-transparent colored static that
|
|
10
|
+
// washes out to nothing under a low opacity. The filter runs in sRGB (so the
|
|
11
|
+
// grain stays centered on mid-grey instead of being gamma-lifted toward
|
|
12
|
+
// white), collapses to a single opaque grey channel and boosts its contrast,
|
|
13
|
+
// giving a neutral film grain that reads clearly even at a few percent.
|
|
14
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.8' intercept='-0.4'/%3E%3CfeFuncG type='linear' slope='1.8' intercept='-0.4'/%3E%3CfeFuncB type='linear' slope='1.8' intercept='-0.4'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
15
|
+
background-repeat: repeat;
|
|
16
|
+
mix-blend-mode: var(--noise-blend, overlay);
|
|
17
|
+
|
|
18
|
+
// The overlay blend has little to bite into on a dark surface, so the grain
|
|
19
|
+
// is lifted to stay perceptible.
|
|
20
|
+
[dark] & {
|
|
21
|
+
opacity: calc(var(--noise-opacity, .05) * 1.5);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.animated {
|
|
26
|
+
animation: fluxVisualNoiseShift .6s steps(1) infinite;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Discrete position jumps read as film grain without a per-frame script.
|
|
30
|
+
@keyframes fluxVisualNoiseShift {
|
|
31
|
+
0% {
|
|
32
|
+
background-position: 0 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
10% {
|
|
36
|
+
background-position: -12px 6px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
20% {
|
|
40
|
+
background-position: 10px -14px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
30% {
|
|
44
|
+
background-position: -6px 12px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
40% {
|
|
48
|
+
background-position: 14px 4px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
50% {
|
|
52
|
+
background-position: -14px -8px;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
60% {
|
|
56
|
+
background-position: 8px 14px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
70% {
|
|
60
|
+
background-position: -10px -12px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
80% {
|
|
64
|
+
background-position: 12px 8px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
90% {
|
|
68
|
+
background-position: -4px -14px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
100% {
|
|
72
|
+
background-position: 0 0;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media (prefers-reduced-motion: reduce) {
|
|
77
|
+
.animated {
|
|
78
|
+
animation: none;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.glowLayer {
|
|
2
|
+
transition: opacity .25s ease;
|
|
3
|
+
pointer-events: none;
|
|
4
|
+
opacity: 0;
|
|
5
|
+
-webkit-mask: radial-gradient(circle var(--pattern-glow-size, 120px) at var(--pattern-glow-x, 50%) var(--pattern-glow-y, 50%), #000 0%, transparent 100%);
|
|
6
|
+
mask: radial-gradient(circle var(--pattern-glow-size, 120px) at var(--pattern-glow-x, 50%) var(--pattern-glow-y, 50%), #000 0%, transparent 100%);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.isActive {
|
|
10
|
+
opacity: 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.glowDot {
|
|
14
|
+
fill: var(--primary-500);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.glowLine {
|
|
18
|
+
stroke: var(--primary-500);
|
|
19
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.ping {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
width: var(--ping-size);
|
|
5
|
+
height: var(--ping-size);
|
|
6
|
+
pointer-events: none;
|
|
7
|
+
color: var(--ping-color);
|
|
8
|
+
border-radius: 50%;
|
|
9
|
+
background: currentColor;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.ping::before,
|
|
13
|
+
.ping::after {
|
|
14
|
+
position: absolute;
|
|
15
|
+
inset: 0;
|
|
16
|
+
content: '';
|
|
17
|
+
animation: visualPing calc(var(--ping-duration) * 1s) cubic-bezier(0, 0, .2, 1) infinite;
|
|
18
|
+
border-radius: 50%;
|
|
19
|
+
background: currentColor;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.ping::after {
|
|
23
|
+
animation-delay: calc(var(--ping-duration) * -.5s);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@media (prefers-reduced-motion: reduce) {
|
|
27
|
+
.ping::before,
|
|
28
|
+
.ping::after {
|
|
29
|
+
content: none;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@keyframes visualPing {
|
|
34
|
+
0% {
|
|
35
|
+
transform: scale(1);
|
|
36
|
+
opacity: .5;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
75%,
|
|
40
|
+
100% {
|
|
41
|
+
transform: scale(2.5);
|
|
42
|
+
opacity: 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.slotText {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
white-space: pre;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.charSlot {
|
|
7
|
+
line-height: 1.3;
|
|
8
|
+
position: relative;
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
// Clip only vertically: the roll needs a top/bottom mask, but glyph side
|
|
11
|
+
// bearings, kerning overhang and the settle tilt must stay visible so
|
|
12
|
+
// letters never look cropped.
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
overflow-x: visible;
|
|
15
|
+
overflow-y: clip;
|
|
16
|
+
// Cells must never flex-shrink, otherwise a width-constrained line crushes
|
|
17
|
+
// them into overlapping slivers instead of letting the row overflow.
|
|
18
|
+
flex: none;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
vertical-align: bottom;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Cells appearing from or collapsing to empty change width drastically, so clip
|
|
24
|
+
// them horizontally too while they resize — their glyph wipes in/out with the
|
|
25
|
+
// cell instead of spilling over the neighbours.
|
|
26
|
+
.charSlot.isResizing {
|
|
27
|
+
overflow-x: clip;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.charSizer {
|
|
31
|
+
visibility: hidden;
|
|
32
|
+
white-space: pre;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.charFace {
|
|
36
|
+
position: absolute;
|
|
37
|
+
inset: 0;
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
white-space: pre;
|
|
42
|
+
will-change: transform;
|
|
43
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.textShimmer {
|
|
2
|
+
display: inline-block;
|
|
3
|
+
animation: textShimmerSweep var(--shimmer-duration, 2s) linear infinite;
|
|
4
|
+
color: transparent;
|
|
5
|
+
background-image: linear-gradient(
|
|
6
|
+
90deg,
|
|
7
|
+
var(--shimmer-base, var(--gray-400)) calc(50% - var(--shimmer-spread, 15) * 1%),
|
|
8
|
+
var(--shimmer-color, var(--gray-950)) 50%,
|
|
9
|
+
var(--shimmer-base, var(--gray-400)) calc(50% + var(--shimmer-spread, 15) * 1%)
|
|
10
|
+
);
|
|
11
|
+
// Both edges of the gradient are the base color, so tiling it seamlessly
|
|
12
|
+
// keeps the text fully painted at every step: outside the moving highlight
|
|
13
|
+
// band the text is always covered by the base color instead of falling off
|
|
14
|
+
// the single tile into a transparent (clipped) gap. A no-repeat background
|
|
15
|
+
// only covers the text for background-position 0%..100%; past that the tile
|
|
16
|
+
// slides off and the text vanishes.
|
|
17
|
+
background-repeat: repeat;
|
|
18
|
+
background-position: 100% center;
|
|
19
|
+
background-clip: text;
|
|
20
|
+
background-size: 200% 100%;
|
|
21
|
+
-webkit-background-clip: text;
|
|
22
|
+
-webkit-text-fill-color: transparent;
|
|
23
|
+
|
|
24
|
+
[dark] & {
|
|
25
|
+
background-image: linear-gradient(
|
|
26
|
+
90deg,
|
|
27
|
+
var(--shimmer-base, var(--gray-500)) calc(50% - var(--shimmer-spread, 15) * 1%),
|
|
28
|
+
var(--shimmer-color, var(--gray-50)) 50%,
|
|
29
|
+
var(--shimmer-base, var(--gray-500)) calc(50% + var(--shimmer-spread, 15) * 1%)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// No sweep when reduced motion is requested: fall back to a plain, solid
|
|
34
|
+
// text color so the label stays legible without animating.
|
|
35
|
+
@media (prefers-reduced-motion: reduce) {
|
|
36
|
+
animation: none;
|
|
37
|
+
color: var(--shimmer-base, var(--gray-500));
|
|
38
|
+
background: none;
|
|
39
|
+
-webkit-text-fill-color: currentColor;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The 100% to -100% travel shifts the background by exactly one tile width
|
|
44
|
+
// (background-size is 200%), so the repeated pattern lands back on itself and
|
|
45
|
+
// the loop restarts without a jump.
|
|
46
|
+
@keyframes textShimmerSweep {
|
|
47
|
+
from {
|
|
48
|
+
background-position: 100% center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
to {
|
|
52
|
+
background-position: -100% center;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
@property --shine-degrees {
|
|
2
|
+
syntax: '<angle>';
|
|
3
|
+
initial-value: 0deg;
|
|
4
|
+
inherits: false;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.fillVisual {
|
|
8
|
+
position: absolute;
|
|
9
|
+
inset: 0;
|
|
10
|
+
width: 100%;
|
|
11
|
+
height: 100%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.animatedColors {
|
|
15
|
+
composes: fillVisual;
|
|
16
|
+
|
|
17
|
+
filter: blur(60px) saturate(180%);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.dotPattern {
|
|
21
|
+
composes: fillVisual;
|
|
22
|
+
|
|
23
|
+
fill: var(--gray-300);
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.flickeringGrid {
|
|
28
|
+
composes: fillVisual;
|
|
29
|
+
|
|
30
|
+
pointer-events: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.gridPattern {
|
|
34
|
+
composes: fillVisual;
|
|
35
|
+
|
|
36
|
+
fill: var(--gray-100);
|
|
37
|
+
stroke: var(--gray-300);
|
|
38
|
+
pointer-events: none;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.borderShine {
|
|
42
|
+
position: relative;
|
|
43
|
+
|
|
44
|
+
--shine-radius: var(--radius);
|
|
45
|
+
--shine-mask: linear-gradient(#fff #{0} #{0}) content-box, linear-gradient(#fff #{0} #{0});
|
|
46
|
+
|
|
47
|
+
&::before {
|
|
48
|
+
position: absolute;
|
|
49
|
+
display: block;
|
|
50
|
+
inset: calc(var(--shine-offset) * -1px);
|
|
51
|
+
padding: calc(var(--shine-width) * 1px);
|
|
52
|
+
content: '';
|
|
53
|
+
background: conic-gradient(from var(--shine-degrees), #{var(--shine-colors)});
|
|
54
|
+
border-radius: var(--shine-radius);
|
|
55
|
+
pointer-events: none;
|
|
56
|
+
animation: borderShinePosition calc(var(--shine-duration) * 1s) linear infinite;
|
|
57
|
+
mask: var(--shine-mask);
|
|
58
|
+
-webkit-mask-composite: xor;
|
|
59
|
+
mask-composite: exclude;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@keyframes borderShinePosition {
|
|
64
|
+
from {
|
|
65
|
+
--shine-degrees: 0deg;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
to {
|
|
69
|
+
--shine-degrees: 360deg;
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './component';
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare module '*.module.css' {
|
|
2
|
+
const content: Record<string, string>;
|
|
3
|
+
export default content;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
declare module '*.module.scss' {
|
|
7
|
+
const content: Record<string, string>;
|
|
8
|
+
export default content;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare module '*.svg' {
|
|
12
|
+
export = string;
|
|
13
|
+
}
|