proto-table-wc 0.0.457 → 0.0.459

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.
@@ -2,166 +2,166 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-267e3f8d.js');
5
+ const index = require('./index-719e6a11.js');
6
6
 
7
7
  const demoTableCss = ".detailWrapper{font-weight:100;font-size:13px;display:flex;flex-direction:column;justify-items:start;padding:5px;padding-left:30px}";
8
8
 
9
9
  const DemoTable = class {
10
- constructor(hostRef) {
11
- index.registerInstance(this, hostRef);
12
- this.fields = [
13
- { label: 'Date', prop: 'date' },
14
- { label: 'List Price', prop: 'price' },
15
- { label: '% of Market', prop: 'market' },
16
- { label: 'ProfitTime Score', prop: 'score' },
17
- ];
18
- this.items = [];
19
- this.table = undefined;
20
- this.renderDetails = item => {
21
- const { tags = [] } = item;
22
- return (index.h("div", { class: "detailWrapper" }, index.h("span", null, tags.length, " details..."), index.h("ul", null, tags.map(tag => (index.h("li", null, tag))))));
23
- };
24
- }
25
- componentWillLoad() {
26
- this.items = [
27
- {
28
- date: '08/30/2020',
29
- price: '$24,000',
30
- market: '98%',
31
- score: 'No Score',
32
- tags: ['one', 'two', 'three'],
33
- },
34
- {
35
- date: '08/31/2020',
36
- price: '$24,000',
37
- market: '99%',
38
- score: 'No Score',
39
- tags: ['uno', 'duo'],
40
- },
41
- {
42
- date: '09/01/2020',
43
- price: '$27,000',
44
- market: '102%',
45
- score: 'Platinum',
46
- },
47
- {
48
- date: '09/02/2020',
49
- price: '$27,423',
50
- market: '104%',
51
- score: 'Platinum',
52
- tags: ['dog', 'cat', 'fish', 'hamster'],
53
- },
54
- {
55
- date: '09/03/2020',
56
- price: '$27,521',
57
- market: '106%',
58
- score: 'Platinum',
59
- tags: ['4wd', 'sports'],
60
- },
61
- {
62
- date: '09/04/2020',
63
- price: '$27,687',
64
- market: '107%',
65
- score: 'Platinum',
66
- tags: ['leather', 'chrome'],
67
- },
68
- ];
69
- }
70
- componentDidLoad() {
71
- const { table, items, fields } = this;
72
- table.data = items;
73
- table.fields = fields;
74
- table.details = this.renderDetails;
75
- }
76
- render() {
77
- return index.h("proto-table", { ref: el => (this.table = el) });
78
- }
10
+ constructor(hostRef) {
11
+ index.registerInstance(this, hostRef);
12
+ this.fields = [
13
+ { label: 'Date', prop: 'date' },
14
+ { label: 'List Price', prop: 'price' },
15
+ { label: '% of Market', prop: 'market' },
16
+ { label: 'ProfitTime Score', prop: 'score' },
17
+ ];
18
+ this.items = [];
19
+ this.table = undefined;
20
+ this.renderDetails = item => {
21
+ const { tags = [] } = item;
22
+ return (index.h("div", { class: "detailWrapper" }, index.h("span", null, tags.length, " details..."), index.h("ul", null, tags.map(tag => (index.h("li", null, tag))))));
23
+ };
24
+ }
25
+ componentWillLoad() {
26
+ this.items = [
27
+ {
28
+ date: '08/30/2020',
29
+ price: '$24,000',
30
+ market: '98%',
31
+ score: 'No Score',
32
+ tags: ['one', 'two', 'three'],
33
+ },
34
+ {
35
+ date: '08/31/2020',
36
+ price: '$24,000',
37
+ market: '99%',
38
+ score: 'No Score',
39
+ tags: ['uno', 'duo'],
40
+ },
41
+ {
42
+ date: '09/01/2020',
43
+ price: '$27,000',
44
+ market: '102%',
45
+ score: 'Platinum',
46
+ },
47
+ {
48
+ date: '09/02/2020',
49
+ price: '$27,423',
50
+ market: '104%',
51
+ score: 'Platinum',
52
+ tags: ['dog', 'cat', 'fish', 'hamster'],
53
+ },
54
+ {
55
+ date: '09/03/2020',
56
+ price: '$27,521',
57
+ market: '106%',
58
+ score: 'Platinum',
59
+ tags: ['4wd', 'sports'],
60
+ },
61
+ {
62
+ date: '09/04/2020',
63
+ price: '$27,687',
64
+ market: '107%',
65
+ score: 'Platinum',
66
+ tags: ['leather', 'chrome'],
67
+ },
68
+ ];
69
+ }
70
+ componentDidLoad() {
71
+ const { table, items, fields } = this;
72
+ table.data = items;
73
+ table.fields = fields;
74
+ table.details = this.renderDetails;
75
+ }
76
+ render() {
77
+ return index.h("proto-table", { ref: el => (this.table = el) });
78
+ }
79
79
  };
80
80
  DemoTable.style = demoTableCss;
81
81
 
82
82
  const iconPaths = {
83
- 'down': 'M12 15.4L6.6 10 8 8.6l4 4 4-4 1.4 1.4z',
84
- 'up': 'M16 15.4l-4-4-4 4L6.6 14 12 8.6l5.4 5.4z',
85
- 'left': 'M14 17.4L8.6 12 14 6.6 15.4 8l-4 4 4 4z',
86
- 'right': 'M10 17.4L8.6 16l4-4-4-4L10 6.6l5.4 5.4z',
87
- 'more': 'M12 14a2 2 0 100-4 2 2 0 000 4zm-6 0a2 2 0 100-4 2 2 0 000 4zm12 0a2 2 0 100-4 2 2 0 000 4z',
88
- 'arrow-up': 'M5.3 10.7l1.4 1.4L11 7.8V20h2V7.8l4.3 4.3 1.4-1.4L12 4z',
89
- 'arrow-down': 'M18.7 13.3l-1.4-1.4-4.3 4.3V4h-2v12.2l-4.3-4.3-1.4 1.4L12 20z',
83
+ 'down': 'M12 15.4L6.6 10 8 8.6l4 4 4-4 1.4 1.4z',
84
+ 'up': 'M16 15.4l-4-4-4 4L6.6 14 12 8.6l5.4 5.4z',
85
+ 'left': 'M14 17.4L8.6 12 14 6.6 15.4 8l-4 4 4 4z',
86
+ 'right': 'M10 17.4L8.6 16l4-4-4-4L10 6.6l5.4 5.4z',
87
+ 'more': 'M12 14a2 2 0 100-4 2 2 0 000 4zm-6 0a2 2 0 100-4 2 2 0 000 4zm12 0a2 2 0 100-4 2 2 0 000 4z',
88
+ 'arrow-up': 'M5.3 10.7l1.4 1.4L11 7.8V20h2V7.8l4.3 4.3 1.4-1.4L12 4z',
89
+ 'arrow-down': 'M18.7 13.3l-1.4-1.4-4.3 4.3V4h-2v12.2l-4.3-4.3-1.4 1.4L12 20z',
90
90
  };
91
91
 
92
92
  const protoTableCss = ".table{font-weight:400;font-size:13px;display:flex;flex-direction:column;width:100%;border:1px solid var(--clrs-navy);border-radius:2px}.table svg{fill:var(--clrs-navy)}.header{display:flex}.headerCell{flex-basis:100%;display:flex;align-items:center;justify-items:start;border-right:1px solid var(--clrs-navy);border-bottom:1px solid var(--clrs-navy);padding:5px;cursor:pointer}.headerCell svg g{display:none}.headerCell.sort svg g{display:inline}.headerCell:hover svg g{display:inline}.headerCell:hover{background-color:var(--clrs-silver)}.headerCell:last-child{border-right:none}.cell{flex-basis:100%;display:flex;align-items:center;justify-items:start;padding:5px}.cell:first-child svg{cursor:pointer}.sort{background-color:var(--cx-column-sort)}.row{display:flex;justify-items:stretch;width:100%}.row.expanded{background-color:var(--cx-row-expanded)}.row.expanded svg{fill:var(--clrs-red)}.row:hover{background-color:var(--cx-row-hover)}";
93
93
 
94
94
  const iconAliases = {
95
- 'right': 'show',
96
- 'down': 'hide',
97
- 'arrow-up': 'sort',
98
- 'arrow-down': 'sort',
95
+ 'right': 'show',
96
+ 'down': 'hide',
97
+ 'arrow-up': 'sort',
98
+ 'arrow-down': 'sort',
99
99
  };
100
100
  const aliasFor = name => {
101
- return iconAliases[name];
101
+ return iconAliases[name];
102
102
  };
103
103
  const ProtoTable = class {
104
- constructor(hostRef) {
105
- index.registerInstance(this, hostRef);
106
- this.protoIcon = (name, hex = undefined, size = 24) => {
107
- const path = iconPaths[name];
108
- return (index.h("svg", { width: size, height: size, viewBox: "0 0 24 24", role: "img", "aria-labelledby": "title" }, index.h("title", null, aliasFor(name)), index.h("g", { fill: hex }, index.h("path", { d: path })), index.h("path", { d: "M0 0h24v24H0z", fill: "none" })));
109
- };
110
- this.handleCellClick = (index, row) => {
111
- return () => {
112
- if (index === 0) {
113
- this.expanded = this.expanded === row ? undefined : row;
114
- }
115
- };
116
- };
117
- this.handleSortClick = index => {
118
- // NOTE: small state machine for dealing with sorting...
119
- return () => {
120
- if (this.sort === index) {
121
- if (this.clicks === 2) {
122
- this.clicks = 0;
123
- this.sort = undefined;
124
- }
125
- else {
126
- this.clicks = this.clicks + 1;
127
- }
128
- }
129
- else {
130
- this.sort = index;
131
- this.clicks = 1;
132
- }
133
- };
134
- };
135
- this.iconFor = column => {
136
- return this.sort === column && this.clicks === 2 ? 'arrow-up' : 'arrow-down';
137
- };
138
- this.header = () => {
139
- const { fields, iconFor, protoIcon } = this;
140
- return (index.h("div", { class: "header" }, fields.map(({ label }, index$1) => {
141
- const cellClass = index$1 === this.sort ? 'headerCell sort' : 'headerCell';
142
- const ikon = iconFor(index$1);
143
- return (index.h("div", { class: cellClass, onClick: this.handleSortClick(index$1) }, protoIcon(ikon), index.h("span", null, label)));
144
- })));
145
- };
146
- this.row = (data, row) => {
147
- const { fields, protoIcon } = this;
148
- const rowClass = this.expanded === row ? 'row expanded' : 'row';
149
- return (index.h("div", { class: "rowContainer" }, index.h("div", { class: rowClass }, fields.map(({ prop }, index$1) => {
150
- const cellClass = index$1 === this.sort ? 'cell sort' : 'cell';
151
- return (index.h("div", { class: cellClass, onClick: this.handleCellClick(index$1, row) }, index$1 === 0 && this.details ? protoIcon(this.expanded === row ? 'down' : 'right') : protoIcon('pad'), data[prop]));
152
- })), this.details && this.expanded === row && this.details(data)));
153
- };
154
- this.data = [];
155
- this.details = undefined;
156
- this.fields = [];
157
- this.expanded = undefined;
158
- this.sort = undefined;
159
- this.clicks = 0;
160
- }
161
- render() {
162
- const items = this.data || [];
163
- return (index.h("div", { class: "table" }, this.header(), items.map((item, index) => this.row(item, index))));
164
- }
104
+ constructor(hostRef) {
105
+ index.registerInstance(this, hostRef);
106
+ this.protoIcon = (name, hex = undefined, size = 24) => {
107
+ const path = iconPaths[name];
108
+ return (index.h("svg", { width: size, height: size, viewBox: "0 0 24 24", role: "img", "aria-labelledby": "title" }, index.h("title", null, aliasFor(name)), index.h("g", { fill: hex }, index.h("path", { d: path })), index.h("path", { d: "M0 0h24v24H0z", fill: "none" })));
109
+ };
110
+ this.handleCellClick = (index, row) => {
111
+ return () => {
112
+ if (index === 0) {
113
+ this.expanded = this.expanded === row ? undefined : row;
114
+ }
115
+ };
116
+ };
117
+ this.handleSortClick = index => {
118
+ // NOTE: small state machine for dealing with sorting...
119
+ return () => {
120
+ if (this.sort === index) {
121
+ if (this.clicks === 2) {
122
+ this.clicks = 0;
123
+ this.sort = undefined;
124
+ }
125
+ else {
126
+ this.clicks = this.clicks + 1;
127
+ }
128
+ }
129
+ else {
130
+ this.sort = index;
131
+ this.clicks = 1;
132
+ }
133
+ };
134
+ };
135
+ this.iconFor = column => {
136
+ return this.sort === column && this.clicks === 2 ? 'arrow-up' : 'arrow-down';
137
+ };
138
+ this.header = () => {
139
+ const { fields, iconFor, protoIcon } = this;
140
+ return (index.h("div", { class: "header" }, fields.map(({ label }, index$1) => {
141
+ const cellClass = index$1 === this.sort ? 'headerCell sort' : 'headerCell';
142
+ const ikon = iconFor(index$1);
143
+ return (index.h("div", { class: cellClass, onClick: this.handleSortClick(index$1) }, protoIcon(ikon), index.h("span", null, label)));
144
+ })));
145
+ };
146
+ this.row = (data, row) => {
147
+ const { fields, protoIcon } = this;
148
+ const rowClass = this.expanded === row ? 'row expanded' : 'row';
149
+ return (index.h("div", { class: "rowContainer" }, index.h("div", { class: rowClass }, fields.map(({ prop }, index$1) => {
150
+ const cellClass = index$1 === this.sort ? 'cell sort' : 'cell';
151
+ return (index.h("div", { class: cellClass, onClick: this.handleCellClick(index$1, row) }, index$1 === 0 && this.details ? protoIcon(this.expanded === row ? 'down' : 'right') : protoIcon('pad'), data[prop]));
152
+ })), this.details && this.expanded === row && this.details(data)));
153
+ };
154
+ this.data = [];
155
+ this.details = undefined;
156
+ this.fields = [];
157
+ this.expanded = undefined;
158
+ this.sort = undefined;
159
+ this.clicks = 0;
160
+ }
161
+ render() {
162
+ const items = this.data || [];
163
+ return (index.h("div", { class: "table" }, this.header(), items.map((item, index) => this.row(item, index))));
164
+ }
165
165
  };
166
166
  ProtoTable.style = protoTableCss;
167
167
 
@@ -49,6 +49,13 @@ const uniqueTime = (key, measureText) => {
49
49
  }
50
50
  };
51
51
  const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}';
52
+ /**
53
+ * Constant for styles to be globally applied to `slot-fb` elements for pseudo-slot behavior.
54
+ *
55
+ * Two cascading rules must be used instead of a `:not()` selector due to Stencil browser
56
+ * support as of Stencil v4.
57
+ */
58
+ const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}';
52
59
  /**
53
60
  * Default style mode id
54
61
  */
@@ -263,6 +270,10 @@ const addStyle = (styleContainerNode, cmpMeta, mode) => {
263
270
  }
264
271
  styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link'));
265
272
  }
273
+ // Add styles for `slot-fb` elements if we're using slots outside the Shadow DOM
274
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
275
+ styleElm.innerHTML += SLOT_FB_CSS;
276
+ }
266
277
  if (appliedStyles) {
267
278
  appliedStyles.add(scopeId);
268
279
  }
@@ -400,7 +411,11 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
400
411
  elm[memberName] = newValue;
401
412
  }
402
413
  }
403
- catch (e) { }
414
+ catch (e) {
415
+ /**
416
+ * in case someone tries to set a read-only property, e.g. "namespaceURI", we just ignore it
417
+ */
418
+ }
404
419
  }
405
420
  if (newValue == null || newValue === false) {
406
421
  if (newValue !== false || elm.getAttribute(memberName) === '') {
@@ -419,6 +434,11 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
419
434
  }
420
435
  };
421
436
  const parseClassListRegex = /\s/;
437
+ /**
438
+ * Parsed a string of classnames into an array
439
+ * @param value className string, e.g. "foo bar baz"
440
+ * @returns list of classes, e.g. ["foo", "bar", "baz"]
441
+ */
422
442
  const parseClassList = (value) => (!value ? [] : value.split(parseClassListRegex));
423
443
  const CAPTURE_EVENT_SUFFIX = 'Capture';
424
444
  const CAPTURE_EVENT_REGEX = new RegExp(CAPTURE_EVENT_SUFFIX + '$');
@@ -1167,10 +1187,10 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
1167
1187
  */
1168
1188
  const proxyComponent = (Cstr, cmpMeta, flags) => {
1169
1189
  var _a;
1190
+ const prototype = Cstr.prototype;
1170
1191
  if (cmpMeta.$members$) {
1171
1192
  // It's better to have a const than two Object.entries()
1172
1193
  const members = Object.entries(cmpMeta.$members$);
1173
- const prototype = Cstr.prototype;
1174
1194
  members.map(([memberName, [memberFlags]]) => {
1175
1195
  if ((memberFlags & 31 /* MEMBER_FLAGS.Prop */ ||
1176
1196
  ((flags & 2 /* PROXY_FLAGS.proxyState */) && memberFlags & 32 /* MEMBER_FLAGS.State */))) {
@@ -1193,6 +1213,7 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1193
1213
  const attrNameToPropName = new Map();
1194
1214
  prototype.attributeChangedCallback = function (attrName, oldValue, newValue) {
1195
1215
  plt.jmp(() => {
1216
+ var _a;
1196
1217
  const propName = attrNameToPropName.get(attrName);
1197
1218
  // In a web component lifecycle the attributeChangedCallback runs prior to connectedCallback
1198
1219
  // in the case where an attribute was set inline.
@@ -1248,11 +1269,12 @@ const proxyComponent = (Cstr, cmpMeta, flags) => {
1248
1269
  // 1. The instance is ready
1249
1270
  // 2. The watchers are ready
1250
1271
  // 3. The value has changed
1251
- if (!(flags & 8 /* HOST_FLAGS.isConstructingInstance */) &&
1272
+ if (flags &&
1273
+ !(flags & 8 /* HOST_FLAGS.isConstructingInstance */) &&
1252
1274
  flags & 128 /* HOST_FLAGS.isWatchReady */ &&
1253
1275
  newValue !== oldValue) {
1254
1276
  const instance = hostRef.$lazyInstance$ ;
1255
- const entry = cmpMeta.$watchers$[attrName];
1277
+ const entry = (_a = cmpMeta.$watchers$) === null || _a === void 0 ? void 0 : _a[attrName];
1256
1278
  entry === null || entry === void 0 ? void 0 : entry.forEach((callbackName) => {
1257
1279
  if (instance[callbackName] != null) {
1258
1280
  instance[callbackName].call(instance, newValue, oldValue, attrName);
@@ -1432,12 +1454,13 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1432
1454
  const customElements = win.customElements;
1433
1455
  const head = doc.head;
1434
1456
  const metaCharset = /*@__PURE__*/ head.querySelector('meta[charset]');
1435
- const visibilityStyle = /*@__PURE__*/ doc.createElement('style');
1457
+ const dataStyles = /*@__PURE__*/ doc.createElement('style');
1436
1458
  const deferredConnectedCallbacks = [];
1437
1459
  let appLoadFallback;
1438
1460
  let isBootstrapping = true;
1439
1461
  Object.assign(plt, options);
1440
1462
  plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', doc.baseURI).href;
1463
+ let hasSlotRelocation = false;
1441
1464
  lazyBundles.map((lazyBundle) => {
1442
1465
  lazyBundle[1].map((compactMeta) => {
1443
1466
  const cmpMeta = {
@@ -1446,6 +1469,11 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1446
1469
  $members$: compactMeta[2],
1447
1470
  $listeners$: compactMeta[3],
1448
1471
  };
1472
+ // Check if we are using slots outside the shadow DOM in this component.
1473
+ // We'll use this information later to add styles for `slot-fb` elements
1474
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
1475
+ hasSlotRelocation = true;
1476
+ }
1449
1477
  {
1450
1478
  cmpMeta.$members$ = compactMeta[2];
1451
1479
  }
@@ -1496,15 +1524,23 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1496
1524
  }
1497
1525
  });
1498
1526
  });
1527
+ // Add styles for `slot-fb` elements if any of our components are using slots outside the Shadow DOM
1528
+ if (hasSlotRelocation) {
1529
+ dataStyles.innerHTML += SLOT_FB_CSS;
1530
+ }
1531
+ // Add hydration styles
1499
1532
  {
1500
- visibilityStyle.innerHTML = cmpTags + HYDRATED_CSS;
1501
- visibilityStyle.setAttribute('data-styles', '');
1533
+ dataStyles.innerHTML += cmpTags + HYDRATED_CSS;
1534
+ }
1535
+ // If we have styles, add them to the DOM
1536
+ if (dataStyles.innerHTML.length) {
1537
+ dataStyles.setAttribute('data-styles', '');
1538
+ head.insertBefore(dataStyles, metaCharset ? metaCharset.nextSibling : head.firstChild);
1502
1539
  // Apply CSP nonce to the style tag if it exists
1503
1540
  const nonce = (_a = plt.$nonce$) !== null && _a !== void 0 ? _a : queryNonceMetaTagContent(doc);
1504
1541
  if (nonce != null) {
1505
- visibilityStyle.setAttribute('nonce', nonce);
1542
+ dataStyles.setAttribute('nonce', nonce);
1506
1543
  }
1507
- head.insertBefore(visibilityStyle, metaCharset ? metaCharset.nextSibling : head.firstChild);
1508
1544
  }
1509
1545
  // Process deferred connectedCallbacks now all components have been registered
1510
1546
  isBootstrapping = false;
@@ -1656,7 +1692,7 @@ const flush = () => {
1656
1692
  }
1657
1693
  }
1658
1694
  };
1659
- const nextTick = /*@__PURE__*/ (cb) => promiseResolve().then(cb);
1695
+ const nextTick = (cb) => promiseResolve().then(cb);
1660
1696
  const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);
1661
1697
 
1662
1698
  exports.bootstrapLazy = bootstrapLazy;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-267e3f8d.js');
5
+ const index = require('./index-719e6a11.js');
6
6
 
7
7
  const defineCustomElements = (win, options) => {
8
8
  if (typeof window === 'undefined') return undefined;
@@ -2,10 +2,10 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-267e3f8d.js');
5
+ const index = require('./index-719e6a11.js');
6
6
 
7
7
  /*
8
- Stencil Client Patch Browser v4.7.1 | MIT Licensed | https://stenciljs.com
8
+ Stencil Client Patch Browser v4.8.0 | MIT Licensed | https://stenciljs.com
9
9
  */
10
10
  const patchBrowser = () => {
11
11
  const importMeta = (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('proto-table-wc.cjs.js', document.baseURI).href));
@@ -5,7 +5,7 @@
5
5
  ],
6
6
  "compiler": {
7
7
  "name": "@stencil/core",
8
- "version": "4.7.1",
8
+ "version": "4.8.0",
9
9
  "typescriptVersion": "5.2.2"
10
10
  },
11
11
  "collections": [],