@k8o/arte-odyssey 5.0.4 → 6.0.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/dist/components/buttons/button/button.d.mts +1 -1
- package/dist/components/buttons/button/button.mjs +11 -7
- package/dist/components/buttons/icon-button/icon-button.d.mts +1 -1
- package/dist/components/buttons/icon-button/icon-button.mjs +1 -1
- package/dist/components/buttons/icon-link/icon-link.d.mts +1 -1
- package/dist/components/buttons/icon-link/icon-link.mjs +1 -1
- package/dist/components/buttons/link-button/link-button.d.mts +1 -1
- package/dist/components/buttons/link-button/link-button.mjs +7 -5
- package/dist/components/data-display/accordion/accordion-button.mjs +1 -1
- package/dist/components/data-display/card/card.mjs +2 -2
- package/dist/components/data-display/card/interactive-card.mjs +2 -2
- package/dist/components/data-display/card/type.d.mts +0 -1
- package/dist/components/form/autocomplete/autocomplete.mjs +2 -2
- package/dist/components/form/checkbox-card/checkbox-card.mjs +2 -2
- package/dist/components/form/form-control/form-control.mjs +4 -4
- package/dist/components/form/number-field/number-field.mjs +12 -6
- package/dist/components/form/radio-card/radio-card.mjs +1 -1
- package/dist/components/form/switch/switch.mjs +1 -1
- package/dist/components/index.d.mts +2 -1
- package/dist/components/index.mjs +2 -1
- package/dist/components/navigation/pagination/index.d.mts +2 -0
- package/dist/components/navigation/pagination/index.mjs +2 -0
- package/dist/components/navigation/pagination/pagination.d.mts +15 -0
- package/dist/components/navigation/pagination/pagination.mjs +65 -0
- package/dist/components/navigation/tabs/tabs.mjs +1 -1
- package/dist/components/overlays/dialog/dialog.mjs +1 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu.mjs +2 -2
- package/dist/components/overlays/list-box/list-box.mjs +2 -2
- package/dist/components/overlays/modal/modal.mjs +1 -1
- package/dist/components/overlays/tooltip/tooltip.mjs +1 -1
- package/dist/hooks/scroll-direction/index.d.mts +7 -1
- package/dist/hooks/scroll-direction/index.mjs +18 -6
- package/dist/hooks/scroll-lock/index.d.mts +3 -1
- package/dist/hooks/scroll-lock/index.mjs +35 -16
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/styles/index.css +3 -0
- package/package.json +2 -1
|
@@ -4,7 +4,7 @@ import { FC, HTMLProps, ReactNode } from "react";
|
|
|
4
4
|
declare const Button: FC<{
|
|
5
5
|
type?: 'button' | 'submit';
|
|
6
6
|
size?: 'sm' | 'md' | 'lg';
|
|
7
|
-
color?: 'primary' | 'gray';
|
|
7
|
+
color?: 'primary' | 'secondary' | 'gray';
|
|
8
8
|
variant?: 'contained' | 'outlined' | 'skeleton';
|
|
9
9
|
fullWidth?: boolean;
|
|
10
10
|
startIcon?: ReactNode;
|
|
@@ -4,14 +4,18 @@ import { jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
const Button = ({ ref, children, type = "button", size = "md", color = "primary", variant = "contained", disabled = false, fullWidth = false, onClick, startIcon, endIcon, ...rest }) => {
|
|
5
5
|
return /* @__PURE__ */ jsxs("button", {
|
|
6
6
|
className: cn("cursor-pointer rounded-full border-2 text-center font-bold transition-colors", {
|
|
7
|
-
"border-transparent bg-primary-bg text-fg hover:bg-primary-bg/
|
|
8
|
-
"border-transparent bg-bg
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
7
|
+
"border-transparent bg-primary-bg text-fg hover:bg-primary-bg-emphasize/80 active:bg-primary-bg-emphasize": variant === "contained" && color === "primary",
|
|
8
|
+
"border-transparent bg-secondary-bg text-fg hover:bg-secondary-bg-emphasize/80 active:bg-secondary-bg-emphasize": variant === "contained" && color === "secondary",
|
|
9
|
+
"border-transparent bg-bg-subtle text-fg-base hover:bg-bg-mute/80 active:bg-bg-mute": variant === "contained" && color === "gray",
|
|
10
|
+
"cursor-not-allowed opacity-35 hover:bg-primary-bg active:bg-primary-bg": disabled && variant === "contained" && color === "primary",
|
|
11
|
+
"cursor-not-allowed opacity-35 hover:bg-secondary-bg active:bg-secondary-bg": disabled && variant === "contained" && color === "secondary",
|
|
12
|
+
"cursor-not-allowed opacity-35 hover:bg-bg-subtle active:bg-bg-subtle": disabled && variant === "contained" && color === "gray",
|
|
13
|
+
"border-primary-border bg-bg-base text-primary-fg hover:bg-bg-subtle active:bg-bg-mute": variant === "outlined" && color === "primary",
|
|
14
|
+
"border-secondary-border bg-bg-base text-secondary-fg hover:bg-bg-subtle active:bg-bg-mute": variant === "outlined" && color === "secondary",
|
|
15
|
+
"border-border-base bg-bg-base text-fg-base hover:bg-bg-subtle active:bg-bg-mute": variant === "outlined" && color === "gray",
|
|
12
16
|
"cursor-not-allowed bg-bg-base opacity-35 hover:bg-bg-base active:bg-bg-base": disabled && variant === "outlined",
|
|
13
|
-
"border-transparent bg-transparent text-fg-mute hover:text-fg-base active:text-fg-base": variant === "skeleton",
|
|
14
|
-
"cursor-not-allowed bg-transparent text-fg-mute opacity-35 hover:text-fg-mute active:text-fg-mute": disabled && variant === "skeleton"
|
|
17
|
+
"border-transparent bg-transparent text-fg-mute hover:bg-bg-subtle hover:text-fg-base active:bg-bg-mute active:text-fg-base": variant === "skeleton",
|
|
18
|
+
"cursor-not-allowed bg-transparent text-fg-mute opacity-35 hover:bg-transparent hover:text-fg-mute active:bg-transparent active:text-fg-mute": disabled && variant === "skeleton"
|
|
15
19
|
}, "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info", size === "sm" && "px-3 py-1 text-sm", size === "md" && "px-4 py-2 text-md", size === "lg" && "px-6 py-3 text-lg", fullWidth && "w-full", Boolean(startIcon ?? endIcon) && "flex items-center gap-2", startIcon && endIcon ? "justify-between" : startIcon && variant !== "skeleton" ? "justify-center" : endIcon && "justify-between"),
|
|
16
20
|
disabled,
|
|
17
21
|
onClick,
|
|
@@ -3,7 +3,7 @@ import { FC, HTMLProps } from "react";
|
|
|
3
3
|
//#region src/components/buttons/icon-button/icon-button.d.ts
|
|
4
4
|
type Props = {
|
|
5
5
|
size?: 'sm' | 'md' | 'lg';
|
|
6
|
-
bg?: 'transparent' | 'base' | 'primary';
|
|
6
|
+
bg?: 'transparent' | 'base' | 'primary' | 'secondary';
|
|
7
7
|
label: string;
|
|
8
8
|
} & Omit<HTMLProps<HTMLButtonElement>, 'size' | 'type'>;
|
|
9
9
|
declare const IconButton: FC<Props>;
|
|
@@ -4,7 +4,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
const IconButton = ({ ref, size = "md", bg = "transparent", label, children, ...props }) => {
|
|
5
5
|
return /* @__PURE__ */ jsxs("button", {
|
|
6
6
|
"aria-label": props.role ? label : void 0,
|
|
7
|
-
className: cn("inline-flex cursor-pointer rounded-full
|
|
7
|
+
className: cn("inline-flex cursor-pointer rounded-full transition-colors", "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info", (bg === "transparent" || bg === "base") && "hover:bg-bg-subtle active:bg-bg-mute", bg === "base" && "bg-bg-base", bg === "transparent" && "bg-transparent", bg === "primary" && "bg-primary-bg hover:bg-primary-bg-emphasize/80 active:bg-primary-bg-emphasize", bg === "secondary" && "bg-secondary-bg hover:bg-secondary-bg-emphasize/80 active:bg-secondary-bg-emphasize", size === "sm" && "p-1", size === "md" && "p-2", size === "lg" && "p-3", props.disabled && "cursor-not-allowed opacity-50 hover:bg-transparent active:bg-transparent"),
|
|
8
8
|
ref,
|
|
9
9
|
...props,
|
|
10
10
|
children: [!props.role && /* @__PURE__ */ jsx("span", {
|
|
@@ -11,7 +11,7 @@ declare const IconLink: <T extends string>({
|
|
|
11
11
|
renderAnchor
|
|
12
12
|
}: PropsWithChildren<{
|
|
13
13
|
size?: "sm" | "md" | "lg";
|
|
14
|
-
bg?: "transparent" | "base" | "primary";
|
|
14
|
+
bg?: "transparent" | "base" | "primary" | "secondary";
|
|
15
15
|
label?: string;
|
|
16
16
|
href: T;
|
|
17
17
|
openInNewTab?: boolean;
|
|
@@ -12,7 +12,7 @@ const IconLink = ({ size = "md", bg = "transparent", label, href, children, open
|
|
|
12
12
|
};
|
|
13
13
|
return renderAnchor({
|
|
14
14
|
href,
|
|
15
|
-
className: cn("inline-flex rounded-full transition-colors
|
|
15
|
+
className: cn("inline-flex rounded-full transition-colors focus-visible:ring-2 focus-visible:ring-border-info", (bg === "transparent" || bg === "base") && "hover:bg-bg-subtle active:bg-bg-mute", bg === "base" && "bg-bg-base", bg === "transparent" && "bg-transparent", bg === "primary" && "bg-primary-bg hover:bg-primary-bg-emphasize/80 active:bg-primary-bg-emphasize", bg === "secondary" && "bg-secondary-bg hover:bg-secondary-bg-emphasize/80 active:bg-secondary-bg-emphasize", size === "sm" && "p-1", size === "md" && "p-2", size === "lg" && "p-3"),
|
|
16
16
|
...props,
|
|
17
17
|
children: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
18
18
|
className: "sr-only",
|
|
@@ -15,7 +15,7 @@ declare const LinkButton: <T extends string>({
|
|
|
15
15
|
}: {
|
|
16
16
|
variant?: "contained" | "outlined" | "skeleton";
|
|
17
17
|
size?: "sm" | "md" | "lg";
|
|
18
|
-
color?: "primary" | "gray";
|
|
18
|
+
color?: "primary" | "secondary" | "gray";
|
|
19
19
|
href: T;
|
|
20
20
|
startIcon?: ReactNode;
|
|
21
21
|
endIcon?: ReactNode;
|
|
@@ -13,11 +13,13 @@ const LinkButton = ({ children, size = "md", color = "primary", variant = "conta
|
|
|
13
13
|
return renderAnchor({
|
|
14
14
|
href,
|
|
15
15
|
className: cn("rounded-full border-2 text-center font-bold transition-colors", {
|
|
16
|
-
"border-transparent bg-primary-bg text-fg hover:bg-primary-bg/
|
|
17
|
-
"border-transparent bg-bg
|
|
18
|
-
"border-
|
|
19
|
-
"border-border
|
|
20
|
-
"border-
|
|
16
|
+
"border-transparent bg-primary-bg text-fg hover:bg-primary-bg-emphasize/80 active:bg-primary-bg-emphasize": variant === "contained" && color === "primary",
|
|
17
|
+
"border-transparent bg-secondary-bg text-fg hover:bg-secondary-bg-emphasize/80 active:bg-secondary-bg-emphasize": variant === "contained" && color === "secondary",
|
|
18
|
+
"border-transparent bg-bg-subtle text-fg-base hover:bg-bg-mute/80 active:bg-bg-mute": variant === "contained" && color === "gray",
|
|
19
|
+
"border-primary-border bg-bg-base text-primary-fg hover:bg-bg-subtle active:bg-bg-mute": variant === "outlined" && color === "primary",
|
|
20
|
+
"border-secondary-border bg-bg-base text-secondary-fg hover:bg-bg-subtle active:bg-bg-mute": variant === "outlined" && color === "secondary",
|
|
21
|
+
"border-border-base bg-bg-base text-fg-base hover:bg-bg-subtle active:bg-bg-mute": variant === "outlined" && color === "gray",
|
|
22
|
+
"border-transparent bg-transparent text-fg-mute hover:bg-bg-subtle hover:text-fg-base active:bg-bg-mute active:text-fg-base": variant === "skeleton"
|
|
21
23
|
}, "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info", size === "sm" && "px-3 py-1 text-sm", size === "md" && "px-4 py-2 text-md", size === "lg" && "px-6 py-3 text-lg", Boolean(startIcon ?? endIcon) && "flex items-center gap-2", Boolean(endIcon) && "justify-between", active && "text-fg-info hover:text-fg-info active:text-fg-info"),
|
|
22
24
|
"aria-label": children,
|
|
23
25
|
...props,
|
|
@@ -11,7 +11,7 @@ const AccordionButton = ({ children }) => {
|
|
|
11
11
|
return /* @__PURE__ */ jsxs("button", {
|
|
12
12
|
"aria-controls": `${id}-panel`,
|
|
13
13
|
"aria-expanded": open,
|
|
14
|
-
className: cn("flex w-full cursor-pointer items-center justify-between rounded-md p-4 text-fg-base", "hover:text-primary-fg", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-info"),
|
|
14
|
+
className: cn("flex w-full cursor-pointer items-center justify-between rounded-md p-4 text-fg-base transition-colors", "hover:bg-primary-bg-subtle hover:text-primary-fg", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-info"),
|
|
15
15
|
id: `${id}-button`,
|
|
16
16
|
onClick: toggleOpen,
|
|
17
17
|
type: "button",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn } from "../../../helpers/cn.mjs";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/data-display/card/card.tsx
|
|
4
|
-
const Card = ({ children,
|
|
5
|
-
className: cn("rounded-xl", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit",
|
|
4
|
+
const Card = ({ children, width = "full", appearance = "shadow" }) => /* @__PURE__ */ jsx("div", {
|
|
5
|
+
className: cn("rounded-xl", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit", "bg-bg-base"),
|
|
6
6
|
children
|
|
7
7
|
});
|
|
8
8
|
//#endregion
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn } from "../../../helpers/cn.mjs";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/data-display/card/interactive-card.tsx
|
|
4
|
-
const InteractiveCard = ({ children,
|
|
5
|
-
className: cn("rounded-xl transition-transform hover:scale-[1.02] active:scale-[0.98]", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit",
|
|
4
|
+
const InteractiveCard = ({ children, width = "full", appearance = "shadow" }) => /* @__PURE__ */ jsx("div", {
|
|
5
|
+
className: cn("rounded-xl transition-transform hover:scale-[1.02] active:scale-[0.98]", appearance === "shadow" && "shadow-sm", appearance === "bordered" && "border border-border-mute", width === "full" && "w-full", width === "fit" && "w-fit", "bg-bg-base"),
|
|
6
6
|
children
|
|
7
7
|
});
|
|
8
8
|
//#endregion
|
|
@@ -142,7 +142,7 @@ const Autocomplete = ({ id, name, describedbyId, isInvalid, isDisabled, isRequir
|
|
|
142
142
|
/* @__PURE__ */ jsx("div", {
|
|
143
143
|
className: "relative w-full",
|
|
144
144
|
children: open && /* @__PURE__ */ jsx("div", {
|
|
145
|
-
className: "absolute top-1 z-10 w-full rounded-xl
|
|
145
|
+
className: "absolute top-1 z-10 w-full rounded-xl bg-bg-raised shadow-md",
|
|
146
146
|
role: "presentation",
|
|
147
147
|
children: /* @__PURE__ */ jsxs("ul", {
|
|
148
148
|
className: "max-h-96 py-2",
|
|
@@ -153,7 +153,7 @@ const Autocomplete = ({ id, name, describedbyId, isInvalid, isDisabled, isRequir
|
|
|
153
153
|
}), filteredOptions.map((option, idx) => {
|
|
154
154
|
const selected = currentValue.includes(option.value);
|
|
155
155
|
return /* @__PURE__ */ jsx("li", {
|
|
156
|
-
className: cn("cursor-pointer px-3 py-2", selected && "bg-bg-
|
|
156
|
+
className: cn("cursor-pointer px-3 py-2 transition-colors", selected && "bg-primary-bg-subtle text-primary-fg", selectIndex === idx && !selected && "bg-bg-subtle", selectIndex === idx && selected && "bg-primary-bg-mute text-primary-fg"),
|
|
157
157
|
id: `${id}_option_${option.value}`,
|
|
158
158
|
onClick: (e) => {
|
|
159
159
|
e.stopPropagation();
|
|
@@ -22,7 +22,7 @@ const CheckboxCard = ({ labelId, name, isDisabled, isInvalid = false, options, v
|
|
|
22
22
|
const disabled = isDisabled || option.disabled;
|
|
23
23
|
const optionId = `${groupId}-${option.value}`;
|
|
24
24
|
return /* @__PURE__ */ jsxs("label", {
|
|
25
|
-
className: cn("flex w-full min-w-0 rounded-xl border bg-bg-base p-4 text-left transition-colors", "has-[input:focus-visible]:outline-hidden has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-border-info", checked && "border-border-
|
|
25
|
+
className: cn("flex w-full min-w-0 rounded-xl border bg-bg-base p-4 text-left transition-colors", "has-[input:focus-visible]:outline-hidden has-[input:focus-visible]:ring-2 has-[input:focus-visible]:ring-border-info", checked && "border-primary-border bg-primary-bg-subtle hover:bg-primary-bg-mute", isInvalid ? "border-border-error" : !checked && "border-border-mute hover:bg-bg-subtle", disabled && "cursor-not-allowed border-border-mute bg-bg-subtle text-fg-mute"),
|
|
26
26
|
id: optionId,
|
|
27
27
|
children: [
|
|
28
28
|
/* @__PURE__ */ jsx("input", {
|
|
@@ -55,7 +55,7 @@ const CheckboxCard = ({ labelId, name, isDisabled, isInvalid = false, options, v
|
|
|
55
55
|
}),
|
|
56
56
|
/* @__PURE__ */ jsx("span", {
|
|
57
57
|
"aria-hidden": true,
|
|
58
|
-
className: cn("mt-0.5 ml-4 inline-flex size-5 shrink-0 items-center justify-center rounded-md border", checked ? "border-border-
|
|
58
|
+
className: cn("mt-0.5 ml-4 inline-flex size-5 shrink-0 items-center justify-center rounded-md border", checked ? "border-border-base bg-primary-bg text-fg-base" : "border-border-mute bg-bg-base text-transparent"),
|
|
59
59
|
children: /* @__PURE__ */ jsx(CheckIcon, { size: "sm" })
|
|
60
60
|
})
|
|
61
61
|
]
|
|
@@ -10,7 +10,7 @@ const FormControl = ({ isDisabled = false, isInvalid = false, isRequired = false
|
|
|
10
10
|
className: "flex w-full flex-col",
|
|
11
11
|
children: [
|
|
12
12
|
labelAs === "label" ? /* @__PURE__ */ jsxs("label", {
|
|
13
|
-
className: "mb-1 flex gap-2 font-bold text-fg-base text-md",
|
|
13
|
+
className: "mb-1 flex gap-2 pl-0.5 font-bold text-fg-base text-md",
|
|
14
14
|
htmlFor: id,
|
|
15
15
|
id: labelId,
|
|
16
16
|
children: [label, isRequired && /* @__PURE__ */ jsx("span", {
|
|
@@ -18,7 +18,7 @@ const FormControl = ({ isDisabled = false, isInvalid = false, isRequired = false
|
|
|
18
18
|
children: "必須"
|
|
19
19
|
})]
|
|
20
20
|
}) : /* @__PURE__ */ jsxs("legend", {
|
|
21
|
-
className: "mb-1 flex gap-2 font-bold text-fg-base text-md",
|
|
21
|
+
className: "mb-1 flex gap-2 pl-0.5 font-bold text-fg-base text-md",
|
|
22
22
|
children: [label, isRequired && /* @__PURE__ */ jsx("span", {
|
|
23
23
|
className: "font-medium text-fg-error",
|
|
24
24
|
children: "必須"
|
|
@@ -34,11 +34,11 @@ const FormControl = ({ isDisabled = false, isInvalid = false, isRequired = false
|
|
|
34
34
|
}),
|
|
35
35
|
isInvalid && errorText ? /* @__PURE__ */ jsx("p", {
|
|
36
36
|
"aria-live": "polite",
|
|
37
|
-
className: "text-fg-error text-sm",
|
|
37
|
+
className: "mt-1 pl-0.5 text-fg-error text-sm",
|
|
38
38
|
id: `${id}-feedback`,
|
|
39
39
|
children: errorText
|
|
40
40
|
}) : helpText && /* @__PURE__ */ jsx("p", {
|
|
41
|
-
className: "text-fg-mute text-sm",
|
|
41
|
+
className: "mt-1 pl-0.5 text-fg-mute text-sm",
|
|
42
42
|
id: `${id}-helptext`,
|
|
43
43
|
children: helpText
|
|
44
44
|
})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../../../helpers/cn.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { ChevronIcon } from "../../icons/lucide.mjs";
|
|
4
4
|
import { between } from "../../../helpers/number/between.mjs";
|
|
5
5
|
import { toPrecision } from "../../../helpers/number/to-precision.mjs";
|
|
6
6
|
import { cast } from "../../../helpers/number/cast.mjs";
|
|
@@ -66,9 +66,9 @@ const NumberField = ({ id, name, describedbyId, isInvalid, isDisabled, isRequire
|
|
|
66
66
|
value: displayValue
|
|
67
67
|
}), /* @__PURE__ */ jsxs("div", {
|
|
68
68
|
"aria-hidden": "true",
|
|
69
|
-
className: "absolute right-
|
|
69
|
+
className: "absolute right-1 flex h-full flex-col py-1",
|
|
70
70
|
children: [/* @__PURE__ */ jsxs("button", {
|
|
71
|
-
className: cn("flex w-6 grow items-center justify-center rounded-
|
|
71
|
+
className: cn("flex w-6 grow items-center justify-center rounded-md text-fg-mute transition-colors", "hover:bg-bg-mute hover:text-fg-base", "disabled:cursor-not-allowed disabled:text-fg-mute disabled:hover:bg-transparent"),
|
|
72
72
|
disabled: isDisabled,
|
|
73
73
|
onClick: () => {
|
|
74
74
|
const newValue = between(toPrecision(cast(displayValue, precision) + step, precision), min, max);
|
|
@@ -80,9 +80,12 @@ const NumberField = ({ id, name, describedbyId, isInvalid, isDisabled, isRequire
|
|
|
80
80
|
children: [/* @__PURE__ */ jsx("span", {
|
|
81
81
|
className: "sr-only",
|
|
82
82
|
children: "増やす"
|
|
83
|
-
}), /* @__PURE__ */ jsx(
|
|
83
|
+
}), /* @__PURE__ */ jsx(ChevronIcon, {
|
|
84
|
+
direction: "up",
|
|
85
|
+
size: "sm"
|
|
86
|
+
})]
|
|
84
87
|
}), /* @__PURE__ */ jsxs("button", {
|
|
85
|
-
className: cn("flex w-6 grow items-center justify-center rounded-
|
|
88
|
+
className: cn("flex w-6 grow items-center justify-center rounded-md text-fg-mute transition-colors", "hover:bg-bg-mute hover:text-fg-base", "disabled:cursor-not-allowed disabled:text-fg-mute disabled:hover:bg-transparent"),
|
|
86
89
|
disabled: isDisabled,
|
|
87
90
|
onClick: () => {
|
|
88
91
|
const newValue = between(toPrecision(cast(displayValue, precision) - step, precision), min, max);
|
|
@@ -94,7 +97,10 @@ const NumberField = ({ id, name, describedbyId, isInvalid, isDisabled, isRequire
|
|
|
94
97
|
children: [/* @__PURE__ */ jsx("span", {
|
|
95
98
|
className: "sr-only",
|
|
96
99
|
children: "減らす"
|
|
97
|
-
}), /* @__PURE__ */ jsx(
|
|
100
|
+
}), /* @__PURE__ */ jsx(ChevronIcon, {
|
|
101
|
+
direction: "down",
|
|
102
|
+
size: "sm"
|
|
103
|
+
})]
|
|
98
104
|
})]
|
|
99
105
|
})]
|
|
100
106
|
});
|
|
@@ -36,7 +36,7 @@ const RadioCard = ({ labelId, name, isDisabled, isInvalid = false, options, valu
|
|
|
36
36
|
return /* @__PURE__ */ jsxs("button", {
|
|
37
37
|
"aria-describedby": option.description ? `${optionId}-description` : void 0,
|
|
38
38
|
"aria-pressed": checked,
|
|
39
|
-
className: cn("flex w-full min-w-0 rounded-xl border bg-bg-base p-4 text-left transition-colors", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info", checked && "border-border-
|
|
39
|
+
className: cn("flex w-full min-w-0 rounded-xl border bg-bg-base p-4 text-left transition-colors", "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info", checked && "border-primary-border bg-primary-bg-subtle hover:bg-primary-bg-mute", isInvalid ? "border-border-error" : !checked && "border-border-mute hover:bg-bg-subtle", disabled && "cursor-not-allowed border-border-mute bg-bg-subtle text-fg-mute"),
|
|
40
40
|
disabled,
|
|
41
41
|
id: optionId,
|
|
42
42
|
onClick: () => {
|
|
@@ -34,7 +34,7 @@ const Switch = ({ value, defaultChecked, describedbyId, id, isDisabled, isInvali
|
|
|
34
34
|
type: "checkbox"
|
|
35
35
|
}), /* @__PURE__ */ jsx("span", {
|
|
36
36
|
"aria-hidden": true,
|
|
37
|
-
className: cn("inline-flex h-7 w-12 items-center rounded-full
|
|
37
|
+
className: cn("inline-flex h-7 w-12 items-center rounded-full transition-colors", isInvalid && "ring-2 ring-border-error", isSelected ? "bg-primary-bg" : "bg-bg-mute", isDisabled && "bg-bg-subtle", "peer-focus-visible:outline-hidden peer-focus-visible:ring-2 peer-focus-visible:ring-border-info peer-focus-visible:ring-offset-2"),
|
|
38
38
|
children: /* @__PURE__ */ jsx("span", { className: cn("ml-0.5 size-5 rounded-full bg-bg-base shadow-xs transition-transform", isSelected && "translate-x-5", isDisabled && "bg-bg-emphasize") })
|
|
39
39
|
})]
|
|
40
40
|
}), label ? /* @__PURE__ */ jsx("span", { children: label }) : null]
|
|
@@ -41,6 +41,7 @@ import { ScrollLinked } from "./layout/scroll-linked/scroll-linked.mjs";
|
|
|
41
41
|
import { Separator } from "./layout/separator/separator.mjs";
|
|
42
42
|
import { Anchor } from "./navigation/anchor/anchor.mjs";
|
|
43
43
|
import { Breadcrumb } from "./navigation/breadcrumb/breadcrumb.mjs";
|
|
44
|
+
import { Pagination } from "./navigation/pagination/pagination.mjs";
|
|
44
45
|
import { Tabs } from "./navigation/tabs/tabs.mjs";
|
|
45
46
|
import { Dialog } from "./overlays/dialog/dialog.mjs";
|
|
46
47
|
import { Drawer } from "./overlays/drawer/drawer.mjs";
|
|
@@ -52,4 +53,4 @@ import { Popover } from "./overlays/popover/popover.mjs";
|
|
|
52
53
|
import { Tooltip } from "./overlays/tooltip/tooltip.mjs";
|
|
53
54
|
import { ArteOdysseyProvider } from "./providers/arte-odyssey-provider.mjs";
|
|
54
55
|
import { PortalRootProvider, usePortalRoot } from "./providers/portal-root.mjs";
|
|
55
|
-
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, useOpenContext, usePortalRoot, useToast };
|
|
56
|
+
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, useOpenContext, usePortalRoot, useToast };
|
|
@@ -41,6 +41,7 @@ import { ScrollLinked } from "./layout/scroll-linked/scroll-linked.mjs";
|
|
|
41
41
|
import { Separator } from "./layout/separator/separator.mjs";
|
|
42
42
|
import { Anchor } from "./navigation/anchor/anchor.mjs";
|
|
43
43
|
import { Breadcrumb } from "./navigation/breadcrumb/breadcrumb.mjs";
|
|
44
|
+
import { Pagination } from "./navigation/pagination/pagination.mjs";
|
|
44
45
|
import { Tabs } from "./navigation/tabs/tabs.mjs";
|
|
45
46
|
import { Dialog } from "./overlays/dialog/dialog.mjs";
|
|
46
47
|
import { Modal } from "./overlays/modal/modal.mjs";
|
|
@@ -52,4 +53,4 @@ import { Popover } from "./overlays/popover/popover.mjs";
|
|
|
52
53
|
import { DropdownMenu } from "./overlays/dropdown-menu/dropdown-menu.mjs";
|
|
53
54
|
import { ListBox } from "./overlays/list-box/list-box.mjs";
|
|
54
55
|
import { Tooltip } from "./overlays/tooltip/tooltip.mjs";
|
|
55
|
-
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, useOpenContext, usePortalRoot, useToast };
|
|
56
|
+
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, useOpenContext, usePortalRoot, useToast };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/components/navigation/pagination/pagination.d.ts
|
|
4
|
+
type Props = {
|
|
5
|
+
totalPages: number;
|
|
6
|
+
currentPage: number;
|
|
7
|
+
onPageChange: (page: number) => void;
|
|
8
|
+
isDisabled?: boolean;
|
|
9
|
+
prevLabel?: string;
|
|
10
|
+
nextLabel?: string;
|
|
11
|
+
'aria-label'?: string;
|
|
12
|
+
};
|
|
13
|
+
declare const Pagination: FC<Props>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { Pagination };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button } from "../../buttons/button/button.mjs";
|
|
3
|
+
import { ChevronIcon } from "../../icons/lucide.mjs";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/navigation/pagination/pagination.tsx
|
|
6
|
+
const Pagination = ({ totalPages, currentPage, onPageChange, isDisabled = false, prevLabel = "前へ", nextLabel = "次へ", "aria-label": ariaLabel = "ページネーション" }) => {
|
|
7
|
+
const safeTotal = Math.max(1, totalPages);
|
|
8
|
+
const safeCurrent = Math.min(Math.max(1, currentPage), safeTotal);
|
|
9
|
+
const isFirst = safeCurrent <= 1;
|
|
10
|
+
const isLast = safeCurrent >= safeTotal;
|
|
11
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
12
|
+
"aria-label": ariaLabel,
|
|
13
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
14
|
+
className: "flex items-center justify-center gap-2",
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx(Button, {
|
|
17
|
+
color: "gray",
|
|
18
|
+
disabled: isDisabled || isFirst,
|
|
19
|
+
onClick: () => {
|
|
20
|
+
onPageChange(safeCurrent - 1);
|
|
21
|
+
},
|
|
22
|
+
size: "sm",
|
|
23
|
+
startIcon: /* @__PURE__ */ jsx(ChevronIcon, {
|
|
24
|
+
direction: "left",
|
|
25
|
+
size: "sm"
|
|
26
|
+
}),
|
|
27
|
+
variant: "skeleton",
|
|
28
|
+
children: prevLabel
|
|
29
|
+
}),
|
|
30
|
+
/* @__PURE__ */ jsxs("p", {
|
|
31
|
+
"aria-current": "page",
|
|
32
|
+
"aria-live": "polite",
|
|
33
|
+
className: "px-3 text-fg-mute text-sm tabular-nums",
|
|
34
|
+
children: [
|
|
35
|
+
/* @__PURE__ */ jsx("span", {
|
|
36
|
+
className: "text-fg-base",
|
|
37
|
+
children: safeCurrent
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ jsx("span", {
|
|
40
|
+
className: "mx-1",
|
|
41
|
+
children: "/"
|
|
42
|
+
}),
|
|
43
|
+
/* @__PURE__ */ jsx("span", { children: safeTotal })
|
|
44
|
+
]
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ jsx(Button, {
|
|
47
|
+
color: "gray",
|
|
48
|
+
disabled: isDisabled || isLast,
|
|
49
|
+
endIcon: /* @__PURE__ */ jsx(ChevronIcon, {
|
|
50
|
+
direction: "right",
|
|
51
|
+
size: "sm"
|
|
52
|
+
}),
|
|
53
|
+
onClick: () => {
|
|
54
|
+
onPageChange(safeCurrent + 1);
|
|
55
|
+
},
|
|
56
|
+
size: "sm",
|
|
57
|
+
variant: "skeleton",
|
|
58
|
+
children: nextLabel
|
|
59
|
+
})
|
|
60
|
+
]
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
export { Pagination };
|
|
@@ -66,7 +66,7 @@ const Tab = ({ id, children }) => {
|
|
|
66
66
|
return /* @__PURE__ */ jsxs("div", {
|
|
67
67
|
"aria-controls": selectedId === id ? `${rootId}-panel-${id}` : void 0,
|
|
68
68
|
"aria-selected": selectedId === id,
|
|
69
|
-
className: cn("relative cursor-pointer rounded-lg p-2 transition-colors", "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info"),
|
|
69
|
+
className: cn("relative cursor-pointer rounded-lg p-2 transition-colors", selectedId !== id && "hover:bg-primary-bg-subtle hover:text-primary-fg", "focus-visible:border-transparent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border-info"),
|
|
70
70
|
id: `${rootId}-tab-${id}`,
|
|
71
71
|
onClick: () => {
|
|
72
72
|
setSelectedId(id);
|
|
@@ -17,7 +17,7 @@ const Root = ({ ref, id, children, tabIndex, role = "dialog" }) => {
|
|
|
17
17
|
return /* @__PURE__ */ jsx("section", {
|
|
18
18
|
"aria-describedby": `${rootId}-content`,
|
|
19
19
|
"aria-labelledby": `${rootId}-header`,
|
|
20
|
-
className: "relative w-full rounded-lg
|
|
20
|
+
className: "relative w-full rounded-lg bg-bg-raised shadow-md",
|
|
21
21
|
id,
|
|
22
22
|
ref,
|
|
23
23
|
role,
|
|
@@ -44,7 +44,7 @@ const Content = ({ children }) => {
|
|
|
44
44
|
children: /* @__PURE__ */ jsx(Popover.Content, { renderItem: (props) => /* @__PURE__ */ jsx("div", {
|
|
45
45
|
...props,
|
|
46
46
|
...contentProps,
|
|
47
|
-
className: "flex min-w-40 flex-col rounded-lg
|
|
47
|
+
className: "flex min-w-40 flex-col rounded-lg bg-bg-raised py-2 shadow-md",
|
|
48
48
|
children
|
|
49
49
|
}) })
|
|
50
50
|
});
|
|
@@ -52,7 +52,7 @@ const Content = ({ children }) => {
|
|
|
52
52
|
const Item = ({ label, onClick }) => {
|
|
53
53
|
const props = useMenuItem({ onClick });
|
|
54
54
|
return /* @__PURE__ */ jsx("button", {
|
|
55
|
-
className: cn("w-full px-2 py-1 text-left transition-colors", "hover:bg-bg-
|
|
55
|
+
className: cn("w-full px-2 py-1 text-left transition-colors", "hover:bg-bg-subtle", "focus-visible:bg-bg-subtle focus-visible:outline-none"),
|
|
56
56
|
...props,
|
|
57
57
|
children: label
|
|
58
58
|
});
|
|
@@ -59,7 +59,7 @@ const Content = ({ helpContent }) => {
|
|
|
59
59
|
children: /* @__PURE__ */ jsx(Popover.Content, { renderItem: (props) => /* @__PURE__ */ jsxs("div", {
|
|
60
60
|
...props,
|
|
61
61
|
...contentProps,
|
|
62
|
-
className: "flex max-h-48 min-w-40 flex-col overflow-y-auto rounded-lg
|
|
62
|
+
className: "flex max-h-48 min-w-40 flex-col overflow-y-auto rounded-lg bg-bg-raised py-2 shadow-md",
|
|
63
63
|
children: [helpContent, options.map(({ key, label }, idx) => /* @__PURE__ */ jsx(Item, {
|
|
64
64
|
index: idx,
|
|
65
65
|
label
|
|
@@ -70,7 +70,7 @@ const Content = ({ helpContent }) => {
|
|
|
70
70
|
const Item = ({ label, index }) => {
|
|
71
71
|
const { props, selected } = useMenuItem(index);
|
|
72
72
|
return /* @__PURE__ */ jsxs("button", {
|
|
73
|
-
className: cn("flex w-full items-center justify-between px-3 py-2 text-left transition-colors", "hover:bg-bg-
|
|
73
|
+
className: cn("flex w-full items-center justify-between px-3 py-2 text-left transition-colors", "hover:bg-bg-subtle", "focus-visible:border-transparent focus-visible:bg-bg-subtle focus-visible:outline-hidden"),
|
|
74
74
|
...props,
|
|
75
75
|
children: [label, selected && /* @__PURE__ */ jsx("span", {
|
|
76
76
|
className: "text-fg-success",
|
|
@@ -140,7 +140,7 @@ const Modal = ({ ref, type = "center", defaultOpen, isOpen, onClose, children })
|
|
|
140
140
|
]);
|
|
141
141
|
return /* @__PURE__ */ jsx(motion.dialog, {
|
|
142
142
|
animate: realDialogOpen ? "open" : "closed",
|
|
143
|
-
className: cn("
|
|
143
|
+
className: cn("bg-bg-raised text-fg-base shadow-md backdrop:bg-back-drop", type === "center" && "m-auto max-h-lg w-5/6 max-w-2xl rounded-lg", type === "bottom" && "mt-auto w-screen max-w-screen rounded-t-lg", type === "right" && "ml-auto h-svh max-h-none w-screen max-w-sm rounded-l-lg", type === "left" && "mr-auto h-svh max-h-none w-screen max-w-sm rounded-r-lg"),
|
|
144
144
|
exit: "closed",
|
|
145
145
|
initial: "closed",
|
|
146
146
|
onClick: (e) => {
|
|
@@ -39,7 +39,7 @@ const Content = ({ children }) => {
|
|
|
39
39
|
},
|
|
40
40
|
renderItem: (props) => /* @__PURE__ */ jsx("div", {
|
|
41
41
|
...props,
|
|
42
|
-
className: "rounded-lg
|
|
42
|
+
className: "rounded-lg bg-bg-inverse px-4 py-2 text-fg-inverse shadow-md",
|
|
43
43
|
children
|
|
44
44
|
})
|
|
45
45
|
});
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
|
|
1
3
|
//#region src/hooks/scroll-direction/index.d.ts
|
|
2
4
|
type ScrollDirection = {
|
|
3
5
|
x: 'left' | 'right';
|
|
4
6
|
y: 'up' | 'down';
|
|
5
7
|
};
|
|
6
|
-
|
|
8
|
+
type UseScrollDirectionOptions = {
|
|
9
|
+
threshold?: number;
|
|
10
|
+
target?: RefObject<HTMLElement | null>;
|
|
11
|
+
};
|
|
12
|
+
declare const useScrollDirection: (options?: UseScrollDirectionOptions) => ScrollDirection;
|
|
7
13
|
//#endregion
|
|
8
14
|
export { useScrollDirection };
|
|
@@ -6,7 +6,8 @@ const SERVER_SNAPSHOT = {
|
|
|
6
6
|
y: "up"
|
|
7
7
|
};
|
|
8
8
|
const getServerSnapshot = () => SERVER_SNAPSHOT;
|
|
9
|
-
const useScrollDirection = (
|
|
9
|
+
const useScrollDirection = (options = {}) => {
|
|
10
|
+
const { threshold = 50, target } = options;
|
|
10
11
|
const stateRef = useRef({
|
|
11
12
|
direction: {
|
|
12
13
|
x: "right",
|
|
@@ -16,9 +17,20 @@ const useScrollDirection = (threshold = 50) => {
|
|
|
16
17
|
prevScrollY: 0
|
|
17
18
|
});
|
|
18
19
|
const subscribe = useCallback((callback) => {
|
|
20
|
+
const element = target?.current ?? null;
|
|
21
|
+
const eventTarget = element ?? window;
|
|
22
|
+
const getScroll = () => {
|
|
23
|
+
if (element) return {
|
|
24
|
+
x: element.scrollLeft,
|
|
25
|
+
y: element.scrollTop
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
x: window.scrollX,
|
|
29
|
+
y: window.scrollY
|
|
30
|
+
};
|
|
31
|
+
};
|
|
19
32
|
const handleScroll = () => {
|
|
20
|
-
const currentScrollY =
|
|
21
|
-
const currentScrollX = window.scrollX;
|
|
33
|
+
const { x: currentScrollX, y: currentScrollY } = getScroll();
|
|
22
34
|
const state = stateRef.current;
|
|
23
35
|
let changed = false;
|
|
24
36
|
const newDirection = { ...state.direction };
|
|
@@ -51,11 +63,11 @@ const useScrollDirection = (threshold = 50) => {
|
|
|
51
63
|
};
|
|
52
64
|
if (changed) callback();
|
|
53
65
|
};
|
|
54
|
-
|
|
66
|
+
eventTarget.addEventListener("scroll", handleScroll, { passive: true });
|
|
55
67
|
return () => {
|
|
56
|
-
|
|
68
|
+
eventTarget.removeEventListener("scroll", handleScroll);
|
|
57
69
|
};
|
|
58
|
-
}, [threshold]);
|
|
70
|
+
}, [threshold, target]);
|
|
59
71
|
const getSnapshot = () => stateRef.current.direction;
|
|
60
72
|
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
61
73
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
|
|
1
3
|
//#region src/hooks/scroll-lock/index.d.ts
|
|
2
4
|
type UseScrollLockReturn = {
|
|
3
5
|
lock: () => void;
|
|
4
6
|
unlock: () => void;
|
|
5
7
|
};
|
|
6
|
-
declare const useScrollLock: () => UseScrollLockReturn;
|
|
8
|
+
declare const useScrollLock: (target?: RefObject<HTMLElement | null>) => UseScrollLockReturn;
|
|
7
9
|
//#endregion
|
|
8
10
|
export { useScrollLock };
|
|
@@ -1,36 +1,55 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useCallback, useEffect, useRef } from "react";
|
|
3
3
|
//#region src/hooks/scroll-lock/index.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
const lockRegistry = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
const resolveTarget = (target) => {
|
|
6
|
+
return target?.current ?? document.body;
|
|
7
|
+
};
|
|
8
|
+
const useScrollLock = (target) => {
|
|
7
9
|
const isLockedRef = useRef(false);
|
|
10
|
+
const lockedElementRef = useRef(null);
|
|
8
11
|
const lock = useCallback(() => {
|
|
9
12
|
if (isLockedRef.current) return;
|
|
13
|
+
const element = resolveTarget(target);
|
|
10
14
|
isLockedRef.current = true;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
lockedElementRef.current = element;
|
|
16
|
+
const entry = lockRegistry.get(element);
|
|
17
|
+
if (entry) entry.count++;
|
|
18
|
+
else {
|
|
19
|
+
lockRegistry.set(element, {
|
|
20
|
+
count: 1,
|
|
21
|
+
originalOverflow: element.style.overflow
|
|
22
|
+
});
|
|
23
|
+
element.style.overflow = "hidden";
|
|
14
24
|
}
|
|
15
|
-
|
|
16
|
-
}, []);
|
|
25
|
+
}, [target]);
|
|
17
26
|
const unlock = useCallback(() => {
|
|
18
27
|
if (!isLockedRef.current) return;
|
|
28
|
+
const element = lockedElementRef.current;
|
|
29
|
+
if (!element) return;
|
|
19
30
|
isLockedRef.current = false;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
lockedElementRef.current = null;
|
|
32
|
+
const entry = lockRegistry.get(element);
|
|
33
|
+
if (!entry) return;
|
|
34
|
+
entry.count--;
|
|
35
|
+
if (entry.count === 0) {
|
|
36
|
+
element.style.overflow = entry.originalOverflow;
|
|
37
|
+
lockRegistry.delete(element);
|
|
24
38
|
}
|
|
25
39
|
}, []);
|
|
26
40
|
useEffect(() => {
|
|
27
41
|
return () => {
|
|
28
42
|
if (isLockedRef.current) {
|
|
43
|
+
const element = lockedElementRef.current;
|
|
29
44
|
isLockedRef.current = false;
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
45
|
+
lockedElementRef.current = null;
|
|
46
|
+
if (!element) return;
|
|
47
|
+
const entry = lockRegistry.get(element);
|
|
48
|
+
if (!entry) return;
|
|
49
|
+
entry.count--;
|
|
50
|
+
if (entry.count === 0) {
|
|
51
|
+
element.style.overflow = entry.originalOverflow;
|
|
52
|
+
lockRegistry.delete(element);
|
|
34
53
|
}
|
|
35
54
|
}
|
|
36
55
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -42,6 +42,7 @@ import { ScrollLinked } from "./components/layout/scroll-linked/scroll-linked.mj
|
|
|
42
42
|
import { Separator } from "./components/layout/separator/separator.mjs";
|
|
43
43
|
import { Anchor } from "./components/navigation/anchor/anchor.mjs";
|
|
44
44
|
import { Breadcrumb } from "./components/navigation/breadcrumb/breadcrumb.mjs";
|
|
45
|
+
import { Pagination } from "./components/navigation/pagination/pagination.mjs";
|
|
45
46
|
import { Tabs } from "./components/navigation/tabs/tabs.mjs";
|
|
46
47
|
import { Dialog } from "./components/overlays/dialog/dialog.mjs";
|
|
47
48
|
import { Drawer } from "./components/overlays/drawer/drawer.mjs";
|
|
@@ -83,4 +84,4 @@ import { useThrottle, useThrottledCallback } from "./hooks/throttle/index.mjs";
|
|
|
83
84
|
import { useTimeout } from "./hooks/timeout/index.mjs";
|
|
84
85
|
import { useWindowResize } from "./hooks/window-resize/index.mjs";
|
|
85
86
|
import { useWindowSize } from "./hooks/window-size/index.mjs";
|
|
86
|
-
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Direction, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Option, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, Status, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebounce, useDebouncedCallback, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useThrottle, useThrottledCallback, useTimeout, useToast, useWindowResize, useWindowSize, uuidV4 };
|
|
87
|
+
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Direction, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Option, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, Status, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebounce, useDebouncedCallback, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useThrottle, useThrottledCallback, useTimeout, useToast, useWindowResize, useWindowSize, uuidV4 };
|
package/dist/index.mjs
CHANGED
|
@@ -52,6 +52,7 @@ import { ScrollLinked } from "./components/layout/scroll-linked/scroll-linked.mj
|
|
|
52
52
|
import { Separator } from "./components/layout/separator/separator.mjs";
|
|
53
53
|
import { Anchor } from "./components/navigation/anchor/anchor.mjs";
|
|
54
54
|
import { Breadcrumb } from "./components/navigation/breadcrumb/breadcrumb.mjs";
|
|
55
|
+
import { Pagination } from "./components/navigation/pagination/pagination.mjs";
|
|
55
56
|
import { Tabs } from "./components/navigation/tabs/tabs.mjs";
|
|
56
57
|
import { Dialog } from "./components/overlays/dialog/dialog.mjs";
|
|
57
58
|
import { Modal } from "./components/overlays/modal/modal.mjs";
|
|
@@ -82,4 +83,4 @@ import { useStep } from "./hooks/step/index.mjs";
|
|
|
82
83
|
import { useThrottle, useThrottledCallback } from "./hooks/throttle/index.mjs";
|
|
83
84
|
import { useWindowResize } from "./hooks/window-resize/index.mjs";
|
|
84
85
|
import { useWindowSize } from "./hooks/window-size/index.mjs";
|
|
85
|
-
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebounce, useDebouncedCallback, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useThrottle, useThrottledCallback, useTimeout, useToast, useWindowResize, useWindowSize, uuidV4 };
|
|
86
|
+
export { AIIcon, AccessibilityIcon, Accordion, Alert, AlertIcon, Anchor, ArteOdyssey, ArteOdysseyProvider, AtomIcon, Autocomplete, Avatar, BadIcon, Badge, BaselineStatus, BlogIcon, BoringIcon, Breadcrumb, Button, Card, CheckIcon, Checkbox, CheckboxCard, CheckboxGroup, ChevronIcon, CloseIcon, Code, ColorContrastIcon, ColorInfoIcon, CopyIcon, DarkModeIcon, Dialog, DifficultIcon, Drawer, DropdownMenu, EasyIcon, ExternalLinkIcon, FileField, FormControl, FormIcon, GitHubIcon, GoodIcon, Heading, HistoryIcon, IconButton, IconLink, InformativeIcon, InteractiveCard, InterestingIcon, LightModeIcon, LinkButton, LinkIcon, ListBox, ListIcon, LocationIcon, Logo, LogoIcon, MailIcon, MinusIcon, MixedColorIcon, Modal, NavigationMenuIcon, NewsIcon, NumberField, Pagination, PaletteIcon, PasswordInput, PlusIcon, Popover, PortalRootProvider, PrepareIcon, Progress, PublishDateIcon, QiitaIcon, RSSIcon, Radio, RadioCard, ScrollLinked, Select, SendIcon, Separator, ShallowIcon, ShieldCheckIcon, Skeleton, SlideIcon, Slider, SparklesIcon, Spinner, SubscribeIcon, Switch, Table, TableIcon, Tabs, TagIcon, TextField, Textarea, ToastProvider, Tooltip, TwitterIcon, UpdateDateIcon, ViewIcon, ViewOffIcon, between, cast, cn, commalize, findAllColors, isInternalRoute, toPrecision, useBreakpoint, useClickAway, useClient, useClipboard, useControllableState, useDebounce, useDebouncedCallback, useDisclosure, useHash, useHover, useInView, useIntersectionObserver, useInterval, useLocalStorage, useOpenContext, usePortalRoot, useResize, useScrollDirection, useScrollLock, useSessionStorage, useStep, useThrottle, useThrottledCallback, useTimeout, useToast, useWindowResize, useWindowSize, uuidV4 };
|
package/dist/styles/index.css
CHANGED
|
@@ -222,6 +222,7 @@
|
|
|
222
222
|
--fg-error: var(--red-800);
|
|
223
223
|
|
|
224
224
|
--bg-base: var(--white);
|
|
225
|
+
--bg-raised: var(--white);
|
|
225
226
|
--bg-surface: var(--gray-50);
|
|
226
227
|
--bg-subtle: var(--gray-100);
|
|
227
228
|
--bg-mute: var(--gray-200);
|
|
@@ -275,6 +276,7 @@
|
|
|
275
276
|
--fg-error: var(--red-200);
|
|
276
277
|
|
|
277
278
|
--bg-base: var(--gray-900);
|
|
279
|
+
--bg-raised: var(--gray-800);
|
|
278
280
|
--bg-surface: var(--gray-950);
|
|
279
281
|
--bg-subtle: var(--gray-800);
|
|
280
282
|
--bg-mute: var(--gray-700);
|
|
@@ -328,6 +330,7 @@
|
|
|
328
330
|
--color-fg-error: var(--fg-error);
|
|
329
331
|
|
|
330
332
|
--color-bg-base: var(--bg-base);
|
|
333
|
+
--color-bg-raised: var(--bg-raised);
|
|
331
334
|
--color-bg-surface: var(--bg-surface);
|
|
332
335
|
--color-bg-subtle: var(--bg-subtle);
|
|
333
336
|
--color-bg-mute: var(--bg-mute);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k8o/arte-odyssey",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "k8o's react ui library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"components",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"@chromatic-com/storybook": "5.1.1",
|
|
53
53
|
"@storybook/addon-a11y": "10.3.4",
|
|
54
54
|
"@storybook/addon-docs": "10.3.4",
|
|
55
|
+
"@storybook/addon-mcp": "0.5.0",
|
|
55
56
|
"@storybook/addon-vitest": "10.3.4",
|
|
56
57
|
"@storybook/react-vite": "10.3.4",
|
|
57
58
|
"@tailwindcss/postcss": "4.2.2",
|