Skip to content

Commit

Permalink
fix: added playground for modal (#35)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: gioboa <giorgiob.boa@gmail.com>
  • Loading branch information
daniela-bonvini and gioboa authored Nov 14, 2023
1 parent fc1fb53 commit e058ec8
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 48 deletions.
159 changes: 159 additions & 0 deletions apps/website/src/routes/examples/SfModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { component$, useContext, useSignal, useTask$ } from '@builder.io/qwik';
import {
SfButton,
SfIconClose,
SfIconLock,
SfIconSearch,
SfModal,
} from 'qwik-storefront-ui';
import { ComponentExample } from '../../../components/utils/ComponentExample';
import { createControlsOptions } from '../../../components/utils/ControlsOptions';
import { ControlsType } from '../../../components/utils/types';
import { EXAMPLES_STATE } from '../layout';

const prefixSlotOptions = createControlsOptions({
none: undefined,
'Search icon': <SfIconSearch />,
});
const suffixSlotOptions = createControlsOptions({
none: undefined,
'Lock icon': <SfIconLock />,
});

export default component$(() => {
const selectPrefix = useSignal<boolean>();
const selectSuffix = useSignal<boolean>();

const examplesState = useContext(EXAMPLES_STATE);

useTask$(() => {
examplesState.data = {
controls: [
{
type: 'text',
modelName: 'slot',
description:
'Only for demonstration purposes. Default slot, replaces example modal content',
},
{
type: 'boolean',
modelName: 'open',
propType: 'boolean',
isRequired: true,
description: 'If true modal is visible',
},
{
type: 'boolean',
modelName: 'disableClickAway',
propType: 'boolean',
isRequired: true,
description:
"If true can't close modal when clicking outside of modal",
},
{
type: 'boolean',
modelName: 'disableEsc',
propType: 'boolean',
isRequired: true,
description:
"If true can't close modal drawer when using ESC keyboard button",
},
] satisfies ControlsType,
state: {
slot: 'Hello',
open: false,
disableClickAway: false,
disableEsc: false,
},
};
});

useTask$(({ track }) => {
track(() => examplesState.data.state);
if (selectPrefix.value === null) return;
selectPrefix.value = prefixSlotOptions.getValue(
examplesState.data.state.slotPrefix
);
});

useTask$(({ track }) => {
track(() => examplesState.data.state);
if (selectSuffix.value === null) return;
selectSuffix.value = suffixSlotOptions.getValue(
examplesState.data.state.slotSuffix
);
});

return (
<ComponentExample componentContainerClass="space-x-2">
<SfButton
type="button"
preventdefault:click
onClick$={() => {
examplesState.data.state.open = true;
console.log('value from button:', examplesState.data.state.open);
}}
>
To Checkout
</SfButton>

{examplesState.data.state.open && (
<SfModal
open={examplesState.data.state.open}
disableClickAway={examplesState.data.state.disableClickAway}
disableEsc={examplesState.data.state.disableEsc}
onClose$={() => {
examplesState.data.state.open = false;
}}
class="max-w-[90%] md:max-w-lg"
as="section"
role="alertdialog"
aria-labelledby="promoModalTitle"
aria-describedby="promoModalDesc"
>
<header>
<SfButton
square
variant="tertiary"
class="absolute right-2 top-2"
onClick$={() => {
examplesState.data.state.open = false;
}}
>
<SfIconClose />
</SfButton>
<h3
id="promoModalTitle"
class="font-bold typography-headline-4 md:typography-headline-3"
>
You might miss out on great deals
</h3>
</header>
<p id="promoModalDesc" class="mt-2">
There are special offers for some of the items on your wishlist. Do
you want to see these deals before proceeding to checkout page?
</p>
<footer class="flex justify-end gap-4 mt-4">
<SfButton
type="button"
variant="secondary"
onClick$={() => {
examplesState.data.state.open = false;
}}
>
Skip
</SfButton>
<SfButton
type="button"
onClick$={() => {
examplesState.data.state.open = false;
}}
>
Yes!
</SfButton>
</footer>
</SfModal>
)}
</ComponentExample>
);
});
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@commitlint/cli": "17.6.5",
"@commitlint/config-angular": "17.6.5",
"@commitlint/config-conventional": "17.6.5",
"@frsource/autoresize-textarea": "^1.3.76",
"@jscutlery/semver": "3.0.0",
"@k11r/nx-cloudflare-wrangler": "2.4.2",
"@mertasan/tailwindcss-variables": "2.6.1",
Expand All @@ -37,7 +38,6 @@
"@vue/shared": "^3.3.4",
"all-contributors-cli": "6.26.0",
"autoprefixer": "10.4.14",
"@frsource/autoresize-textarea": "^1.3.76",
"cypress": "12.13.0",
"cz-conventional-changelog": "3.3.0",
"eslint": "8.42.0",
Expand Down Expand Up @@ -82,6 +82,8 @@
],
"dependencies": {
"history": "5.3.0",
"nuxt-gtag": "1.1.1"
"micromark": "^4.0.0",
"nuxt-gtag": "1.1.1",
"postprocess": "^0.2.4"
}
}
51 changes: 32 additions & 19 deletions packages/qwik-storefront-ui/src/components/SfModal/SfModal.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { Slot, component$ } from '@builder.io/qwik';
import { Slot, component$, useSignal, useVisibleTask$ } from '@builder.io/qwik';
import { SfModalProps } from './types';

const defaultModalTag = 'div';

export const SfModal = component$<SfModalProps>(
({
as,
ref,
open,
disableClickAway,
disableEsc,
onClose,
onClose$,
class: _class,
...attributes
}) => {
const Tag = as || defaultModalTag;
const elementRef = useSignal<Element>();

// TODO
// const modalRef = useRef(null);
Expand All @@ -23,38 +22,52 @@ export const SfModal = component$<SfModalProps>(
// onClose?.();
// });

const onKeyDown = (event: KeyboardEvent) => {
if (!disableEsc && event.key === 'Escape') {
onClose?.();
}
if (
'onKeyDown' in attributes &&
typeof attributes.onKeyDown === 'function'
)
return attributes.onKeyDown?.(event);
};

// TODO
// useTrapFocus(modalRef, {
// activeState: open,
// initialFocus: InitialFocusType.autofocus,
// initialFocusContainerFallback: true,
// });

return open ? (
useVisibleTask$(({ cleanup }) => {
const handleClick = (event: Event) => {
if (
!disableClickAway &&
!elementRef.value?.contains(event.target as Node)
) {
onClose$ && onClose$();
}
};
document.addEventListener('click', handleClick);

const handleKeyDown = (event: KeyboardEvent) => {
if (!disableEsc && event.key === 'Escape') {
onClose$ && onClose$();
}
};
document.addEventListener('keydown', handleKeyDown);

cleanup(() => {
document.removeEventListener('click', handleClick);
document.removeEventListener('keydown', handleKeyDown);
});
});

return (
<Tag
{...(ref ? { ref } : {})}
ref={elementRef ? elementRef : {}}
class={`fixed inset-0 w-fit h-fit m-auto p-6 pt-10 lg:p-10 border border-neutral-100 bg-white shadow-xl rounded-xl outline-none
${_class}`}
tabIndex="-1"
aria-modal="true"
data-testid="modal"
{...attributes}
onKeyDown={onKeyDown}
disableEsc={disableEsc}
disableClickAway={disableClickAway}
>
<Slot />
</Tag>
) : null;
);
}
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export type SfModalProps = QwikIntrinsicElements['modal'] & {
as: any;
class?: string;
ref?: Signal<Element>;
open?: boolean;
open: boolean;
disableClickAway?: boolean;
disableEsc?: boolean;
onClose$?: PropFunction<() => void>;
Expand Down
Loading

0 comments on commit e058ec8

Please sign in to comment.