margo-ui 1.2.4 → 1.3.1
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/README.md +1 -1
- package/package.json +1 -1
- package/src/components/button_micro/button_micro.tsx +37 -0
- package/src/components/button_micro/style.ts +6 -0
- package/src/components/button_micro/type.ts +10 -0
- package/src/components/dialog/dialog.tsx +25 -0
- package/src/components/dialog/style.ts +6 -0
- package/src/components/dialog/type.ts +8 -0
- package/src/components/header/header.tsx +36 -0
- package/src/components/header/style.ts +8 -0
- package/src/components/header/type.ts +20 -0
- package/src/components/item/style.ts +1 -1
- package/src/components/layer/layer.css +51 -0
- package/src/components/layer/layer.tsx +44 -0
- package/src/components/layer/style.ts +2 -0
- package/src/components/layer/type.ts +8 -0
- package/src/components/navigation_bar/navigation_bar.tsx +15 -8
- package/src/components/sheet/sheet.css +41 -0
- package/src/components/sheet/sheet.tsx +32 -0
- package/src/components/sheet/style.ts +14 -0
- package/src/components/sheet/type.ts +14 -0
- package/src/css/theme.css +8 -0
- package/src/css/variables.css +11 -0
- package/src/hoc/mask_gradient_x/mask_gradient_x.css +17 -0
- package/src/hoc/mask_gradient_x/mask_gradient_x.tsx +22 -0
- package/src/hoc/mask_gradient_x/type.ts +15 -0
- package/src/index.ts +17 -0
package/README.md
CHANGED
|
@@ -28,7 +28,7 @@ The package is published as TypeScript source: your bundler compiles it, exactly
|
|
|
28
28
|
|
|
29
29
|
## Approach
|
|
30
30
|
|
|
31
|
-
- **Tokens
|
|
31
|
+
- **Tokens first.** Colours, type and elevation are `--margo-` custom properties, mirrored into Tailwind's theme: redeclaring them themes the kit. Per-instance overrides go through `className`, merged over the defaults.
|
|
32
32
|
- **CSS first.** Effects live on pseudo-elements; JavaScript only writes coordinates. Most components hold no state.
|
|
33
33
|
- **Polymorphic.** `as` chooses the rendered element, and the remaining props are typed against it.
|
|
34
34
|
- **Composed, not configured.** Components expose parts to mount rather than booleans to set.
|
package/package.json
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Tag } from "react-renderable";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import { buttonMicroActiveClassName, buttonMicroBaseClassName, buttonMicroSurfaceClassName } from "./style.js";
|
|
5
|
+
|
|
6
|
+
import type { ElementType, MouseEvent } from "react";
|
|
7
|
+
import type { ButtonMicroProps } from "./type.js";
|
|
8
|
+
|
|
9
|
+
export const ButtonMicro = <T extends ElementType = "button">({
|
|
10
|
+
active = false,
|
|
11
|
+
onClickBlur,
|
|
12
|
+
onClick,
|
|
13
|
+
className,
|
|
14
|
+
...rest
|
|
15
|
+
}: ButtonMicroProps<T>) => {
|
|
16
|
+
const handleClick = (event: MouseEvent<HTMLElement>) => {
|
|
17
|
+
onClick?.(event);
|
|
18
|
+
if (typeof onClickBlur === "function") {
|
|
19
|
+
const target = event.currentTarget;
|
|
20
|
+
onClickBlur(event);
|
|
21
|
+
setTimeout(() => target.blur(), 150);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Tag
|
|
27
|
+
{...Tag.forward<T>(rest, "button")}
|
|
28
|
+
data-margo-active={active}
|
|
29
|
+
onClick={handleClick}
|
|
30
|
+
className={cn(
|
|
31
|
+
buttonMicroBaseClassName,
|
|
32
|
+
active ? buttonMicroActiveClassName : buttonMicroSurfaceClassName,
|
|
33
|
+
className,
|
|
34
|
+
)}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const buttonMicroBaseClassName = `w-fit text-xs underline underline-offset-2 outline-none
|
|
2
|
+
focus-visible:text-on-main`;
|
|
3
|
+
|
|
4
|
+
export const buttonMicroSurfaceClassName = "text-medium hover:text-on-main";
|
|
5
|
+
|
|
6
|
+
export const buttonMicroActiveClassName = "text-primary-darken";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TagProps } from "react-renderable";
|
|
2
|
+
import type { ElementType, MouseEventHandler } from "react";
|
|
3
|
+
|
|
4
|
+
export type ButtonMicroOwnProps = {
|
|
5
|
+
active?: boolean;
|
|
6
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
7
|
+
onClickBlur?: MouseEventHandler<HTMLElement>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type ButtonMicroProps<T extends ElementType = "button"> = TagProps<T, ButtonMicroOwnProps>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Tag } from "react-renderable";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import { dialogBaseClassName, dialogBodyClassName, dialogFooterClassName } from "./style.js";
|
|
5
|
+
|
|
6
|
+
import type { ElementType } from "react";
|
|
7
|
+
import type { DialogBodyProps, DialogFooterProps, DialogProps } from "./type.js";
|
|
8
|
+
|
|
9
|
+
export const Dialog = <T extends ElementType = "div">({ className, children, ...rest }: DialogProps<T>) => (
|
|
10
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(dialogBaseClassName, className)}>
|
|
11
|
+
{children}
|
|
12
|
+
</Tag>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
Dialog.Body = <T extends ElementType = "div">({ className, children, ...rest }: DialogBodyProps<T>) => (
|
|
16
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(dialogBodyClassName, className)}>
|
|
17
|
+
{children}
|
|
18
|
+
</Tag>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
Dialog.Footer = <T extends ElementType = "div">({ className, children, ...rest }: DialogFooterProps<T>) => (
|
|
22
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(dialogFooterClassName, className)}>
|
|
23
|
+
{children}
|
|
24
|
+
</Tag>
|
|
25
|
+
);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const dialogBaseClassName = `flex m-4 max-h-[calc(100%-2rem)] w-[calc(100%-2rem)] flex-col overflow-hidden
|
|
2
|
+
rounded-lg border-2 border-border bg-main text-on-main shadow-sm`;
|
|
3
|
+
|
|
4
|
+
export const dialogBodyClassName = "min-h-0 flex-1 overflow-y-auto px-5 py-4 text-sm";
|
|
5
|
+
|
|
6
|
+
export const dialogFooterClassName = "flex items-center justify-end gap-2 border-t-2 border-border px-5 py-4";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { TagProps } from "react-renderable";
|
|
2
|
+
import type { ElementType } from "react";
|
|
3
|
+
|
|
4
|
+
export type DialogProps<T extends ElementType = "div"> = TagProps<T>;
|
|
5
|
+
|
|
6
|
+
export type DialogBodyProps<T extends ElementType = "div"> = TagProps<T>;
|
|
7
|
+
|
|
8
|
+
export type DialogFooterProps<T extends ElementType = "div"> = TagProps<T>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Tag } from "react-renderable";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import {
|
|
5
|
+
headerBaseClassName,
|
|
6
|
+
headerLeadingClassName,
|
|
7
|
+
headerTitleClassName,
|
|
8
|
+
headerTrailingClassName,
|
|
9
|
+
} from "./style.js";
|
|
10
|
+
|
|
11
|
+
import type { ElementType } from "react";
|
|
12
|
+
import type { HeaderLeadingProps, HeaderProps, HeaderTitleProps, HeaderTrailingProps } from "./type.js";
|
|
13
|
+
|
|
14
|
+
export const Header = <T extends ElementType = "header">({ className, children, ...rest }: HeaderProps<T>) => (
|
|
15
|
+
<Tag {...Tag.forward<T>(rest, "header")} className={cn(headerBaseClassName, className)}>
|
|
16
|
+
{children}
|
|
17
|
+
</Tag>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
Header.Leading = ({ children, className }: HeaderLeadingProps) => (
|
|
21
|
+
<span data-margo-header-slot={true} className={cn(headerLeadingClassName, className)}>
|
|
22
|
+
{children}
|
|
23
|
+
</span>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
Header.Title = ({ title, id, className }: HeaderTitleProps) => (
|
|
27
|
+
<span data-margo-header-slot={true} id={id} className={cn(headerTitleClassName, className)}>
|
|
28
|
+
{title}
|
|
29
|
+
</span>
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
Header.Trailing = ({ children, className }: HeaderTrailingProps) => (
|
|
33
|
+
<span data-margo-header-slot={true} className={cn(headerTrailingClassName, className)}>
|
|
34
|
+
{children}
|
|
35
|
+
</span>
|
|
36
|
+
);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const headerBaseClassName = "flex w-full items-center gap-3 px-5 py-4 shadow-sm";
|
|
2
|
+
|
|
3
|
+
export const headerLeadingClassName = "flex shrink-0 items-center gap-2";
|
|
4
|
+
|
|
5
|
+
export const headerTitleClassName = "min-w-0 flex-1 line-clamp-2 text-md font-semibold text-on-main";
|
|
6
|
+
|
|
7
|
+
export const headerTrailingClassName = `ml-auto flex shrink-0 items-center gap-2
|
|
8
|
+
[[data-margo-header-slot]+&]:ml-0`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TagProps } from "react-renderable";
|
|
2
|
+
import type { ElementType, ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
export type HeaderProps<T extends ElementType = "header"> = TagProps<T>;
|
|
5
|
+
|
|
6
|
+
export type HeaderLeadingProps = {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type HeaderTitleProps = {
|
|
12
|
+
title: ReactNode;
|
|
13
|
+
id?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type HeaderTrailingProps = {
|
|
18
|
+
children?: ReactNode;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
@@ -7,7 +7,7 @@ hover:shadow-item focus-visible:shadow-item`;
|
|
|
7
7
|
|
|
8
8
|
export const itemActiveClassName = "margo-border-gradient-primary text-on-main shadow-item";
|
|
9
9
|
|
|
10
|
-
export const itemIconClassName = `ml-auto flex size-4 shrink-0 items-center justify-center
|
|
10
|
+
export const itemIconClassName = `ml-auto flex size-4 shrink-0 items-center justify-center first:ml-0
|
|
11
11
|
[[data-margo-item-slot]+&]:ml-0`;
|
|
12
12
|
|
|
13
13
|
export const itemLabelClassName = "min-w-0 truncate text-left";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.margo-layer {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
z-index: var(--margo-layer-z-index);
|
|
5
|
+
transition:
|
|
6
|
+
visibility var(--margo-layer-duration) var(--margo-layer-easing),
|
|
7
|
+
overlay var(--margo-layer-duration) var(--margo-layer-easing) allow-discrete,
|
|
8
|
+
display var(--margo-layer-duration) var(--margo-layer-easing) allow-discrete;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.margo-layer:not([open]) {
|
|
12
|
+
visibility: hidden;
|
|
13
|
+
pointer-events: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.margo-layer > *:not([data-margo-travel]) {
|
|
17
|
+
opacity: 0;
|
|
18
|
+
transition: opacity var(--margo-layer-duration) var(--margo-layer-easing);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.margo-layer[open] > *:not([data-margo-travel]) {
|
|
22
|
+
opacity: 1;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@starting-style {
|
|
26
|
+
.margo-layer[open] > *:not([data-margo-travel]) {
|
|
27
|
+
opacity: 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.margo-layer::backdrop {
|
|
32
|
+
opacity: 0;
|
|
33
|
+
transition:
|
|
34
|
+
opacity var(--margo-layer-duration) var(--margo-layer-easing),
|
|
35
|
+
overlay var(--margo-layer-duration) var(--margo-layer-easing) allow-discrete,
|
|
36
|
+
display var(--margo-layer-duration) var(--margo-layer-easing) allow-discrete;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.margo-layer[open]::backdrop {
|
|
40
|
+
opacity: 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@starting-style {
|
|
44
|
+
.margo-layer[open]::backdrop {
|
|
45
|
+
opacity: 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
html:has(.margo-layer[open]) {
|
|
50
|
+
overflow: clip;
|
|
51
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import { layerBaseClassName } from "./style.js";
|
|
5
|
+
|
|
6
|
+
import type { MouseEvent, SyntheticEvent } from "react";
|
|
7
|
+
import type { LayerProps } from "./type.js";
|
|
8
|
+
|
|
9
|
+
import "./layer.css";
|
|
10
|
+
|
|
11
|
+
export const Layer = ({ open = false, onClose, dismissible = true, className, children, ...rest }: LayerProps) => {
|
|
12
|
+
const layerRef = useRef<HTMLDialogElement>(null);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const layer = layerRef.current;
|
|
16
|
+
|
|
17
|
+
if (!layer) return;
|
|
18
|
+
if (open && !layer.open) layer.showModal();
|
|
19
|
+
if (!open && layer.open) layer.close();
|
|
20
|
+
}, [open]);
|
|
21
|
+
|
|
22
|
+
const handleClick = (event: MouseEvent<HTMLDialogElement>) => {
|
|
23
|
+
if (!dismissible || event.target !== event.currentTarget) return;
|
|
24
|
+
|
|
25
|
+
onClose?.();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const handleCancel = (event: SyntheticEvent<HTMLDialogElement>) => {
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
onClose?.();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<dialog
|
|
35
|
+
{...rest}
|
|
36
|
+
ref={layerRef}
|
|
37
|
+
onCancel={handleCancel}
|
|
38
|
+
onClick={handleClick}
|
|
39
|
+
className={cn(layerBaseClassName, className)}
|
|
40
|
+
>
|
|
41
|
+
{children}
|
|
42
|
+
</dialog>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
@@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from "react";
|
|
|
3
3
|
import { Tag } from "react-renderable";
|
|
4
4
|
|
|
5
5
|
import { cn } from "../../utils/cn/cn.js";
|
|
6
|
-
import {
|
|
6
|
+
import { navigationBarBaseClassName, navigationBarDefaultFill, navigationBarTrackClassName } from "./style.js";
|
|
7
7
|
|
|
8
8
|
import type { CSSProperties, ElementType } from "react";
|
|
9
9
|
import type { NavigationBarProps } from "./type.js";
|
|
@@ -14,7 +14,8 @@ const TRICKLE_MS = 200;
|
|
|
14
14
|
const TRICKLE_CEILING = 90;
|
|
15
15
|
const TRICKLE_RATIO = 0.12;
|
|
16
16
|
const START_PROGRESS = 8;
|
|
17
|
-
const
|
|
17
|
+
const HOLD_MS = 300;
|
|
18
|
+
const FADE_MS = 400;
|
|
18
19
|
|
|
19
20
|
export const NavigationBar = <T extends ElementType = "div">({
|
|
20
21
|
loading = false,
|
|
@@ -25,10 +26,12 @@ export const NavigationBar = <T extends ElementType = "div">({
|
|
|
25
26
|
const [progress, setProgress] = useState(0);
|
|
26
27
|
const [isVisible, setIsVisible] = useState(false);
|
|
27
28
|
const timeoutRef = useRef<number | undefined>(undefined);
|
|
29
|
+
const resetRef = useRef<number | undefined>(undefined);
|
|
28
30
|
|
|
29
31
|
useEffect(() => {
|
|
30
32
|
if (loading) {
|
|
31
33
|
window.clearTimeout(timeoutRef.current);
|
|
34
|
+
window.clearTimeout(resetRef.current);
|
|
32
35
|
setIsVisible(true);
|
|
33
36
|
setProgress(START_PROGRESS);
|
|
34
37
|
|
|
@@ -41,12 +44,14 @@ export const NavigationBar = <T extends ElementType = "div">({
|
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
setProgress((current) => (current > 0 ? 100 : 0));
|
|
44
|
-
timeoutRef.current = window.setTimeout(() => {
|
|
45
|
-
setIsVisible(false);
|
|
46
|
-
setProgress(0);
|
|
47
|
-
}, FADE_MS);
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
timeoutRef.current = window.setTimeout(() => setIsVisible(false), HOLD_MS);
|
|
49
|
+
resetRef.current = window.setTimeout(() => setProgress(0), HOLD_MS + FADE_MS);
|
|
50
|
+
|
|
51
|
+
return () => {
|
|
52
|
+
window.clearTimeout(timeoutRef.current);
|
|
53
|
+
window.clearTimeout(resetRef.current);
|
|
54
|
+
};
|
|
50
55
|
}, [loading]);
|
|
51
56
|
|
|
52
57
|
return (
|
|
@@ -54,7 +59,9 @@ export const NavigationBar = <T extends ElementType = "div">({
|
|
|
54
59
|
{...Tag.forward<T>(rest)}
|
|
55
60
|
role="progressbar"
|
|
56
61
|
aria-hidden={!isVisible}
|
|
57
|
-
style={
|
|
62
|
+
style={
|
|
63
|
+
{ "--margo-navigation-bar-fill": fill, "--margo-navigation-bar-progress": `${progress}%` } as CSSProperties
|
|
64
|
+
}
|
|
58
65
|
className={cn(navigationBarBaseClassName, isVisible ? "opacity-100" : "opacity-0", className)}
|
|
59
66
|
>
|
|
60
67
|
<div className={navigationBarTrackClassName} />
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
.margo-sheet {
|
|
2
|
+
transition: translate var(--margo-layer-duration) var(--margo-layer-easing);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.margo-sheet[data-margo-side="start"] {
|
|
6
|
+
translate: -100% 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.margo-sheet[data-margo-side="end"] {
|
|
10
|
+
translate: 100% 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.margo-sheet[data-margo-side="top"] {
|
|
14
|
+
translate: 0 -100%;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.margo-sheet[data-margo-side="bottom"] {
|
|
18
|
+
translate: 0 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dialog[open] .margo-sheet {
|
|
22
|
+
translate: 0 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@starting-style {
|
|
26
|
+
dialog[open] .margo-sheet[data-margo-side="start"] {
|
|
27
|
+
translate: -100% 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
dialog[open] .margo-sheet[data-margo-side="end"] {
|
|
31
|
+
translate: 100% 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
dialog[open] .margo-sheet[data-margo-side="top"] {
|
|
35
|
+
translate: 0 -100%;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
dialog[open] .margo-sheet[data-margo-side="bottom"] {
|
|
39
|
+
translate: 0 100%;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Tag } from "react-renderable";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import { sheetBaseClassName, sheetBodyClassName, sheetFooterClassName, sheetSideClassName } from "./style.js";
|
|
5
|
+
|
|
6
|
+
import type { ElementType } from "react";
|
|
7
|
+
import type { SheetBodyProps, SheetFooterProps, SheetProps } from "./type.js";
|
|
8
|
+
|
|
9
|
+
import "./sheet.css";
|
|
10
|
+
|
|
11
|
+
export const Sheet = <T extends ElementType = "div">({ side = "end", className, children, ...rest }: SheetProps<T>) => (
|
|
12
|
+
<Tag
|
|
13
|
+
{...Tag.forward<T>(rest)}
|
|
14
|
+
data-margo-side={side}
|
|
15
|
+
data-margo-travel={true}
|
|
16
|
+
className={cn(sheetBaseClassName, sheetSideClassName[side], className)}
|
|
17
|
+
>
|
|
18
|
+
{children}
|
|
19
|
+
</Tag>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
Sheet.Body = <T extends ElementType = "div">({ className, children, ...rest }: SheetBodyProps<T>) => (
|
|
23
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(sheetBodyClassName, className)}>
|
|
24
|
+
{children}
|
|
25
|
+
</Tag>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
Sheet.Footer = <T extends ElementType = "div">({ className, children, ...rest }: SheetFooterProps<T>) => (
|
|
29
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(sheetFooterClassName, className)}>
|
|
30
|
+
{children}
|
|
31
|
+
</Tag>
|
|
32
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SheetSide } from "./type.js";
|
|
2
|
+
|
|
3
|
+
export const sheetBaseClassName = "margo-sheet flex flex-col overflow-hidden border-border bg-main text-on-main";
|
|
4
|
+
|
|
5
|
+
export const sheetSideClassName: Record<SheetSide, string> = {
|
|
6
|
+
start: "h-full w-[85%] max-w-[26rem] justify-self-start self-stretch border-r-2",
|
|
7
|
+
end: "h-full w-[85%] max-w-[26rem] justify-self-end self-stretch border-l-2",
|
|
8
|
+
top: "h-auto max-h-[40%] w-full self-start justify-self-stretch border-b-2",
|
|
9
|
+
bottom: "h-auto max-h-[40%] w-full self-end justify-self-stretch border-t-2",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const sheetBodyClassName = "min-h-0 flex-1 overflow-y-auto px-5 py-4 text-sm";
|
|
13
|
+
|
|
14
|
+
export const sheetFooterClassName = "flex items-center justify-end gap-2 border-t-2 border-border px-5 py-4";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TagProps } from "react-renderable";
|
|
2
|
+
import type { ElementType } from "react";
|
|
3
|
+
|
|
4
|
+
export type SheetSide = "start" | "end" | "top" | "bottom";
|
|
5
|
+
|
|
6
|
+
export type SheetOwnProps = {
|
|
7
|
+
side?: SheetSide;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type SheetProps<T extends ElementType = "div"> = TagProps<T, SheetOwnProps>;
|
|
11
|
+
|
|
12
|
+
export type SheetBodyProps<T extends ElementType = "div"> = TagProps<T>;
|
|
13
|
+
|
|
14
|
+
export type SheetFooterProps<T extends ElementType = "div"> = TagProps<T>;
|
package/src/css/theme.css
CHANGED
|
@@ -29,6 +29,14 @@
|
|
|
29
29
|
--shadow-item: var(--margo-shadow-item);
|
|
30
30
|
--shadow-chip: var(--margo-shadow-chip);
|
|
31
31
|
|
|
32
|
+
/* Durations */
|
|
33
|
+
--duration-layer: var(--margo-layer-duration);
|
|
34
|
+
--ease-layer: var(--margo-layer-easing);
|
|
35
|
+
|
|
36
|
+
/* Layers */
|
|
37
|
+
--z-index-layer: var(--margo-layer-z-index);
|
|
38
|
+
--z-index-max: var(--margo-max-z-index);
|
|
39
|
+
|
|
32
40
|
/* Border widths */
|
|
33
41
|
--border-width-2: var(--margo-border-width-2);
|
|
34
42
|
|
package/src/css/variables.css
CHANGED
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
|
|
32
32
|
--margo-border-width-2: 1.5px;
|
|
33
33
|
|
|
34
|
+
--margo-layer-duration: 750ms;
|
|
35
|
+
--margo-layer-easing: cubic-bezier(0.32, 0.72, 0, 1);
|
|
36
|
+
--margo-layer-z-index: 100;
|
|
37
|
+
--margo-max-z-index: 9999;
|
|
38
|
+
|
|
34
39
|
--margo-grid-max-width: 80rem;
|
|
35
40
|
--margo-grid-padding: 1rem;
|
|
36
41
|
--margo-grid-gutter-x: 2rem;
|
|
@@ -101,3 +106,9 @@
|
|
|
101
106
|
--margo-code-type: #79c0ff;
|
|
102
107
|
--margo-code-punct: #8b949e;
|
|
103
108
|
}
|
|
109
|
+
|
|
110
|
+
@media (prefers-reduced-motion: reduce) {
|
|
111
|
+
:root {
|
|
112
|
+
--margo-layer-duration: 1ms;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.margo-mask-gradient-x {
|
|
2
|
+
--margo-mask-gradient-x-offset-left: 0px;
|
|
3
|
+
--margo-mask-gradient-x-offset-right: 0px;
|
|
4
|
+
--margo-mask-gradient-x-fade-left: 2rem;
|
|
5
|
+
--margo-mask-gradient-x-fade-right: 2rem;
|
|
6
|
+
|
|
7
|
+
--margo-mask-gradient-x-image: linear-gradient(
|
|
8
|
+
to right,
|
|
9
|
+
transparent var(--margo-mask-gradient-x-offset-left),
|
|
10
|
+
#000 calc(var(--margo-mask-gradient-x-offset-left) + var(--margo-mask-gradient-x-fade-left)),
|
|
11
|
+
#000 calc(100% - var(--margo-mask-gradient-x-offset-right) - var(--margo-mask-gradient-x-fade-right)),
|
|
12
|
+
transparent calc(100% - var(--margo-mask-gradient-x-offset-right))
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
-webkit-mask-image: var(--margo-mask-gradient-x-image);
|
|
16
|
+
mask-image: var(--margo-mask-gradient-x-image);
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { cloneElement } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
|
|
5
|
+
import type { CSSProperties } from "react";
|
|
6
|
+
import type { MaskGradientXProps } from "./type.js";
|
|
7
|
+
|
|
8
|
+
import "./mask_gradient_x.css";
|
|
9
|
+
|
|
10
|
+
export const MaskGradientX = ({ children, fade, fadeLeft, fadeRight, offsetLeft, offsetRight }: MaskGradientXProps) => {
|
|
11
|
+
const style = {
|
|
12
|
+
"--margo-mask-gradient-x-offset-left": offsetLeft,
|
|
13
|
+
"--margo-mask-gradient-x-offset-right": offsetRight,
|
|
14
|
+
"--margo-mask-gradient-x-fade-left": fadeLeft ?? fade,
|
|
15
|
+
"--margo-mask-gradient-x-fade-right": fadeRight ?? fade,
|
|
16
|
+
} as CSSProperties;
|
|
17
|
+
|
|
18
|
+
return cloneElement(children, {
|
|
19
|
+
className: cn("margo-mask-gradient-x", children.props.className),
|
|
20
|
+
style: { ...style, ...children.props.style },
|
|
21
|
+
});
|
|
22
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CSSProperties, ReactElement } from "react";
|
|
2
|
+
|
|
3
|
+
export type MaskGradientXChildProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
style?: CSSProperties;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type MaskGradientXProps = {
|
|
9
|
+
children: ReactElement<MaskGradientXChildProps>;
|
|
10
|
+
fade?: string;
|
|
11
|
+
fadeLeft?: string;
|
|
12
|
+
fadeRight?: string;
|
|
13
|
+
offsetLeft?: string;
|
|
14
|
+
offsetRight?: string;
|
|
15
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
export { Blockquote } from "./components/blockquote/blockquote.js";
|
|
2
2
|
export { Button } from "./components/button/button.js";
|
|
3
|
+
export { ButtonMicro } from "./components/button_micro/button_micro.js";
|
|
3
4
|
export { Card } from "./components/card/card.js";
|
|
4
5
|
export { Chip } from "./components/chip/chip.js";
|
|
6
|
+
export { Dialog } from "./components/dialog/dialog.js";
|
|
7
|
+
export { Header } from "./components/header/header.js";
|
|
8
|
+
export { Layer } from "./components/layer/layer.js";
|
|
5
9
|
export { Item } from "./components/item/item.js";
|
|
6
10
|
export { NavigationBar } from "./components/navigation_bar/navigation_bar.js";
|
|
7
11
|
export { ProgressBar } from "./components/progress_bar/progress_bar.js";
|
|
8
12
|
export { Table } from "./components/table/table.js";
|
|
9
13
|
export { Splash } from "./components/splash/splash.js";
|
|
14
|
+
export { Sheet } from "./components/sheet/sheet.js";
|
|
10
15
|
export { Snippet } from "./components/snippet/snippet.js";
|
|
11
16
|
export { Spinner } from "./components/spinner/spinner.js";
|
|
12
17
|
export { Tooltip } from "./components/tooltip/tooltip.js";
|
|
13
18
|
|
|
14
19
|
export { BackgroundGlow } from "./hoc/background_glow/background_glow.js";
|
|
15
20
|
export { BorderGlow } from "./hoc/border_glow/border_glow.js";
|
|
21
|
+
export { MaskGradientX } from "./hoc/mask_gradient_x/mask_gradient_x.js";
|
|
16
22
|
export { MaskGradientY } from "./hoc/mask_gradient_y/mask_gradient_y.js";
|
|
17
23
|
export { Ripple } from "./hoc/ripple/ripple.js";
|
|
18
24
|
|
|
@@ -32,8 +38,17 @@ export type {
|
|
|
32
38
|
ButtonLabelProps,
|
|
33
39
|
ButtonProps,
|
|
34
40
|
} from "./components/button/type.js";
|
|
41
|
+
export type { ButtonMicroProps } from "./components/button_micro/type.js";
|
|
35
42
|
export type { CardProps } from "./components/card/type.js";
|
|
36
43
|
export type { ChipProps } from "./components/chip/type.js";
|
|
44
|
+
export type { DialogBodyProps, DialogFooterProps, DialogProps } from "./components/dialog/type.js";
|
|
45
|
+
export type {
|
|
46
|
+
HeaderLeadingProps,
|
|
47
|
+
HeaderProps,
|
|
48
|
+
HeaderTitleProps,
|
|
49
|
+
HeaderTrailingProps,
|
|
50
|
+
} from "./components/header/type.js";
|
|
51
|
+
export type { LayerProps } from "./components/layer/type.js";
|
|
37
52
|
export type { ItemIconProps, ItemLabelProps, ItemProps } from "./components/item/type.js";
|
|
38
53
|
export type { NavigationBarProps } from "./components/navigation_bar/type.js";
|
|
39
54
|
export type { ProgressBarMode, ProgressBarProps } from "./components/progress_bar/type.js";
|
|
@@ -46,12 +61,14 @@ export type {
|
|
|
46
61
|
TableRowProps,
|
|
47
62
|
} from "./components/table/type.js";
|
|
48
63
|
export type { SplashProps, SplashServeProps } from "./components/splash/type.js";
|
|
64
|
+
export type { SheetBodyProps, SheetFooterProps, SheetProps, SheetSide } from "./components/sheet/type.js";
|
|
49
65
|
export type { SnippetProps, SnippetToken, SnippetTokenType } from "./components/snippet/type.js";
|
|
50
66
|
export type { SpinnerProps } from "./components/spinner/type.js";
|
|
51
67
|
export type { TooltipPosition, TooltipProps } from "./components/tooltip/type.js";
|
|
52
68
|
|
|
53
69
|
export type { BackgroundGlowProps } from "./hoc/background_glow/type.js";
|
|
54
70
|
export type { BorderGlowPosition, BorderGlowProps } from "./hoc/border_glow/type.js";
|
|
71
|
+
export type { MaskGradientXProps } from "./hoc/mask_gradient_x/type.js";
|
|
55
72
|
export type { MaskGradientYProps } from "./hoc/mask_gradient_y/type.js";
|
|
56
73
|
export type { RippleProps } from "./hoc/ripple/type.js";
|
|
57
74
|
|