@pixi-ui-editor/runtime-pixi 0.8.0 → 0.10.0
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/SceneViewport.js.map +1 -1
- package/dist/controls.d.ts +17 -1
- package/dist/controls.d.ts.map +1 -1
- package/dist/controls.js +30 -1
- package/dist/controls.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/layout.js.map +1 -1
- package/dist/layoutGroups.js.map +1 -1
- package/dist/particles.js.map +1 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +36 -0
- package/dist/scene.js.map +1 -1
- package/dist/views/ItemTableNodeView.d.ts +57 -0
- package/dist/views/ItemTableNodeView.d.ts.map +1 -0
- package/dist/views/ItemTableNodeView.js +100 -0
- package/dist/views/ItemTableNodeView.js.map +1 -0
- package/dist/views/NodeView.d.ts +20 -0
- package/dist/views/NodeView.d.ts.map +1 -1
- package/dist/views/NodeView.js +25 -1
- package/dist/views/NodeView.js.map +1 -1
- package/dist/views/PaginationNodeView.d.ts +38 -2
- package/dist/views/PaginationNodeView.d.ts.map +1 -1
- package/dist/views/PaginationNodeView.js +85 -28
- package/dist/views/PaginationNodeView.js.map +1 -1
- package/dist/views/ParticleEmitterNodeView.js.map +1 -1
- package/dist/views/SpineNodeView.d.ts +9 -0
- package/dist/views/SpineNodeView.d.ts.map +1 -1
- package/dist/views/SpineNodeView.js +21 -1
- package/dist/views/SpineNodeView.js.map +1 -1
- package/dist/views/createNodeView.d.ts.map +1 -1
- package/dist/views/createNodeView.js +4 -0
- package/dist/views/createNodeView.js.map +1 -1
- package/package.json +2 -2
package/dist/scene.js
CHANGED
|
@@ -12,6 +12,10 @@ import { applyLayoutGroup, applyLayoutItem, createGridLineBreak, initializePixiL
|
|
|
12
12
|
import { LayoutGroupNodeView } from "./views/basic.js";
|
|
13
13
|
import { PageItemContainer } from "./pageGroup.js";
|
|
14
14
|
import { PageGroupNodeView } from "./views/PageGroupNodeView.js";
|
|
15
|
+
import { PaginationNodeView } from "./views/PaginationNodeView.js";
|
|
16
|
+
import { ItemTableNodeView } from "./views/ItemTableNodeView.js";
|
|
17
|
+
import { ButtonNodeView } from "./views/ButtonNodeView.js";
|
|
18
|
+
import { StagedButtonNodeView } from "./views/StagedButtonNodeView.js";
|
|
15
19
|
import { ScrollItemContainer } from "./scrollView.js";
|
|
16
20
|
import { ScrollViewNodeView } from "./views/ScrollViewNodeView.js";
|
|
17
21
|
import { SpineNodeView } from "./views/SpineNodeView.js";
|
|
@@ -125,6 +129,7 @@ export function buildSceneView(document, sceneId, profile, options) {
|
|
|
125
129
|
const localization = new SceneLocalization(document, scene, nodeViews, options.localization);
|
|
126
130
|
wireCheckboxGroups(owner.nodes, nodeViews);
|
|
127
131
|
wireSpineConnectors(owner.nodes, nodeViews);
|
|
132
|
+
wireNodeReferences(owner.nodes, nodeViews, interaction);
|
|
128
133
|
return { root: hostRoot, nodeViews, localization };
|
|
129
134
|
}
|
|
130
135
|
function wireSpineConnectors(nodes, nodeViews) {
|
|
@@ -140,6 +145,30 @@ function wireSpineConnectors(nodes, nodeViews) {
|
|
|
140
145
|
}));
|
|
141
146
|
}
|
|
142
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Разрешает все ссылки «нода → нода» в живые views: элементы item table и кнопки-стрелки пагинатора.
|
|
150
|
+
* Та же форма, что у `wireSpineConnectors`: документ хранит id, а во что он превратился, знает только
|
|
151
|
+
* собранная сцена, поэтому сами виды никогда не резолвят id. Один проход на все виды ссылок, чтобы
|
|
152
|
+
* следующая не завела собственный обход с чуть другой областью видимости.
|
|
153
|
+
*
|
|
154
|
+
* Стрелки подключаются только в runtime-сцене: на authoring-канвасе контрол инертен, как и клик по
|
|
155
|
+
* самой точке пагинатора. Вместимость таблицы, наоборот, видна и в редакторе — это не интерактивность.
|
|
156
|
+
*/
|
|
157
|
+
function wireNodeReferences(nodes, nodeViews, interaction) {
|
|
158
|
+
const arrowView = (nodeId) => {
|
|
159
|
+
const view = nodeId === undefined ? undefined : nodeViews.get(nodeId);
|
|
160
|
+
return view instanceof ButtonNodeView || view instanceof StagedButtonNodeView ? view : undefined;
|
|
161
|
+
};
|
|
162
|
+
for (const node of nodes) {
|
|
163
|
+
const view = nodeViews.get(node.id);
|
|
164
|
+
if (node.type === "item-table" && view instanceof ItemTableNodeView) {
|
|
165
|
+
view.setItems((node.items ?? []).map((itemId) => nodeViews.get(itemId)));
|
|
166
|
+
}
|
|
167
|
+
else if (node.type === "pagination" && view instanceof PaginationNodeView && interaction === "runtime") {
|
|
168
|
+
view.setArrows({ previous: arrowView(node.prevButtonNodeId), next: arrowView(node.nextButtonNodeId) });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
143
172
|
/**
|
|
144
173
|
* Authored `group` gives sibling checkboxes radio-button behavior: checking one force-unchecks its
|
|
145
174
|
* live group-mates (same `parentId`, same `group`), without touching the document. Runs once per
|
|
@@ -192,6 +221,13 @@ export function updateNodeView(view, node, profile, parentSize, parentNode, effe
|
|
|
192
221
|
const own = resolveProfileTransform(node, profile).transform;
|
|
193
222
|
view.parent.sync(node, profile, { width: own.width, height: own.height });
|
|
194
223
|
}
|
|
224
|
+
else if (parentNode !== undefined && parentNode.type === "page-group" && view.parent instanceof PageItemContainer && parentSize !== undefined) {
|
|
225
|
+
// A page is position-managed exactly like a layout/scroll item: it fills the group's own rectangle
|
|
226
|
+
// (`parentSize`, the same value `buildSceneView` passes as `childSize`). Without this branch an
|
|
227
|
+
// in-place update fell through to `view.update` and handed the page back its authored x/y and
|
|
228
|
+
// anchors, so editing anything inside a page group knocked its pages out of place.
|
|
229
|
+
view.parent.sync(node, profile, parentSize);
|
|
230
|
+
}
|
|
195
231
|
else {
|
|
196
232
|
view.update(node, profile, parentSize);
|
|
197
233
|
}
|
package/dist/scene.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene.js","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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","sourcesContent":["import { type SkeletonData } from \"@esotericsoftware/spine-pixi-v8\";\r\nimport { createStableId, isLayoutGroup, isParticleEffect, resolveLayoutGroupSettings, resolveOwnerNodeGraph, type EffectDefinition, type GridLayoutSettings, type LayoutProfileId, type ProjectDocument, type Scene, type SpineReferenceFrame, type UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Texture, type Ticker } from \"pixi.js\";\r\nimport { loadSceneSpines } from \"./assets/spine.js\";\r\nimport { loadSceneTextures, type FileUrlResolver } from \"./assets/textures.js\";\r\nimport { loadSceneFonts } from \"./assets/fonts.js\";\r\nimport { loadSceneBitmapFonts } from \"./assets/bitmapFonts.js\";\r\nimport type { SceneAssetCache } from \"./assets/cache.js\";\r\nimport { getCanvasLogicalSize, getCanvasScale, resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"./layout.js\";\r\nimport { NodeView, type SceneInteractionMode } from \"./views/NodeView.js\";\r\nimport { CheckboxNodeView } from \"./views/CheckboxNodeView.js\";\r\nimport { createNodeView } from \"./views/createNodeView.js\";\r\nimport { applyLayoutGroup, applyLayoutItem, createGridLineBreak, initializePixiLayout, LayoutItemContainer } from \"./layoutGroups.js\";\r\nimport { LayoutGroupNodeView } from \"./views/basic.js\";\r\nimport { PageItemContainer } from \"./pageGroup.js\";\r\nimport { PageGroupNodeView } from \"./views/PageGroupNodeView.js\";\r\nimport { ScrollItemContainer } from \"./scrollView.js\";\r\nimport { ScrollViewNodeView } from \"./views/ScrollViewNodeView.js\";\r\nimport { SpineNodeView } from \"./views/SpineNodeView.js\";\r\nimport { ParticleEmitterNodeView } from \"./views/ParticleEmitterNodeView.js\";\r\nimport { SceneLocalization, type SceneLocalizationOptions } from \"./localization.js\";\r\nimport { SceneViewport } from \"./SceneViewport.js\";\r\nimport type { Sound } from \"@pixi/sound\";\r\n\r\nexport type BuildSceneViewOptions = {\r\n /** Explicit: an editor canvas must pass \"authoring\", Preview and the consuming app \"runtime\". */\r\n interaction: SceneInteractionMode;\r\n textures?: ReadonlyMap<string, Texture>;\r\n spines?: ReadonlyMap<string, SkeletonData>;\r\n fonts?: ReadonlyMap<string, string>;\r\n bitmapFonts?: ReadonlyMap<string, string>;\r\n sounds?: ReadonlyMap<string, Sound>;\r\n /**\r\n * The host's own Application ticker, driving self-updating content such as Spine skeletons.\r\n * Without it they fall back to `Ticker.shared`, which runs a second rAF loop independent of the\r\n * renderer that draws them — see the same rule as `updateParticleEmitters`.\r\n */\r\n ticker?: Ticker;\r\n /** Called after Yoga changes a managed rectangle; authoring hosts use it to refresh overlays. */\r\n onLayout?: () => void;\r\n /**\r\n * Начальное состояние локализации. Опция необязательна: при наличии `Text.textKey` base locale\r\n * каталога применяется и без неё, а документ без ключей выглядит ровно как раньше.\r\n */\r\n localization?: SceneLocalizationOptions;\r\n /** Internal host boundary override: prefab views are spawnable content, not screen viewports. */\r\n clipToViewport?: boolean;\r\n};\r\n\r\nexport type SceneViewResult = { root: SceneViewport; nodeViews: Map<string, Container>; localization: SceneLocalization };\r\nconst particleEmitterRegistry = new WeakMap<Container, readonly ParticleEmitterNodeView[]>();\r\n\r\nfunction spineReferenceFrameFor(document: ProjectDocument, node: UINode): SpineReferenceFrame | undefined {\r\n if (node.type !== \"spine\") return undefined;\r\n const asset = document.assets.find((candidate) => candidate.id === node.assetId);\r\n return asset?.type === \"spine\" ? asset.referenceFrame : undefined;\r\n}\r\n\r\n/** Builds a PixiJS display tree for a scene without depending on DOM or editor state. */\r\nexport function buildSceneView(\r\n document: ProjectDocument,\r\n sceneId: string,\r\n profile: LayoutProfileId,\r\n options: BuildSceneViewOptions,\r\n): SceneViewResult {\r\n initializePixiLayout();\r\n const { interaction, textures, spines, fonts, bitmapFonts, sounds, ticker, onLayout } = options;\r\n const scene = document.scenes.find((candidate) => candidate.id === sceneId);\r\n\r\n if (scene === undefined) {\r\n throw new Error(`Scene '${sceneId}' does not exist in the project document.`);\r\n }\r\n\r\n const nodeViews = new Map<string, Container>();\r\n const particleEmitters: ParticleEmitterNodeView[] = [];\r\n\r\n // Materialized prefab children use instance-scoped IDs, so authoring and runtime can address\r\n // multiple instances independently without changing canonical definition IDs.\r\n const screenSize = scene.layout.referenceViewports[profile];\r\n const referenceResolution = scene.layout.preferredViewports[profile];\r\n const canvasScale = getCanvasScale(screenSize, referenceResolution);\r\n const canvasSize = getCanvasLogicalSize(screenSize, referenceResolution);\r\n\r\n // Единый резолвер иерархии: тот же граф, что видит редактор, включая вложенные пресеты.\r\n const owner = resolveOwnerNodeGraph(document, scene);\r\n const prefabIds = new Set(document.prefabs.map((prefab) => prefab.id));\r\n\r\n const buildOwner = (rootSize: LayoutSize): Container => {\r\n const nodesById = new Map(owner.nodes.map((node) => [node.id, node]));\r\n\r\n const buildNode = (nodeId: string, parentSize: LayoutSize): NodeView => {\r\n const node = nodesById.get(nodeId);\r\n\r\n if (node === undefined) {\r\n throw new Error(`Scene '${sceneId}' references missing node '${nodeId}'.`);\r\n }\r\n\r\n const resolved = resolveProfileTransform(node, profile);\r\n const transform = resolveAnchoredTransform(resolved.transform, parentSize);\r\n const view = createNodeView(node, interaction, textures, spines, (prefabId) => prefabIds.has(prefabId), fonts, sounds, node.type === \"particle-emitter\" ? document.effects.find((effect) => effect.id === node.effectId && isParticleEffect(effect)) : undefined, spineReferenceFrameFor(document, node), ticker, bitmapFonts);\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\r\n // Yoga owns only the group's inner layoutContent; the outer NodeView keeps authored transform.\r\n view.update(node, profile, parentSize);\r\n nodeViews.set(node.id, view);\r\n if (view instanceof ParticleEmitterNodeView) particleEmitters.push(view);\r\n\r\n // Прямые дети корня сцены разрешают якоря относительно логического Canvas, а не размера корня.\r\n // Прямой ребёнок grid-layout (сам `node` здесь) не владеет своим отрисованным размером: Unity-подобная\r\n // фиксированная ячейка полностью переопределяет authored transform (см. applyLayoutItem). Его\r\n // собственным потомкам нужен именно cellWidth/cellHeight, а не anchor-resolved authored-размер —\r\n // иначе они не отслеживают изменение Cell width/height и якорятся относительно устаревшего размера.\r\n const gridParent = node.parentId === null ? undefined : nodesById.get(node.parentId);\r\n const gridCell = gridParent?.type === \"grid-layout\" ? resolveLayoutGroupSettings<GridLayoutSettings>(gridParent, profile) : undefined;\r\n const childSize = node.parentId === null\r\n ? rootSize\r\n : gridCell !== undefined\r\n ? { width: gridCell.cellWidth, height: gridCell.cellHeight }\r\n : { width: transform.width, height: transform.height };\r\n for (const [childIndex, childId] of node.children.entries()) {\r\n const childNode = nodesById.get(childId);\r\n const childView = buildNode(childId, childSize);\r\n if (isLayoutGroup(node) && childNode !== undefined && view instanceof LayoutGroupNodeView) {\r\n const layoutItem = new LayoutItemContainer(childView, onLayout);\r\n applyLayoutItem(layoutItem, childNode, node, profile);\r\n view.addLayoutChild(layoutItem);\r\n } else if (node.type === \"scroll-view\" && childNode !== undefined && view instanceof ScrollViewNodeView) {\r\n const scrollItem = new ScrollItemContainer(childView, onLayout);\r\n // Как и у layout-item: собственный (не растянутый якорями) размер ребёнка — List не\r\n // предоставляет per-item override размера, в отличие от Yoga flexGrow/cellSize.\r\n const own = resolveProfileTransform(childNode, profile).transform;\r\n scrollItem.sync(childNode, profile, { width: own.width, height: own.height });\r\n view.addScrollItem(scrollItem);\r\n } else if (node.type === \"page-group\" && childNode !== undefined && view instanceof PageGroupNodeView) {\r\n // Unlike a scroll-view item, a page fills the group's own resolved rect completely\r\n // (`childSize`, computed above): a page is a full sub-screen, not content sized to itself.\r\n const pageItem = new PageItemContainer(childView);\r\n pageItem.sync(childNode, profile, childSize);\r\n view.addPageItem(pageItem);\r\n } else {\r\n view.addChild(childView);\r\n }\r\n if (node.type === \"grid-layout\") {\r\n const settings = node.layoutGroup.overrides?.[profile] === undefined ? node.layoutGroup.base : { ...node.layoutGroup.base, ...node.layoutGroup.overrides[profile] };\r\n if (settings.constraint !== \"flexible\" && settings.constraintCount !== undefined && (childIndex + 1) % settings.constraintCount === 0 && childIndex + 1 < node.children.length) {\r\n const lineBreak = createGridLineBreak(node, profile);\r\n if (lineBreak !== undefined && view instanceof LayoutGroupNodeView) view.addLayoutChild(lineBreak);\r\n }\r\n }\r\n }\r\n\r\n return view;\r\n };\r\n\r\n const ownerRoot = new Container();\r\n for (const rootNodeId of owner.rootNodeIds) {\r\n ownerRoot.addChild(buildNode(rootNodeId, rootSize));\r\n }\r\n\r\n return ownerRoot;\r\n };\r\n\r\n const canvasRoot = buildOwner(canvasSize);\r\n canvasRoot.scale.set(canvasScale);\r\n const hostRoot = new SceneViewport(canvasRoot, screenSize, options.clipToViewport ?? interaction === \"runtime\");\r\n particleEmitterRegistry.set(hostRoot, particleEmitters);\r\n // Контроллер применяет переводы сразу к уже созданным views, поэтому keyed Text показывает\r\n // базовую локаль без единого дополнительного вызова со стороны хоста.\r\n const localization = new SceneLocalization(document, scene, nodeViews, options.localization);\r\n wireCheckboxGroups(owner.nodes, nodeViews);\r\n wireSpineConnectors(owner.nodes, nodeViews);\r\n return { root: hostRoot, nodeViews, localization };\r\n}\r\n\r\nfunction wireSpineConnectors(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\r\n for (const node of nodes) {\r\n if (node.type !== \"spine\") continue;\r\n const view = nodeViews.get(node.id);\r\n if (!(view instanceof SpineNodeView)) continue;\r\n view.setConnectorBones((node.connectors ?? []).flatMap((connector) => {\r\n const target = nodeViews.get(connector.targetNodeId);\r\n return target === undefined ? [] : [{ ...connector, target }];\r\n }));\r\n }\r\n}\r\n\r\n/**\r\n * Authored `group` gives sibling checkboxes radio-button behavior: checking one force-unchecks its\r\n * live group-mates (same `parentId`, same `group`), without touching the document. Runs once per\r\n * scene build; `CheckboxNodeView.forceCheck` never re-emits `onCheck`, so this can't recurse.\r\n */\r\nfunction wireCheckboxGroups(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\r\n const byGroup = new Map<string, CheckboxNodeView[]>();\r\n for (const node of nodes) {\r\n if (node.type !== \"checkbox\" || node.group === undefined) continue;\r\n const view = nodeViews.get(node.id);\r\n if (!(view instanceof CheckboxNodeView)) continue;\r\n const key = `${node.parentId ?? \"\"}::${node.group}`;\r\n const group = byGroup.get(key) ?? [];\r\n group.push(view);\r\n byGroup.set(key, group);\r\n }\r\n for (const group of byGroup.values()) {\r\n if (group.length < 2) continue;\r\n for (const view of group) {\r\n view.onCheck.connect((checked) => {\r\n if (!checked) return;\r\n for (const other of group) if (other !== view) other.forceCheck(false);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Applies a node's resolved transform, visibility, and content to an existing display object,\r\n * so editors can update views in place without rebuilding the scene tree.\r\n */\r\nexport function updateNodeView(view: Container, node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize, parentNode?: UINode, effect?: EffectDefinition, spineReferenceFrame?: SpineReferenceFrame): void {\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\r\n if (!(view instanceof NodeView)) return;\r\n if (view instanceof SpineNodeView) view.setReferenceFrame(spineReferenceFrame);\r\n if (node.type === \"particle-emitter\" && effect !== undefined && isParticleEffect(effect) && \"syncEffect\" in view && typeof (view as { syncEffect?: unknown }).syncEffect === \"function\") (view as { syncEffect(effect: import(\"@pixi-ui-editor/schema\").ParticleEffectDefinition): void }).syncEffect(effect);\r\n if (parentNode !== undefined && isLayoutGroup(parentNode) && view.parent instanceof LayoutItemContainer) {\r\n applyLayoutItem(view.parent, node, parentNode, profile);\r\n } else if (parentNode !== undefined && parentNode.type === \"scroll-view\" && view.parent instanceof ScrollItemContainer) {\r\n const own = resolveProfileTransform(node, profile).transform;\r\n view.parent.sync(node, profile, { width: own.width, height: own.height });\r\n } else {\r\n view.update(node, profile, parentSize);\r\n }\r\n}\r\n\r\n/** Previews a resolved editor rectangle without consulting content bounds or rebuilding the view. */\r\nexport function previewNodeView(view: Container, node: UINode, profile: LayoutProfileId, transform: UINode[\"transform\"]): void {\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, undefined, { width: transform.width, height: transform.height });\r\n if (view instanceof NodeView) view.preview(node, transform, resolveProfileTransform(node, profile).visible, profile);\r\n}\r\n\r\n/** Hosts call this from their own Application ticker; runtime never subscribes to Ticker.shared. */\r\nexport function updateParticleEmitters(root: Container, deltaSeconds: number): void {\r\n const registered = particleEmitterRegistry.get(root);\r\n if (registered !== undefined) {\r\n for (const emitter of registered) emitter.updateParticles(deltaSeconds);\r\n return;\r\n }\r\n // Backward-compatible fallback for hosts that assemble a display tree manually instead of using\r\n // buildSceneView. Built scenes always take the O(emitter count) registry path above.\r\n const visit = (view: Container): void => {\r\n if (view instanceof ParticleEmitterNodeView) view.updateParticles(deltaSeconds);\r\n for (const child of view.children) visit(child);\r\n };\r\n visit(root);\r\n}\r\n\r\n/** Lists the nodes a scene renders, including nodes of prefab definitions its prefab instances expand to. */\r\nexport function collectRenderedNodes(document: ProjectDocument, scene: Scene): UINode[] {\r\n return resolveOwnerNodeGraph(document, scene).nodes;\r\n}\r\n\r\nexport type PrefabViewConfiguration = Pick<Extract<UINode, { type: \"prefab-instance\" }>, \"propertyOverrides\" | \"locallyAddedNodes\"> & { instanceId?: string };\r\n\r\nfunction prefabScene(document: ProjectDocument, prefabId: string, configuration: PrefabViewConfiguration = {}): { document: ProjectDocument; sceneId: string; instanceId: string } {\r\n const prefab = document.prefabs.find((candidate) => candidate.id === prefabId);\r\n if (prefab === undefined) throw new Error(`Prefab '${prefabId}' does not exist in the project document.`);\r\n const width = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.x) + Math.max(0, node.transform.width)));\r\n const height = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.y) + Math.max(0, node.transform.height)));\r\n const instanceId = configuration.instanceId ?? createStableId();\r\n const instance: Extract<UINode, { type: \"prefab-instance\" }> = {\r\n id: instanceId, name: prefab.name, type: \"prefab-instance\", prefabId, parentId: null, children: [],\r\n visible: true, transform: { x: 0, y: 0, width, height, scaleX: 1, scaleY: 1, rotation: 0, anchorMinX: 0, anchorMaxX: 0, anchorMinY: 0, anchorMaxY: 0, pivotX: 0, pivotY: 0 },\r\n ...(configuration.propertyOverrides === undefined ? {} : { propertyOverrides: structuredClone(configuration.propertyOverrides) }),\r\n ...(configuration.locallyAddedNodes === undefined ? {} : { locallyAddedNodes: structuredClone(configuration.locallyAddedNodes) }),\r\n };\r\n const sceneId = createStableId();\r\n const viewport = { width, height };\r\n const scene: Scene = { id: sceneId, name: prefab.name, rootNodeIds: [instance.id], nodes: [instance], layout: { referenceViewports: { desktop: viewport, mobile: viewport }, preferredViewports: { desktop: viewport, mobile: viewport } } };\r\n return { document: { ...document, scenes: [...document.scenes, scene] }, sceneId, instanceId };\r\n}\r\n\r\n/** Builds a fresh runtime prefab instance without requiring it to already exist in a scene. */\r\nexport function buildPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, options: BuildSceneViewOptions, configuration: PrefabViewConfiguration = {}): SceneViewResult & { instanceId: string } {\r\n const synthetic = prefabScene(document, prefabId, configuration);\r\n return { ...buildSceneView(synthetic.document, synthetic.sceneId, profile, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\r\n}\r\n\r\n/** Loads a prefab's assets and returns a fresh display tree suitable for dynamic game-code spawning. */\r\nexport async function loadPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, resolveFileUrl: FileUrlResolver, options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; assetCache?: SceneAssetCache }, configuration: PrefabViewConfiguration = {}): Promise<SceneViewResult & { instanceId: string }> {\r\n const synthetic = prefabScene(document, prefabId, configuration);\r\n return { ...await loadSceneView(synthetic.document, synthetic.sceneId, profile, resolveFileUrl, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\r\n}\r\n\r\n/** Loads a scene's textures and Spine data, then builds its display tree in one call. */\r\nexport async function loadSceneView(\r\n document: ProjectDocument,\r\n sceneId: string,\r\n profile: LayoutProfileId,\r\n resolveFileUrl: FileUrlResolver,\r\n options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; clipToViewport?: boolean; assetCache?: SceneAssetCache },\r\n): Promise<SceneViewResult> {\r\n // Без assetCache каждый вызов начинает с пустых кэшей: для одиночной загрузки сцены это нормально, а вот\r\n // игровой код, который поднимает пресеты по одному, обязан передать собственный кэш — иначе один и тот же\r\n // скелет, атлас и текстура парсятся заново на каждую вьюху и дублируются в видеопамяти.\r\n const cache = options.assetCache;\r\n const [textures, spines, fonts, bitmapFonts] = await Promise.all([\r\n loadSceneTextures(document, sceneId, (asset) => (asset.type === \"image\" ? resolveFileUrl(asset.source.uri) : undefined), resolveFileUrl, cache?.textures, cache?.spritesheets, cache?.bitmapFonts),\r\n loadSceneSpines(document, sceneId, resolveFileUrl, cache?.spines),\r\n loadSceneFonts(document, sceneId, resolveFileUrl, cache?.fonts),\r\n loadSceneBitmapFonts(document, sceneId, resolveFileUrl, cache?.bitmapFonts),\r\n ]);\r\n return buildSceneView(document, sceneId, profile, { interaction: options.interaction, textures, spines, fonts, bitmapFonts, ticker: options.ticker, localization: options.localization, clipToViewport: options.clipToViewport });\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"scene.js","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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","sourcesContent":["import { type SkeletonData } from \"@esotericsoftware/spine-pixi-v8\";\nimport { createStableId, isLayoutGroup, isParticleEffect, resolveLayoutGroupSettings, resolveOwnerNodeGraph, type EffectDefinition, type GridLayoutSettings, type LayoutProfileId, type ProjectDocument, type Scene, type SpineReferenceFrame, type UINode } from \"@pixi-ui-editor/schema\";\nimport { Container, Texture, type Ticker } from \"pixi.js\";\nimport { loadSceneSpines } from \"./assets/spine.js\";\nimport { loadSceneTextures, type FileUrlResolver } from \"./assets/textures.js\";\nimport { loadSceneFonts } from \"./assets/fonts.js\";\nimport { loadSceneBitmapFonts } from \"./assets/bitmapFonts.js\";\nimport type { SceneAssetCache } from \"./assets/cache.js\";\nimport { getCanvasLogicalSize, getCanvasScale, resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"./layout.js\";\nimport { NodeView, type SceneInteractionMode } from \"./views/NodeView.js\";\nimport { CheckboxNodeView } from \"./views/CheckboxNodeView.js\";\nimport { createNodeView } from \"./views/createNodeView.js\";\nimport { applyLayoutGroup, applyLayoutItem, createGridLineBreak, initializePixiLayout, LayoutItemContainer } from \"./layoutGroups.js\";\nimport { LayoutGroupNodeView } from \"./views/basic.js\";\nimport { PageItemContainer } from \"./pageGroup.js\";\nimport { PageGroupNodeView } from \"./views/PageGroupNodeView.js\";\nimport { PaginationNodeView, type PaginationArrow } from \"./views/PaginationNodeView.js\";\nimport { ItemTableNodeView } from \"./views/ItemTableNodeView.js\";\nimport { ButtonNodeView } from \"./views/ButtonNodeView.js\";\nimport { StagedButtonNodeView } from \"./views/StagedButtonNodeView.js\";\nimport { ScrollItemContainer } from \"./scrollView.js\";\nimport { ScrollViewNodeView } from \"./views/ScrollViewNodeView.js\";\nimport { SpineNodeView } from \"./views/SpineNodeView.js\";\nimport { ParticleEmitterNodeView } from \"./views/ParticleEmitterNodeView.js\";\nimport { SceneLocalization, type SceneLocalizationOptions } from \"./localization.js\";\nimport { SceneViewport } from \"./SceneViewport.js\";\nimport type { Sound } from \"@pixi/sound\";\n\nexport type BuildSceneViewOptions = {\n /** Explicit: an editor canvas must pass \"authoring\", Preview and the consuming app \"runtime\". */\n interaction: SceneInteractionMode;\n textures?: ReadonlyMap<string, Texture>;\n spines?: ReadonlyMap<string, SkeletonData>;\n fonts?: ReadonlyMap<string, string>;\n bitmapFonts?: ReadonlyMap<string, string>;\n sounds?: ReadonlyMap<string, Sound>;\n /**\n * The host's own Application ticker, driving self-updating content such as Spine skeletons.\n * Without it they fall back to `Ticker.shared`, which runs a second rAF loop independent of the\n * renderer that draws them — see the same rule as `updateParticleEmitters`.\n */\n ticker?: Ticker;\n /** Called after Yoga changes a managed rectangle; authoring hosts use it to refresh overlays. */\n onLayout?: () => void;\n /**\n * Начальное состояние локализации. Опция необязательна: при наличии `Text.textKey` base locale\n * каталога применяется и без неё, а документ без ключей выглядит ровно как раньше.\n */\n localization?: SceneLocalizationOptions;\n /** Internal host boundary override: prefab views are spawnable content, not screen viewports. */\n clipToViewport?: boolean;\n};\n\nexport type SceneViewResult = { root: SceneViewport; nodeViews: Map<string, Container>; localization: SceneLocalization };\nconst particleEmitterRegistry = new WeakMap<Container, readonly ParticleEmitterNodeView[]>();\n\nfunction spineReferenceFrameFor(document: ProjectDocument, node: UINode): SpineReferenceFrame | undefined {\n if (node.type !== \"spine\") return undefined;\n const asset = document.assets.find((candidate) => candidate.id === node.assetId);\n return asset?.type === \"spine\" ? asset.referenceFrame : undefined;\n}\n\n/** Builds a PixiJS display tree for a scene without depending on DOM or editor state. */\nexport function buildSceneView(\n document: ProjectDocument,\n sceneId: string,\n profile: LayoutProfileId,\n options: BuildSceneViewOptions,\n): SceneViewResult {\n initializePixiLayout();\n const { interaction, textures, spines, fonts, bitmapFonts, sounds, ticker, onLayout } = options;\n const scene = document.scenes.find((candidate) => candidate.id === sceneId);\n\n if (scene === undefined) {\n throw new Error(`Scene '${sceneId}' does not exist in the project document.`);\n }\n\n const nodeViews = new Map<string, Container>();\n const particleEmitters: ParticleEmitterNodeView[] = [];\n\n // Materialized prefab children use instance-scoped IDs, so authoring and runtime can address\n // multiple instances independently without changing canonical definition IDs.\n const screenSize = scene.layout.referenceViewports[profile];\n const referenceResolution = scene.layout.preferredViewports[profile];\n const canvasScale = getCanvasScale(screenSize, referenceResolution);\n const canvasSize = getCanvasLogicalSize(screenSize, referenceResolution);\n\n // Единый резолвер иерархии: тот же граф, что видит редактор, включая вложенные пресеты.\n const owner = resolveOwnerNodeGraph(document, scene);\n const prefabIds = new Set(document.prefabs.map((prefab) => prefab.id));\n\n const buildOwner = (rootSize: LayoutSize): Container => {\n const nodesById = new Map(owner.nodes.map((node) => [node.id, node]));\n\n const buildNode = (nodeId: string, parentSize: LayoutSize): NodeView => {\n const node = nodesById.get(nodeId);\n\n if (node === undefined) {\n throw new Error(`Scene '${sceneId}' references missing node '${nodeId}'.`);\n }\n\n const resolved = resolveProfileTransform(node, profile);\n const transform = resolveAnchoredTransform(resolved.transform, parentSize);\n const view = createNodeView(node, interaction, textures, spines, (prefabId) => prefabIds.has(prefabId), fonts, sounds, node.type === \"particle-emitter\" ? document.effects.find((effect) => effect.id === node.effectId && isParticleEffect(effect)) : undefined, spineReferenceFrameFor(document, node), ticker, bitmapFonts);\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\n // Yoga owns only the group's inner layoutContent; the outer NodeView keeps authored transform.\n view.update(node, profile, parentSize);\n nodeViews.set(node.id, view);\n if (view instanceof ParticleEmitterNodeView) particleEmitters.push(view);\n\n // Прямые дети корня сцены разрешают якоря относительно логического Canvas, а не размера корня.\n // Прямой ребёнок grid-layout (сам `node` здесь) не владеет своим отрисованным размером: Unity-подобная\n // фиксированная ячейка полностью переопределяет authored transform (см. applyLayoutItem). Его\n // собственным потомкам нужен именно cellWidth/cellHeight, а не anchor-resolved authored-размер —\n // иначе они не отслеживают изменение Cell width/height и якорятся относительно устаревшего размера.\n const gridParent = node.parentId === null ? undefined : nodesById.get(node.parentId);\n const gridCell = gridParent?.type === \"grid-layout\" ? resolveLayoutGroupSettings<GridLayoutSettings>(gridParent, profile) : undefined;\n const childSize = node.parentId === null\n ? rootSize\n : gridCell !== undefined\n ? { width: gridCell.cellWidth, height: gridCell.cellHeight }\n : { width: transform.width, height: transform.height };\n for (const [childIndex, childId] of node.children.entries()) {\n const childNode = nodesById.get(childId);\n const childView = buildNode(childId, childSize);\n if (isLayoutGroup(node) && childNode !== undefined && view instanceof LayoutGroupNodeView) {\n const layoutItem = new LayoutItemContainer(childView, onLayout);\n applyLayoutItem(layoutItem, childNode, node, profile);\n view.addLayoutChild(layoutItem);\n } else if (node.type === \"scroll-view\" && childNode !== undefined && view instanceof ScrollViewNodeView) {\n const scrollItem = new ScrollItemContainer(childView, onLayout);\n // Как и у layout-item: собственный (не растянутый якорями) размер ребёнка — List не\n // предоставляет per-item override размера, в отличие от Yoga flexGrow/cellSize.\n const own = resolveProfileTransform(childNode, profile).transform;\n scrollItem.sync(childNode, profile, { width: own.width, height: own.height });\n view.addScrollItem(scrollItem);\n } else if (node.type === \"page-group\" && childNode !== undefined && view instanceof PageGroupNodeView) {\n // Unlike a scroll-view item, a page fills the group's own resolved rect completely\n // (`childSize`, computed above): a page is a full sub-screen, not content sized to itself.\n const pageItem = new PageItemContainer(childView);\n pageItem.sync(childNode, profile, childSize);\n view.addPageItem(pageItem);\n } else {\n view.addChild(childView);\n }\n if (node.type === \"grid-layout\") {\n const settings = node.layoutGroup.overrides?.[profile] === undefined ? node.layoutGroup.base : { ...node.layoutGroup.base, ...node.layoutGroup.overrides[profile] };\n if (settings.constraint !== \"flexible\" && settings.constraintCount !== undefined && (childIndex + 1) % settings.constraintCount === 0 && childIndex + 1 < node.children.length) {\n const lineBreak = createGridLineBreak(node, profile);\n if (lineBreak !== undefined && view instanceof LayoutGroupNodeView) view.addLayoutChild(lineBreak);\n }\n }\n }\n\n return view;\n };\n\n const ownerRoot = new Container();\n for (const rootNodeId of owner.rootNodeIds) {\n ownerRoot.addChild(buildNode(rootNodeId, rootSize));\n }\n\n return ownerRoot;\n };\n\n const canvasRoot = buildOwner(canvasSize);\n canvasRoot.scale.set(canvasScale);\n const hostRoot = new SceneViewport(canvasRoot, screenSize, options.clipToViewport ?? interaction === \"runtime\");\n particleEmitterRegistry.set(hostRoot, particleEmitters);\n // Контроллер применяет переводы сразу к уже созданным views, поэтому keyed Text показывает\n // базовую локаль без единого дополнительного вызова со стороны хоста.\n const localization = new SceneLocalization(document, scene, nodeViews, options.localization);\n wireCheckboxGroups(owner.nodes, nodeViews);\n wireSpineConnectors(owner.nodes, nodeViews);\n wireNodeReferences(owner.nodes, nodeViews, interaction);\n return { root: hostRoot, nodeViews, localization };\n}\n\nfunction wireSpineConnectors(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\n for (const node of nodes) {\n if (node.type !== \"spine\") continue;\n const view = nodeViews.get(node.id);\n if (!(view instanceof SpineNodeView)) continue;\n view.setConnectorBones((node.connectors ?? []).flatMap((connector) => {\n const target = nodeViews.get(connector.targetNodeId);\n return target === undefined ? [] : [{ ...connector, target }];\n }));\n }\n}\n\n/**\n * Разрешает все ссылки «нода → нода» в живые views: элементы item table и кнопки-стрелки пагинатора.\n * Та же форма, что у `wireSpineConnectors`: документ хранит id, а во что он превратился, знает только\n * собранная сцена, поэтому сами виды никогда не резолвят id. Один проход на все виды ссылок, чтобы\n * следующая не завела собственный обход с чуть другой областью видимости.\n *\n * Стрелки подключаются только в runtime-сцене: на authoring-канвасе контрол инертен, как и клик по\n * самой точке пагинатора. Вместимость таблицы, наоборот, видна и в редакторе — это не интерактивность.\n */\nfunction wireNodeReferences(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>, interaction: SceneInteractionMode): void {\n const arrowView = (nodeId: string | undefined): PaginationArrow | undefined => {\n const view = nodeId === undefined ? undefined : nodeViews.get(nodeId);\n return view instanceof ButtonNodeView || view instanceof StagedButtonNodeView ? view : undefined;\n };\n for (const node of nodes) {\n const view = nodeViews.get(node.id);\n if (node.type === \"item-table\" && view instanceof ItemTableNodeView) {\n view.setItems((node.items ?? []).map((itemId) => nodeViews.get(itemId)));\n } else if (node.type === \"pagination\" && view instanceof PaginationNodeView && interaction === \"runtime\") {\n view.setArrows({ previous: arrowView(node.prevButtonNodeId), next: arrowView(node.nextButtonNodeId) });\n }\n }\n}\n\n/**\n * Authored `group` gives sibling checkboxes radio-button behavior: checking one force-unchecks its\n * live group-mates (same `parentId`, same `group`), without touching the document. Runs once per\n * scene build; `CheckboxNodeView.forceCheck` never re-emits `onCheck`, so this can't recurse.\n */\nfunction wireCheckboxGroups(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\n const byGroup = new Map<string, CheckboxNodeView[]>();\n for (const node of nodes) {\n if (node.type !== \"checkbox\" || node.group === undefined) continue;\n const view = nodeViews.get(node.id);\n if (!(view instanceof CheckboxNodeView)) continue;\n const key = `${node.parentId ?? \"\"}::${node.group}`;\n const group = byGroup.get(key) ?? [];\n group.push(view);\n byGroup.set(key, group);\n }\n for (const group of byGroup.values()) {\n if (group.length < 2) continue;\n for (const view of group) {\n view.onCheck.connect((checked) => {\n if (!checked) return;\n for (const other of group) if (other !== view) other.forceCheck(false);\n });\n }\n }\n}\n\n/**\n * Applies a node's resolved transform, visibility, and content to an existing display object,\n * so editors can update views in place without rebuilding the scene tree.\n */\nexport function updateNodeView(view: Container, node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize, parentNode?: UINode, effect?: EffectDefinition, spineReferenceFrame?: SpineReferenceFrame): void {\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\n if (!(view instanceof NodeView)) return;\n if (view instanceof SpineNodeView) view.setReferenceFrame(spineReferenceFrame);\n if (node.type === \"particle-emitter\" && effect !== undefined && isParticleEffect(effect) && \"syncEffect\" in view && typeof (view as { syncEffect?: unknown }).syncEffect === \"function\") (view as { syncEffect(effect: import(\"@pixi-ui-editor/schema\").ParticleEffectDefinition): void }).syncEffect(effect);\n if (parentNode !== undefined && isLayoutGroup(parentNode) && view.parent instanceof LayoutItemContainer) {\n applyLayoutItem(view.parent, node, parentNode, profile);\n } else if (parentNode !== undefined && parentNode.type === \"scroll-view\" && view.parent instanceof ScrollItemContainer) {\n const own = resolveProfileTransform(node, profile).transform;\n view.parent.sync(node, profile, { width: own.width, height: own.height });\n } else if (parentNode !== undefined && parentNode.type === \"page-group\" && view.parent instanceof PageItemContainer && parentSize !== undefined) {\n // A page is position-managed exactly like a layout/scroll item: it fills the group's own rectangle\n // (`parentSize`, the same value `buildSceneView` passes as `childSize`). Without this branch an\n // in-place update fell through to `view.update` and handed the page back its authored x/y and\n // anchors, so editing anything inside a page group knocked its pages out of place.\n view.parent.sync(node, profile, parentSize);\n } else {\n view.update(node, profile, parentSize);\n }\n}\n\n/** Previews a resolved editor rectangle without consulting content bounds or rebuilding the view. */\nexport function previewNodeView(view: Container, node: UINode, profile: LayoutProfileId, transform: UINode[\"transform\"]): void {\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, undefined, { width: transform.width, height: transform.height });\n if (view instanceof NodeView) view.preview(node, transform, resolveProfileTransform(node, profile).visible, profile);\n}\n\n/** Hosts call this from their own Application ticker; runtime never subscribes to Ticker.shared. */\nexport function updateParticleEmitters(root: Container, deltaSeconds: number): void {\n const registered = particleEmitterRegistry.get(root);\n if (registered !== undefined) {\n for (const emitter of registered) emitter.updateParticles(deltaSeconds);\n return;\n }\n // Backward-compatible fallback for hosts that assemble a display tree manually instead of using\n // buildSceneView. Built scenes always take the O(emitter count) registry path above.\n const visit = (view: Container): void => {\n if (view instanceof ParticleEmitterNodeView) view.updateParticles(deltaSeconds);\n for (const child of view.children) visit(child);\n };\n visit(root);\n}\n\n/** Lists the nodes a scene renders, including nodes of prefab definitions its prefab instances expand to. */\nexport function collectRenderedNodes(document: ProjectDocument, scene: Scene): UINode[] {\n return resolveOwnerNodeGraph(document, scene).nodes;\n}\n\nexport type PrefabViewConfiguration = Pick<Extract<UINode, { type: \"prefab-instance\" }>, \"propertyOverrides\" | \"locallyAddedNodes\"> & { instanceId?: string };\n\nfunction prefabScene(document: ProjectDocument, prefabId: string, configuration: PrefabViewConfiguration = {}): { document: ProjectDocument; sceneId: string; instanceId: string } {\n const prefab = document.prefabs.find((candidate) => candidate.id === prefabId);\n if (prefab === undefined) throw new Error(`Prefab '${prefabId}' does not exist in the project document.`);\n const width = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.x) + Math.max(0, node.transform.width)));\n const height = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.y) + Math.max(0, node.transform.height)));\n const instanceId = configuration.instanceId ?? createStableId();\n const instance: Extract<UINode, { type: \"prefab-instance\" }> = {\n id: instanceId, name: prefab.name, type: \"prefab-instance\", prefabId, parentId: null, children: [],\n visible: true, transform: { x: 0, y: 0, width, height, scaleX: 1, scaleY: 1, rotation: 0, anchorMinX: 0, anchorMaxX: 0, anchorMinY: 0, anchorMaxY: 0, pivotX: 0, pivotY: 0 },\n ...(configuration.propertyOverrides === undefined ? {} : { propertyOverrides: structuredClone(configuration.propertyOverrides) }),\n ...(configuration.locallyAddedNodes === undefined ? {} : { locallyAddedNodes: structuredClone(configuration.locallyAddedNodes) }),\n };\n const sceneId = createStableId();\n const viewport = { width, height };\n const scene: Scene = { id: sceneId, name: prefab.name, rootNodeIds: [instance.id], nodes: [instance], layout: { referenceViewports: { desktop: viewport, mobile: viewport }, preferredViewports: { desktop: viewport, mobile: viewport } } };\n return { document: { ...document, scenes: [...document.scenes, scene] }, sceneId, instanceId };\n}\n\n/** Builds a fresh runtime prefab instance without requiring it to already exist in a scene. */\nexport function buildPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, options: BuildSceneViewOptions, configuration: PrefabViewConfiguration = {}): SceneViewResult & { instanceId: string } {\n const synthetic = prefabScene(document, prefabId, configuration);\n return { ...buildSceneView(synthetic.document, synthetic.sceneId, profile, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\n}\n\n/** Loads a prefab's assets and returns a fresh display tree suitable for dynamic game-code spawning. */\nexport async function loadPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, resolveFileUrl: FileUrlResolver, options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; assetCache?: SceneAssetCache }, configuration: PrefabViewConfiguration = {}): Promise<SceneViewResult & { instanceId: string }> {\n const synthetic = prefabScene(document, prefabId, configuration);\n return { ...await loadSceneView(synthetic.document, synthetic.sceneId, profile, resolveFileUrl, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\n}\n\n/** Loads a scene's textures and Spine data, then builds its display tree in one call. */\nexport async function loadSceneView(\n document: ProjectDocument,\n sceneId: string,\n profile: LayoutProfileId,\n resolveFileUrl: FileUrlResolver,\n options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; clipToViewport?: boolean; assetCache?: SceneAssetCache },\n): Promise<SceneViewResult> {\n // Без assetCache каждый вызов начинает с пустых кэшей: для одиночной загрузки сцены это нормально, а вот\n // игровой код, который поднимает пресеты по одному, обязан передать собственный кэш — иначе один и тот же\n // скелет, атлас и текстура парсятся заново на каждую вьюху и дублируются в видеопамяти.\n const cache = options.assetCache;\n const [textures, spines, fonts, bitmapFonts] = await Promise.all([\n loadSceneTextures(document, sceneId, (asset) => (asset.type === \"image\" ? resolveFileUrl(asset.source.uri) : undefined), resolveFileUrl, cache?.textures, cache?.spritesheets, cache?.bitmapFonts),\n loadSceneSpines(document, sceneId, resolveFileUrl, cache?.spines),\n loadSceneFonts(document, sceneId, resolveFileUrl, cache?.fonts),\n loadSceneBitmapFonts(document, sceneId, resolveFileUrl, cache?.bitmapFonts),\n ]);\n return buildSceneView(document, sceneId, profile, { interaction: options.interaction, textures, spines, fonts, bitmapFonts, ticker: options.ticker, localization: options.localization, clipToViewport: options.clipToViewport });\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type LayoutProfileId, type UINode } from "@pixi-ui-editor/schema";
|
|
2
|
+
import { Container } from "pixi.js";
|
|
3
|
+
import { NodeView } from "./NodeView.js";
|
|
4
|
+
/**
|
|
5
|
+
* Узел фиксированной вместимости: держит авторский список узлов (`items`, ссылки по адресу — их
|
|
6
|
+
* разрешает `scene.ts`, тем же приёмом, что цели spine-коннекторов) и показывает только первые
|
|
7
|
+
* `visibleCount` из них — остальные скрыты всегда, а не «на этой странице». Автор раскладывает
|
|
8
|
+
* элементы под максимум, а сколько их реально помещается, задаётся на профиль: в разной ориентации
|
|
9
|
+
* экрана на экран влезает разное число строк.
|
|
10
|
+
*
|
|
11
|
+
* Список именно авторский, а не дети: элемент обычно уже лежит там, где его выравнивает layout-группа.
|
|
12
|
+
*
|
|
13
|
+
* Узел намеренно ничего больше не делает. Он не страницы (`PageGroupNodeView` показывает ровно
|
|
14
|
+
* одного ребёнка и растягивает его на себя), не раскладка (позицию элементы сохраняют свою) и ничего не
|
|
15
|
+
* знает ни про какие данные: чем наполнить видимые элементы и когда, решает игровой код через
|
|
16
|
+
* generic API из `controls.ts` (`getItemTableViewVisibleItems`, `getItemTableViewItem`,
|
|
17
|
+
* `setItemTableViewVisibleCount`, `setItemTableViewItemsVisible`). Связка «переключили страницу →
|
|
18
|
+
* перезаполнили элементы» тоже принадлежит игре: `PaginationNodeView.onPageChange` и эта таблица
|
|
19
|
+
* ничего друг о друге не знают.
|
|
20
|
+
*
|
|
21
|
+
* Видимость складывается с авторской: элемент, скрытый в документе, не станет видимым из-за
|
|
22
|
+
* вместимости, а скрытый вместимостью держится флагом `NodeView.hiddenByOwner` (см. `applyVisibility`).
|
|
23
|
+
*/
|
|
24
|
+
export declare class ItemTableNodeView extends NodeView {
|
|
25
|
+
private itemViews;
|
|
26
|
+
private authoredVisibleCount;
|
|
27
|
+
/** Транзиентное переопределение от игрового кода; `undefined` — авторское значение профиля. */
|
|
28
|
+
private runtimeVisibleCount?;
|
|
29
|
+
/** Транзиентный «скрыть/показать всё» поверх вместимости; `undefined` — вместимость решает сама. */
|
|
30
|
+
private forcedItemsVisible?;
|
|
31
|
+
/**
|
|
32
|
+
* Разрешённые views авторского списка `items`, позиционно выровненные с ним (`scene.ts`). Ссылка,
|
|
33
|
+
* которая ни во что не разрешилась, сохраняет свою дырку `undefined`, чтобы остальные элементы не
|
|
34
|
+
* сдвинулись; сама висячая ссылка — ошибка валидации документа, а не забота этого вида.
|
|
35
|
+
*/
|
|
36
|
+
setItems(views: readonly (Container | undefined)[]): void;
|
|
37
|
+
/** Элементы в авторском порядке; нерезолвенные ссылки пропущены. */
|
|
38
|
+
get items(): Container[];
|
|
39
|
+
get visibleCount(): number;
|
|
40
|
+
/** Транзиентно меняет вместимость; `undefined` возвращает авторское значение профиля. */
|
|
41
|
+
set visibleCount(value: number | undefined);
|
|
42
|
+
/** Элементы, показанные прямо сейчас, в авторском порядке. */
|
|
43
|
+
get visibleItems(): Container[];
|
|
44
|
+
/** Индекс — позиция в авторском списке, а не среди показанных: адресация не «плавает». */
|
|
45
|
+
itemAt(index: number): Container | undefined;
|
|
46
|
+
/** Показывает или прячет все элементы разом; `undefined` возвращает управление вместимости. */
|
|
47
|
+
setItemsVisible(visible: boolean | undefined): void;
|
|
48
|
+
/**
|
|
49
|
+
* Проход по элементам: влезающие включены, остальные выключены. Помимо самого `visible` ставится
|
|
50
|
+
* `hiddenByOwner`, потому что `visible` узла пересчитывается из документа на каждом обновлении —
|
|
51
|
+
* в том числе из колбэка layout-движка, который для элемента внутри layout-группы срабатывает
|
|
52
|
+
* позже прохода таблицы и без флага вернул бы скрытый элемент обратно.
|
|
53
|
+
*/
|
|
54
|
+
private applyVisibility;
|
|
55
|
+
protected syncContent(node: UINode, _transform: UINode["transform"], profile: LayoutProfileId): void;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=ItemTableNodeView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ItemTableNodeView.d.ts","sourceRoot":"","sources":["../../src/views/ItemTableNodeView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACzG,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;IAC7C,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,oBAAoB,CAAK;IACjC,+FAA+F;IAC/F,OAAO,CAAC,mBAAmB,CAAC,CAAS;IACrC,oGAAoG;IACpG,OAAO,CAAC,kBAAkB,CAAC,CAAU;IAErC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,CASxD;IAED,oEAAoE;IACpE,IAAI,KAAK,IAAI,SAAS,EAAE,CAEvB;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,yFAAyF;IACzF,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAGzC;IAED,8DAA8D;IAC9D,IAAI,YAAY,IAAI,SAAS,EAAE,CAE9B;IAED,0FAA0F;IAC1F,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAE3C;IAED,+FAA+F;IAC/F,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAGlD;IAED;;;;;OAKG;IACH,OAAO,CAAC,eAAe;IAcvB,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAInG;CACF"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { resolveItemTableVisibleCount } from "@pixi-ui-editor/schema";
|
|
2
|
+
import { NodeView } from "./NodeView.js";
|
|
3
|
+
/**
|
|
4
|
+
* Узел фиксированной вместимости: держит авторский список узлов (`items`, ссылки по адресу — их
|
|
5
|
+
* разрешает `scene.ts`, тем же приёмом, что цели spine-коннекторов) и показывает только первые
|
|
6
|
+
* `visibleCount` из них — остальные скрыты всегда, а не «на этой странице». Автор раскладывает
|
|
7
|
+
* элементы под максимум, а сколько их реально помещается, задаётся на профиль: в разной ориентации
|
|
8
|
+
* экрана на экран влезает разное число строк.
|
|
9
|
+
*
|
|
10
|
+
* Список именно авторский, а не дети: элемент обычно уже лежит там, где его выравнивает layout-группа.
|
|
11
|
+
*
|
|
12
|
+
* Узел намеренно ничего больше не делает. Он не страницы (`PageGroupNodeView` показывает ровно
|
|
13
|
+
* одного ребёнка и растягивает его на себя), не раскладка (позицию элементы сохраняют свою) и ничего не
|
|
14
|
+
* знает ни про какие данные: чем наполнить видимые элементы и когда, решает игровой код через
|
|
15
|
+
* generic API из `controls.ts` (`getItemTableViewVisibleItems`, `getItemTableViewItem`,
|
|
16
|
+
* `setItemTableViewVisibleCount`, `setItemTableViewItemsVisible`). Связка «переключили страницу →
|
|
17
|
+
* перезаполнили элементы» тоже принадлежит игре: `PaginationNodeView.onPageChange` и эта таблица
|
|
18
|
+
* ничего друг о друге не знают.
|
|
19
|
+
*
|
|
20
|
+
* Видимость складывается с авторской: элемент, скрытый в документе, не станет видимым из-за
|
|
21
|
+
* вместимости, а скрытый вместимостью держится флагом `NodeView.hiddenByOwner` (см. `applyVisibility`).
|
|
22
|
+
*/
|
|
23
|
+
export class ItemTableNodeView extends NodeView {
|
|
24
|
+
itemViews = [];
|
|
25
|
+
authoredVisibleCount = 0;
|
|
26
|
+
/** Транзиентное переопределение от игрового кода; `undefined` — авторское значение профиля. */
|
|
27
|
+
runtimeVisibleCount;
|
|
28
|
+
/** Транзиентный «скрыть/показать всё» поверх вместимости; `undefined` — вместимость решает сама. */
|
|
29
|
+
forcedItemsVisible;
|
|
30
|
+
/**
|
|
31
|
+
* Разрешённые views авторского списка `items`, позиционно выровненные с ним (`scene.ts`). Ссылка,
|
|
32
|
+
* которая ни во что не разрешилась, сохраняет свою дырку `undefined`, чтобы остальные элементы не
|
|
33
|
+
* сдвинулись; сама висячая ссылка — ошибка валидации документа, а не забота этого вида.
|
|
34
|
+
*/
|
|
35
|
+
setItems(views) {
|
|
36
|
+
// Выбывшие из списка возвращаются под управление документа: иначе узел, убранный из таблицы,
|
|
37
|
+
// остался бы скрытым её прежней вместимостью навсегда.
|
|
38
|
+
const next = new Set(views);
|
|
39
|
+
for (const previous of this.itemViews) {
|
|
40
|
+
if (previous instanceof NodeView && !next.has(previous)) {
|
|
41
|
+
previous.hiddenByOwner = false;
|
|
42
|
+
previous.visible = previous.documentVisible;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
this.itemViews = [...views];
|
|
46
|
+
this.applyVisibility();
|
|
47
|
+
}
|
|
48
|
+
/** Элементы в авторском порядке; нерезолвенные ссылки пропущены. */
|
|
49
|
+
get items() {
|
|
50
|
+
return this.itemViews.filter((item) => item !== undefined);
|
|
51
|
+
}
|
|
52
|
+
get visibleCount() {
|
|
53
|
+
return this.runtimeVisibleCount ?? this.authoredVisibleCount;
|
|
54
|
+
}
|
|
55
|
+
/** Транзиентно меняет вместимость; `undefined` возвращает авторское значение профиля. */
|
|
56
|
+
set visibleCount(value) {
|
|
57
|
+
this.runtimeVisibleCount = value === undefined ? undefined : Math.max(0, Math.round(value));
|
|
58
|
+
this.applyVisibility();
|
|
59
|
+
}
|
|
60
|
+
/** Элементы, показанные прямо сейчас, в авторском порядке. */
|
|
61
|
+
get visibleItems() {
|
|
62
|
+
return this.items.filter((item) => item.visible);
|
|
63
|
+
}
|
|
64
|
+
/** Индекс — позиция в авторском списке, а не среди показанных: адресация не «плавает». */
|
|
65
|
+
itemAt(index) {
|
|
66
|
+
return this.itemViews[index];
|
|
67
|
+
}
|
|
68
|
+
/** Показывает или прячет все элементы разом; `undefined` возвращает управление вместимости. */
|
|
69
|
+
setItemsVisible(visible) {
|
|
70
|
+
this.forcedItemsVisible = visible;
|
|
71
|
+
this.applyVisibility();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Проход по элементам: влезающие включены, остальные выключены. Помимо самого `visible` ставится
|
|
75
|
+
* `hiddenByOwner`, потому что `visible` узла пересчитывается из документа на каждом обновлении —
|
|
76
|
+
* в том числе из колбэка layout-движка, который для элемента внутри layout-группы срабатывает
|
|
77
|
+
* позже прохода таблицы и без флага вернул бы скрытый элемент обратно.
|
|
78
|
+
*/
|
|
79
|
+
applyVisibility() {
|
|
80
|
+
const count = this.visibleCount;
|
|
81
|
+
this.itemViews.forEach((item, index) => {
|
|
82
|
+
if (item === undefined)
|
|
83
|
+
return;
|
|
84
|
+
const enabled = this.forcedItemsVisible ?? index < count;
|
|
85
|
+
if (item instanceof NodeView) {
|
|
86
|
+
item.hiddenByOwner = !enabled;
|
|
87
|
+
item.visible = enabled && item.documentVisible;
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
item.visible = enabled;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
syncContent(node, _transform, profile) {
|
|
94
|
+
if (node.type !== "item-table")
|
|
95
|
+
return;
|
|
96
|
+
this.authoredVisibleCount = resolveItemTableVisibleCount(node, profile);
|
|
97
|
+
this.applyVisibility();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=ItemTableNodeView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ItemTableNodeView.js","sourceRoot":"","sources":["../../src/views/ItemTableNodeView.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveItemTableVisibleCount, type LayoutProfileId, type UINode } from \"@pixi-ui-editor/schema\";\nimport { Container } from \"pixi.js\";\nimport { NodeView } from \"./NodeView.js\";\n\n/**\n * Узел фиксированной вместимости: держит авторский список узлов (`items`, ссылки по адресу — их\n * разрешает `scene.ts`, тем же приёмом, что цели spine-коннекторов) и показывает только первые\n * `visibleCount` из них — остальные скрыты всегда, а не «на этой странице». Автор раскладывает\n * элементы под максимум, а сколько их реально помещается, задаётся на профиль: в разной ориентации\n * экрана на экран влезает разное число строк.\n *\n * Список именно авторский, а не дети: элемент обычно уже лежит там, где его выравнивает layout-группа.\n *\n * Узел намеренно ничего больше не делает. Он не страницы (`PageGroupNodeView` показывает ровно\n * одного ребёнка и растягивает его на себя), не раскладка (позицию элементы сохраняют свою) и ничего не\n * знает ни про какие данные: чем наполнить видимые элементы и когда, решает игровой код через\n * generic API из `controls.ts` (`getItemTableViewVisibleItems`, `getItemTableViewItem`,\n * `setItemTableViewVisibleCount`, `setItemTableViewItemsVisible`). Связка «переключили страницу →\n * перезаполнили элементы» тоже принадлежит игре: `PaginationNodeView.onPageChange` и эта таблица\n * ничего друг о друге не знают.\n *\n * Видимость складывается с авторской: элемент, скрытый в документе, не станет видимым из-за\n * вместимости, а скрытый вместимостью держится флагом `NodeView.hiddenByOwner` (см. `applyVisibility`).\n */\nexport class ItemTableNodeView extends NodeView {\n private itemViews: (Container | undefined)[] = [];\n private authoredVisibleCount = 0;\n /** Транзиентное переопределение от игрового кода; `undefined` — авторское значение профиля. */\n private runtimeVisibleCount?: number;\n /** Транзиентный «скрыть/показать всё» поверх вместимости; `undefined` — вместимость решает сама. */\n private forcedItemsVisible?: boolean;\n\n /**\n * Разрешённые views авторского списка `items`, позиционно выровненные с ним (`scene.ts`). Ссылка,\n * которая ни во что не разрешилась, сохраняет свою дырку `undefined`, чтобы остальные элементы не\n * сдвинулись; сама висячая ссылка — ошибка валидации документа, а не забота этого вида.\n */\n setItems(views: readonly (Container | undefined)[]): void {\n // Выбывшие из списка возвращаются под управление документа: иначе узел, убранный из таблицы,\n // остался бы скрытым её прежней вместимостью навсегда.\n const next = new Set(views);\n for (const previous of this.itemViews) {\n if (previous instanceof NodeView && !next.has(previous)) { previous.hiddenByOwner = false; previous.visible = previous.documentVisible; }\n }\n this.itemViews = [...views];\n this.applyVisibility();\n }\n\n /** Элементы в авторском порядке; нерезолвенные ссылки пропущены. */\n get items(): Container[] {\n return this.itemViews.filter((item): item is Container => item !== undefined);\n }\n\n get visibleCount(): number {\n return this.runtimeVisibleCount ?? this.authoredVisibleCount;\n }\n\n /** Транзиентно меняет вместимость; `undefined` возвращает авторское значение профиля. */\n set visibleCount(value: number | undefined) {\n this.runtimeVisibleCount = value === undefined ? undefined : Math.max(0, Math.round(value));\n this.applyVisibility();\n }\n\n /** Элементы, показанные прямо сейчас, в авторском порядке. */\n get visibleItems(): Container[] {\n return this.items.filter((item) => item.visible);\n }\n\n /** Индекс — позиция в авторском списке, а не среди показанных: адресация не «плавает». */\n itemAt(index: number): Container | undefined {\n return this.itemViews[index];\n }\n\n /** Показывает или прячет все элементы разом; `undefined` возвращает управление вместимости. */\n setItemsVisible(visible: boolean | undefined): void {\n this.forcedItemsVisible = visible;\n this.applyVisibility();\n }\n\n /**\n * Проход по элементам: влезающие включены, остальные выключены. Помимо самого `visible` ставится\n * `hiddenByOwner`, потому что `visible` узла пересчитывается из документа на каждом обновлении —\n * в том числе из колбэка layout-движка, который для элемента внутри layout-группы срабатывает\n * позже прохода таблицы и без флага вернул бы скрытый элемент обратно.\n */\n private applyVisibility(): void {\n const count = this.visibleCount;\n this.itemViews.forEach((item, index) => {\n if (item === undefined) return;\n const enabled = this.forcedItemsVisible ?? index < count;\n if (item instanceof NodeView) {\n item.hiddenByOwner = !enabled;\n item.visible = enabled && item.documentVisible;\n return;\n }\n item.visible = enabled;\n });\n }\n\n protected syncContent(node: UINode, _transform: UINode[\"transform\"], profile: LayoutProfileId): void {\n if (node.type !== \"item-table\") return;\n this.authoredVisibleCount = resolveItemTableVisibleCount(node, profile);\n this.applyVisibility();\n }\n}\n"]}
|
package/dist/views/NodeView.d.ts
CHANGED
|
@@ -22,6 +22,18 @@ export declare abstract class NodeView extends Container {
|
|
|
22
22
|
/** Authored/computed RectTransform-like rectangle; unlike Pixi bounds it also exists without content. */
|
|
23
23
|
protected layoutWidth: number;
|
|
24
24
|
protected layoutHeight: number;
|
|
25
|
+
/**
|
|
26
|
+
* Скрыт ли узел владельцем-вместимостью (`ItemTableNodeView`) поверх авторской видимости.
|
|
27
|
+
*
|
|
28
|
+
* Флаг живёт здесь, а не только в самом владельце, потому что `visible` заново выводится из
|
|
29
|
+
* документа на каждом обновлении — в том числе в `updateManaged`, который для элемента внутри
|
|
30
|
+
* layout-группы дёргает сам layout-движок своим колбэком `onLayout` (см. `LayoutItemContainer`),
|
|
31
|
+
* то есть уже после того, как владелец закончил свой проход. Одно присваивание `visible` снаружи
|
|
32
|
+
* пережило бы ровно до следующего пересчёта раскладки; сложение с этим флагом переживает любой.
|
|
33
|
+
*/
|
|
34
|
+
hiddenByOwner: boolean;
|
|
35
|
+
/** Visibility last resolved from the document, before `hiddenByOwner` is applied on top. */
|
|
36
|
+
private authoredVisible;
|
|
25
37
|
constructor(textures?: ReadonlyMap<string, Texture>);
|
|
26
38
|
protected textureFor(assetId: string | undefined): Texture | undefined;
|
|
27
39
|
/**
|
|
@@ -42,6 +54,12 @@ export declare abstract class NodeView extends Container {
|
|
|
42
54
|
protected setContent(content: Container): void;
|
|
43
55
|
/** Syncs type-specific content to the resolved layout rectangle; layout math itself is shared. */
|
|
44
56
|
protected abstract syncContent(node: UINode, transform: UINode["transform"], profile: LayoutProfileId): void;
|
|
57
|
+
/**
|
|
58
|
+
* Called after the view's own transform has been applied, before the next render. A subclass can
|
|
59
|
+
* use it to recompute geometry that depends on the view's world transform (e.g. Spine connector
|
|
60
|
+
* hosts) immediately, without waiting for the next ticker frame or document commit.
|
|
61
|
+
*/
|
|
62
|
+
protected onLayoutTransformApplied(): void;
|
|
45
63
|
private applyResolvedTransform;
|
|
46
64
|
update(node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize): void;
|
|
47
65
|
/** Applies a transient editor rectangle without deriving it from content-dependent Pixi bounds. */
|
|
@@ -49,6 +67,8 @@ export declare abstract class NodeView extends Container {
|
|
|
49
67
|
/** Applies the rectangle owned by a direct parent's layout solver. */
|
|
50
68
|
updateManaged(node: UINode, profile: LayoutProfileId, size: LayoutSize): void;
|
|
51
69
|
get layoutRectangle(): LayoutSize;
|
|
70
|
+
/** Авторская видимость узла отдельно от `visible`, поверх которой применяется `hiddenByOwner`. */
|
|
71
|
+
get documentVisible(): boolean;
|
|
52
72
|
getSpine(): Spine | undefined;
|
|
53
73
|
/**
|
|
54
74
|
* Rasterizes canvas-based content (`TextNodeView`) at a higher pixel density than the renderer's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeView.d.ts","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AACxD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAa,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAElG;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3D;;;;GAIG;AACH,8BAAsB,QAAS,SAAQ,SAAS;IAC9C,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC9B,4FAA4F;IAC5F,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtE,6FAA6F;IAC7F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,yGAAyG;IACzG,SAAS,CAAC,WAAW,SAAK;IAC1B,SAAS,CAAC,YAAY,SAAK;
|
|
1
|
+
{"version":3,"file":"NodeView.d.ts","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AACxD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAa,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAElG;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3D;;;;GAIG;AACH,8BAAsB,QAAS,SAAQ,SAAS;IAC9C,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC9B,4FAA4F;IAC5F,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtE,6FAA6F;IAC7F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,yGAAyG;IACzG,SAAS,CAAC,WAAW,SAAK;IAC1B,SAAS,CAAC,YAAY,SAAK;IAC3B;;;;;;;;OAQG;IACH,aAAa,UAAS;IACtB,4FAA4F;IAC5F,OAAO,CAAC,eAAe,CAAQ;IAE/B,YAAY,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,EAGlD;IAED,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAErE;IAED;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEvC;IAED,mGAAmG;IACnG,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAI7C;IAED,kGAAkG;IAClG,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;IAE7G;;;;OAIG;IACH,SAAS,CAAC,wBAAwB,IAAI,IAAI,CAAG;IAE7C,OAAO,CAAC,sBAAsB;IAyB9B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CAG5E;IAED,mGAAmG;IACnG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,UAAO,EAAE,OAAO,GAAE,eAA2B,GAAG,IAAI,CAEhH;IAED,sEAAsE;IACtE,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAG5E;IAED,IAAI,eAAe,IAAI,UAAU,CAEhC;IAED,kGAAkG;IAClG,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,QAAQ,IAAI,KAAK,GAAG,SAAS,CAE5B;IAED;;;;;;OAMG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAG;CACnD"}
|
package/dist/views/NodeView.js
CHANGED
|
@@ -15,6 +15,18 @@ export class NodeView extends Container {
|
|
|
15
15
|
/** Authored/computed RectTransform-like rectangle; unlike Pixi bounds it also exists without content. */
|
|
16
16
|
layoutWidth = 0;
|
|
17
17
|
layoutHeight = 0;
|
|
18
|
+
/**
|
|
19
|
+
* Скрыт ли узел владельцем-вместимостью (`ItemTableNodeView`) поверх авторской видимости.
|
|
20
|
+
*
|
|
21
|
+
* Флаг живёт здесь, а не только в самом владельце, потому что `visible` заново выводится из
|
|
22
|
+
* документа на каждом обновлении — в том числе в `updateManaged`, который для элемента внутри
|
|
23
|
+
* layout-группы дёргает сам layout-движок своим колбэком `onLayout` (см. `LayoutItemContainer`),
|
|
24
|
+
* то есть уже после того, как владелец закончил свой проход. Одно присваивание `visible` снаружи
|
|
25
|
+
* пережило бы ровно до следующего пересчёта раскладки; сложение с этим флагом переживает любой.
|
|
26
|
+
*/
|
|
27
|
+
hiddenByOwner = false;
|
|
28
|
+
/** Visibility last resolved from the document, before `hiddenByOwner` is applied on top. */
|
|
29
|
+
authoredVisible = true;
|
|
18
30
|
constructor(textures) {
|
|
19
31
|
super();
|
|
20
32
|
this.textures = textures;
|
|
@@ -47,6 +59,12 @@ export class NodeView extends Container {
|
|
|
47
59
|
this.content = content;
|
|
48
60
|
this.addChild(content);
|
|
49
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Called after the view's own transform has been applied, before the next render. A subclass can
|
|
64
|
+
* use it to recompute geometry that depends on the view's world transform (e.g. Spine connector
|
|
65
|
+
* hosts) immediately, without waiting for the next ticker frame or document commit.
|
|
66
|
+
*/
|
|
67
|
+
onLayoutTransformApplied() { }
|
|
50
68
|
applyResolvedTransform(node, transform, visible, managedByLayout, profile) {
|
|
51
69
|
this.syncContent(node, transform, profile);
|
|
52
70
|
const pivotX = (transform.pivotX ?? 0) * transform.width;
|
|
@@ -59,7 +77,8 @@ export class NodeView extends Container {
|
|
|
59
77
|
this.position.set(managedByLayout ? pivotX : transform.x, managedByLayout ? pivotY : transform.y);
|
|
60
78
|
this.rotation = transform.rotation;
|
|
61
79
|
this.scale.set(transform.scaleX, transform.scaleY);
|
|
62
|
-
this.
|
|
80
|
+
this.authoredVisible = visible;
|
|
81
|
+
this.visible = visible && !this.hiddenByOwner;
|
|
63
82
|
this.layoutWidth = transform.width;
|
|
64
83
|
this.layoutHeight = transform.height;
|
|
65
84
|
// Тот же прямоугольник, что видит пользователь: grab-зона не зависит от содержимого ноды.
|
|
@@ -67,6 +86,7 @@ export class NodeView extends Container {
|
|
|
67
86
|
this.grabRect.y = 0;
|
|
68
87
|
this.grabRect.width = transform.width;
|
|
69
88
|
this.grabRect.height = transform.height;
|
|
89
|
+
this.onLayoutTransformApplied();
|
|
70
90
|
}
|
|
71
91
|
update(node, profile, parentSize) {
|
|
72
92
|
const resolved = resolveProfileTransform(node, profile);
|
|
@@ -84,6 +104,10 @@ export class NodeView extends Container {
|
|
|
84
104
|
get layoutRectangle() {
|
|
85
105
|
return { width: this.layoutWidth, height: this.layoutHeight };
|
|
86
106
|
}
|
|
107
|
+
/** Авторская видимость узла отдельно от `visible`, поверх которой применяется `hiddenByOwner`. */
|
|
108
|
+
get documentVisible() {
|
|
109
|
+
return this.authoredVisible;
|
|
110
|
+
}
|
|
87
111
|
getSpine() {
|
|
88
112
|
return this.content instanceof Spine ? this.content : undefined;
|
|
89
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeView.js","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"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","sourcesContent":["import { Spine } from \"@esotericsoftware/spine-pixi-v8\";\r\nimport { type LayoutProfileId, type UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Rectangle, Texture, type PointData } from \"pixi.js\";\r\nimport { resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"../layout.js\";\r\n\r\n/**\r\n * Whether a built scene is an inert authoring surface or a live one.\r\n * The editor canvas builds `authoring` scenes so controls never swallow selection and drag\r\n * gestures; Preview and the consuming app build `runtime` scenes with real pointer handling.\r\n */\r\nexport type SceneInteractionMode = \"authoring\" | \"runtime\";\r\n\r\n/**\r\n * Base display object for every schema node type. The whole layout contract — profile overrides,\r\n * anchors, pivot, position, scale, visibility — lives here once; subclasses only synchronize their\r\n * type-specific content against the resolved layout rectangle.\r\n */\r\nexport abstract class NodeView extends Container {\r\n protected content?: Container;\r\n /** A mutable scene texture map: assets may be loaded after this stable view was created. */\r\n protected readonly textures: ReadonlyMap<string, Texture> | undefined;\r\n /** Node's own grab rectangle in local space, kept equal to its resolved layout rectangle. */\r\n private readonly grabRect = new Rectangle();\r\n /** Authored/computed RectTransform-like rectangle; unlike Pixi bounds it also exists without content. */\r\n protected layoutWidth = 0;\r\n protected layoutHeight = 0;\r\n\r\n constructor(textures?: ReadonlyMap<string, Texture>) {\r\n super();\r\n this.textures = textures;\r\n }\r\n\r\n protected textureFor(assetId: string | undefined): Texture | undefined {\r\n return assetId === undefined ? undefined : this.textures?.get(assetId);\r\n }\r\n\r\n /**\r\n * Makes every node selectable and draggable by its layout rectangle, whatever it renders.\r\n *\r\n * Lives here rather than in a subclass because a bare `Container` has no `containsPoint` of its\r\n * own: without this, Pixi could only find a node through whatever content the subclass happens to\r\n * draw, so nodes that draw nothing (container) or keep their content out of hit testing (button,\r\n * whose `@pixi/ui` view is inert while authoring) would silently stop being selectable.\r\n *\r\n * Deliberately `containsPoint` and NOT `hitArea`: Pixi's `hitPruneFn` drops a container together\r\n * with its whole subtree once the point falls outside its `hitArea`, which would make any child\r\n * reaching past its parent's rectangle visible but unclickable. `containsPoint` never clips\r\n * children — they are hit-tested first and independently, so a child always stays grabbable.\r\n */\r\n containsPoint(point: PointData): boolean {\r\n return this.grabRect.contains(point.x, point.y);\r\n }\r\n\r\n /** Заменяет содержимое ноды: прежнее снимается со сцены и уничтожается, чтобы не копить сироты. */\r\n protected setContent(content: Container): void {\r\n if (this.content !== undefined) { this.removeChild(this.content); this.content.destroy(); }\r\n this.content = content;\r\n this.addChild(content);\r\n }\r\n\r\n /** Syncs type-specific content to the resolved layout rectangle; layout math itself is shared. */\r\n protected abstract syncContent(node: UINode, transform: UINode[\"transform\"], profile: LayoutProfileId): void;\r\n\r\n private applyResolvedTransform(node: UINode, transform: UINode[\"transform\"], visible: boolean, managedByLayout: boolean, profile: LayoutProfileId): void {\r\n this.syncContent(node, transform, profile);\r\n\r\n const pivotX = (transform.pivotX ?? 0) * transform.width;\r\n const pivotY = (transform.pivotY ?? 0) * transform.height;\r\n this.pivot.set(pivotX, pivotY);\r\n // x/y are the pivot offset from the resolved anchor. Thus a centred anchor and pivot at\r\n // zero offsets place the visual centre exactly at the parent's centre.\r\n // A managed child is positioned by its technical Yoga item. Its own NodeView keeps only the\r\n // pivot offset inside that computed rectangle; authored x/y and anchors do not participate.\r\n this.position.set(managedByLayout ? pivotX : transform.x, managedByLayout ? pivotY : transform.y);\r\n this.rotation = transform.rotation;\r\n this.scale.set(transform.scaleX, transform.scaleY);\r\n this.visible = visible;\r\n this.layoutWidth = transform.width;\r\n this.layoutHeight = transform.height;\r\n // Тот же прямоугольник, что видит пользователь: grab-зона не зависит от содержимого ноды.\r\n this.grabRect.x = 0;\r\n this.grabRect.y = 0;\r\n this.grabRect.width = transform.width;\r\n this.grabRect.height = transform.height;\r\n }\r\n\r\n update(node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize): void {\r\n const resolved = resolveProfileTransform(node, profile);\r\n this.applyResolvedTransform(node, resolveAnchoredTransform(resolved.transform, parentSize), resolved.visible, false, profile);\r\n }\r\n\r\n /** Applies a transient editor rectangle without deriving it from content-dependent Pixi bounds. */\r\n preview(node: UINode, transform: UINode[\"transform\"], visible = true, profile: LayoutProfileId = \"desktop\"): void {\r\n this.applyResolvedTransform(node, transform, visible, false, profile);\r\n }\r\n\r\n /** Applies the rectangle owned by a direct parent's layout solver. */\r\n updateManaged(node: UINode, profile: LayoutProfileId, size: LayoutSize): void {\r\n const resolved = resolveProfileTransform(node, profile);\r\n this.applyResolvedTransform(node, { ...resolved.transform, x: 0, y: 0, width: size.width, height: size.height }, resolved.visible, true, profile);\r\n }\r\n\r\n get layoutRectangle(): LayoutSize {\r\n return { width: this.layoutWidth, height: this.layoutHeight };\r\n }\r\n\r\n getSpine(): Spine | undefined {\r\n return this.content instanceof Spine ? this.content : undefined;\r\n }\r\n\r\n /**\r\n * Rasterizes canvas-based content (`TextNodeView`) at a higher pixel density than the renderer's\r\n * own backing resolution, so an authoring camera zoomed in doesn't magnify an already-rasterized\r\n * bitmap past its source resolution and read as blurred. A no-op base implementation: sprite/\r\n * graphics/bitmap-text content is either GPU-native (always crisp under zoom) or, for bitmap-text,\r\n * has its resolution fixed by the installed `BitmapFont` and can't be changed per instance.\r\n */\r\n setContentResolution(_resolution: number): void {}\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"NodeView.js","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"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","sourcesContent":["import { Spine } from \"@esotericsoftware/spine-pixi-v8\";\r\nimport { type LayoutProfileId, type UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Rectangle, Texture, type PointData } from \"pixi.js\";\r\nimport { resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"../layout.js\";\r\n\r\n/**\r\n * Whether a built scene is an inert authoring surface or a live one.\r\n * The editor canvas builds `authoring` scenes so controls never swallow selection and drag\r\n * gestures; Preview and the consuming app build `runtime` scenes with real pointer handling.\r\n */\r\nexport type SceneInteractionMode = \"authoring\" | \"runtime\";\r\n\r\n/**\r\n * Base display object for every schema node type. The whole layout contract — profile overrides,\r\n * anchors, pivot, position, scale, visibility — lives here once; subclasses only synchronize their\r\n * type-specific content against the resolved layout rectangle.\r\n */\r\nexport abstract class NodeView extends Container {\r\n protected content?: Container;\r\n /** A mutable scene texture map: assets may be loaded after this stable view was created. */\r\n protected readonly textures: ReadonlyMap<string, Texture> | undefined;\r\n /** Node's own grab rectangle in local space, kept equal to its resolved layout rectangle. */\r\n private readonly grabRect = new Rectangle();\r\n /** Authored/computed RectTransform-like rectangle; unlike Pixi bounds it also exists without content. */\r\n protected layoutWidth = 0;\r\n protected layoutHeight = 0;\r\n /**\r\n * Скрыт ли узел владельцем-вместимостью (`ItemTableNodeView`) поверх авторской видимости.\r\n *\r\n * Флаг живёт здесь, а не только в самом владельце, потому что `visible` заново выводится из\r\n * документа на каждом обновлении — в том числе в `updateManaged`, который для элемента внутри\r\n * layout-группы дёргает сам layout-движок своим колбэком `onLayout` (см. `LayoutItemContainer`),\r\n * то есть уже после того, как владелец закончил свой проход. Одно присваивание `visible` снаружи\r\n * пережило бы ровно до следующего пересчёта раскладки; сложение с этим флагом переживает любой.\r\n */\r\n hiddenByOwner = false;\r\n /** Visibility last resolved from the document, before `hiddenByOwner` is applied on top. */\r\n private authoredVisible = true;\r\n\r\n constructor(textures?: ReadonlyMap<string, Texture>) {\r\n super();\r\n this.textures = textures;\r\n }\r\n\r\n protected textureFor(assetId: string | undefined): Texture | undefined {\r\n return assetId === undefined ? undefined : this.textures?.get(assetId);\r\n }\r\n\r\n /**\r\n * Makes every node selectable and draggable by its layout rectangle, whatever it renders.\r\n *\r\n * Lives here rather than in a subclass because a bare `Container` has no `containsPoint` of its\r\n * own: without this, Pixi could only find a node through whatever content the subclass happens to\r\n * draw, so nodes that draw nothing (container) or keep their content out of hit testing (button,\r\n * whose `@pixi/ui` view is inert while authoring) would silently stop being selectable.\r\n *\r\n * Deliberately `containsPoint` and NOT `hitArea`: Pixi's `hitPruneFn` drops a container together\r\n * with its whole subtree once the point falls outside its `hitArea`, which would make any child\r\n * reaching past its parent's rectangle visible but unclickable. `containsPoint` never clips\r\n * children — they are hit-tested first and independently, so a child always stays grabbable.\r\n */\r\n containsPoint(point: PointData): boolean {\r\n return this.grabRect.contains(point.x, point.y);\r\n }\r\n\r\n /** Заменяет содержимое ноды: прежнее снимается со сцены и уничтожается, чтобы не копить сироты. */\r\n protected setContent(content: Container): void {\r\n if (this.content !== undefined) { this.removeChild(this.content); this.content.destroy(); }\r\n this.content = content;\r\n this.addChild(content);\r\n }\r\n\r\n /** Syncs type-specific content to the resolved layout rectangle; layout math itself is shared. */\r\n protected abstract syncContent(node: UINode, transform: UINode[\"transform\"], profile: LayoutProfileId): void;\r\n\r\n /**\r\n * Called after the view's own transform has been applied, before the next render. A subclass can\r\n * use it to recompute geometry that depends on the view's world transform (e.g. Spine connector\r\n * hosts) immediately, without waiting for the next ticker frame or document commit.\r\n */\r\n protected onLayoutTransformApplied(): void {}\r\n\r\n private applyResolvedTransform(node: UINode, transform: UINode[\"transform\"], visible: boolean, managedByLayout: boolean, profile: LayoutProfileId): void {\r\n this.syncContent(node, transform, profile);\r\n\r\n const pivotX = (transform.pivotX ?? 0) * transform.width;\r\n const pivotY = (transform.pivotY ?? 0) * transform.height;\r\n this.pivot.set(pivotX, pivotY);\r\n // x/y are the pivot offset from the resolved anchor. Thus a centred anchor and pivot at\r\n // zero offsets place the visual centre exactly at the parent's centre.\r\n // A managed child is positioned by its technical Yoga item. Its own NodeView keeps only the\r\n // pivot offset inside that computed rectangle; authored x/y and anchors do not participate.\r\n this.position.set(managedByLayout ? pivotX : transform.x, managedByLayout ? pivotY : transform.y);\r\n this.rotation = transform.rotation;\r\n this.scale.set(transform.scaleX, transform.scaleY);\r\n this.authoredVisible = visible;\r\n this.visible = visible && !this.hiddenByOwner;\r\n this.layoutWidth = transform.width;\r\n this.layoutHeight = transform.height;\r\n // Тот же прямоугольник, что видит пользователь: grab-зона не зависит от содержимого ноды.\r\n this.grabRect.x = 0;\r\n this.grabRect.y = 0;\r\n this.grabRect.width = transform.width;\r\n this.grabRect.height = transform.height;\r\n this.onLayoutTransformApplied();\r\n }\r\n\r\n update(node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize): void {\r\n const resolved = resolveProfileTransform(node, profile);\r\n this.applyResolvedTransform(node, resolveAnchoredTransform(resolved.transform, parentSize), resolved.visible, false, profile);\r\n }\r\n\r\n /** Applies a transient editor rectangle without deriving it from content-dependent Pixi bounds. */\r\n preview(node: UINode, transform: UINode[\"transform\"], visible = true, profile: LayoutProfileId = \"desktop\"): void {\r\n this.applyResolvedTransform(node, transform, visible, false, profile);\r\n }\r\n\r\n /** Applies the rectangle owned by a direct parent's layout solver. */\r\n updateManaged(node: UINode, profile: LayoutProfileId, size: LayoutSize): void {\r\n const resolved = resolveProfileTransform(node, profile);\r\n this.applyResolvedTransform(node, { ...resolved.transform, x: 0, y: 0, width: size.width, height: size.height }, resolved.visible, true, profile);\r\n }\r\n\r\n get layoutRectangle(): LayoutSize {\r\n return { width: this.layoutWidth, height: this.layoutHeight };\r\n }\r\n\r\n /** Авторская видимость узла отдельно от `visible`, поверх которой применяется `hiddenByOwner`. */\r\n get documentVisible(): boolean {\r\n return this.authoredVisible;\r\n }\r\n\r\n getSpine(): Spine | undefined {\r\n return this.content instanceof Spine ? this.content : undefined;\r\n }\r\n\r\n /**\r\n * Rasterizes canvas-based content (`TextNodeView`) at a higher pixel density than the renderer's\r\n * own backing resolution, so an authoring camera zoomed in doesn't magnify an already-rasterized\r\n * bitmap past its source resolution and read as blurred. A no-op base implementation: sprite/\r\n * graphics/bitmap-text content is either GPU-native (always crisp under zoom) or, for bitmap-text,\r\n * has its resolution fixed by the installed `BitmapFont` and can't be changed per instance.\r\n */\r\n setContentResolution(_resolution: number): void {}\r\n}\r\n"]}
|