@movable/studio-framework 3.0.0-canary.0 → 3.0.0-esmodules.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.es.js CHANGED
@@ -44,13 +44,50 @@ function _extends() {
44
44
  }
45
45
 
46
46
  const {
47
- entries
47
+ entries: entries$2
48
48
  } = Object;
49
- const STYLE_WHITELIST = new Set(['top', 'left', 'color', 'width', 'border', 'borderRadius', 'borderColor', 'borderStyle', 'borderWidth', 'boxSizing', 'boxShadow', 'height', 'marginTop', 'marginLeft', 'marginBottom', 'marginRight', 'zIndex', 'fontSize', 'position', 'textAlign', 'transform', 'textShadow', 'lineHeight', 'fontFamily', 'fontWeight', 'textTransform', 'letterSpacing', 'backgroundColor', 'backgroundImage', 'transformOrigin', 'opacity', 'overflow', 'display', 'flexDirection', 'justifyContent', 'whiteSpace']);
49
+ const STYLE_WHITELIST = {
50
+ top: true,
51
+ left: true,
52
+ color: true,
53
+ width: true,
54
+ border: true,
55
+ borderRadius: true,
56
+ borderColor: true,
57
+ borderStyle: true,
58
+ borderWidth: true,
59
+ boxSizing: true,
60
+ boxShadow: true,
61
+ height: true,
62
+ marginTop: true,
63
+ marginLeft: true,
64
+ marginBottom: true,
65
+ marginRight: true,
66
+ zIndex: true,
67
+ fontSize: true,
68
+ position: true,
69
+ textAlign: true,
70
+ transform: true,
71
+ textShadow: true,
72
+ lineHeight: true,
73
+ fontFamily: true,
74
+ fontWeight: true,
75
+ textTransform: true,
76
+ letterSpacing: true,
77
+ backgroundColor: true,
78
+ backgroundImage: true,
79
+ transformOrigin: true,
80
+ opacity: true,
81
+ overflow: true,
82
+ display: true,
83
+ flexDirection: true,
84
+ justifyContent: true,
85
+ whiteSpace: true
86
+ };
50
87
  const PROPERTY_TRANSFORMS = {
51
88
  transform: value => `rotate(${value}deg)`
52
89
  };
53
- const TRANSFORMS_MAP = new Map(entries(PROPERTY_TRANSFORMS));
90
+ const TRANSFORMS_MAP = new Map(entries$2(PROPERTY_TRANSFORMS));
54
91
 
55
92
  function transformStyle(key, value) {
56
93
  const transform = TRANSFORMS_MAP.get(key);
@@ -58,9 +95,13 @@ function transformStyle(key, value) {
58
95
  }
59
96
 
60
97
  function styleFromAttributes(tag) {
61
- return entries(tag).filter(([key]) => STYLE_WHITELIST.has(key)).map(([key, value]) => [key, transformStyle(key, value)]).reduce((result, [key, value]) => ({ ...result,
62
- [key]: value
63
- }), {});
98
+ const result = {};
99
+
100
+ for (const key of Object.keys(tag)) {
101
+ if (STYLE_WHITELIST[key]) result[key] = transformStyle(key, tag[key]);
102
+ }
103
+
104
+ return result;
64
105
  }
65
106
 
66
107
  function normalizeRichTextStyles(attributes = {}) {
@@ -121,7 +162,7 @@ class StyledElement extends React.Component {
121
162
  tag,
122
163
  registryResolver
123
164
  } = this.props;
124
- const elementModifierFunctions = resolveElementModifiers((tag === null || tag === void 0 ? void 0 : tag.appliedElementModifiers) || [], registryResolver);
165
+ const elementModifierFunctions = resolveElementModifiers(tag?.appliedElementModifiers || [], registryResolver);
125
166
  runModifiers(domNode, elementModifierFunctions);
126
167
  }
127
168
  }
@@ -364,6 +405,13 @@ function StudioErrorWrapper(error, message) {
364
405
 
365
406
  return error.clone(wrappedMessage);
366
407
  }
408
+ class StudioError extends BaseStudioError {
409
+ constructor(dynamicProperty, message) {
410
+ super(message);
411
+ this.setSourceDynamicProperty(dynamicProperty);
412
+ }
413
+
414
+ }
367
415
 
368
416
  function getStateTuple(prop, resolver) {
369
417
  if (!prop) {
@@ -427,6 +475,7 @@ class TagComponent extends React.Component {
427
475
  getPropertyWithFallback(prop, fallback) {
428
476
  const {
429
477
  tag,
478
+ canvas,
430
479
  propertyResolver
431
480
  } = this.props;
432
481
  const [result, error] = getStateTuple(prop, propertyResolver);
@@ -436,7 +485,7 @@ class TagComponent extends React.Component {
436
485
 
437
486
  if (propertyFallback) {
438
487
  const warning = error ? StudioErrorWrapper(error, 'Fallback Warning') : new BaseStudioError('Fallback Warning');
439
- const consoleMessage = warning.setErrorType('FallbackWarning').setTag(tag).setSourceDynamicProperty(prop).setEntryDynamicProperty(prop);
488
+ const consoleMessage = warning.setErrorType('FallbackWarning').setTag(tag).setCanvas(canvas).setSourceType('tag').setSourceDynamicProperty(prop).setEntryDynamicProperty(prop);
440
489
  console.warn(consoleMessage);
441
490
  return propertyFallback;
442
491
  }
@@ -444,10 +493,10 @@ class TagComponent extends React.Component {
444
493
  if (passedFallback) return fallback;
445
494
 
446
495
  if (error) {
447
- throw StudioErrorWrapper(error).setTag(tag);
496
+ throw StudioErrorWrapper(error).setTag(tag).setCanvas(canvas).setSourceType('tag');
448
497
  }
449
498
 
450
- throw new BaseStudioError('Missing Data').setErrorType('MissingData').setTag(tag).setSourceDynamicProperty(prop).setEntryDynamicProperty(prop);
499
+ throw new BaseStudioError('Missing Data').setErrorType('MissingData').setTag(tag).setCanvas(canvas).setSourceType('tag').setSourceDynamicProperty(prop).setEntryDynamicProperty(prop);
451
500
  }
452
501
 
453
502
  constructor(props) {
@@ -495,7 +544,8 @@ class Tags extends React.Component {
495
544
  registryResolver,
496
545
  propertyResolver,
497
546
  onPendingPromise,
498
- tags
547
+ tags,
548
+ canvas
499
549
  } = this.props;
500
550
  return tags.map((tag, index) => {
501
551
  const {
@@ -507,11 +557,13 @@ class Tags extends React.Component {
507
557
  registryResolver: registryResolver
508
558
  }, subtags ? /*#__PURE__*/React.createElement(Tags, {
509
559
  tags: subtags,
560
+ canvas: canvas,
510
561
  registryResolver: registryResolver,
511
562
  propertyResolver: propertyResolver,
512
563
  onPendingPromise: onPendingPromise
513
564
  }) : /*#__PURE__*/React.createElement(TagComponent, {
514
565
  tag: tag,
566
+ canvas: canvas,
515
567
  registryResolver: registryResolver,
516
568
  propertyResolver: propertyResolver,
517
569
  onPendingPromise: onPendingPromise
@@ -530,7 +582,7 @@ class SizeContainer extends React.Component {
530
582
  canvas,
531
583
  registryResolver
532
584
  } = this.props;
533
- const elementModifierFunctions = resolveElementModifiers((canvas === null || canvas === void 0 ? void 0 : canvas.appliedElementModifiers) || [], registryResolver);
585
+ const elementModifierFunctions = resolveElementModifiers(canvas?.appliedElementModifiers || [], registryResolver);
534
586
  runModifiers(domNode, elementModifierFunctions);
535
587
  }
536
588
  }
@@ -646,7 +698,6 @@ function contextAccessor(context, cb) {
646
698
  let _Symbol$iterator;
647
699
 
648
700
  const ERROR_KEY = Symbol('error');
649
- const TEMP_STORAGE = Symbol('temporary-key');
650
701
 
651
702
  function isError(t) {
652
703
  return t && typeof t === 'object' && ERROR_KEY in t;
@@ -666,6 +717,8 @@ class CacheMap {
666
717
  _defineProperty(this, "acceptingKeys", true);
667
718
 
668
719
  _defineProperty(this, "tempContext", void 0);
720
+
721
+ _defineProperty(this, "tempStorageKey", context => JSON.stringify(context));
669
722
  }
670
723
 
671
724
  get(context) {
@@ -703,11 +756,12 @@ class CacheMap {
703
756
 
704
757
  freezeContext() {
705
758
  this.acceptingKeys = false;
759
+ const temp = this.tempStorageKey(this.tempContext);
706
760
 
707
- if (this.cache.has(TEMP_STORAGE)) {
708
- const value = this.cache.get(TEMP_STORAGE);
761
+ if (this.cache.has(temp)) {
762
+ const value = this.cache.get(temp);
709
763
  const context = this.tempContext;
710
- this.cache.delete(TEMP_STORAGE);
764
+ this.cache.delete(temp);
711
765
  this.cache.set(this.cacheKeyFor(context), value);
712
766
  }
713
767
  }
@@ -725,7 +779,7 @@ class CacheMap {
725
779
  cacheKeyFor(context) {
726
780
  if (this.acceptingKeys) {
727
781
  this.tempContext = context;
728
- return TEMP_STORAGE;
782
+ return this.tempStorageKey(context);
729
783
  }
730
784
 
731
785
  if (this.keyCache.has(context)) {
@@ -784,6 +838,7 @@ class ComputeThrottler {
784
838
  result = compute();
785
839
  } catch (e) {
786
840
  this.isPending = false;
841
+ this.tryNextInQueue();
787
842
  throw e;
788
843
  }
789
844
 
@@ -874,6 +929,31 @@ function parseGetPropertyArgs(args) {
874
929
  return [false, '', arg3];
875
930
  }
876
931
  }
932
+ function parseGetPropertyProxyArgs(args) {
933
+ let callback = null;
934
+
935
+ if (typeof args[args.length - 1] === 'function') {
936
+ callback = args.pop();
937
+ }
938
+
939
+ if (!callback) {
940
+ callback = (_, error) => {
941
+ if (error) {
942
+ throw error;
943
+ }
944
+ };
945
+ }
946
+
947
+ const [arg1, arg2, arg3] = args;
948
+
949
+ if (typeof arg2 === 'string' && typeof arg3 !== 'function') {
950
+ return [arg1, arg2, arg3, callback];
951
+ } else if (typeof arg1 === 'string' && typeof arg2 !== 'function' && typeof arg2 !== 'string') {
952
+ return [false, arg1, arg2, callback];
953
+ } else if (typeof arg3 !== 'function') {
954
+ return [false, '', arg3, callback];
955
+ }
956
+ }
877
957
  function parseSetPropertyArgs(args) {
878
958
  if (args.length === 2) {
879
959
  const [arg1, arg2] = args;
@@ -883,18 +963,42 @@ function parseSetPropertyArgs(args) {
883
963
  }
884
964
  }
885
965
 
886
- let DebugType;
966
+ /** This implementation is adapted from uuidjs rather than requiring the full library
967
+ * see: https://github.com/movableink/studio-framework/pull/762#discussion_r555175040
968
+ */
969
+ const byteToHex = [];
970
+
971
+ for (let i = 0; i < 256; ++i) {
972
+ byteToHex.push((i + 0x100).toString(16).substr(1));
973
+ }
974
+
975
+ function generateV4Uuid() {
976
+ // generate cryptographically strong random numbers
977
+ // see: github.com/uuidjs/uuid/blob/master/src/rng-browser.js
978
+ const unsigned8BitArray = new Uint8Array(16);
979
+ const getRandomValues = crypto.getRandomValues.bind(crypto);
980
+ const randomValues = getRandomValues(unsigned8BitArray); // per 4.4, set bits for version and `clock_seq_hi_and_reserved`
981
+ // see: github.com/uuidjs/uuid/blob/master/src/v4.js
887
982
 
888
- (function (DebugType) {
889
- DebugType["cacheRead"] = "cache-read";
890
- DebugType["propertyRequest"] = "property-request";
891
- DebugType["resolve"] = "resolve";
892
- DebugType["await"] = "await";
893
- DebugType["error"] = "error";
894
- DebugType["override"] = "override";
895
- })(DebugType || (DebugType = {}));
983
+ randomValues[6] = randomValues[6] & 0x0f | 0x40;
984
+ randomValues[8] = randomValues[8] & 0x3f | 0x80; // strigify v4 format
985
+ // see: github.com/uuidjs/uuid/blob/master/src/stringify.js
896
986
 
897
- class InertDebugEvent {
987
+ return (byteToHex[randomValues[0]] + byteToHex[randomValues[1]] + byteToHex[randomValues[2]] + byteToHex[randomValues[3]] + '-' + byteToHex[randomValues[4]] + byteToHex[randomValues[5]] + '-' + byteToHex[randomValues[6]] + byteToHex[randomValues[7]] + '-' + byteToHex[randomValues[8]] + byteToHex[randomValues[9]] + '-' + byteToHex[randomValues[10]] + byteToHex[randomValues[11]] + byteToHex[randomValues[12]] + byteToHex[randomValues[13]] + byteToHex[randomValues[14]] + byteToHex[randomValues[15]]).toLowerCase();
988
+ }
989
+
990
+ let EventType;
991
+
992
+ (function (EventType) {
993
+ EventType["cacheRead"] = "cache-read";
994
+ EventType["propertyRequest"] = "property-request";
995
+ EventType["resolve"] = "resolve";
996
+ EventType["await"] = "await";
997
+ EventType["error"] = "error";
998
+ EventType["override"] = "override";
999
+ })(EventType || (EventType = {}));
1000
+
1001
+ class InertEvent {
898
1002
  makeChildEvent() {
899
1003
  return this;
900
1004
  } // eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -907,8 +1011,12 @@ class InertDebugEvent {
907
1011
 
908
1012
  }
909
1013
 
910
- class ActiveDebugEvent {
1014
+ class ActiveEvent {
911
1015
  constructor(type, dynamicProperty) {
1016
+ _defineProperty(this, "id", void 0);
1017
+
1018
+ _defineProperty(this, "createdAt", void 0);
1019
+
912
1020
  _defineProperty(this, "type", void 0);
913
1021
 
914
1022
  _defineProperty(this, "dynamicProperty", void 0);
@@ -921,10 +1029,12 @@ class ActiveDebugEvent {
921
1029
 
922
1030
  this.type = type;
923
1031
  this.dynamicProperty = dynamicProperty;
1032
+ this.id = generateV4Uuid();
1033
+ this.createdAt = Date.now();
924
1034
  }
925
1035
 
926
1036
  makeChildEvent(type, prop) {
927
- const event = new ActiveDebugEvent(type, prop || this.dynamicProperty);
1037
+ const event = new ActiveEvent(type, prop || this.dynamicProperty);
928
1038
  this.childEvents.push(event);
929
1039
  return event;
930
1040
  }
@@ -939,10 +1049,10 @@ class ActiveDebugEvent {
939
1049
 
940
1050
  }
941
1051
  function createEvent(type, prop) {
942
- return new ActiveDebugEvent(type, prop);
1052
+ return new ActiveEvent(type, prop);
943
1053
  }
944
1054
  function createInertEvent() {
945
- return new InertDebugEvent();
1055
+ return new InertEvent();
946
1056
  }
947
1057
 
948
1058
  function deprecateGetContext(key) {
@@ -1004,6 +1114,10 @@ class Property {
1004
1114
  return this.overrideFn;
1005
1115
  }
1006
1116
 
1117
+ get dependencies() {
1118
+ return this.dependentProperties;
1119
+ }
1120
+
1007
1121
  getCacheFor(context) {
1008
1122
  if (this.memoizeCache) {
1009
1123
  return this.memoizeCache.get(context);
@@ -1072,8 +1186,9 @@ class Property {
1072
1186
 
1073
1187
  getPropertyProxy(context, requestEvent) {
1074
1188
  return (...args) => {
1075
- const [grouping, key, extraContext = {}] = parseGetPropertyArgs(args);
1076
- const property = this.computed.getPropertyInstance(grouping || this.grouping, key);
1189
+ const [grouping, key, extraContext = {}, callback] = parseGetPropertyProxyArgs(args);
1190
+ const propertyGroupKey = grouping || this.grouping;
1191
+ const property = this.computed.getPropertyInstance(propertyGroupKey, key);
1077
1192
 
1078
1193
  if (!property) {
1079
1194
  return null;
@@ -1084,21 +1199,89 @@ class Property {
1084
1199
  ...extraContext
1085
1200
  };
1086
1201
  const prop = {
1087
- propertyGroupKey: grouping,
1202
+ propertyGroupKey: propertyGroupKey,
1088
1203
  propertyPath: key,
1089
1204
  context: fullContext
1090
1205
  };
1091
- const childEvent = requestEvent.makeChildEvent(DebugType.propertyRequest, prop);
1092
- const result = property.compute(fullContext, childEvent);
1206
+ const childEvent = requestEvent.makeChildEvent(EventType.propertyRequest, prop);
1207
+ let result;
1208
+ let error;
1209
+ if (window.MICapture?.isPreview) this.throwIfDependencyCycleDetected(property);
1210
+
1211
+ try {
1212
+ result = property.compute(fullContext, childEvent);
1213
+ } catch (e) {
1214
+ error = e;
1215
+ }
1093
1216
 
1094
1217
  if (isPromise(result)) {
1095
1218
  throw new PromiseException(result);
1096
1219
  }
1097
1220
 
1098
- return result;
1221
+ try {
1222
+ if (error) {
1223
+ callback(null, error);
1224
+ return;
1225
+ } else {
1226
+ callback(result, null);
1227
+ return result;
1228
+ }
1229
+ } catch (e) {
1230
+ const wrappedError = StudioErrorWrapper(e).setSourceDynamicProperty(prop);
1231
+ throw wrappedError;
1232
+ }
1099
1233
  };
1100
1234
  }
1101
1235
 
1236
+ throwIfDependencyCycleDetected(property) {
1237
+ performance.now();
1238
+ const hasDependentProperties = property.dependentProperties.size;
1239
+
1240
+ if (hasDependentProperties) {
1241
+ const dependencyCycleProperties = this.getDependencyCycle(property.dependentProperties);
1242
+ const isDependencyCycleDetected = dependencyCycleProperties.length;
1243
+
1244
+ if (isDependencyCycleDetected) {
1245
+ throw new Error(`Dependency cycle detected: ${dependencyCycleProperties.map(prop => {
1246
+ return prop.grouping ? prop.grouping + '::' + prop.propertyKey : prop.propertyKey;
1247
+ }).join(' > ')}`);
1248
+ }
1249
+ }
1250
+ }
1251
+
1252
+ getDependencyCycle(dependencies) {
1253
+ const propsToInspect = [...dependencies.values()];
1254
+ const propsInspected = new Set();
1255
+ const propsCompleted = new Set();
1256
+
1257
+ while (propsToInspect.length) {
1258
+ const currentProperty = propsToInspect.pop();
1259
+ const detectionResult = this.detectCycle(currentProperty, propsInspected, propsCompleted);
1260
+ if (detectionResult.length) return [currentProperty, ...detectionResult];
1261
+ }
1262
+
1263
+ return [];
1264
+ }
1265
+
1266
+ detectCycle(currentProperty, propsInspected, propsCompleted) {
1267
+ if (!propsCompleted.has(currentProperty)) {
1268
+ propsInspected.add(currentProperty);
1269
+ propsCompleted.add(currentProperty);
1270
+
1271
+ for (const prop of currentProperty.dependencies) {
1272
+ if (!propsCompleted.has(prop)) {
1273
+ const detectionResult = this.detectCycle(prop, propsInspected, propsCompleted);
1274
+ if (detectionResult.length) return [prop, ...detectionResult];
1275
+ }
1276
+
1277
+ if (propsInspected.has(prop)) return [prop];
1278
+ }
1279
+ }
1280
+
1281
+ propsInspected.delete(currentProperty);
1282
+ return [];
1283
+ }
1284
+
1102
1285
  generateComputeArgs(passedContext = {}, requestEvent) {
1103
1286
  const context = contextAccessor(passedContext, key => this.memoizeCache.addContextKey(key));
1104
1287
  const getProperty = this.getPropertyProxy(passedContext, requestEvent);
@@ -1128,7 +1311,7 @@ class Property {
1128
1311
  const overwrittenResult = overrideFn(result, context);
1129
1312
 
1130
1313
  if (overrideFn !== DEFAULT_OVERRIDE) {
1131
- const overrideEvent = event.makeChildEvent(DebugType.override);
1314
+ const overrideEvent = event.makeChildEvent(EventType.override);
1132
1315
  overrideEvent.setValue(result);
1133
1316
  }
1134
1317
 
@@ -1147,7 +1330,7 @@ class Property {
1147
1330
  };
1148
1331
  const wrappedError = StudioErrorWrapper(error).setSourceDynamicProperty(dynamicProperty).setEntryDynamicProperty(dynamicProperty);
1149
1332
  this.memoizeCache.setError(context, wrappedError);
1150
- event.makeChildEvent(DebugType.error);
1333
+ event.makeChildEvent(EventType.error);
1151
1334
  event.setError(wrappedError);
1152
1335
  throw wrappedError;
1153
1336
  }
@@ -1155,7 +1338,7 @@ class Property {
1155
1338
  async resolvePromiseResult(promise, context, event) {
1156
1339
  try {
1157
1340
  const result = await promise;
1158
- event.makeChildEvent(DebugType.resolve);
1341
+ event.makeChildEvent(EventType.resolve);
1159
1342
  const overwrittenResult = this.overrideResult(result, context, event);
1160
1343
  this.memoizeCache.set(context, overwrittenResult);
1161
1344
  event.setValue(overwrittenResult);
@@ -1167,7 +1350,7 @@ class Property {
1167
1350
 
1168
1351
  async yieldPromiseException(exception, context, event) {
1169
1352
  try {
1170
- event.makeChildEvent(DebugType.await);
1353
+ event.makeChildEvent(EventType.await);
1171
1354
  await exception.promise;
1172
1355
  return this.trySyncCompute(context, event);
1173
1356
  } catch (error) {
@@ -1181,10 +1364,10 @@ class Property {
1181
1364
  const result = this.computeFn(computeArgs);
1182
1365
 
1183
1366
  if (isPromise(result)) {
1184
- event.makeChildEvent(DebugType.await);
1367
+ event.makeChildEvent(EventType.await);
1185
1368
  return this.resolvePromiseResult(result, context, event);
1186
1369
  } else {
1187
- event.makeChildEvent(DebugType.resolve);
1370
+ event.makeChildEvent(EventType.resolve);
1188
1371
  const overwrittenResult = this.overrideResult(result, context, event);
1189
1372
  this.memoizeCache.set(context, overwrittenResult);
1190
1373
  event.setValue(overwrittenResult);
@@ -1198,7 +1381,7 @@ class Property {
1198
1381
  cachedCompute(context, event) {
1199
1382
  // If memoize cache is not set up, compute compute and set up the cache.
1200
1383
  if (this.memoizeCache.has(context)) {
1201
- event.makeChildEvent(DebugType.cacheRead);
1384
+ event.makeChildEvent(EventType.cacheRead);
1202
1385
  return this.memoizeCache.get(context);
1203
1386
  } // Immediately cache the response (it wil be re-written when finalized if it's a promise).
1204
1387
 
@@ -1291,7 +1474,7 @@ class GroupedRegistry {
1291
1474
  }
1292
1475
 
1293
1476
  const {
1294
- entries: entries$2
1477
+ entries
1295
1478
  } = Object;
1296
1479
 
1297
1480
  function isComputeFn(fn) {
@@ -1306,13 +1489,13 @@ class AsyncComputed {
1306
1489
 
1307
1490
  _defineProperty(this, "globProperties", new GroupedRegistry());
1308
1491
 
1309
- _defineProperty(this, "debugEnabled", false);
1492
+ _defineProperty(this, "eventsEnabled", false);
1310
1493
 
1311
- _defineProperty(this, "propertyDebugEventsTree", []);
1494
+ _defineProperty(this, "eventsTree", []);
1312
1495
  }
1313
1496
 
1314
- enableDebugMode() {
1315
- this.debugEnabled = true;
1497
+ enableEvents() {
1498
+ this.eventsEnabled = true;
1316
1499
  }
1317
1500
 
1318
1501
  setProperty(...args) {
@@ -1331,7 +1514,7 @@ class AsyncComputed {
1331
1514
  }
1332
1515
 
1333
1516
  setProperties(object, prefix) {
1334
- entries$2(object).forEach(([path, value]) => {
1517
+ entries(object).forEach(([path, value]) => {
1335
1518
  const fullPath = prefix ? `${prefix}.${path}` : path;
1336
1519
  this.setProperty(fullPath, value);
1337
1520
  });
@@ -1347,8 +1530,8 @@ class AsyncComputed {
1347
1530
  return result;
1348
1531
  }
1349
1532
 
1350
- get propertyDebugEvents() {
1351
- return this.propertyDebugEventsTree;
1533
+ get propertyEvents() {
1534
+ return this.eventsTree;
1352
1535
  }
1353
1536
 
1354
1537
  getPropertyInstance(grouping, path) {
@@ -1419,14 +1602,14 @@ class AsyncComputed {
1419
1602
 
1420
1603
  let requestEvent;
1421
1604
 
1422
- if (this.debugEnabled) {
1423
- requestEvent = createEvent(DebugType.propertyRequest, {
1605
+ if (this.eventsEnabled) {
1606
+ requestEvent = createEvent(EventType.propertyRequest, {
1424
1607
  propertyGroupKey: property.grouping,
1425
1608
  // make sure we're using the property's actual grouping
1426
1609
  propertyPath: path,
1427
1610
  context: context
1428
1611
  });
1429
- this.propertyDebugEventsTree.push(requestEvent);
1612
+ this.eventsTree.push(requestEvent);
1430
1613
  } else {
1431
1614
  requestEvent = createInertEvent();
1432
1615
  }
@@ -1530,7 +1713,7 @@ function trimTextOverflow(element) {
1530
1713
  const parentElement = element.parentElement;
1531
1714
  const parentBox = parentElement.getBoundingClientRect(); // It fits already; no need to resize.
1532
1715
 
1533
- if (!overflowsParent(element, parentBox)) {
1716
+ if (!overflowsParent$1(element, parentBox)) {
1534
1717
  return;
1535
1718
  }
1536
1719
 
@@ -1555,7 +1738,7 @@ function truncateText(element, parentBox) {
1555
1738
  element.parentElement.nextElementSibling.remove();
1556
1739
  }
1557
1740
 
1558
- while (endPos > 0 && overflowsParent(element, parentBox)) {
1741
+ while (endPos > 0 && overflowsParent$1(element, parentBox)) {
1559
1742
  endPos = currentText.lastIndexOf(' ');
1560
1743
  currentText = currentText.substr(0, endPos);
1561
1744
 
@@ -1586,7 +1769,7 @@ function findOverlappingElement(element, parentBox) {
1586
1769
  const children = Array.from(element.children);
1587
1770
 
1588
1771
  for (const child of children) {
1589
- if (overflowsParent(child, parentBox)) {
1772
+ if (overflowsParent$1(child, parentBox)) {
1590
1773
  return findOverlappingElement(child, parentBox);
1591
1774
  }
1592
1775
  } // if no child is found to overlap, return self.
@@ -1595,14 +1778,14 @@ function findOverlappingElement(element, parentBox) {
1595
1778
  return element;
1596
1779
  }
1597
1780
 
1598
- function overflowsParent(element, parentBox) {
1781
+ function overflowsParent$1(element, parentBox) {
1599
1782
  const selfBox = element.getBoundingClientRect();
1600
1783
  const isOutside = !(selfBox.left >= parentBox.left && selfBox.right <= parentBox.right && selfBox.bottom <= parentBox.bottom && element.scrollHeight <= parentBox.height && element.scrollWidth <= parentBox.width);
1601
1784
  return isOutside;
1602
1785
  }
1603
1786
 
1604
1787
  const {
1605
- min
1788
+ min: min$1
1606
1789
  } = Math;
1607
1790
  function convertToEms(insertProperties, baseFontSize) {
1608
1791
  return insertProperties.map(prop => {
@@ -1623,16 +1806,16 @@ function shrinkToFit(element, richTextStructure, baseFontSize, minFontSize) {
1623
1806
  } = element;
1624
1807
  const parentBox = parentElement.getBoundingClientRect(); // It fits already; no need to resize.
1625
1808
 
1626
- if (!overflowsParent$1(parentBox, element)) {
1809
+ if (!overflowsParent(parentBox, element)) {
1627
1810
  return true;
1628
1811
  }
1629
1812
 
1630
1813
  const smallestFontRatio = richTextStructure.reduce((smallest, op) => {
1631
- smallest = min(smallest, getFontRatio(op));
1814
+ smallest = min$1(smallest, getFontRatio(op));
1632
1815
 
1633
1816
  if (op.spans) {
1634
1817
  for (const span of op.spans) {
1635
- smallest = min(smallest, getFontRatio(span));
1818
+ smallest = min$1(smallest, getFontRatio(span));
1636
1819
  }
1637
1820
  }
1638
1821
 
@@ -1658,7 +1841,7 @@ function resizeToFit(currentFontSize, selfElement, parentBox, minimumFontSize, s
1658
1841
 
1659
1842
  selfElement.style.fontSize = `${currentFontSize}px`; // Re-run if still outside of parent container
1660
1843
 
1661
- if (overflowsParent$1(parentBox, selfElement)) {
1844
+ if (overflowsParent(parentBox, selfElement)) {
1662
1845
  // truncate if min font size reached
1663
1846
  const nextFontSize = currentFontSize - 1;
1664
1847
  return resizeToFit(nextFontSize, selfElement, parentBox, minimumFontSize, smallestRatio);
@@ -1667,7 +1850,7 @@ function resizeToFit(currentFontSize, selfElement, parentBox, minimumFontSize, s
1667
1850
  return true;
1668
1851
  }
1669
1852
 
1670
- function overflowsParent$1(parentBox, selfElement) {
1853
+ function overflowsParent(parentBox, selfElement) {
1671
1854
  const range = document.createRange();
1672
1855
  range.selectNode(selfElement);
1673
1856
  const selfBox = range.getBoundingClientRect();
@@ -1707,7 +1890,7 @@ const DEFAULT_P_STYLES = {
1707
1890
  padding: 0
1708
1891
  };
1709
1892
  const {
1710
- min: min$1
1893
+ min
1711
1894
  } = Math;
1712
1895
  function makeRenderStructure(ops, fitToOneLine) {
1713
1896
  const paragraphs = [];
@@ -1794,7 +1977,7 @@ function getMinFontSize(ops, defaultSize) {
1794
1977
  const fontSize = op.attributes && op.attributes.fontSize;
1795
1978
 
1796
1979
  if (fontSize) {
1797
- return min$1(curMin, parseFloat(fontSize.toString()));
1980
+ return min(curMin, parseFloat(fontSize.toString()));
1798
1981
  }
1799
1982
 
1800
1983
  return curMin;
@@ -1959,7 +2142,12 @@ function ImageTag({
1959
2142
  throw new Error('Could not render image as no URL was provided');
1960
2143
  }
1961
2144
 
1962
- CD.waitForAsset(imageUrl);
2145
+ const isDataURL = imageUrl.match(/^data:/);
2146
+
2147
+ if (!isDataURL) {
2148
+ CD.waitForAsset(imageUrl);
2149
+ }
2150
+
1963
2151
  const styles = {
1964
2152
  height: '100%',
1965
2153
  width: '100%',
@@ -2001,13 +2189,22 @@ const HIDDEN_IMAGE_STYLE = {
2001
2189
  position: 'absolute',
2002
2190
  opacity: 0
2003
2191
  };
2004
- function stylesForImage(imageUrl, cropStyle) {
2192
+ function stylesForImage(imageUrl, cropStyle, imageAnchor = {
2193
+ horizontalPosition: 'left',
2194
+ verticalPosition: 'top'
2195
+ }) {
2005
2196
  const cropStyles = CROPPING_OPTIONS[cropStyle];
2006
- return {
2197
+ const {
2198
+ horizontalPosition,
2199
+ verticalPosition
2200
+ } = imageAnchor;
2201
+ const imageStyles = {
2007
2202
  background: `url("${imageUrl}")`,
2008
2203
  ...BASE_STYLES,
2009
2204
  ...cropStyles
2010
2205
  };
2206
+ imageStyles.backgroundPosition = `${horizontalPosition} ${verticalPosition}`;
2207
+ return imageStyles;
2011
2208
  }
2012
2209
 
2013
2210
  class DynamicImageTag extends StudioTool {
@@ -2024,15 +2221,21 @@ class DynamicImageTag extends StudioTool {
2024
2221
  tag: {
2025
2222
  dynamicProperty,
2026
2223
  isCropped,
2027
- dynamicAltText
2224
+ dynamicAltText,
2225
+ imageAnchor
2028
2226
  },
2029
2227
  getPropertyWithFallback
2030
2228
  } = this.props;
2031
2229
  const src = getPropertyWithFallback(dynamicProperty);
2032
2230
  const altText = getPropertyWithFallback(dynamicAltText, '');
2033
- CD.waitForAsset(src);
2231
+ const isDataURL = src.match(/^data:/);
2232
+
2233
+ if (!isDataURL) {
2234
+ CD.waitForAsset(src);
2235
+ }
2236
+
2034
2237
  const styleType = isCropped ? 'cropped' : 'contained';
2035
- const styles = stylesForImage(src, styleType);
2238
+ const styles = stylesForImage(src, styleType, imageAnchor);
2036
2239
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
2037
2240
  className: "studio-dynamic-image",
2038
2241
  role: "image",
@@ -2140,6 +2343,7 @@ class App extends React.Component {
2140
2343
  canvas: canvas
2141
2344
  }, /*#__PURE__*/React.createElement(Tags, {
2142
2345
  tags: tags || [],
2346
+ canvas: canvas,
2143
2347
  registryResolver: registryResolver,
2144
2348
  propertyResolver: propertyResolver,
2145
2349
  onPendingPromise: this.onPendingPromise
@@ -2304,12 +2508,15 @@ function makeCustomTool(toolData) {
2304
2508
  } = this.props;
2305
2509
  const {
2306
2510
  code,
2307
- propertyInputs = []
2511
+ propertyInputs = [],
2512
+ context_options: contextOptionsInputs = []
2308
2513
  } = toolData;
2309
2514
  const propertyNames = propertyInputs.map(input => input.variableName);
2310
- const Tool = new Function(...propertyNames, 'html', 'CD', 'tag', code);
2311
- const values = propertyInputs.map(prop => getPropertyWithFallback(prop));
2312
- return Tool(...values, html, CD, tag);
2515
+ const contextOptionsNames = contextOptionsInputs.map(input => input.name);
2516
+ const Tool = new Function(...propertyNames, ...contextOptionsNames, 'html', 'CD', 'tag', code);
2517
+ const propertyValues = propertyInputs.map(prop => getPropertyWithFallback(prop));
2518
+ const contextValues = contextOptionsInputs.map(input => tag.toolProperties[input.name]);
2519
+ return Tool(...propertyValues, ...contextValues, html, CD, tag);
2313
2520
  }
2314
2521
 
2315
2522
  };
@@ -2343,9 +2550,9 @@ function cleanHTML(element) {
2343
2550
  newBody.style.cssText = BASE_STYLE;
2344
2551
  newBody.appendChild(element);
2345
2552
 
2346
- if (analyticsLength > 250) {
2553
+ if (analyticsLength > 500) {
2347
2554
  analytics.setAttribute('data-mi-data', '{}');
2348
- console.log('extraData trying to be set exceeds 250 characters, setting extraData to be empty to avoid breaking crops');
2555
+ console.log('extraData trying to be set exceeds 500 characters, setting extraData to be empty to avoid breaking crops');
2349
2556
  }
2350
2557
 
2351
2558
  if (analytics) {
@@ -2382,6 +2589,85 @@ function addBrowserContent(baseElement) {
2382
2589
  rootNode.body.appendChild(script);
2383
2590
  }
2384
2591
 
2592
+ const COUNT_OF_SCRIPT_TAGS_COMPILED_BY_STUDIO = 5;
2593
+
2594
+ const stringMatch = (original, comparable, ignoreRegExp) => {
2595
+ return original.replace(ignoreRegExp, '') === comparable;
2596
+ };
2597
+
2598
+ const studioOverwritableJs = 'var app = new studio[a-zA-Z0-9]*.A\\(\\);';
2599
+ const jsIgnoreRE = new RegExp(`\\s|${studioOverwritableJs}`, 'g');
2600
+ const jsCompareString = `(function(){app.render(document.getElementById('react-root')).then(function(){window.APP_SUCCESSFULLY_RENDERED=true;});})();`;
2601
+ const isPristinePicJsTag = scriptTag => {
2602
+ const script = scriptTag.innerHTML;
2603
+ return stringMatch(script, jsCompareString, jsIgnoreRE);
2604
+ };
2605
+ const isDocumentEligibleForStaticHandling = rootNode => {
2606
+ const document = getDocumentNode(rootNode);
2607
+ const scriptTags = document.getElementsByTagName('script');
2608
+ const hasTagContainingPristinePicJs = Array.from(scriptTags).some(isPristinePicJsTag);
2609
+
2610
+ if (!hasTagContainingPristinePicJs) {
2611
+ console.log('static status is false - user-altered js detected');
2612
+ return false;
2613
+ }
2614
+
2615
+ if (scriptTags.length > COUNT_OF_SCRIPT_TAGS_COMPILED_BY_STUDIO) {
2616
+ console.log('static status is false - user-added script tags detected');
2617
+ return false;
2618
+ }
2619
+
2620
+ return true;
2621
+ };
2622
+
2623
+ const basicTypes = new Set(['group', 'image', 'rectangle', 'richText', 'staticPic', 'text']);
2624
+
2625
+ const isTagStatic = tag => {
2626
+ const {
2627
+ appliedElementModifiers,
2628
+ conditionalDynamicProperty,
2629
+ dynamicAltText,
2630
+ dynamicProperty,
2631
+ richText,
2632
+ subtags,
2633
+ type
2634
+ } = tag;
2635
+ if (subtags?.length) return subtags.some(isTagStatic);
2636
+ const isCustomTool = type.startsWith('customTool.');
2637
+ const hasDynamicRichText = richText?.some(({
2638
+ insert
2639
+ }) => typeof insert === 'object' && insert.dynamicProperty);
2640
+ if (appliedElementModifiers || !basicTypes.has(type) || conditionalDynamicProperty || dynamicAltText || dynamicProperty || hasDynamicRichText || isCustomTool) return false;
2641
+ return true;
2642
+ };
2643
+
2644
+ const areAttributesStatic = attributes => {
2645
+ const {
2646
+ canvases
2647
+ } = attributes;
2648
+
2649
+ for (const {
2650
+ appliedElementModifiers,
2651
+ tags = [],
2652
+ clickthroughDynamicProperty,
2653
+ conditionalDynamicProperty
2654
+ } of canvases) {
2655
+ if (appliedElementModifiers || clickthroughDynamicProperty || conditionalDynamicProperty) {
2656
+ console.log('static status is false - dynamic properties on canvas detected');
2657
+ return false;
2658
+ }
2659
+
2660
+ for (const tag of tags) {
2661
+ if (!isTagStatic(tag)) {
2662
+ console.log('static status is false - dynamic properties on tag detected');
2663
+ return false;
2664
+ }
2665
+ }
2666
+ }
2667
+
2668
+ return true;
2669
+ };
2670
+
2385
2671
  class StudioFramework {
2386
2672
  constructor(opts = setupAppDefaults()) {
2387
2673
  _defineProperty(this, "currentGrouping", false);
@@ -2406,22 +2692,40 @@ class StudioFramework {
2406
2692
 
2407
2693
  _defineProperty(this, "debug", {
2408
2694
  CD,
2695
+ enableDebugMode: () => {
2696
+ this.asyncComputed.enableEvents();
2697
+ },
2409
2698
  getAllProperties: () => this.asyncComputed.dumpState(),
2410
- getPropertyEvents: () => this.asyncComputed.propertyDebugEvents,
2699
+ getPropertyEvents: () => {
2700
+ console.warn('`app.debug.getPropertyEvents()` is deprecated. Please use `app.meta.enableEvents()` and `app.meta.getEvents([consoleLog])`.');
2701
+ return this.asyncComputed.propertyEvents;
2702
+ },
2411
2703
  logProperties: () => {
2412
2704
  const state = this.asyncComputed.dumpState();
2413
- console.warn('`app.debug.logProperties()` is deprecated. Please use `app.debug.logPropertyTree()`');
2705
+ console.warn('`app.debug.logProperties()` is deprecated. Please use `app.meta.enableEvents` and `app.meta.getEvents([consoleLog])`.');
2414
2706
  console.log(JSON.stringify(state, null, 2));
2415
2707
  },
2416
- enableDebugMode: () => {
2417
- this.asyncComputed.enableDebugMode();
2418
- },
2419
2708
  logPropertyTree: () => {
2420
- const events = this.asyncComputed.propertyDebugEvents;
2709
+ const events = this.asyncComputed.propertyEvents;
2421
2710
  console.log(JSON.stringify(events, null, 2));
2422
2711
  }
2423
2712
  });
2424
2713
 
2714
+ _defineProperty(this, "meta", {
2715
+ eventsEnabled: false,
2716
+ enableEvents: () => {
2717
+ // tbd: options for pruning which events are captured
2718
+ this.meta.eventsEnabled = true;
2719
+ this.asyncComputed.enableEvents();
2720
+ },
2721
+ getEvents: consoleLog => {
2722
+ if (!this.meta.eventsEnabled) console.warn('`app.metadata.getEvents()` was called, however `app.metadata.enableEvents([...options])` was not set first. No events will be returned.');
2723
+ const events = this.asyncComputed.propertyEvents;
2724
+ if (consoleLog) console.log(JSON.stringify(events, null, 2));
2725
+ return events;
2726
+ }
2727
+ });
2728
+
2425
2729
  const {
2426
2730
  canvases = [],
2427
2731
  customProps = [],
@@ -2434,6 +2738,12 @@ class StudioFramework {
2434
2738
  namespacedOptions = [],
2435
2739
  queryParams = {}
2436
2740
  } = opts;
2741
+
2742
+ if (window.MICapture?.isPreview) {
2743
+ console.log('static status is true - static check has started');
2744
+ window.RENDERED_STATICALLY = true;
2745
+ }
2746
+
2437
2747
  this.options = options;
2438
2748
  this.namespacedOptions = namespacedOptions;
2439
2749
  this.customProps = customProps;
@@ -2451,7 +2761,25 @@ class StudioFramework {
2451
2761
  return queryParams;
2452
2762
  });
2453
2763
  animation(this);
2454
- this.setup();
2764
+
2765
+ if (this.shouldPerformStaticCheck) {
2766
+ const proxy = new Proxy(this, {
2767
+ set(target, key, value) {
2768
+ if (key in target && key !== 'currentGrouping') {
2769
+ window.RENDERED_STATICALLY = false;
2770
+ console.log(`static status is false - overridden StudioFramework class method `, key);
2771
+ }
2772
+
2773
+ return Reflect.set(target, key, value);
2774
+ }
2775
+
2776
+ });
2777
+ this.setup.call(proxy);
2778
+ if (this.shouldPerformStaticCheck) window.RENDERED_STATICALLY = areAttributesStatic(opts);
2779
+ } else {
2780
+ this.setup();
2781
+ }
2782
+
2455
2783
  this.setupOptions();
2456
2784
  this.setupNamespacedOptions();
2457
2785
  this.setupCustomTools();
@@ -2459,16 +2787,20 @@ class StudioFramework {
2459
2787
  this.setupModifiedProps();
2460
2788
  }
2461
2789
 
2790
+ get shouldPerformStaticCheck() {
2791
+ return window.MICapture?.isPreview && window.RENDERED_STATICALLY;
2792
+ }
2793
+
2462
2794
  triggerRerender() {
2463
2795
  if (this.appComponent) {
2464
2796
  this.appComponent.forceUpdate();
2465
2797
  }
2466
2798
  }
2467
2799
 
2468
- async isCurrentCanvas(canvas) {
2800
+ async resolveConditionalDynamicProperty(model) {
2469
2801
  const {
2470
2802
  conditionalDynamicProperty
2471
- } = canvas;
2803
+ } = model;
2472
2804
  if (!conditionalDynamicProperty) return [true, null];
2473
2805
  const {
2474
2806
  propertyGroupKey = '',
@@ -2485,7 +2817,7 @@ class StudioFramework {
2485
2817
  } = this;
2486
2818
 
2487
2819
  for (const canvas of canvases) {
2488
- const [result, error] = await this.isCurrentCanvas(canvas);
2820
+ const [result, error] = await this.resolveConditionalDynamicProperty(canvas);
2489
2821
  if (result) return canvas;
2490
2822
 
2491
2823
  if (error) {
@@ -2555,28 +2887,41 @@ class StudioFramework {
2555
2887
  setup() {} // eslint-disable-next-line
2556
2888
 
2557
2889
 
2558
- setupTags(tags) {
2559
- return tags;
2560
- } // eslint-disable-next-line
2890
+ async getCurrentTags(tags, canvas) {
2891
+ const filteredTags = [];
2561
2892
 
2893
+ for (const tag of tags) {
2894
+ const [result, error] = await this.resolveConditionalDynamicProperty(tag);
2562
2895
 
2563
- async clickthrough(currentCanvas) {
2564
- let {
2565
- clickthrough_dynamic_property
2566
- } = this.options;
2896
+ if (result) {
2897
+ filteredTags.push(tag);
2898
+ }
2567
2899
 
2568
- if (currentCanvas === null || currentCanvas === void 0 ? void 0 : currentCanvas.clickthroughDynamicProperty) {
2569
- clickthrough_dynamic_property = currentCanvas.clickthroughDynamicProperty;
2900
+ if (error) {
2901
+ const wrappedError = StudioErrorWrapper(error, `Skipped ${tag.label || tag.displayName} because conditional dynamic property threw an error`).setSourceType('tag-condition').setSourceDynamicProperty(tag.conditionalDynamicProperty).setEntryDynamicProperty(tag.conditionalDynamicProperty).setTag(tag).setCanvas(canvas);
2902
+ console.warn(wrappedError);
2903
+ }
2570
2904
  }
2571
2905
 
2572
- if (clickthrough_dynamic_property) {
2906
+ return this.setupTags(filteredTags);
2907
+ }
2908
+
2909
+ setupTags(tags) {
2910
+ return tags;
2911
+ }
2912
+
2913
+ async clickthrough(currentCanvas) {
2914
+ const canvasCDP = currentCanvas?.clickthroughDynamicProperty;
2915
+
2916
+ if (canvasCDP) {
2573
2917
  const {
2574
2918
  context,
2575
2919
  propertyPath,
2576
- propertyValue
2577
- } = clickthrough_dynamic_property;
2920
+ propertyValue,
2921
+ propertyGroupKey
2922
+ } = canvasCDP;
2578
2923
  if (propertyValue) return propertyValue;
2579
- const [result, error] = await this.getPropertyTuple(propertyPath, context);
2924
+ const [result, error] = await this.getPropertyTuple(propertyGroupKey, propertyPath, context);
2580
2925
 
2581
2926
  if (error) {
2582
2927
  throw StudioErrorWrapper(error).setSourceType('dynamic-clickthrough').setCanvas(currentCanvas);
@@ -2658,18 +3003,25 @@ class StudioFramework {
2658
3003
  const {
2659
3004
  propertyGroupKey,
2660
3005
  propertyPath,
3006
+ propertyValue,
2661
3007
  context
2662
3008
  } = value;
2663
- this.setProperty(`options.${key}`, ({
2664
- getProperty
2665
- }) => {
2666
- return getProperty(propertyGroupKey, propertyPath, context);
2667
- });
2668
- this.setProperty(key, ({
2669
- getProperty
2670
- }) => {
2671
- return getProperty(propertyGroupKey, propertyPath, context);
2672
- });
3009
+
3010
+ if (propertyGroupKey === 'static') {
3011
+ this.setProperty(`options.${key}`, propertyValue);
3012
+ this.setProperty(key, propertyValue);
3013
+ } else {
3014
+ this.setProperty(`options.${key}`, ({
3015
+ getProperty
3016
+ }) => {
3017
+ return getProperty(propertyGroupKey, propertyPath, context);
3018
+ });
3019
+ this.setProperty(key, ({
3020
+ getProperty
3021
+ }) => {
3022
+ return getProperty(propertyGroupKey, propertyPath, context);
3023
+ });
3024
+ }
2673
3025
  } else {
2674
3026
  this.setProperty(`options.${key}`, value);
2675
3027
  this.setProperty(key, value);
@@ -2695,13 +3047,19 @@ class StudioFramework {
2695
3047
  const {
2696
3048
  propertyGroupKey,
2697
3049
  propertyPath,
3050
+ propertyValue,
2698
3051
  context
2699
3052
  } = value;
2700
- this.setProperty(`options.${fieldName}`, ({
2701
- getProperty
2702
- }) => {
2703
- return getProperty(propertyGroupKey, propertyPath, context);
2704
- });
3053
+
3054
+ if (propertyGroupKey === 'static') {
3055
+ this.setProperty(`options.${fieldName}`, propertyValue);
3056
+ } else {
3057
+ this.setProperty(`options.${fieldName}`, ({
3058
+ getProperty
3059
+ }) => {
3060
+ return getProperty(propertyGroupKey, propertyPath, context);
3061
+ });
3062
+ }
2705
3063
  } else {
2706
3064
  this.setProperty(`options.${fieldName}`, value);
2707
3065
  }
@@ -2795,19 +3153,47 @@ class StudioFramework {
2795
3153
  throw e;
2796
3154
  }
2797
3155
 
3156
+ handleAndPreventFutureAnalyticsCalls(data) {
3157
+ if (typeof data !== 'object') {
3158
+ throw new Error('The result of `analyticsData` must be an object');
3159
+ }
3160
+
3161
+ const format = window.MICapture?.format;
3162
+ const analytics = document.querySelector('#mi-data');
3163
+
3164
+ if (format === 'html') {
3165
+ const analyticsLength = analytics ? (analytics.getAttribute('data-mi-data') || '').length : 0;
3166
+
3167
+ if (analyticsLength > 500) {
3168
+ analytics.setAttribute('data-mi-data', '{}');
3169
+ console.log('extraData trying to be set exceeds 500 characters, setting extraData to be empty to avoid breaking crops');
3170
+ }
3171
+ } // Force a full overwrite
3172
+
3173
+
3174
+ if (analytics) document.querySelector('#mi-data').remove();
3175
+ CD.setExtraData(data);
3176
+
3177
+ CD.setExtraData = () => {
3178
+ console.log('setExtraData call was prevented via handleAndPreventFutureAnalyticsCalls');
3179
+ };
3180
+
3181
+ CD.resume();
3182
+ }
3183
+
2798
3184
  async render(targetElement) {
3185
+ if (window.MICapture?.isPreview) console.log('Preview Render');
2799
3186
  let currentCanvas;
2800
3187
 
2801
3188
  try {
2802
- var _currentCanvas;
2803
-
2804
3189
  CD.pause();
2805
3190
  currentCanvas = await this.getCurrentCanvas();
2806
3191
  const clickthroughURL = await this.handleClickthrough(currentCanvas);
2807
- const canvasTags = ((_currentCanvas = currentCanvas) === null || _currentCanvas === void 0 ? void 0 : _currentCanvas.tags) || [];
2808
- const tags = this.setupTags(canvasTags);
3192
+ const canvasTags = currentCanvas?.tags || [];
3193
+ const tags = await this.getCurrentTags(canvasTags, currentCanvas);
2809
3194
  const height = currentCanvas.height || this.options.height;
2810
3195
  const width = currentCanvas.width || this.options.width;
3196
+ const format = window.MICapture?.format;
2811
3197
  const renderPromise = this.renderApp(targetElement, clickthroughURL, tags, {
2812
3198
  height,
2813
3199
  width
@@ -2819,12 +3205,23 @@ class StudioFramework {
2819
3205
  this.setupAnimation();
2820
3206
  }
2821
3207
 
2822
- cleanHTML(targetElement);
2823
- addBrowserContent(targetElement);
2824
- CD.resume();
3208
+ if (this.shouldPerformStaticCheck) {
3209
+ if (window.RENDERED_STATICALLY = isDocumentEligibleForStaticHandling(targetElement)) {
3210
+ console.log('static status is true - static check has finished');
3211
+ } else {
3212
+ console.log('static status is false - static check has finished');
3213
+ }
3214
+ }
3215
+
3216
+ if (format === 'html') {
3217
+ cleanHTML(targetElement);
3218
+ addBrowserContent(targetElement);
3219
+ }
2825
3220
  } catch (e) {
2826
3221
  const wrappedError = StudioErrorWrapper(e).setCanvas(currentCanvas);
2827
3222
  this.handleRenderError(wrappedError);
3223
+ } finally {
3224
+ CD.resume();
2828
3225
  }
2829
3226
  }
2830
3227
 
@@ -3116,4 +3513,4 @@ if (window.MICapture && window.MICapture.captureAppLog) {
3116
3513
  }
3117
3514
 
3118
3515
  export default StudioFramework;
3119
- export { App, StudioTool, computedPath, makeDynamicProperty };
3516
+ export { App, StudioError, StudioTool, computedPath, makeDynamicProperty };