@pixi-ui-editor/schema 0.11.0 → 0.13.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/index.js CHANGED
@@ -5,7 +5,8 @@ import { applyPrefabNodePatch, materializePrefabInstance, PREFAB_NODE_PATH_SEPAR
5
5
  import { collectBindingKeys, collectBindingKeyScopes } from "./bindingKeys.js";
6
6
  import { collectLocalizationIssues, createDefaultLocalization, LocalizationSchema } from "./localization.js";
7
7
  export { collectBindingKeys, collectBindingKeyScopes, OWNER_BINDING_KEY_SCOPE } from "./bindingKeys.js";
8
- export const CURRENT_SCHEMA_VERSION = 37;
8
+ export { rewriteNodeReferences, rewritePrefabInstanceReferencePatches } from "./nodeReferences.js";
9
+ export const CURRENT_SCHEMA_VERSION = 39;
9
10
  const Id = Type.String({ format: "uuid" });
10
11
  const Name = Type.String({ minLength: 1 });
11
12
  /**
@@ -69,7 +70,12 @@ const TextStyleOverrides = Type.Partial(Type.Object({ desktop: Type.Partial(Text
69
70
  // 1) to keep the rendered text inside the resolved rectangle. Both live on the node itself, not inside
70
71
  // `style`/`textStyleOverrides`: shrinking is a runtime fit computed from the resolved box at render
71
72
  // time, not an authored per-orientation style choice, the same reasoning bitmap text's fields follow.
72
- const Text = Type.Composite([NodeBase, Type.Object({ type: Type.Literal("text"), text: Type.String(), textKey: Type.Optional(Type.String()), style: Type.Optional(TextStyleDefinitionSchema), textStyleOverrides: Type.Optional(TextStyleOverrides), autoSize: Type.Optional(Type.Boolean()), minFontSize: Type.Optional(Type.Number({ exclusiveMinimum: 0 })) })]);
73
+ export const TextCaseSchema = Type.Union([Type.Literal("none"), Type.Literal("uppercase"), Type.Literal("lowercase")]);
74
+ // Display-only transform applied on top of the resolved string (authored text, translation, or live
75
+ // preview) right before it reaches the renderer/measurer — never written back into `text`/catalog
76
+ // entries, so switching the case later, or reading the source string back out, stays lossless.
77
+ // Omitted/`"none"` keeps historical documents byte-for-byte unchanged without a migration.
78
+ const Text = Type.Composite([NodeBase, Type.Object({ type: Type.Literal("text"), text: Type.String(), textKey: Type.Optional(Type.String()), style: Type.Optional(TextStyleDefinitionSchema), textStyleOverrides: Type.Optional(TextStyleOverrides), autoSize: Type.Optional(Type.Boolean()), minFontSize: Type.Optional(Type.Number({ exclusiveMinimum: 0 })), textCase: Type.Optional(TextCaseSchema) })]);
73
79
  // Optional preserves existing documents; omitted animationSpeed is interpreted as 1 by every runtime.
74
80
  // `autoplay` is the serialized initial playback decision. Older documents are migrated to true,
75
81
  // preserving the runtime behavior they had before this field became explicit.
@@ -139,7 +145,16 @@ export const PrefabNodeOverrideSchema = Type.Object({
139
145
  export const BUTTON_STATE_KEYS = ["normal", "hover", "pressed", "disabled"];
140
146
  /** Discriminated transition: в v0 поддержан только `instant`, чтобы позже добавить bump/slide/fade без неявных полей. */
141
147
  const ButtonTransition = Type.Object({ kind: Type.Literal("instant") });
142
- const ButtonStates = Type.Object({ normalAssetId: Type.Optional(Id), hoverAssetId: Type.Optional(Id), pressedAssetId: Type.Optional(Id), disabledAssetId: Type.Optional(Id) });
148
+ const ButtonTint = Type.String({ pattern: "^#[0-9A-Fa-f]{6}$" });
149
+ /**
150
+ * Appearance is owned by each visual button state. Missing tint/opacity deliberately mean the
151
+ * neutral Pixi values (white and 1), so existing button artwork preserves its exact appearance.
152
+ */
153
+ const ButtonStates = Type.Object({
154
+ normalAssetId: Type.Optional(Id), hoverAssetId: Type.Optional(Id), pressedAssetId: Type.Optional(Id), disabledAssetId: Type.Optional(Id),
155
+ normalTint: Type.Optional(ButtonTint), hoverTint: Type.Optional(ButtonTint), pressedTint: Type.Optional(ButtonTint), disabledTint: Type.Optional(ButtonTint),
156
+ normalOpacity: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })), hoverOpacity: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })), pressedOpacity: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })), disabledOpacity: Type.Optional(Type.Number({ minimum: 0, maximum: 1 })),
157
+ });
143
158
  const ButtonSounds = Type.Object({ pressAssetId: Type.Optional(Id), hoverAssetId: Type.Optional(Id) });
144
159
  const ButtonTransitions = Type.Partial(Type.Object({ normal: ButtonTransition, hover: ButtonTransition, pressed: ButtonTransition, disabled: ButtonTransition }));
145
160
  // `enabled` — сериализованное начальное presentation-состояние; runtime setter документ не меняет.
@@ -187,7 +202,17 @@ const ScrollView = Type.Composite([NodeBase, Type.Object({ type: Type.Literal("s
187
202
  // `defaultPage` is the authored/initial visible page; switching pages at runtime is driven one-way by
188
203
  // game code (or the standalone `pagination` widget's `onPageChange`) through `setPageGroupPage`, never
189
204
  // by the group itself — it has no built-in swipe gesture or transition.
190
- const PageGroup = Type.Composite([NodeBase, Type.Object({ type: Type.Literal("page-group"), defaultPage: Type.Integer({ minimum: 0 }) })]);
205
+ // Optional carousel arrows: existing authored buttons wired the same way `pagination`'s
206
+ // `prevButtonNodeId`/`nextButtonNodeId` are (ADR 0043) — the group renders nothing of its own, only
207
+ // subscribes to a press. `pageUpButtonNodeId` advances (wraps past the last page to the first),
208
+ // `pageDownButtonNodeId` goes back (wraps past the first page to the last) — unlike pagination's
209
+ // prev/next, page-group never disables an arrow at the edge of the range, because there is no edge.
210
+ const PageGroup = Type.Composite([NodeBase, Type.Object({
211
+ type: Type.Literal("page-group"),
212
+ defaultPage: Type.Integer({ minimum: 0 }),
213
+ pageUpButtonNodeId: Type.Optional(NodeAddress),
214
+ pageDownButtonNodeId: Type.Optional(NodeAddress),
215
+ })]);
191
216
  // Контейнер фиксированной вместимости: держит список дочерних узлов и показывает только первые
192
217
  // `visibleCount` из них, остальные скрыты всегда. Это не страницы (`page-group` показывает ровно
193
218
  // одного ребёнка и растягивает его на себя) и не раскладка (`isPositionManagingContainer` его не
@@ -447,6 +472,20 @@ function checkNodeReferences(document, owner, path, issues) {
447
472
  }
448
473
  continue;
449
474
  }
475
+ if (node.type === "page-group") {
476
+ for (const field of ["pageUpButtonNodeId", "pageDownButtonNodeId"]) {
477
+ const buttonId = node[field];
478
+ if (buttonId === undefined)
479
+ continue;
480
+ const arrowPath = `${path}/pageGroupArrows/${node.id}/${field}`;
481
+ const target = nodes.get(buttonId);
482
+ if (target === undefined)
483
+ add(issues, "MISSING_PAGE_GROUP_ARROW", arrowPath, `Page group arrow '${buttonId}' does not exist in this owner.`);
484
+ else if (target.type !== "button" && target.type !== "staged-button")
485
+ add(issues, "INVALID_PAGE_GROUP_ARROW", arrowPath, "A page group arrow must reference a button or staged-button node.");
486
+ }
487
+ continue;
488
+ }
450
489
  if (node.type !== "spine")
451
490
  continue;
452
491
  const claimedSlots = new Set();
@@ -1297,6 +1336,10 @@ export function migrateProjectDocument(input) {
1297
1336
  // старого. `propertyOverrides[].nodeId` и `parentId` локального узла стали путями, а путь длиной в
1298
1337
  // один сегмент — это ровно прежний id узла определения; вложенных инстансов в `locallyAddedNodes`
1299
1338
  // v15 хранить не мог, поэтому запрещённых значений в старых документах не бывает.
1339
+ // v38 → v39 (per-state button tint/opacity) не требует переписывания данных: новые appearance
1340
+ // fields optional and therefore resolve to white / 1 for every existing button.
1341
+ // v37 → v38 (page-group carousel arrows) не требует переписывания данных: добавлены только
1342
+ // опциональные поля `pageUpButtonNodeId`/`pageDownButtonNodeId`, любой документ v37 уже валиден как v38.
1300
1343
  migrated.schemaVersion = CURRENT_SCHEMA_VERSION;
1301
1344
  assertProjectDocument(migrated);
1302
1345
  return migrated;