Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme): support modal design on Detached Mode #445

Merged
merged 12 commits into from
Feb 18, 2021
Merged
3 changes: 2 additions & 1 deletion examples/js/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ autocomplete({
container: '#autocomplete',
placeholder: 'Search',
debug: true,
detachedMediaQuery: '',
openOnFocus: true,
plugins: [
shortcutsPlugin,
Expand Down Expand Up @@ -121,7 +122,7 @@ type ProductItemProps = {
function ProductItem({ hit, insights }: ProductItemProps) {
return (
<Fragment>
<div className="aa-ItemIcon">
<div className="aa-ItemIcon aa-ItemIcon--align-top">
<img src={hit.image} alt={hit.name} width="40" height="40" />
</div>
<div className="aa-ItemContent">
Expand Down
37 changes: 34 additions & 3 deletions packages/autocomplete-js/src/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export function autocomplete<TItem extends BaseItem>(
dom: dom.value,
Fragment: props.value.renderer.renderer.Fragment,
panelContainer: isDetached.value
? dom.value.detachedOverlay
? dom.value.detachedContainer
: props.value.renderer.panelContainer,
propGetters,
state: lastStateRef.current,
Expand Down Expand Up @@ -179,10 +179,10 @@ export function autocomplete<TItem extends BaseItem>(

runEffect(() => {
const panelContainerElement = isDetached.value
? document.body
? props.value.core.environment.document.body
: props.value.renderer.panelContainer;
const panelElement = isDetached.value
? dom.value.detachedOverlay
? dom.value.detachedContainer
: dom.value.panel;

if (isDetached.value && lastStateRef.current.isOpen) {
Expand Down Expand Up @@ -251,6 +251,37 @@ export function autocomplete<TItem extends BaseItem>(
};
});

runEffect(() => {
if (!isDetached.value) {
return () => {};
}

function toggleModalClassname(isActive: boolean) {
dom.value.detachedContainer.classList.toggle(
'aa-DetachedContainer--Modal',
isActive
);
}

function onChange(event: MediaQueryListEvent) {
toggleModalClassname(event.matches);
}

const isModalDetachedMql = window.matchMedia(
getComputedStyle(
props.value.core.environment.document.documentElement
).getPropertyValue('--aa-detached-modal-media-query')
);

toggleModalClassname(isModalDetachedMql.matches);

isModalDetachedMql.addEventListener('change', onChange);

return () => {
isModalDetachedMql.removeEventListener('change', onChange);
};
});

runEffect(() => {
requestAnimationFrame(setPanelPosition);

Expand Down
15 changes: 13 additions & 2 deletions packages/autocomplete-js/src/createAutocompleteDom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,19 @@ export function createAutocompleteDom<TItem extends BaseItem>({
class: classNames.root,
...rootProps,
});
const detachedContainer = createDomElement('div', {
class: classNames.detachedContainer,
onMouseDown(event: MouseEvent) {
event.stopPropagation();
},
});
const detachedOverlay = createDomElement('div', {
class: classNames.detachedOverlay,
children: [detachedContainer],
onMouseDown() {
document.body.removeChild(detachedOverlay);
onDetachedOverlayClose();
},
});

const labelProps = propGetters.getLabelProps({
Expand Down Expand Up @@ -171,15 +182,15 @@ export function createAutocompleteDom<TItem extends BaseItem>({
children: [form, detachedCancelButton],
});

detachedOverlay.appendChild(detachedFormContainer);
detachedContainer.appendChild(detachedFormContainer);
root.appendChild(detachedSearchButton);
} else {
root.appendChild(form);
}

return {
openDetachedOverlay,
detachedOverlay,
detachedContainer,
inputWrapper,
input,
root,
Expand Down
11 changes: 7 additions & 4 deletions packages/autocomplete-js/src/getDefaultOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { getHTMLElement, mergeClassNames } from './utils';
const defaultClassNames: AutocompleteClassNames = {
detachedCancelButton: 'aa-DetachedCancelButton',
detachedFormContainer: 'aa-DetachedFormContainer',
detachedContainer: 'aa-DetachedContainer',
detachedOverlay: 'aa-DetachedOverlay',
detachedSearchButton: 'aa-DetachedSearchButton',
detachedSearchButtonIcon: 'aa-DetachedSearchButtonIcon',
Expand Down Expand Up @@ -80,6 +81,10 @@ export function getDefaultOptions<TItem extends BaseItem>(
'The `container` option does not support `input` elements. You need to change the container to a `div`.'
);

const environment = (typeof window !== 'undefined'
? window
: {}) as typeof window;

return {
renderer: {
classNames: mergeClassNames(
Expand All @@ -104,15 +109,13 @@ export function getDefaultOptions<TItem extends BaseItem>(
renderer: renderer ?? defaultRenderer,
detachedMediaQuery:
detachedMediaQuery ??
getComputedStyle(document.documentElement).getPropertyValue(
getComputedStyle(environment.document.documentElement).getPropertyValue(
'--aa-detached-media-query'
),
},
core: {
...core,
environment: (typeof window !== 'undefined'
? window
: {}) as typeof window,
environment,
},
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type AutocompleteClassNames = {
detachedCancelButton: string;
detachedFormContainer: string;
detachedContainer: string;
detachedOverlay: string;
detachedSearchButton: string;
detachedSearchButtonIcon: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/autocomplete-js/src/types/AutocompleteDom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ export type AutocompleteDom = {
resetButton: HTMLButtonElement;
loadingIndicator: HTMLDivElement;
panel: HTMLDivElement;
detachedOverlay: HTMLDivElement;
detachedContainer: HTMLDivElement;
};
43 changes: 39 additions & 4 deletions packages/autocomplete-theme-classic/src/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
0 6px 16px -4px rgba(35, 38, 59, 0.15);
--aa-panel-max-height: 500px;
--aa-detached-media-query: (max-width: 500px);
--aa-detached-modal-media-query: (min-width: 500px);
}

// ----------------
Expand Down Expand Up @@ -270,6 +271,10 @@ body {
display: none;
}
}
// todo: rename to SourceNoResults
.aa-SourceEmpty {
padding: var(--aa-spacing);
}
&:empty {
// hide empty section
display: none;
Expand Down Expand Up @@ -321,7 +326,6 @@ body {
// the result type icon inlined svg or img
.aa-ItemIcon {
align-items: center;
align-self: flex-start;
background: #fff;
border-radius: 3px;
box-shadow: inset 0 0 0 1px var(--aa-selected-color);
Expand All @@ -335,6 +339,9 @@ body {
stroke-width: var(--aa-icon-stroke-width);
text-align: center;
width: calc(var(--aa-icon-size) + var(--aa-spacing));
&.aa-ItemIcon--align-top {
align-self: flex-start;
}
&.aa-ItemIcon--no-border {
background: none;
box-shadow: none;
Expand Down Expand Up @@ -364,6 +371,7 @@ body {
}
.aa-ItemContentTitle {
display: inline-block;
line-height: 1.25em;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
Expand Down Expand Up @@ -487,7 +495,7 @@ body {
}
}

.aa-DetachedOverlay {
.aa-DetachedContainer {
background: var(--aa-background-color);
bottom: 0;
display: flex;
Expand All @@ -498,6 +506,7 @@ body {
position: fixed;
right: 0;
top: 0;
z-index: 1000;

.aa-DetachedFormContainer {
border-bottom: solid 1px var(--aa-selected-color);
Expand All @@ -520,18 +529,18 @@ body {
.aa-Panel {
background-color: var(--aa-background-color);
overflow: hidden;
padding: 0 var(--aa-spacing-half);
position: relative;

.aa-PanelLayout {
box-shadow: none;
height: 100%;
margin: 0;
max-height: none;
overflow-y: auto;
padding: 0;
padding: 6px var(--aa-spacing-half) 80px;
width: 100%;
}

.aa-Item {
border-radius: 3px;
padding: 0;
Expand All @@ -543,6 +552,22 @@ body {
&::after {
height: 32px;
}

&.aa-DetachedContainer--Modal {
border-radius: 6px;
bottom: inherit;
height: auto;
margin: 0 auto;
max-width: 500px;
francoischalifour marked this conversation as resolved.
Show resolved Hide resolved
position: absolute;
top: 3%;
.aa-Panel {
.aa-PanelLayout {
max-height: 500px;
francoischalifour marked this conversation as resolved.
Show resolved Hide resolved
padding-bottom: var(--aa-spacing-half);
}
}
}
}

// remove scroll for body
Expand All @@ -551,6 +576,16 @@ body {
overflow: hidden;
}

.aa-DetachedOverlay {
background-color: var(--aa-muted-color);
height: 100vh;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 999;
}

@media (hover: none) and (pointer: coarse) {
.aa-TouchOnly {
display: none !important; // TODO: fix specificity issue
Expand Down
1 change: 1 addition & 0 deletions packages/website/docs/autocomplete-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ The class names to inject in each created DOM element. It it useful to design wi
type ClassNames = Partial<{
detachedCancelButton: string;
detachedFormContainer: string;
detachedContainer: string;
detachedOverlay: string;
detachedSearchButton: string;
detachedSearchButtonIcon: string;
Expand Down