@fanvue/ui 2.13.0 → 2.14.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.
Files changed (42) hide show
  1. package/dist/cjs/components/ChatInput/ChatInput.cjs +75 -27
  2. package/dist/cjs/components/ChatInput/ChatInput.cjs.map +1 -1
  3. package/dist/cjs/components/CreatorCard/CreatorCard.cjs +81 -0
  4. package/dist/cjs/components/CreatorCard/CreatorCard.cjs.map +1 -0
  5. package/dist/cjs/components/CreatorCover/CreatorCover.cjs +83 -0
  6. package/dist/cjs/components/CreatorCover/CreatorCover.cjs.map +1 -0
  7. package/dist/cjs/components/CreatorTile/CreatorTile.cjs +64 -0
  8. package/dist/cjs/components/CreatorTile/CreatorTile.cjs.map +1 -0
  9. package/dist/cjs/components/CyclingText/CyclingText.cjs +137 -0
  10. package/dist/cjs/components/CyclingText/CyclingText.cjs.map +1 -0
  11. package/dist/cjs/components/CyclingText/useCyclingCycle.cjs +212 -0
  12. package/dist/cjs/components/CyclingText/useCyclingCycle.cjs.map +1 -0
  13. package/dist/cjs/components/CyclingText/useCyclingTextTrackWidth.cjs +55 -0
  14. package/dist/cjs/components/CyclingText/useCyclingTextTrackWidth.cjs.map +1 -0
  15. package/dist/cjs/components/CyclingText/usePageVisibility.cjs +38 -0
  16. package/dist/cjs/components/CyclingText/usePageVisibility.cjs.map +1 -0
  17. package/dist/cjs/components/CyclingText/usePrefersReducedMotion.cjs +39 -0
  18. package/dist/cjs/components/CyclingText/usePrefersReducedMotion.cjs.map +1 -0
  19. package/dist/cjs/index.cjs +8 -0
  20. package/dist/cjs/index.cjs.map +1 -1
  21. package/dist/components/ChatInput/ChatInput.mjs +75 -27
  22. package/dist/components/ChatInput/ChatInput.mjs.map +1 -1
  23. package/dist/components/CreatorCard/CreatorCard.mjs +64 -0
  24. package/dist/components/CreatorCard/CreatorCard.mjs.map +1 -0
  25. package/dist/components/CreatorCover/CreatorCover.mjs +66 -0
  26. package/dist/components/CreatorCover/CreatorCover.mjs.map +1 -0
  27. package/dist/components/CreatorTile/CreatorTile.mjs +47 -0
  28. package/dist/components/CreatorTile/CreatorTile.mjs.map +1 -0
  29. package/dist/components/CyclingText/CyclingText.mjs +120 -0
  30. package/dist/components/CyclingText/CyclingText.mjs.map +1 -0
  31. package/dist/components/CyclingText/useCyclingCycle.mjs +195 -0
  32. package/dist/components/CyclingText/useCyclingCycle.mjs.map +1 -0
  33. package/dist/components/CyclingText/useCyclingTextTrackWidth.mjs +38 -0
  34. package/dist/components/CyclingText/useCyclingTextTrackWidth.mjs.map +1 -0
  35. package/dist/components/CyclingText/usePageVisibility.mjs +21 -0
  36. package/dist/components/CyclingText/usePageVisibility.mjs.map +1 -0
  37. package/dist/components/CyclingText/usePrefersReducedMotion.mjs +22 -0
  38. package/dist/components/CyclingText/usePrefersReducedMotion.mjs.map +1 -0
  39. package/dist/index.d.ts +223 -0
  40. package/dist/index.mjs +8 -0
  41. package/dist/index.mjs.map +1 -1
  42. package/package.json +1 -1
@@ -0,0 +1,195 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ const initialCycleState = {
4
+ currentIndex: 0,
5
+ incomingIndex: null,
6
+ incomingEntered: false,
7
+ transitioning: false
8
+ };
9
+ function cycleReducer(state, action) {
10
+ switch (action.type) {
11
+ case "tick": {
12
+ if (action.itemCount <= 1) return state;
13
+ const next = (state.currentIndex + 1) % action.itemCount;
14
+ return {
15
+ ...state,
16
+ incomingIndex: next,
17
+ incomingEntered: false,
18
+ transitioning: true
19
+ };
20
+ }
21
+ case "incoming_entered":
22
+ return { ...state, incomingEntered: true };
23
+ case "transition_complete": {
24
+ if (!state.transitioning || state.incomingIndex === null) return state;
25
+ return {
26
+ currentIndex: state.incomingIndex,
27
+ incomingIndex: null,
28
+ incomingEntered: false,
29
+ transitioning: false
30
+ };
31
+ }
32
+ case "pause_clear":
33
+ return {
34
+ ...state,
35
+ incomingIndex: null,
36
+ incomingEntered: false,
37
+ transitioning: false
38
+ };
39
+ case "clamp_after_items_change": {
40
+ if (action.itemCount === 0) return state;
41
+ const idx = state.currentIndex >= action.itemCount ? 0 : state.currentIndex;
42
+ return {
43
+ currentIndex: idx,
44
+ incomingIndex: null,
45
+ incomingEntered: false,
46
+ transitioning: false
47
+ };
48
+ }
49
+ default:
50
+ return state;
51
+ }
52
+ }
53
+ function useCyclingCycle(items, sizing, intervalMs, paused, docVisible, transitionMs) {
54
+ const [cycle, dispatch] = React.useReducer(cycleReducer, initialCycleState);
55
+ const enterOuterFrameRef = React.useRef(null);
56
+ const enterInnerFrameRef = React.useRef(null);
57
+ const fallbackTimerRef = React.useRef(null);
58
+ const cycleTimeoutRef = React.useRef(null);
59
+ const clearCycleTimeout = React.useCallback(() => {
60
+ if (cycleTimeoutRef.current !== null) {
61
+ clearTimeout(cycleTimeoutRef.current);
62
+ cycleTimeoutRef.current = null;
63
+ }
64
+ }, []);
65
+ const clearAnimationArtifacts = React.useCallback(() => {
66
+ if (enterOuterFrameRef.current !== null) {
67
+ cancelAnimationFrame(enterOuterFrameRef.current);
68
+ enterOuterFrameRef.current = null;
69
+ }
70
+ if (enterInnerFrameRef.current !== null) {
71
+ cancelAnimationFrame(enterInnerFrameRef.current);
72
+ enterInnerFrameRef.current = null;
73
+ }
74
+ if (fallbackTimerRef.current !== null) {
75
+ clearTimeout(fallbackTimerRef.current);
76
+ fallbackTimerRef.current = null;
77
+ }
78
+ clearCycleTimeout();
79
+ }, [clearCycleTimeout]);
80
+ const itemCount = items.length;
81
+ React.useEffect(() => {
82
+ if (itemCount === 0) return;
83
+ dispatch({ type: "clamp_after_items_change", itemCount });
84
+ }, [itemCount]);
85
+ const safeCurrentIndex = itemCount === 0 ? 0 : cycle.currentIndex % itemCount;
86
+ const safeIncomingIndex = cycle.incomingIndex === null || itemCount === 0 ? null : cycle.incomingIndex % itemCount;
87
+ const currentLabel = itemCount === 0 ? "" : items[safeCurrentIndex] ?? "";
88
+ const incomingLabel = safeIncomingIndex === null ? null : items[safeIncomingIndex] ?? "";
89
+ const longestItem = React.useMemo(() => {
90
+ if (itemCount === 0) return "";
91
+ let longest = items[0] ?? "";
92
+ for (const item of items) {
93
+ if (item.length > longest.length) longest = item;
94
+ }
95
+ return longest;
96
+ }, [items, itemCount]);
97
+ const sizingLabel = sizing === "longest" ? longestItem : incomingLabel && incomingLabel.length > currentLabel.length ? incomingLabel : currentLabel;
98
+ const shouldCycle = !paused && docVisible && itemCount > 1;
99
+ React.useEffect(() => {
100
+ if (!shouldCycle || itemCount <= 1) {
101
+ clearCycleTimeout();
102
+ return;
103
+ }
104
+ if (cycle.transitioning) {
105
+ return;
106
+ }
107
+ cycleTimeoutRef.current = setTimeout(() => {
108
+ cycleTimeoutRef.current = null;
109
+ dispatch({ type: "tick", itemCount });
110
+ }, intervalMs);
111
+ return () => {
112
+ clearCycleTimeout();
113
+ };
114
+ }, [shouldCycle, itemCount, intervalMs, cycle.transitioning, clearCycleTimeout]);
115
+ React.useEffect(() => {
116
+ if (paused) {
117
+ clearAnimationArtifacts();
118
+ dispatch({ type: "pause_clear" });
119
+ }
120
+ }, [paused, clearAnimationArtifacts]);
121
+ React.useEffect(() => {
122
+ return () => {
123
+ clearAnimationArtifacts();
124
+ };
125
+ }, [clearAnimationArtifacts]);
126
+ React.useEffect(() => {
127
+ if (!cycle.transitioning || cycle.incomingIndex === null || cycle.incomingEntered) {
128
+ return;
129
+ }
130
+ if (enterOuterFrameRef.current !== null) {
131
+ cancelAnimationFrame(enterOuterFrameRef.current);
132
+ }
133
+ if (enterInnerFrameRef.current !== null) {
134
+ cancelAnimationFrame(enterInnerFrameRef.current);
135
+ }
136
+ enterOuterFrameRef.current = requestAnimationFrame(() => {
137
+ enterOuterFrameRef.current = null;
138
+ enterInnerFrameRef.current = requestAnimationFrame(() => {
139
+ enterInnerFrameRef.current = null;
140
+ dispatch({ type: "incoming_entered" });
141
+ });
142
+ });
143
+ return () => {
144
+ if (enterOuterFrameRef.current !== null) {
145
+ cancelAnimationFrame(enterOuterFrameRef.current);
146
+ enterOuterFrameRef.current = null;
147
+ }
148
+ if (enterInnerFrameRef.current !== null) {
149
+ cancelAnimationFrame(enterInnerFrameRef.current);
150
+ enterInnerFrameRef.current = null;
151
+ }
152
+ };
153
+ }, [cycle.transitioning, cycle.incomingIndex, cycle.incomingEntered]);
154
+ React.useEffect(() => {
155
+ if (!cycle.transitioning) {
156
+ return;
157
+ }
158
+ if (fallbackTimerRef.current !== null) {
159
+ clearTimeout(fallbackTimerRef.current);
160
+ }
161
+ fallbackTimerRef.current = setTimeout(() => {
162
+ dispatch({ type: "transition_complete" });
163
+ fallbackTimerRef.current = null;
164
+ }, transitionMs);
165
+ return () => {
166
+ if (fallbackTimerRef.current !== null) {
167
+ clearTimeout(fallbackTimerRef.current);
168
+ fallbackTimerRef.current = null;
169
+ }
170
+ };
171
+ }, [cycle.transitioning, transitionMs]);
172
+ const onOutgoingTransitionEnd = React.useCallback(
173
+ (event) => {
174
+ if (!cycle.transitioning) return;
175
+ if (event.propertyName !== "opacity") return;
176
+ if (fallbackTimerRef.current !== null) {
177
+ clearTimeout(fallbackTimerRef.current);
178
+ fallbackTimerRef.current = null;
179
+ }
180
+ dispatch({ type: "transition_complete" });
181
+ },
182
+ [cycle.transitioning]
183
+ );
184
+ return {
185
+ cycle,
186
+ currentLabel,
187
+ incomingLabel,
188
+ sizingLabel,
189
+ onOutgoingTransitionEnd
190
+ };
191
+ }
192
+ export {
193
+ useCyclingCycle
194
+ };
195
+ //# sourceMappingURL=useCyclingCycle.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCyclingCycle.mjs","sources":["../../../src/components/CyclingText/useCyclingCycle.ts"],"sourcesContent":["import * as React from \"react\";\n\ntype CyclingTextSizingOption = \"longest\" | \"current\";\n\ntype CycleState = {\n currentIndex: number;\n incomingIndex: number | null;\n incomingEntered: boolean;\n transitioning: boolean;\n};\n\ntype CycleAction =\n | { type: \"tick\"; itemCount: number }\n | { type: \"incoming_entered\" }\n | { type: \"transition_complete\" }\n | { type: \"pause_clear\" }\n | { type: \"clamp_after_items_change\"; itemCount: number };\n\nconst initialCycleState: CycleState = {\n currentIndex: 0,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n};\n\nfunction cycleReducer(state: CycleState, action: CycleAction): CycleState {\n switch (action.type) {\n case \"tick\": {\n if (action.itemCount <= 1) return state;\n const next = (state.currentIndex + 1) % action.itemCount;\n return {\n ...state,\n incomingIndex: next,\n incomingEntered: false,\n transitioning: true,\n };\n }\n case \"incoming_entered\":\n return { ...state, incomingEntered: true };\n case \"transition_complete\": {\n if (!state.transitioning || state.incomingIndex === null) return state;\n return {\n currentIndex: state.incomingIndex,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n }\n case \"pause_clear\":\n return {\n ...state,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n case \"clamp_after_items_change\": {\n if (action.itemCount === 0) return state;\n const idx = state.currentIndex >= action.itemCount ? 0 : state.currentIndex;\n return {\n currentIndex: idx,\n incomingIndex: null,\n incomingEntered: false,\n transitioning: false,\n };\n }\n default:\n return state;\n }\n}\n\nexport function useCyclingCycle(\n items: readonly string[],\n sizing: CyclingTextSizingOption,\n intervalMs: number,\n paused: boolean,\n docVisible: boolean,\n transitionMs: number,\n) {\n const [cycle, dispatch] = React.useReducer(cycleReducer, initialCycleState);\n\n const enterOuterFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n const enterInnerFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n const fallbackTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n const cycleTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCycleTimeout = React.useCallback(() => {\n if (cycleTimeoutRef.current !== null) {\n clearTimeout(cycleTimeoutRef.current);\n cycleTimeoutRef.current = null;\n }\n }, []);\n\n const clearAnimationArtifacts = React.useCallback(() => {\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n enterOuterFrameRef.current = null;\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n enterInnerFrameRef.current = null;\n }\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n clearCycleTimeout();\n }, [clearCycleTimeout]);\n\n const itemCount = items.length;\n\n React.useEffect(() => {\n if (itemCount === 0) return;\n dispatch({ type: \"clamp_after_items_change\", itemCount });\n }, [itemCount]);\n\n const safeCurrentIndex = itemCount === 0 ? 0 : cycle.currentIndex % itemCount;\n const safeIncomingIndex =\n cycle.incomingIndex === null || itemCount === 0 ? null : cycle.incomingIndex % itemCount;\n\n const currentLabel = itemCount === 0 ? \"\" : (items[safeCurrentIndex] ?? \"\");\n const incomingLabel = safeIncomingIndex === null ? null : (items[safeIncomingIndex] ?? \"\");\n\n const longestItem = React.useMemo(() => {\n if (itemCount === 0) return \"\";\n let longest = items[0] ?? \"\";\n for (const item of items) {\n if (item.length > longest.length) longest = item;\n }\n return longest;\n }, [items, itemCount]);\n\n const sizingLabel =\n sizing === \"longest\"\n ? longestItem\n : incomingLabel && incomingLabel.length > currentLabel.length\n ? incomingLabel\n : currentLabel;\n\n const shouldCycle = !paused && docVisible && itemCount > 1;\n\n React.useEffect(() => {\n if (!shouldCycle || itemCount <= 1) {\n clearCycleTimeout();\n return;\n }\n\n if (cycle.transitioning) {\n return;\n }\n\n cycleTimeoutRef.current = setTimeout(() => {\n cycleTimeoutRef.current = null;\n dispatch({ type: \"tick\", itemCount });\n }, intervalMs);\n\n return () => {\n clearCycleTimeout();\n };\n }, [shouldCycle, itemCount, intervalMs, cycle.transitioning, clearCycleTimeout]);\n\n React.useEffect(() => {\n if (paused) {\n clearAnimationArtifacts();\n dispatch({ type: \"pause_clear\" });\n }\n }, [paused, clearAnimationArtifacts]);\n\n React.useEffect(() => {\n return () => {\n clearAnimationArtifacts();\n };\n }, [clearAnimationArtifacts]);\n\n React.useEffect(() => {\n if (!cycle.transitioning || cycle.incomingIndex === null || cycle.incomingEntered) {\n return;\n }\n\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n }\n\n enterOuterFrameRef.current = requestAnimationFrame(() => {\n enterOuterFrameRef.current = null;\n enterInnerFrameRef.current = requestAnimationFrame(() => {\n enterInnerFrameRef.current = null;\n dispatch({ type: \"incoming_entered\" });\n });\n });\n\n return () => {\n if (enterOuterFrameRef.current !== null) {\n cancelAnimationFrame(enterOuterFrameRef.current);\n enterOuterFrameRef.current = null;\n }\n if (enterInnerFrameRef.current !== null) {\n cancelAnimationFrame(enterInnerFrameRef.current);\n enterInnerFrameRef.current = null;\n }\n };\n }, [cycle.transitioning, cycle.incomingIndex, cycle.incomingEntered]);\n\n React.useEffect(() => {\n if (!cycle.transitioning) {\n return;\n }\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n }\n fallbackTimerRef.current = setTimeout(() => {\n dispatch({ type: \"transition_complete\" });\n fallbackTimerRef.current = null;\n }, transitionMs);\n\n return () => {\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n };\n }, [cycle.transitioning, transitionMs]);\n\n const onOutgoingTransitionEnd = React.useCallback(\n (event: React.TransitionEvent<HTMLSpanElement>) => {\n if (!cycle.transitioning) return;\n if (event.propertyName !== \"opacity\") return;\n if (fallbackTimerRef.current !== null) {\n clearTimeout(fallbackTimerRef.current);\n fallbackTimerRef.current = null;\n }\n dispatch({ type: \"transition_complete\" });\n },\n [cycle.transitioning],\n );\n\n return {\n cycle,\n currentLabel,\n incomingLabel,\n sizingLabel,\n onOutgoingTransitionEnd,\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ function useCyclingTextTrackWidth() {
4
+ const sizingLabelRef = React.useRef(null);
5
+ const [trackWidth, setTrackWidth] = React.useState(null);
6
+ const widthFrameRef = React.useRef(null);
7
+ React.useEffect(() => {
8
+ const node = sizingLabelRef.current;
9
+ if (!node) return;
10
+ const measure = () => {
11
+ const next = Math.ceil(node.getBoundingClientRect().width);
12
+ if (!next) return;
13
+ if (widthFrameRef.current !== null) {
14
+ cancelAnimationFrame(widthFrameRef.current);
15
+ }
16
+ widthFrameRef.current = requestAnimationFrame(() => {
17
+ setTrackWidth(next);
18
+ widthFrameRef.current = null;
19
+ });
20
+ };
21
+ measure();
22
+ if (typeof ResizeObserver === "undefined") return;
23
+ const observer = new ResizeObserver(measure);
24
+ observer.observe(node);
25
+ return () => {
26
+ observer.disconnect();
27
+ if (widthFrameRef.current !== null) {
28
+ cancelAnimationFrame(widthFrameRef.current);
29
+ widthFrameRef.current = null;
30
+ }
31
+ };
32
+ }, []);
33
+ return { sizingLabelRef, trackWidth };
34
+ }
35
+ export {
36
+ useCyclingTextTrackWidth
37
+ };
38
+ //# sourceMappingURL=useCyclingTextTrackWidth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCyclingTextTrackWidth.mjs","sources":["../../../src/components/CyclingText/useCyclingTextTrackWidth.ts"],"sourcesContent":["import * as React from \"react\";\n\n/**\n * Observes the measured label node and stores its width so the wrapper can animate width\n * without layout thrash when fonts load or the parent resizes.\n */\nexport function useCyclingTextTrackWidth() {\n const sizingLabelRef = React.useRef<HTMLSpanElement | null>(null);\n const [trackWidth, setTrackWidth] = React.useState<number | null>(null);\n const widthFrameRef = React.useRef<ReturnType<typeof requestAnimationFrame> | null>(null);\n\n React.useEffect(() => {\n const node = sizingLabelRef.current;\n if (!node) return;\n\n const measure = () => {\n const next = Math.ceil(node.getBoundingClientRect().width);\n if (!next) return;\n if (widthFrameRef.current !== null) {\n cancelAnimationFrame(widthFrameRef.current);\n }\n widthFrameRef.current = requestAnimationFrame(() => {\n setTrackWidth(next);\n widthFrameRef.current = null;\n });\n };\n\n measure();\n\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(measure);\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n if (widthFrameRef.current !== null) {\n cancelAnimationFrame(widthFrameRef.current);\n widthFrameRef.current = null;\n }\n };\n }, []);\n\n return { sizingLabelRef, trackWidth };\n}\n"],"names":[],"mappings":";;AAMO,SAAS,2BAA2B;AACzC,QAAM,iBAAiB,MAAM,OAA+B,IAAI;AAChE,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAwB,IAAI;AACtE,QAAM,gBAAgB,MAAM,OAAwD,IAAI;AAExF,QAAM,UAAU,MAAM;AACpB,UAAM,OAAO,eAAe;AAC5B,QAAI,CAAC,KAAM;AAEX,UAAM,UAAU,MAAM;AACpB,YAAM,OAAO,KAAK,KAAK,KAAK,sBAAA,EAAwB,KAAK;AACzD,UAAI,CAAC,KAAM;AACX,UAAI,cAAc,YAAY,MAAM;AAClC,6BAAqB,cAAc,OAAO;AAAA,MAC5C;AACA,oBAAc,UAAU,sBAAsB,MAAM;AAClD,sBAAc,IAAI;AAClB,sBAAc,UAAU;AAAA,MAC1B,CAAC;AAAA,IACH;AAEA,YAAA;AAEA,QAAI,OAAO,mBAAmB,YAAa;AAC3C,UAAM,WAAW,IAAI,eAAe,OAAO;AAC3C,aAAS,QAAQ,IAAI;AAErB,WAAO,MAAM;AACX,eAAS,WAAA;AACT,UAAI,cAAc,YAAY,MAAM;AAClC,6BAAqB,cAAc,OAAO;AAC1C,sBAAc,UAAU;AAAA,MAC1B;AAAA,IACF;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,SAAO,EAAE,gBAAgB,WAAA;AAC3B;"}
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ function usePageVisibility() {
4
+ const [visible, setVisible] = React.useState(true);
5
+ React.useEffect(() => {
6
+ if (typeof document === "undefined") {
7
+ return;
8
+ }
9
+ const update = () => {
10
+ setVisible(document.visibilityState === "visible");
11
+ };
12
+ update();
13
+ document.addEventListener("visibilitychange", update);
14
+ return () => document.removeEventListener("visibilitychange", update);
15
+ }, []);
16
+ return visible;
17
+ }
18
+ export {
19
+ usePageVisibility
20
+ };
21
+ //# sourceMappingURL=usePageVisibility.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePageVisibility.mjs","sources":["../../../src/components/CyclingText/usePageVisibility.ts"],"sourcesContent":["import * as React from \"react\";\n\n/**\n * Tracks whether the browser tab is visible (`document.visibilityState === \"visible\"`).\n * Cycling animations use this to pause while the document is hidden so timers do not queue\n * many swaps while the user is away.\n */\nexport function usePageVisibility(): boolean {\n const [visible, setVisible] = React.useState(true);\n\n React.useEffect(() => {\n if (typeof document === \"undefined\") {\n return;\n }\n const update = () => {\n setVisible(document.visibilityState === \"visible\");\n };\n update();\n document.addEventListener(\"visibilitychange\", update);\n return () => document.removeEventListener(\"visibilitychange\", update);\n }, []);\n\n return visible;\n}\n"],"names":[],"mappings":";;AAOO,SAAS,oBAA6B;AAC3C,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AAEjD,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,aAAa,aAAa;AACnC;AAAA,IACF;AACA,UAAM,SAAS,MAAM;AACnB,iBAAW,SAAS,oBAAoB,SAAS;AAAA,IACnD;AACA,WAAA;AACA,aAAS,iBAAiB,oBAAoB,MAAM;AACpD,WAAO,MAAM,SAAS,oBAAoB,oBAAoB,MAAM;AAAA,EACtE,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;"}
@@ -0,0 +1,22 @@
1
+ "use client";
2
+ import * as React from "react";
3
+ function usePrefersReducedMotion() {
4
+ const [reduced, setReduced] = React.useState(false);
5
+ React.useEffect(() => {
6
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
7
+ return;
8
+ }
9
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
10
+ const sync = () => {
11
+ setReduced(mq.matches);
12
+ };
13
+ sync();
14
+ mq.addEventListener("change", sync);
15
+ return () => mq.removeEventListener("change", sync);
16
+ }, []);
17
+ return reduced;
18
+ }
19
+ export {
20
+ usePrefersReducedMotion
21
+ };
22
+ //# sourceMappingURL=usePrefersReducedMotion.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrefersReducedMotion.mjs","sources":["../../../src/components/CyclingText/usePrefersReducedMotion.ts"],"sourcesContent":["import * as React from \"react\";\n\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = React.useState(false);\n\n React.useEffect(() => {\n if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") {\n return;\n }\n const mq = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n const sync = () => {\n setReduced(mq.matches);\n };\n sync();\n mq.addEventListener(\"change\", sync);\n return () => mq.removeEventListener(\"change\", sync);\n }, []);\n\n return reduced;\n}\n"],"names":[],"mappings":";;AAEO,SAAS,0BAAmC;AACjD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAElD,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E;AAAA,IACF;AACA,UAAM,KAAK,OAAO,WAAW,kCAAkC;AAC/D,UAAM,OAAO,MAAM;AACjB,iBAAW,GAAG,OAAO;AAAA,IACvB;AACA,SAAA;AACA,OAAG,iBAAiB,UAAU,IAAI;AAClC,WAAO,MAAM,GAAG,oBAAoB,UAAU,IAAI;AAAA,EACpD,GAAG,CAAA,CAAE;AAEL,SAAO;AACT;"}
package/dist/index.d.ts CHANGED
@@ -917,9 +917,38 @@ export declare type ChartIconProps = BaseIconProps;
917
917
  * onSubmit={(text) => send(text)}
918
918
  * />
919
919
  * ```
920
+ *
921
+ * @example
922
+ * ```tsx
923
+ * <ChatInput
924
+ * showFileButton
925
+ * onFileClick={() => openPicker()}
926
+ * attachments={files}
927
+ * onAttachmentRemove={(id) => setFiles((prev) => prev.filter((f) => f.id !== id))}
928
+ * />
929
+ * ```
930
+ *
931
+ * @example
932
+ * ```tsx
933
+ * <ChatInput
934
+ * showFileButton
935
+ * onFileClick={() => openPicker()}
936
+ * attachmentPreviews={<CustomVideoStrip items={items} />}
937
+ * />
938
+ * ```
920
939
  */
921
940
  export declare const ChatInput: React_2.ForwardRefExoticComponent<ChatInputProps & React_2.RefAttributes<HTMLTextAreaElement>>;
922
941
 
942
+ /** A single image thumbnail in the built-in attachment strip. */
943
+ export declare interface ChatInputAttachmentItem {
944
+ /** Stable id passed to {@link ChatInputProps.onAttachmentRemove} and used as React `key`. */
945
+ id: string;
946
+ /** Image URL for the thumbnail. */
947
+ src: string;
948
+ /** Optional value passed to the remove control `aria-label`. */
949
+ ariaLabel?: string;
950
+ }
951
+
923
952
  /**
924
953
  * Props for {@link ChatInput}. Standard textarea HTML attributes are forwarded to the inner
925
954
  * `<textarea>` except `className` (applied to the outer container), `rows` (use `minRows`), and
@@ -964,6 +993,21 @@ export declare interface ChatInputProps extends Omit<React_2.TextareaHTMLAttribu
964
993
  selectValue?: string;
965
994
  /** Callback fired when the user picks a different dropdown option. */
966
995
  onSelectChange?: (value: string) => void;
996
+ /**
997
+ * Image attachments shown in the built-in thumbnail strip. Ignored when {@link ChatInputProps.attachmentPreviews}
998
+ * is provided (including `null`).
999
+ */
1000
+ attachments?: ChatInputAttachmentItem[];
1001
+ /**
1002
+ * Called when the user removes a built-in thumbnail. The remove button is disabled when this is
1003
+ * omitted or the input is {@link ChatInputProps.disabled}.
1004
+ */
1005
+ onAttachmentRemove?: (id: string) => void;
1006
+ /**
1007
+ * Replaces the built-in attachment strip entirely. When set to any value other than `undefined`
1008
+ * (including `null` or `[]`), {@link ChatInputProps.attachments} is ignored.
1009
+ */
1010
+ attachmentPreviews?: React_2.ReactNode;
967
1011
  /** Additional className applied to the outermost container. */
968
1012
  className?: string;
969
1013
  }
@@ -1251,6 +1295,136 @@ export declare type CountSize = "16" | "24" | "32";
1251
1295
  /** Colour variant for the count badge. */
1252
1296
  export declare type CountVariant = "default" | "alert" | "brand" | "pink" | "info" | "success" | "warning";
1253
1297
 
1298
+ /**
1299
+ * A portrait media card highlighting a creator with avatar, name, optional
1300
+ * tagline, and up to two stacked action buttons over a background image.
1301
+ *
1302
+ * Pass zero, one, or two {@link Button} elements via `actions` to render the
1303
+ * no-button, single-button, or two-button variants.
1304
+ *
1305
+ * @example
1306
+ * ```tsx
1307
+ * <CreatorCard
1308
+ * imageSrc="/creator.jpg"
1309
+ * name="Jane Doe"
1310
+ * description="MODEL & PODCASTER"
1311
+ * avatar={{ src: "/avatar.jpg", alt: "Jane Doe", fallback: "JD" }}
1312
+ * actions={
1313
+ * <>
1314
+ * <Button variant="brand" fullWidth>Join for free for 3 days</Button>
1315
+ * <Button variant="primary" fullWidth>Follow for Free</Button>
1316
+ * </>
1317
+ * }
1318
+ * />
1319
+ * ```
1320
+ */
1321
+ export declare const CreatorCard: React_2.ForwardRefExoticComponent<CreatorCardProps & React_2.RefAttributes<HTMLDivElement>>;
1322
+
1323
+ export declare interface CreatorCardProps extends React_2.HTMLAttributes<HTMLDivElement> {
1324
+ /** URL of the background media (image or video poster). */
1325
+ imageSrc: string;
1326
+ /** Alt text for the background image. @default "" */
1327
+ imageAlt?: string;
1328
+ /** Creator display name shown as the heading. */
1329
+ name: string;
1330
+ /** Optional secondary line shown below the name (e.g. role or tagline). */
1331
+ description?: string;
1332
+ /** Avatar props forwarded to the inner {@link Avatar}. */
1333
+ avatar?: React_2.ComponentPropsWithoutRef<typeof Avatar>;
1334
+ /**
1335
+ * Action buttons rendered at the bottom of the card. Pass zero, one, or two
1336
+ * `Button` elements to render variants with no, one, or two CTAs.
1337
+ */
1338
+ actions?: React_2.ReactNode;
1339
+ }
1340
+
1341
+ /**
1342
+ * A creator profile hero with a stylised blurred backdrop, central cover image,
1343
+ * status pill, name, tagline, and primary call to action.
1344
+ *
1345
+ * @example
1346
+ * ```tsx
1347
+ * <CreatorCover
1348
+ * imageSrc="/creator.jpg"
1349
+ * imageAlt="Jane Doe"
1350
+ * name="JANE DOE"
1351
+ * tagline="GLOBAL POPSTAR"
1352
+ * tag="New Joiner"
1353
+ * action={<Button variant="primary" size="48" fullWidth>Join for free for 7 days</Button>}
1354
+ * />
1355
+ * ```
1356
+ */
1357
+ export declare const CreatorCover: React_2.ForwardRefExoticComponent<CreatorCoverProps & React_2.RefAttributes<HTMLElement>>;
1358
+
1359
+ export declare interface CreatorCoverProps extends Omit<React_2.HTMLAttributes<HTMLElement>, "title"> {
1360
+ /** URL of the creator image displayed in the centre card. Also used as the blurred backdrop unless `backgroundSrc` is provided. */
1361
+ imageSrc: string;
1362
+ /** Alt text for the centre cover image. @default "" */
1363
+ imageAlt?: string;
1364
+ /** Override URL used for the blurred background image. @default `imageSrc` */
1365
+ backgroundSrc?: string;
1366
+ /** Creator's name, rendered as the heading. */
1367
+ name: string;
1368
+ /** Smaller subtitle below the name (e.g. "GLOBAL POPSTAR"). Rendered uppercase in the brand colour. */
1369
+ tagline?: string;
1370
+ /**
1371
+ * Status label rendered as a pill overlapping the bottom of the cover image (e.g. "New Joiner").
1372
+ * Strings render with default green pill styling; pass a node for custom markup.
1373
+ */
1374
+ tag?: CreatorCoverSlot;
1375
+ /**
1376
+ * Primary call to action displayed below the title.
1377
+ */
1378
+ action?: React_2.ReactNode;
1379
+ /** When `true`, fades the bottom of the component to transparent and increases bottom padding to 64px. @default false */
1380
+ fadeBottom?: boolean;
1381
+ }
1382
+
1383
+ /** Slot that accepts a string (rendered as default styling) or a node for full control. */
1384
+ export declare type CreatorCoverSlot = string | React_2.ReactNode;
1385
+
1386
+ /**
1387
+ * A visual highlight tile showcasing a creator with an overlaid name and tagline.
1388
+ *
1389
+ * The tile renders a full-bleed image with a bottom gradient that ensures the
1390
+ * overlaid text remains legible regardless of the underlying photography.
1391
+ *
1392
+ * @example
1393
+ * ```tsx
1394
+ * <CreatorTile
1395
+ * imageSrc="https://example.com/creator.jpg"
1396
+ * imageAlt="Portrait of Jane Doe"
1397
+ * name="JANE DOE"
1398
+ * tagline="GLOBAL MUSIC ICON"
1399
+ * />
1400
+ * ```
1401
+ */
1402
+ export declare const CreatorTile: React_2.ForwardRefExoticComponent<CreatorTileProps & React_2.RefAttributes<HTMLDivElement>>;
1403
+
1404
+ /** Width-to-height ratio preset for the tile. */
1405
+ export declare type CreatorTileAspectRatio = "tall" | "medium" | "short";
1406
+
1407
+ export declare interface CreatorTileProps extends React_2.HTMLAttributes<HTMLDivElement> {
1408
+ /** Source URL of the creator's image. Rendered as the tile background. */
1409
+ imageSrc: string;
1410
+ /** Alt text for the creator image. Use an empty string for purely decorative imagery. */
1411
+ imageAlt?: string;
1412
+ /** Creator name shown as the prominent overlay heading. */
1413
+ name: React_2.ReactNode;
1414
+ /** Short tagline shown under the name in the brand accent color. */
1415
+ tagline?: React_2.ReactNode;
1416
+ /**
1417
+ * Width-to-height ratio preset.
1418
+ *
1419
+ * - `tall` – 1:2 narrow portrait
1420
+ * - `medium` – 2:3 classic poster (default)
1421
+ * - `short` – 4:5 closer to square
1422
+ *
1423
+ * @default "medium"
1424
+ */
1425
+ aspectRatio?: CreatorTileAspectRatio;
1426
+ }
1427
+
1254
1428
  /** A compact "×" cross icon (20 × 20). */
1255
1429
  export declare const CrossIcon: React_2.ForwardRefExoticComponent<React_2.SVGAttributes<SVGSVGElement> & {
1256
1430
  className?: string;
@@ -1269,6 +1443,55 @@ export declare const CrownIcon: React_2.ForwardRefExoticComponent<BaseIconProps
1269
1443
  /** Props for {@link CrownIcon}. See {@link BaseIconProps} for the shared shape. */
1270
1444
  export declare type CrownIconProps = BaseIconProps;
1271
1445
 
1446
+ /**
1447
+ * Cycles through a list of strings with a slide-in/slide-out animation. Lives
1448
+ * inline so it can sit inside divs, spans, buttons, or as a fake placeholder
1449
+ * overlay.
1450
+ *
1451
+ * @example
1452
+ * ```tsx
1453
+ * <CyclingText items={["Thinking", "Reading messages", "Drafting reply"]} />
1454
+ * ```
1455
+ */
1456
+ export declare const CyclingText: React_2.ForwardRefExoticComponent<CyclingTextProps & React_2.RefAttributes<HTMLSpanElement>>;
1457
+
1458
+ export declare interface CyclingTextProps extends Omit<React_2.HTMLAttributes<HTMLSpanElement>, "children"> {
1459
+ /** Strings to cycle through, in order. Cycles back to the first after the last. */
1460
+ items: readonly string[];
1461
+ /**
1462
+ * Milliseconds to wait after the previous transition finishes before starting the next one.
1463
+ * @default 2100
1464
+ */
1465
+ intervalMs?: number;
1466
+ /** Slide and cross-fade duration in milliseconds. @default 200 */
1467
+ transitionMs?: number;
1468
+ /** Direction the outgoing item slides. @default "up" */
1469
+ direction?: "up" | "down";
1470
+ /** When true, freezes on the current item — no further cycling until cleared. @default false */
1471
+ paused?: boolean;
1472
+ /**
1473
+ * How the wrapper sizes itself horizontally.
1474
+ * - `longest` reserves space for the longest item — no width jitter as items cycle.
1475
+ * - `current` shrinks/grows with each item, animating width between cycles.
1476
+ * @default "longest"
1477
+ */
1478
+ sizing?: CyclingTextSizing;
1479
+ /**
1480
+ * When `true`, updates are exposed to assistive technologies via `aria-live="polite"`.
1481
+ * Leave `false` for decorative or frequently changing copy so screen readers are not interrupted on every cycle.
1482
+ * @default false
1483
+ */
1484
+ announceChanges?: boolean;
1485
+ /**
1486
+ * Class applied to each visible label span (current + incoming). Use this for
1487
+ * effects that have to sit on the text element itself, e.g. `background-clip: text`.
1488
+ */
1489
+ labelClassName?: string;
1490
+ }
1491
+
1492
+ /** How the wrapper should be sized to accommodate variable-length items. */
1493
+ export declare type CyclingTextSizing = "longest" | "current";
1494
+
1272
1495
  /** Root component that manages open/close state for a dialog. */
1273
1496
  export declare const Dialog: React_2.FC<DialogPrimitive.DialogProps>;
1274
1497
 
package/dist/index.mjs CHANGED
@@ -20,6 +20,10 @@ import { ChatInput } from "./components/ChatInput/ChatInput.mjs";
20
20
  import { Checkbox } from "./components/Checkbox/Checkbox.mjs";
21
21
  import { Chip } from "./components/Chip/Chip.mjs";
22
22
  import { Count } from "./components/Count/Count.mjs";
23
+ import { CreatorCard } from "./components/CreatorCard/CreatorCard.mjs";
24
+ import { CreatorCover } from "./components/CreatorCover/CreatorCover.mjs";
25
+ import { CreatorTile } from "./components/CreatorTile/CreatorTile.mjs";
26
+ import { CyclingText } from "./components/CyclingText/CyclingText.mjs";
23
27
  import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogTitle, DialogTrigger } from "./components/Dialog/Dialog.mjs";
24
28
  import { Divider } from "./components/Divider/Divider.mjs";
25
29
  import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger } from "./components/Drawer/Drawer.mjs";
@@ -281,8 +285,12 @@ export {
281
285
  CompassIcon,
282
286
  CopyIcon,
283
287
  Count,
288
+ CreatorCard,
289
+ CreatorCover,
290
+ CreatorTile,
284
291
  CrossIcon,
285
292
  CrownIcon,
293
+ CyclingText,
286
294
  Dialog,
287
295
  DialogBody,
288
296
  DialogClose,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanvue/ui",
3
- "version": "2.13.0",
3
+ "version": "2.14.1",
4
4
  "description": "React component library built with Tailwind CSS for Fanvue ecosystem",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",