composeai 0.1.7 → 0.1.8
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/index.cjs +126 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -1
- package/dist/index.d.ts +55 -1
- package/dist/index.js +126 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/composer.css +31 -0
package/dist/index.cjs
CHANGED
|
@@ -802,6 +802,7 @@ function useComposerContext() {
|
|
|
802
802
|
}
|
|
803
803
|
function EditorShell({
|
|
804
804
|
placeholder,
|
|
805
|
+
animated,
|
|
805
806
|
mode,
|
|
806
807
|
variant,
|
|
807
808
|
multiline,
|
|
@@ -820,7 +821,11 @@ function EditorShell({
|
|
|
820
821
|
const editor = slotProps("editor", editorClass, classNames, sx);
|
|
821
822
|
const editorResolved = resolveSx(sx?.editor);
|
|
822
823
|
const placeholderBase = mirrorEditorPadding(editorResolved);
|
|
823
|
-
const placeholderClass =
|
|
824
|
+
const placeholderClass = cn(
|
|
825
|
+
isCompact ? "composer-placeholder composer-placeholder--compact" : multiline ? "composer-placeholder composer-placeholder--multiline" : "composer-placeholder composer-placeholder--inline",
|
|
826
|
+
// Adds the blinking caret after the typewriter text.
|
|
827
|
+
animated && "composer-placeholder--animated"
|
|
828
|
+
);
|
|
824
829
|
const placeholderProps = slotProps(
|
|
825
830
|
"placeholder",
|
|
826
831
|
placeholderClass,
|
|
@@ -4929,6 +4934,107 @@ function useComposerHandle(ref, onSubmit) {
|
|
|
4929
4934
|
};
|
|
4930
4935
|
}, [editor, ref, onSubmit, addFiles]);
|
|
4931
4936
|
}
|
|
4937
|
+
var DEFAULT_TIMING = {
|
|
4938
|
+
typeSpeed: 55,
|
|
4939
|
+
deleteSpeed: 28,
|
|
4940
|
+
holdDuration: 1800,
|
|
4941
|
+
pauseDuration: 450
|
|
4942
|
+
};
|
|
4943
|
+
function useAnimatedPlaceholder(phrases, enabled, options) {
|
|
4944
|
+
const [state, setState] = react.useState({
|
|
4945
|
+
text: "",
|
|
4946
|
+
active: true
|
|
4947
|
+
});
|
|
4948
|
+
const optsRef = react.useRef({});
|
|
4949
|
+
optsRef.current = options ?? {};
|
|
4950
|
+
const active = enabled && Array.isArray(phrases) && phrases.length > 0;
|
|
4951
|
+
const key = active ? phrases.join("\u241F") : "";
|
|
4952
|
+
const loop = !!options?.loop;
|
|
4953
|
+
const phrasesRef = react.useRef(phrases);
|
|
4954
|
+
phrasesRef.current = phrases;
|
|
4955
|
+
react.useEffect(() => {
|
|
4956
|
+
if (!active) {
|
|
4957
|
+
setState({ text: "", active: true });
|
|
4958
|
+
return;
|
|
4959
|
+
}
|
|
4960
|
+
const list = phrasesRef.current;
|
|
4961
|
+
const lastIdx = list.length - 1;
|
|
4962
|
+
const reduceMotion = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
4963
|
+
if (reduceMotion) {
|
|
4964
|
+
setState({ text: list[0], active: false });
|
|
4965
|
+
return;
|
|
4966
|
+
}
|
|
4967
|
+
let timer;
|
|
4968
|
+
let phraseIdx = 0;
|
|
4969
|
+
let charIdx = 0;
|
|
4970
|
+
let phase = "typing";
|
|
4971
|
+
const tick = () => {
|
|
4972
|
+
const timing = { ...DEFAULT_TIMING, ...optsRef.current };
|
|
4973
|
+
const { typeSpeed, deleteSpeed, holdDuration, pauseDuration } = timing;
|
|
4974
|
+
const settleTo = optsRef.current.settleTo;
|
|
4975
|
+
const current = list[phraseIdx];
|
|
4976
|
+
const isLast = phraseIdx === lastIdx;
|
|
4977
|
+
switch (phase) {
|
|
4978
|
+
case "typing": {
|
|
4979
|
+
charIdx += 1;
|
|
4980
|
+
setState({ text: current.slice(0, charIdx), active: true });
|
|
4981
|
+
if (charIdx >= current.length) {
|
|
4982
|
+
phase = "holding";
|
|
4983
|
+
timer = setTimeout(tick, holdDuration);
|
|
4984
|
+
} else {
|
|
4985
|
+
timer = setTimeout(tick, typeSpeed);
|
|
4986
|
+
}
|
|
4987
|
+
break;
|
|
4988
|
+
}
|
|
4989
|
+
case "holding": {
|
|
4990
|
+
if (!loop && isLast) {
|
|
4991
|
+
if (settleTo !== void 0) {
|
|
4992
|
+
phase = "settling";
|
|
4993
|
+
timer = setTimeout(tick, deleteSpeed);
|
|
4994
|
+
} else {
|
|
4995
|
+
setState({ text: current, active: false });
|
|
4996
|
+
}
|
|
4997
|
+
} else {
|
|
4998
|
+
phase = "deleting";
|
|
4999
|
+
timer = setTimeout(tick, deleteSpeed);
|
|
5000
|
+
}
|
|
5001
|
+
break;
|
|
5002
|
+
}
|
|
5003
|
+
case "deleting": {
|
|
5004
|
+
charIdx -= 1;
|
|
5005
|
+
setState({ text: current.slice(0, Math.max(0, charIdx)), active: true });
|
|
5006
|
+
if (charIdx <= 0) {
|
|
5007
|
+
phase = "pausing";
|
|
5008
|
+
timer = setTimeout(tick, pauseDuration);
|
|
5009
|
+
} else {
|
|
5010
|
+
timer = setTimeout(tick, deleteSpeed);
|
|
5011
|
+
}
|
|
5012
|
+
break;
|
|
5013
|
+
}
|
|
5014
|
+
case "pausing": {
|
|
5015
|
+
phraseIdx = phraseIdx >= lastIdx ? 0 : phraseIdx + 1;
|
|
5016
|
+
charIdx = 0;
|
|
5017
|
+
phase = "typing";
|
|
5018
|
+
timer = setTimeout(tick, typeSpeed);
|
|
5019
|
+
break;
|
|
5020
|
+
}
|
|
5021
|
+
case "settling": {
|
|
5022
|
+
charIdx -= 1;
|
|
5023
|
+
if (charIdx <= 0) {
|
|
5024
|
+
setState({ text: settleTo ?? "", active: false });
|
|
5025
|
+
} else {
|
|
5026
|
+
setState({ text: current.slice(0, charIdx), active: true });
|
|
5027
|
+
timer = setTimeout(tick, deleteSpeed);
|
|
5028
|
+
}
|
|
5029
|
+
break;
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
};
|
|
5033
|
+
timer = setTimeout(tick, DEFAULT_TIMING.typeSpeed);
|
|
5034
|
+
return () => clearTimeout(timer);
|
|
5035
|
+
}, [active, key, loop]);
|
|
5036
|
+
return active ? state : null;
|
|
5037
|
+
}
|
|
4932
5038
|
|
|
4933
5039
|
// src/internal/shortcut.ts
|
|
4934
5040
|
var MODIFIERS = /* @__PURE__ */ new Set([
|
|
@@ -5006,6 +5112,7 @@ function matchesShortcut(parsed, event) {
|
|
|
5006
5112
|
var Composer = react.forwardRef(function Composer2(props, ref) {
|
|
5007
5113
|
const {
|
|
5008
5114
|
placeholder = "Send a message\u2026",
|
|
5115
|
+
animatedPlaceholder,
|
|
5009
5116
|
onSend,
|
|
5010
5117
|
onStop,
|
|
5011
5118
|
isStreaming,
|
|
@@ -5035,6 +5142,7 @@ var Composer = react.forwardRef(function Composer2(props, ref) {
|
|
|
5035
5142
|
attachmentOptions,
|
|
5036
5143
|
dir
|
|
5037
5144
|
} = props;
|
|
5145
|
+
const hasPlaceholder = props.placeholder != null;
|
|
5038
5146
|
const tokenStyle = react.useMemo(() => {
|
|
5039
5147
|
const derived = color ? deriveColorTokens(color) : null;
|
|
5040
5148
|
if (!derived && !tokens) return void 0;
|
|
@@ -5078,6 +5186,8 @@ var Composer = react.forwardRef(function Composer2(props, ref) {
|
|
|
5078
5186
|
ComposerCard,
|
|
5079
5187
|
{
|
|
5080
5188
|
placeholder,
|
|
5189
|
+
animatedPlaceholder,
|
|
5190
|
+
hasPlaceholder,
|
|
5081
5191
|
initialValue,
|
|
5082
5192
|
handleRef: ref,
|
|
5083
5193
|
onSend,
|
|
@@ -5115,6 +5225,8 @@ var RICH_NODES = [
|
|
|
5115
5225
|
var PLAIN_NODES = [MentionNode];
|
|
5116
5226
|
function ComposerCard({
|
|
5117
5227
|
placeholder,
|
|
5228
|
+
animatedPlaceholder,
|
|
5229
|
+
hasPlaceholder,
|
|
5118
5230
|
initialValue,
|
|
5119
5231
|
handleRef,
|
|
5120
5232
|
onSend,
|
|
@@ -5176,6 +5288,8 @@ function ComposerCard({
|
|
|
5176
5288
|
ComposerInner,
|
|
5177
5289
|
{
|
|
5178
5290
|
placeholder,
|
|
5291
|
+
animatedPlaceholder,
|
|
5292
|
+
hasPlaceholder,
|
|
5179
5293
|
mode,
|
|
5180
5294
|
variant,
|
|
5181
5295
|
multiline,
|
|
@@ -5196,6 +5310,8 @@ function ComposerCard({
|
|
|
5196
5310
|
}
|
|
5197
5311
|
function ComposerInner({
|
|
5198
5312
|
placeholder,
|
|
5313
|
+
animatedPlaceholder,
|
|
5314
|
+
hasPlaceholder,
|
|
5199
5315
|
mode,
|
|
5200
5316
|
variant,
|
|
5201
5317
|
multiline,
|
|
@@ -5326,6 +5442,13 @@ function ComposerInner({
|
|
|
5326
5442
|
});
|
|
5327
5443
|
}, [editor, registerRunPrompt, submit]);
|
|
5328
5444
|
const isCompact = variant === "compact";
|
|
5445
|
+
const animatedPhrases = Array.isArray(animatedPlaceholder) ? animatedPlaceholder : animatedPlaceholder?.phrases;
|
|
5446
|
+
const animatedLoop = Array.isArray(animatedPlaceholder) ? false : !!animatedPlaceholder?.loop;
|
|
5447
|
+
const animatedFrame = useAnimatedPlaceholder(animatedPhrases, !hasText, {
|
|
5448
|
+
loop: animatedLoop,
|
|
5449
|
+
settleTo: hasPlaceholder ? placeholder : void 0
|
|
5450
|
+
});
|
|
5451
|
+
const effectivePlaceholder = animatedFrame?.text ?? placeholder;
|
|
5329
5452
|
const mermaidActive = multiline && mode === "markdown" && !!features.mermaid;
|
|
5330
5453
|
const toolbarSlot = /* @__PURE__ */ jsxRuntime.jsx(Toolbar, { extras: toolbarExtras, variant, submit });
|
|
5331
5454
|
const sendButton = /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -5349,7 +5472,8 @@ function ComposerInner({
|
|
|
5349
5472
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5350
5473
|
EditorShell,
|
|
5351
5474
|
{
|
|
5352
|
-
placeholder,
|
|
5475
|
+
placeholder: effectivePlaceholder,
|
|
5476
|
+
animated: animatedFrame?.active ?? false,
|
|
5353
5477
|
mode,
|
|
5354
5478
|
variant,
|
|
5355
5479
|
multiline,
|