@ash-qw/dsh-theme-prts 0.1.92 → 0.1.94

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.
@@ -1,6 +1,12 @@
1
1
  import { createThemeSettingsOverlay, themeSettingsMarkup } from './theme-settings-workbench.js'
2
2
  import { createResizeShieldAdapter } from './resize-shield-adapter.js'
3
3
 
4
+ const PHONE_RAIL_BREAKPOINT = 640
5
+ const RAIL_HOLD_DELAY_MS = 350
6
+ const RAIL_HOLD_MOVE_TOLERANCE = 8
7
+ const RAIL_SWIPE_THRESHOLD = 32
8
+ const RAIL_SWIPE_AXIS_RATIO = 1.25
9
+
4
10
  function setText(root, selector, value) {
5
11
  const node = root?.querySelector(selector)
6
12
  const next = String(value ?? '')
@@ -9,7 +15,7 @@ function setText(root, selector, value) {
9
15
 
10
16
  function markup(emblem) {
11
17
  return `<div data-prts-shell data-plugin="dsh-theme-prts">
12
- <button type="button" data-prts-rail-launcher aria-label="打开 P.R.T.S. 导航" aria-controls="prts-nav-rail" aria-expanded="false"><span aria-hidden="true">P.R.T.S.</span></button>
18
+ <button type="button" data-prts-rail-launcher aria-label="打开 P.R.T.S. 导航" aria-controls="prts-nav-rail" aria-expanded="false"><span aria-hidden="true">P.R.T.S.</span><i data-prts-rail-gesture-cue aria-hidden="true">⌄<br>⌄</i></button>
13
19
  <nav id="prts-nav-rail" data-prts-nav-rail aria-label="P.R.T.S. 导航">
14
20
  <button type="button" data-prts-rail-brand aria-label="P.R.T.S. 终端设置" aria-controls="prts-theme-settings" aria-expanded="false">${emblem || ''}<span>P.R.T.S.</span></button>
15
21
  <div data-prts-nav-bottom>
@@ -35,8 +41,10 @@ export function createOperationsShell({
35
41
  adapter,
36
42
  hostGeometry,
37
43
  onSchemeToggle = () => {},
44
+ onSchemeDragStart = () => undefined,
38
45
  onThemeDisable = () => {},
39
46
  onPreferenceChange = () => {},
47
+ onPreferencePreview = () => {},
40
48
  onVisualReset = () => {},
41
49
  getConversationScalePreview = () => ({ visible: false, reason: 'unmeasured', mode: 'hidden' }),
42
50
  onRetrySave = () => {},
@@ -47,14 +55,166 @@ export function createOperationsShell({
47
55
  let navRail
48
56
  let railLauncher
49
57
  let railMode
58
+ let railViewport
59
+ let railDefaultHidden = false
50
60
  let railViewportQuery
61
+ let railPointerQuery
62
+ let railHoverQuery
63
+ let railPointer
64
+ let railHoldTimer
51
65
  let settingsOverlay
52
66
  let schemeToggle
67
+ let schemeIntent
68
+ let schemePressRevision = 0
69
+ let schemePressAnimation
70
+ let schemePointer
71
+ let suppressSchemeClick = false
72
+ let suppressSchemeClickTimer
53
73
  let themeDisable
54
74
  let connectionIndicator
55
75
  let conversationObserver
56
76
  let schemeObserver
57
77
  let operationRegion
78
+ const schemePressDelays = new Set()
79
+
80
+ function reducedMotion() {
81
+ if (root.dataset.prtsMotion === 'reduced') return true
82
+ try { return window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true } catch { return false }
83
+ }
84
+
85
+ function phoneRailGesture() {
86
+ if (railMode !== 'overlay' || Number(window.innerWidth) > PHONE_RAIL_BREAKPOINT) return false
87
+ return railPointerQuery?.matches === true
88
+ || railHoverQuery?.matches === true
89
+ || Number(window.navigator?.maxTouchPoints) > 0
90
+ }
91
+
92
+ function clearRailGesture({ release = true } = {}) {
93
+ if (railHoldTimer !== undefined) window.clearTimeout(railHoldTimer)
94
+ railHoldTimer = undefined
95
+ const pointer = railPointer
96
+ railPointer = undefined
97
+ if (release && pointer) {
98
+ try { railLauncher?.releasePointerCapture?.(pointer.pointerId) } catch {}
99
+ }
100
+ railLauncher?.removeAttribute('data-prts-rail-gesture-active')
101
+ railLauncher?.removeAttribute('data-prts-rail-gesture-ready')
102
+ railLauncher?.style?.removeProperty('--prts-rail-gesture-progress')
103
+ }
104
+
105
+ function armRailGesture() {
106
+ railHoldTimer = undefined
107
+ if (!railPointer || !phoneRailGesture()) return
108
+ railPointer.armed = true
109
+ railLauncher?.setAttribute('data-prts-rail-gesture-active', '')
110
+ }
111
+
112
+ function onRailPointerDown(event) {
113
+ if (!phoneRailGesture() || railPointer || (event.button ?? 0) !== 0) return
114
+ const pointerId = event.pointerId ?? 1
115
+ railPointer = {
116
+ pointerId,
117
+ startX: Number(event.clientX) || 0,
118
+ startY: Number(event.clientY) || 0,
119
+ armed: false,
120
+ ready: false,
121
+ }
122
+ try { railLauncher?.setPointerCapture?.(pointerId) } catch {}
123
+ railHoldTimer = window.setTimeout(armRailGesture, RAIL_HOLD_DELAY_MS)
124
+ }
125
+
126
+ function onRailPointerMove(event) {
127
+ const pointer = railPointer
128
+ if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
129
+ const deltaX = (Number(event.clientX) || 0) - pointer.startX
130
+ const deltaY = (Number(event.clientY) || 0) - pointer.startY
131
+ if (!pointer.armed) {
132
+ if (Math.hypot(deltaX, deltaY) > RAIL_HOLD_MOVE_TOLERANCE) clearRailGesture()
133
+ return
134
+ }
135
+ event.preventDefault?.()
136
+ if (Math.abs(deltaX) > Math.max(RAIL_HOLD_MOVE_TOLERANCE, Math.max(0, deltaY) / RAIL_SWIPE_AXIS_RATIO)) {
137
+ clearRailGesture()
138
+ return
139
+ }
140
+ const progress = Math.min(1, Math.max(0, deltaY) / RAIL_SWIPE_THRESHOLD)
141
+ pointer.ready = deltaY >= RAIL_SWIPE_THRESHOLD
142
+ && deltaY >= Math.abs(deltaX) * RAIL_SWIPE_AXIS_RATIO
143
+ railLauncher?.style?.setProperty('--prts-rail-gesture-progress', Math.round(progress * 12) + 'px')
144
+ railLauncher?.toggleAttribute('data-prts-rail-gesture-ready', pointer.ready)
145
+ }
146
+
147
+ function onRailPointerUp(event) {
148
+ const pointer = railPointer
149
+ if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
150
+ const shouldOpen = pointer.armed && pointer.ready
151
+ clearRailGesture()
152
+ if (shouldOpen) openRail()
153
+ }
154
+
155
+ function onRailLostPointerCapture(event) {
156
+ if (!railPointer || (event.pointerId ?? 1) !== railPointer.pointerId) return
157
+ clearRailGesture({ release: false })
158
+ }
159
+
160
+ function onRailClick(event) {
161
+ if (phoneRailGesture() && Number(event?.detail) > 0) {
162
+ event.preventDefault?.()
163
+ return
164
+ }
165
+ toggleRail()
166
+ }
167
+
168
+ function playSchemePress() {
169
+ if (!schemeToggle || reducedMotion()) return
170
+ const revision = ++schemePressRevision
171
+ schemePressAnimation?.cancel?.()
172
+ schemePressAnimation = undefined
173
+ schemeToggle.removeAttribute('data-prts-scheme-press')
174
+
175
+ if (typeof schemeToggle.animate === 'function') {
176
+ const animation = schemeToggle.animate([
177
+ { transform: 'translateY(0) scale(1)' },
178
+ { transform: 'translateY(0) scale(.96)', offset: 0.5 },
179
+ { transform: 'translateY(0) scale(1)' },
180
+ ], { duration: 100, easing: 'cubic-bezier(.22, 1, .36, 1)' })
181
+ schemePressAnimation = animation
182
+ Promise.resolve(animation.finished).catch(() => {}).finally(() => {
183
+ if (revision === schemePressRevision && schemePressAnimation === animation) schemePressAnimation = undefined
184
+ })
185
+ return
186
+ }
187
+
188
+ schemeToggle.setAttribute('data-prts-scheme-press', '')
189
+ const entry = { timer: undefined }
190
+ entry.timer = window.setTimeout(() => {
191
+ schemePressDelays.delete(entry)
192
+ if (revision === schemePressRevision) schemeToggle?.removeAttribute('data-prts-scheme-press')
193
+ }, 100)
194
+ schemePressDelays.add(entry)
195
+ }
196
+
197
+ function clearSchemePressDelays() {
198
+ schemePressRevision += 1
199
+ schemePressAnimation?.cancel?.()
200
+ schemePressAnimation = undefined
201
+ schemeToggle?.removeAttribute('data-prts-scheme-press')
202
+ for (const entry of schemePressDelays) {
203
+ window.clearTimeout(entry.timer)
204
+ }
205
+ schemePressDelays.clear()
206
+ }
207
+
208
+ function schemeTarget() {
209
+ const current = schemeIntent ?? (root.dataset.prtsScheme === 'dark' ? 'dark' : 'light')
210
+ return current === 'dark' ? 'light' : 'dark'
211
+ }
212
+
213
+ function schemeOrigin() {
214
+ const rect = schemeToggle?.getBoundingClientRect?.()
215
+ return rect ? { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 } : undefined
216
+ }
217
+
58
218
  function syncConversationState() {
59
219
  if (!operationRegion) return
60
220
  const candidate = operationRegion.querySelector(
@@ -65,13 +225,122 @@ export function createOperationsShell({
65
225
  settingsOverlay?.refreshScalePreview()
66
226
  }
67
227
 
68
- function toggleScheme() {
69
- onSchemeToggle(root.dataset.prtsScheme === 'dark' ? 'light' : 'dark')
228
+ function toggleScheme(event) {
229
+ if (suppressSchemeClick) {
230
+ event?.preventDefault?.()
231
+ return
232
+ }
233
+ const next = schemeTarget()
234
+ schemeIntent = next
235
+ playSchemePress()
236
+ let request
237
+ try { request = onSchemeToggle(next, { origin: schemeOrigin() }) } catch { request = undefined }
238
+ Promise.resolve(request).catch(() => {}).finally(() => {
239
+ if (schemeIntent === next) schemeIntent = undefined
240
+ })
241
+ }
242
+
243
+ function schemePointerProgress(event) {
244
+ const width = Math.max(1, Number(window.innerWidth) || Number(root.clientWidth) || 1)
245
+ return Math.min(1, Math.max(0, Number(event?.clientX) / width || 0))
246
+ }
247
+
248
+ function clearSchemeClickSuppression() {
249
+ if (suppressSchemeClickTimer !== undefined) window.clearTimeout(suppressSchemeClickTimer)
250
+ suppressSchemeClickTimer = undefined
251
+ suppressSchemeClick = false
252
+ }
253
+
254
+ function suppressNextSchemeClick() {
255
+ clearSchemeClickSuppression()
256
+ suppressSchemeClick = true
257
+ suppressSchemeClickTimer = window.setTimeout(() => {
258
+ suppressSchemeClickTimer = undefined
259
+ suppressSchemeClick = false
260
+ }, 0)
261
+ }
262
+
263
+ function settleSchemePointer({ commit = false } = {}) {
264
+ const pointer = schemePointer
265
+ if (!pointer) return
266
+ schemePointer = undefined
267
+ try { schemeToggle?.releasePointerCapture?.(pointer.pointerId) } catch {}
268
+ if (!pointer.dragging) return
269
+ suppressNextSchemeClick()
270
+ let result
271
+ try { result = pointer.gesture?.finish?.(commit) } catch { result = undefined }
272
+ Promise.resolve(result).catch(() => {}).finally(() => {
273
+ if (schemeIntent === pointer.target) schemeIntent = undefined
274
+ })
275
+ }
276
+
277
+ function onSchemePointerDown(event) {
278
+ if ((event.button ?? 0) !== 0 || schemePointer) return
279
+ const pointerId = event.pointerId ?? 1
280
+ schemePointer = {
281
+ pointerId,
282
+ startX: Number(event.clientX) || 0,
283
+ startY: Number(event.clientY) || 0,
284
+ target: schemeTarget(),
285
+ origin: schemeOrigin(),
286
+ dragging: false,
287
+ gesture: undefined,
288
+ }
289
+ try { schemeToggle?.setPointerCapture?.(pointerId) } catch {}
290
+ }
291
+
292
+ function onSchemePointerMove(event) {
293
+ const pointer = schemePointer
294
+ if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
295
+ const deltaX = (Number(event.clientX) || 0) - pointer.startX
296
+ if (!pointer.dragging) {
297
+ if (deltaX < 8) return
298
+ pointer.dragging = true
299
+ schemeIntent = pointer.target
300
+ playSchemePress()
301
+ const progress = schemePointerProgress(event)
302
+ try {
303
+ pointer.gesture = onSchemeDragStart(pointer.target, {
304
+ origin: pointer.origin,
305
+ progress,
306
+ clientX: Number(event.clientX) || 0,
307
+ })
308
+ } catch {
309
+ pointer.gesture = undefined
310
+ }
311
+ }
312
+ event.preventDefault?.()
313
+ pointer.gesture?.update?.(schemePointerProgress(event))
314
+ }
315
+
316
+ function onSchemePointerUp(event) {
317
+ const pointer = schemePointer
318
+ if (!pointer || (event.pointerId ?? 1) !== pointer.pointerId) return
319
+ const commit = pointer.dragging && schemePointerProgress(event) >= .5
320
+ settleSchemePointer({ commit })
321
+ }
322
+
323
+ function cancelSchemePointer() {
324
+ const pointer = schemePointer
325
+ if (!pointer) return
326
+ if (pointer.dragging) {
327
+ try { pointer.gesture?.cancel?.() } catch {}
328
+ }
329
+ schemePointer = undefined
330
+ try { schemeToggle?.releasePointerCapture?.(pointer.pointerId) } catch {}
331
+ if (pointer.dragging) suppressNextSchemeClick()
332
+ if (schemeIntent === pointer.target) schemeIntent = undefined
333
+ }
334
+
335
+ function onSchemeLostPointerCapture(event) {
336
+ if (!schemePointer || (event.pointerId ?? 1) !== schemePointer.pointerId) return
337
+ cancelSchemePointer()
70
338
  }
71
339
 
72
340
  function syncSchemeToggle() {
73
341
  if (!schemeToggle) return
74
342
  const current = root.dataset.prtsScheme === 'dark' ? 'dark' : 'light'
343
+ if (schemeIntent === current) schemeIntent = undefined
75
344
  schemeToggle.dataset.prtsSchemeCurrent = current
76
345
  schemeToggle.setAttribute('aria-label', current === 'dark' ? '切换到日间模式' : '切换到夜间模式')
77
346
  }
@@ -81,7 +350,8 @@ export function createOperationsShell({
81
350
  const overlay = railMode === 'overlay'
82
351
  const open = overlay && root.hasAttribute('data-prts-rail-open')
83
352
  railLauncher.setAttribute('aria-expanded', String(open))
84
- railLauncher.setAttribute('aria-label', open ? '关闭 P.R.T.S. 导航' : '打开 P.R.T.S. 导航')
353
+ const closedLabel = phoneRailGesture() ? '长按并向下滑动打开 P.R.T.S. 导航' : '打开 P.R.T.S. 导航'
354
+ railLauncher.setAttribute('aria-label', open ? '关闭 P.R.T.S. 导航' : closedLabel)
85
355
  if (overlay && !open) {
86
356
  navRail.setAttribute('aria-hidden', 'true')
87
357
  navRail.setAttribute('inert', '')
@@ -110,13 +380,17 @@ export function createOperationsShell({
110
380
  else window?.setTimeout?.(focusFirst, 0)
111
381
  }
112
382
 
113
- function setRailViewport(width = window.innerWidth) {
114
- const nextMode = Number(width) >= 1180 ? 'docked' : 'overlay'
115
- if (nextMode === railMode) return railMode
383
+ function setRailViewport(width = window.innerWidth, { forceClose = false } = {}) {
384
+ const nextViewport = Number(width) >= 1180 ? 'wide' : 'narrow'
385
+ const viewportChanged = nextViewport !== railViewport
386
+ const nextMode = railDefaultHidden || nextViewport === 'narrow' ? 'overlay' : 'docked'
387
+ const modeChanged = nextMode !== railMode
388
+ if (!viewportChanged && !modeChanged && !forceClose) return railMode
389
+ railViewport = nextViewport
116
390
  railMode = nextMode
391
+ clearRailGesture()
117
392
  root.dataset.prtsRailMode = nextMode
118
- if (nextMode === 'docked') root.removeAttribute('data-prts-rail-open')
119
- else root.removeAttribute('data-prts-rail-open')
393
+ root.removeAttribute('data-prts-rail-open')
120
394
  syncRailState()
121
395
  return nextMode
122
396
  }
@@ -134,23 +408,26 @@ export function createOperationsShell({
134
408
 
135
409
  function onDocumentClick(event) {
136
410
  if (railMode !== 'overlay' || !root.hasAttribute('data-prts-rail-open')) return
137
- if (navRail?.contains?.(event.target) || railLauncher?.contains?.(event.target)) return
411
+ const settingsPanel = shell?.querySelector?.('[data-prts-theme-settings]')
412
+ const insideSettingsContent = settingsPanel?.contains?.(event.target) && event.target !== settingsPanel
413
+ if (navRail?.contains?.(event.target) || railLauncher?.contains?.(event.target) || insideSettingsContent) return
138
414
  closeRail()
139
415
  }
140
416
 
141
- function onRailAction(event) {
142
- const action = event.target?.closest?.('[data-prts-rail-brand], [data-prts-scheme-toggle]')
143
- if (action && navRail?.contains?.(action)) closeRail()
144
- }
145
-
146
417
  function onResponsiveChange() {
418
+ clearRailGesture()
147
419
  setRailViewport(window.innerWidth)
420
+ syncRailState()
148
421
  settingsOverlay?.scheduleScalePreviewRefresh?.()
149
422
  }
150
423
 
151
424
  function bindResponsiveQueries() {
152
425
  railViewportQuery = window.matchMedia?.('(min-width: 1180px)')
426
+ railPointerQuery = window.matchMedia?.('(pointer: coarse)')
427
+ railHoverQuery = window.matchMedia?.('(hover: none)')
153
428
  railViewportQuery?.addEventListener?.('change', onResponsiveChange)
429
+ railPointerQuery?.addEventListener?.('change', onResponsiveChange)
430
+ railHoverQuery?.addEventListener?.('change', onResponsiveChange)
154
431
  }
155
432
  function disableTheme() { onThemeDisable() }
156
433
 
@@ -177,6 +454,7 @@ export function createOperationsShell({
177
454
  panel: shell.querySelector('[data-prts-theme-settings]'),
178
455
  backdrop: shell.querySelector('[data-prts-settings-backdrop]'),
179
456
  onPreferenceChange,
457
+ onPreferencePreview,
180
458
  onResetVisual: onVisualReset,
181
459
  onRetrySave,
182
460
  getConversationScalePreview,
@@ -190,11 +468,21 @@ export function createOperationsShell({
190
468
  conversationObserver.observe(operationRegion, { childList: true, subtree: true, attributes: true, attributeFilter: ['hidden', 'data-chat-flow-kind', 'data-message-role'] })
191
469
  schemeObserver = new window.MutationObserver(syncSchemeToggle)
192
470
  schemeObserver.observe(root, { attributes: true, attributeFilter: ['data-prts-scheme'] })
193
- railLauncher.addEventListener('click', toggleRail)
194
- navRail.addEventListener('click', onRailAction)
471
+ railLauncher.addEventListener('click', onRailClick)
472
+ railLauncher.addEventListener('pointerdown', onRailPointerDown)
473
+ railLauncher.addEventListener('pointermove', onRailPointerMove)
474
+ railLauncher.addEventListener('pointerup', onRailPointerUp)
475
+ railLauncher.addEventListener('pointercancel', clearRailGesture)
476
+ railLauncher.addEventListener('lostpointercapture', onRailLostPointerCapture)
195
477
  document.addEventListener('keydown', onRailKeydown)
196
478
  document.addEventListener('click', onDocumentClick)
197
479
  schemeToggle.addEventListener('click', toggleScheme)
480
+ schemeToggle.addEventListener('pointerdown', onSchemePointerDown)
481
+ schemeToggle.addEventListener('pointermove', onSchemePointerMove)
482
+ schemeToggle.addEventListener('pointerup', onSchemePointerUp)
483
+ schemeToggle.addEventListener('pointercancel', cancelSchemePointer)
484
+ schemeToggle.addEventListener('lostpointercapture', onSchemeLostPointerCapture)
485
+ window.addEventListener?.('blur', cancelSchemePointer)
198
486
  themeDisable.addEventListener('click', disableTheme)
199
487
  syncConversationState()
200
488
  syncSchemeToggle()
@@ -202,14 +490,32 @@ export function createOperationsShell({
202
490
  }
203
491
 
204
492
  function dispose() {
205
- railLauncher?.removeEventListener('click', toggleRail)
206
- navRail?.removeEventListener('click', onRailAction)
493
+ clearRailGesture()
494
+ cancelSchemePointer()
495
+ clearSchemeClickSuppression()
496
+ clearSchemePressDelays()
497
+ railLauncher?.removeEventListener('click', onRailClick)
498
+ railLauncher?.removeEventListener('pointerdown', onRailPointerDown)
499
+ railLauncher?.removeEventListener('pointermove', onRailPointerMove)
500
+ railLauncher?.removeEventListener('pointerup', onRailPointerUp)
501
+ railLauncher?.removeEventListener('pointercancel', clearRailGesture)
502
+ railLauncher?.removeEventListener('lostpointercapture', onRailLostPointerCapture)
207
503
  document.removeEventListener('keydown', onRailKeydown)
208
504
  document.removeEventListener('click', onDocumentClick)
209
505
  schemeToggle?.removeEventListener('click', toggleScheme)
506
+ schemeToggle?.removeEventListener('pointerdown', onSchemePointerDown)
507
+ schemeToggle?.removeEventListener('pointermove', onSchemePointerMove)
508
+ schemeToggle?.removeEventListener('pointerup', onSchemePointerUp)
509
+ schemeToggle?.removeEventListener('pointercancel', cancelSchemePointer)
510
+ schemeToggle?.removeEventListener('lostpointercapture', onSchemeLostPointerCapture)
511
+ window.removeEventListener?.('blur', cancelSchemePointer)
210
512
  themeDisable?.removeEventListener('click', disableTheme)
211
513
  railViewportQuery?.removeEventListener?.('change', onResponsiveChange)
514
+ railPointerQuery?.removeEventListener?.('change', onResponsiveChange)
515
+ railHoverQuery?.removeEventListener?.('change', onResponsiveChange)
212
516
  railViewportQuery = undefined
517
+ railPointerQuery = undefined
518
+ railHoverQuery = undefined
213
519
  resizeShield.dispose()
214
520
  settingsOverlay?.dispose()
215
521
  conversationObserver?.disconnect()
@@ -218,7 +524,10 @@ export function createOperationsShell({
218
524
  root.removeAttribute('data-prts-conversation-state')
219
525
  root.removeAttribute('data-prts-rail-mode')
220
526
  root.removeAttribute('data-prts-rail-open')
221
- navRail = railLauncher = railMode = undefined
527
+ root.removeAttribute('data-prts-rail-default-hidden')
528
+ navRail = railLauncher = railMode = railViewport = undefined
529
+ railDefaultHidden = false
530
+ schemeIntent = undefined
222
531
  shell = settingsOverlay = schemeToggle = themeDisable = connectionIndicator = undefined
223
532
  conversationObserver = schemeObserver = undefined
224
533
  operationRegion = undefined
@@ -232,7 +541,12 @@ export function createOperationsShell({
232
541
  dispose()
233
542
  return false
234
543
  }
544
+ const nextRailDefaultHidden = Boolean(preferences.railDefaultHidden)
545
+ const railPreferenceChanged = nextRailDefaultHidden !== railDefaultHidden
546
+ railDefaultHidden = nextRailDefaultHidden
235
547
  if (!mount()) return false
548
+ root.toggleAttribute('data-prts-rail-default-hidden', railDefaultHidden)
549
+ setRailViewport(window.innerWidth, { forceClose: railPreferenceChanged })
236
550
  const connection = status?.connection || 'unknown'
237
551
  const connectionLabel = status?.connectionLabel || '未知'
238
552
  connectionIndicator.dataset.state = connection