@kubohiroya/turbowarp-plus-editor-layout 0.1.6 → 0.1.7
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/sprite-asset-pane.d.ts +45 -0
- package/dist/sprite-asset-pane.js +43 -0
- package/dist/sprite-tabs.d.ts +3 -1
- package/dist/sprite-tabs.js +33 -27
- package/package.json +1 -1
- package/src/sprite-asset-pane.tsx +96 -0
- package/src/sprite-tabs.ts +31 -22
|
@@ -1,4 +1,49 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type { SpriteAssetPreviewItem } from './sprite-tabs.ts';
|
|
3
|
+
interface NativeAssetPanelProps {
|
|
4
|
+
children?: React.ReactNode;
|
|
5
|
+
buttons: readonly {
|
|
6
|
+
title: string;
|
|
7
|
+
img: string;
|
|
8
|
+
onClick(): void;
|
|
9
|
+
}[];
|
|
10
|
+
items: readonly {
|
|
11
|
+
dragPayload?: object;
|
|
12
|
+
name: string;
|
|
13
|
+
url?: string;
|
|
14
|
+
details?: React.ReactNode;
|
|
15
|
+
}[];
|
|
16
|
+
isRtl?: boolean;
|
|
17
|
+
listActions?: React.ElementType;
|
|
18
|
+
selectedItemIndex: number;
|
|
19
|
+
onItemClick(index: number): void;
|
|
20
|
+
}
|
|
21
|
+
interface NativeSelectorProps extends NativeAssetPanelProps {
|
|
22
|
+
wrapperAttributes?: Record<string, string>;
|
|
23
|
+
listRef?(node: HTMLElement | null): void;
|
|
24
|
+
onListScroll?(event: React.UIEvent<HTMLElement>): void;
|
|
25
|
+
draggingType?: null;
|
|
26
|
+
onAddSortable?(): void;
|
|
27
|
+
onRemoveSortable?(): void;
|
|
28
|
+
}
|
|
29
|
+
export type NativeAssetSelector = React.ComponentType<NativeSelectorProps>;
|
|
30
|
+
export type NativeAssetPanelRenderer = (props: NativeAssetPanelProps, options: {
|
|
31
|
+
panelAttributes: Record<string, string>;
|
|
32
|
+
detailAttributes: Record<string, string>;
|
|
33
|
+
renderSelector(Component: NativeAssetSelector, props: NativeSelectorProps): React.ReactNode;
|
|
34
|
+
}) => React.ReactNode;
|
|
35
|
+
export type SpriteAssetLayout = (items: readonly SpriteAssetPreviewItem[], index: number, detail: React.ReactNode, scrollTop: number) => React.ReactNode;
|
|
36
|
+
interface PanelState {
|
|
37
|
+
rememberLayout(render: SpriteAssetLayout): void;
|
|
38
|
+
getScrollTop(): number;
|
|
39
|
+
rememberScrollTop(position: number): void;
|
|
40
|
+
}
|
|
41
|
+
export declare function NativeAssetPanel({ render, previewSelector, panel, state }: {
|
|
42
|
+
render: NativeAssetPanelRenderer;
|
|
43
|
+
previewSelector: NativeAssetSelector;
|
|
44
|
+
panel: NativeAssetPanelProps;
|
|
45
|
+
state: PanelState;
|
|
46
|
+
}): React.JSX.Element;
|
|
2
47
|
export interface SpriteMediaAsset {
|
|
3
48
|
/** Host identity for this item within its target, independent of the list order. */
|
|
4
49
|
id: string;
|
|
@@ -1,4 +1,47 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
const noop = () => { };
|
|
3
|
+
function NativeAssetPanelSurface({ render, panel, state, previewSelector, scrollTop }) {
|
|
4
|
+
const list = React.useRef(null);
|
|
5
|
+
const setList = React.useCallback((node) => {
|
|
6
|
+
list.current = node;
|
|
7
|
+
}, []);
|
|
8
|
+
React.useLayoutEffect(() => {
|
|
9
|
+
const position = state?.getScrollTop() ?? scrollTop;
|
|
10
|
+
if (list.current && position !== undefined)
|
|
11
|
+
list.current.scrollTop = position;
|
|
12
|
+
}, [state, scrollTop]);
|
|
13
|
+
return render(panel, {
|
|
14
|
+
panelAttributes: { 'data-layout-asset-panel': '' },
|
|
15
|
+
detailAttributes: { 'data-layout-asset-detail': '' },
|
|
16
|
+
renderSelector(Component, props) {
|
|
17
|
+
const selectorProps = { ...props, listRef: setList, wrapperAttributes: { 'data-layout-asset-list': '' } };
|
|
18
|
+
if (previewSelector) {
|
|
19
|
+
return React.createElement("div", { inert: '', style: { display: 'contents' } }, React.createElement(previewSelector, {
|
|
20
|
+
...selectorProps, draggingType: null, onAddSortable: noop, onRemoveSortable: noop
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
return React.createElement(Component, { ...selectorProps, onListScroll: event => {
|
|
24
|
+
state?.rememberScrollTop(event.currentTarget.scrollTop);
|
|
25
|
+
} });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function NativeAssetPanel({ render, previewSelector, panel, state }) {
|
|
30
|
+
const { items, buttons, isRtl, listActions } = panel;
|
|
31
|
+
React.useLayoutEffect(() => {
|
|
32
|
+
const previousItems = new Map(items.map(item => [item.dragPayload, item]));
|
|
33
|
+
const readOnlyButtons = buttons.map(({ title, img }) => ({ title, img, onClick: noop }));
|
|
34
|
+
state.rememberLayout((previewItems, selectedItemIndex, detail, scrollTop) => React.createElement(NativeAssetPanelSurface, { render: render, previewSelector: previewSelector, scrollTop: scrollTop, panel: {
|
|
35
|
+
isRtl, listActions, selectedItemIndex, buttons: readOnlyButtons,
|
|
36
|
+
onItemClick: noop, children: detail,
|
|
37
|
+
items: previewItems.map(item => {
|
|
38
|
+
const previous = previousItems.get(item.asset);
|
|
39
|
+
return { name: item.name, url: item.imageUrl || previous?.url, details: previous?.details };
|
|
40
|
+
})
|
|
41
|
+
} }));
|
|
42
|
+
}, [state, render, previewSelector, items, buttons, isRtl, listActions]);
|
|
43
|
+
return React.createElement(NativeAssetPanelSurface, { render: render, panel: panel, state: state });
|
|
44
|
+
}
|
|
2
45
|
const english = {
|
|
3
46
|
costumes: 'Costumes', sounds: 'Sounds', variables: 'Variables', name: 'Name', value: 'Value',
|
|
4
47
|
local: 'Sprite', global: 'Project', emptyCostumes: 'No costumes', emptySounds: 'No sounds',
|
package/dist/sprite-tabs.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { NativeAssetPanel } from './sprite-asset-pane.tsx';
|
|
3
|
+
import type { NativeAssetPanelRenderer, NativeAssetSelector, SpriteAssetLayout } from './sprite-asset-pane.tsx';
|
|
2
4
|
import type { SpriteVariable } from './sprite-asset-pane.tsx';
|
|
3
5
|
import type { SpriteSearchResult } from './sprite-editor-toolbar.tsx';
|
|
4
6
|
import type { DockviewStagePane } from './dockview-stage.ts';
|
|
@@ -49,6 +51,7 @@ export interface SpriteTabAdapter<Snapshot = unknown> {
|
|
|
49
51
|
export interface SpriteAssetSelection {
|
|
50
52
|
restore(target: object, assets: readonly object[]): number | undefined;
|
|
51
53
|
remember(target: object, asset: object | undefined, select?: (index: number) => void): void;
|
|
54
|
+
renderPanel?(render: NativeAssetPanelRenderer, previewSelector: NativeAssetSelector, panel: React.ComponentProps<typeof NativeAssetPanel>['panel']): React.ReactNode;
|
|
52
55
|
rememberLayout?(render: SpriteAssetLayout): void;
|
|
53
56
|
getScrollTop?(): number;
|
|
54
57
|
rememberScrollTop?(position: number): void;
|
|
@@ -62,7 +65,6 @@ export interface SpriteAssetPreviewItem {
|
|
|
62
65
|
buffer?: AudioBuffer;
|
|
63
66
|
duration?: number;
|
|
64
67
|
}
|
|
65
|
-
type SpriteAssetLayout = (items: readonly SpriteAssetPreviewItem[], index: number, detail: React.ReactNode, scrollTop: number) => React.ReactNode;
|
|
66
68
|
export interface SpriteAssetPreviewData {
|
|
67
69
|
items: readonly SpriteAssetPreviewItem[];
|
|
68
70
|
defaultAsset?: object;
|
package/dist/sprite-tabs.js
CHANGED
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { createPortal } from 'react-dom';
|
|
3
3
|
import { createDockview, DefaultTab, themeLight } from 'dockview';
|
|
4
4
|
import { createSpriteLayoutMenu } from "./sprite-layout-menu.js";
|
|
5
|
-
import { SpriteAssetPane } from "./sprite-asset-pane.js";
|
|
5
|
+
import { NativeAssetPanel, SpriteAssetPane } from "./sprite-asset-pane.js";
|
|
6
6
|
import { SpriteEditorToolbar, spriteEditorSections } from "./sprite-editor-toolbar.js";
|
|
7
7
|
import { getDocumentWorkspace } from "./document-workspace.js";
|
|
8
8
|
import { readWorkspaceLayout } from "./workspace-layout.js";
|
|
@@ -14,32 +14,38 @@ function createAssetSelections(target, source) {
|
|
|
14
14
|
const layouts = new Map(source?.layouts);
|
|
15
15
|
const scroll = new Map(source?.scroll);
|
|
16
16
|
const selectors = new Map();
|
|
17
|
-
const forKind = (kind) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
17
|
+
const forKind = (kind) => {
|
|
18
|
+
const state = {
|
|
19
|
+
rememberLayout(render) {
|
|
20
|
+
layouts.set(kind, render);
|
|
21
|
+
},
|
|
22
|
+
getScrollTop: () => scroll.get(kind) ?? 0,
|
|
23
|
+
rememberScrollTop(position) {
|
|
24
|
+
scroll.set(kind, position);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
...state,
|
|
29
|
+
renderPanel: (render, previewSelector, panel) => React.createElement(NativeAssetPanel, { render, previewSelector, panel, state }),
|
|
30
|
+
restore(current, assets) {
|
|
31
|
+
if (current !== target)
|
|
32
|
+
return;
|
|
33
|
+
const index = assets.indexOf(selected.get(kind));
|
|
34
|
+
if (index >= 0)
|
|
35
|
+
return index;
|
|
36
|
+
},
|
|
37
|
+
remember(current, asset, select) {
|
|
38
|
+
if (current !== target)
|
|
39
|
+
return;
|
|
40
|
+
if (asset)
|
|
41
|
+
selected.set(kind, asset);
|
|
42
|
+
else
|
|
43
|
+
selected.delete(kind);
|
|
44
|
+
if (select)
|
|
45
|
+
selectors.set(kind, select);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
};
|
|
43
49
|
const ports = { costumes: forKind('costumes'), sounds: forKind('sounds') };
|
|
44
50
|
return { selected, ports, layouts, selectors, scroll };
|
|
45
51
|
}
|
package/package.json
CHANGED
|
@@ -1,4 +1,100 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import type {SpriteAssetPreviewItem} from './sprite-tabs.ts';
|
|
3
|
+
|
|
4
|
+
interface NativeAssetPanelProps {
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
buttons: readonly {title: string; img: string; onClick(): void}[];
|
|
7
|
+
items: readonly {dragPayload?: object; name: string; url?: string; details?: React.ReactNode}[];
|
|
8
|
+
isRtl?: boolean;
|
|
9
|
+
listActions?: React.ElementType;
|
|
10
|
+
selectedItemIndex: number;
|
|
11
|
+
onItemClick(index: number): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface NativeSelectorProps extends NativeAssetPanelProps {
|
|
15
|
+
wrapperAttributes?: Record<string, string>;
|
|
16
|
+
listRef?(node: HTMLElement | null): void;
|
|
17
|
+
onListScroll?(event: React.UIEvent<HTMLElement>): void;
|
|
18
|
+
draggingType?: null;
|
|
19
|
+
onAddSortable?(): void;
|
|
20
|
+
onRemoveSortable?(): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type NativeAssetSelector = React.ComponentType<NativeSelectorProps>;
|
|
24
|
+
export type NativeAssetPanelRenderer = (props: NativeAssetPanelProps, options: {
|
|
25
|
+
panelAttributes: Record<string, string>;
|
|
26
|
+
detailAttributes: Record<string, string>;
|
|
27
|
+
renderSelector(Component: NativeAssetSelector, props: NativeSelectorProps): React.ReactNode;
|
|
28
|
+
}) => React.ReactNode;
|
|
29
|
+
|
|
30
|
+
export type SpriteAssetLayout = (items: readonly SpriteAssetPreviewItem[], index: number,
|
|
31
|
+
detail: React.ReactNode, scrollTop: number) => React.ReactNode;
|
|
32
|
+
|
|
33
|
+
interface PanelState {
|
|
34
|
+
rememberLayout(render: SpriteAssetLayout): void;
|
|
35
|
+
getScrollTop(): number;
|
|
36
|
+
rememberScrollTop(position: number): void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const noop = () => {};
|
|
40
|
+
|
|
41
|
+
function NativeAssetPanelSurface({render, panel, state, previewSelector, scrollTop}: {
|
|
42
|
+
render: NativeAssetPanelRenderer;
|
|
43
|
+
panel: NativeAssetPanelProps;
|
|
44
|
+
state?: PanelState;
|
|
45
|
+
previewSelector?: NativeAssetSelector;
|
|
46
|
+
scrollTop?: number;
|
|
47
|
+
}) {
|
|
48
|
+
const list = React.useRef<HTMLElement | null>(null);
|
|
49
|
+
const setList = React.useCallback((node: HTMLElement | null) => {
|
|
50
|
+
list.current = node;
|
|
51
|
+
}, []);
|
|
52
|
+
React.useLayoutEffect(() => {
|
|
53
|
+
const position = state?.getScrollTop() ?? scrollTop;
|
|
54
|
+
if (list.current && position !== undefined) list.current.scrollTop = position;
|
|
55
|
+
}, [state, scrollTop]);
|
|
56
|
+
|
|
57
|
+
return render(panel, {
|
|
58
|
+
panelAttributes: {'data-layout-asset-panel': ''},
|
|
59
|
+
detailAttributes: {'data-layout-asset-detail': ''},
|
|
60
|
+
renderSelector(Component, props) {
|
|
61
|
+
const selectorProps = {...props, listRef: setList, wrapperAttributes: {'data-layout-asset-list': ''}};
|
|
62
|
+
if (previewSelector) {
|
|
63
|
+
return <div {...{inert: ''}} style={{display: 'contents'}}>
|
|
64
|
+
{React.createElement(previewSelector, {
|
|
65
|
+
...selectorProps, draggingType: null, onAddSortable: noop, onRemoveSortable: noop
|
|
66
|
+
})}
|
|
67
|
+
</div>;
|
|
68
|
+
}
|
|
69
|
+
return <Component {...selectorProps} onListScroll={event => {
|
|
70
|
+
state?.rememberScrollTop(event.currentTarget.scrollTop);
|
|
71
|
+
}} />;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function NativeAssetPanel({render, previewSelector, panel, state}: {
|
|
77
|
+
render: NativeAssetPanelRenderer;
|
|
78
|
+
previewSelector: NativeAssetSelector;
|
|
79
|
+
panel: NativeAssetPanelProps;
|
|
80
|
+
state: PanelState;
|
|
81
|
+
}) {
|
|
82
|
+
const {items, buttons, isRtl, listActions} = panel;
|
|
83
|
+
React.useLayoutEffect(() => {
|
|
84
|
+
const previousItems = new Map(items.map(item => [item.dragPayload, item]));
|
|
85
|
+
const readOnlyButtons = buttons.map(({title, img}) => ({title, img, onClick: noop}));
|
|
86
|
+
state.rememberLayout((previewItems, selectedItemIndex, detail, scrollTop) => <NativeAssetPanelSurface
|
|
87
|
+
render={render} previewSelector={previewSelector} scrollTop={scrollTop} panel={{
|
|
88
|
+
isRtl, listActions, selectedItemIndex, buttons: readOnlyButtons,
|
|
89
|
+
onItemClick: noop, children: detail,
|
|
90
|
+
items: previewItems.map(item => {
|
|
91
|
+
const previous = previousItems.get(item.asset);
|
|
92
|
+
return {name: item.name, url: item.imageUrl || previous?.url, details: previous?.details};
|
|
93
|
+
})
|
|
94
|
+
}} />);
|
|
95
|
+
}, [state, render, previewSelector, items, buttons, isRtl, listActions]);
|
|
96
|
+
return <NativeAssetPanelSurface render={render} panel={panel} state={state} />;
|
|
97
|
+
}
|
|
2
98
|
|
|
3
99
|
export interface SpriteMediaAsset {
|
|
4
100
|
/** Host identity for this item within its target, independent of the list order. */
|
package/src/sprite-tabs.ts
CHANGED
|
@@ -3,7 +3,8 @@ import {createPortal} from 'react-dom';
|
|
|
3
3
|
import {createDockview, DefaultTab, themeLight} from 'dockview';
|
|
4
4
|
import type {DockviewGroupPanel, GroupPanelPartInitParameters, IDockviewPanel, SerializedDockview} from 'dockview';
|
|
5
5
|
import {createSpriteLayoutMenu} from './sprite-layout-menu.ts';
|
|
6
|
-
import {SpriteAssetPane} from './sprite-asset-pane.tsx';
|
|
6
|
+
import {NativeAssetPanel, SpriteAssetPane} from './sprite-asset-pane.tsx';
|
|
7
|
+
import type {NativeAssetPanelRenderer, NativeAssetSelector, SpriteAssetLayout} from './sprite-asset-pane.tsx';
|
|
7
8
|
import type {SpriteVariable} from './sprite-asset-pane.tsx';
|
|
8
9
|
import {SpriteEditorToolbar, spriteEditorSections} from './sprite-editor-toolbar.tsx';
|
|
9
10
|
import type {SpriteSearchResult} from './sprite-editor-toolbar.tsx';
|
|
@@ -61,6 +62,8 @@ export interface SpriteTabAdapter<Snapshot = unknown> {
|
|
|
61
62
|
export interface SpriteAssetSelection {
|
|
62
63
|
restore(target: object, assets: readonly object[]): number | undefined;
|
|
63
64
|
remember(target: object, asset: object | undefined, select?: (index: number) => void): void;
|
|
65
|
+
renderPanel?(render: NativeAssetPanelRenderer, previewSelector: NativeAssetSelector,
|
|
66
|
+
panel: React.ComponentProps<typeof NativeAssetPanel>['panel']): React.ReactNode;
|
|
64
67
|
rememberLayout?(render: SpriteAssetLayout): void;
|
|
65
68
|
getScrollTop?(): number;
|
|
66
69
|
rememberScrollTop?(position: number): void;
|
|
@@ -77,7 +80,6 @@ export interface SpriteAssetPreviewItem {
|
|
|
77
80
|
duration?: number;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
type SpriteAssetLayout = (items: readonly SpriteAssetPreviewItem[], index: number, detail: React.ReactNode, scrollTop: number) => React.ReactNode;
|
|
81
83
|
const variableSection = spriteEditorSections.indexOf('variables');
|
|
82
84
|
|
|
83
85
|
export interface SpriteAssetPreviewData {
|
|
@@ -95,26 +97,33 @@ function createAssetSelections(target: Target, source?: {
|
|
|
95
97
|
const layouts = new Map(source?.layouts);
|
|
96
98
|
const scroll = new Map(source?.scroll);
|
|
97
99
|
const selectors = new Map<AssetKind, (index: number) => void>();
|
|
98
|
-
const forKind = (kind: AssetKind): SpriteAssetSelection =>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
100
|
+
const forKind = (kind: AssetKind): SpriteAssetSelection => {
|
|
101
|
+
const state = {
|
|
102
|
+
rememberLayout(render: SpriteAssetLayout) {
|
|
103
|
+
layouts.set(kind, render);
|
|
104
|
+
},
|
|
105
|
+
getScrollTop: () => scroll.get(kind) ?? 0,
|
|
106
|
+
rememberScrollTop(position: number) {
|
|
107
|
+
scroll.set(kind, position);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
...state,
|
|
112
|
+
renderPanel: (render, previewSelector, panel) =>
|
|
113
|
+
React.createElement(NativeAssetPanel, {render, previewSelector, panel, state}),
|
|
114
|
+
restore(current, assets) {
|
|
115
|
+
if (current !== target) return;
|
|
116
|
+
const index = assets.indexOf(selected.get(kind));
|
|
117
|
+
if (index >= 0) return index;
|
|
118
|
+
},
|
|
119
|
+
remember(current, asset, select) {
|
|
120
|
+
if (current !== target) return;
|
|
121
|
+
if (asset) selected.set(kind, asset);
|
|
122
|
+
else selected.delete(kind);
|
|
123
|
+
if (select) selectors.set(kind, select);
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
};
|
|
118
127
|
const ports: AssetSelections = {costumes: forKind('costumes'), sounds: forKind('sounds')};
|
|
119
128
|
return {selected, ports, layouts, selectors, scroll};
|
|
120
129
|
}
|