reshaped 3.1.1 → 3.1.3

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/bundle.css +1 -1
  3. package/dist/bundle.js +11 -11
  4. package/dist/components/Actionable/Actionable.js +3 -1
  5. package/dist/components/Modal/Modal.js +2 -2
  6. package/dist/components/Modal/Modal.types.d.ts +2 -0
  7. package/dist/components/Modal/tests/Modal.stories.d.ts +1 -0
  8. package/dist/components/Modal/tests/Modal.stories.js +11 -1
  9. package/dist/components/Overlay/Overlay.js +3 -3
  10. package/dist/components/Overlay/Overlay.module.css +1 -1
  11. package/dist/components/Overlay/Overlay.types.d.ts +2 -0
  12. package/dist/components/Overlay/tests/Overlay.stories.js +11 -3
  13. package/dist/components/Pagination/PaginationControlled.js +3 -2
  14. package/dist/components/Pagination/tests/Pagination.stories.js +3 -0
  15. package/dist/components/Text/Text.js +3 -1
  16. package/dist/components/Text/Text.module.css +1 -1
  17. package/dist/components/View/View.js +3 -1
  18. package/dist/components/View/View.types.d.ts +1 -1
  19. package/dist/components/View/tests/View.stories.js +4 -0
  20. package/dist/components/_private/Flyout/Flyout.constants.d.ts +1 -1
  21. package/dist/components/_private/Flyout/Flyout.constants.js +1 -1
  22. package/dist/components/_private/Flyout/Flyout.types.d.ts +4 -0
  23. package/dist/components/_private/Flyout/FlyoutControlled.js +39 -6
  24. package/dist/components/_private/Flyout/FlyoutTrigger.js +3 -1
  25. package/dist/components/_private/Flyout/useFlyout.d.ts +5 -1
  26. package/dist/components/_private/Flyout/useFlyout.js +20 -6
  27. package/dist/styles/textAlign/index.d.ts +3 -0
  28. package/dist/styles/textAlign/index.js +10 -0
  29. package/dist/styles/textAlign/textAlign.module.css +1 -0
  30. package/dist/styles/types.d.ts +1 -0
  31. package/package.json +2 -2
@@ -11,7 +11,9 @@ const Actionable = forwardRef((props, ref) => {
11
11
  const hasClickHandler = onClick || attributes?.onClick;
12
12
  const hasFocusHandler = attributes?.onFocus || attributes?.onBlur;
13
13
  const isLink = Boolean(href || attributes?.href);
14
- const isButton = Boolean(hasClickHandler || hasFocusHandler || type);
14
+ // Including attributes ref for the cases when event listeners are added through it
15
+ // To make sure it doesn't render a span
16
+ const isButton = Boolean(hasClickHandler || hasFocusHandler || type || attributes?.ref);
15
17
  const renderedAsButton = !isLink && isButton && (!as || as === "button");
16
18
  let TagName;
17
19
  if (isLink) {
@@ -40,7 +40,7 @@ const ModalSubtitle = (props) => {
40
40
  return (_jsx(Text, { variant: "body-3", color: "neutral-faded", attributes: { id: `${id}-subtitle` }, children: children }));
41
41
  };
42
42
  const Modal = (props) => {
43
- const { children, onClose, onOpen, active, size, padding = 4, position = "center", transparentOverlay, ariaLabel, autoFocus = true, disableSwipeGesture, overlayClassName, className, attributes, } = props;
43
+ const { children, onClose, onOpen, active, size, padding = 4, position = "center", transparentOverlay, blurredOverlay, ariaLabel, autoFocus = true, disableSwipeGesture, disableCloseOnOutsideClick, overlayClassName, className, attributes, } = props;
44
44
  const onCloseRef = useHandlerRef(onClose);
45
45
  const id = useElementId();
46
46
  const clientPosition = useResponsiveClientValue(position);
@@ -165,7 +165,7 @@ const Modal = (props) => {
165
165
  setHideProgress(progress / 2);
166
166
  dragDistanceRef.current = dragDistance;
167
167
  }, [dragDistance, clientPosition, rootRef]);
168
- return (_jsx(Overlay, { onClose: onClose, onOpen: onOpen, active: active, transparent: transparentOverlay || hideProgress, className: overlayClassName, attributes: {
168
+ return (_jsx(Overlay, { onClose: onClose, onOpen: onOpen, disableCloseOnClick: disableCloseOnOutsideClick, active: active, transparent: transparentOverlay || hideProgress, blurred: blurredOverlay, className: overlayClassName, attributes: {
169
169
  onTouchStart: handleDragStart,
170
170
  }, children: ({ active }) => {
171
171
  const rootClassNames = classNames(s.root, className, paddingStyles?.classNames, active && s["--active"], dragging && s["--dragging"], responsiveClassNames(s, "--position", position));
@@ -20,7 +20,9 @@ export type Props = {
20
20
  size?: G.Responsive<string>;
21
21
  padding?: G.Responsive<number>;
22
22
  transparentOverlay?: boolean;
23
+ blurredOverlay?: boolean;
23
24
  disableSwipeGesture?: boolean;
25
+ disableCloseOnOutsideClick?: boolean;
24
26
  autoFocus?: boolean;
25
27
  ariaLabel?: string;
26
28
  className?: G.ClassName;
@@ -19,5 +19,6 @@ export declare const size: () => React.JSX.Element;
19
19
  export declare const padding: () => React.JSX.Element;
20
20
  export declare const composition: () => React.JSX.Element;
21
21
  export declare const overlay: () => React.JSX.Element;
22
+ export declare const flags: () => React.JSX.Element;
22
23
  export declare const edgeCases: () => React.JSX.Element;
23
24
  export declare const trapFocusEdgeCases: () => React.JSX.Element;
@@ -97,9 +97,19 @@ export const composition = () => (<Example>
97
97
  export const overlay = () => (<Example>
98
98
  <Example.Item title="transparentOverlay, doesn't lock scroll">
99
99
  <Demo transparentOverlay/>
100
- <View height="1000px"/>
101
100
  </Example.Item>
101
+ <Example.Item title="blurredOverlay">
102
+ <Demo blurredOverlay/>
103
+ </Example.Item>
104
+ <View height="1000px"/>
102
105
  </Example>);
106
+ export const flags = () => {
107
+ return (<Example>
108
+ <Example.Item title="disableCloseOnOutsideClick">
109
+ <Demo disableCloseOnOutsideClick/>
110
+ </Example.Item>
111
+ </Example>);
112
+ };
103
113
  export const edgeCases = () => {
104
114
  const menuModalToggle = useToggle();
105
115
  const scrollModalToggle = useToggle();
@@ -13,7 +13,7 @@ import Portal from "../_private/Portal/index.js";
13
13
  import s from "./Overlay.module.css";
14
14
  import useHandlerRef from "../../hooks/useHandlerRef.js";
15
15
  const Overlay = (props) => {
16
- const { active, children, transparent, onClose, onOpen, className, attributes } = props;
16
+ const { active, children, transparent, blurred, onClose, onOpen, disableCloseOnClick, className, attributes, } = props;
17
17
  const onCloseRef = useHandlerRef(onClose);
18
18
  const onOpenRef = useHandlerRef(onOpen);
19
19
  const clickThrough = transparent === true;
@@ -26,7 +26,7 @@ const Overlay = (props) => {
26
26
  const { active: rendered, activate: render, deactivate: remove } = useToggle(active || false);
27
27
  const { active: visible, activate: show, deactivate: hide } = useToggle(active || false);
28
28
  const isDismissible = useIsDismissible(active, contentRef);
29
- const rootClassNames = classNames(s.root, visible && s["--visible"], clickThrough && s["--click-through"], animated && s["--animated"], className);
29
+ const rootClassNames = classNames(s.root, visible && s["--visible"], clickThrough && s["--click-through"], blurred && s["--blurred"], animated && s["--animated"], className);
30
30
  const isInsideChild = (el) => {
31
31
  if (!contentRef.current)
32
32
  return;
@@ -46,7 +46,7 @@ const Overlay = (props) => {
46
46
  const handleMouseUp = (event) => {
47
47
  const isMouseUpValid = !isInsideChild(event.target);
48
48
  const shouldClose = isMouseDownValidRef.current && isMouseUpValid && !clickThrough;
49
- if (!shouldClose)
49
+ if (!shouldClose || disableCloseOnClick)
50
50
  return;
51
51
  close();
52
52
  };
@@ -1 +1 @@
1
- .root{overflow:auto;-webkit-overflow-scrolling:touch;background-color:rgba(var(--rs-color-rgb-black),0);color:var(--rs-color-white);cursor:default!important;inset:0;opacity:0;position:fixed;z-index:var(--rs-z-index-overlay)}.wrapper{display:table;height:100%;width:100%}.inner{display:table-cell;text-align:center}.content,.inner{vertical-align:middle}.content{display:inline-block;text-align:initial}.root.--visible{background-color:rgba(var(--rs-color-rgb-black),var(--rs-overlay-opacity));opacity:1}.root.--click-through{color:inherit;pointer-events:none}.root.--click-through .content,.root.--click-through>:not(.wrapper){pointer-events:all}.root.--animated{transition:var(--rs-duration-medium) var(--rs-easing-accelerate);transition-property:background-color,transform,opacity}.root.--animated.--visible{transition-timing-function:var(--rs-easing-decelerate)}
1
+ .root{overflow:auto;-webkit-overflow-scrolling:touch;background-color:rgba(var(--rs-color-rgb-black),0);color:var(--rs-color-white);cursor:default!important;inset:-1px;opacity:0;outline:none;position:fixed;z-index:var(--rs-z-index-overlay)}.wrapper{display:table;height:100%;width:100%}.inner{display:table-cell;text-align:center}.content,.inner{vertical-align:middle}.content{display:inline-block;text-align:initial}.root.--visible{background-color:rgba(var(--rs-color-rgb-black),var(--rs-overlay-opacity));opacity:1}.root.--click-through{color:inherit;pointer-events:none}.root.--blurred{backdrop-filter:blur(3px)}.root.--click-through .content,.root.--click-through>:not(.wrapper){pointer-events:all}.root.--animated{transition:var(--rs-duration-medium) var(--rs-easing-accelerate);transition-property:background-color,transform,opacity}.root.--animated.--visible{transition-timing-function:var(--rs-easing-decelerate)}
@@ -2,12 +2,14 @@ import type React from "react";
2
2
  import type * as G from "../../types/global";
3
3
  export type Props = {
4
4
  transparent?: boolean | number;
5
+ blurred?: boolean;
5
6
  children?: React.ReactNode | ((props: {
6
7
  active: boolean;
7
8
  }) => React.ReactNode);
8
9
  active?: boolean;
9
10
  onClose?: () => void;
10
11
  onOpen?: () => void;
12
+ disableCloseOnClick?: boolean;
11
13
  className?: G.ClassName;
12
14
  attributes?: G.Attributes<"div">;
13
15
  };
@@ -14,15 +14,15 @@ export default {
14
14
  },
15
15
  };
16
16
  export const base = () => {
17
- const baseToggle = useToggle(true);
17
+ const baseToggle = useToggle(false);
18
18
  const transparentToggle = useToggle(false);
19
+ const blurredToggle = useToggle(false);
19
20
  return (<Example>
20
21
  <Example.Item title="locks scroll">
21
22
  <Button onClick={() => baseToggle.activate()}>Open overlay</Button>
22
23
  <Overlay active={baseToggle.active} onClose={() => baseToggle.deactivate()}>
23
24
  Overlay content
24
25
  </Overlay>
25
- <div style={{ height: 1000 }}/>
26
26
  </Example.Item>
27
27
 
28
28
  <Example.Item title="transparent, doesn't lock scroll">
@@ -30,8 +30,16 @@ export const base = () => {
30
30
  <Overlay active={transparentToggle.active} onClose={() => transparentToggle.deactivate()} transparent>
31
31
  Overlay content
32
32
  </Overlay>
33
- <div style={{ height: 1000 }}/>
34
33
  </Example.Item>
34
+
35
+ <Example.Item title="blurred">
36
+ <Button onClick={() => blurredToggle.activate()}>Open overlay</Button>
37
+ <Overlay active={blurredToggle.active} onClose={() => blurredToggle.deactivate()} blurred>
38
+ Overlay content
39
+ </Overlay>
40
+ </Example.Item>
41
+
42
+ <div style={{ height: 1000 }}/>
35
43
  </Example>);
36
44
  };
37
45
  class CustomElement extends window.HTMLElement {
@@ -11,8 +11,9 @@ const PaginationControlled = (props) => {
11
11
  const selectionRadius = 1;
12
12
  const edgeRadius = 1;
13
13
  const pages = [];
14
- const hasHead = selectedPage - selectionRadius > edgeRadius + 2;
15
- const hasTail = selectedPage + selectionRadius < total - edgeRadius;
14
+ const minLengthToSplit = (edgeRadius + 1) * 2 + selectionRadius * 2 + 1;
15
+ const hasHead = total > minLengthToSplit && selectedPage - selectionRadius > edgeRadius + 2;
16
+ const hasTail = total > minLengthToSplit && selectedPage + selectionRadius < total - edgeRadius;
16
17
  /**
17
18
  * Calculate the amount of rendered pages + dots
18
19
  * Removing head or tail also removes their dots
@@ -20,5 +20,8 @@ export const truncate = () => {
20
20
  <Example.Item title="end">
21
21
  <Pagination total={10} defaultPage={10} previousAriaLabel="Previous page" nextAriaLabel="Next page" pageAriaLabel={(args) => `Page ${args.page}`}/>
22
22
  </Example.Item>
23
+ <Example.Item title="no truncation">
24
+ <Pagination total={4} previousAriaLabel="Previous page" nextAriaLabel="Next page" pageAriaLabel={(args) => `Page ${args.page}`}/>
25
+ </Example.Item>
23
26
  </Example>);
24
27
  };
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { classNames, responsiveClassNames } from "../../utilities/helpers.js";
3
+ import getTextAlignStyles from "../../styles/textAlign/index.js";
3
4
  import s from "./Text.module.css";
4
5
  const tagMap = {
5
6
  "title-1": "h1",
@@ -12,12 +13,13 @@ const tagMap = {
12
13
  const Text = (props) => {
13
14
  const { variant, color, weight, align, decoration, maxLines, wrap, children, className, attributes, } = props;
14
15
  const largestVariant = typeof variant === "string" ? variant : variant?.xl || variant?.l || variant?.m || variant?.s;
16
+ const alignStyles = getTextAlignStyles(align);
15
17
  /**
16
18
  * Using any here to let TS save on type resolving, otherwise TS throws an error due to the type complexity
17
19
  * It still resolves the attributes correctly based on the tag
18
20
  */
19
21
  const TagName = props.as || (largestVariant && tagMap[largestVariant]) || "div";
20
- const rootClassName = classNames(s.root, color && s[`--color-${color}`], ...responsiveClassNames(s, "--variant", variant), ...responsiveClassNames(s, "--align", align), ...responsiveClassNames(s, "--weight", weight), decoration && s[`--decoration-${decoration}`], maxLines !== undefined && s[`--clamp`], maxLines === 1 && s["--break-all"], wrap && s[`--wrap-${wrap}`], className);
22
+ const rootClassName = classNames(s.root, color && s[`--color-${color}`], ...responsiveClassNames(s, "--variant", variant), ...responsiveClassNames(s, "--weight", weight), decoration && s[`--decoration-${decoration}`], maxLines !== undefined && s[`--clamp`], maxLines === 1 && s["--break-all"], wrap && s[`--wrap-${wrap}`], alignStyles?.classNames, className);
21
23
  const style = {
22
24
  ...attributes?.style,
23
25
  "--rs-text-lines": maxLines,
@@ -1 +1 @@
1
- .root{transition:color var(--rs-duration-fast) var(--rs-easing-standard)}.--clamp{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--rs-text-lines);overflow:hidden}.--break-all{word-break:break-all}.--wrap-balance{text-wrap:balance}.--align-start{text-align:start}.--align-center{text-align:center}.--align-end{text-align:end}.--variant-title-1{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold{font-weight:var(--rs-font-weight-bold)!important}.--color-neutral{color:var(--rs-color-foreground-neutral)}.--color-neutral-faded{color:var(--rs-color-foreground-neutral-faded)}.--color-primary{color:var(--rs-color-foreground-primary)}.--color-warning{color:var(--rs-color-foreground-warning)}.--color-positive{color:var(--rs-color-foreground-positive)}.--color-critical{color:var(--rs-color-foreground-critical)}.--color-disabled{color:var(--rs-color-foreground-disabled)}.--decoration-line-through{text-decoration:line-through}@media (--rs-viewport-m ){.--align-start--m{text-align:start}.--align-center--m{text-align:center}.--align-end--m{text-align:end}.--variant-title-1--m{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2--m{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3--m{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4--m{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5--m{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6--m{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1--m{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2--m{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3--m{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1--m{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2--m{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3--m{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1--m{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2--m{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular--m{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium--m{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold--m{font-weight:var(--rs-font-weight-bold)!important}}@media (--rs-viewport-l ){.--align-start--l{text-align:start}.--align-center--l{text-align:center}.--align-end--l{text-align:end}.--variant-title-1--l{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2--l{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3--l{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4--l{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5--l{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6--l{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1--l{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2--l{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3--l{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1--l{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2--l{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3--l{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1--l{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2--l{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular--l{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium--l{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold--l{font-weight:var(--rs-font-weight-bold)!important}}@media (--rs-viewport-xl ){.--align-start--xl{text-align:start}.--align-center--xl{text-align:center}.--align-end--xl{text-align:end}.--variant-title-1--xl{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2--xl{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3--xl{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4--xl{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5--xl{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6--xl{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1--xl{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2--xl{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3--xl{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1--xl{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2--xl{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3--xl{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1--xl{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2--xl{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular--xl{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium--xl{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold--xl{font-weight:var(--rs-font-weight-bold)!important}}
1
+ .root{transition:color var(--rs-duration-fast) var(--rs-easing-standard)}.--clamp{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:var(--rs-text-lines);overflow:hidden}.--break-all{word-break:break-all}.--wrap-balance{text-wrap:balance}.--variant-title-1{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold{font-weight:var(--rs-font-weight-bold)!important}.--color-neutral{color:var(--rs-color-foreground-neutral)}.--color-neutral-faded{color:var(--rs-color-foreground-neutral-faded)}.--color-primary{color:var(--rs-color-foreground-primary)}.--color-warning{color:var(--rs-color-foreground-warning)}.--color-positive{color:var(--rs-color-foreground-positive)}.--color-critical{color:var(--rs-color-foreground-critical)}.--color-disabled{color:var(--rs-color-foreground-disabled)}.--decoration-line-through{text-decoration:line-through}@media (--rs-viewport-m ){.--variant-title-1--m{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2--m{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3--m{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4--m{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5--m{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6--m{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1--m{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2--m{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3--m{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1--m{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2--m{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3--m{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1--m{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2--m{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular--m{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium--m{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold--m{font-weight:var(--rs-font-weight-bold)!important}}@media (--rs-viewport-l ){.--variant-title-1--l{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2--l{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3--l{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4--l{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5--l{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6--l{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1--l{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2--l{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3--l{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1--l{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2--l{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3--l{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1--l{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2--l{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular--l{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium--l{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold--l{font-weight:var(--rs-font-weight-bold)!important}}@media (--rs-viewport-xl ){.--variant-title-1--xl{font-family:var(--rs-font-family-title-1);font-size:var(--rs-font-size-title-1);font-weight:var(--rs-font-weight-title-1);letter-spacing:var(--rs-letter-spacing-title-1);line-height:var(--rs-line-height-title-1)}.--variant-title-2--xl{font-family:var(--rs-font-family-title-2);font-size:var(--rs-font-size-title-2);font-weight:var(--rs-font-weight-title-2);letter-spacing:var(--rs-letter-spacing-title-2);line-height:var(--rs-line-height-title-2)}.--variant-title-3--xl{font-family:var(--rs-font-family-title-3);font-size:var(--rs-font-size-title-3);font-weight:var(--rs-font-weight-title-3);letter-spacing:var(--rs-letter-spacing-title-3);line-height:var(--rs-line-height-title-3)}.--variant-title-4--xl{font-family:var(--rs-font-family-title-4);font-size:var(--rs-font-size-title-4);font-weight:var(--rs-font-weight-title-4);letter-spacing:var(--rs-letter-spacing-title-4);line-height:var(--rs-line-height-title-4)}.--variant-title-5--xl{font-family:var(--rs-font-family-title-5);font-size:var(--rs-font-size-title-5);font-weight:var(--rs-font-weight-title-5);letter-spacing:var(--rs-letter-spacing-title-5);line-height:var(--rs-line-height-title-5)}.--variant-title-6--xl{font-family:var(--rs-font-family-title-6);font-size:var(--rs-font-size-title-6);font-weight:var(--rs-font-weight-title-6);letter-spacing:var(--rs-letter-spacing-title-6);line-height:var(--rs-line-height-title-6)}.--variant-featured-1--xl{font-family:var(--rs-font-family-featured-1);font-size:var(--rs-font-size-featured-1);font-weight:var(--rs-font-weight-featured-1);letter-spacing:var(--rs-letter-spacing-featured-1);line-height:var(--rs-line-height-featured-1)}.--variant-featured-2--xl{font-family:var(--rs-font-family-featured-2);font-size:var(--rs-font-size-featured-2);font-weight:var(--rs-font-weight-featured-2);letter-spacing:var(--rs-letter-spacing-featured-2);line-height:var(--rs-line-height-featured-2)}.--variant-featured-3--xl{font-family:var(--rs-font-family-featured-3);font-size:var(--rs-font-size-featured-3);font-weight:var(--rs-font-weight-featured-3);letter-spacing:var(--rs-letter-spacing-featured-3);line-height:var(--rs-line-height-featured-3)}.--variant-body-1--xl{font-family:var(--rs-font-family-body-1);font-size:var(--rs-font-size-body-1);font-weight:var(--rs-font-weight-body-1);letter-spacing:var(--rs-letter-spacing-body-1);line-height:var(--rs-line-height-body-1)}.--variant-body-2--xl{font-family:var(--rs-font-family-body-2);font-size:var(--rs-font-size-body-2);font-weight:var(--rs-font-weight-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--variant-body-3--xl{font-family:var(--rs-font-family-body-3);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--variant-caption-1--xl{font-family:var(--rs-font-family-caption-1);font-size:var(--rs-font-size-caption-1);font-weight:var(--rs-font-weight-caption-1);letter-spacing:var(--rs-letter-spacing-caption-1);line-height:var(--rs-line-height-caption-1)}.--variant-caption-2--xl{font-family:var(--rs-font-family-caption-2);font-size:var(--rs-font-size-caption-2);font-weight:var(--rs-font-weight-caption-2);letter-spacing:var(--rs-letter-spacing-caption-2);line-height:var(--rs-line-height-caption-2)}.--weight-regular--xl{font-weight:var(--rs-font-weight-regular)!important}.--weight-medium--xl{font-weight:var(--rs-font-weight-medium)!important}.--weight-bold--xl{font-weight:var(--rs-font-weight-bold)!important}}
@@ -17,6 +17,7 @@ import getPositionStyles from "../../styles/position/index.js";
17
17
  import getInsetStyles from "../../styles/inset/index.js";
18
18
  import getAspectRatioStyles from "../../styles/aspectRatio/index.js";
19
19
  import getBorderStyles from "../../styles/border/index.js";
20
+ import getTextAlignStyles from "../../styles/textAlign/index.js";
20
21
  const ViewItem = (props) => {
21
22
  const { columns, grow, gapBefore, as: TagName = "div", order, children, className, attributes, } = props;
22
23
  const itemClassNames = classNames(s.item, className, gapBefore === "auto" && s["item--gap-auto"], gapBefore !== undefined && s["item--gap-before"], columns && s["item--columns"], ...responsiveClassNames(s, "item--grow", grow), ...responsiveClassNames(s, "item--columns", columns));
@@ -63,6 +64,7 @@ const View = (props) => {
63
64
  const insetEndStyles = getInsetStyles(insetEnd, "end");
64
65
  const aspectRatioStyles = getAspectRatioStyles(aspectRatio);
65
66
  const borderStyles = getBorderStyles(borderColor);
67
+ const textAlignStyles = getTextAlignStyles(textAlign);
66
68
  let renderedItemIndex = 0;
67
69
  // If wrap is not defined, it can be set based on item grow and split usage
68
70
  let nowrap;
@@ -135,7 +137,7 @@ const View = (props) => {
135
137
  return renderItem({ child, index: renderedIndex });
136
138
  });
137
139
  // Classnames and attributes are written here so we can assign nowrap to the root element based on the children
138
- const rootClassNames = classNames(s.root, className, radiusStyles?.classNames, positionStyles?.classNames, bleedStyles?.classNames, widthStyles?.classNames, heightStyles?.classNames, aspectRatioStyles?.classNames, maxWidthStyles?.classNames, maxHeightStyles?.classNames, minWidthStyles?.classNames, minHeightStyles?.classNames, insetStyles?.classNames, insetTopStyles?.classNames, insetBottomStyles?.classNames, insetStartStyles?.classNames, insetEndStyles?.classNames, borderStyles?.classNames, textAlign && s[`--align-text-${textAlign}`], backgroundColor && s[`--bg-${backgroundColor}`], shadow && s[`--shadow-${shadow}`], overflow && s[`--overflow-${overflow}`], animated && s["--animated"], divided && s["--divided"], (padding !== undefined || paddingInline !== undefined || paddingBlock !== undefined) &&
140
+ const rootClassNames = classNames(s.root, className, radiusStyles?.classNames, positionStyles?.classNames, bleedStyles?.classNames, widthStyles?.classNames, heightStyles?.classNames, aspectRatioStyles?.classNames, maxWidthStyles?.classNames, maxHeightStyles?.classNames, minWidthStyles?.classNames, minHeightStyles?.classNames, insetStyles?.classNames, insetTopStyles?.classNames, insetBottomStyles?.classNames, insetStartStyles?.classNames, insetEndStyles?.classNames, borderStyles?.classNames, textAlignStyles?.classNames, backgroundColor && s[`--bg-${backgroundColor}`], shadow && s[`--shadow-${shadow}`], overflow && s[`--overflow-${overflow}`], animated && s["--animated"], divided && s["--divided"], (padding !== undefined || paddingInline !== undefined || paddingBlock !== undefined) &&
139
141
  s["--padding"], paddingBottom !== undefined && s["--padding-bottom"], paddingEnd !== undefined && s["--padding-end"], paddingStart !== undefined && s["--padding-start"], paddingTop !== undefined && s["--padding-top"], (isFlex || nowrap) && s["--flex"], ...responsiveClassNames(s, "--direction", direction), ...responsiveClassNames(s, "--align", align), ...responsiveClassNames(s, "--justify", justify),
140
142
  // Wrap and nowrap are separate here because inverting any of them could result into a false value which will be ignored by classNames
141
143
  ...responsiveClassNames(s, "--nowrap", nowrap || wrap === false), ...responsiveClassNames(s, "--wrap", wrap),
@@ -27,7 +27,7 @@ export type Props<TagName extends keyof JSX.IntrinsicElements = "div"> = {
27
27
  paddingInline?: G.Responsive<number>;
28
28
  paddingBlock?: G.Responsive<number>;
29
29
  bleed?: G.Responsive<number>;
30
- textAlign?: "center" | "start" | "end";
30
+ textAlign?: G.Responsive<TStyles.TextAlign>;
31
31
  backgroundColor?: "neutral" | "neutral-faded" | "critical" | "critical-faded" | "positive" | "warning" | "warning-faded" | "positive-faded" | "primary" | "primary-faded" | "elevation-base" | "elevation-raised" | "elevation-overlay" | "page" | "page-faded" | "disabled" | "disabled-faded" | "brand" | "white" | "black";
32
32
  borderColor?: G.Responsive<TStyles.BorderColor>;
33
33
  borderRadius?: G.Responsive<TStyles.Radius>;
@@ -359,6 +359,10 @@ export const textAlign = () => (<Example>
359
359
  <Example.Item title="textAlign: end">
360
360
  <View textAlign="end">Content</View>
361
361
  </Example.Item>
362
+
363
+ <Example.Item title="textAlign: [s] start, [m+] end">
364
+ <View textAlign={{ s: "start", m: "end" }}>Content</View>
365
+ </Example.Item>
362
366
  </Example>);
363
367
  export const size = () => (<Example>
364
368
  <Example.Item title="height: 100px, width: 100px">
@@ -1,3 +1,3 @@
1
1
  export declare const mouseEnter = 800;
2
- export declare const mouseEnterShort = 50;
2
+ export declare const mouseEnterShort = 100;
3
3
  export declare const mouseLeave = 150;
@@ -1,3 +1,3 @@
1
1
  export const mouseEnter = 800;
2
- export const mouseEnterShort = 50;
2
+ export const mouseEnterShort = 100;
3
3
  export const mouseLeave = 150;
@@ -50,8 +50,10 @@ export type TriggerAttributes = {
50
50
  ref: React.RefObject<HTMLButtonElement>;
51
51
  onBlur?: (e: React.FocusEvent) => void;
52
52
  onFocus?: () => void;
53
+ onMouseDown?: () => void;
53
54
  onMouseEnter?: () => void;
54
55
  onMouseLeave?: () => void;
56
+ onTouchStart?: () => void;
55
57
  onClick?: () => void;
56
58
  "aria-describedby"?: string;
57
59
  "aria-haspopup"?: "dialog" | "menu" | "listbox";
@@ -106,11 +108,13 @@ export type ContextProps = {
106
108
  handleOpen: () => void;
107
109
  handleMouseEnter: () => void;
108
110
  handleMouseLeave: () => void;
111
+ handleMouseDown: () => void;
109
112
  handleTransitionEnd: (e: React.TransitionEvent) => void;
110
113
  handleTransitionStart: (e: TransitionEvent) => void;
111
114
  handleClick: () => void;
112
115
  handleBlur: (e: React.FocusEvent) => void;
113
116
  handleFocus: () => void;
117
+ handleTouchStart: () => void;
114
118
  handleContentMouseDown: () => void;
115
119
  handleContentMouseUp: () => void;
116
120
  isSubmenu: boolean;
@@ -33,15 +33,26 @@ const FlyoutRoot = (props) => {
33
33
  */
34
34
  const triggerElRef = (!parentFlyoutContentContext && parentFlyoutTriggerContext?.triggerElRef) ||
35
35
  internalTriggerElRef;
36
+ const triggerBoundsRef = React.useRef();
36
37
  const flyoutElRef = React.useRef(null);
37
38
  const id = useElementId(passedId);
38
39
  const timerRef = React.useRef();
39
40
  const trapFocusRef = React.useRef(null);
40
41
  const lockedRef = React.useRef(false);
42
+ // Check if transition had enough time to start when opening a flyout
43
+ // In some cases there is not enough time to start, like when you're holding tab key
41
44
  const transitionStartedRef = React.useRef(false);
45
+ // Lock blur event while pressing anywhere inside the flyout content
42
46
  const lockedBlurEffects = React.useRef(false);
47
+ // Focus shouldn't retrun back to the trigger when user intentionally clicks outside the flyout
43
48
  const shouldReturnFocusRef = React.useRef(true);
44
- const flyout = useFlyout(triggerElRef, flyoutElRef, {
49
+ // Touch devices trigger onMouseEnter but we don't need to apply regular hover timeouts
50
+ // So we're saving a flag on touch start and then change the mouse enter behavior
51
+ const hoverTriggeredWithTouchEventRef = React.useRef(false);
52
+ const flyout = useFlyout({
53
+ triggerElRef,
54
+ flyoutElRef,
55
+ triggerBoundsRef,
45
56
  width,
46
57
  position: passedPosition,
47
58
  defaultActive: resolvedActive,
@@ -97,11 +108,22 @@ const FlyoutRoot = (props) => {
97
108
  return;
98
109
  handleOpen();
99
110
  }, [handleOpen, triggerType]);
111
+ const handleTouchStart = React.useCallback(() => {
112
+ if (triggerType !== "hover")
113
+ return;
114
+ hoverTriggeredWithTouchEventRef.current = true;
115
+ }, [triggerType]);
100
116
  const handleMouseEnter = React.useCallback(() => {
101
117
  clearTimer();
102
- timerRef.current = setTimeout(handleOpen, cooldown.timer || isSubmenu ? timeouts.mouseEnterShort : timeouts.mouseEnter);
103
- if (!isSubmenu && triggerType === "hover")
104
- cooldown.warm();
118
+ if (hoverTriggeredWithTouchEventRef.current) {
119
+ handleOpen();
120
+ hoverTriggeredWithTouchEventRef.current = false;
121
+ }
122
+ else {
123
+ timerRef.current = setTimeout(handleOpen, cooldown.timer || isSubmenu ? timeouts.mouseEnterShort : timeouts.mouseEnter);
124
+ if (!isSubmenu && triggerType === "hover")
125
+ cooldown.warm();
126
+ }
105
127
  }, [clearTimer, timerRef, handleOpen, isSubmenu, triggerType]);
106
128
  const handleMouseLeave = React.useCallback(() => {
107
129
  cooldown.cool();
@@ -116,8 +138,17 @@ const FlyoutRoot = (props) => {
116
138
  handleClose();
117
139
  }
118
140
  }, [status, handleOpen, handleClose]);
119
- const handleContentMouseDown = () => (lockedBlurEffects.current = true);
120
- const handleContentMouseUp = () => (lockedBlurEffects.current = false);
141
+ const handleTriggerMouseDown = React.useCallback(() => {
142
+ const rect = triggerElRef.current?.getBoundingClientRect();
143
+ triggerBoundsRef.current = rect;
144
+ }, [triggerElRef]);
145
+ const handleContentMouseDown = () => {
146
+ lockedBlurEffects.current = true;
147
+ hoverTriggeredWithTouchEventRef.current = true;
148
+ };
149
+ const handleContentMouseUp = () => {
150
+ lockedBlurEffects.current = false;
151
+ };
121
152
  const handleTransitionStart = React.useCallback((e) => {
122
153
  if (!resolvedActive)
123
154
  return;
@@ -251,8 +282,10 @@ const FlyoutRoot = (props) => {
251
282
  handleBlur,
252
283
  handleMouseEnter,
253
284
  handleMouseLeave,
285
+ handleTouchStart,
254
286
  handleTransitionStart,
255
287
  handleTransitionEnd,
288
+ handleMouseDown: handleTriggerMouseDown,
256
289
  handleClick: handleTriggerClick,
257
290
  handleContentMouseDown,
258
291
  handleContentMouseUp,
@@ -3,16 +3,18 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useFlyoutContext, TriggerProvider } from "./Flyout.context.js";
4
4
  const FlyoutTrigger = (props) => {
5
5
  const { children } = props;
6
- const { id, triggerElRef, triggerType, flyout, handleFocus, handleBlur, handleMouseEnter, handleMouseLeave, handleClick, trapFocusMode, isSubmenu, } = useFlyoutContext();
6
+ const { id, triggerElRef, triggerType, flyout, handleFocus, handleBlur, handleMouseEnter, handleMouseLeave, handleMouseDown, handleTouchStart, handleClick, trapFocusMode, isSubmenu, } = useFlyoutContext();
7
7
  let childrenAttributes = {
8
8
  ref: triggerElRef,
9
9
  };
10
10
  if (triggerType === "click" || trapFocusMode === "action-menu") {
11
11
  childrenAttributes.onClick = handleClick;
12
+ childrenAttributes.onMouseDown = handleMouseDown;
12
13
  }
13
14
  if (triggerType === "hover") {
14
15
  childrenAttributes.onMouseEnter = handleMouseEnter;
15
16
  childrenAttributes.onMouseLeave = handleMouseLeave;
17
+ childrenAttributes.onTouchStart = handleTouchStart;
16
18
  }
17
19
  // Submenus open on keypress instead of hover
18
20
  if ((triggerType === "hover" && !isSubmenu) || triggerType === "focus") {
@@ -11,7 +11,11 @@ type PassedFlyoutOptions = {
11
11
  forcePosition?: boolean;
12
12
  container?: HTMLElement | null;
13
13
  };
14
- type UseFlyout = (originRef: ElementRef, targetRef: ElementRef, options: PassedFlyoutOptions) => Pick<T.State, "styles" | "position" | "status"> & {
14
+ type UseFlyout = (args: PassedFlyoutOptions & {
15
+ triggerElRef: ElementRef;
16
+ flyoutElRef: ElementRef;
17
+ triggerBoundsRef: React.RefObject<DOMRect | undefined>;
18
+ }) => Pick<T.State, "styles" | "position" | "status"> & {
15
19
  updatePosition: (options?: {
16
20
  sync?: boolean;
17
21
  }) => void;
@@ -59,10 +59,11 @@ const resetStyles = {
59
59
  /**
60
60
  * Set position of the target element to fit on the screen
61
61
  */
62
- const flyout = (triggerEl, flyoutEl, options) => {
62
+ const flyout = (args) => {
63
+ const { triggerEl, flyoutEl, triggerBounds: passedTriggerBounds, ...options } = args;
63
64
  const { position, forcePosition, width, container } = options;
64
65
  const targetClone = flyoutEl.cloneNode(true);
65
- const triggerBounds = triggerEl.getBoundingClientRect();
66
+ const triggerBounds = passedTriggerBounds || triggerEl.getBoundingClientRect();
66
67
  // Reset all styles applied on the previous hook execution
67
68
  targetClone.style = "";
68
69
  Object.keys(resetStyles).forEach((key) => {
@@ -155,7 +156,8 @@ const flyoutReducer = (state, action) => {
155
156
  throw new Error("Invalid reducer type");
156
157
  }
157
158
  };
158
- const useFlyout = (originRef, targetRef, options) => {
159
+ const useFlyout = (args) => {
160
+ const { triggerElRef, flyoutElRef, triggerBoundsRef, ...options } = args;
159
161
  const { position: defaultPosition = "bottom", forcePosition, width, container } = options;
160
162
  const [isRTL] = useRTL();
161
163
  const [state, dispatch] = React.useReducer(flyoutReducer, {
@@ -176,9 +178,12 @@ const useFlyout = (originRef, targetRef, options) => {
176
178
  dispatch({ type: "remove" });
177
179
  }, []);
178
180
  const updatePosition = React.useCallback((options) => {
179
- if (!originRef.current || !targetRef.current)
181
+ if (!triggerElRef.current || !flyoutElRef.current)
180
182
  return;
181
- const nextFlyoutData = flyout(originRef.current, targetRef.current, {
183
+ const nextFlyoutData = flyout({
184
+ triggerEl: triggerElRef.current,
185
+ flyoutEl: flyoutElRef.current,
186
+ triggerBounds: triggerBoundsRef.current,
182
187
  width,
183
188
  position: defaultPosition,
184
189
  forcePosition,
@@ -187,7 +192,16 @@ const useFlyout = (originRef, targetRef, options) => {
187
192
  });
188
193
  if (nextFlyoutData)
189
194
  dispatch({ type: "position", payload: { ...nextFlyoutData, sync: options?.sync } });
190
- }, [container, defaultPosition, forcePosition, isRTL, originRef, targetRef, width]);
195
+ }, [
196
+ container,
197
+ defaultPosition,
198
+ forcePosition,
199
+ isRTL,
200
+ flyoutElRef,
201
+ triggerElRef,
202
+ triggerBoundsRef,
203
+ width,
204
+ ]);
191
205
  React.useEffect(() => {
192
206
  if (state.status === "rendered")
193
207
  updatePosition();
@@ -0,0 +1,3 @@
1
+ import * as T from "../types";
2
+ declare const getTextAlignStyles: T.StaticStyleUtility<T.TextAlign>;
3
+ export default getTextAlignStyles;
@@ -0,0 +1,10 @@
1
+ import { responsiveClassNames } from "../../utilities/helpers.js";
2
+ import s from "./textAlign.module.css";
3
+ const getTextAlignStyles = (value) => {
4
+ if (!value)
5
+ return null;
6
+ return {
7
+ classNames: [...responsiveClassNames(s, "--text-align", value)],
8
+ };
9
+ };
10
+ export default getTextAlignStyles;
@@ -0,0 +1 @@
1
+ .--text-align-start{text-align:start}.--text-align-center{text-align:center}.--text-align-end{text-align:end}@media (--rs-viewport-m ){.--text-align-start--m{text-align:start}.--text-align-center--m{text-align:center}.--text-align-end--m{text-align:end}}@media (--rs-viewport-l ){.--text-align-start--l{text-align:start}.--text-align-center--l{text-align:center}.--text-align-end--l{text-align:end}}@media (--rs-viewport-xl ){.--text-align-start--xl{text-align:start}.--text-align-center--xl{text-align:center}.--text-align-end--xl{text-align:end}}
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import * as G from "../types/global";
3
+ export type TextAlign = "start" | "center" | "end";
3
4
  export type Radius = "small" | "medium" | "large" | "circular" | "none";
4
5
  export type Position = "relative" | "absolute" | "fixed" | "sticky" | "static";
5
6
  export type BorderColor = "neutral" | "neutral-faded" | "critical" | "critical-faded" | "warning" | "warning-faded" | "positive" | "positive-faded" | "primary" | "primary-faded" | "disabled" | "brand" | "transparent";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "reshaped",
3
3
  "description": "Professionally crafted design system in React & Figma for building products of any scale and complexity",
4
- "version": "3.1.1",
4
+ "version": "3.1.3",
5
5
  "license": "MIT",
6
6
  "email": "hello@reshaped.so",
7
7
  "homepage": "https://reshaped.so",
@@ -122,7 +122,7 @@
122
122
  "eslint-config-airbnb-typescript": "17.1.0",
123
123
  "eslint-config-prettier": "9.1.0",
124
124
  "eslint-plugin-import": "2.29.1",
125
- "eslint-plugin-jsx-a11y": "6.8.0",
125
+ "eslint-plugin-jsx-a11y": "6.9.0",
126
126
  "eslint-plugin-prettier": "5.1.3",
127
127
  "eslint-plugin-react": "7.33.2",
128
128
  "eslint-plugin-react-hooks": "4.6.0",