@ttt-productions/ui-core 0.11.9 → 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.
@@ -6,9 +6,10 @@ import { type ButtonProps } from "./button.js";
6
6
  * consumer can never route them through the passthrough channel: `aria-label`
7
7
  * is set via {@link ScrollToTopButtonProps.ariaLabel}, extra classes via the
8
8
  * merge-aware {@link ScrollToTopButtonProps.className}, content via
9
- * {@link ScrollToTopButtonProps.icon}, and `onClick` is fixed to scroll-to-top.
10
- * This mirrors how the sibling `Button` destructures its owned `className` out
11
- * of the forwarded `...props`.
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`.
12
13
  */
13
14
  type ScrollToTopButtonPassthrough = Omit<React.ComponentPropsWithoutRef<"button">, "className" | "onClick" | "aria-label" | "children">;
14
15
  export interface ScrollToTopButtonProps extends ScrollToTopButtonPassthrough {
@@ -24,7 +25,16 @@ export interface ScrollToTopButtonProps extends ScrollToTopButtonPassthrough {
24
25
  variant?: ButtonProps["variant"];
25
26
  /** Button size. Forwarded to the underlying Button. Default "icon". */
26
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;
27
37
  }
28
- export declare function ScrollToTopButton({ threshold, ariaLabel, className, icon, variant, size, ...rest }: ScrollToTopButtonProps): React.JSX.Element;
38
+ export declare function ScrollToTopButton({ threshold, ariaLabel, className, icon, variant, size, scrollBehavior, ...rest }: ScrollToTopButtonProps): React.JSX.Element;
29
39
  export {};
30
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;;;;;;;;;GASG;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;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,SAAe,EACf,SAA2B,EAC3B,SAAS,EACT,IAAI,EACJ,OAAO,EACP,IAAa,EACb,GAAG,IAAI,EACR,EAAE,sBAAsB,qBA4BxB"}
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", ...rest }) {
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: "smooth" });
15
+ const onClick = () => window.scrollTo({ top: 0, behavior: scrollBehavior });
16
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;AAgCxC,MAAM,UAAU,iBAAiB,CAAC,EAChC,SAAS,GAAG,GAAG,EACf,SAAS,GAAG,eAAe,EAC3B,SAAS,EACT,IAAI,EACJ,OAAO,EACP,IAAI,GAAG,MAAM,EACb,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,QAAQ,EAAE,CAAC,CAAC;IAEtE,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 * This mirrors how the sibling `Button` destructures its owned `className` out\n * 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\nexport function ScrollToTopButton({\n threshold = 400,\n ariaLabel = \"Scroll to top\",\n className,\n icon,\n variant,\n size = \"icon\",\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: \"smooth\" });\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"]}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/ui-core",
3
- "version": "0.11.9",
3
+ "version": "0.11.10",
4
4
  "description": "Shared UI components for TTT Productions projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,9 +11,10 @@ import { cn } from "../../lib/utils.js";
11
11
  * consumer can never route them through the passthrough channel: `aria-label`
12
12
  * is set via {@link ScrollToTopButtonProps.ariaLabel}, extra classes via the
13
13
  * merge-aware {@link ScrollToTopButtonProps.className}, content via
14
- * {@link ScrollToTopButtonProps.icon}, and `onClick` is fixed to scroll-to-top.
15
- * This mirrors how the sibling `Button` destructures its owned `className` out
16
- * of the forwarded `...props`.
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`.
17
18
  */
18
19
  type ScrollToTopButtonPassthrough = Omit<
19
20
  React.ComponentPropsWithoutRef<"button">,
@@ -33,6 +34,15 @@ export interface ScrollToTopButtonProps extends ScrollToTopButtonPassthrough {
33
34
  variant?: ButtonProps["variant"];
34
35
  /** Button size. Forwarded to the underlying Button. Default "icon". */
35
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;
36
46
  }
37
47
 
38
48
  export function ScrollToTopButton({
@@ -42,6 +52,7 @@ export function ScrollToTopButton({
42
52
  icon,
43
53
  variant,
44
54
  size = "icon",
55
+ scrollBehavior = "smooth",
45
56
  ...rest
46
57
  }: ScrollToTopButtonProps) {
47
58
  const [isVisible, setIsVisible] = React.useState(false);
@@ -53,7 +64,7 @@ export function ScrollToTopButton({
53
64
  return () => window.removeEventListener("scroll", toggle);
54
65
  }, [threshold]);
55
66
 
56
- const onClick = () => window.scrollTo({ top: 0, behavior: "smooth" });
67
+ const onClick = () => window.scrollTo({ top: 0, behavior: scrollBehavior });
57
68
 
58
69
  return (
59
70
  <Button