algolia-experiences 1.0.0 → 1.0.2

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/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "algolia-experiences",
3
3
  "license": "MIT",
4
- "version": "1.0.0",
4
+ "version": "1.0.2",
5
5
  "main": "src/index.ts",
6
6
  "jsdelivr": "dist/algolia-experiences.production.min.js",
7
7
  "unpkg": "dist/algolia-experiences.production.min.js",
8
+ "files": [
9
+ "dist"
10
+ ],
8
11
  "dependencies": {
9
12
  "instantsearch.js": "^4.73.2",
10
13
  "algoliasearch": "^4.23.2"
package/rollup.config.js DELETED
@@ -1,76 +0,0 @@
1
- import babel from 'rollup-plugin-babel';
2
- import commonjs from 'rollup-plugin-commonjs';
3
- import filesize from 'rollup-plugin-filesize';
4
- import resolve from 'rollup-plugin-node-resolve';
5
- import replace from 'rollup-plugin-replace';
6
- import { uglify } from 'rollup-plugin-uglify';
7
-
8
- import packageJson from '../../package.json';
9
-
10
- const version =
11
- process.env.NODE_ENV === 'production'
12
- ? packageJson.version
13
- : `UNRELEASED (${new Date().toUTCString()})`;
14
- const algolia = '© Algolia, Inc. and contributors; MIT License';
15
- const link = 'https://github.com/algolia/instantsearch';
16
- const license = `/*! algolia-experiences ${version} | ${algolia} | ${link} */`;
17
-
18
- const plugins = [
19
- resolve({
20
- browser: true,
21
- preferBuiltins: false,
22
- extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'],
23
- }),
24
- babel({
25
- rootMode: 'upward',
26
- runtimeHelpers: true,
27
- exclude: /node_modules|algoliasearch-helper/,
28
- extensions: ['.js', '.ts', '.tsx'],
29
- }),
30
- commonjs(),
31
- filesize({
32
- showMinifiedSize: false,
33
- showGzippedSize: true,
34
- }),
35
- ];
36
-
37
- const createConfiguration = ({ mode, filename }) => ({
38
- input: 'src/index.ts',
39
- output: {
40
- file: `dist/${filename}`,
41
- name: 'instantsearch',
42
- format: 'umd',
43
- banner: license,
44
- sourcemap: true,
45
- },
46
- onwarn(warning, warn) {
47
- if (warning.code === 'CIRCULAR_DEPENDENCY')
48
- throw new Error(warning.message);
49
-
50
- warn(warning);
51
- },
52
- plugins: [
53
- ...plugins,
54
- replace({
55
- __DEV__: mode === 'development',
56
- 'process.env.NODE_ENV': JSON.stringify('production'),
57
- }),
58
- mode === 'production' &&
59
- uglify({
60
- output: {
61
- preamble: license,
62
- },
63
- }),
64
- ].filter(Boolean),
65
- });
66
-
67
- export default [
68
- createConfiguration({
69
- mode: 'development',
70
- filename: 'algolia-experiences.development.js',
71
- }),
72
- createConfiguration({
73
- mode: 'production',
74
- filename: 'algolia-experiences.production.min.js',
75
- }),
76
- ];
@@ -1,130 +0,0 @@
1
- import type { Configuration } from './types';
2
-
3
- const CONFIGURATION_OBJECT: Record<string, Configuration> = {
4
- qsdfqsdf: {
5
- id: 'qsdfqsdf',
6
- indexName: 'instant_search',
7
- children: [
8
- {
9
- type: 'ais.searchBox',
10
- parameters: {},
11
- },
12
- {
13
- type: 'columns',
14
- children: [
15
- [
16
- {
17
- type: 'ais.refinementList',
18
- parameters: {
19
- attribute: 'brand',
20
- },
21
- },
22
- ],
23
- [
24
- {
25
- type: 'ais.hits',
26
- parameters: {},
27
- children: [
28
- {
29
- type: 'div',
30
- parameters: {
31
- text: [
32
- { type: 'string', value: 'cols: ' },
33
- { type: 'highlight', path: ['name'] },
34
- ],
35
- },
36
- },
37
- ],
38
- },
39
- ],
40
- ],
41
- },
42
- {
43
- type: 'ais.configure',
44
- parameters: {
45
- hitsPerPage: 2,
46
- },
47
- },
48
- {
49
- type: 'ais.hits',
50
- parameters: {},
51
- children: [
52
- {
53
- type: 'div',
54
- parameters: {
55
- text: [
56
- { type: 'string', value: 'one: ' },
57
- { type: 'highlight', path: ['name'] },
58
- ],
59
- },
60
- },
61
- ],
62
- },
63
- ],
64
- },
65
- 'other-one': {
66
- id: 'other-one',
67
- indexName: 'instant_search',
68
- children: [
69
- {
70
- type: 'ais.configure',
71
- parameters: {
72
- hitsPerPage: 3,
73
- },
74
- },
75
- {
76
- type: 'ais.hits',
77
- parameters: {},
78
- children: [
79
- {
80
- type: 'div',
81
- parameters: {
82
- text: [
83
- { type: 'string', value: 'other: ' },
84
- { type: 'attribute', path: ['name'] },
85
- ],
86
- },
87
- },
88
- ],
89
- },
90
- {
91
- type: 'ais.pagination',
92
- parameters: {
93
- padding: 2,
94
- },
95
- },
96
- {
97
- type: 'ais.trendingItems',
98
- parameters: { limit: 4 },
99
- children: [
100
- {
101
- type: 'div',
102
- parameters: {
103
- text: [
104
- { type: 'string', value: 'trending: ' },
105
- { type: 'attribute', path: ['name'] },
106
- ],
107
- },
108
- },
109
- {
110
- type: 'image',
111
- parameters: {
112
- src: [{ type: 'attribute', path: ['image'] }],
113
- alt: [{ type: 'string', value: '' }],
114
- },
115
- },
116
- ],
117
- },
118
- ],
119
- },
120
- };
121
- const CONFIGURATION_MAP = new Map<string, Configuration>(
122
- Object.entries(CONFIGURATION_OBJECT)
123
- );
124
- const FAKE_DELAY = 1000;
125
-
126
- export function fakeFetchConfiguration(ids: string[]) {
127
- return new Promise((resolve) => setTimeout(resolve, FAKE_DELAY)).then(() =>
128
- ids.map((id) => CONFIGURATION_MAP.get(id)!).filter(Boolean)
129
- );
130
- }
@@ -1,259 +0,0 @@
1
- import algoliasearch from 'algoliasearch/lite';
2
- import InstantSearch from 'instantsearch.js/es/lib/InstantSearch';
3
- import { getPropertyByPath } from 'instantsearch.js/es/lib/utils';
4
-
5
- import { fakeFetchConfiguration } from './fake-configuration';
6
- import { widgets } from './widgets';
7
-
8
- import type {
9
- Child,
10
- Configuration,
11
- TemplateChild,
12
- TemplateText,
13
- } from './types';
14
- import type { Widget } from 'instantsearch.js';
15
-
16
- // @TODO: hook up to some way it can be set runtime, maybe query params
17
- const VERBOSE = true;
18
-
19
- declare global {
20
- interface Window {
21
- __search: InstantSearch;
22
- }
23
- }
24
-
25
- export function setupInstantSearch() {
26
- try {
27
- const settings = getSettings();
28
-
29
- const searchClient = algoliasearch(settings.appId, settings.apiKey);
30
- const search = new InstantSearch({
31
- searchClient,
32
- });
33
- window.__search = search;
34
-
35
- const elements = getElements();
36
-
37
- injectStyles();
38
-
39
- fakeFetchConfiguration([...elements.keys()]).then((configuration) => {
40
- search
41
- .addWidgets(
42
- configuration.flatMap((config) => configToIndex(config, elements))
43
- )
44
- .start();
45
- });
46
- } catch (err) {
47
- error((err as Error).message);
48
- }
49
- }
50
-
51
- function injectStyles() {
52
- const style = document.createElement('style');
53
- style.textContent = `
54
- .ais-Columns {
55
- display: grid;
56
- grid-template-columns: minmax(min-content, 200px) 1fr;
57
- }
58
- `;
59
- document.head.appendChild(style);
60
- }
61
-
62
- function getSettings(): { appId: string; apiKey: string } {
63
- const metaConfiguration = document.querySelector<HTMLMetaElement>(
64
- 'meta[name="instantsearch-configuration"]'
65
- );
66
-
67
- if (!metaConfiguration || !metaConfiguration.content) {
68
- throw new Error('No meta tag found');
69
- }
70
-
71
- const { appId, apiKey } = JSON.parse(metaConfiguration.content);
72
-
73
- if (!appId || !apiKey) {
74
- throw new Error('Missing appId or apiKey in the meta tag');
75
- }
76
-
77
- return { appId, apiKey };
78
- }
79
-
80
- function getElements() {
81
- const elements = new Map<string, HTMLElement>();
82
- document
83
- .querySelectorAll<HTMLElement>('[data-instantsearch-id]')
84
- .forEach((element) => {
85
- const id = element.dataset.instantsearchId!;
86
- elements.set(id, element);
87
- });
88
-
89
- return elements;
90
- }
91
-
92
- function configToIndex(
93
- config: Configuration,
94
- elements: Map<string, HTMLElement>
95
- ) {
96
- const container = elements.get(config.id);
97
- if (!container) {
98
- error(`Element with id ${config.id} not found`);
99
- return [];
100
- }
101
-
102
- return [
103
- widgets['ais.index']({
104
- indexName: config.indexName,
105
- indexId: config.id,
106
- }).addWidgets(
107
- config.children.flatMap((child) => childToWidget(child, container))
108
- ),
109
- ];
110
- }
111
-
112
- const hitWidgets = new Set([
113
- 'ais.hits',
114
- 'ais.infiniteHits',
115
- 'ais.frequentlyBoughtTogether',
116
- 'ais.lookingSimilar',
117
- 'ais.relatedProducts',
118
- 'ais.trendingItems',
119
- ]);
120
-
121
- function isTemplateWidget(
122
- child: Child
123
- ): child is Child & { children: TemplateChild[] } {
124
- return hitWidgets.has(child.type);
125
- }
126
-
127
- const textChildrenObject = {
128
- paragraph: 'p',
129
- div: 'div',
130
- span: 'span',
131
- h2: 'h2',
132
- };
133
- const textChildren = new Map(Object.entries(textChildrenObject));
134
-
135
- type TextChildType = keyof typeof textChildrenObject;
136
- function isTextChild(child: TemplateChild): child is TemplateChild & {
137
- type: TextChildType;
138
- } {
139
- return textChildren.has(child.type as any);
140
- }
141
-
142
- function renderText(text: TemplateText[number], hit: any, components: any) {
143
- if (text.type === 'string') {
144
- return text.value;
145
- }
146
-
147
- if (text.type === 'attribute') {
148
- return getPropertyByPath(hit, text.path);
149
- }
150
-
151
- if (text.type === 'highlight') {
152
- return components.Highlight({
153
- hit,
154
- attribute: text.path,
155
- });
156
- }
157
-
158
- if (text.type === 'snippet') {
159
- return components.Snippet({
160
- hit,
161
- attribute: text.path,
162
- });
163
- }
164
-
165
- return null;
166
- }
167
-
168
- function renderAttribute(text: TemplateText[number], hit: any) {
169
- if (text.type === 'string') {
170
- return text.value;
171
- }
172
-
173
- if (text.type === 'attribute') {
174
- return getPropertyByPath(hit, text.path);
175
- }
176
-
177
- return null;
178
- }
179
-
180
- function childToWidget(child: Child, container: HTMLElement): Widget[] {
181
- const widgetContainer = container.appendChild(document.createElement('div'));
182
-
183
- if (child.type === 'columns') {
184
- widgetContainer.classList.add('ais-Columns');
185
-
186
- return child.children
187
- .map((column) => column.map((ch) => childToWidget(ch, widgetContainer)))
188
- .flat(2);
189
- }
190
-
191
- if (child.type === 'ais.configure') {
192
- return [widgets[child.type]({ ...child.parameters })];
193
- }
194
-
195
- if (isTemplateWidget(child)) {
196
- // type cast is needed here because the spread adding `container` and `templates` loses the type discriminant
197
- const parameters = child.parameters as Parameters<
198
- typeof widgets['ais.hits']
199
- >[0];
200
- const widget = widgets[child.type] as typeof widgets['ais.hits'];
201
-
202
- return [
203
- widget({
204
- ...parameters,
205
- container: widgetContainer,
206
- templates: {
207
- item: (hit: any, { html, components }) => {
208
- if (!child.children.length) {
209
- return html`<code> no item template given</code>`;
210
- }
211
-
212
- return child.children.map((ch) => {
213
- if (isTextChild(ch)) {
214
- const Tag = textChildren.get(ch.type)!;
215
- return html`<${Tag}>
216
- ${ch.parameters.text.map((text) =>
217
- renderText(text, hit, components)
218
- )}
219
- </${Tag}>`;
220
- }
221
-
222
- if (ch.type === 'image') {
223
- return html`<img
224
- src="${ch.parameters.src
225
- .map((src) => renderAttribute(src, hit))
226
- .join('')}"
227
- alt="${ch.parameters.alt
228
- .map((alt) => renderAttribute(alt, hit))
229
- .join('')}"
230
- />`;
231
- }
232
-
233
- return html``;
234
- });
235
- },
236
- },
237
- }),
238
- ];
239
- }
240
-
241
- // type cast is needed here because the spread adding `container` loses the type discriminant
242
- const parameters = child.parameters as Parameters<
243
- typeof widgets['ais.pagination']
244
- >[0];
245
- const widget = widgets[child.type] as typeof widgets['ais.pagination'];
246
- return [
247
- widget({
248
- ...parameters,
249
- container: widgetContainer,
250
- }),
251
- ];
252
- }
253
-
254
- function error(message: string) {
255
- if (VERBOSE) {
256
- // eslint-disable-next-line no-console
257
- console.error(`[InstantSearch] ${message}`);
258
- }
259
- }
package/src/types.ts DELETED
@@ -1,54 +0,0 @@
1
- import type { widgets } from './widgets';
2
-
3
- type StaticString = { type: 'string'; value: string };
4
- type Attribute = { type: 'attribute'; path: string[] };
5
- type Highlight = { type: 'highlight' | 'snippet'; path: string[] };
6
- export type TemplateText = Array<Attribute | StaticString | Highlight>;
7
- export type TemplateAttribute = Array<Attribute | StaticString>;
8
- export type TemplateChild =
9
- | {
10
- type: 'paragraph' | 'div' | 'span' | 'h2';
11
- parameters: {
12
- text: TemplateText;
13
- };
14
- }
15
- | {
16
- type: 'image';
17
- parameters: {
18
- src: TemplateAttribute;
19
- alt: TemplateAttribute;
20
- };
21
- };
22
-
23
- export type Child =
24
- | {
25
- [key in keyof typeof widgets]: key extends
26
- | 'ais.hits'
27
- | 'ais.infiniteHits'
28
- | 'ais.frequentlyBoughtTogether'
29
- | 'ais.lookingSimilar'
30
- | 'ais.relatedProducts'
31
- | 'ais.trendingItems'
32
- ? {
33
- type: key;
34
- parameters: Omit<
35
- Parameters<typeof widgets[key]>[0],
36
- 'container' | 'templates'
37
- >;
38
- children: TemplateChild[];
39
- }
40
- : {
41
- type: key;
42
- parameters: Omit<Parameters<typeof widgets[key]>[0], 'container'>;
43
- };
44
- }[keyof typeof widgets]
45
- | {
46
- type: 'columns';
47
- children: Child[][];
48
- };
49
-
50
- export type Configuration = {
51
- id: string;
52
- indexName: string;
53
- children: Child[];
54
- };
package/src/widgets.ts DELETED
@@ -1,55 +0,0 @@
1
- import {
2
- breadcrumb,
3
- clearRefinements,
4
- configure,
5
- currentRefinements,
6
- frequentlyBoughtTogether,
7
- hierarchicalMenu,
8
- hits,
9
- hitsPerPage,
10
- index,
11
- infiniteHits,
12
- lookingSimilar,
13
- menu,
14
- numericMenu,
15
- pagination,
16
- panel,
17
- rangeInput,
18
- rangeSlider,
19
- ratingMenu,
20
- refinementList,
21
- relatedProducts,
22
- searchBox,
23
- sortBy,
24
- stats,
25
- toggleRefinement,
26
- trendingItems,
27
- } from 'instantsearch.js/es/widgets';
28
-
29
- export const widgets = {
30
- 'ais.breadcrumb': breadcrumb,
31
- 'ais.clearRefinements': clearRefinements,
32
- 'ais.configure': configure,
33
- 'ais.currentRefinements': currentRefinements,
34
- 'ais.frequentlyBoughtTogether': frequentlyBoughtTogether,
35
- 'ais.hierarchicalMenu': hierarchicalMenu,
36
- 'ais.hits': hits,
37
- 'ais.hitsPerPage': hitsPerPage,
38
- 'ais.index': index,
39
- 'ais.infiniteHits': infiniteHits,
40
- 'ais.lookingSimilar': lookingSimilar,
41
- 'ais.menu': menu,
42
- 'ais.numericMenu': numericMenu,
43
- 'ais.pagination': pagination,
44
- 'ais.panel': panel,
45
- 'ais.rangeInput': rangeInput,
46
- 'ais.rangeSlider': rangeSlider,
47
- 'ais.ratingMenu': ratingMenu,
48
- 'ais.refinementList': refinementList,
49
- 'ais.relatedProducts': relatedProducts,
50
- 'ais.searchBox': searchBox,
51
- 'ais.sortBy': sortBy,
52
- 'ais.stats': stats,
53
- 'ais.toggleRefinement': toggleRefinement,
54
- 'ais.trendingItems': trendingItems,
55
- };