Skip to content

Commit

Permalink
feat(theme): support modal design on Detached Mode (#445)
Browse files Browse the repository at this point in the history
Co-authored-by: François Chalifour <francois.chalifour@gmail.com>
  • Loading branch information
Shipow and francoischalifour authored Feb 18, 2021
1 parent 30c4f3e commit 5043d27
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 12 deletions.
2 changes: 1 addition & 1 deletion examples/js/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,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
35 changes: 33 additions & 2 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,7 +179,7 @@ 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
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
14 changes: 13 additions & 1 deletion 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,14 +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,
detachedContainer,
detachedOverlay,
inputWrapper,
input,
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
1 change: 1 addition & 0 deletions packages/autocomplete-js/src/types/AutocompleteDom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ export type AutocompleteDom = {
resetButton: HTMLButtonElement;
loadingIndicator: HTMLDivElement;
panel: HTMLDivElement;
detachedContainer: HTMLDivElement;
detachedOverlay: HTMLDivElement;
};
45 changes: 41 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,9 @@
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);
--aa-detached-modal-max-width: 500px;
--aa-detached-modal-max-height: 500px;
}

// ----------------
Expand Down Expand Up @@ -270,6 +273,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 +328,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 +341,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 +373,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 +497,7 @@ body {
}
}

.aa-DetachedOverlay {
.aa-DetachedContainer {
background: var(--aa-background-color);
bottom: 0;
display: flex;
Expand All @@ -498,6 +508,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 +531,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 +554,22 @@ body {
&::after {
height: 32px;
}

&.aa-DetachedContainer--Modal {
border-radius: 6px;
bottom: inherit;
height: auto;
margin: 0 auto;
max-width: var(--aa-detached-modal-max-width);
position: absolute;
top: 3%;
.aa-Panel {
.aa-PanelLayout {
max-height: var(--aa-detached-modal-max-height);
padding-bottom: var(--aa-spacing-half);
}
}
}
}

// remove scroll for body
Expand All @@ -551,6 +578,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

0 comments on commit 5043d27

Please sign in to comment.