@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.
- package/dist/cjs/components/ChatInput/ChatInput.cjs +75 -27
- package/dist/cjs/components/ChatInput/ChatInput.cjs.map +1 -1
- package/dist/cjs/components/CreatorCard/CreatorCard.cjs +81 -0
- package/dist/cjs/components/CreatorCard/CreatorCard.cjs.map +1 -0
- package/dist/cjs/components/CreatorCover/CreatorCover.cjs +83 -0
- package/dist/cjs/components/CreatorCover/CreatorCover.cjs.map +1 -0
- package/dist/cjs/components/CreatorTile/CreatorTile.cjs +64 -0
- package/dist/cjs/components/CreatorTile/CreatorTile.cjs.map +1 -0
- package/dist/cjs/components/CyclingText/CyclingText.cjs +137 -0
- package/dist/cjs/components/CyclingText/CyclingText.cjs.map +1 -0
- package/dist/cjs/components/CyclingText/useCyclingCycle.cjs +212 -0
- package/dist/cjs/components/CyclingText/useCyclingCycle.cjs.map +1 -0
- package/dist/cjs/components/CyclingText/useCyclingTextTrackWidth.cjs +55 -0
- package/dist/cjs/components/CyclingText/useCyclingTextTrackWidth.cjs.map +1 -0
- package/dist/cjs/components/CyclingText/usePageVisibility.cjs +38 -0
- package/dist/cjs/components/CyclingText/usePageVisibility.cjs.map +1 -0
- package/dist/cjs/components/CyclingText/usePrefersReducedMotion.cjs +39 -0
- package/dist/cjs/components/CyclingText/usePrefersReducedMotion.cjs.map +1 -0
- package/dist/cjs/index.cjs +8 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/ChatInput/ChatInput.mjs +75 -27
- package/dist/components/ChatInput/ChatInput.mjs.map +1 -1
- package/dist/components/CreatorCard/CreatorCard.mjs +64 -0
- package/dist/components/CreatorCard/CreatorCard.mjs.map +1 -0
- package/dist/components/CreatorCover/CreatorCover.mjs +66 -0
- package/dist/components/CreatorCover/CreatorCover.mjs.map +1 -0
- package/dist/components/CreatorTile/CreatorTile.mjs +47 -0
- package/dist/components/CreatorTile/CreatorTile.mjs.map +1 -0
- package/dist/components/CyclingText/CyclingText.mjs +120 -0
- package/dist/components/CyclingText/CyclingText.mjs.map +1 -0
- package/dist/components/CyclingText/useCyclingCycle.mjs +195 -0
- package/dist/components/CyclingText/useCyclingCycle.mjs.map +1 -0
- package/dist/components/CyclingText/useCyclingTextTrackWidth.mjs +38 -0
- package/dist/components/CyclingText/useCyclingTextTrackWidth.mjs.map +1 -0
- package/dist/components/CyclingText/usePageVisibility.mjs +21 -0
- package/dist/components/CyclingText/usePageVisibility.mjs.map +1 -0
- package/dist/components/CyclingText/usePrefersReducedMotion.mjs +22 -0
- package/dist/components/CyclingText/usePrefersReducedMotion.mjs.map +1 -0
- package/dist/index.d.ts +223 -0
- package/dist/index.mjs +8 -0
- package/dist/index.mjs.map +1 -1
- 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,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|