@jskit-ai/assistant-core 0.2.6 → 0.2.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/examples/conversation/package.json +5 -5
- package/package.json +18 -7
- package/src/client/browser.js +21 -0
- package/src/client/conversation/AssistantAttachmentQueue.vue +25 -108
- package/src/client/conversation/AssistantComposerActions.vue +1 -1
- package/src/client/conversation/AssistantConversationElement.vue +14 -52
- package/src/client/conversation/AssistantGoalControl.vue +18 -12
- package/src/client/conversation/AssistantPromptInput.vue +6 -91
- package/src/client/conversation/AssistantTranscript.css +505 -0
- package/src/client/conversation/AssistantTranscript.vue +24 -1197
- package/src/client/conversation/attachmentFiles.js +158 -0
- package/src/client/conversation/attachmentQueueItems.js +121 -0
- package/src/client/conversation/attachmentUploadRows.js +265 -0
- package/src/client/conversation/conversationDisplay.js +54 -0
- package/src/client/conversation/messageDelivery.js +13 -9
- package/src/client/conversation/retainedConversation.js +14 -3
- package/src/client/conversation/submitText.js +13 -2
- package/src/client/conversation/transcriptEntries.js +225 -0
- package/src/client/conversation/useAssistantAttachments.js +86 -388
- package/src/client/conversation/useAssistantQuestions.js +16 -3
- package/src/client/conversation/useAssistantSuggestions.js +16 -2
- package/src/client/conversation/useScrollToBottom.js +17 -19
- package/src/client/conversation/useTextareaAutoGrow.js +115 -0
- package/src/client/conversation/useTranscriptScrollFollow.js +525 -0
- package/src/client/lib/assistantApi.js +192 -161
- package/src/client/types.js +110 -0
- package/src/server/conversation/attachments.js +21 -6
- package/src/server/conversation/boundedToolLoop.js +1 -0
- package/src/server/conversation/claudeClient.js +71 -20
- package/src/server/conversation/claudeCommandRun.js +191 -0
- package/src/server/conversation/claudeHistory.js +7 -0
- package/src/server/conversation/claudeNativeTurn.js +708 -0
- package/src/server/conversation/claudeProcess.js +186 -112
- package/src/server/conversation/claudeProcessStart.js +214 -0
- package/src/server/conversation/claudePromptDelivery.js +183 -0
- package/src/server/conversation/claudeSessionCleanup.js +248 -0
- package/src/server/conversation/claudeTools.js +15 -3
- package/src/server/conversation/claudeTurn.js +212 -1388
- package/src/server/conversation/codexAccountReader.js +168 -0
- package/src/server/conversation/codexAuthPreflight.js +5 -4
- package/src/server/conversation/codexClient.js +18 -6
- package/src/server/conversation/codexConfiguration.js +8 -844
- package/src/server/conversation/codexConversationStops.js +377 -0
- package/src/server/conversation/codexConversationStore.js +119 -85
- package/src/server/conversation/codexConversationTurns.js +378 -0
- package/src/server/conversation/codexConversations.js +134 -866
- package/src/server/conversation/codexDetachedConversation.js +203 -0
- package/src/server/conversation/codexDetachedTurn.js +145 -104
- package/src/server/conversation/codexEvents.js +5 -200
- package/src/server/conversation/codexGoalCommands.js +14 -4
- package/src/server/conversation/codexHelperExecution.js +57 -57
- package/src/server/conversation/codexHelperThreadLedger.js +30 -288
- package/src/server/conversation/codexHelperThreadRecord.js +304 -0
- package/src/server/conversation/codexHelperThreadRecovery.js +54 -76
- package/src/server/conversation/codexHelperThreads.js +94 -93
- package/src/server/conversation/codexHistoryAdapter.js +13 -8
- package/src/server/conversation/codexIsolation.js +672 -0
- package/src/server/conversation/codexLiveItems.js +379 -0
- package/src/server/conversation/codexMessageCommands.js +68 -286
- package/src/server/conversation/codexMessageDelivery.js +46 -37
- package/src/server/conversation/codexModelCatalog.js +86 -7
- package/src/server/conversation/codexNotificationObserver.js +81 -88
- package/src/server/conversation/codexNotificationQueue.js +21 -10
- package/src/server/conversation/codexObservationControl.js +105 -89
- package/src/server/conversation/codexOutput.js +84 -419
- package/src/server/conversation/codexProcess.js +29 -1053
- package/src/server/conversation/codexProcessLeader.js +1 -0
- package/src/server/conversation/codexPromptDispatch.js +241 -0
- package/src/server/conversation/codexProvider.js +147 -1807
- package/src/server/conversation/codexProviderAuth.js +348 -0
- package/src/server/conversation/codexProviderInvalidation.js +371 -0
- package/src/server/conversation/codexProviderInventories.js +437 -0
- package/src/server/conversation/codexProviderOwner.js +149 -957
- package/src/server/conversation/codexProviderRelease.js +465 -0
- package/src/server/conversation/codexProviderSelection.js +26 -15
- package/src/server/conversation/codexProviderThreads.js +698 -0
- package/src/server/conversation/codexProviderTurns.js +453 -0
- package/src/server/conversation/codexReasoning.js +32 -23
- package/src/server/conversation/codexRenewalCommands.js +18 -6
- package/src/server/conversation/codexRenewalThreads.js +7 -22
- package/src/server/conversation/codexResultSettlement.js +70 -88
- package/src/server/conversation/codexRunJournal.js +91 -97
- package/src/server/conversation/codexRuntime.js +426 -0
- package/src/server/conversation/codexRuntimeInventory.js +113 -0
- package/src/server/conversation/codexRuntimeLifecycle.js +39 -13
- package/src/server/conversation/codexRuntimeStart.js +431 -0
- package/src/server/conversation/codexRuntimeStop.js +324 -0
- package/src/server/conversation/codexSessionCleanup.js +25 -10
- package/src/server/conversation/codexSessionReconciliation.js +21 -7
- package/src/server/conversation/codexThreadReadiness.js +49 -52
- package/src/server/conversation/codexThreadSnapshot.js +210 -0
- package/src/server/conversation/codexThreadStatus.js +48 -62
- package/src/server/conversation/codexTurn.js +171 -55
- package/src/server/conversation/codexTurnActivity.js +210 -0
- package/src/server/conversation/codexTurnControl.js +44 -48
- package/src/server/conversation/codexTurnEndings.js +610 -0
- package/src/server/conversation/codexTurnRecovery.js +97 -848
- package/src/server/conversation/codexTurnState.js +138 -111
- package/src/server/conversation/completedResponses.js +227 -0
- package/src/server/conversation/configuration.js +2 -2
- package/src/server/conversation/continuity.js +43 -6
- package/src/server/conversation/conversationDelivery.js +394 -0
- package/src/server/conversation/conversationEntries.js +365 -0
- package/src/server/conversation/conversationEvents.js +192 -0
- package/src/server/conversation/conversationGoals.js +187 -0
- package/src/server/conversation/conversationHandles.js +237 -0
- package/src/server/conversation/conversationReads.js +206 -0
- package/src/server/conversation/conversationRefusals.js +58 -0
- package/src/server/conversation/conversationReplacement.js +254 -0
- package/src/server/conversation/conversationSending.js +273 -0
- package/src/server/conversation/conversationStopping.js +121 -0
- package/src/server/conversation/conversationTurnDelivery.js +413 -0
- package/src/server/conversation/conversationTurns.js +511 -0
- package/src/server/conversation/deliveryTiming.js +25 -3
- package/src/server/conversation/fileStorage.js +11 -6
- package/src/server/conversation/hookBridge.js +14 -3
- package/src/server/conversation/index.js +1 -1
- package/src/server/conversation/localExecution.js +82 -625
- package/src/server/conversation/nativeCommandCallbacks.js +10 -0
- package/src/server/conversation/nativeConversationLifecycle.js +379 -0
- package/src/server/conversation/nativeHistoryExport.js +27 -18
- package/src/server/conversation/normalize.js +9 -0
- package/src/server/conversation/openCodeClient.js +295 -366
- package/src/server/conversation/openCodeNativeHistory.js +141 -0
- package/src/server/conversation/openCodeNativeSession.js +79 -0
- package/src/server/conversation/openCodeProcess.js +109 -53
- package/src/server/conversation/openCodeProcessOwner.js +565 -0
- package/src/server/conversation/openCodeRuntime.js +111 -1814
- package/src/server/conversation/openCodeSessionTurns.js +547 -0
- package/src/server/conversation/openCodeTemporaryConversations.js +394 -0
- package/src/server/conversation/openCodeTools.js +28 -14
- package/src/server/conversation/openCodeTurn.js +80 -74
- package/src/server/conversation/openCodeTurnMonitor.js +388 -0
- package/src/server/conversation/processIdentity.js +582 -0
- package/src/server/conversation/provider.js +21 -6
- package/src/server/conversation/providers/api.js +268 -107
- package/src/server/conversation/providers/claude.js +29 -6
- package/src/server/conversation/providers/claudeDriver.js +325 -250
- package/src/server/conversation/providers/codex.js +69 -33
- package/src/server/conversation/providers/codexDriver.js +503 -1081
- package/src/server/conversation/providers/codexDriverConnection.js +331 -0
- package/src/server/conversation/providers/codexDriverTurns.js +464 -0
- package/src/server/conversation/providers/opencode.js +30 -4
- package/src/server/conversation/providers/opencodeDriver.js +321 -659
- package/src/server/conversation/providers/opencodeStandalone.js +475 -0
- package/src/server/conversation/providers/scoped.js +64 -19
- package/src/server/conversation/runtime.js +171 -2863
- package/src/server/conversation/storage.js +91 -50
- package/src/server/conversation/streams.js +15 -2
- package/src/server/conversation/structuredOutput.js +7 -11
- package/src/server/conversation/systemPrompt.js +13 -1
- package/src/server/conversation/tools.js +47 -15
- package/src/server/conversation/transcript.js +49 -20
- package/src/server/hosts/claudeTurn.js +2 -4
- package/src/server/hosts/codexConfiguration.js +6 -8
- package/src/server/hosts/codexEvents.js +4 -2
- package/src/server/hosts/codexProcess.js +1 -1
- package/src/server/hosts/codexProvider.js +11 -9
- package/src/server/hosts/codexTurn.js +3 -3
- package/src/server/hosts/openCodeClient.js +4 -2
- package/src/server/index.js +0 -2
- package/src/server/lib/aiConnectionClient.js +35 -25
- package/src/server/lib/ndjson.js +1 -0
- package/src/server/lib/providers/anthropicClient.js +15 -6
- package/src/server/lib/providers/common.js +10 -6
- package/src/server/lib/providers/openAiCompatibleClient.js +40 -23
- package/src/server/lib/serviceToolCatalog.js +29 -283
- package/src/server/lib/serviceToolEntries.js +270 -0
- package/src/server/types.js +78 -0
- package/src/shared/assistantResource.js +0 -23
- package/src/shared/conversation/answerChoiceSugar.js +2 -14
- package/src/shared/conversation/messageInputSugar.js +18 -0
- package/src/shared/conversation/numberedQuestionSugar.js +6 -16
- package/src/shared/conversation/pagination.js +1 -1
- package/src/shared/conversation/questions.js +1 -0
- package/src/shared/conversation/streaming.js +1 -0
- package/src/shared/index.js +0 -1
- package/src/testing/conversationStorageContract.js +20 -0
- package/test/aiConnectionClient.test.js +42 -1
- package/test/apiConversationDriver.test.js +217 -38
- package/test/assistantBoundedToolLoop.test.js +1 -1
- package/test/claudeConversationSession.test.js +15 -11
- package/test/claudeInstructionResume.test.js +1 -1
- package/test/claudeProcess.test.js +9 -9
- package/test/claudeTurn.test.js +21 -8
- package/test/codexAccountChange.test.js +5 -3
- package/test/codexConversationSession.test.js +22 -21
- package/test/codexEvents.test.js +3 -1
- package/test/codexHelperDeletion.test.js +3 -7
- package/test/codexIsolation.test.js +6 -6
- package/test/codexModelCatalog.test.js +6 -7
- package/test/codexProcess.test.js +3 -3
- package/test/codexThreadSelection.test.js +4 -1
- package/test/codexTurn.test.js +29 -20
- package/test/conversationApiFacilities.test.js +11 -9
- package/test/conversationAttachments.test.js +3 -3
- package/test/conversationConfiguration.test.js +4 -4
- package/test/conversationNativeStorage.test.js +11 -10
- package/test/conversationReplacement.test.js +13 -13
- package/test/conversationRuntime.test.js +9 -5
- package/test/conversationSession.test.js +78 -22
- package/test/conversationTools.test.js +47 -26
- package/test/fileConversationStorage.test.js +10 -3
- package/test/fixtures/codexHelperThreadLedger.js +3 -3
- package/test/frameworkActions.test.js +33 -18
- package/test/localConversationExecution.test.js +4 -4
- package/test/localExecution.test.js +1 -1
- package/test/openCodeConnectionChange.test.js +3 -2
- package/test/openCodeRuntime.test.js +8 -7
- package/test/openCodeTools.test.js +1 -1
- package/test/opencodeConversationSession.test.js +4 -3
- package/test/serviceToolCatalog.test.js +3 -8
- package/src/server/lib/assistantCompletion.js +0 -190
- package/src/server/lib/assistantToolLoop.js +0 -259
|
@@ -2,7 +2,13 @@ import { computed, ref, toValue, watch } from "vue";
|
|
|
2
2
|
import { numberedQuestionSubmissionText, parseNumberedQuestionPrompt } from "../../shared/conversation/numberedQuestionSugar.js";
|
|
3
3
|
import { parseAnswerChoicePrompt } from "../../shared/conversation/answerChoiceSugar.js";
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Ordinary chat answer fields; the caller owns authorized message selection and delivery.
|
|
7
|
+
* @param {{
|
|
8
|
+
* message?: import("vue").MaybeRefOrGetter<string>,
|
|
9
|
+
* extraChoice?: import("vue").MaybeRefOrGetter<{ value: string, title?: string } | null>
|
|
10
|
+
* }} [options]
|
|
11
|
+
*/
|
|
6
12
|
function useAssistantQuestions({ message = "", extraChoice = null } = {}) {
|
|
7
13
|
const questionText = computed(() => String(toValue(message) || ""));
|
|
8
14
|
const answers = ref({});
|
|
@@ -69,8 +75,15 @@ function useAssistantQuestions({ message = "", extraChoice = null } = {}) {
|
|
|
69
75
|
choice.value = "";
|
|
70
76
|
});
|
|
71
77
|
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
function setAnswers(value) {
|
|
79
|
+
answers.value = value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function setChoice(value) {
|
|
83
|
+
choice.value = value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return { questions, selectItems, choices, answers, choice, active, capture, markSubmitted, dismiss, reset, setAnswers, setChoice };
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
export { useAssistantQuestions };
|
|
@@ -3,11 +3,24 @@ import { useJskitText } from "../i18n.js";
|
|
|
3
3
|
|
|
4
4
|
const { serverMessage } = useJskitText();
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Suggestion requests use an application-supplied agent; credentials stay on its server.
|
|
8
|
+
* @param {{
|
|
9
|
+
* active?: import("vue").MaybeRefOrGetter<boolean>,
|
|
10
|
+
* requestKey?: import("vue").MaybeRefOrGetter<unknown>,
|
|
11
|
+
* draft?: import("vue").MaybeRefOrGetter<string>,
|
|
12
|
+
* configuration?: import("vue").MaybeRefOrGetter<object>,
|
|
13
|
+
* generate?: import("vue").MaybeRef<((input: { draft: string, configuration: object, signal: AbortSignal }) =>
|
|
14
|
+
* Promise<{ label: string, prompt: string }[]>) | null>,
|
|
15
|
+
* onSelect?: (prompt: string) => boolean | void,
|
|
16
|
+
* debounceMs?: import("vue").MaybeRefOrGetter<number>,
|
|
17
|
+
* minIntervalMs?: import("vue").MaybeRefOrGetter<number>
|
|
18
|
+
* }} options
|
|
19
|
+
*/
|
|
7
20
|
export function useAssistantSuggestions({
|
|
8
21
|
active = true, requestKey = "", draft = "", configuration = {},
|
|
9
22
|
generate, onSelect = () => false, debounceMs = 750, minIntervalMs = 0
|
|
10
|
-
}
|
|
23
|
+
}) {
|
|
11
24
|
const items = ref([]);
|
|
12
25
|
const loading = ref(false);
|
|
13
26
|
const preview = ref("");
|
|
@@ -17,6 +30,7 @@ export function useAssistantSuggestions({
|
|
|
17
30
|
const currentDraft = computed(() => String(toValue(draft) ?? "").trim());
|
|
18
31
|
const configurationKey = computed(() => JSON.stringify(toValue(configuration) ?? {}));
|
|
19
32
|
const key = computed(() => JSON.stringify([toValue(requestKey), currentDraft.value, configurationKey.value]));
|
|
33
|
+
// readable-check: allow method-probe - optional operation: without a generator, or while its ref holds none, no suggestions are requested
|
|
20
34
|
const eligible = computed(() => toValue(active) !== false && typeof unref(generate) === "function" && dismissedKey.value !== key.value);
|
|
21
35
|
const visible = computed(() => eligible.value && (loading.value || items.value.length > 0));
|
|
22
36
|
let timer;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { nextTick, onBeforeUnmount, unref } from "vue";
|
|
2
|
+
import { hasWindowFunction, waitForLayoutFrame } from "../browser.js";
|
|
2
3
|
|
|
3
4
|
const DEFAULT_SETTLE_DELAYS_MS = [0, 80];
|
|
4
5
|
|
|
@@ -6,25 +7,12 @@ function readElement(value) {
|
|
|
6
7
|
return unref(value) || null;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
|
-
function hasWindowTimer(name) {
|
|
10
|
-
return typeof window !== "undefined" && typeof window[name] === "function";
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function waitForLayoutFrame() {
|
|
14
|
-
if (typeof window === "undefined" || typeof window.requestAnimationFrame !== "function") {
|
|
15
|
-
return Promise.resolve();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return new Promise((resolve) => {
|
|
19
|
-
window.requestAnimationFrame(resolve);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
10
|
function normalizedScrollBehavior(value = "") {
|
|
24
11
|
return value === "smooth" ? "smooth" : "auto";
|
|
25
12
|
}
|
|
26
13
|
|
|
27
14
|
function scrollElementToBottom(targetElement, behavior = "auto") {
|
|
15
|
+
// readable-check: allow method-probe - platform object: an older browser's elements have no scrollTo()
|
|
28
16
|
if (behavior === "smooth" && typeof targetElement.scrollTo === "function") {
|
|
29
17
|
targetElement.scrollTo({
|
|
30
18
|
behavior,
|
|
@@ -35,13 +23,23 @@ function scrollElementToBottom(targetElement, behavior = "auto") {
|
|
|
35
23
|
targetElement.scrollTop = targetElement.scrollHeight;
|
|
36
24
|
}
|
|
37
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Scrolls `target` to its end now, after the next layout, and again after each settle delay, while `enabled`.
|
|
28
|
+
* @param {{
|
|
29
|
+
* anchor?: import("vue").MaybeRef<Element | null>,
|
|
30
|
+
* enabled?: import("vue").MaybeRef<boolean>,
|
|
31
|
+
* scrollAnchorIntoView?: boolean,
|
|
32
|
+
* settleDelaysMs?: number[],
|
|
33
|
+
* target: import("vue").MaybeRef<Element | null>
|
|
34
|
+
* }} options
|
|
35
|
+
*/
|
|
38
36
|
function useScrollToBottom({
|
|
39
37
|
anchor = null,
|
|
40
38
|
enabled = true,
|
|
41
39
|
scrollAnchorIntoView = true,
|
|
42
40
|
settleDelaysMs = DEFAULT_SETTLE_DELAYS_MS,
|
|
43
41
|
target
|
|
44
|
-
}
|
|
42
|
+
}) {
|
|
45
43
|
const scheduledTimers = new Set();
|
|
46
44
|
let disposed = false;
|
|
47
45
|
let scheduleVersion = 0;
|
|
@@ -51,7 +49,7 @@ function useScrollToBottom({
|
|
|
51
49
|
}
|
|
52
50
|
|
|
53
51
|
function clearScheduledTimers() {
|
|
54
|
-
if (
|
|
52
|
+
if (hasWindowFunction("clearTimeout")) {
|
|
55
53
|
scheduledTimers.forEach((timer) => {
|
|
56
54
|
window.clearTimeout(timer);
|
|
57
55
|
});
|
|
@@ -64,7 +62,7 @@ function useScrollToBottom({
|
|
|
64
62
|
clearScheduledTimers();
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
function scrollNow(options
|
|
65
|
+
function scrollNow(options) {
|
|
68
66
|
if (disposed || !isEnabled()) {
|
|
69
67
|
return;
|
|
70
68
|
}
|
|
@@ -83,7 +81,7 @@ function useScrollToBottom({
|
|
|
83
81
|
if (behavior === "smooth") {
|
|
84
82
|
anchorOptions.behavior = behavior;
|
|
85
83
|
}
|
|
86
|
-
readElement(anchor)?.scrollIntoView
|
|
84
|
+
readElement(anchor)?.scrollIntoView(anchorOptions);
|
|
87
85
|
}
|
|
88
86
|
scrollElementToBottom(targetElement, behavior);
|
|
89
87
|
}
|
|
@@ -93,7 +91,7 @@ function useScrollToBottom({
|
|
|
93
91
|
disposed ||
|
|
94
92
|
version !== scheduleVersion ||
|
|
95
93
|
!isEnabled() ||
|
|
96
|
-
!
|
|
94
|
+
!hasWindowFunction("setTimeout")
|
|
97
95
|
) {
|
|
98
96
|
return;
|
|
99
97
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { onBeforeUnmount, onMounted, watch } from "vue";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Grows the prompt's textarea with its text, up to its CSS max-height, after each change of its model value,
|
|
5
|
+
* placeholder, rows or density and each change of its width. preserveHeightForNextModelValue() keeps the current
|
|
6
|
+
* height through the next model value change; typing ends that hold.
|
|
7
|
+
* @param {{
|
|
8
|
+
* autoGrow: boolean,
|
|
9
|
+
* density: string,
|
|
10
|
+
* modelValue: string,
|
|
11
|
+
* placeholder: string,
|
|
12
|
+
* placeholderAffectsHeight: boolean,
|
|
13
|
+
* rows: number | string
|
|
14
|
+
* }} props The prompt input's props.
|
|
15
|
+
* @param {import("vue").Ref<HTMLTextAreaElement | null>} textareaRef
|
|
16
|
+
*/
|
|
17
|
+
function useTextareaAutoGrow(props, textareaRef) {
|
|
18
|
+
let resizeFrame = 0;
|
|
19
|
+
let resizeObserver = null;
|
|
20
|
+
let preserveHeightForNextModelValueChange = false;
|
|
21
|
+
|
|
22
|
+
function resizeTextarea() {
|
|
23
|
+
if (!props.autoGrow) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const textarea = textareaRef.value;
|
|
27
|
+
if (!textarea) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (!props.placeholderAffectsHeight && !textarea.value) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const style = window.getComputedStyle(textarea);
|
|
34
|
+
const minHeight = Number.parseFloat(style.minHeight) || 0;
|
|
35
|
+
const maxHeight = Number.parseFloat(style.maxHeight) || Number.POSITIVE_INFINITY;
|
|
36
|
+
textarea.style.height = "auto";
|
|
37
|
+
const contentHeight = Math.max(textarea.scrollHeight, minHeight);
|
|
38
|
+
const targetHeight = Math.min(contentHeight, maxHeight);
|
|
39
|
+
textarea.style.height = `${targetHeight}px`;
|
|
40
|
+
textarea.style.overflowY = contentHeight > targetHeight + 1 ? "auto" : "hidden";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function queueResizeTextarea() {
|
|
44
|
+
if (!props.autoGrow || typeof window === "undefined") {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (resizeFrame) return;
|
|
48
|
+
resizeFrame = window.requestAnimationFrame(() => {
|
|
49
|
+
resizeFrame = 0;
|
|
50
|
+
resizeTextarea();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function preserveHeightForNextModelValue() {
|
|
55
|
+
const textarea = textareaRef.value;
|
|
56
|
+
if (!props.autoGrow || !textarea) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (resizeFrame) {
|
|
60
|
+
window.cancelAnimationFrame(resizeFrame);
|
|
61
|
+
resizeFrame = 0;
|
|
62
|
+
}
|
|
63
|
+
preserveHeightForNextModelValueChange = true;
|
|
64
|
+
textarea.style.height = `${textarea.getBoundingClientRect().height}px`;
|
|
65
|
+
textarea.style.overflowY = "auto";
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Typing writes the model value itself, so its next change resizes the textarea again. */
|
|
70
|
+
function releasePreservedHeight() {
|
|
71
|
+
preserveHeightForNextModelValueChange = false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
onMounted(() => {
|
|
75
|
+
queueResizeTextarea();
|
|
76
|
+
let lastWidth = 0;
|
|
77
|
+
resizeObserver = new ResizeObserver(([entry]) => {
|
|
78
|
+
// Height changes are our own output. Only width changes need another layout.
|
|
79
|
+
const width = entry.contentRect.width;
|
|
80
|
+
if (width !== lastWidth) {
|
|
81
|
+
lastWidth = width;
|
|
82
|
+
queueResizeTextarea();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
resizeObserver.observe(textareaRef.value);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
onBeforeUnmount(() => {
|
|
89
|
+
resizeObserver?.disconnect();
|
|
90
|
+
if (resizeFrame && typeof window !== "undefined") {
|
|
91
|
+
window.cancelAnimationFrame(resizeFrame);
|
|
92
|
+
resizeFrame = 0;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
watch(() => [
|
|
97
|
+
props.autoGrow,
|
|
98
|
+
props.modelValue,
|
|
99
|
+
props.placeholder,
|
|
100
|
+
props.placeholderAffectsHeight,
|
|
101
|
+
props.rows,
|
|
102
|
+
props.density
|
|
103
|
+
], (values, previousValues = []) => {
|
|
104
|
+
const modelValueChanged = values[1] !== previousValues[1];
|
|
105
|
+
if (preserveHeightForNextModelValueChange && modelValueChanged) {
|
|
106
|
+
preserveHeightForNextModelValueChange = false;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
queueResizeTextarea();
|
|
110
|
+
}, { flush: "post" });
|
|
111
|
+
|
|
112
|
+
return { preserveHeightForNextModelValue, queueResizeTextarea, releasePreservedHeight };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export { useTextareaAutoGrow };
|