raft-ui 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -6,7 +6,11 @@ React UI components for rui, styled with Tailwind CSS v4.
6
6
 
7
7
  ```tsx
8
8
  import { Button } from "raft-ui";
9
- import "raft-ui/styles.css";
9
+ ```
10
+
11
+ ```css
12
+ @import "tailwindcss";
13
+ @import "raft-ui/styles.css";
10
14
  ```
11
15
 
12
16
  ## Development
package/dist/index.d.mts CHANGED
@@ -751,6 +751,74 @@ declare function DropdownMenuCheckboxItemIndicator({
751
751
  }: DropdownMenuCheckboxItemIndicatorProps): import("react").JSX.Element;
752
752
  //#endregion
753
753
  //#region src/components/tooltip/tooltip.d.ts
754
+ declare const tooltip: import("tailwind-variants/lite").TVReturnType<{
755
+ theme: {
756
+ brutal: {
757
+ content: string[];
758
+ arrow: string[];
759
+ };
760
+ elegant: {
761
+ content: string[];
762
+ arrow: never[];
763
+ };
764
+ };
765
+ variant: {
766
+ default: {};
767
+ inverse: {
768
+ content: string[];
769
+ };
770
+ };
771
+ }, {
772
+ trigger: string[];
773
+ positioner: string[];
774
+ content: string[];
775
+ arrow: string[];
776
+ }, undefined, {
777
+ theme: {
778
+ brutal: {
779
+ content: string[];
780
+ arrow: string[];
781
+ };
782
+ elegant: {
783
+ content: string[];
784
+ arrow: never[];
785
+ };
786
+ };
787
+ variant: {
788
+ default: {};
789
+ inverse: {
790
+ content: string[];
791
+ };
792
+ };
793
+ }, {
794
+ trigger: string[];
795
+ positioner: string[];
796
+ content: string[];
797
+ arrow: string[];
798
+ }, import("tailwind-variants/lite").TVReturnType<{
799
+ theme: {
800
+ brutal: {
801
+ content: string[];
802
+ arrow: string[];
803
+ };
804
+ elegant: {
805
+ content: string[];
806
+ arrow: never[];
807
+ };
808
+ };
809
+ variant: {
810
+ default: {};
811
+ inverse: {
812
+ content: string[];
813
+ };
814
+ };
815
+ }, {
816
+ trigger: string[];
817
+ positioner: string[];
818
+ content: string[];
819
+ arrow: string[];
820
+ }, undefined, unknown, unknown, undefined>>;
821
+ type TooltipStyleProps = VariantProps<typeof tooltip>;
754
822
  type TooltipProviderProps = Tooltip$1.Provider.Props;
755
823
  declare function TooltipProvider({
756
824
  delay,
@@ -767,7 +835,7 @@ type TooltipPortalProps = Tooltip$1.Portal.Props;
767
835
  declare function TooltipPortal(props: TooltipPortalProps): import("react").JSX.Element;
768
836
  type TooltipContentProps = StyledProps<Tooltip$1.Popup.Props> & Pick<Tooltip$1.Positioner.Props, "align" | "alignOffset" | "anchor" | "arrowPadding" | "collisionAvoidance" | "collisionBoundary" | "collisionPadding" | "disableAnchorTracking" | "positionMethod" | "side" | "sideOffset" | "sticky"> & {
769
837
  portalProps?: TooltipPortalProps;
770
- };
838
+ } & Pick<TooltipStyleProps, "variant">;
771
839
  declare function TooltipContent({
772
840
  align,
773
841
  alignOffset,
@@ -782,6 +850,7 @@ declare function TooltipContent({
782
850
  sideOffset,
783
851
  sticky,
784
852
  portalProps,
853
+ variant,
785
854
  className,
786
855
  children,
787
856
  ...props
@@ -1871,6 +1940,7 @@ declare const heading: import("tailwind-variants/lite").TVReturnType<{
1871
1940
  primary: string[];
1872
1941
  information: string[];
1873
1942
  muted: string[];
1943
+ placeholder: string[];
1874
1944
  accent: string[];
1875
1945
  success: string[];
1876
1946
  warning: string[];
@@ -1890,6 +1960,7 @@ declare const heading: import("tailwind-variants/lite").TVReturnType<{
1890
1960
  primary: string[];
1891
1961
  information: string[];
1892
1962
  muted: string[];
1963
+ placeholder: string[];
1893
1964
  accent: string[];
1894
1965
  success: string[];
1895
1966
  warning: string[];
@@ -1909,6 +1980,7 @@ declare const heading: import("tailwind-variants/lite").TVReturnType<{
1909
1980
  primary: string[];
1910
1981
  information: string[];
1911
1982
  muted: string[];
1983
+ placeholder: string[];
1912
1984
  accent: string[];
1913
1985
  success: string[];
1914
1986
  warning: string[];
@@ -1927,6 +1999,7 @@ declare const sans: import("tailwind-variants/lite").TVReturnType<{
1927
1999
  primary: string[];
1928
2000
  information: string[];
1929
2001
  muted: string[];
2002
+ placeholder: string[];
1930
2003
  accent: string[];
1931
2004
  success: string[];
1932
2005
  warning: string[];
@@ -1944,6 +2017,7 @@ declare const sans: import("tailwind-variants/lite").TVReturnType<{
1944
2017
  primary: string[];
1945
2018
  information: string[];
1946
2019
  muted: string[];
2020
+ placeholder: string[];
1947
2021
  accent: string[];
1948
2022
  success: string[];
1949
2023
  warning: string[];
@@ -1961,6 +2035,7 @@ declare const sans: import("tailwind-variants/lite").TVReturnType<{
1961
2035
  primary: string[];
1962
2036
  information: string[];
1963
2037
  muted: string[];
2038
+ placeholder: string[];
1964
2039
  accent: string[];
1965
2040
  success: string[];
1966
2041
  warning: string[];
@@ -1979,6 +2054,7 @@ declare const mono: import("tailwind-variants/lite").TVReturnType<{
1979
2054
  primary: string[];
1980
2055
  information: string[];
1981
2056
  muted: string[];
2057
+ placeholder: string[];
1982
2058
  accent: string[];
1983
2059
  success: string[];
1984
2060
  warning: string[];
@@ -1996,6 +2072,7 @@ declare const mono: import("tailwind-variants/lite").TVReturnType<{
1996
2072
  primary: string[];
1997
2073
  information: string[];
1998
2074
  muted: string[];
2075
+ placeholder: string[];
1999
2076
  accent: string[];
2000
2077
  success: string[];
2001
2078
  warning: string[];
@@ -2013,6 +2090,7 @@ declare const mono: import("tailwind-variants/lite").TVReturnType<{
2013
2090
  primary: string[];
2014
2091
  information: string[];
2015
2092
  muted: string[];
2093
+ placeholder: string[];
2016
2094
  accent: string[];
2017
2095
  success: string[];
2018
2096
  warning: string[];
package/dist/index.mjs CHANGED
@@ -1621,7 +1621,7 @@ const dropdownMenu = tv({
1621
1621
  submenuTrigger: ["flex w-full cursor-default select-none items-center gap-2 px-3 py-2 [@media(max-height:600px)]:py-1", "text-left text-sm outline-none transition-colors"],
1622
1622
  label: [],
1623
1623
  shortcut: ["ml-auto"],
1624
- itemCount: ["ml-auto tabular-nums"],
1624
+ itemCount: ["ml-auto inline-flex min-w-5 justify-center gap-0 px-1 tabular-nums"],
1625
1625
  separator: ["border-t-2"],
1626
1626
  indicator: ["pointer-events-none ml-auto flex size-3 shrink-0 items-center justify-center"]
1627
1627
  },
@@ -1648,7 +1648,7 @@ const dropdownMenu = tv({
1648
1648
  ],
1649
1649
  label: ["border-b border-black px-3 py-2", "font-sans text-[10px] font-bold uppercase leading-none tracking-wide text-black/60"],
1650
1650
  shortcut: ["font-sans text-sm font-semibold leading-6"],
1651
- itemCount: ["rounded border border-black bg-brutal-pink px-1.5 py-0.5", "font-sans text-[10px] leading-none font-bold text-white"],
1651
+ itemCount: ["rounded border border-black bg-brutal-pink px-1 py-0.5", "font-sans text-[10px] leading-none font-bold text-white"],
1652
1652
  separator: ["border-black"],
1653
1653
  indicator: []
1654
1654
  },
@@ -1883,8 +1883,8 @@ const tooltip = tv({
1883
1883
  trigger: ["select-none"],
1884
1884
  positioner: ["isolate z-50 outline-none"],
1885
1885
  content: [
1886
- "relative inline-flex max-w-xs items-center gap-1.5 px-2.5 py-1.5",
1887
- "text-xs leading-4 whitespace-normal",
1886
+ "relative inline-flex max-w-xs items-center gap-1.5 px-3 py-2",
1887
+ "text-[13px] leading-[18px] whitespace-normal",
1888
1888
  "origin-[var(--transform-origin)] outline-none",
1889
1889
  "transition-[opacity,transform] duration-100",
1890
1890
  "data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
@@ -1906,26 +1906,37 @@ const tooltip = tv({
1906
1906
  "data-[side=inline-end]:left-[-8px] data-[side=inline-end]:rotate-90"
1907
1907
  ]
1908
1908
  },
1909
- variants: { theme: {
1910
- brutal: {
1911
- content: [
1912
- "border-2 border-black bg-white",
1913
- "font-sans font-bold text-black",
1914
- "shadow-none",
1915
- "[&_[data-slot=kbd]]:text-black/60"
1916
- ],
1917
- arrow: ["hidden"]
1909
+ variants: {
1910
+ theme: {
1911
+ brutal: {
1912
+ content: [
1913
+ "border-2 border-black bg-white",
1914
+ "font-sans font-bold text-black",
1915
+ "shadow-none",
1916
+ "[&_[data-slot=kbd]]:text-black/60"
1917
+ ],
1918
+ arrow: ["hidden"]
1919
+ },
1920
+ elegant: {
1921
+ content: [
1922
+ "rounded-md bg-layer-popover",
1923
+ "font-sans text-[13px] font-medium tracking-[-0.005em] text-foreground-strong",
1924
+ "shadow-[0_0_0_1px_oklch(0.21_0.006_285_/_0.10),0_1px_1px_oklch(0.21_0.006_285_/_0.04),0_1px_4px_-3px_oklch(0.21_0.006_285_/_0.10)]",
1925
+ "[&_[data-slot=kbd]]:bg-foreground-muted/10 [&_[data-slot=kbd]]:text-foreground-muted [&_[data-slot=kbd]]:ring-0"
1926
+ ],
1927
+ arrow: []
1928
+ }
1918
1929
  },
1919
- elegant: {
1920
- content: [
1921
- "rounded-md bg-layer-popover",
1922
- "font-sans text-xs font-medium tracking-[-0.005em] text-foreground-strong",
1923
- "shadow-[0_0_0_1px_oklch(0.21_0.006_285_/_0.10),0_1px_1px_oklch(0.21_0.006_285_/_0.04),0_1px_4px_-3px_oklch(0.21_0.006_285_/_0.10)]",
1924
- "[&_[data-slot=kbd]]:bg-foreground-muted/10 [&_[data-slot=kbd]]:text-foreground-muted [&_[data-slot=kbd]]:ring-0"
1925
- ],
1926
- arrow: []
1930
+ variant: {
1931
+ default: {},
1932
+ inverse: { content: [
1933
+ "bg-foreground-strong text-foreground-inverse",
1934
+ "!shadow-[0_12px_24px_0_oklch(0.21_0.006_285_/_0.045),0_1px_2px_0_oklch(0.21_0.006_285_/_0.035)]",
1935
+ "[&_[data-slot=kbd]]:bg-white/10 [&_[data-slot=kbd]]:text-foreground-inverse [&_[data-slot=kbd]]:ring-0"
1936
+ ] }
1927
1937
  }
1928
- } }
1938
+ },
1939
+ defaultVariants: { variant: "default" }
1929
1940
  });
1930
1941
  function TooltipProvider({ delay = 0, ...props }) {
1931
1942
  return /* @__PURE__ */ jsx(Tooltip$1.Provider, {
@@ -1950,16 +1961,20 @@ function TooltipPortal(props) {
1950
1961
  ...props
1951
1962
  });
1952
1963
  }
1953
- function TooltipArrow({ className, ...props }) {
1954
- const { arrow } = tooltip({ theme: useThemeFamily() });
1964
+ function TooltipArrow({ className, variant, ...props }) {
1965
+ const { arrow } = tooltip({
1966
+ theme: useThemeFamily(),
1967
+ variant
1968
+ });
1955
1969
  return /* @__PURE__ */ jsx(Tooltip$1.Arrow, {
1956
1970
  "data-slot": "tooltip-arrow",
1957
1971
  className: arrow({ className }),
1958
1972
  ...props,
1959
- children: /* @__PURE__ */ jsx(TooltipArrowSvg, {})
1973
+ children: /* @__PURE__ */ jsx(TooltipArrowSvg, { variant })
1960
1974
  });
1961
1975
  }
1962
- function TooltipArrowSvg(props) {
1976
+ function TooltipArrowSvg({ variant, ...props }) {
1977
+ const isInverse = variant === "inverse";
1963
1978
  return /* @__PURE__ */ jsxs("svg", {
1964
1979
  width: "12",
1965
1980
  height: "6",
@@ -1968,18 +1983,21 @@ function TooltipArrowSvg(props) {
1968
1983
  ...props,
1969
1984
  children: [/* @__PURE__ */ jsx("path", {
1970
1985
  d: "M1 0H11L6 5.25Z",
1971
- className: "fill-layer-popover"
1986
+ className: isInverse ? "fill-foreground-strong" : "fill-layer-popover"
1972
1987
  }), /* @__PURE__ */ jsx("path", {
1973
1988
  d: "M1 0.5L6 5.25L11 0.5",
1974
- className: "stroke-[oklch(0.21_0.006_285_/_0.10)]",
1989
+ className: isInverse ? "stroke-[oklch(0_0_0_/_0.18)]" : "stroke-[oklch(0.21_0.006_285_/_0.10)]",
1975
1990
  strokeLinecap: "round",
1976
1991
  strokeLinejoin: "round",
1977
1992
  vectorEffect: "non-scaling-stroke"
1978
1993
  })]
1979
1994
  });
1980
1995
  }
1981
- function TooltipContent({ align = "center", alignOffset = 0, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking = false, positionMethod = "fixed", side = "top", sideOffset = 6, sticky, portalProps, className, children, ...props }) {
1982
- const { positioner, content } = tooltip({ theme: useThemeFamily() });
1996
+ function TooltipContent({ align = "center", alignOffset = 0, anchor, arrowPadding, collisionAvoidance, collisionBoundary, collisionPadding, disableAnchorTracking = false, positionMethod = "fixed", side = "top", sideOffset = 6, sticky, portalProps, variant, className, children, ...props }) {
1997
+ const { positioner, content } = tooltip({
1998
+ theme: useThemeFamily(),
1999
+ variant
2000
+ });
1983
2001
  return /* @__PURE__ */ jsx(Tooltip$1.Portal, {
1984
2002
  ...portalProps,
1985
2003
  children: /* @__PURE__ */ jsx(Tooltip$1.Positioner, {
@@ -2000,7 +2018,7 @@ function TooltipContent({ align = "center", alignOffset = 0, anchor, arrowPaddin
2000
2018
  "data-slot": "tooltip-content",
2001
2019
  className: content({ className }),
2002
2020
  ...props,
2003
- children: [children, /* @__PURE__ */ jsx(TooltipArrow, {})]
2021
+ children: [children, /* @__PURE__ */ jsx(TooltipArrow, { variant })]
2004
2022
  })
2005
2023
  })
2006
2024
  });
@@ -3813,12 +3831,11 @@ function AvatarGroupCount({ size, className, ...props }) {
3813
3831
  const inlineCode = tv({
3814
3832
  slots: { root: [] },
3815
3833
  variants: { theme: {
3816
- brutal: { root: "border border-black bg-brutal-yellow/40 px-1 text-sm font-mono text-black [overflow-wrap:anywhere]" },
3834
+ brutal: { root: ["border border-black bg-brutal-yellow/50 px-1.5", "font-mono text-sm font-medium text-black [overflow-wrap:anywhere]"] },
3817
3835
  elegant: { root: [
3818
- "inline-flex items-center rounded px-2 py-0.5",
3819
- "font-mono text-xs font-medium",
3820
- "bg-layer-muted text-[oklch(0.38_0_0)] dark:text-[oklch(0.78_0_0)]",
3821
- "shadow-[0_0.5px_0.5px_-0.5px_oklch(0_0_0_/_0.08)]"
3836
+ "inline-flex items-center rounded-md px-2.5 py-0.5",
3837
+ "font-mono text-sm font-medium",
3838
+ "bg-[oklch(0.955_0_0)] text-[oklch(0.44_0_0)] dark:bg-[oklch(0.24_0.006_286)] dark:text-[oklch(0.78_0_0)]"
3822
3839
  ] }
3823
3840
  } }
3824
3841
  });
@@ -3837,6 +3854,7 @@ const textColorVariants = {
3837
3854
  primary: ["text-primary-700"],
3838
3855
  information: ["text-info-dark"],
3839
3856
  muted: ["text-foreground-muted"],
3857
+ placeholder: ["text-foreground-placeholder"],
3840
3858
  accent: ["text-accent-700"],
3841
3859
  success: ["text-success-base"],
3842
3860
  warning: ["text-warning-base"],
@@ -4716,7 +4734,11 @@ const tabs = tv({
4716
4734
  variants: {
4717
4735
  theme: {
4718
4736
  brutal: {
4719
- list: ["flex w-max max-w-full overflow-x-auto border-2 border-line-strong bg-layer-panel", "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden"],
4737
+ list: [
4738
+ "flex w-max max-w-full overflow-x-auto border-2 border-line-strong bg-layer-panel",
4739
+ "data-[sorting=true]:[overflow-x:hidden]",
4740
+ "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
4741
+ ],
4720
4742
  background: "hidden",
4721
4743
  tab: [
4722
4744
  "bg-layer-panel px-4 py-1.5 text-xs font-semibold transition-colors",
@@ -4745,6 +4767,8 @@ const tabs = tv({
4745
4767
  "group/tabs-list relative flex h-12 w-max max-w-full items-center gap-6 px-4",
4746
4768
  "overflow-x-auto overflow-y-hidden overscroll-contain whitespace-nowrap",
4747
4769
  "border-b border-line-muted",
4770
+ "data-[sorting=true]:[overflow-x:hidden]",
4771
+ "data-[sorting=true]:[&_[data-slot=tabs-indicator]]:opacity-0 data-[sorting=true]:[&_[data-slot=tabs-indicator]]:transition-none",
4748
4772
  "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
4749
4773
  ],
4750
4774
  background: ["pointer-events-none absolute inset-x-0 top-0 z-0 h-px bg-line-muted"],
@@ -4777,6 +4801,8 @@ const tabs = tv({
4777
4801
  "group/tabs-list relative isolate flex h-auto w-max max-w-full items-center gap-1",
4778
4802
  "overflow-x-auto overflow-y-visible overscroll-contain whitespace-nowrap",
4779
4803
  "p-px",
4804
+ "data-[sorting=true]:[overflow-x:hidden]",
4805
+ "data-[sorting=true]:[&_[data-slot=tabs-indicator]]:opacity-0 data-[sorting=true]:[&_[data-slot=tabs-indicator]]:transition-none",
4780
4806
  "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
4781
4807
  ],
4782
4808
  background: ["pointer-events-none absolute inset-0 z-0 rounded-[7px] bg-layer-muted"],
@@ -4788,6 +4814,11 @@ const tabs = tv({
4788
4814
  "data-[active]:text-[oklch(38%_.006_285)]",
4789
4815
  "data-[active]:hover:text-[oklch(38%_.006_285)]",
4790
4816
  "data-[active]:[&_[data-slot=tabs-label]]:text-[0.8125rem]",
4817
+ "data-[reorderable=true]:data-[active]:bg-layer-panel",
4818
+ "data-[reorderable=true]:data-[active]:shadow-[0_0_0_1px_oklch(0%_0_0/.1),0_1px_1px_-1px_oklch(0%_0_0/.04),0_1px_2px_oklch(0%_0_0/.03)]",
4819
+ "group-has-[>[data-slot=tabs-background]]/tabs-list:data-[reorderable=true]:data-[active]:shadow-[0_0_0_1px_oklch(0%_0_0/.045),0_1px_1px_-1px_oklch(0%_0_0/.025),0_1px_2px_oklch(0%_0_0/.02)]",
4820
+ "data-[dragging-active=true]:bg-layer-panel",
4821
+ "data-[dragging-active=true]:shadow-[0_0_0_1px_oklch(0%_0_0/.1),0_1px_1px_-1px_oklch(0%_0_0/.04),0_1px_2px_oklch(0%_0_0/.03)]",
4791
4822
  "[&_svg]:pointer-events-none [&_svg]:size-3.5 [&_svg]:shrink-0 [&_svg]:[stroke-width:1.5]",
4792
4823
  "[&_svg]:text-foreground-placeholder [&_svg]:transition-colors [&_svg]:duration-150 [&_svg]:ease-out",
4793
4824
  "hover:[&_svg]:text-[oklch(42%_.006_285)]",
@@ -4809,7 +4840,6 @@ const tabs = tv({
4809
4840
  const TabsReorderContext = createContext({ enabled: false });
4810
4841
  const TabsValueContext = createContext(void 0);
4811
4842
  const TabsListVariantContext = createContext("default");
4812
- const REORDER_ENABLED_CONTEXT = { enabled: true };
4813
4843
  function Tabs({ value, defaultValue, onValueChange, className, ...props }) {
4814
4844
  const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
4815
4845
  const resolvedValue = value ?? uncontrolledValue;
@@ -4833,6 +4863,7 @@ function Tabs({ value, defaultValue, onValueChange, className, ...props }) {
4833
4863
  }
4834
4864
  function TabsList({ className, children, variant = "default", ...props }) {
4835
4865
  const theme = useThemeFamily();
4866
+ const reorder = use(TabsReorderContext);
4836
4867
  const resolvedVariant = theme === "elegant" ? variant : "underline";
4837
4868
  const { list } = tabs({
4838
4869
  theme,
@@ -4845,20 +4876,33 @@ function TabsList({ className, children, variant = "default", ...props }) {
4845
4876
  "data-variant": resolvedVariant,
4846
4877
  className: list({ className }),
4847
4878
  ...props,
4848
- children: [children, theme === "elegant" ? /* @__PURE__ */ jsx(TabsIndicator, {}) : null]
4879
+ children: [children, theme === "elegant" && !reorder.enabled ? /* @__PURE__ */ jsx(TabsIndicator, {}) : null]
4849
4880
  })
4850
4881
  });
4851
4882
  }
4852
4883
  function SortableTabsList({ value, onReorder, children, variant = "default", ...props }) {
4884
+ const [activeId, setActiveId] = useState(void 0);
4853
4885
  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 6 } }), useSensor(TouchSensor, { activationConstraint: {
4854
4886
  delay: 350,
4855
4887
  tolerance: 8
4856
4888
  } }));
4857
4889
  const tabIds = useMemo(() => value.map(String), [value]);
4890
+ const reorderContext = useMemo(() => ({
4891
+ enabled: true,
4892
+ activeId
4893
+ }), [activeId]);
4858
4894
  return /* @__PURE__ */ jsx(DndContext, {
4895
+ autoScroll: false,
4859
4896
  sensors,
4860
4897
  collisionDetection: closestCenter,
4898
+ onDragStart: useCallback(({ active }) => {
4899
+ setActiveId(String(active.id));
4900
+ }, []),
4901
+ onDragCancel: useCallback(() => {
4902
+ setActiveId(void 0);
4903
+ }, []),
4861
4904
  onDragEnd: useCallback(({ active, over }) => {
4905
+ setActiveId(void 0);
4862
4906
  if (!over || active.id === over.id) return;
4863
4907
  const oldIndex = tabIds.indexOf(String(active.id));
4864
4908
  const newIndex = tabIds.indexOf(String(over.id));
@@ -4873,10 +4917,11 @@ function SortableTabsList({ value, onReorder, children, variant = "default", ...
4873
4917
  items: tabIds,
4874
4918
  strategy: horizontalListSortingStrategy,
4875
4919
  children: /* @__PURE__ */ jsx(TabsReorderContext.Provider, {
4876
- value: REORDER_ENABLED_CONTEXT,
4920
+ value: reorderContext,
4877
4921
  children: /* @__PURE__ */ jsx(TabsList, {
4878
4922
  variant,
4879
4923
  ...props,
4924
+ "data-sorting": activeId ? "true" : void 0,
4880
4925
  children
4881
4926
  })
4882
4927
  })
@@ -4891,10 +4936,12 @@ function TabsTab({ value, ...props }) {
4891
4936
  }
4892
4937
  function SortableTabsTab({ value, ...props }) {
4893
4938
  const reorder = use(TabsReorderContext);
4939
+ const activeValue = use(TabsValueContext);
4894
4940
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
4895
4941
  id: value,
4896
4942
  disabled: !reorder.enabled
4897
4943
  });
4944
+ const isDraggingActive = isDragging && activeValue === String(value);
4898
4945
  if (!reorder.enabled) return /* @__PURE__ */ jsx(TabsTabButton, {
4899
4946
  value,
4900
4947
  ...props
@@ -4910,10 +4957,11 @@ function SortableTabsTab({ value, ...props }) {
4910
4957
  return /* @__PURE__ */ jsx(TabsTabButton, {
4911
4958
  value,
4912
4959
  sortableRef: setNodeRef,
4960
+ ...props,
4961
+ "data-dragging-active": isDraggingActive ? "true" : void 0,
4913
4962
  "data-dragging-source": isDragging ? "true" : void 0,
4914
4963
  "data-reorderable": "true",
4915
4964
  style,
4916
- ...props,
4917
4965
  ...sortableAttributes,
4918
4966
  ...listeners
4919
4967
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "raft-ui",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "React UI components for Raft.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -40,8 +40,6 @@
40
40
  "@dnd-kit/core": "^6.3.1",
41
41
  "@dnd-kit/sortable": "^10.0.0",
42
42
  "@dnd-kit/utilities": "^3.2.2",
43
- "@fontsource-variable/geist-mono": "^5.2.8",
44
- "@fontsource-variable/space-grotesk": "^5.2.10",
45
43
  "@tanstack/react-hotkeys": "^0.10.0",
46
44
  "cnfast": "^0.0.7",
47
45
  "lucide-react": "^1.21.0",
@@ -28,7 +28,7 @@ const dropdownMenu = tv({
28
28
  ],
29
29
  label: [],
30
30
  shortcut: ["ml-auto"],
31
- itemCount: ["ml-auto tabular-nums"],
31
+ itemCount: ["ml-auto inline-flex min-w-5 justify-center gap-0 px-1 tabular-nums"],
32
32
  separator: ["border-t-2"],
33
33
  indicator: ["pointer-events-none ml-auto flex size-3 shrink-0 items-center justify-center"],
34
34
  },
@@ -63,7 +63,7 @@ const dropdownMenu = tv({
63
63
  ],
64
64
  shortcut: ["font-sans text-sm font-semibold leading-6"],
65
65
  itemCount: [
66
- "rounded border border-black bg-brutal-pink px-1.5 py-0.5",
66
+ "rounded border border-black bg-brutal-pink px-1 py-0.5",
67
67
  "font-sans text-[10px] leading-none font-bold text-white",
68
68
  ],
69
69
  separator: ["border-black"],
@@ -9,14 +9,16 @@ const inlineCode = tv({
9
9
  variants: {
10
10
  theme: {
11
11
  brutal: {
12
- root: "border border-black bg-brutal-yellow/40 px-1 text-sm font-mono text-black [overflow-wrap:anywhere]",
12
+ root: [
13
+ "border border-black bg-brutal-yellow/50 px-1.5",
14
+ "font-mono text-sm font-medium text-black [overflow-wrap:anywhere]",
15
+ ],
13
16
  },
14
17
  elegant: {
15
18
  root: [
16
- "inline-flex items-center rounded px-2 py-0.5",
17
- "font-mono text-xs font-medium",
18
- "bg-layer-muted text-[oklch(0.38_0_0)] dark:text-[oklch(0.78_0_0)]",
19
- "shadow-[0_0.5px_0.5px_-0.5px_oklch(0_0_0_/_0.08)]",
19
+ "inline-flex items-center rounded-md px-2.5 py-0.5",
20
+ "font-mono text-sm font-medium",
21
+ "bg-[oklch(0.955_0_0)] text-[oklch(0.44_0_0)] dark:bg-[oklch(0.24_0.006_286)] dark:text-[oklch(0.78_0_0)]",
20
22
  ],
21
23
  },
22
24
  },
@@ -16,6 +16,7 @@ import {
16
16
  useSensor,
17
17
  useSensors,
18
18
  type DragEndEvent,
19
+ type DragStartEvent,
19
20
  } from "@dnd-kit/core";
20
21
  import {
21
22
  arrayMove,
@@ -46,6 +47,7 @@ const tabs = tv({
46
47
  brutal: {
47
48
  list: [
48
49
  "flex w-max max-w-full overflow-x-auto border-2 border-line-strong bg-layer-panel",
50
+ "data-[sorting=true]:[overflow-x:hidden]",
49
51
  "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
50
52
  ],
51
53
  background: "hidden",
@@ -79,6 +81,8 @@ const tabs = tv({
79
81
  "group/tabs-list relative flex h-12 w-max max-w-full items-center gap-6 px-4",
80
82
  "overflow-x-auto overflow-y-hidden overscroll-contain whitespace-nowrap",
81
83
  "border-b border-line-muted",
84
+ "data-[sorting=true]:[overflow-x:hidden]",
85
+ "data-[sorting=true]:[&_[data-slot=tabs-indicator]]:opacity-0 data-[sorting=true]:[&_[data-slot=tabs-indicator]]:transition-none",
82
86
  "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
83
87
  ],
84
88
  background: ["pointer-events-none absolute inset-x-0 top-0 z-0 h-px bg-line-muted"],
@@ -112,6 +116,8 @@ const tabs = tv({
112
116
  "group/tabs-list relative isolate flex h-auto w-max max-w-full items-center gap-1",
113
117
  "overflow-x-auto overflow-y-visible overscroll-contain whitespace-nowrap",
114
118
  "p-px",
119
+ "data-[sorting=true]:[overflow-x:hidden]",
120
+ "data-[sorting=true]:[&_[data-slot=tabs-indicator]]:opacity-0 data-[sorting=true]:[&_[data-slot=tabs-indicator]]:transition-none",
115
121
  "[scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
116
122
  ],
117
123
  background: ["pointer-events-none absolute inset-0 z-0 rounded-[7px] bg-layer-muted"],
@@ -123,6 +129,11 @@ const tabs = tv({
123
129
  "data-[active]:text-[oklch(38%_.006_285)]",
124
130
  "data-[active]:hover:text-[oklch(38%_.006_285)]",
125
131
  "data-[active]:[&_[data-slot=tabs-label]]:text-[0.8125rem]",
132
+ "data-[reorderable=true]:data-[active]:bg-layer-panel",
133
+ "data-[reorderable=true]:data-[active]:shadow-[0_0_0_1px_oklch(0%_0_0/.1),0_1px_1px_-1px_oklch(0%_0_0/.04),0_1px_2px_oklch(0%_0_0/.03)]",
134
+ "group-has-[>[data-slot=tabs-background]]/tabs-list:data-[reorderable=true]:data-[active]:shadow-[0_0_0_1px_oklch(0%_0_0/.045),0_1px_1px_-1px_oklch(0%_0_0/.025),0_1px_2px_oklch(0%_0_0/.02)]",
135
+ "data-[dragging-active=true]:bg-layer-panel",
136
+ "data-[dragging-active=true]:shadow-[0_0_0_1px_oklch(0%_0_0/.1),0_1px_1px_-1px_oklch(0%_0_0/.04),0_1px_2px_oklch(0%_0_0/.03)]",
126
137
  "[&_svg]:pointer-events-none [&_svg]:size-3.5 [&_svg]:shrink-0 [&_svg]:[stroke-width:1.5]",
127
138
  "[&_svg]:text-foreground-placeholder [&_svg]:transition-colors [&_svg]:duration-150 [&_svg]:ease-out",
128
139
  "hover:[&_svg]:text-[oklch(42%_.006_285)]",
@@ -145,6 +156,7 @@ const tabs = tv({
145
156
 
146
157
  type TabsReorderContextValue = {
147
158
  enabled: boolean;
159
+ activeId?: string | undefined;
148
160
  };
149
161
 
150
162
  const TabsReorderContext = createContext<TabsReorderContextValue>({ enabled: false });
@@ -152,7 +164,6 @@ const TabsValueContext = createContext<string | undefined>(undefined);
152
164
  type TabsListVariant = "default" | "underline";
153
165
 
154
166
  const TabsListVariantContext = createContext<TabsListVariant>("default");
155
- const REORDER_ENABLED_CONTEXT = { enabled: true } as const satisfies TabsReorderContextValue;
156
167
 
157
168
  export type TabsProps<T extends string = string> = StyledProps<
158
169
  Omit<BaseTabs.Root.Props, "defaultValue" | "onValueChange" | "value">
@@ -199,6 +210,7 @@ export type TabsListProps = StyledProps<BaseTabs.List.Props> & {
199
210
 
200
211
  export function TabsList({ className, children, variant = "default", ...props }: TabsListProps) {
201
212
  const theme = useThemeFamily();
213
+ const reorder = use(TabsReorderContext);
202
214
  const resolvedVariant = theme === "elegant" ? variant : "underline";
203
215
  const { list } = tabs({ theme, variant: resolvedVariant });
204
216
 
@@ -211,7 +223,7 @@ export function TabsList({ className, children, variant = "default", ...props }:
211
223
  {...props}
212
224
  >
213
225
  {children}
214
- {theme === "elegant" ? <TabsIndicator /> : null}
226
+ {theme === "elegant" && !reorder.enabled ? <TabsIndicator /> : null}
215
227
  </BaseTabs.List>
216
228
  </TabsListVariantContext.Provider>
217
229
  );
@@ -229,13 +241,25 @@ export function SortableTabsList<T extends string = string>({
229
241
  variant = "default",
230
242
  ...props
231
243
  }: SortableTabsListProps<T>) {
244
+ const [activeId, setActiveId] = useState<string | undefined>(undefined);
232
245
  const sensors = useSensors(
233
246
  useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
234
247
  useSensor(TouchSensor, { activationConstraint: { delay: 350, tolerance: 8 } }),
235
248
  );
236
249
  const tabIds = useMemo(() => value.map(String), [value]);
250
+ const reorderContext = useMemo(
251
+ () => ({ enabled: true, activeId }) as const satisfies TabsReorderContextValue,
252
+ [activeId],
253
+ );
254
+ const handleDragStart = useCallback(({ active }: DragStartEvent) => {
255
+ setActiveId(String(active.id));
256
+ }, []);
257
+ const handleDragCancel = useCallback(() => {
258
+ setActiveId(undefined);
259
+ }, []);
237
260
  const handleDragEnd = useCallback(
238
261
  ({ active, over }: DragEndEvent) => {
262
+ setActiveId(undefined);
239
263
  if (!over || active.id === over.id) return;
240
264
  const oldIndex = tabIds.indexOf(String(active.id));
241
265
  const newIndex = tabIds.indexOf(String(over.id));
@@ -246,10 +270,17 @@ export function SortableTabsList<T extends string = string>({
246
270
  );
247
271
 
248
272
  return (
249
- <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
273
+ <DndContext
274
+ autoScroll={false}
275
+ sensors={sensors}
276
+ collisionDetection={closestCenter}
277
+ onDragStart={handleDragStart}
278
+ onDragCancel={handleDragCancel}
279
+ onDragEnd={handleDragEnd}
280
+ >
250
281
  <SortableContext items={tabIds} strategy={horizontalListSortingStrategy}>
251
- <TabsReorderContext.Provider value={REORDER_ENABLED_CONTEXT}>
252
- <TabsList variant={variant} {...props}>
282
+ <TabsReorderContext.Provider value={reorderContext}>
283
+ <TabsList variant={variant} {...props} data-sorting={activeId ? "true" : undefined}>
253
284
  {children}
254
285
  </TabsList>
255
286
  </TabsReorderContext.Provider>
@@ -273,10 +304,12 @@ export function SortableTabsTab<T extends string = string>({
273
304
  ...props
274
305
  }: SortableTabsTabProps<T>) {
275
306
  const reorder = use(TabsReorderContext);
307
+ const activeValue = use(TabsValueContext);
276
308
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
277
309
  id: value,
278
310
  disabled: !reorder.enabled,
279
311
  });
312
+ const isDraggingActive = isDragging && activeValue === String(value);
280
313
 
281
314
  if (!reorder.enabled) {
282
315
  return <TabsTabButton value={value} {...props} />;
@@ -295,10 +328,11 @@ export function SortableTabsTab<T extends string = string>({
295
328
  <TabsTabButton
296
329
  value={value}
297
330
  sortableRef={setNodeRef}
331
+ {...props}
332
+ data-dragging-active={isDraggingActive ? "true" : undefined}
298
333
  data-dragging-source={isDragging ? "true" : undefined}
299
334
  data-reorderable="true"
300
335
  style={style}
301
- {...props}
302
336
  {...sortableAttributes}
303
337
  {...listeners}
304
338
  />
@@ -7,6 +7,7 @@ const textColorVariants = {
7
7
  primary: ["text-primary-700"],
8
8
  information: ["text-info-dark"],
9
9
  muted: ["text-foreground-muted"],
10
+ placeholder: ["text-foreground-placeholder"],
10
11
  accent: ["text-accent-700"],
11
12
  success: ["text-success-base"],
12
13
  warning: ["text-warning-base"],
@@ -1,6 +1,6 @@
1
1
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
2
2
  import type { ComponentProps } from "react";
3
- import { tv } from "../../lib/tv.ts";
3
+ import { tv, type VariantProps } from "../../lib/tv.ts";
4
4
  import type { StyledProps } from "../../lib/styled-props.ts";
5
5
  import { useThemeFamily } from "../../lib/theme/use-theme.ts";
6
6
 
@@ -9,8 +9,8 @@ const tooltip = tv({
9
9
  trigger: ["select-none"],
10
10
  positioner: ["isolate z-50 outline-none"],
11
11
  content: [
12
- "relative inline-flex max-w-xs items-center gap-1.5 px-2.5 py-1.5",
13
- "text-xs leading-4 whitespace-normal",
12
+ "relative inline-flex max-w-xs items-center gap-1.5 px-3 py-2",
13
+ "text-[13px] leading-[18px] whitespace-normal",
14
14
  "origin-[var(--transform-origin)] outline-none",
15
15
  "transition-[opacity,transform] duration-100",
16
16
  "data-[starting-style]:scale-95 data-[starting-style]:opacity-0",
@@ -46,16 +46,31 @@ const tooltip = tv({
46
46
  elegant: {
47
47
  content: [
48
48
  "rounded-md bg-layer-popover",
49
- "font-sans text-xs font-medium tracking-[-0.005em] text-foreground-strong",
49
+ "font-sans text-[13px] font-medium tracking-[-0.005em] text-foreground-strong",
50
50
  "shadow-[0_0_0_1px_oklch(0.21_0.006_285_/_0.10),0_1px_1px_oklch(0.21_0.006_285_/_0.04),0_1px_4px_-3px_oklch(0.21_0.006_285_/_0.10)]",
51
51
  "[&_[data-slot=kbd]]:bg-foreground-muted/10 [&_[data-slot=kbd]]:text-foreground-muted [&_[data-slot=kbd]]:ring-0",
52
52
  ],
53
53
  arrow: [],
54
54
  },
55
55
  },
56
+ variant: {
57
+ default: {},
58
+ inverse: {
59
+ content: [
60
+ "bg-foreground-strong text-foreground-inverse",
61
+ "!shadow-[0_12px_24px_0_oklch(0.21_0.006_285_/_0.045),0_1px_2px_0_oklch(0.21_0.006_285_/_0.035)]",
62
+ "[&_[data-slot=kbd]]:bg-white/10 [&_[data-slot=kbd]]:text-foreground-inverse [&_[data-slot=kbd]]:ring-0",
63
+ ],
64
+ },
65
+ },
66
+ },
67
+ defaultVariants: {
68
+ variant: "default",
56
69
  },
57
70
  });
58
71
 
72
+ type TooltipStyleProps = VariantProps<typeof tooltip>;
73
+
59
74
  export type TooltipProviderProps = BaseTooltip.Provider.Props;
60
75
 
61
76
  export function TooltipProvider({ delay = 0, ...props }: TooltipProviderProps) {
@@ -88,25 +103,35 @@ export function TooltipPortal(props: TooltipPortalProps) {
88
103
  return <BaseTooltip.Portal data-slot="tooltip-portal" {...props} />;
89
104
  }
90
105
 
91
- type TooltipArrowProps = StyledProps<BaseTooltip.Arrow.Props>;
106
+ type TooltipArrowProps = StyledProps<BaseTooltip.Arrow.Props> & Pick<TooltipStyleProps, "variant">;
92
107
 
93
- function TooltipArrow({ className, ...props }: TooltipArrowProps) {
108
+ function TooltipArrow({ className, variant, ...props }: TooltipArrowProps) {
94
109
  const theme = useThemeFamily();
95
- const { arrow } = tooltip({ theme });
110
+ const { arrow } = tooltip({ theme, variant });
96
111
  return (
97
112
  <BaseTooltip.Arrow data-slot="tooltip-arrow" className={arrow({ className })} {...props}>
98
- <TooltipArrowSvg />
113
+ <TooltipArrowSvg variant={variant} />
99
114
  </BaseTooltip.Arrow>
100
115
  );
101
116
  }
102
117
 
103
- function TooltipArrowSvg(props: ComponentProps<"svg">) {
118
+ function TooltipArrowSvg({
119
+ variant,
120
+ ...props
121
+ }: ComponentProps<"svg"> & Pick<TooltipStyleProps, "variant">) {
122
+ const isInverse = variant === "inverse";
123
+
104
124
  return (
105
125
  <svg width="12" height="6" viewBox="0 0 12 6" fill="none" {...props}>
106
- <path d="M1 0H11L6 5.25Z" className="fill-layer-popover" />
126
+ <path
127
+ d="M1 0H11L6 5.25Z"
128
+ className={isInverse ? "fill-foreground-strong" : "fill-layer-popover"}
129
+ />
107
130
  <path
108
131
  d="M1 0.5L6 5.25L11 0.5"
109
- className="stroke-[oklch(0.21_0.006_285_/_0.10)]"
132
+ className={
133
+ isInverse ? "stroke-[oklch(0_0_0_/_0.18)]" : "stroke-[oklch(0.21_0.006_285_/_0.10)]"
134
+ }
110
135
  strokeLinecap="round"
111
136
  strokeLinejoin="round"
112
137
  vectorEffect="non-scaling-stroke"
@@ -132,7 +157,7 @@ export type TooltipContentProps = StyledProps<BaseTooltip.Popup.Props> &
132
157
  | "sticky"
133
158
  > & {
134
159
  portalProps?: TooltipPortalProps;
135
- };
160
+ } & Pick<TooltipStyleProps, "variant">;
136
161
 
137
162
  export function TooltipContent({
138
163
  align = "center",
@@ -148,12 +173,13 @@ export function TooltipContent({
148
173
  sideOffset = 6,
149
174
  sticky,
150
175
  portalProps,
176
+ variant,
151
177
  className,
152
178
  children,
153
179
  ...props
154
180
  }: TooltipContentProps) {
155
181
  const theme = useThemeFamily();
156
- const { positioner, content } = tooltip({ theme });
182
+ const { positioner, content } = tooltip({ theme, variant });
157
183
 
158
184
  return (
159
185
  <BaseTooltip.Portal {...portalProps}>
@@ -178,7 +204,7 @@ export function TooltipContent({
178
204
  {...props}
179
205
  >
180
206
  {children}
181
- <TooltipArrow />
207
+ <TooltipArrow variant={variant} />
182
208
  </BaseTooltip.Popup>
183
209
  </BaseTooltip.Positioner>
184
210
  </BaseTooltip.Portal>
@@ -131,7 +131,12 @@ export default function ReorderablePanelTabs<T extends string>({
131
131
 
132
132
  return (
133
133
  <div className="overflow-x-auto border-b-2 border-black bg-white scrollbar-none">
134
- <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
134
+ <DndContext
135
+ autoScroll={false}
136
+ sensors={sensors}
137
+ collisionDetection={closestCenter}
138
+ onDragEnd={handleDragEnd}
139
+ >
135
140
  <SortableContext items={tabIds} strategy={horizontalListSortingStrategy}>
136
141
  <div className="flex min-w-max">
137
142
  {tabs.map((tab) => (
package/src/styles.css CHANGED
@@ -1,5 +1,4 @@
1
- @import "tailwindcss";
2
- @import "./fonts/brutal.css";
1
+ @import url("https://fonts.googleapis.com/css2?family=Geist+Mono:wght@300..700&family=Hanken+Grotesk:wght@300..700&display=swap");
3
2
 
4
3
  /* Pure token contract. No legacy action/surface/destructive/component aliases. */
5
4
 
@@ -303,9 +302,9 @@
303
302
  --theme-shadow-lg: 4px 4px 0px var(--color-black);
304
303
  --theme-shadow-xl: 6px 6px 0px var(--line-strong);
305
304
 
306
- --heading-font: "Space Grotesk Variable", "Space Grotesk", system-ui, sans-serif;
307
- --sans-font: "Space Grotesk Variable", "Space Grotesk", system-ui, sans-serif;
308
- --mono-font: "Geist Mono Variable", "Geist Mono", ui-monospace, monospace;
305
+ --heading-font: "Hanken Grotesk", system-ui, sans-serif;
306
+ --sans-font: "Hanken Grotesk", system-ui, sans-serif;
307
+ --mono-font: "Geist Mono", ui-monospace, monospace;
309
308
  }
310
309
 
311
310
  [data-theme="elegant"] {
@@ -408,7 +407,7 @@
408
407
 
409
408
  --heading-font: "Inter", system-ui, sans-serif;
410
409
  --sans-font: "Geist", system-ui, sans-serif;
411
- --mono-font: "Geist Mono Variable", "Geist Mono", ui-monospace, monospace;
410
+ --mono-font: "Geist Mono", ui-monospace, monospace;
412
411
  }
413
412
 
414
413
  @media (prefers-color-scheme: dark) {
@@ -1,2 +0,0 @@
1
- @import "@fontsource-variable/space-grotesk/wght.css";
2
- @import "@fontsource-variable/geist-mono/wght.css";