diff --git a/admin/src/components/button/button.tsx b/admin/src/components/button/button.tsx index 68b1a837..5f8e65b0 100644 --- a/admin/src/components/button/button.tsx +++ b/admin/src/components/button/button.tsx @@ -6,6 +6,8 @@ import { JSX, mergeProps } from 'solid-js'; import { Props as BaseProps, ButtonType, ClickFunc, defaultProps as defaultBaseProps } from './types'; +export type Ref = HTMLButtonElement; + export interface Props extends BaseProps { /** * 是否为图标按钮 @@ -25,6 +27,7 @@ export interface Props extends BaseProps { accessKey?: string; autofocus?: boolean; value?: string; + ref?: { (el: Ref): void; }; } export const defaultProps: Readonly> = { @@ -39,6 +42,7 @@ export default function(props: Props) { props = mergeProps(defaultProps, props); return ; + return <> + - + // TODO: [CSS anchor](https://caniuse.com/?search=anchor) 支持全面的话,可以用 CSS 代替。 + const rect = btn.getBoundingClientRect(); + pop.style.top = rect.bottom + 'px'; + pop.style.left = rect.left + 'px'; + }}>{props.children} +
pop=el} classList={{'c--confirm-button-panel':true, [`palette--${props.palette}`]:!!props.palette }}> + {props.prompt ?? ctx.t('_i.areYouSure')} +
+ + +
- ; + ; } diff --git a/admin/src/components/button/group.tsx b/admin/src/components/button/group.tsx index f1baad45..5381ac66 100644 --- a/admin/src/components/button/group.tsx +++ b/admin/src/components/button/group.tsx @@ -6,17 +6,21 @@ import { JSX, mergeProps } from 'solid-js'; import { Props as BaseProps, defaultProps } from './types'; +export type Ref = HTMLFieldSetElement; + export interface Props extends BaseProps { /** * 子元素,必须得是 Button 或是 LinkButton 类型。 */ children: JSX.Element; + + ref?: { (el: Ref): void; }; } export default function (props: Props) { props = mergeProps(defaultProps, props); - return
{ if (props.ref) { props.ref(el); }}} disabled={props.disabled} classList={{ 'c--button-group': true, 'c--button-group-rounded': props.rounded, [`c--button-group-${props.style}`]: true, diff --git a/admin/src/components/button/index.ts b/admin/src/components/button/index.ts index 459fdf3b..87ab87cc 100644 --- a/admin/src/components/button/index.ts +++ b/admin/src/components/button/index.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT export { default as Button } from './button'; -export type { Props as ButtonProps } from './button'; +export type { Props as ButtonProps, Ref as ButtonRef } from './button'; export { default as LinkButton } from './link'; export type { Props as LinkButtonProps } from './link'; @@ -12,7 +12,7 @@ export { default as ConfirmButton } from './confirm'; export type { Props as ConfirmButtonProps } from './confirm'; export { default as ButtonGroup } from './group'; -export type { Props as ButtonGroupProps } from './group'; +export type { Props as ButtonGroupProps, Ref as ButtonGroupRef } from './group'; export { default as SplitButton } from './split'; export type { Props as SplitButtonProps } from './split'; diff --git a/admin/src/components/button/split.tsx b/admin/src/components/button/split.tsx index 33ab2b1f..94d87189 100644 --- a/admin/src/components/button/split.tsx +++ b/admin/src/components/button/split.tsx @@ -2,12 +2,11 @@ // // SPDX-License-Identifier: MIT -import { createSignal, For, JSX, Match, mergeProps, splitProps, Switch } from 'solid-js'; +import { For, JSX, Match, mergeProps, onCleanup, splitProps, Switch } from 'solid-js'; -import { Corner } from '@/components/base'; -import { Dropdown } from '@/components/dropdown'; -import { Props as BaseProps, default as Button, defaultProps as defaultBaseProps } from './button'; -import { default as Group } from './group'; +import { onMount } from 'solid-js'; +import { Props as BaseProps, default as Button, defaultProps } from './button'; +import { default as Group, Ref as GroupRef } from './group'; import { ClickFunc } from './types'; type Item = { type: 'divider' } | { @@ -18,15 +17,9 @@ type Item = { type: 'divider' } | { }; export interface Props extends BaseProps { - pos?: Corner; menus: Array; } -const defaultProps = { - ...defaultBaseProps, - pos: 'bottomleft' as Corner -}; - /** * 带有一个默认操作的一组按钮 * @@ -34,31 +27,53 @@ const defaultProps = { */ export default function(props: Props) { props = mergeProps(defaultProps, props); + let pop: HTMLDivElement; + let group: GroupRef; - const [visible, setVisible] = createSignal(false); + const handleClick = (e: MouseEvent) => { + if (!pop.contains(e.target as Node) && !group.contains(e.target as Node)) { + pop.hidePopover(); + } + }; + onMount(() => { + document.body.addEventListener('click', handleClick); + }); + onCleanup(() => { + document.body.removeEventListener('click', handleClick); + }); - const [_, btnProps] = splitProps(props, ['style', 'rounded', 'disabled', 'palette', 'pos']); + const [_, btnProps] = splitProps(props, ['style', 'rounded', 'disabled', 'palette']); - const activator = + const activator = group=el} style={props.style} rounded={props.rounded} disabled={props.disabled}> - + ; - return - - {(item)=>( - - -
-
- - - -
- )} -
-
; + return <> + {activator} +
pop=el} popover="manual" classList={{ 'c--split-button_content':true, [`palette--${props.palette}`]:!!props.palette}}> + + {(item) => ( + + +
+
+ + + +
+ )} +
+
+ ; } diff --git a/admin/src/components/button/style.css b/admin/src/components/button/style.css index 111df623..9c6c82a4 100644 --- a/admin/src/components/button/style.css +++ b/admin/src/components/button/style.css @@ -132,17 +132,21 @@ /************************* confirm-button ******************************/ .c--confirm-button-panel { - @apply flex flex-col p-4 gap-2 bg-palette-bg text-palette-fg mt-1 rounded-md; + @apply p-4 gap-2 bg-palette-bg text-palette-fg mt-1 rounded-md m-0; .actions { @apply flex justify-end gap-2 mt-4; } } + .c--confirm-button-panel:popover-open { + @apply flex flex-col; + } + /************************* confirm-button ******************************/ .c--split-button_content { - @apply flex flex-col bg-palette-bg p-1 gap-y-1 rounded-md mt-1 border border-palette-bg-low; + @apply bg-palette-bg p-1 gap-y-1 rounded-md mt-1 border border-palette-bg-low m-0; button { @apply py-1 px-2 rounded-md text-left; @@ -152,4 +156,8 @@ @apply bg-palette-bg-high text-palette-fg-high; } } + + .c--split-button_content:popover-open { + @apply flex flex-col; + } }