fancy-ui-svelte 0.5.0 → 0.6.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.
@@ -0,0 +1,123 @@
1
+ import { render, cleanup } from "@testing-library/svelte";
2
+ import { afterEach, describe, it, expect, vi } from "vitest";
3
+ import NoiseReveal from "./NoiseReveal.svelte";
4
+ // Holds the last renderer instance created by the mock
5
+ const lastMock = { renderer: null };
6
+ // Three.js uses WebGL which is not available in jsdom — mock the module
7
+ vi.mock("three", () => {
8
+ function Vector2() {
9
+ return { x: 0, y: 0, set: vi.fn() };
10
+ }
11
+ function Texture() {
12
+ return { dispose: vi.fn(), colorSpace: "", image: {} };
13
+ }
14
+ function TextureLoader() {
15
+ return { load: vi.fn(() => Texture()) };
16
+ }
17
+ function ShaderMaterial() {
18
+ return {
19
+ uniforms: {
20
+ uTexture: { value: null },
21
+ uTime: { value: 0 },
22
+ uProgress: { value: 0 },
23
+ uRes: { value: Vector2() },
24
+ uImageRes: { value: Vector2() },
25
+ },
26
+ dispose: vi.fn(),
27
+ };
28
+ }
29
+ function PlaneGeometry() {
30
+ return { dispose: vi.fn() };
31
+ }
32
+ function Mesh() {
33
+ return { scale: { set: vi.fn() } };
34
+ }
35
+ function Scene() {
36
+ return { background: null, add: vi.fn() };
37
+ }
38
+ function PerspectiveCamera() {
39
+ return {
40
+ position: { set: vi.fn() },
41
+ aspect: 1,
42
+ updateProjectionMatrix: vi.fn(),
43
+ };
44
+ }
45
+ function Clock() {
46
+ return { getElapsedTime: vi.fn(() => 0) };
47
+ }
48
+ function WebGLRenderer() {
49
+ const instance = {
50
+ setClearColor: vi.fn(),
51
+ setPixelRatio: vi.fn(),
52
+ setSize: vi.fn(),
53
+ render: vi.fn(),
54
+ dispose: vi.fn(),
55
+ domElement: Object.assign(document.createElement("canvas"), {
56
+ style: { width: "", height: "" },
57
+ }),
58
+ };
59
+ lastMock.renderer = instance;
60
+ return instance;
61
+ }
62
+ return {
63
+ Scene,
64
+ PerspectiveCamera,
65
+ WebGLRenderer,
66
+ PlaneGeometry,
67
+ ShaderMaterial,
68
+ Mesh,
69
+ TextureLoader,
70
+ Texture,
71
+ Vector2,
72
+ Clock,
73
+ SRGBColorSpace: "srgb",
74
+ };
75
+ });
76
+ const src = "https://example.com/image.jpg";
77
+ describe("NoiseReveal", () => {
78
+ afterEach(cleanup);
79
+ it("renders a div container", () => {
80
+ const { container } = render(NoiseReveal, { props: { src } });
81
+ expect(container.querySelector("div")).toBeTruthy();
82
+ });
83
+ it("applies default height class", () => {
84
+ const { container } = render(NoiseReveal, { props: { src } });
85
+ expect(container.querySelector("div")?.className).toContain("h-[400px]");
86
+ });
87
+ it("applies additional class", () => {
88
+ const { container } = render(NoiseReveal, { props: { src, class: "h-[600px]" } });
89
+ expect(container.querySelector("div")?.className).toContain("h-[600px]");
90
+ });
91
+ it("exposes alt text as an accessible image role", () => {
92
+ const { container } = render(NoiseReveal, { props: { src, alt: "Mountain at dusk" } });
93
+ const div = container.querySelector("div[role='img']");
94
+ expect(div).toBeTruthy();
95
+ expect(div?.getAttribute("aria-label")).toBe("Mountain at dusk");
96
+ });
97
+ it("has no img role without alt text", () => {
98
+ const { container } = render(NoiseReveal, { props: { src } });
99
+ expect(container.querySelector("div[role='img']")).toBeFalsy();
100
+ });
101
+ describe("cleanup on unmount", () => {
102
+ it("removes resize listener", () => {
103
+ const spy = vi.spyOn(window, "removeEventListener");
104
+ const { unmount } = render(NoiseReveal, { props: { src } });
105
+ unmount();
106
+ expect(spy).toHaveBeenCalledWith("resize", expect.any(Function));
107
+ spy.mockRestore();
108
+ });
109
+ it("cancels animation frame", () => {
110
+ const spy = vi.spyOn(window, "cancelAnimationFrame");
111
+ const { unmount } = render(NoiseReveal, { props: { src } });
112
+ unmount();
113
+ expect(spy).toHaveBeenCalled();
114
+ spy.mockRestore();
115
+ });
116
+ it("disposes renderer", () => {
117
+ const { unmount } = render(NoiseReveal, { props: { src } });
118
+ const renderer = lastMock.renderer;
119
+ unmount();
120
+ expect(renderer.dispose).toHaveBeenCalled();
121
+ });
122
+ });
123
+ });
@@ -0,0 +1,2 @@
1
+ export { default as NoiseReveal } from "./NoiseReveal.svelte";
2
+ export type { NoiseRevealProps } from "./NoiseReveal.svelte";
@@ -0,0 +1 @@
1
+ export { default as NoiseReveal } from "./NoiseReveal.svelte";
@@ -485,6 +485,88 @@ export const registry = {
485
485
  ],
486
486
  slots: [{ name: "children", description: "Link text content" }],
487
487
  },
488
+ "line-reveal": {
489
+ name: "LineReveal",
490
+ slug: "line-reveal",
491
+ description: "Staggered line-by-line text reveal with lines computed by pretext instead of DOM splitting",
492
+ category: "text",
493
+ status: "done",
494
+ credits: [{ source: "pretext", url: "https://github.com/chenglou/pretext" }],
495
+ tags: ["text", "animation", "reveal", "stagger", "pretext", "typography"],
496
+ props: [
497
+ { name: "text", type: "string", description: "Text to reveal", required: true },
498
+ {
499
+ name: "font",
500
+ type: "string",
501
+ default: "'600 32px \"Helvetica Neue\", Helvetica, Arial, sans-serif'",
502
+ description: "CSS font shorthand used for both measurement and rendering",
503
+ },
504
+ {
505
+ name: "lineHeight",
506
+ type: "number",
507
+ default: "1.2 × font size",
508
+ description: "Line height in pixels",
509
+ },
510
+ {
511
+ name: "stagger",
512
+ type: "number",
513
+ default: "0.08",
514
+ description: "Delay between lines in seconds",
515
+ },
516
+ {
517
+ name: "duration",
518
+ type: "number",
519
+ default: "0.7",
520
+ description: "Animation duration per line in seconds",
521
+ },
522
+ { name: "delay", type: "number", default: "0", description: "Initial delay in seconds" },
523
+ {
524
+ name: "once",
525
+ type: "boolean",
526
+ default: "true",
527
+ description: "Animate only on first viewport entry",
528
+ },
529
+ { name: "class", type: "string", description: "Additional CSS classes" },
530
+ ],
531
+ },
532
+ "editorial-engine": {
533
+ name: "EditorialEngine",
534
+ slug: "editorial-engine",
535
+ description: "Live magazine layout: multi-column text flowing around draggable orbs with zero DOM reads, powered by pretext",
536
+ category: "text",
537
+ status: "done",
538
+ credits: [
539
+ { source: "pretext editorial engine", url: "https://chenglou.me/pretext/editorial-engine/" },
540
+ ],
541
+ tags: ["text", "layout", "magazine", "columns", "pretext", "interactive", "typography"],
542
+ props: [
543
+ {
544
+ name: "headline",
545
+ type: "string",
546
+ default: "built-in copy",
547
+ description: "Auto-sized headline (largest font size that breaks no word)",
548
+ },
549
+ {
550
+ name: "body",
551
+ type: "string",
552
+ default: "built-in copy",
553
+ description: "Body text, paragraphs separated by blank lines",
554
+ },
555
+ {
556
+ name: "pullquotes",
557
+ type: "string[]",
558
+ default: "built-in quotes",
559
+ description: "Up to two pullquotes embedded in the columns",
560
+ },
561
+ {
562
+ name: "fontFamily",
563
+ type: "string",
564
+ default: "Palatino serif stack",
565
+ description: "Font family stack used for all text",
566
+ },
567
+ { name: "class", type: "string", description: "Additional CSS classes for the stage" },
568
+ ],
569
+ },
488
570
  "logo-cloud": {
489
571
  name: "LogoCloud",
490
572
  slug: "logo-cloud",
@@ -855,17 +937,6 @@ export const registry = {
855
937
  },
856
938
  ],
857
939
  },
858
- "fluid-cursor-advanced": {
859
- name: "FluidCursorAdvanced",
860
- slug: "fluid-cursor-advanced",
861
- description: "WebGL fluid simulation confined to a parent container element",
862
- category: "effects",
863
- status: "done",
864
- credits: [
865
- { source: "Inspira UI", url: "https://inspira-ui.com/components/cursor/fluid-cursor" },
866
- ],
867
- tags: ["cursor", "webgl", "fluid", "simulation", "interactive", "contained"],
868
- },
869
940
  "glow-border": {
870
941
  name: "GlowBorder",
871
942
  slug: "glow-border",
@@ -2040,6 +2111,52 @@ export const registry = {
2040
2111
  },
2041
2112
  ],
2042
2113
  },
2114
+ "noise-reveal": {
2115
+ name: "NoiseReveal",
2116
+ slug: "noise-reveal",
2117
+ description: "WebGL image reveal with a Perlin-noise dissolve mask, contracting radial gradient, and wave displacement, inspired by a Codrops shader effect",
2118
+ category: "media",
2119
+ status: "done",
2120
+ credits: [
2121
+ {
2122
+ source: "Codrops",
2123
+ url: "https://tympanus.net/codrops/2024/12/02/how-to-code-a-shader-based-reveal-effect-with-react-three-fiber-glsl/",
2124
+ },
2125
+ {
2126
+ source: "colindmg/r3f-image-reveal-effect",
2127
+ url: "https://github.com/colindmg/r3f-image-reveal-effect",
2128
+ },
2129
+ ],
2130
+ tags: ["media", "image", "reveal", "webgl", "shader", "threejs", "noise"],
2131
+ props: [
2132
+ { name: "src", type: "string", description: "Image URL", required: true },
2133
+ { name: "alt", type: "string", description: "Accessible label for the image" },
2134
+ {
2135
+ name: "trigger",
2136
+ type: '"view" | "manual"',
2137
+ default: '"view"',
2138
+ description: 'Reveal trigger: "view" = on viewport entry, "manual" = via revealed prop',
2139
+ },
2140
+ {
2141
+ name: "revealed",
2142
+ type: "boolean",
2143
+ default: "false",
2144
+ description: 'Manual reveal state (used with trigger="manual"; also allows re-hiding)',
2145
+ },
2146
+ {
2147
+ name: "duration",
2148
+ type: "number",
2149
+ default: "1.5",
2150
+ description: "Reveal animation duration in seconds",
2151
+ },
2152
+ {
2153
+ name: "delay",
2154
+ type: "number",
2155
+ default: "0",
2156
+ description: 'Delay before reveal in seconds (trigger="view")',
2157
+ },
2158
+ ],
2159
+ },
2043
2160
  };
2044
2161
  // =============================================================================
2045
2162
  // Registry Helpers
package/dist/types.d.ts CHANGED
@@ -119,4 +119,6 @@ export interface ComponentMeta {
119
119
  events?: EventDef[];
120
120
  /** Version when component was added */
121
121
  since?: string;
122
+ /** Kept only as a backwards-compatible alias; hidden from generated docs */
123
+ deprecated?: boolean;
122
124
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fancy-ui-svelte",
3
3
  "private": false,
4
- "version": "0.5.0",
4
+ "version": "0.6.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -50,7 +50,7 @@
50
50
  "tailwindcss": "^4.0.0"
51
51
  },
52
52
  "dependencies": {
53
- "@vercel/analytics": "^2.0.1",
53
+ "@chenglou/pretext": "^0.0.5",
54
54
  "canvas-confetti": "^1.9.4",
55
55
  "clsx": "^2.1.1",
56
56
  "gsap": "^3.14.2",
@@ -59,6 +59,7 @@
59
59
  },
60
60
  "devDependencies": {
61
61
  "@changesets/cli": "^2.30.0",
62
+ "@vercel/analytics": "^2.0.1",
62
63
  "@internationalized/date": "^3.10.1",
63
64
  "@lucide/svelte": "^0.562.0",
64
65
  "@playwright/test": "^1.58.2",
@@ -101,6 +102,7 @@
101
102
  "preview": "vite preview",
102
103
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
103
104
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
105
+ "check:registry": "node scripts/check-registry.mjs",
104
106
  "test": "vitest run",
105
107
  "test:watch": "vitest",
106
108
  "test:e2e": "playwright test",