@cratis/scene.engine 4.13.0 → 4.15.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.
Files changed (67) hide show
  1. package/QueryBindingState.ts +43 -0
  2. package/QueryBindingTicket.ts +8 -0
  3. package/dist/cjs/QueryBindingState.js +38 -0
  4. package/dist/cjs/QueryBindingState.js.map +1 -0
  5. package/dist/cjs/forms/CommandFormLayoutKey.js +14 -0
  6. package/dist/cjs/forms/CommandFormLayoutKey.js.map +1 -0
  7. package/dist/cjs/forms/applyCommandFormLayoutKey.js +72 -0
  8. package/dist/cjs/forms/applyCommandFormLayoutKey.js.map +1 -0
  9. package/dist/cjs/forms/stackCommandFormLayout.js +37 -0
  10. package/dist/cjs/forms/stackCommandFormLayout.js.map +1 -0
  11. package/dist/cjs/index.js +12 -0
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/nestBindingScope.js +26 -0
  14. package/dist/cjs/nestBindingScope.js.map +1 -0
  15. package/dist/cjs/removeComponentOutputs.js +19 -0
  16. package/dist/cjs/removeComponentOutputs.js.map +1 -0
  17. package/dist/cjs/resolveBindingExpression.js +12 -8
  18. package/dist/cjs/resolveBindingExpression.js.map +1 -1
  19. package/dist/esm/QueryBindingState.d.ts +10 -0
  20. package/dist/esm/QueryBindingState.d.ts.map +1 -0
  21. package/dist/esm/QueryBindingState.js +36 -0
  22. package/dist/esm/QueryBindingState.js.map +1 -0
  23. package/dist/esm/QueryBindingTicket.d.ts +5 -0
  24. package/dist/esm/QueryBindingTicket.d.ts.map +1 -0
  25. package/dist/esm/QueryBindingTicket.js +2 -0
  26. package/dist/esm/QueryBindingTicket.js.map +1 -0
  27. package/dist/esm/forms/CommandFormLayoutKey.d.ts +7 -0
  28. package/dist/esm/forms/CommandFormLayoutKey.d.ts.map +1 -0
  29. package/dist/esm/forms/CommandFormLayoutKey.js +12 -0
  30. package/dist/esm/forms/CommandFormLayoutKey.js.map +1 -0
  31. package/dist/esm/forms/applyCommandFormLayoutKey.d.ts +5 -0
  32. package/dist/esm/forms/applyCommandFormLayoutKey.d.ts.map +1 -0
  33. package/dist/esm/forms/applyCommandFormLayoutKey.js +70 -0
  34. package/dist/esm/forms/applyCommandFormLayoutKey.js.map +1 -0
  35. package/dist/esm/forms/index.d.ts +3 -0
  36. package/dist/esm/forms/index.d.ts.map +1 -1
  37. package/dist/esm/forms/index.js +3 -0
  38. package/dist/esm/forms/index.js.map +1 -1
  39. package/dist/esm/forms/stackCommandFormLayout.d.ts +3 -0
  40. package/dist/esm/forms/stackCommandFormLayout.d.ts.map +1 -0
  41. package/dist/esm/forms/stackCommandFormLayout.js +35 -0
  42. package/dist/esm/forms/stackCommandFormLayout.js.map +1 -0
  43. package/dist/esm/index.d.ts +4 -0
  44. package/dist/esm/index.d.ts.map +1 -1
  45. package/dist/esm/index.js +6 -0
  46. package/dist/esm/index.js.map +1 -1
  47. package/dist/esm/nestBindingScope.d.ts +3 -0
  48. package/dist/esm/nestBindingScope.d.ts.map +1 -0
  49. package/dist/esm/nestBindingScope.js +24 -0
  50. package/dist/esm/nestBindingScope.js.map +1 -0
  51. package/dist/esm/removeComponentOutputs.d.ts +3 -0
  52. package/dist/esm/removeComponentOutputs.d.ts.map +1 -0
  53. package/dist/esm/removeComponentOutputs.js +17 -0
  54. package/dist/esm/removeComponentOutputs.js.map +1 -0
  55. package/dist/esm/resolveBindingExpression.d.ts.map +1 -1
  56. package/dist/esm/resolveBindingExpression.js +12 -8
  57. package/dist/esm/resolveBindingExpression.js.map +1 -1
  58. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  59. package/forms/CommandFormLayoutKey.ts +10 -0
  60. package/forms/applyCommandFormLayoutKey.ts +47 -0
  61. package/forms/index.ts +3 -0
  62. package/forms/stackCommandFormLayout.ts +22 -0
  63. package/index.ts +4 -0
  64. package/nestBindingScope.ts +19 -0
  65. package/package.json +3 -3
  66. package/removeComponentOutputs.ts +15 -0
  67. package/resolveBindingExpression.ts +14 -7
@@ -0,0 +1,43 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { BindingScope } from './BindingScope';
5
+ import { QueryBindingTicket } from './QueryBindingTicket';
6
+
7
+ /**
8
+ * Keeps the results of bound queries as their arguments change. Every rebind starts a new generation; a
9
+ * result is accepted only for the latest generation of its query, so a slow answer for a previous
10
+ * selection is discarded instead of overwriting the current one. Clearing a query - its arguments became
11
+ * unavailable, or its element left the tree - removes the result and invalidates any run in flight.
12
+ *
13
+ * The C# engine (`QueryBindingState`) behaves identically; both run `binding-resolution-fixtures.json`.
14
+ */
15
+ export class QueryBindingState {
16
+ readonly #generations = new Map<string, number>();
17
+ readonly #results = new Map<string, unknown>();
18
+
19
+ /** Starts a run of a query with new arguments, invalidating every earlier run of that query. */
20
+ begin(query: string): QueryBindingTicket {
21
+ const generation = (this.#generations.get(query) ?? 0) + 1;
22
+ this.#generations.set(query, generation);
23
+ return { query, generation };
24
+ }
25
+
26
+ /** Records a run's result. Returns false, and keeps the current result, when the run is stale. */
27
+ complete(ticket: QueryBindingTicket, result: unknown): boolean {
28
+ if (this.#generations.get(ticket.query) !== ticket.generation) return false;
29
+ this.#results.set(ticket.query, result);
30
+ return true;
31
+ }
32
+
33
+ /** Removes a query's result and invalidates any run still in flight. */
34
+ clear(query: string): void {
35
+ this.#generations.set(query, (this.#generations.get(query) ?? 0) + 1);
36
+ this.#results.delete(query);
37
+ }
38
+
39
+ /** The accepted results, as the query results of a binding scope. */
40
+ get queryResults(): NonNullable<BindingScope['queryResults']> {
41
+ return Object.fromEntries(this.#results);
42
+ }
43
+ }
@@ -0,0 +1,8 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ /** Identifies one run of a bound query, issued when the run starts. */
5
+ export interface QueryBindingTicket {
6
+ query: string;
7
+ generation: number;
8
+ }
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * Keeps the results of bound queries as their arguments change. Every rebind starts a new generation; a
7
+ * result is accepted only for the latest generation of its query, so a slow answer for a previous
8
+ * selection is discarded instead of overwriting the current one. Clearing a query - its arguments became
9
+ * unavailable, or its element left the tree - removes the result and invalidates any run in flight.
10
+ *
11
+ * The C# engine (`QueryBindingState`) behaves identically; both run `binding-resolution-fixtures.json`.
12
+ */ class QueryBindingState {
13
+ #generations = new Map();
14
+ #results = new Map();
15
+ /** Starts a run of a query with new arguments, invalidating every earlier run of that query. */ begin(query) {
16
+ const generation = (this.#generations.get(query) ?? 0) + 1;
17
+ this.#generations.set(query, generation);
18
+ return {
19
+ query,
20
+ generation
21
+ };
22
+ }
23
+ /** Records a run's result. Returns false, and keeps the current result, when the run is stale. */ complete(ticket, result) {
24
+ if (this.#generations.get(ticket.query) !== ticket.generation) return false;
25
+ this.#results.set(ticket.query, result);
26
+ return true;
27
+ }
28
+ /** Removes a query's result and invalidates any run still in flight. */ clear(query) {
29
+ this.#generations.set(query, (this.#generations.get(query) ?? 0) + 1);
30
+ this.#results.delete(query);
31
+ }
32
+ /** The accepted results, as the query results of a binding scope. */ get queryResults() {
33
+ return Object.fromEntries(this.#results);
34
+ }
35
+ }
36
+
37
+ exports.QueryBindingState = QueryBindingState;
38
+ //# sourceMappingURL=QueryBindingState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryBindingState.js","sources":["../../QueryBindingState.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingScope } from './BindingScope';\nimport { QueryBindingTicket } from './QueryBindingTicket';\n\n/**\n * Keeps the results of bound queries as their arguments change. Every rebind starts a new generation; a\n * result is accepted only for the latest generation of its query, so a slow answer for a previous\n * selection is discarded instead of overwriting the current one. Clearing a query - its arguments became\n * unavailable, or its element left the tree - removes the result and invalidates any run in flight.\n *\n * The C# engine (`QueryBindingState`) behaves identically; both run `binding-resolution-fixtures.json`.\n */\nexport class QueryBindingState {\n readonly #generations = new Map<string, number>();\n readonly #results = new Map<string, unknown>();\n\n /** Starts a run of a query with new arguments, invalidating every earlier run of that query. */\n begin(query: string): QueryBindingTicket {\n const generation = (this.#generations.get(query) ?? 0) + 1;\n this.#generations.set(query, generation);\n return { query, generation };\n }\n\n /** Records a run's result. Returns false, and keeps the current result, when the run is stale. */\n complete(ticket: QueryBindingTicket, result: unknown): boolean {\n if (this.#generations.get(ticket.query) !== ticket.generation) return false;\n this.#results.set(ticket.query, result);\n return true;\n }\n\n /** Removes a query's result and invalidates any run still in flight. */\n clear(query: string): void {\n this.#generations.set(query, (this.#generations.get(query) ?? 0) + 1);\n this.#results.delete(query);\n }\n\n /** The accepted results, as the query results of a binding scope. */\n get queryResults(): NonNullable<BindingScope['queryResults']> {\n return Object.fromEntries(this.#results);\n }\n}\n"],"names":["QueryBindingState","Map","begin","query","generation","get","set","complete","ticket","result","clear","delete","queryResults","Object","fromEntries"],"mappings":";;AAAA;AACA;AAKA;;;;;;;AAOC,IACM,MAAMA,iBAAAA,CAAAA;IACA,YAAY,GAAG,IAAIC,GAAAA,EAAAA;IACnB,QAAQ,GAAG,IAAIA,GAAAA,EAAAA;qGAGxBC,KAAAA,CAAMC,KAAa,EAAsB;AACrC,QAAA,MAAMC,UAAAA,GAAc,CAAA,IAAI,CAAC,YAAY,CAACC,GAAG,CAACF,KAAAA,CAAAA,IAAU,CAAA,IAAK,CAAA;AACzD,QAAA,IAAI,CAAC,YAAY,CAACG,GAAG,CAACH,KAAAA,EAAOC,UAAAA,CAAAA;QAC7B,OAAO;AAAED,YAAAA,KAAAA;AAAOC,YAAAA;AAAW,SAAA;AAC/B,IAAA;AAEA,uGACAG,QAAAA,CAASC,MAA0B,EAAEC,MAAe,EAAW;AAC3D,QAAA,IAAI,IAAI,CAAC,YAAY,CAACJ,GAAG,CAACG,MAAAA,CAAOL,KAAK,CAAA,KAAMK,MAAAA,CAAOJ,UAAU,EAAE,OAAO,KAAA;QACtE,IAAI,CAAC,QAAQ,CAACE,GAAG,CAACE,MAAAA,CAAOL,KAAK,EAAEM,MAAAA,CAAAA;QAChC,OAAO,IAAA;AACX,IAAA;6EAGAC,KAAAA,CAAMP,KAAa,EAAQ;AACvB,QAAA,IAAI,CAAC,YAAY,CAACG,GAAG,CAACH,OAAO,CAAC,IAAI,CAAC,YAAY,CAACE,GAAG,CAACF,KAAAA,CAAAA,IAAU,CAAA,IAAK,CAAA,CAAA;AACnE,QAAA,IAAI,CAAC,QAAQ,CAACQ,MAAM,CAACR,KAAAA,CAAAA;AACzB,IAAA;0EAGA,IAAIS,YAAAA,GAA0D;AAC1D,QAAA,OAAOC,OAAOC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAA;AAC3C,IAAA;AACJ;;"}
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /** The keys a designer maps to layout moves and resizes. */ var CommandFormLayoutKey = /*#__PURE__*/ function(CommandFormLayoutKey) {
6
+ CommandFormLayoutKey["ArrowLeft"] = "ArrowLeft";
7
+ CommandFormLayoutKey["ArrowRight"] = "ArrowRight";
8
+ CommandFormLayoutKey["ArrowUp"] = "ArrowUp";
9
+ CommandFormLayoutKey["ArrowDown"] = "ArrowDown";
10
+ return CommandFormLayoutKey;
11
+ }({});
12
+
13
+ exports.CommandFormLayoutKey = CommandFormLayoutKey;
14
+ //# sourceMappingURL=CommandFormLayoutKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandFormLayoutKey.js","sources":["../../../forms/CommandFormLayoutKey.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/** The keys a designer maps to layout moves and resizes. */\nexport enum CommandFormLayoutKey {\n ArrowLeft = 'ArrowLeft',\n ArrowRight = 'ArrowRight',\n ArrowUp = 'ArrowUp',\n ArrowDown = 'ArrowDown',\n}\n"],"names":["CommandFormLayoutKey"],"mappings":";;AAAA;AACA;AAEA,6DACO,IAAKA,oBAAAA,iBAAAA,SAAAA,oBAAAA,EAAAA;;;;;AAAAA,IAAAA,OAAAA,oBAAAA;AAKX,CAAA,CAAA,EAAA;;"}
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ var CommandFormLayoutKey = require('./CommandFormLayoutKey.js');
4
+ var updateCommandFormFieldPlacement = require('./updateCommandFormFieldPlacement.js');
5
+
6
+ // Copyright (c) Cratis. All rights reserved.
7
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8
+ /**
9
+ * Moves or resizes one field from the keyboard, so the layout can be arranged without a pointer.
10
+ *
11
+ * An arrow key moves the field one cell; with `resize`, Left and Right narrow and widen its column span and
12
+ * Up and Down shorten and lengthen its row span. Positions are one-based and never go below one, and spans never below one.
13
+ * The result is a draft validated like any other placement change, so a move or resize past the last
14
+ * column is reported in its diagnostics and the committed layout is kept. Returns undefined for a field that is not placed.
15
+ */ function applyCommandFormLayoutKey(committed, field, key, resize = false, fields = []) {
16
+ const placement = committed.placements.find((candidate)=>candidate.field === field);
17
+ if (!placement) return undefined;
18
+ return updateCommandFormFieldPlacement.updateCommandFormFieldPlacement(committed, resize ? resized(placement, key) : moved(placement, key), fields);
19
+ }
20
+ function moved(placement, key) {
21
+ switch(key){
22
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowLeft:
23
+ return {
24
+ ...placement,
25
+ column: Math.max(1, placement.column - 1)
26
+ };
27
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowRight:
28
+ return {
29
+ ...placement,
30
+ column: placement.column + 1
31
+ };
32
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowUp:
33
+ return {
34
+ ...placement,
35
+ row: Math.max(1, placement.row - 1)
36
+ };
37
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowDown:
38
+ return {
39
+ ...placement,
40
+ row: placement.row + 1
41
+ };
42
+ }
43
+ }
44
+ function resized(placement, key) {
45
+ const columnSpan = placement.columnSpan ?? 1;
46
+ const rowSpan = placement.rowSpan ?? 1;
47
+ switch(key){
48
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowLeft:
49
+ return {
50
+ ...placement,
51
+ columnSpan: Math.max(1, columnSpan - 1)
52
+ };
53
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowRight:
54
+ return {
55
+ ...placement,
56
+ columnSpan: columnSpan + 1
57
+ };
58
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowUp:
59
+ return {
60
+ ...placement,
61
+ rowSpan: Math.max(1, rowSpan - 1)
62
+ };
63
+ case CommandFormLayoutKey.CommandFormLayoutKey.ArrowDown:
64
+ return {
65
+ ...placement,
66
+ rowSpan: rowSpan + 1
67
+ };
68
+ }
69
+ }
70
+
71
+ exports.applyCommandFormLayoutKey = applyCommandFormLayoutKey;
72
+ //# sourceMappingURL=applyCommandFormLayoutKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyCommandFormLayoutKey.js","sources":["../../../forms/applyCommandFormLayoutKey.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CommandFormLayout, FormFieldPlacement } from '@cratis/scene.model';\nimport { CommandFormLayoutDraft } from './CommandFormLayoutDraft';\nimport { CommandFormLayoutKey } from './CommandFormLayoutKey';\nimport { updateCommandFormFieldPlacement } from './updateCommandFormFieldPlacement';\n\n/**\n * Moves or resizes one field from the keyboard, so the layout can be arranged without a pointer.\n *\n * An arrow key moves the field one cell; with `resize`, Left and Right narrow and widen its column span and\n * Up and Down shorten and lengthen its row span. Positions are one-based and never go below one, and spans never below one.\n * The result is a draft validated like any other placement change, so a move or resize past the last\n * column is reported in its diagnostics and the committed layout is kept. Returns undefined for a field that is not placed.\n */\nexport function applyCommandFormLayoutKey(\n committed: CommandFormLayout,\n field: string,\n key: CommandFormLayoutKey,\n resize = false,\n fields: readonly string[] = [],\n): CommandFormLayoutDraft | undefined {\n const placement = committed.placements.find(candidate => candidate.field === field);\n if (!placement) return undefined;\n return updateCommandFormFieldPlacement(committed, resize ? resized(placement, key) : moved(placement, key), fields);\n}\n\nfunction moved(placement: FormFieldPlacement, key: CommandFormLayoutKey): FormFieldPlacement {\n switch (key) {\n case CommandFormLayoutKey.ArrowLeft: return { ...placement, column: Math.max(1, placement.column - 1) };\n case CommandFormLayoutKey.ArrowRight: return { ...placement, column: placement.column + 1 };\n case CommandFormLayoutKey.ArrowUp: return { ...placement, row: Math.max(1, placement.row - 1) };\n case CommandFormLayoutKey.ArrowDown: return { ...placement, row: placement.row + 1 };\n }\n}\n\nfunction resized(placement: FormFieldPlacement, key: CommandFormLayoutKey): FormFieldPlacement {\n const columnSpan = placement.columnSpan ?? 1;\n const rowSpan = placement.rowSpan ?? 1;\n switch (key) {\n case CommandFormLayoutKey.ArrowLeft: return { ...placement, columnSpan: Math.max(1, columnSpan - 1) };\n case CommandFormLayoutKey.ArrowRight: return { ...placement, columnSpan: columnSpan + 1 };\n case CommandFormLayoutKey.ArrowUp: return { ...placement, rowSpan: Math.max(1, rowSpan - 1) };\n case CommandFormLayoutKey.ArrowDown: return { ...placement, rowSpan: rowSpan + 1 };\n }\n}\n"],"names":["applyCommandFormLayoutKey","committed","field","key","resize","fields","placement","placements","find","candidate","undefined","updateCommandFormFieldPlacement","resized","moved","CommandFormLayoutKey","ArrowLeft","column","Math","max","ArrowRight","ArrowUp","row","ArrowDown","columnSpan","rowSpan"],"mappings":";;;;;AAAA;AACA;AAOA;;;;;;;AAOC,IACM,SAASA,yBAAAA,CACZC,SAA4B,EAC5BC,KAAa,EACbC,GAAyB,EACzBC,MAAAA,GAAS,KAAK,EACdC,SAA4B,EAAE,EAAA;IAE9B,MAAMC,SAAAA,GAAYL,SAAAA,CAAUM,UAAU,CAACC,IAAI,CAACC,CAAAA,SAAAA,GAAaA,SAAAA,CAAUP,KAAK,KAAKA,KAAAA,CAAAA;IAC7E,IAAI,CAACI,WAAW,OAAOI,SAAAA;IACvB,OAAOC,+DAAAA,CAAgCV,WAAWG,MAAAA,GAASQ,OAAAA,CAAQN,WAAWH,GAAAA,CAAAA,GAAOU,KAAAA,CAAMP,WAAWH,GAAAA,CAAAA,EAAME,MAAAA,CAAAA;AAChH;AAEA,SAASQ,KAAAA,CAAMP,SAA6B,EAAEH,GAAyB,EAAA;IACnE,OAAQA,GAAAA;AACJ,QAAA,KAAKW,0CAAqBC,SAAS;YAAE,OAAO;AAAE,gBAAA,GAAGT,SAAS;AAAEU,gBAAAA,MAAAA,EAAQC,KAAKC,GAAG,CAAC,CAAA,EAAGZ,SAAAA,CAAUU,MAAM,GAAG,CAAA;AAAG,aAAA;AACtG,QAAA,KAAKF,0CAAqBK,UAAU;YAAE,OAAO;AAAE,gBAAA,GAAGb,SAAS;gBAAEU,MAAAA,EAAQV,SAAAA,CAAUU,MAAM,GAAG;AAAE,aAAA;AAC1F,QAAA,KAAKF,0CAAqBM,OAAO;YAAE,OAAO;AAAE,gBAAA,GAAGd,SAAS;AAAEe,gBAAAA,GAAAA,EAAKJ,KAAKC,GAAG,CAAC,CAAA,EAAGZ,SAAAA,CAAUe,GAAG,GAAG,CAAA;AAAG,aAAA;AAC9F,QAAA,KAAKP,0CAAqBQ,SAAS;YAAE,OAAO;AAAE,gBAAA,GAAGhB,SAAS;gBAAEe,GAAAA,EAAKf,SAAAA,CAAUe,GAAG,GAAG;AAAE,aAAA;AACvF;AACJ;AAEA,SAAST,OAAAA,CAAQN,SAA6B,EAAEH,GAAyB,EAAA;IACrE,MAAMoB,UAAAA,GAAajB,SAAAA,CAAUiB,UAAU,IAAI,CAAA;IAC3C,MAAMC,OAAAA,GAAUlB,SAAAA,CAAUkB,OAAO,IAAI,CAAA;IACrC,OAAQrB,GAAAA;AACJ,QAAA,KAAKW,0CAAqBC,SAAS;YAAE,OAAO;AAAE,gBAAA,GAAGT,SAAS;AAAEiB,gBAAAA,UAAAA,EAAYN,IAAAA,CAAKC,GAAG,CAAC,CAAA,EAAGK,UAAAA,GAAa,CAAA;AAAG,aAAA;AACpG,QAAA,KAAKT,0CAAqBK,UAAU;YAAE,OAAO;AAAE,gBAAA,GAAGb,SAAS;AAAEiB,gBAAAA,UAAAA,EAAYA,UAAAA,GAAa;AAAE,aAAA;AACxF,QAAA,KAAKT,0CAAqBM,OAAO;YAAE,OAAO;AAAE,gBAAA,GAAGd,SAAS;AAAEkB,gBAAAA,OAAAA,EAASP,IAAAA,CAAKC,GAAG,CAAC,CAAA,EAAGM,OAAAA,GAAU,CAAA;AAAG,aAAA;AAC5F,QAAA,KAAKV,0CAAqBQ,SAAS;YAAE,OAAO;AAAE,gBAAA,GAAGhB,SAAS;AAAEkB,gBAAAA,OAAAA,EAASA,OAAAA,GAAU;AAAE,aAAA;AACrF;AACJ;;"}
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ var scene_model = require('@cratis/scene.model');
4
+
5
+ // Copyright (c) Cratis. All rights reserved.
6
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
7
+ /**
8
+ * The layout a command form uses at a compact width: one full-width column, every field on its own row,
9
+ * in reading order - row first, then column, then authored order. Spans and per-field widths are dropped
10
+ * because there is nothing to span. The authored layout is not changed, so the form returns to its columns
11
+ * at a regular width.
12
+ */ function stackCommandFormLayout(layout) {
13
+ const ordered = layout.placements.map((placement, order)=>({
14
+ placement,
15
+ order
16
+ })).sort((left, right)=>left.placement.row - right.placement.row || left.placement.column - right.placement.column || left.order - right.order);
17
+ return {
18
+ ...layout,
19
+ columns: [
20
+ {
21
+ index: 1,
22
+ width: {
23
+ unit: scene_model.FormWidthUnit.Fraction,
24
+ value: 1
25
+ }
26
+ }
27
+ ],
28
+ placements: ordered.map(({ placement }, index)=>({
29
+ field: placement.field,
30
+ row: index + 1,
31
+ column: 1
32
+ }))
33
+ };
34
+ }
35
+
36
+ exports.stackCommandFormLayout = stackCommandFormLayout;
37
+ //# sourceMappingURL=stackCommandFormLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stackCommandFormLayout.js","sources":["../../../forms/stackCommandFormLayout.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CommandFormLayout, FormWidthUnit } from '@cratis/scene.model';\n\n/**\n * The layout a command form uses at a compact width: one full-width column, every field on its own row,\n * in reading order - row first, then column, then authored order. Spans and per-field widths are dropped\n * because there is nothing to span. The authored layout is not changed, so the form returns to its columns\n * at a regular width.\n */\nexport function stackCommandFormLayout(layout: CommandFormLayout): CommandFormLayout {\n const ordered = layout.placements\n .map((placement, order) => ({ placement, order }))\n .sort((left, right) => left.placement.row - right.placement.row || left.placement.column - right.placement.column || left.order - right.order);\n\n return {\n ...layout,\n columns: [{ index: 1, width: { unit: FormWidthUnit.Fraction, value: 1 } }],\n placements: ordered.map(({ placement }, index) => ({ field: placement.field, row: index + 1, column: 1 })),\n };\n}\n"],"names":["stackCommandFormLayout","layout","ordered","placements","map","placement","order","sort","left","right","row","column","columns","index","width","unit","FormWidthUnit","Fraction","value","field"],"mappings":";;;;AAAA;AACA;AAIA;;;;;IAMO,SAASA,sBAAAA,CAAuBC,MAAyB,EAAA;IAC5D,MAAMC,OAAAA,GAAUD,OAAOE,UAAU,CAC5BC,GAAG,CAAC,CAACC,SAAAA,EAAWC,KAAAA,IAAW;AAAED,YAAAA,SAAAA;AAAWC,YAAAA;AAAM,SAAA,CAAA,CAAA,CAC9CC,IAAI,CAAC,CAACC,IAAAA,EAAMC,KAAAA,GAAUD,IAAAA,CAAKH,SAAS,CAACK,GAAG,GAAGD,KAAAA,CAAMJ,SAAS,CAACK,GAAG,IAAIF,IAAAA,CAAKH,SAAS,CAACM,MAAM,GAAGF,KAAAA,CAAMJ,SAAS,CAACM,MAAM,IAAIH,IAAAA,CAAKF,KAAK,GAAGG,MAAMH,KAAK,CAAA;IAEjJ,OAAO;AACH,QAAA,GAAGL,MAAM;QACTW,OAAAA,EAAS;AAAC,YAAA;gBAAEC,KAAAA,EAAO,CAAA;gBAAGC,KAAAA,EAAO;AAAEC,oBAAAA,IAAAA,EAAMC,0BAAcC,QAAQ;oBAAEC,KAAAA,EAAO;AAAE;AAAE;AAAE,SAAA;QAC1Ef,UAAAA,EAAYD,OAAAA,CAAQE,GAAG,CAAC,CAAC,EAAEC,SAAS,EAAE,EAAEQ,KAAAA,IAAW;AAAEM,gBAAAA,KAAAA,EAAOd,UAAUc,KAAK;AAAET,gBAAAA,GAAAA,EAAKG,KAAAA,GAAQ,CAAA;gBAAGF,MAAAA,EAAQ;aAAE,CAAA;AAC3G,KAAA;AACJ;;"}
package/dist/cjs/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var resolveBindingExpression = require('./resolveBindingExpression.js');
4
+ var nestBindingScope = require('./nestBindingScope.js');
5
+ var removeComponentOutputs = require('./removeComponentOutputs.js');
6
+ var QueryBindingState = require('./QueryBindingState.js');
4
7
  var validateBindingExpression = require('./validateBindingExpression.js');
5
8
  var renderElement = require('./renderElement.js');
6
9
  var CommandFormLayoutDiagnosticCode = require('./forms/CommandFormLayoutDiagnosticCode.js');
@@ -13,6 +16,9 @@ var preserveDirtyCommandValues = require('./forms/preserveDirtyCommandValues.js'
13
16
  var resizeCommandFormColumn = require('./forms/resizeCommandFormColumn.js');
14
17
  var updateCommandFormFieldPlacement = require('./forms/updateCommandFormFieldPlacement.js');
15
18
  var validateCommandFormLayout = require('./forms/validateCommandFormLayout.js');
19
+ var CommandFormLayoutKey = require('./forms/CommandFormLayoutKey.js');
20
+ var applyCommandFormLayoutKey = require('./forms/applyCommandFormLayoutKey.js');
21
+ var stackCommandFormLayout = require('./forms/stackCommandFormLayout.js');
16
22
  var elementKind = require('./elementKind.js');
17
23
  var panelKind = require('./panelKind.js');
18
24
  var flowNodeKind = require('./flowNodeKind.js');
@@ -69,6 +75,9 @@ var collectIconUsages = require('./editing/collectIconUsages.js');
69
75
 
70
76
  exports.createBindingResolver = resolveBindingExpression.createBindingResolver;
71
77
  exports.resolveBindingExpression = resolveBindingExpression.resolveBindingExpression;
78
+ exports.nestBindingScope = nestBindingScope.nestBindingScope;
79
+ exports.removeComponentOutputs = removeComponentOutputs.removeComponentOutputs;
80
+ exports.QueryBindingState = QueryBindingState.QueryBindingState;
72
81
  exports.validateBindingExpression = validateBindingExpression.validateBindingExpression;
73
82
  exports.renderElement = renderElement.renderElement;
74
83
  exports.CommandFormLayoutDiagnosticCode = CommandFormLayoutDiagnosticCode.CommandFormLayoutDiagnosticCode;
@@ -81,6 +90,9 @@ exports.preserveDirtyCommandValues = preserveDirtyCommandValues.preserveDirtyCom
81
90
  exports.resizeCommandFormColumn = resizeCommandFormColumn.resizeCommandFormColumn;
82
91
  exports.updateCommandFormFieldPlacement = updateCommandFormFieldPlacement.updateCommandFormFieldPlacement;
83
92
  exports.validateCommandFormLayout = validateCommandFormLayout.validateCommandFormLayout;
93
+ exports.CommandFormLayoutKey = CommandFormLayoutKey.CommandFormLayoutKey;
94
+ exports.applyCommandFormLayoutKey = applyCommandFormLayoutKey.applyCommandFormLayoutKey;
95
+ exports.stackCommandFormLayout = stackCommandFormLayout.stackCommandFormLayout;
84
96
  exports.isContentControl = elementKind.isContentControl;
85
97
  exports.isExternalComponent = elementKind.isExternalComponent;
86
98
  exports.isItemsControl = elementKind.isItemsControl;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * The scope a nested template or region sees. A data context it declares replaces the inherited one - a
7
+ * detail region bound to the selected row reads that row, not the screen's - while query results and
8
+ * component outputs are inherited, with its own entries shadowing the parent's of the same name. A null
9
+ * data context inherits, as in the C# engine, which cannot tell null from absent. The parent scope is not
10
+ * changed.
11
+ */ function nestBindingScope(parent, nested) {
12
+ return {
13
+ dataContext: nested.dataContext ?? parent.dataContext,
14
+ queryResults: {
15
+ ...parent.queryResults ?? {},
16
+ ...nested.queryResults ?? {}
17
+ },
18
+ componentOutputs: {
19
+ ...parent.componentOutputs ?? {},
20
+ ...nested.componentOutputs ?? {}
21
+ }
22
+ };
23
+ }
24
+
25
+ exports.nestBindingScope = nestBindingScope;
26
+ //# sourceMappingURL=nestBindingScope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestBindingScope.js","sources":["../../nestBindingScope.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingScope } from './BindingScope';\n\n/**\n * The scope a nested template or region sees. A data context it declares replaces the inherited one - a\n * detail region bound to the selected row reads that row, not the screen's - while query results and\n * component outputs are inherited, with its own entries shadowing the parent's of the same name. A null\n * data context inherits, as in the C# engine, which cannot tell null from absent. The parent scope is not\n * changed.\n */\nexport function nestBindingScope(parent: BindingScope, nested: BindingScope): BindingScope {\n return {\n dataContext: nested.dataContext ?? parent.dataContext,\n queryResults: { ...(parent.queryResults ?? {}), ...(nested.queryResults ?? {}) },\n componentOutputs: { ...(parent.componentOutputs ?? {}), ...(nested.componentOutputs ?? {}) },\n };\n}\n"],"names":["nestBindingScope","parent","nested","dataContext","queryResults","componentOutputs"],"mappings":";;AAAA;AACA;AAIA;;;;;;AAMC,IACM,SAASA,gBAAAA,CAAiBC,MAAoB,EAAEC,MAAoB,EAAA;IACvE,OAAO;AACHC,QAAAA,WAAAA,EAAaD,MAAAA,CAAOC,WAAW,IAAIF,MAAAA,CAAOE,WAAW;QACrDC,YAAAA,EAAc;AAAE,YAAA,GAAIH,MAAAA,CAAOG,YAAY,IAAI,EAAE;AAAG,YAAA,GAAIF,MAAAA,CAAOE,YAAY,IAAI;AAAI,SAAA;QAC/EC,gBAAAA,EAAkB;AAAE,YAAA,GAAIJ,MAAAA,CAAOI,gBAAgB,IAAI,EAAE;AAAG,YAAA,GAAIH,MAAAA,CAAOG,gBAAgB,IAAI;AAAI;AAC/F,KAAA;AACJ;;"}
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * The scope after elements leave the tree - unmounted, deleted or renamed to a new id. Their output
7
+ * properties are removed, so a binding to them resolves as absent and validates as `unknownComponent`
8
+ * instead of reading a value from an element that no longer exists.
9
+ */ function removeComponentOutputs(scope, elementIds) {
10
+ const removed = new Set(elementIds);
11
+ const componentOutputs = Object.fromEntries(Object.entries(scope.componentOutputs ?? {}).filter(([id])=>!removed.has(id)));
12
+ return {
13
+ ...scope,
14
+ componentOutputs
15
+ };
16
+ }
17
+
18
+ exports.removeComponentOutputs = removeComponentOutputs;
19
+ //# sourceMappingURL=removeComponentOutputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"removeComponentOutputs.js","sources":["../../removeComponentOutputs.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingScope } from './BindingScope';\n\n/**\n * The scope after elements leave the tree - unmounted, deleted or renamed to a new id. Their output\n * properties are removed, so a binding to them resolves as absent and validates as `unknownComponent`\n * instead of reading a value from an element that no longer exists.\n */\nexport function removeComponentOutputs(scope: BindingScope, elementIds: string[]): BindingScope {\n const removed = new Set(elementIds);\n const componentOutputs = Object.fromEntries(Object.entries(scope.componentOutputs ?? {}).filter(([id]) => !removed.has(id)));\n return { ...scope, componentOutputs };\n}\n"],"names":["removeComponentOutputs","scope","elementIds","removed","Set","componentOutputs","Object","fromEntries","entries","filter","id","has"],"mappings":";;AAAA;AACA;AAIA;;;;AAIC,IACM,SAASA,sBAAAA,CAAuBC,KAAmB,EAAEC,UAAoB,EAAA;IAC5E,MAAMC,OAAAA,GAAU,IAAIC,GAAAA,CAAIF,UAAAA,CAAAA;IACxB,MAAMG,gBAAAA,GAAmBC,OAAOC,WAAW,CAACD,OAAOE,OAAO,CAACP,MAAMI,gBAAgB,IAAI,EAAC,CAAA,CAAGI,MAAM,CAAC,CAAC,CAACC,GAAG,GAAK,CAACP,OAAAA,CAAQQ,GAAG,CAACD,EAAAA,CAAAA,CAAAA,CAAAA;IACvH,OAAO;AAAE,QAAA,GAAGT,KAAK;AAAEI,QAAAA;AAAiB,KAAA;AACxC;;"}
@@ -8,9 +8,9 @@ var scene_model = require('@cratis/scene.model');
8
8
  * Resolves a typed binding against the shared runtime binding scope.
9
9
  */ function resolveBindingExpression(binding, scope) {
10
10
  const kind = binding.kind ?? scene_model.BindingSourceKind.DataContext;
11
- if (kind === scene_model.BindingSourceKind.Literal) return binding.value;
12
- const source = sourceValue(binding, scope, kind);
13
- const value = readPath(source, sourcePath(binding, kind));
11
+ // A literal without a value is absent, whether the author wrote `null` or nothing: the C# model cannot
12
+ // tell the two apart, and both engines must resolve the same document to the same value.
13
+ const value = kind === scene_model.BindingSourceKind.Literal ? binding.value ?? undefined : readPath(sourceValue(binding, scope, kind), sourcePath(binding, kind));
14
14
  if (value !== null && value !== undefined) return value;
15
15
  if (binding.nullBehavior === scene_model.BindingNullBehavior.Preserve) return undefined;
16
16
  if (binding.nullBehavior === scene_model.BindingNullBehavior.Clear) return null;
@@ -24,7 +24,7 @@ var scene_model = require('@cratis/scene.model');
24
24
  function sourceValue(binding, scope, kind) {
25
25
  switch(kind){
26
26
  case scene_model.BindingSourceKind.DataContext:
27
- return scope.dataContext;
27
+ return scope.dataContext ?? undefined;
28
28
  case scene_model.BindingSourceKind.QueryResult:
29
29
  return binding.query ? scope.queryResults?.[binding.query] : undefined;
30
30
  case scene_model.BindingSourceKind.ComponentProperty:
@@ -37,12 +37,16 @@ function sourcePath(binding, kind) {
37
37
  if (kind === scene_model.BindingSourceKind.ComponentProperty) return binding.componentPropertyPath ?? binding.path;
38
38
  return binding.path;
39
39
  }
40
- function readPath(source, path) {
40
+ /**
41
+ * Reads a dotted path. Only own properties and array indexes are read - never inherited members such as
42
+ * `constructor` - and anything that is not an object or array ends the walk, so the C# engine can follow
43
+ * exactly the same rule over JSON.
44
+ */ function readPath(source, path) {
41
45
  if (!path) return source;
42
46
  return path.split('.').reduce((current, segment)=>{
43
- if (current === null || current === undefined) return undefined;
44
- if (typeof current !== 'object') return undefined;
45
- return current[segment];
47
+ if (current === null || current === undefined || typeof current !== 'object') return undefined;
48
+ if (Array.isArray(current)) return /^(0|[1-9][0-9]*)$/.test(segment) ? current[Number(segment)] : undefined;
49
+ return Object.hasOwn(current, segment) ? current[segment] : undefined;
46
50
  }, source);
47
51
  }
48
52
 
@@ -1 +1 @@
1
- {"version":3,"file":"resolveBindingExpression.js","sources":["../../resolveBindingExpression.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingExpression, BindingNullBehavior, BindingSourceKind } from '@cratis/scene.model';\nimport { BindingScope } from './BindingScope';\n\n/**\n * Resolves a typed binding against the shared runtime binding scope.\n */\nexport function resolveBindingExpression(binding: BindingExpression, scope: BindingScope): unknown {\n const kind = binding.kind ?? BindingSourceKind.DataContext;\n if (kind === BindingSourceKind.Literal) return binding.value;\n\n const source = sourceValue(binding, scope, kind);\n const value = readPath(source, sourcePath(binding, kind));\n if (value !== null && value !== undefined) return value;\n\n if (binding.nullBehavior === BindingNullBehavior.Preserve) return undefined;\n if (binding.nullBehavior === BindingNullBehavior.Clear) return null;\n return value;\n}\n\n/**\n * Creates a legacy resolver function from a binding scope.\n */\nexport function createBindingResolver(scope: BindingScope): (binding: BindingExpression) => unknown {\n return binding => resolveBindingExpression(binding, scope);\n}\n\nfunction sourceValue(binding: BindingExpression, scope: BindingScope, kind: BindingSourceKind): unknown {\n switch (kind) {\n case BindingSourceKind.DataContext:\n return scope.dataContext;\n case BindingSourceKind.QueryResult:\n return binding.query ? scope.queryResults?.[binding.query] : undefined;\n case BindingSourceKind.ComponentProperty:\n return binding.componentId ? scope.componentOutputs?.[binding.componentId] : undefined;\n case BindingSourceKind.Literal:\n return binding.value;\n }\n}\n\nfunction sourcePath(binding: BindingExpression, kind: BindingSourceKind): string {\n if (kind === BindingSourceKind.ComponentProperty) return binding.componentPropertyPath ?? binding.path;\n return binding.path;\n}\n\nfunction readPath(source: unknown, path: string): unknown {\n if (!path) return source;\n return path.split('.').reduce<unknown>((current, segment) => {\n if (current === null || current === undefined) return undefined;\n if (typeof current !== 'object') return undefined;\n return (current as Record<string, unknown>)[segment];\n }, source);\n}\n"],"names":["resolveBindingExpression","binding","scope","kind","BindingSourceKind","DataContext","Literal","value","source","sourceValue","readPath","sourcePath","undefined","nullBehavior","BindingNullBehavior","Preserve","Clear","createBindingResolver","dataContext","QueryResult","query","queryResults","ComponentProperty","componentId","componentOutputs","componentPropertyPath","path","split","reduce","current","segment"],"mappings":";;;;AAAA;AACA;AAKA;;AAEC,IACM,SAASA,wBAAAA,CAAyBC,OAA0B,EAAEC,KAAmB,EAAA;AACpF,IAAA,MAAMC,IAAAA,GAAOF,OAAAA,CAAQE,IAAI,IAAIC,8BAAkBC,WAAW;AAC1D,IAAA,IAAIF,SAASC,6BAAAA,CAAkBE,OAAO,EAAE,OAAOL,QAAQM,KAAK;IAE5D,MAAMC,MAAAA,GAASC,WAAAA,CAAYR,OAAAA,EAASC,KAAAA,EAAOC,IAAAA,CAAAA;AAC3C,IAAA,MAAMI,KAAAA,GAAQG,QAAAA,CAASF,MAAAA,EAAQG,UAAAA,CAAWV,OAAAA,EAASE,IAAAA,CAAAA,CAAAA;AACnD,IAAA,IAAII,KAAAA,KAAU,IAAA,IAAQA,KAAAA,KAAUK,SAAAA,EAAW,OAAOL,KAAAA;AAElD,IAAA,IAAIN,QAAQY,YAAY,KAAKC,+BAAAA,CAAoBC,QAAQ,EAAE,OAAOH,SAAAA;AAClE,IAAA,IAAIX,QAAQY,YAAY,KAAKC,+BAAAA,CAAoBE,KAAK,EAAE,OAAO,IAAA;IAC/D,OAAOT,KAAAA;AACX;AAEA;;IAGO,SAASU,qBAAAA,CAAsBf,KAAmB,EAAA;IACrD,OAAOD,CAAAA,OAAAA,GAAWD,wBAAAA,CAAyBC,OAAAA,EAASC,KAAAA,CAAAA;AACxD;AAEA,SAASO,WAAAA,CAAYR,OAA0B,EAAEC,KAAmB,EAAEC,IAAuB,EAAA;IACzF,OAAQA,IAAAA;AACJ,QAAA,KAAKC,8BAAkBC,WAAW;AAC9B,YAAA,OAAOH,MAAMgB,WAAW;AAC5B,QAAA,KAAKd,8BAAkBe,WAAW;YAC9B,OAAOlB,OAAAA,CAAQmB,KAAK,GAAGlB,KAAAA,CAAMmB,YAAY,GAAGpB,OAAAA,CAAQmB,KAAK,CAAC,GAAGR,SAAAA;AACjE,QAAA,KAAKR,8BAAkBkB,iBAAiB;YACpC,OAAOrB,OAAAA,CAAQsB,WAAW,GAAGrB,KAAAA,CAAMsB,gBAAgB,GAAGvB,OAAAA,CAAQsB,WAAW,CAAC,GAAGX,SAAAA;AACjF,QAAA,KAAKR,8BAAkBE,OAAO;AAC1B,YAAA,OAAOL,QAAQM,KAAK;AAC5B;AACJ;AAEA,SAASI,UAAAA,CAAWV,OAA0B,EAAEE,IAAuB,EAAA;IACnE,IAAIA,IAAAA,KAASC,8BAAkBkB,iBAAiB,EAAE,OAAOrB,OAAAA,CAAQwB,qBAAqB,IAAIxB,OAAAA,CAAQyB,IAAI;AACtG,IAAA,OAAOzB,QAAQyB,IAAI;AACvB;AAEA,SAAShB,QAAAA,CAASF,MAAe,EAAEkB,IAAY,EAAA;IAC3C,IAAI,CAACA,MAAM,OAAOlB,MAAAA;AAClB,IAAA,OAAOkB,KAAKC,KAAK,CAAC,KAAKC,MAAM,CAAU,CAACC,OAAAA,EAASC,OAAAA,GAAAA;AAC7C,QAAA,IAAID,OAAAA,KAAY,IAAA,IAAQA,OAAAA,KAAYjB,SAAAA,EAAW,OAAOA,SAAAA;QACtD,IAAI,OAAOiB,OAAAA,KAAY,QAAA,EAAU,OAAOjB,SAAAA;QACxC,OAAQiB,OAAmC,CAACC,OAAAA,CAAQ;IACxD,CAAA,EAAGtB,MAAAA,CAAAA;AACP;;;"}
1
+ {"version":3,"file":"resolveBindingExpression.js","sources":["../../resolveBindingExpression.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingExpression, BindingNullBehavior, BindingSourceKind } from '@cratis/scene.model';\nimport { BindingScope } from './BindingScope';\n\n/**\n * Resolves a typed binding against the shared runtime binding scope.\n */\nexport function resolveBindingExpression(binding: BindingExpression, scope: BindingScope): unknown {\n const kind = binding.kind ?? BindingSourceKind.DataContext;\n\n // A literal without a value is absent, whether the author wrote `null` or nothing: the C# model cannot\n // tell the two apart, and both engines must resolve the same document to the same value.\n const value = kind === BindingSourceKind.Literal\n ? binding.value ?? undefined\n : readPath(sourceValue(binding, scope, kind), sourcePath(binding, kind));\n if (value !== null && value !== undefined) return value;\n\n if (binding.nullBehavior === BindingNullBehavior.Preserve) return undefined;\n if (binding.nullBehavior === BindingNullBehavior.Clear) return null;\n return value;\n}\n\n/**\n * Creates a legacy resolver function from a binding scope.\n */\nexport function createBindingResolver(scope: BindingScope): (binding: BindingExpression) => unknown {\n return binding => resolveBindingExpression(binding, scope);\n}\n\nfunction sourceValue(binding: BindingExpression, scope: BindingScope, kind: BindingSourceKind): unknown {\n switch (kind) {\n case BindingSourceKind.DataContext:\n return scope.dataContext ?? undefined;\n case BindingSourceKind.QueryResult:\n return binding.query ? scope.queryResults?.[binding.query] : undefined;\n case BindingSourceKind.ComponentProperty:\n return binding.componentId ? scope.componentOutputs?.[binding.componentId] : undefined;\n case BindingSourceKind.Literal:\n return binding.value;\n }\n}\n\nfunction sourcePath(binding: BindingExpression, kind: BindingSourceKind): string {\n if (kind === BindingSourceKind.ComponentProperty) return binding.componentPropertyPath ?? binding.path;\n return binding.path;\n}\n\n/**\n * Reads a dotted path. Only own properties and array indexes are read - never inherited members such as\n * `constructor` - and anything that is not an object or array ends the walk, so the C# engine can follow\n * exactly the same rule over JSON.\n */\nfunction readPath(source: unknown, path: string): unknown {\n if (!path) return source;\n return path.split('.').reduce<unknown>((current, segment) => {\n if (current === null || current === undefined || typeof current !== 'object') return undefined;\n if (Array.isArray(current)) return /^(0|[1-9][0-9]*)$/.test(segment) ? current[Number(segment)] : undefined;\n return Object.hasOwn(current, segment) ? (current as Record<string, unknown>)[segment] : undefined;\n }, source);\n}\n"],"names":["resolveBindingExpression","binding","scope","kind","BindingSourceKind","DataContext","value","Literal","undefined","readPath","sourceValue","sourcePath","nullBehavior","BindingNullBehavior","Preserve","Clear","createBindingResolver","dataContext","QueryResult","query","queryResults","ComponentProperty","componentId","componentOutputs","componentPropertyPath","path","source","split","reduce","current","segment","Array","isArray","test","Number","Object","hasOwn"],"mappings":";;;;AAAA;AACA;AAKA;;AAEC,IACM,SAASA,wBAAAA,CAAyBC,OAA0B,EAAEC,KAAmB,EAAA;AACpF,IAAA,MAAMC,IAAAA,GAAOF,OAAAA,CAAQE,IAAI,IAAIC,8BAAkBC,WAAW;;;AAI1D,IAAA,MAAMC,KAAAA,GAAQH,IAAAA,KAASC,6BAAAA,CAAkBG,OAAO,GAC1CN,OAAAA,CAAQK,KAAK,IAAIE,SAAAA,GACjBC,SAASC,WAAAA,CAAYT,OAAAA,EAASC,KAAAA,EAAOC,IAAAA,CAAAA,EAAOQ,WAAWV,OAAAA,EAASE,IAAAA,CAAAA,CAAAA;AACtE,IAAA,IAAIG,KAAAA,KAAU,IAAA,IAAQA,KAAAA,KAAUE,SAAAA,EAAW,OAAOF,KAAAA;AAElD,IAAA,IAAIL,QAAQW,YAAY,KAAKC,+BAAAA,CAAoBC,QAAQ,EAAE,OAAON,SAAAA;AAClE,IAAA,IAAIP,QAAQW,YAAY,KAAKC,+BAAAA,CAAoBE,KAAK,EAAE,OAAO,IAAA;IAC/D,OAAOT,KAAAA;AACX;AAEA;;IAGO,SAASU,qBAAAA,CAAsBd,KAAmB,EAAA;IACrD,OAAOD,CAAAA,OAAAA,GAAWD,wBAAAA,CAAyBC,OAAAA,EAASC,KAAAA,CAAAA;AACxD;AAEA,SAASQ,WAAAA,CAAYT,OAA0B,EAAEC,KAAmB,EAAEC,IAAuB,EAAA;IACzF,OAAQA,IAAAA;AACJ,QAAA,KAAKC,8BAAkBC,WAAW;YAC9B,OAAOH,KAAAA,CAAMe,WAAW,IAAIT,SAAAA;AAChC,QAAA,KAAKJ,8BAAkBc,WAAW;YAC9B,OAAOjB,OAAAA,CAAQkB,KAAK,GAAGjB,KAAAA,CAAMkB,YAAY,GAAGnB,OAAAA,CAAQkB,KAAK,CAAC,GAAGX,SAAAA;AACjE,QAAA,KAAKJ,8BAAkBiB,iBAAiB;YACpC,OAAOpB,OAAAA,CAAQqB,WAAW,GAAGpB,KAAAA,CAAMqB,gBAAgB,GAAGtB,OAAAA,CAAQqB,WAAW,CAAC,GAAGd,SAAAA;AACjF,QAAA,KAAKJ,8BAAkBG,OAAO;AAC1B,YAAA,OAAON,QAAQK,KAAK;AAC5B;AACJ;AAEA,SAASK,UAAAA,CAAWV,OAA0B,EAAEE,IAAuB,EAAA;IACnE,IAAIA,IAAAA,KAASC,8BAAkBiB,iBAAiB,EAAE,OAAOpB,OAAAA,CAAQuB,qBAAqB,IAAIvB,OAAAA,CAAQwB,IAAI;AACtG,IAAA,OAAOxB,QAAQwB,IAAI;AACvB;AAEA;;;;AAIC,IACD,SAAShB,QAAAA,CAASiB,MAAe,EAAED,IAAY,EAAA;IAC3C,IAAI,CAACA,MAAM,OAAOC,MAAAA;AAClB,IAAA,OAAOD,KAAKE,KAAK,CAAC,KAAKC,MAAM,CAAU,CAACC,OAAAA,EAASC,OAAAA,GAAAA;AAC7C,QAAA,IAAID,YAAY,IAAA,IAAQA,OAAAA,KAAYrB,aAAa,OAAOqB,OAAAA,KAAY,UAAU,OAAOrB,SAAAA;AACrF,QAAA,IAAIuB,KAAAA,CAAMC,OAAO,CAACH,OAAAA,CAAAA,EAAU,OAAO,mBAAA,CAAoBI,IAAI,CAACH,OAAAA,CAAAA,GAAWD,OAAO,CAACK,MAAAA,CAAOJ,SAAS,GAAGtB,SAAAA;QAClG,OAAO2B,MAAAA,CAAOC,MAAM,CAACP,OAAAA,EAASC,WAAW,OAAoC,CAACA,OAAAA,CAAQ,GAAGtB,SAAAA;IAC7F,CAAA,EAAGkB,MAAAA,CAAAA;AACP;;;"}
@@ -0,0 +1,10 @@
1
+ import { BindingScope } from './BindingScope';
2
+ import { QueryBindingTicket } from './QueryBindingTicket';
3
+ export declare class QueryBindingState {
4
+ #private;
5
+ begin(query: string): QueryBindingTicket;
6
+ complete(ticket: QueryBindingTicket, result: unknown): boolean;
7
+ clear(query: string): void;
8
+ get queryResults(): NonNullable<BindingScope['queryResults']>;
9
+ }
10
+ //# sourceMappingURL=QueryBindingState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryBindingState.d.ts","sourceRoot":"","sources":["../../QueryBindingState.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAU1D,qBAAa,iBAAiB;;IAK1B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,CAIvC;IAGD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAI7D;IAGD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGzB;IAGD,IAAI,YAAY,IAAI,WAAW,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,CAE5D;CACJ"}
@@ -0,0 +1,36 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+ /**
4
+ * Keeps the results of bound queries as their arguments change. Every rebind starts a new generation; a
5
+ * result is accepted only for the latest generation of its query, so a slow answer for a previous
6
+ * selection is discarded instead of overwriting the current one. Clearing a query - its arguments became
7
+ * unavailable, or its element left the tree - removes the result and invalidates any run in flight.
8
+ *
9
+ * The C# engine (`QueryBindingState`) behaves identically; both run `binding-resolution-fixtures.json`.
10
+ */ class QueryBindingState {
11
+ #generations = new Map();
12
+ #results = new Map();
13
+ /** Starts a run of a query with new arguments, invalidating every earlier run of that query. */ begin(query) {
14
+ const generation = (this.#generations.get(query) ?? 0) + 1;
15
+ this.#generations.set(query, generation);
16
+ return {
17
+ query,
18
+ generation
19
+ };
20
+ }
21
+ /** Records a run's result. Returns false, and keeps the current result, when the run is stale. */ complete(ticket, result) {
22
+ if (this.#generations.get(ticket.query) !== ticket.generation) return false;
23
+ this.#results.set(ticket.query, result);
24
+ return true;
25
+ }
26
+ /** Removes a query's result and invalidates any run still in flight. */ clear(query) {
27
+ this.#generations.set(query, (this.#generations.get(query) ?? 0) + 1);
28
+ this.#results.delete(query);
29
+ }
30
+ /** The accepted results, as the query results of a binding scope. */ get queryResults() {
31
+ return Object.fromEntries(this.#results);
32
+ }
33
+ }
34
+
35
+ export { QueryBindingState };
36
+ //# sourceMappingURL=QueryBindingState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryBindingState.js","sources":["../../QueryBindingState.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { BindingScope } from './BindingScope';\nimport { QueryBindingTicket } from './QueryBindingTicket';\n\n/**\n * Keeps the results of bound queries as their arguments change. Every rebind starts a new generation; a\n * result is accepted only for the latest generation of its query, so a slow answer for a previous\n * selection is discarded instead of overwriting the current one. Clearing a query - its arguments became\n * unavailable, or its element left the tree - removes the result and invalidates any run in flight.\n *\n * The C# engine (`QueryBindingState`) behaves identically; both run `binding-resolution-fixtures.json`.\n */\nexport class QueryBindingState {\n readonly #generations = new Map<string, number>();\n readonly #results = new Map<string, unknown>();\n\n /** Starts a run of a query with new arguments, invalidating every earlier run of that query. */\n begin(query: string): QueryBindingTicket {\n const generation = (this.#generations.get(query) ?? 0) + 1;\n this.#generations.set(query, generation);\n return { query, generation };\n }\n\n /** Records a run's result. Returns false, and keeps the current result, when the run is stale. */\n complete(ticket: QueryBindingTicket, result: unknown): boolean {\n if (this.#generations.get(ticket.query) !== ticket.generation) return false;\n this.#results.set(ticket.query, result);\n return true;\n }\n\n /** Removes a query's result and invalidates any run still in flight. */\n clear(query: string): void {\n this.#generations.set(query, (this.#generations.get(query) ?? 0) + 1);\n this.#results.delete(query);\n }\n\n /** The accepted results, as the query results of a binding scope. */\n get queryResults(): NonNullable<BindingScope['queryResults']> {\n return Object.fromEntries(this.#results);\n }\n}\n"],"names":["QueryBindingState","Map","begin","query","generation","get","set","complete","ticket","result","clear","delete","queryResults","Object","fromEntries"],"mappings":"AAAA;AACA;AAKA;;;;;;;AAOC,IACM,MAAMA,iBAAAA,CAAAA;IACA,YAAY,GAAG,IAAIC,GAAAA,EAAAA;IACnB,QAAQ,GAAG,IAAIA,GAAAA,EAAAA;qGAGxBC,KAAAA,CAAMC,KAAa,EAAsB;AACrC,QAAA,MAAMC,UAAAA,GAAc,CAAA,IAAI,CAAC,YAAY,CAACC,GAAG,CAACF,KAAAA,CAAAA,IAAU,CAAA,IAAK,CAAA;AACzD,QAAA,IAAI,CAAC,YAAY,CAACG,GAAG,CAACH,KAAAA,EAAOC,UAAAA,CAAAA;QAC7B,OAAO;AAAED,YAAAA,KAAAA;AAAOC,YAAAA;AAAW,SAAA;AAC/B,IAAA;AAEA,uGACAG,QAAAA,CAASC,MAA0B,EAAEC,MAAe,EAAW;AAC3D,QAAA,IAAI,IAAI,CAAC,YAAY,CAACJ,GAAG,CAACG,MAAAA,CAAOL,KAAK,CAAA,KAAMK,MAAAA,CAAOJ,UAAU,EAAE,OAAO,KAAA;QACtE,IAAI,CAAC,QAAQ,CAACE,GAAG,CAACE,MAAAA,CAAOL,KAAK,EAAEM,MAAAA,CAAAA;QAChC,OAAO,IAAA;AACX,IAAA;6EAGAC,KAAAA,CAAMP,KAAa,EAAQ;AACvB,QAAA,IAAI,CAAC,YAAY,CAACG,GAAG,CAACH,OAAO,CAAC,IAAI,CAAC,YAAY,CAACE,GAAG,CAACF,KAAAA,CAAAA,IAAU,CAAA,IAAK,CAAA,CAAA;AACnE,QAAA,IAAI,CAAC,QAAQ,CAACQ,MAAM,CAACR,KAAAA,CAAAA;AACzB,IAAA;0EAGA,IAAIS,YAAAA,GAA0D;AAC1D,QAAA,OAAOC,OAAOC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAA;AAC3C,IAAA;AACJ;;"}
@@ -0,0 +1,5 @@
1
+ export interface QueryBindingTicket {
2
+ query: string;
3
+ generation: number;
4
+ }
5
+ //# sourceMappingURL=QueryBindingTicket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryBindingTicket.d.ts","sourceRoot":"","sources":["../../QueryBindingTicket.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=QueryBindingTicket.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryBindingTicket.js","sourceRoot":"","sources":["../../QueryBindingTicket.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ export declare enum CommandFormLayoutKey {
2
+ ArrowLeft = "ArrowLeft",
3
+ ArrowRight = "ArrowRight",
4
+ ArrowUp = "ArrowUp",
5
+ ArrowDown = "ArrowDown"
6
+ }
7
+ //# sourceMappingURL=CommandFormLayoutKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandFormLayoutKey.d.ts","sourceRoot":"","sources":["../../../forms/CommandFormLayoutKey.ts"],"names":[],"mappings":"AAIA,oBAAY,oBAAoB;IAC5B,SAAS,cAAc;IACvB,UAAU,eAAe;IACzB,OAAO,YAAY;IACnB,SAAS,cAAc;CAC1B"}
@@ -0,0 +1,12 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+ /** The keys a designer maps to layout moves and resizes. */ var CommandFormLayoutKey = /*#__PURE__*/ function(CommandFormLayoutKey) {
4
+ CommandFormLayoutKey["ArrowLeft"] = "ArrowLeft";
5
+ CommandFormLayoutKey["ArrowRight"] = "ArrowRight";
6
+ CommandFormLayoutKey["ArrowUp"] = "ArrowUp";
7
+ CommandFormLayoutKey["ArrowDown"] = "ArrowDown";
8
+ return CommandFormLayoutKey;
9
+ }({});
10
+
11
+ export { CommandFormLayoutKey };
12
+ //# sourceMappingURL=CommandFormLayoutKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommandFormLayoutKey.js","sources":["../../../forms/CommandFormLayoutKey.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\n/** The keys a designer maps to layout moves and resizes. */\nexport enum CommandFormLayoutKey {\n ArrowLeft = 'ArrowLeft',\n ArrowRight = 'ArrowRight',\n ArrowUp = 'ArrowUp',\n ArrowDown = 'ArrowDown',\n}\n"],"names":["CommandFormLayoutKey"],"mappings":"AAAA;AACA;AAEA,6DACO,IAAKA,oBAAAA,iBAAAA,SAAAA,oBAAAA,EAAAA;;;;;AAAAA,IAAAA,OAAAA,oBAAAA;AAKX,CAAA,CAAA,EAAA;;"}
@@ -0,0 +1,5 @@
1
+ import { CommandFormLayout } from '@cratis/scene.model';
2
+ import { CommandFormLayoutDraft } from './CommandFormLayoutDraft';
3
+ import { CommandFormLayoutKey } from './CommandFormLayoutKey';
4
+ export declare function applyCommandFormLayoutKey(committed: CommandFormLayout, field: string, key: CommandFormLayoutKey, resize?: boolean, fields?: readonly string[]): CommandFormLayoutDraft | undefined;
5
+ //# sourceMappingURL=applyCommandFormLayoutKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyCommandFormLayoutKey.d.ts","sourceRoot":"","sources":["../../../forms/applyCommandFormLayoutKey.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAsB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAW9D,wBAAgB,yBAAyB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,oBAAoB,EACzB,MAAM,UAAQ,EACd,MAAM,GAAE,SAAS,MAAM,EAAO,GAC/B,sBAAsB,GAAG,SAAS,CAIpC"}