xterm-input-panel 1.2.1 → 1.2.3
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/CHANGELOG.md +16 -0
- package/package.json +18 -14
- package/src/storage-namespace.test.ts +22 -0
- package/src/storage-namespace.ts +17 -0
- package/src/virtual-trackpad-tab.stories.ts +5 -3
- package/src/xterm-addon.stories.ts +15 -0
- package/src/xterm-addon.ts +3 -3
- package/LICENSE +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# xterm-input-panel
|
|
2
2
|
|
|
3
|
+
## 1.2.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6dcad78: Upgrade the Vite toolchain to Vite 8 and align the related React, Storybook, and Vitest integrations used by local build and browser-test workflows.
|
|
8
|
+
|
|
9
|
+
## 1.2.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 143b916: Add hosted app distribution support across the CLI, server, and web runtime.
|
|
14
|
+
- add `openspecui --app` with configurable hosted app base URLs and local hosted-app dev mode
|
|
15
|
+
- expose hosted session/bootstrap helpers so versioned frontend entries can reconnect to the correct backend
|
|
16
|
+
- include hosted-app settings and faster dashboard overview loading for the web UI
|
|
17
|
+
- scope xterm input-panel persisted state by hosted session to avoid cross-tab leakage
|
|
18
|
+
|
|
3
19
|
## 1.2.1
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xterm-input-panel",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "storybook dev -p 6007",
|
|
8
|
+
"test:browser": "vitest run --retry 2 --config vitest.storybook.config.ts",
|
|
9
|
+
"typecheck": "tsc --noEmit"
|
|
10
|
+
},
|
|
6
11
|
"dependencies": {
|
|
7
12
|
"lit": "^3.3.2",
|
|
8
13
|
"lucide": "^0.472.0",
|
|
@@ -17,21 +22,20 @@
|
|
|
17
22
|
}
|
|
18
23
|
},
|
|
19
24
|
"devDependencies": {
|
|
20
|
-
"@storybook/addon-vitest": "^10.2.
|
|
21
|
-
"@storybook/web-components": "^10.2.
|
|
22
|
-
"@storybook/web-components-vite": "^10.2.
|
|
23
|
-
"@vitest/browser": "^4.0
|
|
24
|
-
"@vitest/browser-playwright": "^4.0
|
|
25
|
+
"@storybook/addon-vitest": "^10.2.19",
|
|
26
|
+
"@storybook/web-components": "^10.2.19",
|
|
27
|
+
"@storybook/web-components-vite": "^10.2.19",
|
|
28
|
+
"@vitest/browser": "^4.1.0",
|
|
29
|
+
"@vitest/browser-playwright": "^4.1.0",
|
|
25
30
|
"@xterm/xterm": "6.1.0-beta.167",
|
|
26
31
|
"playwright": "^1.58.2",
|
|
27
|
-
"storybook": "^10.2.
|
|
32
|
+
"storybook": "^10.2.19",
|
|
28
33
|
"typescript": "^5.7.2",
|
|
29
|
-
"vite": "^
|
|
30
|
-
"vitest": "^4.0
|
|
34
|
+
"vite": "^8.0.0",
|
|
35
|
+
"vitest": "^4.1.0"
|
|
31
36
|
},
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"typecheck": "tsc --noEmit"
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/jixoai/openspecui"
|
|
36
40
|
}
|
|
37
|
-
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getSessionScopedStorageKey } from './storage-namespace'
|
|
3
|
+
|
|
4
|
+
describe('storage namespace helpers', () => {
|
|
5
|
+
it('scopes hosted version entries by session', () => {
|
|
6
|
+
expect(
|
|
7
|
+
getSessionScopedStorageKey('xtermInputPanelState', {
|
|
8
|
+
pathname: '/versions/v2.1/index.html',
|
|
9
|
+
search: '?session=session-a',
|
|
10
|
+
})
|
|
11
|
+
).toBe('hosted-session:session-a:xtermInputPanelState')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('keeps non-hosted keys unchanged', () => {
|
|
15
|
+
expect(
|
|
16
|
+
getSessionScopedStorageKey('xtermInputPanelState', {
|
|
17
|
+
pathname: '/dashboard',
|
|
18
|
+
search: '?session=session-a',
|
|
19
|
+
})
|
|
20
|
+
).toBe('xtermInputPanelState')
|
|
21
|
+
})
|
|
22
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const HOSTED_VERSION_PATH_RE = /^\/versions\/[^/]+(?:\/|$)/
|
|
2
|
+
|
|
3
|
+
function getHostedSessionId(locationLike: Pick<Location, 'pathname' | 'search'>): string | null {
|
|
4
|
+
if (!HOSTED_VERSION_PATH_RE.test(locationLike.pathname)) {
|
|
5
|
+
return null
|
|
6
|
+
}
|
|
7
|
+
const value = new URLSearchParams(locationLike.search).get('session')?.trim()
|
|
8
|
+
return value ? value : null
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getSessionScopedStorageKey(
|
|
12
|
+
baseKey: string,
|
|
13
|
+
locationLike: Pick<Location, 'pathname' | 'search'> = window.location
|
|
14
|
+
): string {
|
|
15
|
+
const sessionId = getHostedSessionId(locationLike)
|
|
16
|
+
return sessionId ? `hosted-session:${sessionId}:${baseKey}` : baseKey
|
|
17
|
+
}
|
|
@@ -129,7 +129,8 @@ export const DoubleTapEvent: StoryObj = {
|
|
|
129
129
|
pointer(canvas, 'pointerdown', cx, cy)
|
|
130
130
|
pointer(canvas, 'pointerup', cx, cy)
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
// Fire the second tap immediately so CI scheduler jitter cannot push the gesture outside
|
|
133
|
+
// the double-tap window.
|
|
133
134
|
|
|
134
135
|
// Second tap (within 300ms)
|
|
135
136
|
pointer(canvas, 'pointerdown', cx, cy)
|
|
@@ -194,7 +195,8 @@ export const DragEvent: StoryObj = {
|
|
|
194
195
|
pointer(canvas, 'pointerdown', cx, cy)
|
|
195
196
|
pointer(canvas, 'pointerup', cx, cy)
|
|
196
197
|
|
|
197
|
-
|
|
198
|
+
// Start the second touch immediately so the drag sequence stays inside the same
|
|
199
|
+
// second-touch detection window in slower CI browsers.
|
|
198
200
|
|
|
199
201
|
// Second: tap-and-hold then drag (within 300ms of first tap)
|
|
200
202
|
pointer(canvas, 'pointerdown', cx, cy)
|
|
@@ -232,7 +234,7 @@ export const DragMoveDeltas: StoryObj = {
|
|
|
232
234
|
// Tap first
|
|
233
235
|
pointer(canvas, 'pointerdown', cx, cy)
|
|
234
236
|
pointer(canvas, 'pointerup', cx, cy)
|
|
235
|
-
|
|
237
|
+
// Start the drag immediately so the second touch stays within the same gesture window.
|
|
236
238
|
|
|
237
239
|
// Tap-and-drag
|
|
238
240
|
pointer(canvas, 'pointerdown', cx, cy)
|
|
@@ -7,8 +7,19 @@ import { InputPanelAddon } from './xterm-addon.js'
|
|
|
7
7
|
// Register all custom elements (critical — xterm-addon.ts does NOT import these)
|
|
8
8
|
import './index.js'
|
|
9
9
|
|
|
10
|
+
const storyCleanups = new Set<() => void>()
|
|
11
|
+
|
|
10
12
|
/** Reset singleton state between stories */
|
|
11
13
|
function resetAddonState() {
|
|
14
|
+
for (const cleanup of storyCleanups) {
|
|
15
|
+
try {
|
|
16
|
+
cleanup()
|
|
17
|
+
} catch {
|
|
18
|
+
/* ignore test cleanup failures */
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
storyCleanups.clear()
|
|
22
|
+
|
|
12
23
|
// Force-close any active instance
|
|
13
24
|
const active = InputPanelAddon.activeInstance
|
|
14
25
|
if (active) active.close()
|
|
@@ -33,6 +44,10 @@ function setupTerminal(container: HTMLElement, opts?: { stateKey?: string }) {
|
|
|
33
44
|
const addon = new InputPanelAddon({ onInput: inputHandler, stateKey: opts?.stateKey })
|
|
34
45
|
terminal.loadAddon(addon)
|
|
35
46
|
terminal.open(container)
|
|
47
|
+
storyCleanups.add(() => {
|
|
48
|
+
addon.dispose()
|
|
49
|
+
terminal.dispose()
|
|
50
|
+
})
|
|
36
51
|
|
|
37
52
|
return { terminal, addon, inputHandler }
|
|
38
53
|
}
|
package/src/xterm-addon.ts
CHANGED
|
@@ -2,12 +2,12 @@ import type { ITerminalAddon, Terminal } from '@xterm/xterm'
|
|
|
2
2
|
import { iconKeyboard, iconMousePointer2 } from './icons.js'
|
|
3
3
|
import type { InputPanelLayout, InputPanelTab } from './input-panel.js'
|
|
4
4
|
import type { HostPlatform } from './platform.js'
|
|
5
|
+
import { getSessionScopedStorageKey } from './storage-namespace.js'
|
|
5
6
|
|
|
6
7
|
const SENSITIVITY = 1.5
|
|
7
8
|
const EDGE_SCROLL_ZONE = 30
|
|
8
9
|
const EDGE_SCROLL_INTERVAL = 50
|
|
9
10
|
const EDGE_SCROLL_OVERSHOOT = 15
|
|
10
|
-
const STATE_STORAGE_KEY = 'xtermInputPanelState'
|
|
11
11
|
|
|
12
12
|
function isTouchDevice(): boolean {
|
|
13
13
|
return 'ontouchstart' in window || navigator.maxTouchPoints > 0
|
|
@@ -60,7 +60,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
60
60
|
|
|
61
61
|
function loadPanelStateStore(): InputPanelStateStore {
|
|
62
62
|
try {
|
|
63
|
-
const raw = localStorage.getItem(
|
|
63
|
+
const raw = localStorage.getItem(getSessionScopedStorageKey('xtermInputPanelState'))
|
|
64
64
|
if (!raw) return {}
|
|
65
65
|
const parsed = JSON.parse(raw)
|
|
66
66
|
return isRecord(parsed) ? (parsed as InputPanelStateStore) : {}
|
|
@@ -71,7 +71,7 @@ function loadPanelStateStore(): InputPanelStateStore {
|
|
|
71
71
|
|
|
72
72
|
function savePanelStateStore(store: InputPanelStateStore): void {
|
|
73
73
|
try {
|
|
74
|
-
localStorage.setItem(
|
|
74
|
+
localStorage.setItem(getSessionScopedStorageKey('xtermInputPanelState'), JSON.stringify(store))
|
|
75
75
|
} catch {
|
|
76
76
|
/* ignore */
|
|
77
77
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 OpenSpecUI Contributors
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|