Skip to content

Commit

Permalink
feat: init modal base
Browse files Browse the repository at this point in the history
  • Loading branch information
daief committed Apr 12, 2022
1 parent 51354f3 commit db48216
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 26 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# daisyui-vue

基于 daisyui 封装的 vue 组件库。
基于 [daisyui](https://github.com/saadeghi/daisyui) 封装的 vue 组件库。

## Usage

Expand Down Expand Up @@ -140,3 +140,8 @@ export function render() {
- [ ] mockup-code
- [ ] mockup-phone
- [ ] mockup-window

## 命名规则

- 事件名称,`onNameAction`:onMaskClick、onEscKeyDown
- 事件控制,`xxxYYable`: keyboardCloseable
22 changes: 11 additions & 11 deletions docs/src/pages/components/popper.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,17 @@ template slots

### Attributes

| name | description | type | default |
| ------------------ | ------------------------------------ | -------------------------------- | ------- |
| content | popper content | any, function | - |
| open | popper open status | boolean | - |
| placement | popper placement | Placement | auto |
| disableTeleport | disable popper node teleport to body | boolean | false |
| disabled | disable popper | boolean | true |
| onChange | emitted whe popper status change | function | - |
| triggerAction | the action to tigger popper | contextMenu, hover, click, focus | hover |
| outsideCloseable | click outside to close popper | boolean | true |
| escapeKeyCloseable | press escape to close popper | boolean | true |
| name | description | type | default |
| ---------------- | ------------------------------------ | -------------------------------- | ------- |
| content | popper content | any, function | - |
| open | popper open status | boolean | - |
| placement | popper placement | Placement | auto |
| disableTeleport | disable popper node teleport to body | boolean | false |
| disabled | disable popper | boolean | true |
| onChange | emitted whe popper status change | function | - |
| triggerAction | the action to tigger popper | contextMenu, hover, click, focus | hover |
| outsideCloseable | click outside to close popper | boolean | true |
| escapeCloseable | press escape key to close popper | boolean | true |

### Slots

Expand Down
43 changes: 30 additions & 13 deletions docs/src/pages/demo.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
# Demo for development

```html :::demo
<div class="text-center">
<div style="height: 1000px" />
```tsx :::run
import { reactive, watch } from 'vue';

<dv-popper
triggerAction="click"
content="This is a tooltip."
placement="bottom"
open
>
<dv-button>click</dv-button>
</dv-popper>
export default {
setup: () => {
const state = reactive({
show: false,
});

<div style="height: 1000px" />
</div>
let c = 0;

watch([() => c], (newVal, oldVal) => {
console.log(newVal, oldVal);
});

return () => (
<div class="text-center">
<dv-toggle
checked={state.show}
onChange={(e) => (state.show = e.target.checked)}
/>
<hr />
<dv-modal-base
open={state.show}
maskCloseable={false}
onClickMask={() => (state.show = false)}
custom={() => <div onClick={() => c++}>111 - {c}</div>}
></dv-modal-base>
</div>
);
},
};
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"babel-plugin-macros": "^3.1.0",
"babel-plugin-twin": "^1.0.2",
"cssnano": "^5.0.10",
"daisyui": "2.13.4",
"daisyui": "2.13.6",
"download-git-repo": "^3.0.2",
"fs-extra": "^10.0.0",
"glob": "^7.1.7",
Expand Down
1 change: 1 addition & 0 deletions src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './input';
export * from './link';
export * from './mask';
export * from './menu';
export * from './modal';
export * from './navbar';
export * from './popper';
export * from './progress';
Expand Down
130 changes: 130 additions & 0 deletions src/components/modal/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { useEventListener } from '@/shared/hooks/useEventListener';
import { componentV2 } from '@/shared/styled';
import { ExtractFromProps } from '@/shared/types/common';
import { getRenderResult } from '@/shared/utils';
import {
computed,
PropType,
reactive,
StyleValue,
Teleport,
vShow,
watch,
withDirectives,
} from 'vue';
import style from './style/base.less';

export const modalBaseProps = {
disableTeleport: {
type: Boolean,
default: false,
},
container: {
type: [Function, String, Object] as PropType<
string | Element | (() => Element)
>,
default: 'body',
},
open: Boolean,
hideMask: Boolean,
maskCloseable: {
type: Boolean,
default: true,
},
onMaskClick: Function as PropType<(e: MouseEvent) => void>,
escapeCloseable: {
type: Boolean,
default: true,
},
onEscKeyDown: Function as PropType<(e: KeyboardEvent) => void>,
onClose: Function as PropType<
(e: MouseEvent | KeyboardEvent, trigger: 'esc' | 'mask') => void
>,

custom: { default: '' },
// TODO
destroyOnClose: Boolean,
};

export type IModalBaseProps = ExtractFromProps<typeof modalBaseProps>;

export const ModalBase = componentV2<IModalBaseProps>(
{
name: 'ModalBase',
props: modalBaseProps,
inheritAttrs: false,
setup: (props, { slots, attrs }) => {
const state = reactive({
hasTriggered: !!props.open,
});

const maskStyle = computed<StyleValue>(() => [
props.hideMask
? {
pointerEvents: 'none',
background: 'none',
}
: '',
!props.maskCloseable ? { cursor: 'auto' } : '',
]);

const stop = watch(
() => props.open,
(newVal) => {
if (newVal) {
state.hasTriggered = true;
stop();
}
},
);

const handleClickMask = (e: MouseEvent) => {
if (props.maskCloseable && e.target === e.currentTarget) {
props.onMaskClick?.(e);
props.onClose?.(e, 'mask');
}
};

useEventListener(
() => document,
'keydown',
(e) => {
if (props.escapeCloseable && e.key === 'Escape') {
props.onEscKeyDown?.(e);
props.onClose?.(e, 'esc');
}
},
);

return () => {
const toContainer =
typeof props.container === 'function'
? props.container()
: props.container;

const customNode = getRenderResult('custom', props, slots);

return state.hasTriggered ? (
<Teleport disabled={props.disableTeleport} to={toContainer}>
{withDirectives(
<div
{...attrs}
tabindex={-1}
role="presentation"
class="dv-modal-base"
style={maskStyle.value}
onClick={handleClickMask}
>
{customNode || (
<div class="dv-modal-box">{slots.default?.()}</div>
)}
</div>,
[[vShow, props.open]],
)}
</Teleport>
) : null;
};
},
},
[style],
);
1 change: 1 addition & 0 deletions src/components/modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './base';
28 changes: 28 additions & 0 deletions src/components/modal/style/base.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
:root {
--modal-base-z-index: 1000;
}

.dv-modal-base {
@apply cursor-pointer opacity-100;
@apply bg-neutral-focus bg-opacity-40 duration-200 ease-in-out;
@apply fixed inset-0 outline-0;
transition-property: transform, opacity;
overflow: hidden auto;
overscroll-behavior: contain;
z-index: var(--modal-base-z-index);
}

.dv-modal-box {
@apply max-w-full translate-y-10 transform bg-base-100 p-6 transition duration-200 ease-in-out rounded-box;
@apply cursor-auto;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
pointer-events: auto;
width: 34rem;
max-height: calc(100vh - 5em);
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow-y: auto;
overscroll-behavior: contain;
}

0 comments on commit db48216

Please sign in to comment.