@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.
Files changed (58) hide show
  1. package/README.md +32 -0
  2. package/dist/component/FluxVisualAnimatedColors.vue.d.ts +10 -0
  3. package/dist/component/FluxVisualAttention.vue.d.ts +40 -0
  4. package/dist/component/FluxVisualBorderBeam.vue.d.ts +31 -0
  5. package/dist/component/FluxVisualBorderShine.vue.d.ts +53 -0
  6. package/dist/component/FluxVisualDotPattern.vue.d.ts +11 -0
  7. package/dist/component/FluxVisualFlickeringGrid.vue.d.ts +10 -0
  8. package/dist/component/FluxVisualGridPattern.vue.d.ts +10 -0
  9. package/dist/component/FluxVisualHighlighter.vue.d.ts +36 -0
  10. package/dist/component/FluxVisualHighlighterGroup.vue.d.ts +13 -0
  11. package/dist/component/FluxVisualNoise.vue.d.ts +9 -0
  12. package/dist/component/FluxVisualNumberFlow.vue.d.ts +14 -0
  13. package/dist/component/FluxVisualPing.vue.d.ts +8 -0
  14. package/dist/component/FluxVisualSlotText.vue.d.ts +41 -0
  15. package/dist/component/FluxVisualTextScramble.vue.d.ts +20 -0
  16. package/dist/component/FluxVisualTextShimmer.vue.d.ts +18 -0
  17. package/dist/component/index.d.ts +15 -0
  18. package/dist/composable/private/index.d.ts +2 -0
  19. package/dist/composable/private/useBorderBeamPulse.d.ts +21 -0
  20. package/dist/composable/private/useHighlighterGroup.d.ts +51 -0
  21. package/dist/index.css +1110 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.js +12320 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/types.d.ts +13 -0
  26. package/package.json +71 -0
  27. package/src/component/FluxVisualAnimatedColors.vue +187 -0
  28. package/src/component/FluxVisualAttention.vue +86 -0
  29. package/src/component/FluxVisualBorderBeam.vue +171 -0
  30. package/src/component/FluxVisualBorderShine.vue +36 -0
  31. package/src/component/FluxVisualDotPattern.vue +119 -0
  32. package/src/component/FluxVisualFlickeringGrid.vue +159 -0
  33. package/src/component/FluxVisualGridPattern.vue +128 -0
  34. package/src/component/FluxVisualHighlighter.vue +217 -0
  35. package/src/component/FluxVisualHighlighterGroup.vue +20 -0
  36. package/src/component/FluxVisualNoise.vue +31 -0
  37. package/src/component/FluxVisualNumberFlow.vue +235 -0
  38. package/src/component/FluxVisualPing.vue +26 -0
  39. package/src/component/FluxVisualSlotText.vue +457 -0
  40. package/src/component/FluxVisualTextScramble.vue +168 -0
  41. package/src/component/FluxVisualTextShimmer.vue +34 -0
  42. package/src/component/index.ts +15 -0
  43. package/src/composable/private/index.ts +2 -0
  44. package/src/composable/private/useBorderBeamPulse.ts +203 -0
  45. package/src/composable/private/useHighlighterGroup.ts +162 -0
  46. package/src/css/component/Attention.module.scss +104 -0
  47. package/src/css/component/BorderBeam.module.scss +1178 -0
  48. package/src/css/component/Highlighter.module.scss +7 -0
  49. package/src/css/component/Noise.module.scss +80 -0
  50. package/src/css/component/NumberFlow.module.scss +5 -0
  51. package/src/css/component/PatternGlow.module.scss +19 -0
  52. package/src/css/component/Ping.module.scss +44 -0
  53. package/src/css/component/SlotText.module.scss +43 -0
  54. package/src/css/component/TextScramble.module.scss +5 -0
  55. package/src/css/component/TextShimmer.module.scss +54 -0
  56. package/src/css/component/Visual.module.scss +71 -0
  57. package/src/index.ts +1 -0
  58. package/src/types.d.ts +13 -0
@@ -0,0 +1,7 @@
1
+ .highlighter {
2
+ position: relative;
3
+ }
4
+
5
+ .highlighterGroup {
6
+ display: contents;
7
+ }
@@ -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,5 @@
1
+ .numberFlow {
2
+ font-variant-numeric: tabular-nums;
3
+ display: inline-block;
4
+ white-space: nowrap;
5
+ }
@@ -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,5 @@
1
+ .textScramble {
2
+ font-variant-numeric: tabular-nums;
3
+ display: inline-block;
4
+ white-space: pre;
5
+ }
@@ -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
+ }