@noxlovette/material 0.1.18 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/buttons/FAB.svelte +21 -19
- package/dist/components/buttons/FABMenu.svelte +11 -18
- package/dist/components/buttons/theme.d.ts +17 -11
- package/dist/components/buttons/theme.js +1 -4
- package/dist/components/buttons/types.d.ts +2 -6
- package/dist/components/containers/context-menu/ContextMenu.svelte +0 -1
- package/package.json +1 -1
|
@@ -14,7 +14,6 @@ Floating action buttons (FABs) help people take primary actions.
|
|
|
14
14
|
import { fab } from './theme.js';
|
|
15
15
|
import type { FABProps } from './types.js';
|
|
16
16
|
import FABMenu from './FABMenu.svelte';
|
|
17
|
-
import ButtonIcon from './ButtonIcon.svelte';
|
|
18
17
|
import { Layer, Icon } from '../../utils/index.js';
|
|
19
18
|
import { clickOutside } from '../../actions/index.js';
|
|
20
19
|
import { Button, type ButtonRootProps } from 'bits-ui';
|
|
@@ -34,10 +33,19 @@ Floating action buttons (FABs) help people take primary actions.
|
|
|
34
33
|
}: FABProps = $props();
|
|
35
34
|
|
|
36
35
|
const { base, icon, label: labelClass } = $derived(fab({ size, config, expanded }));
|
|
37
|
-
const btnCls = $derived(base({ class: clsx(className) }));
|
|
38
36
|
|
|
39
37
|
let showMenu = $state(false);
|
|
40
38
|
|
|
39
|
+
const btnCls = $derived(
|
|
40
|
+
base({
|
|
41
|
+
class: clsx(
|
|
42
|
+
className,
|
|
43
|
+
'transition-[border-radius] duration-300',
|
|
44
|
+
withMenu && showMenu && '!rounded-full'
|
|
45
|
+
)
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
|
|
41
49
|
function handleClick(e: MouseEvent) {
|
|
42
50
|
if (disabled) {
|
|
43
51
|
e.preventDefault();
|
|
@@ -45,24 +53,12 @@ Floating action buttons (FABs) help people take primary actions.
|
|
|
45
53
|
}
|
|
46
54
|
if (withMenu) {
|
|
47
55
|
e.preventDefault();
|
|
48
|
-
showMenu =
|
|
56
|
+
showMenu = !showMenu;
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
</script>
|
|
52
60
|
|
|
53
|
-
{
|
|
54
|
-
<div class="relative z-50" use:clickOutside={() => (showMenu = false)}>
|
|
55
|
-
<FABMenu>
|
|
56
|
-
{@render children?.()}
|
|
57
|
-
</FABMenu>
|
|
58
|
-
<ButtonIcon
|
|
59
|
-
variant="filled"
|
|
60
|
-
class="shadow-elevation-3"
|
|
61
|
-
iconProps={{ name: 'close' }}
|
|
62
|
-
onclick={() => (showMenu = !showMenu)}
|
|
63
|
-
/>
|
|
64
|
-
</div>
|
|
65
|
-
{:else}
|
|
61
|
+
<div class="contents" use:clickOutside={() => (showMenu = false)}>
|
|
66
62
|
<Button.Root
|
|
67
63
|
{disabled}
|
|
68
64
|
{formaction}
|
|
@@ -71,12 +67,18 @@ Floating action buttons (FABs) help people take primary actions.
|
|
|
71
67
|
data-cy="m3-fab"
|
|
72
68
|
{...restProps as ButtonRootProps}
|
|
73
69
|
>
|
|
74
|
-
<Icon {...iconProps} class={icon()} />
|
|
70
|
+
<Icon {...withMenu && showMenu ? { name: 'close' } : iconProps} class={icon()} />
|
|
75
71
|
<Layer />
|
|
76
|
-
{#if expanded}
|
|
72
|
+
{#if expanded && !(withMenu && showMenu)}
|
|
77
73
|
<p class={labelClass()}>
|
|
78
74
|
{label}
|
|
79
75
|
</p>
|
|
80
76
|
{/if}
|
|
81
77
|
</Button.Root>
|
|
82
|
-
|
|
78
|
+
|
|
79
|
+
{#if withMenu && showMenu}
|
|
80
|
+
<FABMenu>
|
|
81
|
+
{@render children?.()}
|
|
82
|
+
</FABMenu>
|
|
83
|
+
{/if}
|
|
84
|
+
</div>
|
|
@@ -10,21 +10,19 @@ Should be used with `FABMenuItem` as children.
|
|
|
10
10
|
import { enterExit } from '../../animation/enterExit.js';
|
|
11
11
|
import { easeEmphasizedDecel } from '../../animation/easing.js';
|
|
12
12
|
|
|
13
|
-
let { children, class: className,
|
|
13
|
+
let { children, class: className, ...restProps }: FABMenuProps = $props();
|
|
14
14
|
|
|
15
|
-
const { base } =
|
|
15
|
+
const { base } = fabMenu();
|
|
16
16
|
|
|
17
17
|
const margin = 8;
|
|
18
18
|
const gap = 8;
|
|
19
19
|
let coords = $state({
|
|
20
20
|
x: 0,
|
|
21
21
|
y: 0,
|
|
22
|
-
originX: '
|
|
23
|
-
originY: '
|
|
22
|
+
originX: 'right',
|
|
23
|
+
originY: 'bottom',
|
|
24
24
|
maxHeight: 0
|
|
25
25
|
});
|
|
26
|
-
|
|
27
|
-
// TODO: out:enterExit={{ duration: 200, easing: easeEmphasizedAccel, mode: 'scale' }} – if you can solve how to eliminate another button from appearing here, use this too
|
|
28
26
|
</script>
|
|
29
27
|
|
|
30
28
|
<ul
|
|
@@ -38,9 +36,11 @@ Should be used with `FABMenuItem` as children.
|
|
|
38
36
|
style:max-height={coords.maxHeight ? `${coords.maxHeight}px` : undefined}
|
|
39
37
|
style:--enter-exit-origin={`${coords.originY} ${coords.originX}`}
|
|
40
38
|
{@attach (menu) => {
|
|
39
|
+
const anchorEl = menu.previousElementSibling as HTMLElement;
|
|
40
|
+
if (!anchorEl) return;
|
|
41
|
+
|
|
42
|
+
const anchorRect = anchorEl.getBoundingClientRect();
|
|
41
43
|
const rect = menu.getBoundingClientRect();
|
|
42
|
-
const anchorRect = menu.parentElement?.getBoundingClientRect();
|
|
43
|
-
if (!anchorRect) return;
|
|
44
44
|
|
|
45
45
|
const spaceAbove = anchorRect.top - gap - margin;
|
|
46
46
|
const spaceBelow = window.innerHeight - margin - (anchorRect.bottom + gap);
|
|
@@ -52,29 +52,22 @@ Should be used with `FABMenuItem` as children.
|
|
|
52
52
|
const targetTop = placeAbove ? anchorRect.top - gap - maxHeight : anchorRect.bottom + gap;
|
|
53
53
|
|
|
54
54
|
let targetLeft = anchorRect.right - rect.width;
|
|
55
|
-
|
|
56
55
|
if (targetLeft + rect.width > window.innerWidth - margin) {
|
|
57
56
|
targetLeft = window.innerWidth - margin - rect.width;
|
|
58
57
|
}
|
|
59
|
-
if (targetLeft < margin)
|
|
60
|
-
targetLeft = margin;
|
|
61
|
-
}
|
|
58
|
+
if (targetLeft < margin) targetLeft = margin;
|
|
62
59
|
|
|
63
60
|
let clampedTop = targetTop;
|
|
64
|
-
if (clampedTop < margin)
|
|
65
|
-
clampedTop = margin;
|
|
66
|
-
}
|
|
61
|
+
if (clampedTop < margin) clampedTop = margin;
|
|
67
62
|
if (clampedTop + maxHeight > window.innerHeight - margin) {
|
|
68
63
|
clampedTop = window.innerHeight - margin - maxHeight;
|
|
69
64
|
}
|
|
70
65
|
|
|
71
|
-
const x = targetLeft - rect.left;
|
|
72
|
-
const y = clampedTop - rect.top;
|
|
73
66
|
const originY = placeAbove ? 'bottom' : 'top';
|
|
74
67
|
const originX =
|
|
75
68
|
anchorRect.left + anchorRect.width / 2 < targetLeft + rect.width / 2 ? 'left' : 'right';
|
|
76
69
|
|
|
77
|
-
coords = { x, y, originX, originY, maxHeight };
|
|
70
|
+
coords = { x: targetLeft, y: clampedTop, originX, originY, maxHeight };
|
|
78
71
|
}}
|
|
79
72
|
>
|
|
80
73
|
{@render children()}
|
|
@@ -491,22 +491,28 @@ export declare const fab: import("tailwind-variants").TVReturnType<{
|
|
|
491
491
|
label: string;
|
|
492
492
|
}, undefined, unknown, unknown, undefined>>;
|
|
493
493
|
export declare const fabMenu: import("tailwind-variants").TVReturnType<{
|
|
494
|
-
|
|
495
|
-
|
|
494
|
+
[key: string]: {
|
|
495
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
496
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
497
|
+
};
|
|
496
498
|
};
|
|
497
|
-
}
|
|
499
|
+
} | {
|
|
500
|
+
[x: string]: {
|
|
501
|
+
[x: string]: import("tailwind-merge").ClassNameValue | {
|
|
502
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
503
|
+
};
|
|
504
|
+
};
|
|
505
|
+
} | {}, {
|
|
498
506
|
base: string;
|
|
499
507
|
}, undefined, {
|
|
500
|
-
|
|
501
|
-
|
|
508
|
+
[key: string]: {
|
|
509
|
+
[key: string]: import("tailwind-merge").ClassNameValue | {
|
|
510
|
+
base?: import("tailwind-merge").ClassNameValue;
|
|
511
|
+
};
|
|
502
512
|
};
|
|
503
|
-
}, {
|
|
513
|
+
} | {}, {
|
|
504
514
|
base: string;
|
|
505
|
-
}, import("tailwind-variants").TVReturnType<{
|
|
506
|
-
position: {
|
|
507
|
-
top: string;
|
|
508
|
-
};
|
|
509
|
-
}, {
|
|
515
|
+
}, import("tailwind-variants").TVReturnType<unknown, {
|
|
510
516
|
base: string;
|
|
511
517
|
}, undefined, unknown, unknown, undefined>>;
|
|
512
518
|
export declare const fabMenuItem: import("tailwind-variants").TVReturnType<{
|
|
@@ -474,10 +474,7 @@ export const fab = tv({
|
|
|
474
474
|
});
|
|
475
475
|
export const fabMenu = tv({
|
|
476
476
|
slots: {
|
|
477
|
-
base: 'gap-2 pb-2 flex flex-col
|
|
478
|
-
},
|
|
479
|
-
variants: {
|
|
480
|
-
position: { top: 'top-16' }
|
|
477
|
+
base: 'gap-2 pb-2 flex flex-col fixed left-0 top-0 z-[9999] overflow-visible p-1'
|
|
481
478
|
}
|
|
482
479
|
});
|
|
483
480
|
export const fabMenuItem = tv({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AnchorButtonAttributes, IconProps } from '../../utils/index.js';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
4
|
-
import type { ButtonGroupVariants, ButtonIconVariants, ButtonMDVariants, FABMenuItemVariants,
|
|
4
|
+
import type { ButtonGroupVariants, ButtonIconVariants, ButtonMDVariants, FABMenuItemVariants, FABVariants } from './theme.js';
|
|
5
5
|
export interface ButtonGroupProps extends ButtonGroupVariants, HTMLAttributes<HTMLDivElement> {
|
|
6
6
|
/**
|
|
7
7
|
* The content of the button group.
|
|
@@ -157,11 +157,7 @@ export type FABProps = FABVariants & AnchorButtonAttributes & {
|
|
|
157
157
|
*/
|
|
158
158
|
children?: Snippet;
|
|
159
159
|
};
|
|
160
|
-
export type FABMenuProps =
|
|
161
|
-
/**
|
|
162
|
-
* The vertical position of the menu relative to the anchor.
|
|
163
|
-
*/
|
|
164
|
-
position?: FABMenuVariants['position'];
|
|
160
|
+
export type FABMenuProps = HTMLAttributes<HTMLUListElement> & {
|
|
165
161
|
/**
|
|
166
162
|
* The menu items. Use `FABMenuItem` components.
|
|
167
163
|
*/
|
|
@@ -26,7 +26,6 @@ Context menus appear on right-click and provide actions related to the clicked e
|
|
|
26
26
|
import Divider from '../divider/Divider.svelte';
|
|
27
27
|
import { enterExit } from '../../../animation/enterExit.js';
|
|
28
28
|
import { easeEmphasizedDecel } from '../../../animation/easing.js';
|
|
29
|
-
import clsx from 'clsx';
|
|
30
29
|
|
|
31
30
|
let {
|
|
32
31
|
items = [],
|