Skip to content

Commit 390cb3a

Browse files
committed
1 parent 9ab7665 commit 390cb3a

26 files changed

+214
-140
lines changed

packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/atomic-angular.module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {APP_INITIALIZER, ModuleWithProviders, NgModule, Provider} from '@angular
55

66

77
import {
8+
AtomicCommerceInterface,
89
AtomicAriaLive,
910
AtomicAutomaticFacet,
1011
AtomicAutomaticFacetGenerator,
@@ -150,6 +151,7 @@ defineCustomElements(window);
150151

151152

152153
const DECLARATIONS = [
154+
AtomicCommerceInterface,
153155
AtomicAriaLive,
154156
AtomicAutomaticFacet,
155157
AtomicAutomaticFacetGenerator,

packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts

+26
Original file line numberDiff line numberDiff line change
@@ -3082,4 +3082,30 @@ export class AtomicTimeframeFacet {
30823082

30833083
export declare interface AtomicTimeframeFacet extends Components.AtomicTimeframeFacet {}
30843084

3085+
//#region Lit Declarations
30853086

3087+
@ProxyCmp({
3088+
inputs: ['name', 'type', 'analytics', 'logLevel', 'i18n', 'language', 'engine', 'reflectStateInUrl', 'scrollContainer', 'languageAssetsPath', 'iconAssetsPath', 'CspNonce']
3089+
})
3090+
@Component({
3091+
selector: 'atomic-commerce-interface',
3092+
changeDetection: ChangeDetectionStrategy.OnPush,
3093+
template: '<ng-content></ng-content>',
3094+
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
3095+
inputs: ['name', 'type', 'analytics', 'logLevel', 'i18n', 'language', 'engine', 'reflectStateInUrl', 'scrollContainer', 'languageAssetsPath', 'iconAssetsPath', 'CspNonce']
3096+
})
3097+
export class AtomicCommerceInterface {
3098+
protected readonly el: HTMLElement;
3099+
constructor(c: ChangeDetectorRef, el: ElementRef, protected z: NgZone) {
3100+
c.detach();
3101+
this.el = el.nativeElement;
3102+
proxyOutputs(this, this.el, []);
3103+
}
3104+
}
3105+
3106+
export declare interface AtomicCommerceInterface extends LitAtomicCommerceInterface {
3107+
3108+
}
3109+
3110+
import type {AtomicCommerceInterface as LitAtomicCommerceInterface} from '@coveo/atomic/components';
3111+
//#endregion Lit Declarations

packages/atomic-react/src/components/commerce/CommerceInterfaceWrapper.tsx

+23-14
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import type {JSX, i18n} from '@coveo/atomic';
22
import React, {useEffect, useRef} from 'react';
3-
import {AtomicCommerceInterface} from '../stencil-generated/commerce/index.js';
3+
import {AtomicCommerceInterface} from './components';
44

5-
type ExecuteRequest = HTMLAtomicCommerceInterfaceElement['executeFirstRequest'];
5+
export type AtomicCommerceInterface = React.ComponentProps<
6+
typeof AtomicCommerceInterface
7+
>;
8+
9+
type ExecuteRequest = AtomicCommerceInterface['executeFirstRequest'];
610

711
/**
812
* The properties of the AtomicCommerceInterface component
913
*/
1014
interface WrapperProps
11-
extends Omit<JSX.AtomicCommerceInterface, 'i18n' | 'pipeline' | 'searchHub'> {
15+
extends Omit<AtomicCommerceInterface, 'i18n' | 'pipeline' | 'searchHub'> {
1216
/**
1317
* An optional callback function that can be used to control the execution of the first request.
1418
*
@@ -26,7 +30,7 @@ interface WrapperProps
2630

2731
const DefaultProps: Required<Pick<WrapperProps, 'onReady' | 'localization'>> = {
2832
onReady: (executeFirstRequest) => {
29-
return executeFirstRequest();
33+
return executeFirstRequest ? executeFirstRequest() : Promise.resolve();
3034
},
3135
localization: () => {},
3236
};
@@ -45,21 +49,26 @@ export const InterfaceWrapper = (
4549
//TODO, maybe: provide a default engine
4650
}
4751
const {engine, localization, onReady, ...allOtherProps} = mergedProps;
48-
const interfaceRef = useRef<HTMLAtomicCommerceInterfaceElement>(null);
52+
const interfaceRef =
53+
useRef<React.ElementRef<typeof AtomicCommerceInterface>>(null);
4954
let initialization: Promise<void> | null = null;
5055

5156
useEffect(() => {
5257
const commerceInterfaceAtomic = interfaceRef.current!;
5358
if (!initialization) {
54-
initialization = commerceInterfaceAtomic.initializeWithEngine(engine);
55-
initialization.then(() => {
56-
localization(commerceInterfaceAtomic.i18n);
57-
onReady(
58-
commerceInterfaceAtomic.executeFirstRequest.bind(
59-
commerceInterfaceAtomic
60-
)
61-
);
62-
});
59+
const waitForElement = async () => {
60+
await customElements.whenDefined('atomic-commerce-interface');
61+
initialization = commerceInterfaceAtomic.initializeWithEngine(engine);
62+
initialization.then(() => {
63+
localization(commerceInterfaceAtomic.i18n);
64+
onReady(
65+
commerceInterfaceAtomic.executeFirstRequest.bind(
66+
commerceInterfaceAtomic
67+
)
68+
);
69+
});
70+
};
71+
waitForElement();
6372
}
6473
}, [interfaceRef]);
6574

packages/atomic-react/src/components/commerce/CommerceProductListWrapper.tsx

+21-17
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,28 @@ export const ListWrapper: React.FC<WrapperProps> = (props) => {
3535
const commerceProductListRef =
3636
useRef<HTMLAtomicCommerceProductListElement>(null);
3737
useEffect(() => {
38-
commerceProductListRef.current?.setRenderFunction(
39-
(product, root, linkContainer) => {
40-
const templateResult = template(product as Product);
41-
if (hasLinkTemplate(templateResult)) {
42-
createRoot(linkContainer!).render(templateResult.linkTemplate);
43-
createRoot(root).render(templateResult.contentTemplate);
44-
return renderToString(templateResult.contentTemplate);
45-
} else {
46-
createRoot(root).render(templateResult);
47-
otherProps.display === 'grid'
48-
? createRoot(linkContainer!).render(
49-
<AtomicProductLink></AtomicProductLink>
50-
)
51-
: createRoot(linkContainer!).render(<></>);
52-
return renderToString(templateResult);
38+
const waitForElement = async () => {
39+
await customElements.whenDefined('atomic-commerce-product-list');
40+
commerceProductListRef.current?.setRenderFunction(
41+
(product, root, linkContainer) => {
42+
const templateResult = template(product as Product);
43+
if (hasLinkTemplate(templateResult)) {
44+
createRoot(linkContainer!).render(templateResult.linkTemplate);
45+
createRoot(root).render(templateResult.contentTemplate);
46+
return renderToString(templateResult.contentTemplate);
47+
} else {
48+
createRoot(root).render(templateResult);
49+
otherProps.display === 'grid'
50+
? createRoot(linkContainer!).render(
51+
<AtomicProductLink></AtomicProductLink>
52+
)
53+
: createRoot(linkContainer!).render(<></>);
54+
return renderToString(templateResult);
55+
}
5356
}
54-
}
55-
);
57+
);
58+
};
59+
waitForElement();
5660
}, [commerceProductListRef]);
5761
return (
5862
<AtomicCommerceProductList ref={commerceProductListRef} {...otherProps} />

packages/atomic-react/src/components/commerce/CommerceRecommendationListWrapper.tsx

+21-17
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,28 @@ export const ListWrapper: React.FC<WrapperProps> = (props) => {
3535
const commerceRecsListRef =
3636
useRef<HTMLAtomicCommerceRecommendationListElement>(null);
3737
useEffect(() => {
38-
commerceRecsListRef.current?.setRenderFunction(
39-
(product, root, linkContainer) => {
40-
const templateResult = template(product as Product);
41-
if (hasLinkTemplate(templateResult)) {
42-
createRoot(linkContainer!).render(templateResult.linkTemplate);
43-
createRoot(root).render(templateResult.contentTemplate);
44-
return renderToString(templateResult.contentTemplate);
45-
} else {
46-
createRoot(root).render(templateResult);
47-
otherProps.display === 'grid'
48-
? createRoot(linkContainer!).render(
49-
<AtomicProductLink></AtomicProductLink>
50-
)
51-
: createRoot(linkContainer!).render(<></>);
52-
return renderToString(templateResult);
38+
const waitForElement = async () => {
39+
await customElements.whenDefined('atomic-commerce-recommendation-list');
40+
commerceRecsListRef.current?.setRenderFunction(
41+
(product, root, linkContainer) => {
42+
const templateResult = template(product as Product);
43+
if (hasLinkTemplate(templateResult)) {
44+
createRoot(linkContainer!).render(templateResult.linkTemplate);
45+
createRoot(root).render(templateResult.contentTemplate);
46+
return renderToString(templateResult.contentTemplate);
47+
} else {
48+
createRoot(root).render(templateResult);
49+
otherProps.display === 'grid'
50+
? createRoot(linkContainer!).render(
51+
<AtomicProductLink></AtomicProductLink>
52+
)
53+
: createRoot(linkContainer!).render(<></>);
54+
return renderToString(templateResult);
55+
}
5356
}
54-
}
55-
);
57+
);
58+
};
59+
waitForElement();
5660
}, [commerceRecsListRef]);
5761
return (
5862
<AtomicCommerceRecommendationList
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1-
export {};
1+
import {AtomicCommerceInterface as LitAtomicCommerceInterface} from '@coveo/atomic/components';
2+
import {createComponent} from '@lit/react';
3+
import React from 'react';
4+
5+
export const AtomicCommerceInterface = createComponent({
6+
tagName: 'atomic-commerce-interface',
7+
react: React,
8+
elementClass: LitAtomicCommerceInterface,
9+
});

packages/atomic-react/src/components/recommendation/RecsInterfaceWrapper.tsx

+16-11
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,22 @@ export const RecsInterfaceWrapper = (
5353
let initialization: Promise<void> | null = null;
5454

5555
useEffect(() => {
56-
const recsInterfaceAtomic = recsInterfaceRef.current!;
57-
if (!initialization) {
58-
initialization =
59-
recsInterfaceAtomic.initializeWithRecommendationEngine(engine);
60-
initialization.then(() => {
61-
localization(recsInterfaceAtomic.i18n);
62-
onReady(
63-
recsInterfaceAtomic.getRecommendations.bind(recsInterfaceAtomic)
64-
);
65-
});
66-
}
56+
const waitForElement = async () => {
57+
await customElements.whenDefined('atomic-recs-interface');
58+
59+
const recsInterfaceAtomic = recsInterfaceRef.current!;
60+
if (!initialization) {
61+
initialization =
62+
recsInterfaceAtomic.initializeWithRecommendationEngine(engine);
63+
initialization.then(() => {
64+
localization(recsInterfaceAtomic.i18n);
65+
onReady(
66+
recsInterfaceAtomic.getRecommendations.bind(recsInterfaceAtomic)
67+
);
68+
});
69+
}
70+
};
71+
waitForElement();
6772
}, [recsInterfaceRef]);
6873

6974
return (

packages/atomic-react/src/components/recommendation/RecsListWrapper.tsx

+20-16
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,26 @@ export const RecsListWrapper: React.FC<WrapperProps> = (props) => {
3434
const {template, ...otherProps} = props;
3535
const recsListRef = useRef<HTMLAtomicRecsListElement>(null);
3636
useEffect(() => {
37-
recsListRef.current?.setRenderFunction((result, root, linkContainer) => {
38-
const templateResult = template(result as Result);
39-
if (hasLinkTemplate(templateResult)) {
40-
createRoot(linkContainer!).render(templateResult.linkTemplate);
41-
createRoot(root).render(templateResult.contentTemplate);
42-
return renderToString(templateResult.contentTemplate);
43-
} else {
44-
createRoot(root).render(templateResult);
45-
otherProps.display === 'grid'
46-
? createRoot(linkContainer!).render(
47-
<AtomicResultLink></AtomicResultLink>
48-
)
49-
: createRoot(linkContainer!).render(<></>);
50-
return renderToString(templateResult);
51-
}
52-
});
37+
const waitForElement = async () => {
38+
await customElements.whenDefined('atomic-result-list');
39+
recsListRef.current?.setRenderFunction((result, root, linkContainer) => {
40+
const templateResult = template(result as Result);
41+
if (hasLinkTemplate(templateResult)) {
42+
createRoot(linkContainer!).render(templateResult.linkTemplate);
43+
createRoot(root).render(templateResult.contentTemplate);
44+
return renderToString(templateResult.contentTemplate);
45+
} else {
46+
createRoot(root).render(templateResult);
47+
otherProps.display === 'grid'
48+
? createRoot(linkContainer!).render(
49+
<AtomicResultLink></AtomicResultLink>
50+
)
51+
: createRoot(linkContainer!).render(<></>);
52+
return renderToString(templateResult);
53+
}
54+
});
55+
};
56+
waitForElement();
5357
}, [recsListRef]);
5458
return <AtomicRecsList ref={recsListRef} {...otherProps} />;
5559
};

packages/atomic-react/src/components/search/FoldedResultListWrapper.tsx

+9-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ export const FoldedResultListWrapper: React.FC<WrapperProps> = (props) => {
2626
const {template, ...otherProps} = props;
2727
const foldedResultListRef = useRef<HTMLAtomicFoldedResultListElement>(null);
2828
useEffect(() => {
29-
foldedResultListRef.current?.setRenderFunction((foldedResult, root) => {
30-
createRoot(root).render(template(foldedResult as FoldedResult));
31-
return renderToString(template(foldedResult as FoldedResult));
32-
});
29+
const waitForElement = async () => {
30+
await customElements.whenDefined('atomic-folded-result-list');
31+
await customElements.whenDefined('atomic-search-interface');
32+
foldedResultListRef.current?.setRenderFunction((foldedResult, root) => {
33+
createRoot(root).render(template(foldedResult as FoldedResult));
34+
return renderToString(template(foldedResult as FoldedResult));
35+
});
36+
};
37+
waitForElement();
3338
}, [foldedResultListRef]);
3439
return <AtomicFoldedResultList ref={foldedResultListRef} {...otherProps} />;
3540
};

packages/atomic-react/src/components/search/ResultListWrapper.tsx

+23-15
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,31 @@ export const ResultListWrapper: React.FC<WrapperProps> = (props) => {
3434
const {template, ...otherProps} = props;
3535
const resultListRef = useRef<HTMLAtomicResultListElement>(null);
3636
useEffect(() => {
37-
resultListRef.current?.setRenderFunction((result, root, linkContainer) => {
38-
const templateResult = template(result as Result);
39-
if (hasLinkTemplate(templateResult)) {
40-
createRoot(linkContainer!).render(templateResult.linkTemplate);
41-
createRoot(root).render(templateResult.contentTemplate);
42-
return renderToString(templateResult.contentTemplate);
43-
} else {
44-
createRoot(root).render(templateResult);
45-
otherProps.display === 'grid'
46-
? createRoot(linkContainer!).render(
47-
<AtomicResultLink></AtomicResultLink>
48-
)
49-
: createRoot(linkContainer!).render(<></>);
50-
return renderToString(templateResult);
37+
const waitForElement = async () => {
38+
await customElements.whenDefined('atomic-result-list');
39+
const resultListAtomic = resultListRef.current!;
40+
if (resultListAtomic && resultListAtomic.setRenderFunction) {
41+
resultListAtomic.setRenderFunction((result, root, linkContainer) => {
42+
const templateResult = template(result as Result);
43+
if (hasLinkTemplate(templateResult)) {
44+
createRoot(linkContainer!).render(templateResult.linkTemplate);
45+
createRoot(root).render(templateResult.contentTemplate);
46+
return renderToString(templateResult.contentTemplate);
47+
} else {
48+
createRoot(root).render(templateResult);
49+
otherProps.display === 'grid'
50+
? createRoot(linkContainer!).render(
51+
<AtomicResultLink></AtomicResultLink>
52+
)
53+
: createRoot(linkContainer!).render(<></>);
54+
return renderToString(templateResult);
55+
}
56+
});
5157
}
52-
});
58+
};
59+
waitForElement();
5360
}, [resultListRef]);
61+
5462
return <AtomicResultList ref={resultListRef} {...otherProps} />;
5563
};
5664

packages/atomic-react/src/components/search/SearchBoxInstantResultsWrapper.tsx

+8-4
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ export const SearchBoxInstantResultsWrapper: React.FC<WrapperProps> = (
2929
const instantResultsRef =
3030
useRef<HTMLAtomicSearchBoxInstantResultsElement>(null);
3131
useEffect(() => {
32-
instantResultsRef.current?.setRenderFunction((result, root) => {
33-
createRoot(root).render(template(result as Result));
34-
return renderToString(template(result as Result));
35-
});
32+
const waitForElement = async () => {
33+
await customElements.whenDefined('atomic-search-box-instant-results');
34+
instantResultsRef.current?.setRenderFunction((result, root) => {
35+
createRoot(root).render(template(result as Result));
36+
return renderToString(template(result as Result));
37+
});
38+
};
39+
waitForElement();
3640
}, [instantResultsRef]);
3741
return (
3842
<AtomicSearchBoxInstantResults ref={instantResultsRef} {...otherProps} />

0 commit comments

Comments
 (0)