@noxlovette/material 0.1.18 → 0.1.20
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/actions/index.d.ts +1 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/portal.d.ts +3 -0
- package/dist/actions/portal.js +8 -0
- package/dist/components/buttons/FAB.svelte +22 -19
- package/dist/components/buttons/FABMenu.svelte +15 -60
- package/dist/components/buttons/Toggle.svelte +0 -2
- package/dist/components/buttons/theme.d.ts +17 -11
- package/dist/components/buttons/theme.js +3 -6
- package/dist/components/buttons/types.d.ts +4 -6
- package/dist/components/containers/context-menu/ContextMenu.svelte +0 -1
- package/package.json +1 -1
package/dist/actions/index.d.ts
CHANGED
package/dist/actions/index.js
CHANGED
|
@@ -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,9 +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);
|
|
38
|
+
let wrapperEl = $state<HTMLElement | null>(null);
|
|
39
|
+
|
|
40
|
+
const btnCls = $derived(
|
|
41
|
+
base({
|
|
42
|
+
class: clsx(
|
|
43
|
+
className,
|
|
44
|
+
'transition-[border-radius] duration-300',
|
|
45
|
+
withMenu && showMenu && '!rounded-full'
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
);
|
|
40
49
|
|
|
41
50
|
function handleClick(e: MouseEvent) {
|
|
42
51
|
if (disabled) {
|
|
@@ -45,24 +54,12 @@ Floating action buttons (FABs) help people take primary actions.
|
|
|
45
54
|
}
|
|
46
55
|
if (withMenu) {
|
|
47
56
|
e.preventDefault();
|
|
48
|
-
showMenu =
|
|
57
|
+
showMenu = !showMenu;
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
</script>
|
|
52
61
|
|
|
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}
|
|
62
|
+
<div class="contents" bind:this={wrapperEl} use:clickOutside={() => (showMenu = false)}>
|
|
66
63
|
<Button.Root
|
|
67
64
|
{disabled}
|
|
68
65
|
{formaction}
|
|
@@ -71,12 +68,18 @@ Floating action buttons (FABs) help people take primary actions.
|
|
|
71
68
|
data-cy="m3-fab"
|
|
72
69
|
{...restProps as ButtonRootProps}
|
|
73
70
|
>
|
|
74
|
-
<Icon {...iconProps} class={icon()} />
|
|
71
|
+
<Icon {...withMenu && showMenu ? { name: 'close' } : iconProps} class={icon()} />
|
|
75
72
|
<Layer />
|
|
76
|
-
{#if expanded}
|
|
73
|
+
{#if expanded && !(withMenu && showMenu)}
|
|
77
74
|
<p class={labelClass()}>
|
|
78
75
|
{label}
|
|
79
76
|
</p>
|
|
80
77
|
{/if}
|
|
81
78
|
</Button.Root>
|
|
82
|
-
|
|
79
|
+
|
|
80
|
+
{#if withMenu && showMenu && wrapperEl?.firstElementChild}
|
|
81
|
+
<FABMenu anchorEl={wrapperEl.firstElementChild as HTMLElement}>
|
|
82
|
+
{@render children?.()}
|
|
83
|
+
</FABMenu>
|
|
84
|
+
{/if}
|
|
85
|
+
</div>
|
|
@@ -5,76 +5,31 @@ Should be used with `FABMenuItem` as children.
|
|
|
5
5
|
-->
|
|
6
6
|
<script lang="ts">
|
|
7
7
|
import clsx from 'clsx';
|
|
8
|
+
import { flip } from '@floating-ui/dom';
|
|
8
9
|
import { fabMenu } from './theme.js';
|
|
9
10
|
import type { FABMenuProps } from './types.js';
|
|
10
11
|
import { enterExit } from '../../animation/enterExit.js';
|
|
11
|
-
import { easeEmphasizedDecel } from '../../animation/easing.js';
|
|
12
|
+
import { easeEmphasizedAccel, easeEmphasizedDecel } from '../../animation/easing.js';
|
|
13
|
+
import { floating, portal } from '../../actions/index.js';
|
|
12
14
|
|
|
13
|
-
let { children, class: className,
|
|
15
|
+
let { children, class: className, anchorEl, ...restProps }: FABMenuProps = $props();
|
|
14
16
|
|
|
15
|
-
const { base } =
|
|
16
|
-
|
|
17
|
-
const margin = 8;
|
|
18
|
-
const gap = 8;
|
|
19
|
-
let coords = $state({
|
|
20
|
-
x: 0,
|
|
21
|
-
y: 0,
|
|
22
|
-
originX: 'left',
|
|
23
|
-
originY: 'top',
|
|
24
|
-
maxHeight: 0
|
|
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
|
|
17
|
+
const { base } = fabMenu();
|
|
28
18
|
</script>
|
|
29
19
|
|
|
30
20
|
<ul
|
|
31
21
|
data-cy="m3-fab-menu"
|
|
32
22
|
{...restProps}
|
|
33
|
-
class={base({
|
|
34
|
-
class: clsx(className, 'fab-menu overflow-y-auto')
|
|
35
|
-
})}
|
|
23
|
+
class={base({ class: clsx(className, 'fab-menu overflow-y-auto') })}
|
|
36
24
|
in:enterExit={{ duration: 300, easing: easeEmphasizedDecel, mode: 'scale' }}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const spaceAbove = anchorRect.top - gap - margin;
|
|
46
|
-
const spaceBelow = window.innerHeight - margin - (anchorRect.bottom + gap);
|
|
47
|
-
const placeAbove = spaceAbove >= rect.height || spaceAbove >= Math.max(0, spaceBelow);
|
|
48
|
-
|
|
49
|
-
let maxHeight = placeAbove ? spaceAbove : spaceBelow;
|
|
50
|
-
maxHeight = Math.max(0, Math.min(rect.height, maxHeight));
|
|
51
|
-
|
|
52
|
-
const targetTop = placeAbove ? anchorRect.top - gap - maxHeight : anchorRect.bottom + gap;
|
|
53
|
-
|
|
54
|
-
let targetLeft = anchorRect.right - rect.width;
|
|
55
|
-
|
|
56
|
-
if (targetLeft + rect.width > window.innerWidth - margin) {
|
|
57
|
-
targetLeft = window.innerWidth - margin - rect.width;
|
|
58
|
-
}
|
|
59
|
-
if (targetLeft < margin) {
|
|
60
|
-
targetLeft = margin;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
let clampedTop = targetTop;
|
|
64
|
-
if (clampedTop < margin) {
|
|
65
|
-
clampedTop = margin;
|
|
66
|
-
}
|
|
67
|
-
if (clampedTop + maxHeight > window.innerHeight - margin) {
|
|
68
|
-
clampedTop = window.innerHeight - margin - maxHeight;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const x = targetLeft - rect.left;
|
|
72
|
-
const y = clampedTop - rect.top;
|
|
73
|
-
const originY = placeAbove ? 'bottom' : 'top';
|
|
74
|
-
const originX =
|
|
75
|
-
anchorRect.left + anchorRect.width / 2 < targetLeft + rect.width / 2 ? 'left' : 'right';
|
|
76
|
-
|
|
77
|
-
coords = { x, y, originX, originY, maxHeight };
|
|
25
|
+
out:enterExit={{ duration: 200, easing: easeEmphasizedAccel, mode: 'scale' }}
|
|
26
|
+
use:portal
|
|
27
|
+
use:floating={{
|
|
28
|
+
reference: anchorEl,
|
|
29
|
+
strategy: 'fixed',
|
|
30
|
+
placement: 'top-end',
|
|
31
|
+
offsetPx: 8,
|
|
32
|
+
middleware: [flip()]
|
|
78
33
|
}}
|
|
79
34
|
>
|
|
80
35
|
{@render children()}
|
|
@@ -82,6 +37,6 @@ Should be used with `FABMenuItem` as children.
|
|
|
82
37
|
|
|
83
38
|
<style>
|
|
84
39
|
.fab-menu {
|
|
85
|
-
transform-origin:
|
|
40
|
+
transform-origin: bottom right;
|
|
86
41
|
}
|
|
87
42
|
</style>
|
|
@@ -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<{
|
|
@@ -66,7 +66,7 @@ export const button = tv({
|
|
|
66
66
|
{
|
|
67
67
|
usage: 'selection',
|
|
68
68
|
selected: false,
|
|
69
|
-
class: { base: 'bg-md-sys-color-surface-container' }
|
|
69
|
+
class: { base: 'bg-md-sys-color-surface-container-high text-md-sys-color-on-surface-variant' }
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
72
|
variant: 'text',
|
|
@@ -275,7 +275,7 @@ export const buttonIcon = tv({
|
|
|
275
275
|
{
|
|
276
276
|
variation: 'toggle',
|
|
277
277
|
selected: false,
|
|
278
|
-
class: { base: 'bg-md-sys-color-surface-container' }
|
|
278
|
+
class: { base: 'bg-md-sys-color-surface-container-high text-md-sys-color-on-surface-variant' }
|
|
279
279
|
},
|
|
280
280
|
{
|
|
281
281
|
variant: 'text',
|
|
@@ -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 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,9 @@ export type FABProps = FABVariants & AnchorButtonAttributes & {
|
|
|
157
157
|
*/
|
|
158
158
|
children?: Snippet;
|
|
159
159
|
};
|
|
160
|
-
export type FABMenuProps =
|
|
161
|
-
/**
|
|
162
|
-
|
|
163
|
-
*/
|
|
164
|
-
position?: FABMenuVariants['position'];
|
|
160
|
+
export type FABMenuProps = HTMLAttributes<HTMLUListElement> & {
|
|
161
|
+
/** The FAB button element to position the menu relative to. */
|
|
162
|
+
anchorEl: HTMLElement;
|
|
165
163
|
/**
|
|
166
164
|
* The menu items. Use `FABMenuItem` components.
|
|
167
165
|
*/
|
|
@@ -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 = [],
|