@ttt-productions/ui-core 0.11.8 → 0.11.10
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/react/components/scroll-to-top-button.d.ts +25 -3
- package/dist/react/components/scroll-to-top-button.d.ts.map +1 -1
- package/dist/react/components/scroll-to-top-button.js +3 -3
- package/dist/react/components/scroll-to-top-button.js.map +1 -1
- package/package.json +1 -1
- package/src/react/components/scroll-to-top-button.tsx +31 -3
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ButtonProps } from "./button.js";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Standard button DOM props forwarded to the rendered element, minus the props
|
|
5
|
+
* this component owns. Owned props are excluded (not just overridden) so a
|
|
6
|
+
* consumer can never route them through the passthrough channel: `aria-label`
|
|
7
|
+
* is set via {@link ScrollToTopButtonProps.ariaLabel}, extra classes via the
|
|
8
|
+
* merge-aware {@link ScrollToTopButtonProps.className}, content via
|
|
9
|
+
* {@link ScrollToTopButtonProps.icon}, and `onClick` is fixed to scroll-to-top
|
|
10
|
+
* (its scroll animation configurable via
|
|
11
|
+
* {@link ScrollToTopButtonProps.scrollBehavior}). This mirrors how the sibling
|
|
12
|
+
* `Button` destructures its owned `className` out of the forwarded `...props`.
|
|
13
|
+
*/
|
|
14
|
+
type ScrollToTopButtonPassthrough = Omit<React.ComponentPropsWithoutRef<"button">, "className" | "onClick" | "aria-label" | "children">;
|
|
15
|
+
export interface ScrollToTopButtonProps extends ScrollToTopButtonPassthrough {
|
|
4
16
|
/** Scroll threshold (px) before the button appears. Default 400. */
|
|
5
17
|
threshold?: number;
|
|
6
18
|
/** Aria label. Default "Scroll to top". */
|
|
7
19
|
ariaLabel?: string;
|
|
8
|
-
/** Optional extra classes for the button. */
|
|
20
|
+
/** Optional extra classes for the button. Merged with the component's own classes. */
|
|
9
21
|
className?: string;
|
|
10
22
|
/** Optional override for the icon. */
|
|
11
23
|
icon?: React.ReactNode;
|
|
@@ -13,6 +25,16 @@ export interface ScrollToTopButtonProps {
|
|
|
13
25
|
variant?: ButtonProps["variant"];
|
|
14
26
|
/** Button size. Forwarded to the underlying Button. Default "icon". */
|
|
15
27
|
size?: ButtonProps["size"];
|
|
28
|
+
/**
|
|
29
|
+
* Scroll behavior passed to `window.scrollTo`. Default "smooth". Pass "auto"
|
|
30
|
+
* to skip the smooth animation (e.g. for a reduced-motion mode). The package
|
|
31
|
+
* stays motion-policy agnostic: the consumer decides what to pass here — an
|
|
32
|
+
* explicit JS `behavior: "smooth"` is not overridden by a CSS
|
|
33
|
+
* `scroll-behavior` kill-switch, so an app-level reduced-motion mode must
|
|
34
|
+
* pass "auto" to actually stop the animation.
|
|
35
|
+
*/
|
|
36
|
+
scrollBehavior?: ScrollBehavior;
|
|
16
37
|
}
|
|
17
|
-
export declare function ScrollToTopButton({ threshold, ariaLabel, className, icon, variant, size, }: ScrollToTopButtonProps): React.JSX.Element;
|
|
38
|
+
export declare function ScrollToTopButton({ threshold, ariaLabel, className, icon, variant, size, scrollBehavior, ...rest }: ScrollToTopButtonProps): React.JSX.Element;
|
|
39
|
+
export {};
|
|
18
40
|
//# sourceMappingURL=scroll-to-top-button.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-to-top-button.d.ts","sourceRoot":"","sources":["../../../src/react/components/scroll-to-top-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAGvD,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"scroll-to-top-button.d.ts","sourceRoot":"","sources":["../../../src/react/components/scroll-to-top-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAGvD;;;;;;;;;;GAUG;AACH,KAAK,4BAA4B,GAAG,IAAI,CACtC,KAAK,CAAC,wBAAwB,CAAC,QAAQ,CAAC,EACxC,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,CACpD,CAAC;AAEF,MAAM,WAAW,sBAAuB,SAAQ,4BAA4B;IAC1E,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,4FAA4F;IAC5F,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,uEAAuE;IACvE,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,wBAAgB,iBAAiB,CAAC,EAChC,SAAe,EACf,SAA2B,EAC3B,SAAS,EACT,IAAI,EACJ,OAAO,EACP,IAAa,EACb,cAAyB,EACzB,GAAG,IAAI,EACR,EAAE,sBAAsB,qBA4BxB"}
|
|
@@ -4,7 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import { ChevronUp } from "lucide-react";
|
|
5
5
|
import { Button } from "./button.js";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
|
-
export function ScrollToTopButton({ threshold = 400, ariaLabel = "Scroll to top", className, icon, variant, size = "icon", }) {
|
|
7
|
+
export function ScrollToTopButton({ threshold = 400, ariaLabel = "Scroll to top", className, icon, variant, size = "icon", scrollBehavior = "smooth", ...rest }) {
|
|
8
8
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
9
9
|
React.useEffect(() => {
|
|
10
10
|
const toggle = () => setIsVisible(window.scrollY > threshold);
|
|
@@ -12,7 +12,7 @@ export function ScrollToTopButton({ threshold = 400, ariaLabel = "Scroll to top"
|
|
|
12
12
|
window.addEventListener("scroll", toggle, { passive: true });
|
|
13
13
|
return () => window.removeEventListener("scroll", toggle);
|
|
14
14
|
}, [threshold]);
|
|
15
|
-
const onClick = () => window.scrollTo({ top: 0, behavior:
|
|
16
|
-
return (_jsx(Button, { variant: variant, size: size, onClick: onClick, "aria-label": ariaLabel, className: cn("fixed bottom-24 left-1/2 -translate-x-1/2 z-50 rounded-full shadow-lg transition-opacity duration-300", isVisible ? "opacity-100" : "opacity-0 pointer-events-none", className), children: icon ?? _jsx(ChevronUp, { className: "h-5 w-5" }) }));
|
|
15
|
+
const onClick = () => window.scrollTo({ top: 0, behavior: scrollBehavior });
|
|
16
|
+
return (_jsx(Button, { ...rest, variant: variant, size: size, onClick: onClick, "aria-label": ariaLabel, className: cn("fixed bottom-24 left-1/2 -translate-x-1/2 z-50 rounded-full shadow-lg transition-opacity duration-300", isVisible ? "opacity-100" : "opacity-0 pointer-events-none", className), children: icon ?? _jsx(ChevronUp, { className: "h-5 w-5" }) }));
|
|
17
17
|
}
|
|
18
18
|
//# sourceMappingURL=scroll-to-top-button.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-to-top-button.js","sourceRoot":"","sources":["../../../src/react/components/scroll-to-top-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAoB,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"scroll-to-top-button.js","sourceRoot":"","sources":["../../../src/react/components/scroll-to-top-button.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,MAAM,EAAoB,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AA0CxC,MAAM,UAAU,iBAAiB,CAAC,EAChC,SAAS,GAAG,GAAG,EACf,SAAS,GAAG,eAAe,EAC3B,SAAS,EACT,IAAI,EACJ,OAAO,EACP,IAAI,GAAG,MAAM,EACb,cAAc,GAAG,QAAQ,EACzB,GAAG,IAAI,EACgB;IACvB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC;QACT,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;IAE5E,OAAO,CACL,KAAC,MAAM,OACD,IAAI,EACR,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,OAAO,gBACJ,SAAS,EACrB,SAAS,EAAE,EAAE,CACX,uGAAuG,EACvG,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,+BAA+B,EAC3D,SAAS,CACV,YAEA,IAAI,IAAI,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,GACnC,CACV,CAAC;AACJ,CAAC","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { ChevronUp } from \"lucide-react\";\nimport { Button, type ButtonProps } from \"./button.js\";\nimport { cn } from \"../../lib/utils.js\";\n\n/**\n * Standard button DOM props forwarded to the rendered element, minus the props\n * this component owns. Owned props are excluded (not just overridden) so a\n * consumer can never route them through the passthrough channel: `aria-label`\n * is set via {@link ScrollToTopButtonProps.ariaLabel}, extra classes via the\n * merge-aware {@link ScrollToTopButtonProps.className}, content via\n * {@link ScrollToTopButtonProps.icon}, and `onClick` is fixed to scroll-to-top\n * (its scroll animation configurable via\n * {@link ScrollToTopButtonProps.scrollBehavior}). This mirrors how the sibling\n * `Button` destructures its owned `className` out of the forwarded `...props`.\n */\ntype ScrollToTopButtonPassthrough = Omit<\n React.ComponentPropsWithoutRef<\"button\">,\n \"className\" | \"onClick\" | \"aria-label\" | \"children\"\n>;\n\nexport interface ScrollToTopButtonProps extends ScrollToTopButtonPassthrough {\n /** Scroll threshold (px) before the button appears. Default 400. */\n threshold?: number;\n /** Aria label. Default \"Scroll to top\". */\n ariaLabel?: string;\n /** Optional extra classes for the button. Merged with the component's own classes. */\n className?: string;\n /** Optional override for the icon. */\n icon?: React.ReactNode;\n /** Button variant. Forwarded to the underlying Button. Defaults to Button's own default. */\n variant?: ButtonProps[\"variant\"];\n /** Button size. Forwarded to the underlying Button. Default \"icon\". */\n size?: ButtonProps[\"size\"];\n /**\n * Scroll behavior passed to `window.scrollTo`. Default \"smooth\". Pass \"auto\"\n * to skip the smooth animation (e.g. for a reduced-motion mode). The package\n * stays motion-policy agnostic: the consumer decides what to pass here — an\n * explicit JS `behavior: \"smooth\"` is not overridden by a CSS\n * `scroll-behavior` kill-switch, so an app-level reduced-motion mode must\n * pass \"auto\" to actually stop the animation.\n */\n scrollBehavior?: ScrollBehavior;\n}\n\nexport function ScrollToTopButton({\n threshold = 400,\n ariaLabel = \"Scroll to top\",\n className,\n icon,\n variant,\n size = \"icon\",\n scrollBehavior = \"smooth\",\n ...rest\n}: ScrollToTopButtonProps) {\n const [isVisible, setIsVisible] = React.useState(false);\n\n React.useEffect(() => {\n const toggle = () => setIsVisible(window.scrollY > threshold);\n toggle();\n window.addEventListener(\"scroll\", toggle, { passive: true });\n return () => window.removeEventListener(\"scroll\", toggle);\n }, [threshold]);\n\n const onClick = () => window.scrollTo({ top: 0, behavior: scrollBehavior });\n\n return (\n <Button\n {...rest}\n variant={variant}\n size={size}\n onClick={onClick}\n aria-label={ariaLabel}\n className={cn(\n \"fixed bottom-24 left-1/2 -translate-x-1/2 z-50 rounded-full shadow-lg transition-opacity duration-300\",\n isVisible ? \"opacity-100\" : \"opacity-0 pointer-events-none\",\n className,\n )}\n >\n {icon ?? <ChevronUp className=\"h-5 w-5\" />}\n </Button>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -5,12 +5,28 @@ import { ChevronUp } from "lucide-react";
|
|
|
5
5
|
import { Button, type ButtonProps } from "./button.js";
|
|
6
6
|
import { cn } from "../../lib/utils.js";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Standard button DOM props forwarded to the rendered element, minus the props
|
|
10
|
+
* this component owns. Owned props are excluded (not just overridden) so a
|
|
11
|
+
* consumer can never route them through the passthrough channel: `aria-label`
|
|
12
|
+
* is set via {@link ScrollToTopButtonProps.ariaLabel}, extra classes via the
|
|
13
|
+
* merge-aware {@link ScrollToTopButtonProps.className}, content via
|
|
14
|
+
* {@link ScrollToTopButtonProps.icon}, and `onClick` is fixed to scroll-to-top
|
|
15
|
+
* (its scroll animation configurable via
|
|
16
|
+
* {@link ScrollToTopButtonProps.scrollBehavior}). This mirrors how the sibling
|
|
17
|
+
* `Button` destructures its owned `className` out of the forwarded `...props`.
|
|
18
|
+
*/
|
|
19
|
+
type ScrollToTopButtonPassthrough = Omit<
|
|
20
|
+
React.ComponentPropsWithoutRef<"button">,
|
|
21
|
+
"className" | "onClick" | "aria-label" | "children"
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
export interface ScrollToTopButtonProps extends ScrollToTopButtonPassthrough {
|
|
9
25
|
/** Scroll threshold (px) before the button appears. Default 400. */
|
|
10
26
|
threshold?: number;
|
|
11
27
|
/** Aria label. Default "Scroll to top". */
|
|
12
28
|
ariaLabel?: string;
|
|
13
|
-
/** Optional extra classes for the button. */
|
|
29
|
+
/** Optional extra classes for the button. Merged with the component's own classes. */
|
|
14
30
|
className?: string;
|
|
15
31
|
/** Optional override for the icon. */
|
|
16
32
|
icon?: React.ReactNode;
|
|
@@ -18,6 +34,15 @@ export interface ScrollToTopButtonProps {
|
|
|
18
34
|
variant?: ButtonProps["variant"];
|
|
19
35
|
/** Button size. Forwarded to the underlying Button. Default "icon". */
|
|
20
36
|
size?: ButtonProps["size"];
|
|
37
|
+
/**
|
|
38
|
+
* Scroll behavior passed to `window.scrollTo`. Default "smooth". Pass "auto"
|
|
39
|
+
* to skip the smooth animation (e.g. for a reduced-motion mode). The package
|
|
40
|
+
* stays motion-policy agnostic: the consumer decides what to pass here — an
|
|
41
|
+
* explicit JS `behavior: "smooth"` is not overridden by a CSS
|
|
42
|
+
* `scroll-behavior` kill-switch, so an app-level reduced-motion mode must
|
|
43
|
+
* pass "auto" to actually stop the animation.
|
|
44
|
+
*/
|
|
45
|
+
scrollBehavior?: ScrollBehavior;
|
|
21
46
|
}
|
|
22
47
|
|
|
23
48
|
export function ScrollToTopButton({
|
|
@@ -27,6 +52,8 @@ export function ScrollToTopButton({
|
|
|
27
52
|
icon,
|
|
28
53
|
variant,
|
|
29
54
|
size = "icon",
|
|
55
|
+
scrollBehavior = "smooth",
|
|
56
|
+
...rest
|
|
30
57
|
}: ScrollToTopButtonProps) {
|
|
31
58
|
const [isVisible, setIsVisible] = React.useState(false);
|
|
32
59
|
|
|
@@ -37,10 +64,11 @@ export function ScrollToTopButton({
|
|
|
37
64
|
return () => window.removeEventListener("scroll", toggle);
|
|
38
65
|
}, [threshold]);
|
|
39
66
|
|
|
40
|
-
const onClick = () => window.scrollTo({ top: 0, behavior:
|
|
67
|
+
const onClick = () => window.scrollTo({ top: 0, behavior: scrollBehavior });
|
|
41
68
|
|
|
42
69
|
return (
|
|
43
70
|
<Button
|
|
71
|
+
{...rest}
|
|
44
72
|
variant={variant}
|
|
45
73
|
size={size}
|
|
46
74
|
onClick={onClick}
|