@kodaris/krubble-app-components 1.0.101 → 1.0.103
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/chatbot.d.ts +10 -0
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +128 -43
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +128 -43
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +97 -50
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +128 -43
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +93 -46
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/package.json +1 -1
package/dist/krubble-app.umd.js
CHANGED
|
@@ -5798,6 +5798,31 @@
|
|
|
5798
5798
|
this._skillBrowseQuery = '';
|
|
5799
5799
|
/** True while the mic is live and speech is being transcribed into the composer. */
|
|
5800
5800
|
this._isDictating = false;
|
|
5801
|
+
/**
|
|
5802
|
+
* Close the `/` skill menu when the click lands outside it.
|
|
5803
|
+
*
|
|
5804
|
+
* Bound at the document because a click anywhere — including outside this
|
|
5805
|
+
* component entirely — should dismiss the menu. `composedPath()` rather than
|
|
5806
|
+
* `e.target` since the menu lives in this component's shadow root, where
|
|
5807
|
+
* `target` on a document listener is retargeted to the host element and every
|
|
5808
|
+
* inside click would look like an outside one.
|
|
5809
|
+
*/
|
|
5810
|
+
this._handleDocumentClick = (e) => {
|
|
5811
|
+
if (!this._skillMenuOpened) {
|
|
5812
|
+
return;
|
|
5813
|
+
}
|
|
5814
|
+
// Excluded: the textarea, since clicking it keeps editing the same `/` command
|
|
5815
|
+
// and dismissing there would fight the user still typing it; and the plus
|
|
5816
|
+
// button, which owns the menu's open/close itself. The plus exclusion matters
|
|
5817
|
+
// in both directions — this listener runs after the button's own handler, so
|
|
5818
|
+
// without it a click that just opened the menu would immediately close it
|
|
5819
|
+
// again, and a click meant to toggle it shut would be double-handled.
|
|
5820
|
+
const path = e.composedPath();
|
|
5821
|
+
if (path.some((el) => el instanceof HTMLElement && (el.classList.contains('skill-menu') || el.classList.contains('input') || el.classList.contains('input-plus')))) {
|
|
5822
|
+
return;
|
|
5823
|
+
}
|
|
5824
|
+
this._skillMenuOpened = false;
|
|
5825
|
+
};
|
|
5801
5826
|
this._handleMouseMove = (e) => {
|
|
5802
5827
|
if (this._isDragging) {
|
|
5803
5828
|
let newLeft = this._dragStartLeft + (e.clientX - this._dragStartX);
|
|
@@ -5941,6 +5966,7 @@
|
|
|
5941
5966
|
this.opened = true;
|
|
5942
5967
|
}
|
|
5943
5968
|
this._restoreState();
|
|
5969
|
+
document.addEventListener('click', this._handleDocumentClick);
|
|
5944
5970
|
}
|
|
5945
5971
|
disconnectedCallback() {
|
|
5946
5972
|
super.disconnectedCallback();
|
|
@@ -5950,6 +5976,7 @@
|
|
|
5950
5976
|
}
|
|
5951
5977
|
document.removeEventListener('mousemove', this._handleMouseMove);
|
|
5952
5978
|
document.removeEventListener('mouseup', this._handleMouseUp);
|
|
5979
|
+
document.removeEventListener('click', this._handleDocumentClick);
|
|
5953
5980
|
// Release the mic if the chatbot is torn down mid-dictation — otherwise the
|
|
5954
5981
|
// recognizer keeps the browser's recording indicator lit with nothing to
|
|
5955
5982
|
// transcribe into. abort() (not stop()) since the discarded text has nowhere to go.
|
|
@@ -6171,7 +6198,12 @@
|
|
|
6171
6198
|
}
|
|
6172
6199
|
const state = JSON.parse(raw);
|
|
6173
6200
|
// Draft text and the debug drawer are persisted for all variants.
|
|
6174
|
-
|
|
6201
|
+
// A lone `/` is dropped — it's the in-progress half of a menu interaction,
|
|
6202
|
+
// not a draft, and restoring it would revive a stale menu the user never
|
|
6203
|
+
// used. Anything with an actual command after the slash (`/code`, `/code do
|
|
6204
|
+
// the thing`) is a real draft and restores normally. Trimmed before testing
|
|
6205
|
+
// so a stray space around the slash doesn't defeat the check.
|
|
6206
|
+
if (typeof state.message === 'string' && state.message.trim() !== '/') {
|
|
6175
6207
|
this._inputValue = state.message;
|
|
6176
6208
|
}
|
|
6177
6209
|
this._debugPanelOpen = state.debugPanelOpen === 'true';
|
|
@@ -6719,6 +6751,15 @@
|
|
|
6719
6751
|
// the menu interaction, and the picker is a separate window so the menu would
|
|
6720
6752
|
// otherwise linger open behind it (and after a file is chosen).
|
|
6721
6753
|
this._skillMenuOpened = false;
|
|
6754
|
+
// A lone `/` was only the means of reaching this action, so it shouldn't be
|
|
6755
|
+
// left behind in the composer once the picker opens. Nothing else is touched:
|
|
6756
|
+
// a real command (`/code`) stays because `/code` plus an attachment is a valid
|
|
6757
|
+
// invocation, and the plus button reaches this same method with an arbitrary
|
|
6758
|
+
// draft in the composer, which must survive.
|
|
6759
|
+
if (this._inputValue.trim() === '/') {
|
|
6760
|
+
this._inputValue = '';
|
|
6761
|
+
this._saveState();
|
|
6762
|
+
}
|
|
6722
6763
|
this._pendingAttachAnalyze = aiAnalyze;
|
|
6723
6764
|
this._fileInputEl?.click();
|
|
6724
6765
|
}
|
|
@@ -8000,29 +8041,53 @@
|
|
|
8000
8041
|
@paste=${this._handlePaste}
|
|
8001
8042
|
></textarea>
|
|
8002
8043
|
${window.SpeechRecognition || window.webkitSpeechRecognition ? b `
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
@click=${this._handleMicClick}
|
|
8010
|
-
>
|
|
8011
|
-
<svg
|
|
8012
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
8013
|
-
viewBox="0 0 24 24"
|
|
8014
|
-
fill="none"
|
|
8015
|
-
stroke="currentColor"
|
|
8016
|
-
stroke-width="1.75"
|
|
8017
|
-
stroke-linecap="round"
|
|
8018
|
-
stroke-linejoin="round"
|
|
8019
|
-
class="mic-icon"
|
|
8044
|
+
${this._isDictating ? b `
|
|
8045
|
+
<button
|
|
8046
|
+
class="mic-stop"
|
|
8047
|
+
title="Stop dictation"
|
|
8048
|
+
aria-label="Stop dictation"
|
|
8049
|
+
@click=${this._handleMicClick}
|
|
8020
8050
|
>
|
|
8021
|
-
<
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8051
|
+
<svg
|
|
8052
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8053
|
+
fill="currentColor"
|
|
8054
|
+
viewBox="0 0 24 24"
|
|
8055
|
+
class="mic-stop-icon"
|
|
8056
|
+
aria-hidden="true"
|
|
8057
|
+
>
|
|
8058
|
+
<rect
|
|
8059
|
+
x="6"
|
|
8060
|
+
y="6"
|
|
8061
|
+
width="12"
|
|
8062
|
+
height="12"
|
|
8063
|
+
rx="2"
|
|
8064
|
+
/>
|
|
8065
|
+
</svg>
|
|
8066
|
+
</button>
|
|
8067
|
+
` : b `
|
|
8068
|
+
<button
|
|
8069
|
+
class="mic"
|
|
8070
|
+
title="Dictate a message"
|
|
8071
|
+
aria-label="Dictate a message"
|
|
8072
|
+
@click=${this._handleMicClick}
|
|
8073
|
+
>
|
|
8074
|
+
<svg
|
|
8075
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
8076
|
+
viewBox="0 0 24 24"
|
|
8077
|
+
fill="none"
|
|
8078
|
+
stroke="currentColor"
|
|
8079
|
+
stroke-width="1.75"
|
|
8080
|
+
stroke-linecap="round"
|
|
8081
|
+
stroke-linejoin="round"
|
|
8082
|
+
class="mic-icon"
|
|
8083
|
+
aria-hidden="true"
|
|
8084
|
+
>
|
|
8085
|
+
<path d="M12 15a3 3 0 0 0 3-3V6a3 3 0 0 0-6 0v6a3 3 0 0 0 3 3Z"/>
|
|
8086
|
+
<path d="M19 11a7 7 0 0 1-14 0"/>
|
|
8087
|
+
<path d="M12 18v3"/>
|
|
8088
|
+
</svg>
|
|
8089
|
+
</button>
|
|
8090
|
+
`}
|
|
8026
8091
|
` : A}
|
|
8027
8092
|
${this._isStreaming ? b `
|
|
8028
8093
|
<button
|
|
@@ -8867,6 +8932,14 @@
|
|
|
8867
8932
|
color: #b0b0b0;
|
|
8868
8933
|
}
|
|
8869
8934
|
|
|
8935
|
+
/* margin-right rather than a wider .input-wrapper gap, which would also push
|
|
8936
|
+
the plus button and textarea apart. Applied to both mic states so the
|
|
8937
|
+
spacing doesn't shift when dictation swaps one for the other. */
|
|
8938
|
+
.mic,
|
|
8939
|
+
.mic-stop {
|
|
8940
|
+
margin-right: 4px;
|
|
8941
|
+
}
|
|
8942
|
+
|
|
8870
8943
|
.mic {
|
|
8871
8944
|
width: 34px;
|
|
8872
8945
|
height: 34px;
|
|
@@ -8886,30 +8959,42 @@
|
|
|
8886
8959
|
background: #f8f9fc;
|
|
8887
8960
|
}
|
|
8888
8961
|
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8962
|
+
.mic-icon {
|
|
8963
|
+
width: 21px;
|
|
8964
|
+
height: 21px;
|
|
8965
|
+
}
|
|
8966
|
+
|
|
8967
|
+
/* Dictation swaps the mic for this stop button, sitting in the mic's slot so
|
|
8968
|
+
the composer's layout is unchanged and the textarea stays visible with the
|
|
8969
|
+
transcript streaming into it. Structurally identical to .stop; only the
|
|
8970
|
+
colors differ — dictation isn't an error state, so it takes a neutral grey
|
|
8971
|
+
instead of the error red, and that also keeps it distinct from the solid
|
|
8972
|
+
send button sitting right beside it. The icon is dark rather than white
|
|
8973
|
+
because white on this grey wouldn't meet contrast. */
|
|
8974
|
+
.mic-stop {
|
|
8975
|
+
width: 34px;
|
|
8976
|
+
height: 34px;
|
|
8977
|
+
border-radius: 50%;
|
|
8978
|
+
background: #eae7e7;
|
|
8979
|
+
color: #1f1f1f;
|
|
8980
|
+
border: none;
|
|
8981
|
+
cursor: pointer;
|
|
8982
|
+
display: flex;
|
|
8983
|
+
align-items: center;
|
|
8984
|
+
justify-content: center;
|
|
8985
|
+
flex-shrink: 0;
|
|
8986
|
+
transition: all 0.15s;
|
|
8899
8987
|
}
|
|
8900
8988
|
|
|
8901
|
-
.mic-
|
|
8902
|
-
|
|
8903
|
-
height: 18px;
|
|
8989
|
+
.mic-stop:hover {
|
|
8990
|
+
background: #ded9d9;
|
|
8904
8991
|
}
|
|
8905
8992
|
|
|
8906
|
-
|
|
8907
|
-
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
opacity: 0.55;
|
|
8912
|
-
}
|
|
8993
|
+
/* Larger than .stop-icon's 14px: the rect fills only half its 24-unit
|
|
8994
|
+
viewBox, so the drawn square is half this value. */
|
|
8995
|
+
.mic-stop-icon {
|
|
8996
|
+
width: 20px;
|
|
8997
|
+
height: 20px;
|
|
8913
8998
|
}
|
|
8914
8999
|
|
|
8915
9000
|
.send {
|