@searchcraft/javascript-sdk 0.15.0 → 0.16.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 (75) hide show
  1. package/dist/components/defineCustomElements.js +24 -24
  2. package/dist/components/index.d.ts +130 -47
  3. package/dist/components/index.js +29 -29
  4. package/dist/components/safeUrl.js +378 -0
  5. package/dist/components/safeUrl.js.map +1 -0
  6. package/dist/components/searchcraft-ad.js +1 -1
  7. package/dist/components/searchcraft-ad2.js +6 -5
  8. package/dist/components/searchcraft-ad2.js.map +1 -1
  9. package/dist/components/searchcraft-button.js +1 -1
  10. package/dist/components/searchcraft-button2.js +2 -2
  11. package/dist/components/searchcraft-error-message.js +1 -1
  12. package/dist/components/searchcraft-error-message2.js +1 -1
  13. package/dist/components/searchcraft-facet-list.js +1 -1
  14. package/dist/components/searchcraft-facet-list2.js +2 -2
  15. package/dist/components/searchcraft-filter-panel.js +5 -5
  16. package/dist/components/searchcraft-input-form.js +1 -1
  17. package/dist/components/searchcraft-input-form2.js +23 -9
  18. package/dist/components/searchcraft-input-form2.js.map +1 -1
  19. package/dist/components/searchcraft-input-label.js +1 -1
  20. package/dist/components/searchcraft-input-label2.js +2 -2
  21. package/dist/components/searchcraft-loading.js +1 -1
  22. package/dist/components/searchcraft-loading2.js +1 -1
  23. package/dist/components/searchcraft-pagination.js +4 -4
  24. package/dist/components/searchcraft-popover-button.js +17 -6
  25. package/dist/components/searchcraft-popover-button.js.map +1 -1
  26. package/dist/components/searchcraft-popover-footer.js +1 -1
  27. package/dist/components/searchcraft-popover-footer2.js +5 -5
  28. package/dist/components/searchcraft-popover-footer2.js.map +1 -1
  29. package/dist/components/searchcraft-popover-form.js +106 -21
  30. package/dist/components/searchcraft-popover-form.js.map +1 -1
  31. package/dist/components/searchcraft-popover-list-item.js +1 -1
  32. package/dist/components/searchcraft-popover-list-item2.js +71 -10
  33. package/dist/components/searchcraft-popover-list-item2.js.map +1 -1
  34. package/dist/components/searchcraft-popover-list-view.js +1 -1
  35. package/dist/components/searchcraft-popover-list-view2.js +13 -8
  36. package/dist/components/searchcraft-popover-list-view2.js.map +1 -1
  37. package/dist/components/searchcraft-results-info.js +5 -5
  38. package/dist/components/searchcraft-results-info.js.map +1 -1
  39. package/dist/components/searchcraft-results-summary.js +1 -1
  40. package/dist/components/searchcraft-results-summary2.js +10 -9
  41. package/dist/components/searchcraft-results-summary2.js.map +1 -1
  42. package/dist/components/searchcraft-search-result.js +1 -1
  43. package/dist/components/searchcraft-search-result2.js +4 -3
  44. package/dist/components/searchcraft-search-result2.js.map +1 -1
  45. package/dist/components/searchcraft-search-results-per-page.js +3 -3
  46. package/dist/components/searchcraft-search-results.js +35 -18
  47. package/dist/components/searchcraft-search-results.js.map +1 -1
  48. package/dist/components/searchcraft-select.js +1 -1
  49. package/dist/components/searchcraft-select2.js +1 -1
  50. package/dist/components/searchcraft-slider.js +1 -1
  51. package/dist/components/searchcraft-slider2.js +5 -5
  52. package/dist/components/searchcraft-summary-box.js +6 -6
  53. package/dist/components/searchcraft-theme.js +3 -3
  54. package/dist/components/searchcraft-theme.js.map +1 -1
  55. package/dist/components/searchcraft-toggle-button.js +1 -1
  56. package/dist/components/searchcraft-toggle-button2.js +5 -5
  57. package/dist/hydrate/index.js +611 -57
  58. package/dist/hydrate/index.mjs +611 -57
  59. package/dist/themes/hologram.css +1 -1
  60. package/dist/themes/hologram.css.map +1 -1
  61. package/dist/types/components/searchcraft-input-form/searchcraft-input-form.d.ts +7 -0
  62. package/dist/types/components/searchcraft-popover-button/searchcraft-popover-button.d.ts +8 -0
  63. package/dist/types/components/searchcraft-popover-form/searchcraft-popover-form.d.ts +39 -1
  64. package/dist/types/components/searchcraft-popover-list-item/searchcraft-popover-list-item.d.ts +22 -1
  65. package/dist/types/components/searchcraft-popover-list-view/searchcraft-popover-list-view.d.ts +5 -1
  66. package/dist/types/components/searchcraft-results-summary/searchcraft-results-summary.d.ts +2 -2
  67. package/dist/types/components/searchcraft-search-results/searchcraft-search-results.d.ts +14 -8
  68. package/dist/types/components.d.ts +92 -36
  69. package/dist/types/types/sdk-types/templates.types.d.ts +40 -13
  70. package/dist/types/utils/html.d.ts +22 -0
  71. package/dist/types/utils/index.d.ts +1 -0
  72. package/dist/types/utils/safeUrl.d.ts +17 -0
  73. package/package.json +7 -5
  74. package/dist/components/html.js +0 -18
  75. package/dist/components/html.js.map +0 -1
@@ -0,0 +1,378 @@
1
+ import { p as purify } from './purify.es.js?scv=0.16.0';
2
+
3
+ /**
4
+ * States of a small HTML tokenizer, used to find where each value lands in the markup. The
5
+ * states from `TAG_OPEN` to `AFTER_ATTRIBUTE_NAME` are inside a tag but not in a value.
6
+ */
7
+ const TEXT = 0;
8
+ const TAG_OPEN = 1;
9
+ const END_TAG_OPEN = 2;
10
+ const TAG_NAME = 3;
11
+ const BEFORE_ATTRIBUTE_NAME = 4;
12
+ const ATTRIBUTE_NAME = 5;
13
+ const AFTER_ATTRIBUTE_NAME = 6;
14
+ const BEFORE_VALUE = 7;
15
+ const DOUBLE_QUOTED_VALUE = 8;
16
+ const SINGLE_QUOTED_VALUE = 9;
17
+ const UNQUOTED_VALUE = 10;
18
+ const MARKUP_DECLARATION = 11;
19
+ const COMMENT = 12;
20
+ const BOGUS_COMMENT = 13;
21
+ const RAW_TEXT = 14;
22
+ /**
23
+ * Elements whose content is read as text up to their end tag.
24
+ */
25
+ const RAW_TEXT_ELEMENTS = [
26
+ 'iframe',
27
+ 'noembed',
28
+ 'noframes',
29
+ 'noscript',
30
+ 'script',
31
+ 'style',
32
+ 'textarea',
33
+ 'title',
34
+ 'xmp',
35
+ ];
36
+ const SPACE_PATTERN = /[\t\n\f\r ]/;
37
+ const LETTER_PATTERN = /[a-z]/i;
38
+ /**
39
+ * Characters that cannot appear as is in an unquoted attribute value.
40
+ */
41
+ const UNQUOTED_VALUE_SPECIAL_PATTERN = /[\s"'=<>`]/g;
42
+ const createTokenizer = (state) => ({
43
+ state,
44
+ position: 0,
45
+ tagName: '',
46
+ isEndTag: false,
47
+ commentStart: 0,
48
+ });
49
+ /**
50
+ * Reads the markup from where the last call stopped, so `tokenizer.state` tells where the next
51
+ * character lands. It follows the HTML tokenizer closely enough to tell text, tags and
52
+ * attribute values apart, including after comments and inside elements such as `<style>`.
53
+ * It does not follow the tree the browser builds, so inside `<svg>` or `<math>`, elements such
54
+ * as `<style>` and `<title>` are still read as text.
55
+ */
56
+ const tokenize = (tokenizer, markup) => {
57
+ while (tokenizer.position < markup.length) {
58
+ const index = tokenizer.position++;
59
+ const character = markup.charAt(index);
60
+ const isSpace = SPACE_PATTERN.test(character);
61
+ switch (tokenizer.state) {
62
+ case TEXT:
63
+ if (character === '<') {
64
+ tokenizer.state = TAG_OPEN;
65
+ }
66
+ break;
67
+ case TAG_OPEN:
68
+ case END_TAG_OPEN:
69
+ if (LETTER_PATTERN.test(character)) {
70
+ tokenizer.isEndTag = tokenizer.state === END_TAG_OPEN;
71
+ tokenizer.tagName = character;
72
+ tokenizer.state = TAG_NAME;
73
+ }
74
+ else if (tokenizer.state === END_TAG_OPEN) {
75
+ tokenizer.state = character === '>' ? TEXT : BOGUS_COMMENT;
76
+ }
77
+ else if (character === '/') {
78
+ tokenizer.state = END_TAG_OPEN;
79
+ }
80
+ else if (character === '!') {
81
+ tokenizer.state = MARKUP_DECLARATION;
82
+ }
83
+ else if (character === '?') {
84
+ tokenizer.state = BOGUS_COMMENT;
85
+ }
86
+ else {
87
+ // The `<` is text, so read this character again as text.
88
+ tokenizer.state = TEXT;
89
+ tokenizer.position = index;
90
+ }
91
+ break;
92
+ case TAG_NAME:
93
+ if (isSpace || character === '/') {
94
+ tokenizer.state = BEFORE_ATTRIBUTE_NAME;
95
+ }
96
+ else if (character === '>') {
97
+ endTag(tokenizer);
98
+ }
99
+ else {
100
+ tokenizer.tagName += character;
101
+ }
102
+ break;
103
+ case BEFORE_ATTRIBUTE_NAME:
104
+ if (character === '>') {
105
+ endTag(tokenizer);
106
+ }
107
+ else if (!isSpace && character !== '/') {
108
+ tokenizer.state = ATTRIBUTE_NAME;
109
+ }
110
+ break;
111
+ case ATTRIBUTE_NAME:
112
+ case AFTER_ATTRIBUTE_NAME:
113
+ if (character === '>') {
114
+ endTag(tokenizer);
115
+ }
116
+ else if (character === '=') {
117
+ tokenizer.state = BEFORE_VALUE;
118
+ }
119
+ else if (character === '/') {
120
+ tokenizer.state = BEFORE_ATTRIBUTE_NAME;
121
+ }
122
+ else if (isSpace) {
123
+ tokenizer.state = AFTER_ATTRIBUTE_NAME;
124
+ }
125
+ else {
126
+ tokenizer.state = ATTRIBUTE_NAME;
127
+ }
128
+ break;
129
+ case BEFORE_VALUE:
130
+ if (character === '>') {
131
+ endTag(tokenizer);
132
+ }
133
+ else if (character === '"') {
134
+ tokenizer.state = DOUBLE_QUOTED_VALUE;
135
+ }
136
+ else if (character === "'") {
137
+ tokenizer.state = SINGLE_QUOTED_VALUE;
138
+ }
139
+ else if (!isSpace) {
140
+ tokenizer.state = UNQUOTED_VALUE;
141
+ }
142
+ break;
143
+ case DOUBLE_QUOTED_VALUE:
144
+ case SINGLE_QUOTED_VALUE:
145
+ if (character === (tokenizer.state === DOUBLE_QUOTED_VALUE ? '"' : "'")) {
146
+ tokenizer.state = BEFORE_ATTRIBUTE_NAME;
147
+ }
148
+ break;
149
+ case UNQUOTED_VALUE:
150
+ if (character === '>') {
151
+ endTag(tokenizer);
152
+ }
153
+ else if (isSpace) {
154
+ tokenizer.state = BEFORE_ATTRIBUTE_NAME;
155
+ }
156
+ break;
157
+ case MARKUP_DECLARATION:
158
+ if (markup.startsWith('--', index)) {
159
+ tokenizer.state = COMMENT;
160
+ tokenizer.position = index + 2;
161
+ tokenizer.commentStart = index + 2;
162
+ }
163
+ else {
164
+ tokenizer.state = BOGUS_COMMENT;
165
+ tokenizer.position = index;
166
+ }
167
+ break;
168
+ case COMMENT: {
169
+ // A comment ends at `-->` or `--!>`, and `<!-->` and `<!--->` end at once.
170
+ const comment = markup.slice(Math.max(tokenizer.commentStart, index - 3), index);
171
+ if (character === '>' &&
172
+ (index - tokenizer.commentStart < 2
173
+ ? /^-?$/.test(comment)
174
+ : /--!?$/.test(comment))) {
175
+ tokenizer.state = TEXT;
176
+ }
177
+ break;
178
+ }
179
+ case BOGUS_COMMENT:
180
+ if (character === '>') {
181
+ tokenizer.state = TEXT;
182
+ }
183
+ break;
184
+ case RAW_TEXT: {
185
+ const endTagPattern = new RegExp(`</${tokenizer.tagName}[\\t\\n\\f\\r />]`, 'gi');
186
+ endTagPattern.lastIndex = index;
187
+ const match = endTagPattern.exec(markup);
188
+ if (!match) {
189
+ // Read the end again next time, in case the end tag is only partly written yet.
190
+ tokenizer.position = Math.max(index, markup.length - tokenizer.tagName.length - 2);
191
+ return;
192
+ }
193
+ tokenizer.state = TAG_NAME;
194
+ tokenizer.isEndTag = true;
195
+ tokenizer.position = match.index + tokenizer.tagName.length + 2;
196
+ break;
197
+ }
198
+ }
199
+ }
200
+ };
201
+ const endTag = (tokenizer) => {
202
+ const tagName = tokenizer.tagName.toLowerCase();
203
+ if (!tokenizer.isEndTag && RAW_TEXT_ELEMENTS.includes(tagName)) {
204
+ tokenizer.state = RAW_TEXT;
205
+ tokenizer.tagName = tagName;
206
+ }
207
+ else {
208
+ tokenizer.state = TEXT;
209
+ }
210
+ };
211
+ const encodeCharacter = (character) => `&#${character.charCodeAt(0)};`;
212
+ const isTagState = (state) => state >= TAG_OPEN && state <= AFTER_ATTRIBUTE_NAME;
213
+ const isValueState = (state) => state >= BEFORE_VALUE && state <= UNQUOTED_VALUE;
214
+ /**
215
+ * Makes a value safe for where it lands in the markup. With more than one state, the markup
216
+ * may be read in more than one way, so the value is made safe for each of them.
217
+ */
218
+ const placeValue = (value, states) => {
219
+ if (states.every(isTagState)) {
220
+ return value;
221
+ }
222
+ if (!states.some(isValueState)) {
223
+ return value && purify.sanitize(value);
224
+ }
225
+ let escaped = value;
226
+ for (const state of states) {
227
+ if (state === DOUBLE_QUOTED_VALUE) {
228
+ escaped = escaped.replace(/"/g, '&quot;');
229
+ }
230
+ else if (state === SINGLE_QUOTED_VALUE) {
231
+ escaped = escaped.replace(/'/g, '&#39;');
232
+ }
233
+ else if (isValueState(state)) {
234
+ escaped = escaped.replace(UNQUOTED_VALUE_SPECIAL_PATTERN, encodeCharacter);
235
+ }
236
+ }
237
+ if (!states.every(isValueState)) {
238
+ // The value may be read as text too, so it must not start a tag.
239
+ return escaped.replace(/</g, '&lt;');
240
+ }
241
+ // With no value, the next attribute would be read as this attribute's value.
242
+ return escaped || (states.includes(BEFORE_VALUE) ? '""' : '');
243
+ };
244
+ /**
245
+ * This allows you to parse a template string with a function.
246
+ *
247
+ * Each value is made safe for where it lands in the markup:
248
+ * - In text, the value is sanitized with DOMPurify, so it can contain markup but no scripts.
249
+ * DOMPurify also removes URLs it does not allow, so a link with a custom scheme that `safeUrl`
250
+ * allowed loses its `href` when its markup is placed as a value in text, as in a list built
251
+ * from nested `html` calls. Write such links in the template's own markup instead.
252
+ * - In a quoted attribute value, the quote that would end the value is escaped. The browser
253
+ * decodes it again, so quotes display as given. Character references in the value, such as
254
+ * `&amp;`, are decoded by the browser as before.
255
+ * - In an unquoted attribute value, spaces, quotes and `=<>` are escaped.
256
+ * - Inside a tag but not in an attribute value, such as `<a ${attributes}>`, the value is placed
257
+ * as is. Use this only for attributes the template writes itself, such as the output of a
258
+ * nested `html` call, never for indexed data.
259
+ *
260
+ * A template can also be a list of attributes, such as `aria-label="${label}"`, that another
261
+ * template places inside a tag. Until its first tag ends, a value that could be in an attribute
262
+ * value is escaped for that attribute, and `<` is escaped so it cannot start a tag either.
263
+ *
264
+ * Escaping keeps a value inside its attribute but does not make every attribute safe. A value in
265
+ * an event handler such as `onclick` still runs as script, and a value in `style` still applies
266
+ * as CSS. URLs from indexed data should go through `safeUrl` before they are placed in an
267
+ * `href` or `src`.
268
+ */
269
+ const html = (strings, ...values) => {
270
+ const tokenizer = createTokenizer(TEXT);
271
+ // A template can also be a list of attributes that a parent template places inside a tag,
272
+ // so until the two readings meet, its values are made safe for both.
273
+ let attributeTokenizer = createTokenizer(BEFORE_ATTRIBUTE_NAME);
274
+ let result = strings[0] ?? '';
275
+ for (let i = 0; i < values.length; i++) {
276
+ const value = values[i];
277
+ tokenize(tokenizer, result);
278
+ if (attributeTokenizer) {
279
+ tokenize(attributeTokenizer, result);
280
+ if (tokenizer.state === TEXT && attributeTokenizer.state === TEXT) {
281
+ attributeTokenizer = undefined;
282
+ }
283
+ }
284
+ result +=
285
+ placeValue(value || value === 0 ? String(value) : '', attributeTokenizer
286
+ ? [tokenizer.state, attributeTokenizer.state]
287
+ : [tokenizer.state]) + (strings[i + 1] ?? '');
288
+ }
289
+ return result;
290
+ };
291
+
292
+ /**
293
+ * Schemes that are always allowed. `data:` URLs are allowed separately, for images only.
294
+ */
295
+ const ALLOWED_SCHEMES = ['http', 'https', 'mailto', 'tel', 'sms'];
296
+ /**
297
+ * Returned in place of a URL that is not allowed.
298
+ */
299
+ const BLOCKED_URL = '#';
300
+ /**
301
+ * A scheme is only recognized when its `:` comes before any `/`, `?` or `#`.
302
+ */
303
+ const SCHEME_PATTERN = /^([a-z][a-z\d+.-]*):/i;
304
+ const DATA_IMAGE_PATTERN = /^data:image\//i;
305
+ /**
306
+ * Character references the browser decodes in an attribute before it reads the URL.
307
+ * Named references are limited to the ones that can help spell out a scheme.
308
+ */
309
+ const CHARACTER_REFERENCE_PATTERN = /&#[xX]([\da-fA-F]+);?|&#(\d+);?|&(colon|Tab|NewLine);/g;
310
+ const NAMED_CHARACTER_REFERENCES = {
311
+ colon: ':',
312
+ Tab: '\t',
313
+ NewLine: '\n',
314
+ };
315
+ const fromCodePoint = (codePoint) => codePoint > 0 && codePoint <= 0x10ffff
316
+ ? String.fromCodePoint(codePoint)
317
+ : '�';
318
+ const decodeCharacterReferences = (value) => value.replace(CHARACTER_REFERENCE_PATTERN, (_match, hex, decimal, name) => {
319
+ if (hex) {
320
+ return fromCodePoint(Number.parseInt(hex, 16));
321
+ }
322
+ if (decimal) {
323
+ return fromCodePoint(Number.parseInt(decimal, 10));
324
+ }
325
+ return NAMED_CHARACTER_REFERENCES[name ?? ''] ?? '';
326
+ });
327
+ /**
328
+ * Reads a URL the way the browser does before it looks for a scheme: character references
329
+ * are decoded, tabs and newlines are removed, and leading spaces and control characters
330
+ * are ignored.
331
+ */
332
+ const normalizeUrl = (value) => {
333
+ const decoded = decodeCharacterReferences(value).replace(/[\t\n\r]/g, '');
334
+ let start = 0;
335
+ while (start < decoded.length && decoded.charCodeAt(start) <= 0x20) {
336
+ start++;
337
+ }
338
+ return decoded.slice(start);
339
+ };
340
+ const normalizeScheme = (scheme) => scheme.trim().toLowerCase().replace(/:$/, '');
341
+ /**
342
+ * Returns `url` unchanged when it is safe to place in an `href` or `src` attribute, and `#`
343
+ * when it is not.
344
+ *
345
+ * Relative URLs, `http:`, `https:`, `mailto:`, `tel:`, `sms:` and `data:image/` URLs are safe,
346
+ * along with any scheme passed in `options.schemes`. Every other scheme, such as `javascript:`,
347
+ * is blocked, including when it is written in mixed case, has leading spaces or contains tabs,
348
+ * newlines or character references.
349
+ *
350
+ * ```js
351
+ * html`<a href="${safeUrl(item.url)}">${item.title}</a>`;
352
+ * html`<a href="${safeUrl(item.appUrl, { schemes: ['myapp'] })}">Open in app</a>`;
353
+ * ```
354
+ */
355
+ const safeUrl = (url, options) => {
356
+ if (url === undefined || url === null) {
357
+ return '';
358
+ }
359
+ const value = String(url);
360
+ const normalizedUrl = normalizeUrl(value);
361
+ const scheme = normalizedUrl.match(SCHEME_PATTERN)?.[1]?.toLowerCase();
362
+ if (!scheme) {
363
+ return value;
364
+ }
365
+ if (ALLOWED_SCHEMES.includes(scheme) ||
366
+ options?.schemes?.some((allowed) => normalizeScheme(allowed) === scheme)) {
367
+ return value;
368
+ }
369
+ if (scheme === 'data' && DATA_IMAGE_PATTERN.test(normalizedUrl)) {
370
+ return value;
371
+ }
372
+ return BLOCKED_URL;
373
+ };
374
+
375
+ export { html as h, safeUrl as s };
376
+ //# sourceMappingURL=safeUrl.js.map
377
+
378
+ //# sourceMappingURL=safeUrl.js.map
@@ -0,0 +1 @@
1
+ {"file":"safeUrl.js","mappings":"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","names":["DOMPurify"],"sources":["src/utils/html.ts","src/utils/safeUrl.ts"],"sourcesContent":["import DOMPurify from 'dompurify';\n\nimport type { TemplateHtml } from '@types';\n\n/**\n * States of a small HTML tokenizer, used to find where each value lands in the markup. The\n * states from `TAG_OPEN` to `AFTER_ATTRIBUTE_NAME` are inside a tag but not in a value.\n */\nconst TEXT = 0;\nconst TAG_OPEN = 1;\nconst END_TAG_OPEN = 2;\nconst TAG_NAME = 3;\nconst BEFORE_ATTRIBUTE_NAME = 4;\nconst ATTRIBUTE_NAME = 5;\nconst AFTER_ATTRIBUTE_NAME = 6;\nconst BEFORE_VALUE = 7;\nconst DOUBLE_QUOTED_VALUE = 8;\nconst SINGLE_QUOTED_VALUE = 9;\nconst UNQUOTED_VALUE = 10;\nconst MARKUP_DECLARATION = 11;\nconst COMMENT = 12;\nconst BOGUS_COMMENT = 13;\nconst RAW_TEXT = 14;\n\n/**\n * Elements whose content is read as text up to their end tag.\n */\nconst RAW_TEXT_ELEMENTS = [\n 'iframe',\n 'noembed',\n 'noframes',\n 'noscript',\n 'script',\n 'style',\n 'textarea',\n 'title',\n 'xmp',\n];\n\nconst SPACE_PATTERN = /[\\t\\n\\f\\r ]/;\nconst LETTER_PATTERN = /[a-z]/i;\n\n/**\n * Characters that cannot appear as is in an unquoted attribute value.\n */\nconst UNQUOTED_VALUE_SPECIAL_PATTERN = /[\\s\"'=<>`]/g;\n\ntype Tokenizer = {\n state: number;\n position: number;\n tagName: string;\n isEndTag: boolean;\n commentStart: number;\n};\n\nconst createTokenizer = (state: number): Tokenizer => ({\n state,\n position: 0,\n tagName: '',\n isEndTag: false,\n commentStart: 0,\n});\n\n/**\n * Reads the markup from where the last call stopped, so `tokenizer.state` tells where the next\n * character lands. It follows the HTML tokenizer closely enough to tell text, tags and\n * attribute values apart, including after comments and inside elements such as `<style>`.\n * It does not follow the tree the browser builds, so inside `<svg>` or `<math>`, elements such\n * as `<style>` and `<title>` are still read as text.\n */\nconst tokenize = (tokenizer: Tokenizer, markup: string) => {\n while (tokenizer.position < markup.length) {\n const index = tokenizer.position++;\n const character = markup.charAt(index);\n const isSpace = SPACE_PATTERN.test(character);\n\n switch (tokenizer.state) {\n case TEXT:\n if (character === '<') {\n tokenizer.state = TAG_OPEN;\n }\n break;\n case TAG_OPEN:\n case END_TAG_OPEN:\n if (LETTER_PATTERN.test(character)) {\n tokenizer.isEndTag = tokenizer.state === END_TAG_OPEN;\n tokenizer.tagName = character;\n tokenizer.state = TAG_NAME;\n } else if (tokenizer.state === END_TAG_OPEN) {\n tokenizer.state = character === '>' ? TEXT : BOGUS_COMMENT;\n } else if (character === '/') {\n tokenizer.state = END_TAG_OPEN;\n } else if (character === '!') {\n tokenizer.state = MARKUP_DECLARATION;\n } else if (character === '?') {\n tokenizer.state = BOGUS_COMMENT;\n } else {\n // The `<` is text, so read this character again as text.\n tokenizer.state = TEXT;\n tokenizer.position = index;\n }\n break;\n case TAG_NAME:\n if (isSpace || character === '/') {\n tokenizer.state = BEFORE_ATTRIBUTE_NAME;\n } else if (character === '>') {\n endTag(tokenizer);\n } else {\n tokenizer.tagName += character;\n }\n break;\n case BEFORE_ATTRIBUTE_NAME:\n if (character === '>') {\n endTag(tokenizer);\n } else if (!isSpace && character !== '/') {\n tokenizer.state = ATTRIBUTE_NAME;\n }\n break;\n case ATTRIBUTE_NAME:\n case AFTER_ATTRIBUTE_NAME:\n if (character === '>') {\n endTag(tokenizer);\n } else if (character === '=') {\n tokenizer.state = BEFORE_VALUE;\n } else if (character === '/') {\n tokenizer.state = BEFORE_ATTRIBUTE_NAME;\n } else if (isSpace) {\n tokenizer.state = AFTER_ATTRIBUTE_NAME;\n } else {\n tokenizer.state = ATTRIBUTE_NAME;\n }\n break;\n case BEFORE_VALUE:\n if (character === '>') {\n endTag(tokenizer);\n } else if (character === '\"') {\n tokenizer.state = DOUBLE_QUOTED_VALUE;\n } else if (character === \"'\") {\n tokenizer.state = SINGLE_QUOTED_VALUE;\n } else if (!isSpace) {\n tokenizer.state = UNQUOTED_VALUE;\n }\n break;\n case DOUBLE_QUOTED_VALUE:\n case SINGLE_QUOTED_VALUE:\n if (\n character === (tokenizer.state === DOUBLE_QUOTED_VALUE ? '\"' : \"'\")\n ) {\n tokenizer.state = BEFORE_ATTRIBUTE_NAME;\n }\n break;\n case UNQUOTED_VALUE:\n if (character === '>') {\n endTag(tokenizer);\n } else if (isSpace) {\n tokenizer.state = BEFORE_ATTRIBUTE_NAME;\n }\n break;\n case MARKUP_DECLARATION:\n if (markup.startsWith('--', index)) {\n tokenizer.state = COMMENT;\n tokenizer.position = index + 2;\n tokenizer.commentStart = index + 2;\n } else {\n tokenizer.state = BOGUS_COMMENT;\n tokenizer.position = index;\n }\n break;\n case COMMENT: {\n // A comment ends at `-->` or `--!>`, and `<!-->` and `<!--->` end at once.\n const comment = markup.slice(\n Math.max(tokenizer.commentStart, index - 3),\n index,\n );\n if (\n character === '>' &&\n (index - tokenizer.commentStart < 2\n ? /^-?$/.test(comment)\n : /--!?$/.test(comment))\n ) {\n tokenizer.state = TEXT;\n }\n break;\n }\n case BOGUS_COMMENT:\n if (character === '>') {\n tokenizer.state = TEXT;\n }\n break;\n case RAW_TEXT: {\n const endTagPattern = new RegExp(\n `</${tokenizer.tagName}[\\\\t\\\\n\\\\f\\\\r />]`,\n 'gi',\n );\n endTagPattern.lastIndex = index;\n const match = endTagPattern.exec(markup);\n\n if (!match) {\n // Read the end again next time, in case the end tag is only partly written yet.\n tokenizer.position = Math.max(\n index,\n markup.length - tokenizer.tagName.length - 2,\n );\n return;\n }\n\n tokenizer.state = TAG_NAME;\n tokenizer.isEndTag = true;\n tokenizer.position = match.index + tokenizer.tagName.length + 2;\n break;\n }\n }\n }\n};\n\nconst endTag = (tokenizer: Tokenizer) => {\n const tagName = tokenizer.tagName.toLowerCase();\n\n if (!tokenizer.isEndTag && RAW_TEXT_ELEMENTS.includes(tagName)) {\n tokenizer.state = RAW_TEXT;\n tokenizer.tagName = tagName;\n } else {\n tokenizer.state = TEXT;\n }\n};\n\nconst encodeCharacter = (character: string) => `&#${character.charCodeAt(0)};`;\n\nconst isTagState = (state: number) =>\n state >= TAG_OPEN && state <= AFTER_ATTRIBUTE_NAME;\n\nconst isValueState = (state: number) =>\n state >= BEFORE_VALUE && state <= UNQUOTED_VALUE;\n\n/**\n * Makes a value safe for where it lands in the markup. With more than one state, the markup\n * may be read in more than one way, so the value is made safe for each of them.\n */\nconst placeValue = (value: string, states: number[]) => {\n if (states.every(isTagState)) {\n return value;\n }\n\n if (!states.some(isValueState)) {\n return value && DOMPurify.sanitize(value);\n }\n\n let escaped = value;\n\n for (const state of states) {\n if (state === DOUBLE_QUOTED_VALUE) {\n escaped = escaped.replace(/\"/g, '&quot;');\n } else if (state === SINGLE_QUOTED_VALUE) {\n escaped = escaped.replace(/'/g, '&#39;');\n } else if (isValueState(state)) {\n escaped = escaped.replace(\n UNQUOTED_VALUE_SPECIAL_PATTERN,\n encodeCharacter,\n );\n }\n }\n\n if (!states.every(isValueState)) {\n // The value may be read as text too, so it must not start a tag.\n return escaped.replace(/</g, '&lt;');\n }\n\n // With no value, the next attribute would be read as this attribute's value.\n return escaped || (states.includes(BEFORE_VALUE) ? '\"\"' : '');\n};\n\n/**\n * This allows you to parse a template string with a function.\n *\n * Each value is made safe for where it lands in the markup:\n * - In text, the value is sanitized with DOMPurify, so it can contain markup but no scripts.\n * DOMPurify also removes URLs it does not allow, so a link with a custom scheme that `safeUrl`\n * allowed loses its `href` when its markup is placed as a value in text, as in a list built\n * from nested `html` calls. Write such links in the template's own markup instead.\n * - In a quoted attribute value, the quote that would end the value is escaped. The browser\n * decodes it again, so quotes display as given. Character references in the value, such as\n * `&amp;`, are decoded by the browser as before.\n * - In an unquoted attribute value, spaces, quotes and `=<>` are escaped.\n * - Inside a tag but not in an attribute value, such as `<a ${attributes}>`, the value is placed\n * as is. Use this only for attributes the template writes itself, such as the output of a\n * nested `html` call, never for indexed data.\n *\n * A template can also be a list of attributes, such as `aria-label=\"${label}\"`, that another\n * template places inside a tag. Until its first tag ends, a value that could be in an attribute\n * value is escaped for that attribute, and `<` is escaped so it cannot start a tag either.\n *\n * Escaping keeps a value inside its attribute but does not make every attribute safe. A value in\n * an event handler such as `onclick` still runs as script, and a value in `style` still applies\n * as CSS. URLs from indexed data should go through `safeUrl` before they are placed in an\n * `href` or `src`.\n */\nexport const html: TemplateHtml = (strings, ...values) => {\n const tokenizer = createTokenizer(TEXT);\n // A template can also be a list of attributes that a parent template places inside a tag,\n // so until the two readings meet, its values are made safe for both.\n let attributeTokenizer: Tokenizer | undefined = createTokenizer(\n BEFORE_ATTRIBUTE_NAME,\n );\n let result = strings[0] ?? '';\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i];\n\n tokenize(tokenizer, result);\n\n if (attributeTokenizer) {\n tokenize(attributeTokenizer, result);\n\n if (tokenizer.state === TEXT && attributeTokenizer.state === TEXT) {\n attributeTokenizer = undefined;\n }\n }\n\n result +=\n placeValue(\n value || value === 0 ? String(value) : '',\n attributeTokenizer\n ? [tokenizer.state, attributeTokenizer.state]\n : [tokenizer.state],\n ) + (strings[i + 1] ?? '');\n }\n\n return result;\n};\n","import type { SafeUrl } from '@types';\n\n/**\n * Schemes that are always allowed. `data:` URLs are allowed separately, for images only.\n */\nconst ALLOWED_SCHEMES = ['http', 'https', 'mailto', 'tel', 'sms'];\n\n/**\n * Returned in place of a URL that is not allowed.\n */\nconst BLOCKED_URL = '#';\n\n/**\n * A scheme is only recognized when its `:` comes before any `/`, `?` or `#`.\n */\nconst SCHEME_PATTERN = /^([a-z][a-z\\d+.-]*):/i;\n\nconst DATA_IMAGE_PATTERN = /^data:image\\//i;\n\n/**\n * Character references the browser decodes in an attribute before it reads the URL.\n * Named references are limited to the ones that can help spell out a scheme.\n */\nconst CHARACTER_REFERENCE_PATTERN =\n /&#[xX]([\\da-fA-F]+);?|&#(\\d+);?|&(colon|Tab|NewLine);/g;\n\nconst NAMED_CHARACTER_REFERENCES: Record<string, string> = {\n colon: ':',\n Tab: '\\t',\n NewLine: '\\n',\n};\n\nconst fromCodePoint = (codePoint: number) =>\n codePoint > 0 && codePoint <= 0x10ffff\n ? String.fromCodePoint(codePoint)\n : '�';\n\nconst decodeCharacterReferences = (value: string) =>\n value.replace(\n CHARACTER_REFERENCE_PATTERN,\n (_match, hex?: string, decimal?: string, name?: string) => {\n if (hex) {\n return fromCodePoint(Number.parseInt(hex, 16));\n }\n if (decimal) {\n return fromCodePoint(Number.parseInt(decimal, 10));\n }\n return NAMED_CHARACTER_REFERENCES[name ?? ''] ?? '';\n },\n );\n\n/**\n * Reads a URL the way the browser does before it looks for a scheme: character references\n * are decoded, tabs and newlines are removed, and leading spaces and control characters\n * are ignored.\n */\nconst normalizeUrl = (value: string) => {\n const decoded = decodeCharacterReferences(value).replace(/[\\t\\n\\r]/g, '');\n let start = 0;\n\n while (start < decoded.length && decoded.charCodeAt(start) <= 0x20) {\n start++;\n }\n\n return decoded.slice(start);\n};\n\nconst normalizeScheme = (scheme: string) =>\n scheme.trim().toLowerCase().replace(/:$/, '');\n\n/**\n * Returns `url` unchanged when it is safe to place in an `href` or `src` attribute, and `#`\n * when it is not.\n *\n * Relative URLs, `http:`, `https:`, `mailto:`, `tel:`, `sms:` and `data:image/` URLs are safe,\n * along with any scheme passed in `options.schemes`. Every other scheme, such as `javascript:`,\n * is blocked, including when it is written in mixed case, has leading spaces or contains tabs,\n * newlines or character references.\n *\n * ```js\n * html`<a href=\"${safeUrl(item.url)}\">${item.title}</a>`;\n * html`<a href=\"${safeUrl(item.appUrl, { schemes: ['myapp'] })}\">Open in app</a>`;\n * ```\n */\nexport const safeUrl: SafeUrl = (url, options) => {\n if (url === undefined || url === null) {\n return '';\n }\n\n const value = String(url);\n const normalizedUrl = normalizeUrl(value);\n const scheme = normalizedUrl.match(SCHEME_PATTERN)?.[1]?.toLowerCase();\n\n if (!scheme) {\n return value;\n }\n\n if (\n ALLOWED_SCHEMES.includes(scheme) ||\n options?.schemes?.some((allowed) => normalizeScheme(allowed) === scheme)\n ) {\n return value;\n }\n\n if (scheme === 'data' && DATA_IMAGE_PATTERN.test(normalizedUrl)) {\n return value;\n }\n\n return BLOCKED_URL;\n};\n"],"version":3}
@@ -1,4 +1,4 @@
1
- import { S as SearchcraftPopoverListItemAd, d as defineCustomElement$1 } from './searchcraft-ad2.js?scv=0.15.0';
1
+ import { S as SearchcraftPopoverListItemAd, d as defineCustomElement$1 } from './searchcraft-ad2.js?scv=0.16.0';
2
2
 
3
3
  const SearchcraftAd = SearchcraftPopoverListItemAd;
4
4
  const defineCustomElement = defineCustomElement$1;
@@ -1,7 +1,7 @@
1
- import { p as proxyCustomElement, t as transformTag, H, h } from './index2.js?scv=0.15.0';
2
- import { c as classNames } from './index3.js?scv=0.15.0';
3
- import { r as registry } from './CoreInstanceRegistry.js?scv=0.15.0';
4
- import { h as html } from './html.js?scv=0.15.0';
1
+ import { p as proxyCustomElement, t as transformTag, H, h } from './index2.js?scv=0.16.0';
2
+ import { c as classNames } from './index3.js?scv=0.16.0';
3
+ import { r as registry } from './CoreInstanceRegistry.js?scv=0.16.0';
4
+ import { s as safeUrl, h as html } from './safeUrl.js?scv=0.16.0';
5
5
 
6
6
  const urlAlphabet =
7
7
  'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
@@ -146,6 +146,7 @@ const SearchcraftPopoverListItemAd = /*@__PURE__*/ proxyCustomElement(class Sear
146
146
  if (this.core?.config?.admAdConfig?.template) {
147
147
  templateHtml = this.core?.config?.admAdConfig.template(item.admAd, {
148
148
  html,
149
+ safeUrl,
149
150
  });
150
151
  }
151
152
  return (h("div", { class: 'searchcraft-ad searchcraft-adm-ad', "data-searchcraft-ad-container-id": this.adContainerId, id: `searchcraft-adm-ad-${this.adContainerId}`, innerHTML: templateHtml }));
@@ -158,7 +159,7 @@ const SearchcraftPopoverListItemAd = /*@__PURE__*/ proxyCustomElement(class Sear
158
159
  templateHtml = templateRenderFunction({
159
160
  searchTerm: this.searchTerm || '',
160
161
  adContainerId: this.adContainerId,
161
- }, { html });
162
+ }, { html, safeUrl });
162
163
  }
163
164
  return (h("div", { class: 'searchcraft-ad searchcraft-custom-ad', id: containerId, "data-searchcraft-ad-container-id": this.adContainerId, innerHTML: templateHtml }));
164
165
  }
@@ -1 +1 @@
1
- {"file":"searchcraft-ad2.js","mappings":"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","names":["scopedUrlAlphabet","__stencil_proxyCustomElement","HTMLElement"],"sources":["node_modules/nanoid/url-alphabet/index.js","node_modules/nanoid/index.browser.js","src/components/searchcraft-ad/searchcraft-ad.tsx"],"sourcesContent":["export const urlAlphabet =\n 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n","/* @ts-self-types=\"./index.d.ts\" */\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'\nexport { urlAlphabet } from './url-alphabet/index.js'\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n let mask = (2 << Math.log2(alphabet.length - 1)) - 1\n let step = -~((1.6 * mask * defaultSize) / alphabet.length)\n return (size = defaultSize) => {\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let j = step | 0\n while (j--) {\n id += alphabet[bytes[j] & mask] || ''\n if (id.length >= size) return id\n }\n }\n }\n}\nexport let customAlphabet = (alphabet, size = 21) =>\n customRandom(alphabet, size | 0, random)\nexport let nanoid = (size = 21) => {\n let id = ''\n let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))\n while (size--) {\n id += scopedUrlAlphabet[bytes[size] & 63]\n }\n return id\n}\n","import { Component, Element, Prop, State, h } from '@stencil/core';\nimport type { ADMClientResponseItem, AdClientResponseItem } from '@types';\nimport classNames from 'classnames';\nimport { nanoid } from 'nanoid';\n\nimport type { SearchcraftState } from '@store';\n\nimport type { SearchcraftCore } from '@classes';\nimport { registry } from '@classes/CoreInstanceRegistry';\nimport { html } from '@utils';\n\n/**\n * An inline ad meant to be rendered in a list of search results.\n *\n * @internal\n */\n@Component({\n tag: 'searchcraft-ad',\n shadow: false,\n})\nexport class SearchcraftPopoverListItemAd {\n /**\n * The id of the Searchcraft instance that this component should use.\n */\n @Prop() searchcraftId?: string;\n @Prop() adSource: 'Custom' | 'Nativo' | 'adMarketplace' = 'Custom';\n @Prop() adClientResponseItem?: AdClientResponseItem;\n\n /**\n * Where the ad is being rendered within the search results div.\n * Lifecycle behavior differs for ads being rendered in different positions,\n * so we need to be able to handle all of those cases.\n */\n @Prop() renderPosition: 'interstitial' | 'top' | 'bottom' = 'interstitial';\n\n @State() searchTerm?: string;\n @State() isSearchInProgress = false;\n @State() searchResultCount = 0;\n @Element() hostElement?: HTMLElement;\n\n private core?: SearchcraftCore;\n\n private intersectionObserver?: IntersectionObserver;\n private storeUnsubscribe?: () => void;\n private cleanupCore?: () => void;\n private adContainerRenderedTimeout?: NodeJS.Timeout;\n private isComponentConnected = false;\n private timeTaken?: number;\n\n @State() adContainerId = '';\n\n /**\n * Handles when an ad container is first rendered.\n * Core emits an ad_container_rendered event and performs ad client side effects\n *\n */\n handleAdRendered() {\n this.adContainerId = nanoid();\n\n if (this.isComponentConnected && this.searchResultCount > 0) {\n clearTimeout(this.adContainerRenderedTimeout);\n this.adContainerRenderedTimeout = setTimeout(() => {\n this.core?.handleAdContainerRendered({\n adClientResponseItem: this.adClientResponseItem,\n adContainerId: this.adContainerId,\n searchTerm: this.searchTerm || '',\n });\n }, this.core?.config?.customAdConfig?.adContainerRenderedDebounceDelay ||\n 300);\n }\n }\n\n handleAdViewed() {\n this.core?.handleAdContainerViewed({\n adClientResponseItem: this.adClientResponseItem,\n adContainerId: this.adContainerId,\n searchTerm: this.searchTerm || '',\n });\n }\n\n /**\n * Things to do when there's a new incoming search request.\n */\n handleNewIncomingSearchRequest(state: SearchcraftState) {\n const requestProperties = state.searchClientRequestProperties;\n if (requestProperties && typeof requestProperties === 'object') {\n this.searchTerm = requestProperties.searchTerm;\n }\n\n this.searchResultCount = state.searchClientResponseItems.length;\n\n this.handleAdRendered();\n\n this.startIntersectionObserver();\n }\n\n onCoreAvailable(core: SearchcraftCore) {\n const currentState = core.store.getState();\n\n this.isComponentConnected = true;\n this.core = currentState.core;\n this.isSearchInProgress = currentState.isSearchInProgress;\n this.searchResultCount = currentState.searchClientResponseItems.length;\n this.timeTaken = currentState.searchResponseTimeTaken;\n\n const requestProperties = currentState.searchClientRequestProperties;\n if (requestProperties && typeof requestProperties === 'object') {\n this.searchTerm = requestProperties.searchTerm;\n }\n\n /**\n * Interstial ads have a different lifecycle, where we need handle an incoming search\n * request immediately, because they are rendered alongside the search results.\n */\n if (this.renderPosition === 'interstitial') {\n this.handleNewIncomingSearchRequest(currentState);\n }\n\n // Subscribes to store changes (for search term).\n this.storeUnsubscribe = core.store.subscribe((state) => {\n if (this.timeTaken !== state.searchResponseTimeTaken) {\n this.handleNewIncomingSearchRequest(state);\n }\n this.timeTaken = state.searchResponseTimeTaken;\n this.isSearchInProgress = state.isSearchInProgress;\n });\n }\n\n connectedCallback() {\n this.cleanupCore = registry.useCoreInstance(\n this.searchcraftId,\n this.onCoreAvailable.bind(this),\n );\n }\n\n startIntersectionObserver() {\n this.intersectionObserver?.disconnect();\n /**\n * Handles when an ad container is viewable within the document,\n * Core emits an ad_container_viewed event and performs ad client side effects\n */\n if (this.hostElement) {\n this.intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n if (entry?.isIntersecting && this.searchResultCount > 0) {\n this.handleAdViewed();\n }\n },\n { threshold: 0 },\n );\n\n this.intersectionObserver.observe(this.hostElement);\n }\n }\n\n disconnectedCallback() {\n this.storeUnsubscribe?.();\n this.cleanupCore?.();\n this.intersectionObserver?.disconnect();\n this.isComponentConnected = false;\n clearTimeout(this.adContainerRenderedTimeout);\n }\n\n renderADMAd() {\n const item = this.adClientResponseItem as ADMClientResponseItem;\n\n if (!item.admAd) {\n return;\n }\n\n let templateHtml = '<p>Ad Marketplace Ad Placeholder</p>';\n\n if (this.core?.config?.admAdConfig?.template) {\n templateHtml = this.core?.config?.admAdConfig.template(item.admAd, {\n html,\n });\n }\n\n return (\n <div\n class='searchcraft-ad searchcraft-adm-ad'\n data-searchcraft-ad-container-id={this.adContainerId}\n id={`searchcraft-adm-ad-${this.adContainerId}`}\n innerHTML={templateHtml}\n />\n );\n }\n\n renderCustomAd() {\n const templateRenderFunction = this.core?.config?.customAdConfig?.template;\n const containerId = `searchcraft-custom-ad-${this.adContainerId}`;\n let templateHtml = '<p>Custom Ad Placeholder</p>';\n\n if (templateRenderFunction) {\n templateHtml = templateRenderFunction(\n {\n searchTerm: this.searchTerm || '',\n adContainerId: this.adContainerId,\n },\n { html },\n );\n }\n\n return (\n <div\n class='searchcraft-ad searchcraft-custom-ad'\n id={containerId}\n data-searchcraft-ad-container-id={this.adContainerId}\n innerHTML={templateHtml}\n />\n );\n }\n\n renderNativoAd() {\n const nativoClassName =\n this.core?.config.nativoConfig?.adClassName || 'ntv-item';\n return (\n <div\n id={`searchcraft-native-ad-${this.adContainerId}`}\n class={classNames('searchcraft-ad', nativoClassName)}\n data-searchcraft-ad-container-id={this.adContainerId}\n />\n );\n }\n\n render() {\n // Don't render ads if no search results\n if (this.searchResultCount === 0) {\n return;\n }\n\n switch (this.adSource) {\n case 'adMarketplace':\n return this.renderADMAd();\n case 'Custom':\n return this.renderCustomAd();\n case 'Nativo':\n return this.renderNativoAd();\n default:\n return;\n }\n }\n}\n"],"version":3}
1
+ {"file":"searchcraft-ad2.js","mappings":"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","names":["scopedUrlAlphabet","__stencil_proxyCustomElement","HTMLElement"],"sources":["node_modules/nanoid/url-alphabet/index.js","node_modules/nanoid/index.browser.js","src/components/searchcraft-ad/searchcraft-ad.tsx"],"sourcesContent":["export const urlAlphabet =\n 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n","/* @ts-self-types=\"./index.d.ts\" */\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'\nexport { urlAlphabet } from './url-alphabet/index.js'\nexport let random = bytes => crypto.getRandomValues(new Uint8Array(bytes))\nexport let customRandom = (alphabet, defaultSize, getRandom) => {\n let mask = (2 << Math.log2(alphabet.length - 1)) - 1\n let step = -~((1.6 * mask * defaultSize) / alphabet.length)\n return (size = defaultSize) => {\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let j = step | 0\n while (j--) {\n id += alphabet[bytes[j] & mask] || ''\n if (id.length >= size) return id\n }\n }\n }\n}\nexport let customAlphabet = (alphabet, size = 21) =>\n customRandom(alphabet, size | 0, random)\nexport let nanoid = (size = 21) => {\n let id = ''\n let bytes = crypto.getRandomValues(new Uint8Array((size |= 0)))\n while (size--) {\n id += scopedUrlAlphabet[bytes[size] & 63]\n }\n return id\n}\n","import { Component, Element, Prop, State, h } from '@stencil/core';\nimport type { ADMClientResponseItem, AdClientResponseItem } from '@types';\nimport classNames from 'classnames';\nimport { nanoid } from 'nanoid';\n\nimport type { SearchcraftState } from '@store';\n\nimport type { SearchcraftCore } from '@classes';\nimport { registry } from '@classes/CoreInstanceRegistry';\nimport { html, safeUrl } from '@utils';\n\n/**\n * An inline ad meant to be rendered in a list of search results.\n *\n * @internal\n */\n@Component({\n tag: 'searchcraft-ad',\n shadow: false,\n})\nexport class SearchcraftPopoverListItemAd {\n /**\n * The id of the Searchcraft instance that this component should use.\n */\n @Prop() searchcraftId?: string;\n @Prop() adSource: 'Custom' | 'Nativo' | 'adMarketplace' = 'Custom';\n @Prop() adClientResponseItem?: AdClientResponseItem;\n\n /**\n * Where the ad is being rendered within the search results div.\n * Lifecycle behavior differs for ads being rendered in different positions,\n * so we need to be able to handle all of those cases.\n */\n @Prop() renderPosition: 'interstitial' | 'top' | 'bottom' = 'interstitial';\n\n @State() searchTerm?: string;\n @State() isSearchInProgress = false;\n @State() searchResultCount = 0;\n @Element() hostElement?: HTMLElement;\n\n private core?: SearchcraftCore;\n\n private intersectionObserver?: IntersectionObserver;\n private storeUnsubscribe?: () => void;\n private cleanupCore?: () => void;\n private adContainerRenderedTimeout?: NodeJS.Timeout;\n private isComponentConnected = false;\n private timeTaken?: number;\n\n @State() adContainerId = '';\n\n /**\n * Handles when an ad container is first rendered.\n * Core emits an ad_container_rendered event and performs ad client side effects\n *\n */\n handleAdRendered() {\n this.adContainerId = nanoid();\n\n if (this.isComponentConnected && this.searchResultCount > 0) {\n clearTimeout(this.adContainerRenderedTimeout);\n this.adContainerRenderedTimeout = setTimeout(() => {\n this.core?.handleAdContainerRendered({\n adClientResponseItem: this.adClientResponseItem,\n adContainerId: this.adContainerId,\n searchTerm: this.searchTerm || '',\n });\n }, this.core?.config?.customAdConfig?.adContainerRenderedDebounceDelay ||\n 300);\n }\n }\n\n handleAdViewed() {\n this.core?.handleAdContainerViewed({\n adClientResponseItem: this.adClientResponseItem,\n adContainerId: this.adContainerId,\n searchTerm: this.searchTerm || '',\n });\n }\n\n /**\n * Things to do when there's a new incoming search request.\n */\n handleNewIncomingSearchRequest(state: SearchcraftState) {\n const requestProperties = state.searchClientRequestProperties;\n if (requestProperties && typeof requestProperties === 'object') {\n this.searchTerm = requestProperties.searchTerm;\n }\n\n this.searchResultCount = state.searchClientResponseItems.length;\n\n this.handleAdRendered();\n\n this.startIntersectionObserver();\n }\n\n onCoreAvailable(core: SearchcraftCore) {\n const currentState = core.store.getState();\n\n this.isComponentConnected = true;\n this.core = currentState.core;\n this.isSearchInProgress = currentState.isSearchInProgress;\n this.searchResultCount = currentState.searchClientResponseItems.length;\n this.timeTaken = currentState.searchResponseTimeTaken;\n\n const requestProperties = currentState.searchClientRequestProperties;\n if (requestProperties && typeof requestProperties === 'object') {\n this.searchTerm = requestProperties.searchTerm;\n }\n\n /**\n * Interstial ads have a different lifecycle, where we need handle an incoming search\n * request immediately, because they are rendered alongside the search results.\n */\n if (this.renderPosition === 'interstitial') {\n this.handleNewIncomingSearchRequest(currentState);\n }\n\n // Subscribes to store changes (for search term).\n this.storeUnsubscribe = core.store.subscribe((state) => {\n if (this.timeTaken !== state.searchResponseTimeTaken) {\n this.handleNewIncomingSearchRequest(state);\n }\n this.timeTaken = state.searchResponseTimeTaken;\n this.isSearchInProgress = state.isSearchInProgress;\n });\n }\n\n connectedCallback() {\n this.cleanupCore = registry.useCoreInstance(\n this.searchcraftId,\n this.onCoreAvailable.bind(this),\n );\n }\n\n startIntersectionObserver() {\n this.intersectionObserver?.disconnect();\n /**\n * Handles when an ad container is viewable within the document,\n * Core emits an ad_container_viewed event and performs ad client side effects\n */\n if (this.hostElement) {\n this.intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n if (entry?.isIntersecting && this.searchResultCount > 0) {\n this.handleAdViewed();\n }\n },\n { threshold: 0 },\n );\n\n this.intersectionObserver.observe(this.hostElement);\n }\n }\n\n disconnectedCallback() {\n this.storeUnsubscribe?.();\n this.cleanupCore?.();\n this.intersectionObserver?.disconnect();\n this.isComponentConnected = false;\n clearTimeout(this.adContainerRenderedTimeout);\n }\n\n renderADMAd() {\n const item = this.adClientResponseItem as ADMClientResponseItem;\n\n if (!item.admAd) {\n return;\n }\n\n let templateHtml = '<p>Ad Marketplace Ad Placeholder</p>';\n\n if (this.core?.config?.admAdConfig?.template) {\n templateHtml = this.core?.config?.admAdConfig.template(item.admAd, {\n html,\n safeUrl,\n });\n }\n\n return (\n <div\n class='searchcraft-ad searchcraft-adm-ad'\n data-searchcraft-ad-container-id={this.adContainerId}\n id={`searchcraft-adm-ad-${this.adContainerId}`}\n innerHTML={templateHtml}\n />\n );\n }\n\n renderCustomAd() {\n const templateRenderFunction = this.core?.config?.customAdConfig?.template;\n const containerId = `searchcraft-custom-ad-${this.adContainerId}`;\n let templateHtml = '<p>Custom Ad Placeholder</p>';\n\n if (templateRenderFunction) {\n templateHtml = templateRenderFunction(\n {\n searchTerm: this.searchTerm || '',\n adContainerId: this.adContainerId,\n },\n { html, safeUrl },\n );\n }\n\n return (\n <div\n class='searchcraft-ad searchcraft-custom-ad'\n id={containerId}\n data-searchcraft-ad-container-id={this.adContainerId}\n innerHTML={templateHtml}\n />\n );\n }\n\n renderNativoAd() {\n const nativoClassName =\n this.core?.config.nativoConfig?.adClassName || 'ntv-item';\n return (\n <div\n id={`searchcraft-native-ad-${this.adContainerId}`}\n class={classNames('searchcraft-ad', nativoClassName)}\n data-searchcraft-ad-container-id={this.adContainerId}\n />\n );\n }\n\n render() {\n // Don't render ads if no search results\n if (this.searchResultCount === 0) {\n return;\n }\n\n switch (this.adSource) {\n case 'adMarketplace':\n return this.renderADMAd();\n case 'Custom':\n return this.renderCustomAd();\n case 'Nativo':\n return this.renderNativoAd();\n default:\n return;\n }\n }\n}\n"],"version":3}
@@ -1,4 +1,4 @@
1
- import { S as SearchcraftButton$1, d as defineCustomElement$1 } from './searchcraft-button2.js?scv=0.15.0';
1
+ import { S as SearchcraftButton$1, d as defineCustomElement$1 } from './searchcraft-button2.js?scv=0.16.0';
2
2
 
3
3
  const SearchcraftButton = SearchcraftButton$1;
4
4
  const defineCustomElement = defineCustomElement$1;
@@ -1,5 +1,5 @@
1
- import { p as proxyCustomElement, H, c as createEvent, h, F as Fragment, t as transformTag } from './index2.js?scv=0.15.0';
2
- import { c as classNames } from './index3.js?scv=0.15.0';
1
+ import { p as proxyCustomElement, H, c as createEvent, h, F as Fragment, t as transformTag } from './index2.js?scv=0.16.0';
2
+ import { c as classNames } from './index3.js?scv=0.16.0';
3
3
 
4
4
  const SearchcraftButton = /*@__PURE__*/ proxyCustomElement(class SearchcraftButton extends H {
5
5
  constructor(registerHost) {
@@ -1,4 +1,4 @@
1
- import { S as SearchcraftErrorMessage$1, d as defineCustomElement$1 } from './searchcraft-error-message2.js?scv=0.15.0';
1
+ import { S as SearchcraftErrorMessage$1, d as defineCustomElement$1 } from './searchcraft-error-message2.js?scv=0.16.0';
2
2
 
3
3
  const SearchcraftErrorMessage = SearchcraftErrorMessage$1;
4
4
  const defineCustomElement = defineCustomElement$1;
@@ -1,4 +1,4 @@
1
- import { p as proxyCustomElement, H, h, t as transformTag } from './index2.js?scv=0.15.0';
1
+ import { p as proxyCustomElement, H, h, t as transformTag } from './index2.js?scv=0.16.0';
2
2
 
3
3
  const SearchcraftErrorMessage = /*@__PURE__*/ proxyCustomElement(class SearchcraftErrorMessage extends H {
4
4
  constructor(registerHost) {
@@ -1,4 +1,4 @@
1
- import { S as SearchcraftFacetList$1, d as defineCustomElement$1 } from './searchcraft-facet-list2.js?scv=0.15.0';
1
+ import { S as SearchcraftFacetList$1, d as defineCustomElement$1 } from './searchcraft-facet-list2.js?scv=0.16.0';
2
2
 
3
3
  const SearchcraftFacetList = SearchcraftFacetList$1;
4
4
  const defineCustomElement = defineCustomElement$1;
@@ -1,5 +1,5 @@
1
- import { p as proxyCustomElement, H, c as createEvent, h, t as transformTag } from './index2.js?scv=0.15.0';
2
- import { r as registry } from './CoreInstanceRegistry.js?scv=0.15.0';
1
+ import { p as proxyCustomElement, H, c as createEvent, h, t as transformTag } from './index2.js?scv=0.16.0';
2
+ import { r as registry } from './CoreInstanceRegistry.js?scv=0.16.0';
3
3
  import './purify.es.js';
4
4
 
5
5
  /**
@@ -1,8 +1,8 @@
1
- import { p as proxyCustomElement, H, h, t as transformTag } from './index2.js?scv=0.15.0';
2
- import { r as registry } from './CoreInstanceRegistry.js?scv=0.15.0';
3
- import { d as defineCustomElement$4 } from './searchcraft-facet-list2.js?scv=0.15.0';
4
- import { d as defineCustomElement$3 } from './searchcraft-slider2.js?scv=0.15.0';
5
- import { d as defineCustomElement$2 } from './searchcraft-toggle-button2.js?scv=0.15.0';
1
+ import { p as proxyCustomElement, H, h, t as transformTag } from './index2.js?scv=0.16.0';
2
+ import { r as registry } from './CoreInstanceRegistry.js?scv=0.16.0';
3
+ import { d as defineCustomElement$4 } from './searchcraft-facet-list2.js?scv=0.16.0';
4
+ import { d as defineCustomElement$3 } from './searchcraft-slider2.js?scv=0.16.0';
5
+ import { d as defineCustomElement$2 } from './searchcraft-toggle-button2.js?scv=0.16.0';
6
6
 
7
7
  const SearchcraftFilterPanel$1 = /*@__PURE__*/ proxyCustomElement(class SearchcraftFilterPanel extends H {
8
8
  constructor(registerHost) {
@@ -1,4 +1,4 @@
1
- import { S as SearchcraftInputForm$1, d as defineCustomElement$1 } from './searchcraft-input-form2.js?scv=0.15.0';
1
+ import { S as SearchcraftInputForm$1, d as defineCustomElement$1 } from './searchcraft-input-form2.js?scv=0.16.0';
2
2
 
3
3
  const SearchcraftInputForm = SearchcraftInputForm$1;
4
4
  const defineCustomElement = defineCustomElement$1;