@linxin666/dsh-pet 0.1.20 → 0.2.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/README.i18n.yaml +2 -2
- package/README.md +18 -11
- package/README.zh.md +18 -11
- package/assets/whale/pet.json +9 -0
- package/lib/client.js +394 -58
- package/lib/client.js.map +1 -1
- package/lib/index.js +1007 -43
- package/lib/invariant.js +1 -1
- package/lib/{state-Diiq8vjk.js → state-DrMX22GL.js} +86 -28
- package/lib/types/affinity.d.ts +4 -0
- package/lib/types/affinity.d.ts.map +1 -1
- package/lib/types/affinity.js +32 -6
- package/lib/types/chatter.d.ts +111 -0
- package/lib/types/chatter.d.ts.map +1 -0
- package/lib/types/chatter.js +756 -0
- package/lib/types/client/PetDockEntry.d.ts.map +1 -1
- package/lib/types/client/PetDockEntry.js +1 -1
- package/lib/types/client/PetSprite.d.ts.map +1 -1
- package/lib/types/client/PetSprite.js +133 -16
- package/lib/types/client/PluginSettingsCard.d.ts +28 -0
- package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
- package/lib/types/client/PluginSettingsCard.js +147 -6
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +1 -0
- package/lib/types/client/locales.d.ts +4 -0
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/locales.js +4 -0
- package/lib/types/client/sequences.d.ts +10 -0
- package/lib/types/client/sequences.d.ts.map +1 -0
- package/lib/types/client/sequences.js +20 -0
- package/lib/types/event-projection.d.ts +14 -1
- package/lib/types/event-projection.d.ts.map +1 -1
- package/lib/types/event-projection.js +38 -17
- package/lib/types/ledger.d.ts.map +1 -1
- package/lib/types/ledger.js +15 -7
- package/lib/types/loopback.d.ts +25 -0
- package/lib/types/loopback.d.ts.map +1 -0
- package/lib/types/loopback.js +68 -0
- package/lib/types/persist.d.ts.map +1 -1
- package/lib/types/persist.js +3 -1
- package/lib/types/registry.d.ts +7 -1
- package/lib/types/registry.d.ts.map +1 -1
- package/lib/types/registry.js +47 -3
- package/lib/types/remarks.d.ts +2 -0
- package/lib/types/remarks.d.ts.map +1 -1
- package/lib/types/remarks.js +35 -0
- package/lib/types/routes.d.ts.map +1 -1
- package/lib/types/routes.js +14 -0
- package/lib/types/service.d.ts +6 -0
- package/lib/types/service.d.ts.map +1 -1
- package/lib/types/service.js +15 -2
- package/lib/types/state.d.ts +7 -4
- package/lib/types/state.d.ts.map +1 -1
- package/lib/types/state.js +20 -20
- package/package.json +9 -9
- package/src/affinity.test.ts +4 -2
- package/src/affinity.ts +37 -6
- package/src/chatter.test.ts +154 -0
- package/src/chatter.ts +787 -0
- package/src/client/PetDockEntry.test.tsx +93 -0
- package/src/client/PetDockEntry.tsx +1 -0
- package/src/client/PetSprite.test.tsx +253 -3
- package/src/client/PetSprite.tsx +192 -37
- package/src/client/PluginSettingsCard.tsx +229 -18
- package/src/client/index.test.tsx +95 -0
- package/src/client/index.ts +1 -0
- package/src/client/locales.ts +4 -0
- package/src/client/pet-css.test.ts +54 -0
- package/src/client/pet.module.css +215 -57
- package/src/client/sequences.test.ts +33 -0
- package/src/client/sequences.ts +33 -0
- package/src/client/settings-card.module.css +90 -1
- package/src/event-projection.ts +49 -16
- package/src/ledger.test.ts +42 -1
- package/src/ledger.ts +15 -7
- package/src/loopback.ts +63 -0
- package/src/persist.test.ts +18 -1
- package/src/persist.ts +3 -1
- package/src/registry.test.ts +79 -4
- package/src/registry.ts +58 -6
- package/src/remarks.ts +36 -0
- package/src/routes.ts +11 -0
- package/src/service.ts +27 -2
- package/src/state.test.ts +13 -0
- package/src/state.ts +24 -18
package/lib/client.js
CHANGED
|
@@ -63,6 +63,26 @@ window.__ModuleLoader__.load({
|
|
|
63
63
|
}
|
|
64
64
|
//#endregion
|
|
65
65
|
//#region src/state.ts
|
|
66
|
+
/**
|
|
67
|
+
* Map one activity phase onto the animation contract.
|
|
68
|
+
* - thinking → `running` and tool → `running-right` (focused work).
|
|
69
|
+
* - review → `review` while answer text is streaming.
|
|
70
|
+
* - waiting → `waiting` (expectant pose, needs user input).
|
|
71
|
+
* - done → `jumping` (celebration), then back to `idle` after the window.
|
|
72
|
+
* - failed → `failed` briefly, then back to `idle`.
|
|
73
|
+
* - idle → `idle` (calm breathing loop).
|
|
74
|
+
*/
|
|
75
|
+
function animationForPhase(phase) {
|
|
76
|
+
switch (phase) {
|
|
77
|
+
case "thinking": return "running";
|
|
78
|
+
case "tool": return "running-right";
|
|
79
|
+
case "review": return "review";
|
|
80
|
+
case "waiting": return "waiting";
|
|
81
|
+
case "done": return "jumping";
|
|
82
|
+
case "failed": return "failed";
|
|
83
|
+
case "idle": return "idle";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
66
86
|
/** The spritesheet row index for one animation track. */
|
|
67
87
|
function rowOf(animation) {
|
|
68
88
|
return {
|
|
@@ -120,8 +140,32 @@ window.__ModuleLoader__.load({
|
|
|
120
140
|
};
|
|
121
141
|
}
|
|
122
142
|
//#endregion
|
|
143
|
+
//#region src/client/sequences.ts
|
|
144
|
+
/** Resolve the active track and frame after elapsed milliseconds of a looping sequence. */
|
|
145
|
+
function sequenceFrameAt(sequence, tracks, elapsedMs) {
|
|
146
|
+
const itemDurations = sequence.map((animation) => tracks[animation].durations.reduce((sum, value) => sum + value, 0));
|
|
147
|
+
const sequenceDuration = itemDurations.reduce((sum, value) => sum + value, 0);
|
|
148
|
+
let offset = Math.max(0, elapsedMs) % sequenceDuration;
|
|
149
|
+
let itemIndex = 0;
|
|
150
|
+
while (itemIndex < sequence.length - 1 && offset >= itemDurations[itemIndex]) {
|
|
151
|
+
offset -= itemDurations[itemIndex];
|
|
152
|
+
itemIndex += 1;
|
|
153
|
+
}
|
|
154
|
+
const animation = sequence[itemIndex];
|
|
155
|
+
const track = tracks[animation];
|
|
156
|
+
let frameIndex = 0;
|
|
157
|
+
while (frameIndex < track.frames.length - 1 && offset >= track.durations[frameIndex]) {
|
|
158
|
+
offset -= track.durations[frameIndex];
|
|
159
|
+
frameIndex += 1;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
animation,
|
|
163
|
+
frameIndex
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
123
167
|
//#region \0dsh-css:packages/dsh-pet/src/client/pet.module.css.mjs
|
|
124
|
-
const css$2 = ".kz2Bea_float{pointer-events:auto;-webkit-user-select:none;user-select:none;flex-direction:column;align-items:center;display:flex;position:fixed}.kz2Bea_sprite{image-rendering:auto;touch-action:none;position:relative}.kz2Bea_bubble{white-space:nowrap;color:#
|
|
168
|
+
const css$2 = ".kz2Bea_float{pointer-events:auto;-webkit-user-select:none;user-select:none;flex-direction:column;align-items:center;display:flex;position:fixed}.kz2Bea_sprite{image-rendering:auto;touch-action:none;position:relative}.kz2Bea_bubble{white-space:nowrap;color:#f4f7ff;pointer-events:none;border-radius:999px;margin-bottom:6px;padding:4px 10px;font-size:12px;line-height:1.4;animation:2.6s ease-out forwards kz2Bea_pet-bubble-pop;position:absolute;bottom:100%;box-shadow:0 2px 8px #00000040}.kz2Bea_bubblePet{background:#4d6bfef2}.kz2Bea_bubbleFeed{background:#0369a1f2}.kz2Bea_bubbleStatus{text-overflow:ellipsis;backdrop-filter:blur(8px);letter-spacing:.02em;background:linear-gradient(160deg,#131c36e6,#070b1af0);border:1px solid #7e98ff73;max-width:min(280px,100vw - 24px);padding:5px 12px;animation:.24s ease-out kz2Bea_pet-bubble-in;overflow:hidden;box-shadow:0 4px 12px #02061759,inset 0 1px #e2e8ff1a,0 0 12px #4d6bfe2e}.kz2Bea_bubbleWhisper{letter-spacing:.03em;animation:.32s cubic-bezier(.22,1,.36,1) kz2Bea_pet-whisper-in}.kz2Bea_bubbleWhisper:before{content:\"「\";opacity:.7;margin-right:2px}.kz2Bea_bubbleWhisper:after{content:\"」\";opacity:.7;margin-left:2px}.kz2Bea_bubbleStack{pointer-events:auto;flex-direction:column-reverse;align-items:center;gap:4px;display:flex;position:absolute;bottom:100%}.kz2Bea_bubbleAnchor{display:inline-flex;position:relative}.kz2Bea_bubbleMore{z-index:1;color:#eef2ff;cursor:pointer;background:linear-gradient(160deg,#4a68f5f2,#2f44b8f2);border:1px solid #7e98ff8c;border-radius:999px;justify-content:center;align-items:center;min-width:18px;height:18px;padding:0 5px;font-size:10px;font-weight:600;line-height:1;transition:filter .12s;display:inline-flex;position:absolute;top:-9px;right:-10px;box-shadow:0 2px 6px #02061766}.kz2Bea_bubbleMore:hover{filter:brightness(1.15)}.kz2Bea_bubbleMore:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}.kz2Bea_bubbleStack .kz2Bea_bubble{pointer-events:auto;margin-bottom:0;position:relative;bottom:auto}.kz2Bea_bubbleClickable{cursor:pointer;font:inherit;text-align:center;appearance:none;transition:filter .12s,box-shadow .12s}.kz2Bea_bubbleClickable:hover{filter:brightness(1.12)}.kz2Bea_bubbleClickable:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}@keyframes kz2Bea_pet-bubble-in{0%{opacity:0;transform:translateY(6px)scale(.96)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes kz2Bea_pet-whisper-in{0%{opacity:0;transform:translateY(8px)scale(.9)}60%{transform:translateY(-1px)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes kz2Bea_pet-panel-in{0%{opacity:0;transform:translateY(4px)scale(.97)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes kz2Bea_pet-bubble-pop{0%{opacity:0;transform:translateY(6px)scale(.85)}15%{opacity:1;transform:translateY(0)scale(1.05)}25%{transform:translateY(0)scale(1)}75%{opacity:1}to{opacity:0;transform:translateY(-8px)scale(.95)}}.kz2Bea_panel{color:#e6ebf8;backdrop-filter:blur(10px);transform-origin:50% 0;background:linear-gradient(165deg,#131c36f2,#070b1af7);border:1px solid #7e98ff4d;border-radius:12px;flex-direction:column;gap:7px;min-width:148px;margin-top:8px;padding:10px 12px;font-size:12px;animation:.2s cubic-bezier(.22,1,.36,1) kz2Bea_pet-panel-in;display:flex;position:absolute;top:100%;box-shadow:0 8px 24px #02061773,0 0 0 1px #4d6bfe1a,inset 0 1px #e2e8ff14}.kz2Bea_panel:after{content:\"\";height:14px;position:absolute;bottom:100%;left:0;right:0}.kz2Bea_panelAbove{transform-origin:50% 100%;margin-top:0;margin-bottom:8px;top:auto;bottom:100%}.kz2Bea_panelAbove:after{top:100%;bottom:auto}.kz2Bea_rankRow{white-space:nowrap;justify-content:space-between;gap:10px;display:flex}.kz2Bea_nameCell{letter-spacing:.02em;background:linear-gradient(90deg,#a9c1ff,#6c8bff 60%,#4d6bfe);color:#0000;-webkit-background-clip:text;background-clip:text;font-weight:600}.kz2Bea_statRank{color:#9db4ff;font-weight:600}.kz2Bea_statTreats{color:#7dd3fc;font-weight:600}.kz2Bea_statPoints{color:#fcd34d;font-weight:600}.kz2Bea_renameRow{align-items:center;gap:6px;display:flex}.kz2Bea_nameInput{color:#e6ebf8;background:#131c36e6;border:1px solid #7e98ff80;border-radius:6px;outline:none;flex:1;min-width:0;padding:3px 6px;font-size:12px}.kz2Bea_nameInput:focus{border-color:#4d6bfe;box-shadow:0 0 0 2px #4d6bfe73}.kz2Bea_actions{gap:6px;display:flex}.kz2Bea_action{cursor:pointer;color:#fff;background:linear-gradient(#4a68f5,#3a55e0);border:none;border-radius:6px;flex:1;padding:4px 8px;font-size:12px;font-weight:600;transition:filter .12s,box-shadow .12s,transform .12s;box-shadow:0 2px 6px #4d6bfe4d}.kz2Bea_action:hover{filter:brightness(1.08);transform:translateY(-1px);box-shadow:0 4px 10px #4d6bfe66}.kz2Bea_action:active{filter:brightness(.94);transform:translateY(0);box-shadow:0 1px 4px #4d6bfe4d}.kz2Bea_action:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}.kz2Bea_summon{color:#8ea6ff;cursor:pointer;background:#070b1abf;border:1px dashed #7e98ff99;border-radius:999px;padding:2px 10px;font-size:11px;transition:border-color .12s,color .12s,background .12s,box-shadow .12s}.kz2Bea_summon:hover{color:#c3d3ff;background:#070b1ae6;border-color:#7e98fff2}.kz2Bea_summon:active{color:#8ea6ff;border-color:#7e98ffcc}.kz2Bea_summon:focus-visible{outline:none;box-shadow:0 0 0 2px #7e98ffe6}@media (prefers-reduced-motion:reduce){.kz2Bea_bubble,.kz2Bea_bubbleStatus,.kz2Bea_bubbleWhisper,.kz2Bea_panel{opacity:1;animation:none}.kz2Bea_action,.kz2Bea_summon,.kz2Bea_bubbleMore{transition:none}}";
|
|
125
169
|
const tagId$2 = "@linxin666/dsh-pet/pet.module.css";
|
|
126
170
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
127
171
|
const tag = document.createElement("style");
|
|
@@ -134,19 +178,29 @@ window.__ModuleLoader__.load({
|
|
|
134
178
|
"action": "kz2Bea_action",
|
|
135
179
|
"actions": "kz2Bea_actions",
|
|
136
180
|
"bubble": "kz2Bea_bubble",
|
|
181
|
+
"bubbleAnchor": "kz2Bea_bubbleAnchor",
|
|
137
182
|
"bubbleClickable": "kz2Bea_bubbleClickable",
|
|
138
183
|
"bubbleFeed": "kz2Bea_bubbleFeed",
|
|
184
|
+
"bubbleMore": "kz2Bea_bubbleMore",
|
|
139
185
|
"bubblePet": "kz2Bea_bubblePet",
|
|
140
186
|
"bubbleStack": "kz2Bea_bubbleStack",
|
|
141
187
|
"bubbleStatus": "kz2Bea_bubbleStatus",
|
|
188
|
+
"bubbleWhisper": "kz2Bea_bubbleWhisper",
|
|
142
189
|
"float": "kz2Bea_float",
|
|
143
190
|
"nameCell": "kz2Bea_nameCell",
|
|
144
191
|
"nameInput": "kz2Bea_nameInput",
|
|
145
192
|
"panel": "kz2Bea_panel",
|
|
193
|
+
"panelAbove": "kz2Bea_panelAbove",
|
|
194
|
+
"pet-bubble-in": "kz2Bea_pet-bubble-in",
|
|
146
195
|
"pet-bubble-pop": "kz2Bea_pet-bubble-pop",
|
|
196
|
+
"pet-panel-in": "kz2Bea_pet-panel-in",
|
|
197
|
+
"pet-whisper-in": "kz2Bea_pet-whisper-in",
|
|
147
198
|
"rankRow": "kz2Bea_rankRow",
|
|
148
199
|
"renameRow": "kz2Bea_renameRow",
|
|
149
200
|
"sprite": "kz2Bea_sprite",
|
|
201
|
+
"statPoints": "kz2Bea_statPoints",
|
|
202
|
+
"statRank": "kz2Bea_statRank",
|
|
203
|
+
"statTreats": "kz2Bea_statTreats",
|
|
150
204
|
"summon": "kz2Bea_summon"
|
|
151
205
|
};
|
|
152
206
|
//#endregion
|
|
@@ -175,10 +229,17 @@ window.__ModuleLoader__.load({
|
|
|
175
229
|
const { snapshot, definition, display, feedback } = props;
|
|
176
230
|
const spriteRef = (0, react.useRef)(null);
|
|
177
231
|
const floatRef = (0, react.useRef)(null);
|
|
232
|
+
const panelRef = (0, react.useRef)(null);
|
|
233
|
+
const bubbleRef = (0, react.useRef)(null);
|
|
178
234
|
const [imageReady, setImageReady] = (0, react.useState)(false);
|
|
179
235
|
const [hovered, setHovered] = (0, react.useState)(false);
|
|
236
|
+
const [stackPeek, setStackPeek] = (0, react.useState)(false);
|
|
237
|
+
const [stackPinned, setStackPinned] = (0, react.useState)(false);
|
|
180
238
|
const [renaming, setRenaming] = (0, react.useState)(false);
|
|
239
|
+
const [panelAbove, setPanelAbove] = (0, react.useState)(false);
|
|
240
|
+
const [panelLift, setPanelLift] = (0, react.useState)(0);
|
|
181
241
|
const [nameDraft, setNameDraft] = (0, react.useState)("");
|
|
242
|
+
const composingRef = (0, react.useRef)(false);
|
|
182
243
|
const [dragPos, setDragPos] = (0, react.useState)(null);
|
|
183
244
|
const dragRef = (0, react.useRef)(null);
|
|
184
245
|
const hideTimerRef = (0, react.useRef)(null);
|
|
@@ -191,6 +252,7 @@ window.__ModuleLoader__.load({
|
|
|
191
252
|
const columns = definition.columns;
|
|
192
253
|
const rows = definition.rows;
|
|
193
254
|
const tracks = definition.tracks;
|
|
255
|
+
const sequences = definition.sequences;
|
|
194
256
|
(0, react.useEffect)(() => {
|
|
195
257
|
let cancelled = false;
|
|
196
258
|
const img = new Image();
|
|
@@ -204,22 +266,36 @@ window.__ModuleLoader__.load({
|
|
|
204
266
|
};
|
|
205
267
|
}, [definition.atlasUrl]);
|
|
206
268
|
const spriteScale = display.size / cell.height;
|
|
269
|
+
const phase = snapshot?.phase ?? "idle";
|
|
207
270
|
const animation = snapshot?.animation ?? "idle";
|
|
208
271
|
const scaleRef = (0, react.useRef)(spriteScale);
|
|
209
272
|
scaleRef.current = spriteScale;
|
|
210
273
|
(0, react.useEffect)(() => {
|
|
211
274
|
const reduceMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches === true;
|
|
212
|
-
const
|
|
213
|
-
const
|
|
275
|
+
const sequence = animation === animationForPhase(phase) ? sequences?.[phase] : void 0;
|
|
276
|
+
const leadAnimation = sequence?.[0] ?? animation;
|
|
277
|
+
const row = rowOfTrack(leadAnimation);
|
|
278
|
+
const track = trimTrack(tracks[leadAnimation], rows[row] ?? tracks[leadAnimation].frames.length);
|
|
214
279
|
const leadCol = track.frames[0];
|
|
215
280
|
const lead = framePosition(cell, columns, row, leadCol, scaleRef.current);
|
|
216
281
|
if (spriteRef.current !== null) spriteRef.current.style.backgroundPosition = lead.x + "px " + lead.y + "px";
|
|
217
282
|
if (reduceMotion) return;
|
|
218
283
|
let raf = 0;
|
|
219
284
|
let last = performance.now();
|
|
285
|
+
let sequenceElapsed = 0;
|
|
220
286
|
const tick = (ts) => {
|
|
221
287
|
const delta = ts - last;
|
|
222
288
|
last = ts;
|
|
289
|
+
if (sequence !== void 0) {
|
|
290
|
+
sequenceElapsed += delta;
|
|
291
|
+
const current = sequenceFrameAt(sequence, tracks, sequenceElapsed);
|
|
292
|
+
const currentRow = rowOfTrack(current.animation);
|
|
293
|
+
const col = trimTrack(tracks[current.animation], rows[currentRow] ?? tracks[current.animation].frames.length).frames[current.frameIndex];
|
|
294
|
+
const pos = framePosition(cell, columns, currentRow, col, scaleRef.current);
|
|
295
|
+
if (spriteRef.current !== null) spriteRef.current.style.backgroundPosition = pos.x + "px " + pos.y + "px";
|
|
296
|
+
raf = requestAnimationFrame(tick);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
223
299
|
const st = frameRef.current;
|
|
224
300
|
if (st.track !== animation) {
|
|
225
301
|
st.track = animation;
|
|
@@ -245,10 +321,12 @@ window.__ModuleLoader__.load({
|
|
|
245
321
|
return () => cancelAnimationFrame(raf);
|
|
246
322
|
}, [
|
|
247
323
|
animation,
|
|
324
|
+
phase,
|
|
248
325
|
cell,
|
|
249
326
|
columns,
|
|
250
327
|
rows,
|
|
251
|
-
tracks
|
|
328
|
+
tracks,
|
|
329
|
+
sequences
|
|
252
330
|
]);
|
|
253
331
|
const feedbackDoneRef = (0, react.useRef)(props.onFeedbackDone);
|
|
254
332
|
feedbackDoneRef.current = props.onFeedbackDone;
|
|
@@ -264,6 +342,7 @@ window.__ModuleLoader__.load({
|
|
|
264
342
|
hideTimerRef.current = null;
|
|
265
343
|
}
|
|
266
344
|
};
|
|
345
|
+
(0, react.useEffect)(() => () => clearHideTimer(), []);
|
|
267
346
|
const onPointerDown = (e) => {
|
|
268
347
|
e.preventDefault();
|
|
269
348
|
e.target.setPointerCapture?.(e.pointerId);
|
|
@@ -304,8 +383,44 @@ window.__ModuleLoader__.load({
|
|
|
304
383
|
const spriteWidth = Math.round(cell.width * spriteScale);
|
|
305
384
|
const spriteHeight = Math.round(cell.height * spriteScale);
|
|
306
385
|
const sessionBubbles = snapshot?.sessions ?? [];
|
|
386
|
+
const stackOpen = stackPeek || stackPinned;
|
|
387
|
+
const visibleSessions = !stackOpen && sessionBubbles.length > 1 ? sessionBubbles.slice(0, 1) : sessionBubbles;
|
|
307
388
|
const statusBubble = feedback === null && sessionBubbles.length === 0 ? snapshot?.bubble : void 0;
|
|
389
|
+
const whisper = feedback === null ? snapshot?.whisper : void 0;
|
|
390
|
+
const bubblePresent = feedback !== null || sessionBubbles.length > 0 || statusBubble !== void 0 || whisper !== void 0;
|
|
308
391
|
const displayName = snapshot?.name ?? definition.displayName;
|
|
392
|
+
(0, react.useEffect)(() => {
|
|
393
|
+
if (sessionBubbles.length <= 1) setStackPinned(false);
|
|
394
|
+
}, [sessionBubbles.length]);
|
|
395
|
+
(0, react.useLayoutEffect)(() => {
|
|
396
|
+
if (!hovered) {
|
|
397
|
+
setPanelAbove(false);
|
|
398
|
+
setPanelLift(0);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const updatePanelPlacement = () => {
|
|
402
|
+
const sprite = spriteRef.current;
|
|
403
|
+
const panel = panelRef.current;
|
|
404
|
+
if (sprite === null || panel === null) return;
|
|
405
|
+
const above = window.innerHeight - sprite.getBoundingClientRect().bottom < panel.getBoundingClientRect().height + 8;
|
|
406
|
+
setPanelAbove(above);
|
|
407
|
+
const bubbleHeight = above ? bubbleRef.current?.getBoundingClientRect().height ?? 0 : 0;
|
|
408
|
+
setPanelLift(bubbleHeight > 0 ? Math.ceil(bubbleHeight) + 14 : 0);
|
|
409
|
+
};
|
|
410
|
+
updatePanelPlacement();
|
|
411
|
+
window.addEventListener("resize", updatePanelPlacement);
|
|
412
|
+
return () => window.removeEventListener("resize", updatePanelPlacement);
|
|
413
|
+
}, [
|
|
414
|
+
hovered,
|
|
415
|
+
renaming,
|
|
416
|
+
pos.right,
|
|
417
|
+
pos.bottom,
|
|
418
|
+
display.size,
|
|
419
|
+
bubblePresent,
|
|
420
|
+
sessionBubbles.length,
|
|
421
|
+
stackOpen,
|
|
422
|
+
feedback
|
|
423
|
+
]);
|
|
309
424
|
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
310
425
|
ref: floatRef,
|
|
311
426
|
className: pet_module_css_default.float,
|
|
@@ -321,6 +436,7 @@ window.__ModuleLoader__.load({
|
|
|
321
436
|
onPointerLeave: (e) => {
|
|
322
437
|
const next = e.relatedTarget;
|
|
323
438
|
if (next instanceof Node && floatRef.current?.contains(next)) return;
|
|
439
|
+
if (renaming) return;
|
|
324
440
|
clearHideTimer();
|
|
325
441
|
hideTimerRef.current = window.setTimeout(() => setHovered(false), 300);
|
|
326
442
|
},
|
|
@@ -332,7 +448,7 @@ window.__ModuleLoader__.load({
|
|
|
332
448
|
width: spriteWidth,
|
|
333
449
|
height: spriteHeight,
|
|
334
450
|
backgroundImage: imageReady ? "url(" + definition.atlasUrl + ")" : void 0,
|
|
335
|
-
backgroundSize: cell.width * columns * spriteScale + "px " + cell.height * rows.length * spriteScale + "px",
|
|
451
|
+
backgroundSize: cell.width * columns * spriteScale + "px " + cell.height * (definition.atlasRows ?? rows.length) * spriteScale + "px",
|
|
336
452
|
backgroundRepeat: "no-repeat",
|
|
337
453
|
backgroundPosition: "0 0",
|
|
338
454
|
cursor: dragRef.current === null ? "grab" : "grabbing"
|
|
@@ -348,29 +464,54 @@ window.__ModuleLoader__.load({
|
|
|
348
464
|
"aria-label": definition.displayName
|
|
349
465
|
}),
|
|
350
466
|
feedback !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
467
|
+
ref: bubbleRef,
|
|
351
468
|
className: clsx(pet_module_css_default.bubble, feedback.kind === "feed" ? pet_module_css_default.bubbleFeed : pet_module_css_default.bubblePet),
|
|
352
469
|
children: feedback.text
|
|
353
470
|
}, feedback.at),
|
|
354
|
-
feedback === null && sessionBubbles.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.
|
|
471
|
+
feedback === null && (sessionBubbles.length > 0 || statusBubble !== void 0 || whisper !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
472
|
+
ref: bubbleRef,
|
|
355
473
|
className: pet_module_css_default.bubbleStack,
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
474
|
+
onPointerEnter: () => setStackPeek(true),
|
|
475
|
+
onPointerLeave: () => setStackPeek(false),
|
|
476
|
+
children: [visibleSessions.map((session, index) => {
|
|
477
|
+
const speaksWhisper = index === 0 && whisper !== void 0;
|
|
478
|
+
const bubble = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
479
|
+
type: "button",
|
|
480
|
+
className: clsx(pet_module_css_default.bubble, pet_module_css_default.bubbleStatus, pet_module_css_default.bubbleClickable, speaksWhisper && pet_module_css_default.bubbleWhisper),
|
|
481
|
+
title: props.t("pet.openSessionHint"),
|
|
482
|
+
onClick: () => {
|
|
483
|
+
props.onOpenSession(session.sessionId);
|
|
484
|
+
},
|
|
485
|
+
children: speaksWhisper ? whisper : session.bubble
|
|
486
|
+
}, speaksWhisper ? "whisper:" + whisper : session.sessionId);
|
|
487
|
+
if (index !== 0 || sessionBubbles.length <= 1) return bubble;
|
|
488
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
489
|
+
className: pet_module_css_default.bubbleAnchor,
|
|
490
|
+
children: [bubble, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
491
|
+
type: "button",
|
|
492
|
+
className: pet_module_css_default.bubbleMore,
|
|
493
|
+
title: stackOpen ? props.t("pet.collapseSessions") : props.t("pet.moreSessions", { n: sessionBubbles.length - 1 }),
|
|
494
|
+
"aria-label": stackOpen ? props.t("pet.collapseSessions") : props.t("pet.moreSessions", { n: sessionBubbles.length - 1 }),
|
|
495
|
+
"aria-expanded": stackOpen,
|
|
496
|
+
onClick: (e) => {
|
|
497
|
+
e.stopPropagation();
|
|
498
|
+
setStackPinned((open) => !open);
|
|
499
|
+
},
|
|
500
|
+
children: stackOpen ? "×" : "+" + String(sessionBubbles.length - 1)
|
|
501
|
+
})]
|
|
502
|
+
}, "primary");
|
|
503
|
+
}), sessionBubbles.length === 0 && (statusBubble !== void 0 || whisper !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
504
|
+
className: clsx(pet_module_css_default.bubble, pet_module_css_default.bubbleStatus, whisper !== void 0 && pet_module_css_default.bubbleWhisper),
|
|
505
|
+
role: "status",
|
|
506
|
+
"aria-live": "polite",
|
|
507
|
+
children: whisper ?? statusBubble
|
|
508
|
+
}, whisper === void 0 ? "status" : "whisper:" + whisper)]
|
|
371
509
|
}),
|
|
372
510
|
hovered && dragRef.current === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
373
|
-
|
|
511
|
+
ref: panelRef,
|
|
512
|
+
className: clsx(pet_module_css_default.panel, panelAbove && pet_module_css_default.panelAbove),
|
|
513
|
+
"data-placement": panelAbove ? "above" : "below",
|
|
514
|
+
style: panelAbove && panelLift > 0 ? { marginBottom: panelLift } : void 0,
|
|
374
515
|
onPointerEnter: () => {
|
|
375
516
|
clearHideTimer();
|
|
376
517
|
},
|
|
@@ -383,8 +524,14 @@ window.__ModuleLoader__.load({
|
|
|
383
524
|
placeholder: props.t("pet.namePlaceholder"),
|
|
384
525
|
autoFocus: true,
|
|
385
526
|
onChange: (e) => setNameDraft(e.target.value),
|
|
527
|
+
onCompositionStart: () => {
|
|
528
|
+
composingRef.current = true;
|
|
529
|
+
},
|
|
530
|
+
onCompositionEnd: () => {
|
|
531
|
+
composingRef.current = false;
|
|
532
|
+
},
|
|
386
533
|
onKeyDown: (e) => {
|
|
387
|
-
if (e.nativeEvent.isComposing) return;
|
|
534
|
+
if (composingRef.current || e.nativeEvent.isComposing || e.key === "Process") return;
|
|
388
535
|
if (e.key === "Enter") {
|
|
389
536
|
const trimmed = nameDraft.trim();
|
|
390
537
|
if (trimmed !== "") {
|
|
@@ -411,11 +558,20 @@ window.__ModuleLoader__.load({
|
|
|
411
558
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
412
559
|
className: pet_module_css_default.nameCell,
|
|
413
560
|
children: displayName
|
|
414
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
561
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
562
|
+
className: pet_module_css_default.statRank,
|
|
563
|
+
children: props.t("pet.rank", { rank: snapshot?.affinity.rank ?? "?" })
|
|
564
|
+
})]
|
|
415
565
|
}),
|
|
416
566
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
417
567
|
className: pet_module_css_default.rankRow,
|
|
418
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
568
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
569
|
+
className: pet_module_css_default.statTreats,
|
|
570
|
+
children: props.t("pet.treats", { n: snapshot?.treats.stocked ?? 0 })
|
|
571
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
572
|
+
className: pet_module_css_default.statPoints,
|
|
573
|
+
children: props.t("pet.points", { points: snapshot?.affinity.points ?? 0 })
|
|
574
|
+
})]
|
|
419
575
|
}),
|
|
420
576
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
421
577
|
className: pet_module_css_default.actions,
|
|
@@ -430,6 +586,7 @@ window.__ModuleLoader__.load({
|
|
|
430
586
|
type: "button",
|
|
431
587
|
className: pet_module_css_default.action,
|
|
432
588
|
onClick: () => {
|
|
589
|
+
clearHideTimer();
|
|
433
590
|
setNameDraft(displayName);
|
|
434
591
|
setRenaming(true);
|
|
435
592
|
},
|
|
@@ -515,12 +672,13 @@ window.__ModuleLoader__.load({
|
|
|
515
672
|
},
|
|
516
673
|
onClick: props.summon,
|
|
517
674
|
"data-testid": "pet-summon",
|
|
675
|
+
"data-dsh-part": "summon-button",
|
|
518
676
|
children: props.t("pet.summon", { name: snapshot?.name ?? "" })
|
|
519
677
|
});
|
|
520
678
|
}
|
|
521
679
|
//#endregion
|
|
522
680
|
//#region \0dsh-css:packages/dsh-pet/src/client/settings-card.module.css.mjs
|
|
523
|
-
const css$1 = ".kKk9aW_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.kKk9aW_card:hover{border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.kKk9aW_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.kKk9aW_headerStatic{border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.kKk9aW_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kKk9aW_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.kKk9aW_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.kKk9aW_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kKk9aW_chevronOpen{transform:rotate(180deg)}.kKk9aW_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.kKk9aW_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.kKk9aW_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.kKk9aW_discard,.kKk9aW_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.kKk9aW_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.kKk9aW_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.kKk9aW_discard:disabled,.kKk9aW_save:disabled{opacity:.4;cursor:default}.kKk9aW_discard:focus-visible,.kKk9aW_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.kKk9aW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.kKk9aW_field+.kKk9aW_field{border-top:1px solid var(--dsw-alias-border-l2)}.kKk9aW_head{align-items:center;gap:8px;display:flex}.kKk9aW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.kKk9aW_badges{align-items:center;gap:8px;display:inline-flex}.kKk9aW_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.kKk9aW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.kKk9aW_reset:disabled{cursor:default}.kKk9aW_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.kKk9aW_input,.kKk9aW_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_input:focus-visible,.kKk9aW_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.kKk9aW_input:disabled,.kKk9aW_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.kKk9aW_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.kKk9aW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.kKk9aW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.kKk9aW_card,.kKk9aW_header,.kKk9aW_chevron,.kKk9aW_chevronOpen,.kKk9aW_discard,.kKk9aW_save{transition:none}}";
|
|
681
|
+
const css$1 = ".kKk9aW_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.kKk9aW_card:hover{border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.kKk9aW_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.kKk9aW_headerStatic{border-radius:12px;align-items:center;gap:12px;width:100%;padding:14px 16px;display:flex}.kKk9aW_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kKk9aW_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.kKk9aW_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.kKk9aW_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kKk9aW_chevronOpen{transform:rotate(180deg)}.kKk9aW_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.kKk9aW_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_notExposed{color:var(--dsw-alias-state-warn-primary);margin:12px 0 0;font-size:12px;line-height:1.5}.kKk9aW_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.kKk9aW_failed{min-width:0;color:var(--dsw-alias-label-error);text-overflow:ellipsis;white-space:nowrap;flex:1;margin:0;font-size:12px;line-height:1.5;overflow:hidden}.kKk9aW_discard,.kKk9aW_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.kKk9aW_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.kKk9aW_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.kKk9aW_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.kKk9aW_discard:disabled,.kKk9aW_save:disabled{opacity:.4;cursor:default}.kKk9aW_discard:focus-visible,.kKk9aW_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.kKk9aW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.kKk9aW_field+.kKk9aW_field{border-top:1px solid var(--dsw-alias-border-l2)}.kKk9aW_head{align-items:center;gap:8px;display:flex}.kKk9aW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.kKk9aW_badges{align-items:center;gap:8px;display:inline-flex}.kKk9aW_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kKk9aW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.kKk9aW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.kKk9aW_reset:disabled{cursor:default}.kKk9aW_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.kKk9aW_input,.kKk9aW_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_input:focus-visible,.kKk9aW_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.kKk9aW_input:disabled,.kKk9aW_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.kKk9aW_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.kKk9aW_inputInvalid:focus-visible{outline:2px solid var(--dsw-alias-label-error);outline-offset:1px;border-color:var(--dsw-alias-label-error)}.kKk9aW_selectWrap{position:relative}.kKk9aW_selectButton{appearance:none;text-align:left;cursor:pointer;justify-content:space-between;align-items:center;gap:8px;width:100%;display:flex}.kKk9aW_selectLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.kKk9aW_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kKk9aW_selectChevronOpen{transform:rotate(180deg)}.kKk9aW_selectPopup{z-index:40;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-height:240px;box-shadow:0 8px 24px var(--dsw-alias-bg-mask-2);opacity:0;border-radius:8px;flex-direction:column;padding:4px;transition:opacity .1s,transform .1s;display:flex;position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;transform:translateY(-4px)}.kKk9aW_selectPopupOpen{opacity:1;transform:none}.kKk9aW_selectPopupClose{opacity:0;pointer-events:none;transform:translateY(-4px)}.kKk9aW_selectOption{color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;border-radius:6px;padding:6px 10px;font-size:13px;line-height:1.5;overflow:hidden}.kKk9aW_selectOption:hover,.kKk9aW_selectOptionActive{background:var(--dsw-alias-interactive-bg-hover)}.kKk9aW_selectOptionSelected{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary-new-colorprimary-new-color) 10%, transparent);font-weight:500}.kKk9aW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.kKk9aW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}@media (prefers-reduced-motion:reduce){.kKk9aW_card,.kKk9aW_header,.kKk9aW_chevron,.kKk9aW_chevronOpen,.kKk9aW_discard,.kKk9aW_save,.kKk9aW_selectChevron,.kKk9aW_selectChevronOpen,.kKk9aW_selectPopup{transition:none}}";
|
|
524
682
|
const tagId$1 = "@linxin666/dsh-pet/settings-card.module.css";
|
|
525
683
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
526
684
|
const tag = document.createElement("style");
|
|
@@ -557,7 +715,18 @@ window.__ModuleLoader__.load({
|
|
|
557
715
|
"readOnly": "kKk9aW_readOnly",
|
|
558
716
|
"reset": "kKk9aW_reset",
|
|
559
717
|
"save": "kKk9aW_save",
|
|
560
|
-
"select": "kKk9aW_select"
|
|
718
|
+
"select": "kKk9aW_select",
|
|
719
|
+
"selectButton": "kKk9aW_selectButton",
|
|
720
|
+
"selectChevron": "kKk9aW_selectChevron",
|
|
721
|
+
"selectChevronOpen": "kKk9aW_selectChevronOpen",
|
|
722
|
+
"selectLabel": "kKk9aW_selectLabel",
|
|
723
|
+
"selectOption": "kKk9aW_selectOption",
|
|
724
|
+
"selectOptionActive": "kKk9aW_selectOptionActive",
|
|
725
|
+
"selectOptionSelected": "kKk9aW_selectOptionSelected",
|
|
726
|
+
"selectPopup": "kKk9aW_selectPopup",
|
|
727
|
+
"selectPopupClose": "kKk9aW_selectPopupClose",
|
|
728
|
+
"selectPopupOpen": "kKk9aW_selectPopupOpen",
|
|
729
|
+
"selectWrap": "kKk9aW_selectWrap"
|
|
561
730
|
};
|
|
562
731
|
//#endregion
|
|
563
732
|
//#region src/client/PluginSettingsCard.tsx
|
|
@@ -663,7 +832,7 @@ window.__ModuleLoader__.load({
|
|
|
663
832
|
children: props.t("settings.readOnly")
|
|
664
833
|
}) : null,
|
|
665
834
|
props.children,
|
|
666
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
835
|
+
props.hideFooter === true ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
667
836
|
className: settings_card_module_css_default.footer,
|
|
668
837
|
children: [
|
|
669
838
|
state.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
@@ -736,6 +905,175 @@ window.__ModuleLoader__.load({
|
|
|
736
905
|
]
|
|
737
906
|
});
|
|
738
907
|
}
|
|
908
|
+
const NON_SKIN_BODY_MARKERS = /* @__PURE__ */ new Set(["dshSkinCenter", "dshSidebarCollapsed"]);
|
|
909
|
+
function isSkinActive() {
|
|
910
|
+
return Object.keys(document.body.dataset).some((key) => key.startsWith("dsh") && !NON_SKIN_BODY_MARKERS.has(key));
|
|
911
|
+
}
|
|
912
|
+
const SELECT_CLOSE_MS = 100;
|
|
913
|
+
/**
|
|
914
|
+
* The shared dual-mode select control. While an appearance skin is active it
|
|
915
|
+
* renders the legacy native `<select>` untouched, so element-level skin
|
|
916
|
+
* selectors keep working; under the default appearance it renders a
|
|
917
|
+
* self-drawn `role="listbox"` popup whose open/close is transition-animated.
|
|
918
|
+
* Staged cards reach it through BooleanField/ChoiceField; immediate-apply
|
|
919
|
+
* editors (the side-card prefs) bind it directly through onEdit.
|
|
920
|
+
* 双模式下拉框:皮肤激活时用原生 select,默认外观用自绘动画弹层。
|
|
921
|
+
*/
|
|
922
|
+
function SelectField(props) {
|
|
923
|
+
const { id, options, value } = props;
|
|
924
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
925
|
+
const [closing, setClosing] = (0, react.useState)(false);
|
|
926
|
+
const [phase, setPhase] = (0, react.useState)("initial");
|
|
927
|
+
const [activeIndex, setActiveIndex] = (0, react.useState)(0);
|
|
928
|
+
const closeTimer = (0, react.useRef)(void 0);
|
|
929
|
+
const wrapRef = (0, react.useRef)(null);
|
|
930
|
+
const popupRef = (0, react.useRef)(null);
|
|
931
|
+
const currentIndex = () => {
|
|
932
|
+
const index = options.findIndex((option) => option.value === value);
|
|
933
|
+
return index >= 0 ? index : 0;
|
|
934
|
+
};
|
|
935
|
+
const close = (0, react.useCallback)(() => {
|
|
936
|
+
if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
|
|
937
|
+
setClosing(true);
|
|
938
|
+
closeTimer.current = setTimeout(() => {
|
|
939
|
+
setClosing(false);
|
|
940
|
+
setOpen(false);
|
|
941
|
+
}, SELECT_CLOSE_MS);
|
|
942
|
+
}, []);
|
|
943
|
+
const openPopup = () => {
|
|
944
|
+
if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
|
|
945
|
+
setActiveIndex(currentIndex());
|
|
946
|
+
setPhase("initial");
|
|
947
|
+
setClosing(false);
|
|
948
|
+
setOpen(true);
|
|
949
|
+
};
|
|
950
|
+
const commit = (index) => {
|
|
951
|
+
const option = options[index];
|
|
952
|
+
if (option) props.onEdit(option.value);
|
|
953
|
+
close();
|
|
954
|
+
};
|
|
955
|
+
const onTriggerClick = () => {
|
|
956
|
+
if (props.disabled) return;
|
|
957
|
+
if (open && !closing) close();
|
|
958
|
+
else openPopup();
|
|
959
|
+
};
|
|
960
|
+
const onKeyDown = (event) => {
|
|
961
|
+
if (props.disabled) return;
|
|
962
|
+
const count = options.length;
|
|
963
|
+
switch (event.key) {
|
|
964
|
+
case "ArrowDown":
|
|
965
|
+
case "ArrowUp":
|
|
966
|
+
case "Enter":
|
|
967
|
+
case " ":
|
|
968
|
+
event.preventDefault();
|
|
969
|
+
if (!open) openPopup();
|
|
970
|
+
else if (!closing) if (event.key === "ArrowDown") setActiveIndex((index) => (index + 1) % count);
|
|
971
|
+
else if (event.key === "ArrowUp") setActiveIndex((index) => (index - 1 + count) % count);
|
|
972
|
+
else commit(activeIndex);
|
|
973
|
+
break;
|
|
974
|
+
case "Escape":
|
|
975
|
+
if (open) {
|
|
976
|
+
event.preventDefault();
|
|
977
|
+
event.stopPropagation();
|
|
978
|
+
close();
|
|
979
|
+
}
|
|
980
|
+
break;
|
|
981
|
+
case "Tab":
|
|
982
|
+
if (open) close();
|
|
983
|
+
break;
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
(0, react.useEffect)(() => () => {
|
|
987
|
+
if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
|
|
988
|
+
}, []);
|
|
989
|
+
(0, react.useLayoutEffect)(() => {
|
|
990
|
+
if (open && !closing && phase === "initial") {
|
|
991
|
+
popupRef.current?.offsetHeight;
|
|
992
|
+
setPhase("open");
|
|
993
|
+
}
|
|
994
|
+
}, [
|
|
995
|
+
open,
|
|
996
|
+
closing,
|
|
997
|
+
phase
|
|
998
|
+
]);
|
|
999
|
+
(0, react.useEffect)(() => {
|
|
1000
|
+
if (!open) return;
|
|
1001
|
+
const onPointerDown = (event) => {
|
|
1002
|
+
const target = event.target;
|
|
1003
|
+
if (target instanceof Node && !wrapRef.current?.contains(target)) close();
|
|
1004
|
+
};
|
|
1005
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
1006
|
+
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
1007
|
+
}, [open, close]);
|
|
1008
|
+
(0, react.useEffect)(() => {
|
|
1009
|
+
if (props.disabled && open) close();
|
|
1010
|
+
}, [
|
|
1011
|
+
props.disabled,
|
|
1012
|
+
open,
|
|
1013
|
+
close
|
|
1014
|
+
]);
|
|
1015
|
+
if (isSkinActive()) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
1016
|
+
id,
|
|
1017
|
+
className: settings_card_module_css_default.select,
|
|
1018
|
+
value,
|
|
1019
|
+
disabled: props.disabled,
|
|
1020
|
+
onChange: (event) => {
|
|
1021
|
+
props.onEdit(event.target.value);
|
|
1022
|
+
},
|
|
1023
|
+
children: options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1024
|
+
value: option.value,
|
|
1025
|
+
children: option.label
|
|
1026
|
+
}, option.value))
|
|
1027
|
+
});
|
|
1028
|
+
const label = options.find((option) => option.value === value)?.label ?? "";
|
|
1029
|
+
const popupClass = closing ? `${settings_card_module_css_default.selectPopup} ${settings_card_module_css_default.selectPopupClose}` : phase === "open" ? `${settings_card_module_css_default.selectPopup} ${settings_card_module_css_default.selectPopupOpen}` : settings_card_module_css_default.selectPopup;
|
|
1030
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1031
|
+
className: settings_card_module_css_default.selectWrap,
|
|
1032
|
+
ref: wrapRef,
|
|
1033
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1034
|
+
type: "button",
|
|
1035
|
+
id,
|
|
1036
|
+
className: `${settings_card_module_css_default.select} ${settings_card_module_css_default.selectButton}`,
|
|
1037
|
+
disabled: props.disabled,
|
|
1038
|
+
"aria-haspopup": "listbox",
|
|
1039
|
+
"aria-expanded": open,
|
|
1040
|
+
"aria-activedescendant": open ? `${id}-o${activeIndex}` : void 0,
|
|
1041
|
+
"aria-invalid": props.invalid || void 0,
|
|
1042
|
+
onClick: onTriggerClick,
|
|
1043
|
+
onKeyDown,
|
|
1044
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1045
|
+
className: settings_card_module_css_default.selectLabel,
|
|
1046
|
+
children: label
|
|
1047
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
1048
|
+
width: "14",
|
|
1049
|
+
height: "14",
|
|
1050
|
+
viewBox: "0 0 14 14",
|
|
1051
|
+
fill: "none",
|
|
1052
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1053
|
+
className: open ? `${settings_card_module_css_default.selectChevron} ${settings_card_module_css_default.selectChevronOpen}` : settings_card_module_css_default.selectChevron,
|
|
1054
|
+
"aria-hidden": "true",
|
|
1055
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1056
|
+
d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z",
|
|
1057
|
+
fill: "currentColor"
|
|
1058
|
+
})
|
|
1059
|
+
})]
|
|
1060
|
+
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1061
|
+
className: popupClass,
|
|
1062
|
+
role: "listbox",
|
|
1063
|
+
ref: popupRef,
|
|
1064
|
+
children: options.map((option, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1065
|
+
id: `${id}-o${index}`,
|
|
1066
|
+
role: "option",
|
|
1067
|
+
"aria-selected": option.value === value,
|
|
1068
|
+
className: `${settings_card_module_css_default.selectOption}${option.value === value ? ` ${settings_card_module_css_default.selectOptionSelected}` : ""}${index === activeIndex && !closing ? ` ${settings_card_module_css_default.selectOptionActive}` : ""}`,
|
|
1069
|
+
onClick: () => {
|
|
1070
|
+
commit(index);
|
|
1071
|
+
},
|
|
1072
|
+
children: option.label
|
|
1073
|
+
}, option.value))
|
|
1074
|
+
}) : null]
|
|
1075
|
+
});
|
|
1076
|
+
}
|
|
739
1077
|
/** A staged boolean field: 继承 / 开 / 关. */
|
|
740
1078
|
function BooleanField(props) {
|
|
741
1079
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -761,28 +1099,26 @@ window.__ModuleLoader__.load({
|
|
|
761
1099
|
})]
|
|
762
1100
|
}) : null]
|
|
763
1101
|
}),
|
|
764
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1102
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectField, {
|
|
765
1103
|
id: props.id,
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
disabled: props.disabled,
|
|
769
|
-
onChange: (event) => {
|
|
770
|
-
props.onEdit(event.target.value);
|
|
771
|
-
},
|
|
772
|
-
children: [
|
|
773
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1104
|
+
options: [
|
|
1105
|
+
{
|
|
774
1106
|
value: "",
|
|
775
|
-
|
|
776
|
-
}
|
|
777
|
-
|
|
1107
|
+
label: props.inheritLabel
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
778
1110
|
value: "true",
|
|
779
|
-
|
|
780
|
-
}
|
|
781
|
-
|
|
1111
|
+
label: props.onLabel
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
782
1114
|
value: "false",
|
|
783
|
-
|
|
784
|
-
}
|
|
785
|
-
]
|
|
1115
|
+
label: props.offLabel
|
|
1116
|
+
}
|
|
1117
|
+
],
|
|
1118
|
+
value: props.text,
|
|
1119
|
+
disabled: props.disabled,
|
|
1120
|
+
invalid: props.invalid,
|
|
1121
|
+
onEdit: props.onEdit
|
|
786
1122
|
}),
|
|
787
1123
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
788
1124
|
className: settings_card_module_css_default.hint,
|
|
@@ -816,21 +1152,16 @@ window.__ModuleLoader__.load({
|
|
|
816
1152
|
})]
|
|
817
1153
|
}) : null]
|
|
818
1154
|
}),
|
|
819
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1155
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectField, {
|
|
820
1156
|
id: props.id,
|
|
821
|
-
|
|
1157
|
+
options: [{
|
|
1158
|
+
value: "",
|
|
1159
|
+
label: props.inheritLabel
|
|
1160
|
+
}, ...props.choices],
|
|
822
1161
|
value: props.text,
|
|
823
1162
|
disabled: props.disabled,
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
},
|
|
827
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
828
|
-
value: "",
|
|
829
|
-
children: props.inheritLabel
|
|
830
|
-
}), props.choices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
831
|
-
value: choice.value,
|
|
832
|
-
children: choice.label
|
|
833
|
-
}, choice.value))]
|
|
1163
|
+
invalid: props.invalid,
|
|
1164
|
+
onEdit: props.onEdit
|
|
834
1165
|
}),
|
|
835
1166
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
836
1167
|
className: props.invalid ? settings_card_module_css_default.invalid : settings_card_module_css_default.hint,
|
|
@@ -1365,6 +1696,8 @@ window.__ModuleLoader__.load({
|
|
|
1365
1696
|
"pet.state.loading": "宠物正在赶来…",
|
|
1366
1697
|
"pet.state.error": "宠物迷路了(连接失败)",
|
|
1367
1698
|
"pet.openSessionHint": "点击跳转到对应会话",
|
|
1699
|
+
"pet.moreSessions": "展开其余 {n} 个会话的气泡",
|
|
1700
|
+
"pet.collapseSessions": "收起会话气泡",
|
|
1368
1701
|
"settings.title": "宠物",
|
|
1369
1702
|
"settings.description": "选择宠物并调整它的显示布局。",
|
|
1370
1703
|
"settings.pet": "宠物",
|
|
@@ -1409,6 +1742,8 @@ window.__ModuleLoader__.load({
|
|
|
1409
1742
|
"pet.state.loading": "The pet is on its way…",
|
|
1410
1743
|
"pet.state.error": "The pet is lost (connection failed)",
|
|
1411
1744
|
"pet.openSessionHint": "Click to jump to this session",
|
|
1745
|
+
"pet.moreSessions": "Expand {n} more session bubbles",
|
|
1746
|
+
"pet.collapseSessions": "Collapse session bubbles",
|
|
1412
1747
|
"settings.title": "Pet",
|
|
1413
1748
|
"settings.description": "Pick a pet and tune its display layout.",
|
|
1414
1749
|
"settings.pet": "Pet",
|
|
@@ -1632,6 +1967,7 @@ window.__ModuleLoader__.load({
|
|
|
1632
1967
|
});
|
|
1633
1968
|
const container = document.createElement("div");
|
|
1634
1969
|
container.dataset.dshPetRoot = "";
|
|
1970
|
+
container.dataset.dshPlugin = "pet";
|
|
1635
1971
|
document.body.appendChild(container);
|
|
1636
1972
|
const petRoot = (0, react_dom_client.createRoot)(container);
|
|
1637
1973
|
petRoot.render((0, react.createElement)(PetDockEntry, {
|