@player-ui/player 0.11.0-next.3 → 0.11.0-next.4

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.
@@ -12,6 +12,8 @@ import type { Options } from "./options";
12
12
  import type { Resolver } from "../resolver";
13
13
  import { hasTemplateKey } from "../parser/utils";
14
14
 
15
+ const templateSymbol = Symbol("template");
16
+
15
17
  export interface TemplateItemInfo {
16
18
  /** The index of the data for the current iteration of the template */
17
19
  index: number;
@@ -37,7 +39,12 @@ export type TemplateSubstitutionsFunc = (
37
39
  export default class TemplatePlugin implements ViewPlugin {
38
40
  private readonly options: Options;
39
41
 
40
- hooks = {
42
+ hooks: {
43
+ resolveTemplateSubstitutions: SyncWaterfallHook<
44
+ [TemplateSubstitution[], TemplateItemInfo],
45
+ Record<string, any>
46
+ >;
47
+ } = {
41
48
  resolveTemplateSubstitutions: new SyncWaterfallHook<
42
49
  [TemplateSubstitution[], TemplateItemInfo]
43
50
  >(),
@@ -106,10 +113,15 @@ export default class TemplatePlugin implements ViewPlugin {
106
113
  values,
107
114
  };
108
115
 
116
+ // Removes undefined Symbol property
117
+ if (node.placement !== undefined) {
118
+ (result as any)[templateSymbol] = node.placement;
119
+ }
120
+
109
121
  return result;
110
122
  }
111
123
 
112
- applyParser(parser: Parser) {
124
+ applyParser(parser: Parser): void {
113
125
  parser.hooks.onCreateASTNode.tap("template", (node) => {
114
126
  if (node && node.type === NodeType.Template && !node.dynamic) {
115
127
  return this.parseTemplate(
@@ -122,6 +134,55 @@ export default class TemplatePlugin implements ViewPlugin {
122
134
  return node;
123
135
  });
124
136
 
137
+ parser.hooks.onCreateASTNode.tap("template", (node) => {
138
+ function getTemplateSymbolValue(node: Node.Node): string | undefined {
139
+ if (node.type === NodeType.MultiNode) {
140
+ return (node as any)[templateSymbol];
141
+ } else if (node.type === NodeType.Template) {
142
+ return node.placement;
143
+ }
144
+ return undefined;
145
+ }
146
+
147
+ if (
148
+ node &&
149
+ (node.type === NodeType.View || node.type === NodeType.Asset) &&
150
+ Array.isArray(node.children)
151
+ ) {
152
+ node.children = node.children.sort((a, b) => {
153
+ // compare template output with static values
154
+ const aPath = a.path.join();
155
+ const bPath = b.path.join();
156
+
157
+ const pathsEqual = aPath === bPath;
158
+
159
+ if (pathsEqual) {
160
+ const aPlacement = getTemplateSymbolValue(a.value);
161
+ const bPlacement = getTemplateSymbolValue(b.value);
162
+
163
+ if (aPlacement !== undefined && bPlacement === undefined) {
164
+ return aPlacement === "prepend" ? -1 : 1;
165
+ } else if (bPlacement !== undefined && aPlacement === undefined) {
166
+ return bPlacement === "prepend" ? 1 : -1;
167
+ } else if (aPlacement !== undefined && bPlacement !== undefined) {
168
+ // Both have placement values
169
+ if (aPlacement === bPlacement) {
170
+ return 0; // Same placement, no preference
171
+ }
172
+ // "prepend" should come before "append"
173
+ return aPlacement === "prepend" ? -1 : 1;
174
+ }
175
+ return 0;
176
+ }
177
+
178
+ // Trigger more sorting for nested assets
179
+ return aPath > bPath ? 1 : -1;
180
+ });
181
+ }
182
+
183
+ return node;
184
+ });
185
+
125
186
  parser.hooks.parseNode.tap(
126
187
  "template",
127
188
  (
@@ -140,6 +201,7 @@ export default class TemplatePlugin implements ViewPlugin {
140
201
  data: template.data,
141
202
  template: template.value,
142
203
  dynamic: template.dynamic ?? false,
204
+ placement: template.placement,
143
205
  },
144
206
  template,
145
207
  );
@@ -163,7 +225,8 @@ export default class TemplatePlugin implements ViewPlugin {
163
225
  );
164
226
  }
165
227
 
166
- applyResolverHooks(resolver: Resolver) {
228
+ applyResolverHooks(resolver: Resolver): void {
229
+ // Transform dynamic templates into MultiNodes
167
230
  resolver.hooks.beforeResolve.tap("template", (node, options) => {
168
231
  if (node && node.type === NodeType.Template && node.dynamic) {
169
232
  return this.parseTemplate(options.parseNode, node, options);
@@ -173,7 +236,7 @@ export default class TemplatePlugin implements ViewPlugin {
173
236
  });
174
237
  }
175
238
 
176
- apply(view: ViewInstance) {
239
+ apply(view: ViewInstance): void {
177
240
  view.hooks.parser.tap("template", this.applyParser.bind(this));
178
241
  view.hooks.resolver.tap("template", this.applyResolverHooks.bind(this));
179
242
  }
@@ -38,5 +38,13 @@ export declare class Builder {
38
38
  * @param child - The child node
39
39
  */
40
40
  static addChild<N extends Node.BaseWithChildren<NT>, NT extends NodeType>(node: N, path: Node.PathSegment | Node.PathSegment[], child: Node.Node): N;
41
+ /**
42
+ * Updates children of a node of the same path and preserves order
43
+ *
44
+ * @param node - The node to update children for
45
+ * @param pathToMatch - The path to match against child paths
46
+ * @param mapFn - Function to transform matching children
47
+ */
48
+ static updateChildrenByPath<T extends Node.ViewOrAsset | Node.Value>(node: T, pathToMatch: Node.PathSegment[], updateFn: (child: Node.Child) => Node.Node): T;
41
49
  }
42
50
  //# sourceMappingURL=index.d.ts.map
@@ -54,8 +54,10 @@ export declare namespace Node {
54
54
  template: unknown;
55
55
  /** The number of nested templates so far */
56
56
  depth: number;
57
- /** should the template recomputed when data changes */
57
+ /** Should the template recompute when data changes */
58
58
  dynamic?: boolean;
59
+ /** Specifies the template placement in relation to existing elements*/
60
+ placement?: "prepend" | "append";
59
61
  }
60
62
  interface Value extends BaseWithChildren<NodeType.Value>, PluginOptions {
61
63
  /** A simple node representing a value */
@@ -22,7 +22,10 @@ export type TemplateSubstitutionsFunc = (baseSubstitutions: TemplateSubstitution
22
22
  export default class TemplatePlugin implements ViewPlugin {
23
23
  private readonly options;
24
24
  hooks: {
25
- resolveTemplateSubstitutions: SyncWaterfallHook<[TemplateSubstitution[], TemplateItemInfo], Record<string, any>>;
25
+ resolveTemplateSubstitutions: SyncWaterfallHook<[
26
+ TemplateSubstitution[],
27
+ TemplateItemInfo
28
+ ], Record<string, any>>;
26
29
  };
27
30
  constructor(options: Options);
28
31
  private parseTemplate;