margo-ui 2.0.0 → 2.1.0
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/package.json +1 -1
- package/src/components/button/style.ts +2 -2
- package/src/components/checkbox/checkbox.css +28 -0
- package/src/components/checkbox/checkbox.tsx +30 -0
- package/src/components/checkbox/style.ts +5 -0
- package/src/components/checkbox/type.ts +5 -0
- package/src/components/chip/style.ts +3 -2
- package/src/components/layer/layer.tsx +8 -0
- package/src/components/popover/popover.css +18 -0
- package/src/components/popover/popover.tsx +113 -0
- package/src/components/popover/style.ts +39 -0
- package/src/components/popover/type.ts +19 -0
- package/src/components/select/select.tsx +49 -0
- package/src/components/select/style.ts +15 -0
- package/src/components/select/type.ts +13 -0
- package/src/components/snippet/snippet.tsx +16 -2
- package/src/components/snippet/style.ts +6 -3
- package/src/components/snippet/type.ts +4 -1
- package/src/components/splash/splash.tsx +3 -5
- package/src/components/splash/style.ts +3 -1
- package/src/components/toggle/style.ts +4 -0
- package/src/components/toggle/toggle.css +18 -0
- package/src/components/toggle/toggle.tsx +10 -0
- package/src/components/toggle/type.ts +3 -0
- package/src/css/variables.css +5 -0
- package/src/index.ts +10 -1
- package/src/utils/support/support.ts +2 -0
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export const buttonBaseClassName = `group/button flex h-8 w-fit shrink-0 items-center px-2 rounded-lg border-2 text-on-main
|
|
2
2
|
hover:border-on-main hover:text-on-main focus-visible:border-primary
|
|
3
3
|
focus-visible:outline focus-visible:outline-offset-1 focus-visible:outline-on-main
|
|
4
|
-
select-none origin-center transition-transform duration-[160ms] ease-out active:scale-[0.95]`;
|
|
4
|
+
select-none origin-center transition-transform duration-[160ms] ease-out active:scale-[0.95] bg-main`;
|
|
5
5
|
|
|
6
|
-
export const buttonSurfaceClassName = "border-border
|
|
6
|
+
export const buttonSurfaceClassName = "border-border";
|
|
7
7
|
|
|
8
8
|
export const buttonActiveClassName = "border-primary shadow-button";
|
|
9
9
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
.margo-checkbox {
|
|
2
|
+
appearance: none;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.margo-checkbox::before {
|
|
6
|
+
content: "";
|
|
7
|
+
display: block;
|
|
8
|
+
block-size: 100%;
|
|
9
|
+
inline-size: 100%;
|
|
10
|
+
background-color: currentColor;
|
|
11
|
+
clip-path: polygon(14% 44%, 0 60%, 39% 100%, 100% 16%, 85% 0, 39% 69%);
|
|
12
|
+
scale: 0.6;
|
|
13
|
+
opacity: 0;
|
|
14
|
+
transition:
|
|
15
|
+
scale 160ms ease-out,
|
|
16
|
+
opacity 160ms ease-out;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.margo-checkbox:checked::before {
|
|
20
|
+
scale: 1;
|
|
21
|
+
opacity: 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.margo-checkbox:indeterminate::before {
|
|
25
|
+
clip-path: inset(44% 12% 44% 12% round 1px);
|
|
26
|
+
scale: 1;
|
|
27
|
+
opacity: 1;
|
|
28
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import { checkboxBaseClassName } from "./style.js";
|
|
5
|
+
|
|
6
|
+
import type { CheckboxProps } from "./type.js";
|
|
7
|
+
|
|
8
|
+
import "./checkbox.css";
|
|
9
|
+
|
|
10
|
+
export const Checkbox = ({ indeterminate = false, className, ref, ...rest }: CheckboxProps) => {
|
|
11
|
+
const checkboxRef = useRef<HTMLInputElement>(null);
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (checkboxRef.current) checkboxRef.current.indeterminate = indeterminate;
|
|
15
|
+
}, [indeterminate]);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<input
|
|
19
|
+
{...rest}
|
|
20
|
+
ref={(node) => {
|
|
21
|
+
checkboxRef.current = node;
|
|
22
|
+
|
|
23
|
+
if (typeof ref === "function") ref(node);
|
|
24
|
+
else if (ref) ref.current = node;
|
|
25
|
+
}}
|
|
26
|
+
type="checkbox"
|
|
27
|
+
className={cn(checkboxBaseClassName, className)}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const checkboxBaseClassName = `margo-checkbox size-5 flex-none cursor-pointer rounded-md border-2 border-border
|
|
2
|
+
bg-main p-1 text-on-main enabled:hover:border-on-main focus-visible:border-primary focus-visible:outline
|
|
3
|
+
focus-visible:outline-offset-1 focus-visible:outline-on-main checked:border-primary indeterminate:border-primary
|
|
4
|
+
select-none origin-center transition-transform duration-[120ms] ease-out active:scale-[0.95] disabled:cursor-auto
|
|
5
|
+
disabled:opacity-40`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export const chipBaseClassName =
|
|
2
|
-
|
|
1
|
+
export const chipBaseClassName = `bg-on-main/8 margo-text-box-trim flex items-center justify-center px-3 py-0.5
|
|
2
|
+
whitespace-nowrap lowercase flex-none leading-none rounded-md text-mc shadow-chip
|
|
3
|
+
focus-visible:outline focus-visible:outline-offset-1 focus-visible:outline-on-main`;
|
|
3
4
|
|
|
4
5
|
export const chipActiveClassName = "bg-on-main text-main";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn/cn.js";
|
|
4
|
+
import { isMargoLayerSupported } from "../../utils/support/support.js";
|
|
4
5
|
import { layerBaseClassName } from "./style.js";
|
|
5
6
|
|
|
6
7
|
import type { MouseEvent, SyntheticEvent } from "react";
|
|
@@ -21,6 +22,13 @@ export const Layer = ({ open = false, onClose, dismissible = true, className, ch
|
|
|
21
22
|
const layer = layerRef.current;
|
|
22
23
|
|
|
23
24
|
if (!layer) return;
|
|
25
|
+
|
|
26
|
+
if (!isMargoLayerSupported()) {
|
|
27
|
+
setIsMounted(open);
|
|
28
|
+
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
if (open && !layer.open) layer.showModal();
|
|
25
33
|
if (open || !layer.open) return;
|
|
26
34
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.margo-popover {
|
|
2
|
+
opacity: 0;
|
|
3
|
+
scale: 0.98;
|
|
4
|
+
transition:
|
|
5
|
+
opacity var(--margo-popover-duration) var(--margo-popover-easing),
|
|
6
|
+
scale var(--margo-popover-duration) var(--margo-popover-easing),
|
|
7
|
+
visibility var(--margo-popover-duration) var(--margo-popover-easing);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.margo-popover:not([data-margo-open="true"]) {
|
|
11
|
+
visibility: hidden;
|
|
12
|
+
pointer-events: none;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.margo-popover[data-margo-open="true"] {
|
|
16
|
+
opacity: 1;
|
|
17
|
+
scale: 1;
|
|
18
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { Tag } from "react-renderable";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
6
|
+
import {
|
|
7
|
+
popoverAnchorClassName,
|
|
8
|
+
popoverBaseClassName,
|
|
9
|
+
popoverBodyClassName,
|
|
10
|
+
popoverOriginClassName,
|
|
11
|
+
popoverPositionClassName,
|
|
12
|
+
} from "./style.js";
|
|
13
|
+
|
|
14
|
+
import type { ElementType } from "react";
|
|
15
|
+
import type { PopoverAnchorProps, PopoverBodyProps, PopoverProps } from "./type.js";
|
|
16
|
+
|
|
17
|
+
import "./popover.css";
|
|
18
|
+
|
|
19
|
+
export const Popover = ({
|
|
20
|
+
open = false,
|
|
21
|
+
onClose,
|
|
22
|
+
dismissible = true,
|
|
23
|
+
position = "down",
|
|
24
|
+
align = "center",
|
|
25
|
+
className,
|
|
26
|
+
children,
|
|
27
|
+
...rest
|
|
28
|
+
}: PopoverProps) => {
|
|
29
|
+
const popoverRef = useRef<HTMLDivElement>(null);
|
|
30
|
+
const childrenRef = useRef(children);
|
|
31
|
+
|
|
32
|
+
const [isMounted, setIsMounted] = useState(open);
|
|
33
|
+
|
|
34
|
+
if (open) childrenRef.current = children;
|
|
35
|
+
if (open && !isMounted) setIsMounted(true);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const popover = popoverRef.current;
|
|
39
|
+
|
|
40
|
+
if (!popover || open || !isMounted) return;
|
|
41
|
+
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
|
|
44
|
+
const frame = requestAnimationFrame(() => {
|
|
45
|
+
const animations = popover.getAnimations({ subtree: true }).map((animation) => animation.finished);
|
|
46
|
+
|
|
47
|
+
void Promise.allSettled(animations).then(() => {
|
|
48
|
+
if (controller.signal.aborted) return;
|
|
49
|
+
|
|
50
|
+
setIsMounted(false);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return () => {
|
|
55
|
+
controller.abort();
|
|
56
|
+
cancelAnimationFrame(frame);
|
|
57
|
+
};
|
|
58
|
+
}, [isMounted, open]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const popover = popoverRef.current;
|
|
62
|
+
|
|
63
|
+
if (!popover || !open || !dismissible) return;
|
|
64
|
+
|
|
65
|
+
const anchor = popover.offsetParent;
|
|
66
|
+
const controller = new AbortController();
|
|
67
|
+
|
|
68
|
+
const handlePointerDown = (event: PointerEvent) => {
|
|
69
|
+
const target = event.target as Node | null;
|
|
70
|
+
|
|
71
|
+
if (!target || popover.contains(target) || anchor?.contains(target)) return;
|
|
72
|
+
|
|
73
|
+
onClose?.();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
77
|
+
if (event.key === "Escape") onClose?.();
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
document.addEventListener("pointerdown", handlePointerDown, { signal: controller.signal });
|
|
81
|
+
document.addEventListener("keydown", handleKeyDown, { signal: controller.signal });
|
|
82
|
+
|
|
83
|
+
return () => controller.abort();
|
|
84
|
+
}, [dismissible, onClose, open]);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div
|
|
88
|
+
{...rest}
|
|
89
|
+
ref={popoverRef}
|
|
90
|
+
data-margo-open={open}
|
|
91
|
+
className={cn(
|
|
92
|
+
popoverBaseClassName,
|
|
93
|
+
popoverPositionClassName[position][align],
|
|
94
|
+
popoverOriginClassName[position],
|
|
95
|
+
className,
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
{isMounted ? childrenRef.current : null}
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
Popover.Anchor = <T extends ElementType = "div">({ className, children, ...rest }: PopoverAnchorProps<T>) => (
|
|
104
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(popoverAnchorClassName, className)}>
|
|
105
|
+
{children}
|
|
106
|
+
</Tag>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
Popover.Body = <T extends ElementType = "div">({ className, children, ...rest }: PopoverBodyProps<T>) => (
|
|
110
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(popoverBodyClassName, className)}>
|
|
111
|
+
{children}
|
|
112
|
+
</Tag>
|
|
113
|
+
);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PopoverAlign, PopoverPosition } from "./type.js";
|
|
2
|
+
|
|
3
|
+
export const popoverAnchorClassName = "relative inline-block size-fit";
|
|
4
|
+
|
|
5
|
+
export const popoverBaseClassName = `margo-popover absolute z-20 m-0 flex w-max max-w-[calc(100vw-2rem)] flex-col
|
|
6
|
+
overflow-clip rounded-lg border-2 border-border bg-main text-on-main shadow-card outline-none`;
|
|
7
|
+
|
|
8
|
+
export const popoverBodyClassName = `flex min-h-0 max-h-56 flex-col gap-1
|
|
9
|
+
overflow-y-auto overscroll-contain w-64 p-2 text-sm`;
|
|
10
|
+
|
|
11
|
+
export const popoverPositionClassName: Record<PopoverPosition, Record<PopoverAlign, string>> = {
|
|
12
|
+
up: {
|
|
13
|
+
start: "bottom-full left-0 my-1",
|
|
14
|
+
center: "bottom-full left-1/2 my-1 -translate-x-1/2",
|
|
15
|
+
end: "right-0 bottom-full my-1",
|
|
16
|
+
},
|
|
17
|
+
down: {
|
|
18
|
+
start: "top-full left-0 my-1",
|
|
19
|
+
center: "top-full left-1/2 my-1 -translate-x-1/2",
|
|
20
|
+
end: "top-full right-0 my-1",
|
|
21
|
+
},
|
|
22
|
+
left: {
|
|
23
|
+
start: "top-0 right-full mx-1",
|
|
24
|
+
center: "top-1/2 right-full mx-1 -translate-y-1/2",
|
|
25
|
+
end: "right-full bottom-0 mx-1",
|
|
26
|
+
},
|
|
27
|
+
right: {
|
|
28
|
+
start: "top-0 left-full mx-1",
|
|
29
|
+
center: "top-1/2 left-full mx-1 -translate-y-1/2",
|
|
30
|
+
end: "bottom-0 left-full mx-1",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const popoverOriginClassName: Record<PopoverPosition, string> = {
|
|
35
|
+
up: "origin-bottom",
|
|
36
|
+
down: "origin-top",
|
|
37
|
+
left: "origin-right",
|
|
38
|
+
right: "origin-left",
|
|
39
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TagProps } from "react-renderable";
|
|
2
|
+
import type { ComponentPropsWithoutRef, ElementType, ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
export type PopoverPosition = "up" | "down" | "left" | "right";
|
|
5
|
+
|
|
6
|
+
export type PopoverAlign = "start" | "center" | "end";
|
|
7
|
+
|
|
8
|
+
export type PopoverProps = ComponentPropsWithoutRef<"div"> & {
|
|
9
|
+
open?: boolean;
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
dismissible?: boolean;
|
|
12
|
+
position?: PopoverPosition;
|
|
13
|
+
align?: PopoverAlign;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type PopoverAnchorProps<T extends ElementType = "div"> = TagProps<T>;
|
|
18
|
+
|
|
19
|
+
export type PopoverBodyProps<T extends ElementType = "div"> = TagProps<T>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MdKeyboardArrowDown } from "react-icons/md";
|
|
2
|
+
|
|
3
|
+
import { List } from "react-renderable";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
6
|
+
import { selectActiveClassName, selectBaseClassName, selectControlClassName, selectIconClassName } from "./style.js";
|
|
7
|
+
|
|
8
|
+
import type { SelectProps } from "./type.js";
|
|
9
|
+
|
|
10
|
+
export const Select = <T,>({
|
|
11
|
+
options = [],
|
|
12
|
+
itemExtractor = null,
|
|
13
|
+
valueExtractor = null,
|
|
14
|
+
placeholder = "",
|
|
15
|
+
canBeEmpty = false,
|
|
16
|
+
active = false,
|
|
17
|
+
clickable = true,
|
|
18
|
+
className,
|
|
19
|
+
...rest
|
|
20
|
+
}: SelectProps<T>) => {
|
|
21
|
+
return (
|
|
22
|
+
<div
|
|
23
|
+
data-margo-active={active}
|
|
24
|
+
inert={!clickable || undefined}
|
|
25
|
+
className={cn(selectBaseClassName, active && selectActiveClassName, className)}
|
|
26
|
+
>
|
|
27
|
+
<select {...rest} className={selectControlClassName}>
|
|
28
|
+
{placeholder ? (
|
|
29
|
+
<option value="" disabled={!canBeEmpty} hidden={!canBeEmpty}>
|
|
30
|
+
{placeholder}
|
|
31
|
+
</option>
|
|
32
|
+
) : null}
|
|
33
|
+
|
|
34
|
+
<List
|
|
35
|
+
array={options}
|
|
36
|
+
itemExtractor={({ row, index }) => (
|
|
37
|
+
<option key={valueExtractor?.({ row, index }) ?? index} value={valueExtractor?.({ row, index })}>
|
|
38
|
+
{itemExtractor?.({ row, index })}
|
|
39
|
+
</option>
|
|
40
|
+
)}
|
|
41
|
+
/>
|
|
42
|
+
</select>
|
|
43
|
+
|
|
44
|
+
<span className={selectIconClassName}>
|
|
45
|
+
<MdKeyboardArrowDown className="text-md translate-x-0.5" />
|
|
46
|
+
</span>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const selectBaseClassName = `group/select relative flex min-h-[2.5rem] w-full items-center gap-1 rounded-lg
|
|
2
|
+
border-2 border-transparent bg-low text-sm text-medium select-none
|
|
3
|
+
hover:border-on-main hover:text-on-main hover:shadow-input
|
|
4
|
+
focus-within:border-primary focus-within:text-on-main
|
|
5
|
+
has-[select:disabled]:pointer-events-none has-[select:disabled]:opacity-40`;
|
|
6
|
+
|
|
7
|
+
export const selectActiveClassName = "border-primary";
|
|
8
|
+
|
|
9
|
+
export const selectControlClassName = `min-w-0 flex-1 cursor-pointer appearance-none truncate rounded-lg
|
|
10
|
+
bg-transparent px-3 py-2 text-left text-on-main outline-none disabled:cursor-auto
|
|
11
|
+
has-[option[value='']:checked]:text-medium
|
|
12
|
+
[&>option]:bg-main [&>option]:text-on-main
|
|
13
|
+
[&>option:checked]:bg-primary-darken [&>option:checked]:text-on-main`;
|
|
14
|
+
|
|
15
|
+
export const selectIconClassName = "pointer-events-none mr-3 flex size-4 flex-none items-center justify-center";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from "react";
|
|
2
|
+
|
|
3
|
+
export type SelectOwnProps<T> = {
|
|
4
|
+
options?: readonly T[];
|
|
5
|
+
itemExtractor?: ((args: { row: T; index: number }) => string) | null;
|
|
6
|
+
valueExtractor?: ((args: { row: T; index: number }) => string | number) | null;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
canBeEmpty?: boolean;
|
|
9
|
+
active?: boolean;
|
|
10
|
+
clickable?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SelectProps<T> = Omit<ComponentPropsWithRef<"select">, "children"> & SelectOwnProps<T>;
|
|
@@ -12,15 +12,22 @@ import {
|
|
|
12
12
|
snippetBaseClassName,
|
|
13
13
|
snippetCodeClassName,
|
|
14
14
|
snippetCopyClassName,
|
|
15
|
+
snippetPreviewClassName,
|
|
15
16
|
snippetTitleClassName,
|
|
16
17
|
snippetTokenClassName,
|
|
17
18
|
} from "./style.js";
|
|
18
19
|
|
|
19
20
|
import type { ElementType } from "react";
|
|
20
21
|
import { MaskGradientX } from "../../hoc/mask_gradient_x/mask_gradient_x.js";
|
|
21
|
-
import type { SnippetProps } from "./type.js";
|
|
22
|
+
import type { SnippetPreviewProps, SnippetProps } from "./type.js";
|
|
22
23
|
|
|
23
|
-
export const Snippet = <T extends ElementType = "div">({
|
|
24
|
+
export const Snippet = <T extends ElementType = "div">({
|
|
25
|
+
snippet,
|
|
26
|
+
title,
|
|
27
|
+
className,
|
|
28
|
+
children,
|
|
29
|
+
...rest
|
|
30
|
+
}: SnippetProps<T>) => {
|
|
24
31
|
const [isCopied, setIsCopied] = useState(false);
|
|
25
32
|
const source = snippet.trim();
|
|
26
33
|
|
|
@@ -61,6 +68,13 @@ export const Snippet = <T extends ElementType = "div">({ snippet, title, classNa
|
|
|
61
68
|
</code>
|
|
62
69
|
</pre>
|
|
63
70
|
</MaskGradientX>
|
|
71
|
+
{children}
|
|
64
72
|
</Tag>
|
|
65
73
|
);
|
|
66
74
|
};
|
|
75
|
+
|
|
76
|
+
Snippet.Preview = <T extends ElementType = "div">({ className, children, ...rest }: SnippetPreviewProps<T>) => (
|
|
77
|
+
<Tag {...Tag.forward<T>(rest)} className={cn(snippetPreviewClassName, className)}>
|
|
78
|
+
{children}
|
|
79
|
+
</Tag>
|
|
80
|
+
);
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { SnippetTokenType } from "./type.js";
|
|
2
2
|
|
|
3
|
-
export const snippetBaseClassName = "
|
|
3
|
+
export const snippetBaseClassName = "rounded-lg border-2 border-border bg-(--margo-code-surface)";
|
|
4
4
|
|
|
5
|
-
export const snippetBarClassName =
|
|
6
|
-
|
|
5
|
+
export const snippetBarClassName = `flex items-center justify-between gap-4 border-b-2 border-border
|
|
6
|
+
rounded-t-[calc(var(--radius-lg)-var(--margo-border-width-2))] bg-(--margo-code-bar) px-3 py-2`;
|
|
7
7
|
|
|
8
8
|
export const snippetTitleClassName = "text-mc uppercase tracking-widest text-medium";
|
|
9
9
|
|
|
10
10
|
export const snippetCopyClassName = "ml-auto bg-neutral/60";
|
|
11
11
|
|
|
12
|
+
export const snippetPreviewClassName =
|
|
13
|
+
"flex flex-wrap items-center justify-center gap-6 rounded-b-lg border-t-2 border-border p-8";
|
|
14
|
+
|
|
12
15
|
export const snippetCodeClassName = "overflow-x-auto p-4 text-xs leading-relaxed";
|
|
13
16
|
|
|
14
17
|
export const snippetTokenClassName: Record<SnippetTokenType, string> = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TagProps } from "react-renderable";
|
|
2
|
-
import type { ElementType } from "react";
|
|
2
|
+
import type { ElementType, ReactNode } from "react";
|
|
3
3
|
|
|
4
4
|
export type SnippetTokenType =
|
|
5
5
|
| "plain"
|
|
@@ -21,6 +21,9 @@ export type SnippetToken = {
|
|
|
21
21
|
export type SnippetOwnProps = {
|
|
22
22
|
snippet: string;
|
|
23
23
|
title?: string;
|
|
24
|
+
children?: ReactNode;
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
export type SnippetProps<T extends ElementType = "div"> = TagProps<T, SnippetOwnProps>;
|
|
28
|
+
|
|
29
|
+
export type SnippetPreviewProps<T extends ElementType = "div"> = TagProps<T>;
|
|
@@ -4,6 +4,8 @@ import type { ElementType } from "react";
|
|
|
4
4
|
import type { SplashProps, SplashServeProps } from "./type.js";
|
|
5
5
|
|
|
6
6
|
import { cn } from "../../utils/cn/cn.js";
|
|
7
|
+
import { splashBaseClassName, splashOverrideClassName } from "./style.js";
|
|
8
|
+
|
|
7
9
|
import "./splash.css";
|
|
8
10
|
|
|
9
11
|
export const Splash = <T extends ElementType = "div">({ initial = true, className, ...rest }: SplashProps<T>) => (
|
|
@@ -14,11 +16,7 @@ export const Splash = <T extends ElementType = "div">({ initial = true, classNam
|
|
|
14
16
|
role="presentation"
|
|
15
17
|
data-margo-splash=""
|
|
16
18
|
data-margo-splash-initial={initial}
|
|
17
|
-
className={cn(
|
|
18
|
-
"fixed inset-0 z-max",
|
|
19
|
-
className && "[clip-path:none] margo-splash-idle:[clip-path:none]",
|
|
20
|
-
className,
|
|
21
|
-
)}
|
|
19
|
+
className={cn(splashBaseClassName, className && splashOverrideClassName, className)}
|
|
22
20
|
/>
|
|
23
21
|
);
|
|
24
22
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export const toggleBaseClassName = `margo-toggle h-5 w-9 flex-none cursor-pointer rounded-full border-2 border-border
|
|
2
|
+
bg-main p-0.5 text-on-main enabled:hover:border-on-main focus-visible:border-primary focus-visible:outline
|
|
3
|
+
focus-visible:outline-offset-1 focus-visible:outline-on-main checked:border-primary select-none origin-center
|
|
4
|
+
transition-transform duration-[160ms] ease-out active:scale-[0.98] disabled:cursor-auto disabled:opacity-40`;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.margo-toggle {
|
|
2
|
+
appearance: none;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* the thumb travels the track's width minus its height: borders and padding cancel out on both axes */
|
|
6
|
+
.margo-toggle::before {
|
|
7
|
+
content: "";
|
|
8
|
+
display: block;
|
|
9
|
+
block-size: 100%;
|
|
10
|
+
aspect-ratio: 1;
|
|
11
|
+
border-radius: 9999px;
|
|
12
|
+
background-color: currentColor;
|
|
13
|
+
transition: translate 160ms ease-out;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.margo-toggle:checked::before {
|
|
17
|
+
translate: var(--margo-toggle-travel, 1rem) 0;
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn/cn.js";
|
|
2
|
+
import { toggleBaseClassName } from "./style.js";
|
|
3
|
+
|
|
4
|
+
import type { ToggleProps } from "./type.js";
|
|
5
|
+
|
|
6
|
+
import "./toggle.css";
|
|
7
|
+
|
|
8
|
+
export const Toggle = ({ className, ...rest }: ToggleProps) => (
|
|
9
|
+
<input {...rest} type="checkbox" role="switch" className={cn(toggleBaseClassName, className)} />
|
|
10
|
+
);
|
package/src/css/variables.css
CHANGED
|
@@ -34,6 +34,10 @@
|
|
|
34
34
|
--margo-layer-duration: 750ms;
|
|
35
35
|
--margo-layer-easing: cubic-bezier(0.32, 0.72, 0, 1);
|
|
36
36
|
--margo-layer-z-index: 100;
|
|
37
|
+
|
|
38
|
+
--margo-popover-duration: 200ms;
|
|
39
|
+
--margo-popover-easing: cubic-bezier(0.32, 0.72, 0, 1);
|
|
40
|
+
|
|
37
41
|
--margo-max-z-index: 9999;
|
|
38
42
|
|
|
39
43
|
--margo-grid-max-width: 80rem;
|
|
@@ -114,5 +118,6 @@
|
|
|
114
118
|
@media (prefers-reduced-motion: reduce) {
|
|
115
119
|
:root {
|
|
116
120
|
--margo-layer-duration: 1ms;
|
|
121
|
+
--margo-popover-duration: 1ms;
|
|
117
122
|
}
|
|
118
123
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { Blockquote } from "./components/blockquote/blockquote.js";
|
|
|
2
2
|
export { Button } from "./components/button/button.js";
|
|
3
3
|
export { ButtonMicro } from "./components/button_micro/button_micro.js";
|
|
4
4
|
export { Card } from "./components/card/card.js";
|
|
5
|
+
export { Checkbox } from "./components/checkbox/checkbox.js";
|
|
5
6
|
export { Chip } from "./components/chip/chip.js";
|
|
6
7
|
export { Code } from "./components/code/code.js";
|
|
7
8
|
export { Dialog } from "./components/dialog/dialog.js";
|
|
@@ -11,9 +12,12 @@ export { Layer } from "./components/layer/layer.js";
|
|
|
11
12
|
export { Input } from "./components/input/input.js";
|
|
12
13
|
export { Item } from "./components/item/item.js";
|
|
13
14
|
export { NavigationBar } from "./components/navigation_bar/navigation_bar.js";
|
|
15
|
+
export { Popover } from "./components/popover/popover.js";
|
|
14
16
|
export { ProgressBar } from "./components/progress_bar/progress_bar.js";
|
|
15
17
|
export { Table } from "./components/table/table.js";
|
|
18
|
+
export { Toggle } from "./components/toggle/toggle.js";
|
|
16
19
|
export { Splash } from "./components/splash/splash.js";
|
|
20
|
+
export { Select } from "./components/select/select.js";
|
|
17
21
|
export { Sheet } from "./components/sheet/sheet.js";
|
|
18
22
|
export { Snippet } from "./components/snippet/snippet.js";
|
|
19
23
|
export { Spinner } from "./components/spinner/spinner.js";
|
|
@@ -31,6 +35,7 @@ export { MetaColorScheme } from "./meta/meta_color_scheme/meta_color_scheme.js";
|
|
|
31
35
|
export { useMargoTheme } from "./hooks/use_theme.js";
|
|
32
36
|
|
|
33
37
|
export { cn } from "./utils/cn/cn.js";
|
|
38
|
+
export { isMargoLayerSupported } from "./utils/support/support.js";
|
|
34
39
|
export { margoTheme, margoThemeClient } from "./utils/theme/theme.js";
|
|
35
40
|
|
|
36
41
|
export type { BlockquoteProps } from "./components/blockquote/type.js";
|
|
@@ -44,6 +49,7 @@ export type {
|
|
|
44
49
|
} from "./components/button/type.js";
|
|
45
50
|
export type { ButtonMicroProps } from "./components/button_micro/type.js";
|
|
46
51
|
export type { CardProps } from "./components/card/type.js";
|
|
52
|
+
export type { CheckboxProps } from "./components/checkbox/type.js";
|
|
47
53
|
export type { ChipProps } from "./components/chip/type.js";
|
|
48
54
|
export type { CodeOwnProps, CodeProps } from "./components/code/type.js";
|
|
49
55
|
export type { DialogBodyProps, DialogFooterProps, DialogProps } from "./components/dialog/type.js";
|
|
@@ -58,6 +64,7 @@ export type { LayerProps } from "./components/layer/type.js";
|
|
|
58
64
|
export type { InputIconProps, InputProps, InputTextProps } from "./components/input/type.js";
|
|
59
65
|
export type { ItemIconProps, ItemLabelProps, ItemProps } from "./components/item/type.js";
|
|
60
66
|
export type { NavigationBarProps } from "./components/navigation_bar/type.js";
|
|
67
|
+
export type { PopoverAlign, PopoverAnchorProps, PopoverBodyProps, PopoverPosition, PopoverProps } from "./components/popover/type.js";
|
|
61
68
|
export type { ProgressBarMode, ProgressBarProps } from "./components/progress_bar/type.js";
|
|
62
69
|
export type {
|
|
63
70
|
TableBodyProps,
|
|
@@ -68,9 +75,11 @@ export type {
|
|
|
68
75
|
TableRowProps,
|
|
69
76
|
} from "./components/table/type.js";
|
|
70
77
|
export type { SplashProps, SplashServeProps } from "./components/splash/type.js";
|
|
78
|
+
export type { SelectOwnProps, SelectProps } from "./components/select/type.js";
|
|
71
79
|
export type { SheetBodyProps, SheetFooterProps, SheetProps, SheetSide } from "./components/sheet/type.js";
|
|
72
|
-
export type { SnippetProps, SnippetToken, SnippetTokenType } from "./components/snippet/type.js";
|
|
80
|
+
export type { SnippetPreviewProps, SnippetProps, SnippetToken, SnippetTokenType } from "./components/snippet/type.js";
|
|
73
81
|
export type { SpinnerProps } from "./components/spinner/type.js";
|
|
82
|
+
export type { ToggleProps } from "./components/toggle/type.js";
|
|
74
83
|
export type { TooltipPosition, TooltipProps } from "./components/tooltip/type.js";
|
|
75
84
|
|
|
76
85
|
export type { BackgroundGlowProps } from "./hoc/background_glow/type.js";
|