@nebutra/ui 0.2.2 → 0.2.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.
@@ -40,8 +40,8 @@ interface AppShellProps {
40
40
  * fixed-width rail on `md+` viewports and collapses into a `Sheet` overlay on
41
41
  * mobile (triggered by the hamburger button shown in the header).
42
42
  *
43
- * The sidebar width animates smoothly (200ms ease-out) when toggling between
44
- * the expanded and collapsed states so it can host an icon-only rail.
43
+ * The sidebar width animates smoothly (duration-flow, ease-out) when toggling
44
+ * between the expanded and collapsed states so it can host an icon-only rail.
45
45
  *
46
46
  * @status stable
47
47
  *
@@ -102,7 +102,7 @@ var primitiveTransition = {
102
102
  };
103
103
 
104
104
  // src/tokens/components/overlay.ts
105
- var overlayFocusRingClassName = "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
105
+ var overlayFocusRingClassName = "outline-none";
106
106
  var overlayZIndex = {
107
107
  backdrop: 1040,
108
108
  modal: 1050};
@@ -154,6 +154,12 @@ var sheetTokens = {
154
154
  function cn(...inputs) {
155
155
  return twMerge(clsx(inputs));
156
156
  }
157
+
158
+ // src/utils/primitive-props.ts
159
+ function asPlainStyle(style) {
160
+ if (style == null || typeof style === "function") return {};
161
+ return style;
162
+ }
157
163
  function getSheetStyle(style) {
158
164
  return {
159
165
  "--sheet-inset": `${sheetTokens.inset}px`,
@@ -176,7 +182,7 @@ function getSheetStyle(style) {
176
182
  "--sheet-shadow": sheetTokens.surface.shadow,
177
183
  "--sheet-duration": `${overlayTokens.motion.duration}ms`,
178
184
  "--sheet-easing": overlayTokens.motion.easing,
179
- ...style
185
+ ...asPlainStyle(style)
180
186
  };
181
187
  }
182
188
  function Sheet({ modal = "trap-focus", disablePointerDismissal = true, ...props }) {
@@ -329,7 +335,7 @@ function AppShell({
329
335
  "aria-label": "Primary",
330
336
  className: cn(
331
337
  "hidden h-screen overflow-hidden bg-sidebar text-sidebar-foreground md:block",
332
- "transition-[width] duration-200 ease-out",
338
+ "transition-[width] duration-flow ease-out",
333
339
  overlay ? "absolute inset-y-0 left-0 z-40" : "shrink-0",
334
340
  railWidth > 0 && "border-r border-sidebar-border",
335
341
  overlay && railWidth > 0 && "shadow-2xl"
@@ -374,7 +380,7 @@ function AppShell({
374
380
  className: cn(
375
381
  "relative inline-flex size-8 items-center justify-center rounded-[var(--radius-md)] text-foreground/80 after:absolute after:-inset-1.5 after:content-['']",
376
382
  "hover:bg-muted hover:text-foreground md:hidden",
377
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1"
383
+ "focus-visible:outline-none"
378
384
  ),
379
385
  children: /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": "true" })
380
386
  }
@@ -392,7 +398,7 @@ function AppShell({
392
398
  className: cn(
393
399
  "relative inline-flex size-8 items-center justify-center rounded-[var(--radius-md)] text-foreground/80 after:absolute after:-inset-1.5 after:content-['']",
394
400
  "hover:bg-muted hover:text-foreground",
395
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1"
401
+ "focus-visible:outline-none"
396
402
  ),
397
403
  children: /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": "true" })
398
404
  }
@@ -793,7 +799,6 @@ var buttonVariants = cva(
793
799
  "rounded-[var(--btn-default-radius,var(--radius-md))]",
794
800
  "text-[length:var(--control-font-size-md,0.875rem)] font-[number:var(--font-weight-medium,500)]",
795
801
  "transition-colors duration-micro ease-out",
796
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
797
802
  "disabled:pointer-events-none disabled:opacity-50",
798
803
  "aria-busy:cursor-wait"
799
804
  ].join(" "),
@@ -820,8 +825,30 @@ var buttonVariants = cva(
820
825
  },
821
826
  shape: {
822
827
  default: "",
823
- square: "",
824
- circle: ""
828
+ // Radius from --btn-default-radius / --radius-md — brand-switchable.
829
+ // Do not hardcode rounded-md here; a language must be able to retarget
830
+ // the corner treatment of every icon trigger at once.
831
+ square: "rounded-[var(--btn-default-radius,var(--radius-md))]",
832
+ // Pill radius token, not Tailwind rounded-full — same 9999px default,
833
+ // but a brand that ships a softer "circle" can override --radius-pill.
834
+ circle: "rounded-[var(--radius-pill,9999px)]",
835
+ pill: "rounded-[var(--radius-pill,9999px)]"
836
+ },
837
+ // Icon-only box size — orthogonal to `size` (which tunes text-button
838
+ // height/padding/font together) and to `shape` (which picks the
839
+ // corner treatment). Only takes effect combined with shape="square"
840
+ // or shape="circle" (see compoundVariants below); every other
841
+ // combination ignores it. 28/32/36 cover the icon-trigger sizes that
842
+ // actually occur in the app — 24/40/48 are already reachable via
843
+ // shape + size (tiny/default/lg). Heights read --control-height-icon-*
844
+ // so density-aware Brand Packages can scale them with the ladder.
845
+ iconSize: {
846
+ sm: "",
847
+ // 28px default
848
+ md: "",
849
+ // 32px default
850
+ lg: ""
851
+ // 36px default
825
852
  }
826
853
  },
827
854
  compoundVariants: [
@@ -832,22 +859,56 @@ var buttonVariants = cva(
832
859
  {
833
860
  shape: "circle",
834
861
  size: "tiny",
835
- className: "w-[var(--control-height-tiny,1.5rem)] px-0 rounded-full"
862
+ className: "w-[var(--control-height-tiny,1.5rem)] px-0"
836
863
  },
837
864
  {
838
865
  shape: "circle",
839
866
  size: "sm",
840
- className: "w-[var(--control-height-sm,2rem)] px-0 rounded-full"
867
+ className: "w-[var(--control-height-sm,2rem)] px-0"
841
868
  },
842
869
  {
843
870
  shape: "circle",
844
871
  size: "default",
845
- className: "w-[var(--control-height-md,2.5rem)] px-0 rounded-full"
872
+ className: "w-[var(--control-height-md,2.5rem)] px-0"
846
873
  },
847
874
  {
848
875
  shape: "circle",
849
876
  size: "lg",
850
- className: "w-[var(--control-height-lg,3rem)] px-0 rounded-full"
877
+ className: "w-[var(--control-height-lg,3rem)] px-0"
878
+ },
879
+ // iconSize wins over the size-driven box above — matched on shape +
880
+ // iconSize only, so it applies regardless of whatever `size` was
881
+ // passed (or left at its "default" fallback). Corner treatment stays
882
+ // on the shape variant (token-backed); only the box is set here.
883
+ {
884
+ shape: "square",
885
+ iconSize: "sm",
886
+ className: "h-[var(--control-height-icon-sm,1.75rem)] w-[var(--control-height-icon-sm,1.75rem)] px-0"
887
+ },
888
+ {
889
+ shape: "square",
890
+ iconSize: "md",
891
+ className: "h-[var(--control-height-icon-md,2rem)] w-[var(--control-height-icon-md,2rem)] px-0"
892
+ },
893
+ {
894
+ shape: "square",
895
+ iconSize: "lg",
896
+ className: "h-[var(--control-height-icon-lg,2.25rem)] w-[var(--control-height-icon-lg,2.25rem)] px-0"
897
+ },
898
+ {
899
+ shape: "circle",
900
+ iconSize: "sm",
901
+ className: "h-[var(--control-height-icon-sm,1.75rem)] w-[var(--control-height-icon-sm,1.75rem)] px-0"
902
+ },
903
+ {
904
+ shape: "circle",
905
+ iconSize: "md",
906
+ className: "h-[var(--control-height-icon-md,2rem)] w-[var(--control-height-icon-md,2rem)] px-0"
907
+ },
908
+ {
909
+ shape: "circle",
910
+ iconSize: "lg",
911
+ className: "h-[var(--control-height-icon-lg,2.25rem)] w-[var(--control-height-icon-lg,2.25rem)] px-0"
851
912
  }
852
913
  ],
853
914
  defaultVariants: {
@@ -869,7 +930,10 @@ function Spinner({ className }) {
869
930
  }
870
931
  );
871
932
  }
872
- function getIconSizeClass(size) {
933
+ function getIconSizeClass(size, iconSize2) {
934
+ if (iconSize2 === "sm") return "[&>svg]:size-3.5";
935
+ if (iconSize2 === "md") return "[&>svg]:size-3.5";
936
+ if (iconSize2 === "lg") return "[&>svg]:size-4";
873
937
  switch (size) {
874
938
  case "tiny":
875
939
  return "[&>svg]:size-3";
@@ -884,7 +948,10 @@ function getIconSizeClass(size) {
884
948
  return "[&>svg]:size-4";
885
949
  }
886
950
  }
887
- function getSpinnerSizeClass(size) {
951
+ function getSpinnerSizeClass(size, iconSize2) {
952
+ if (iconSize2 === "sm") return "size-3.5";
953
+ if (iconSize2 === "md") return "size-3.5";
954
+ if (iconSize2 === "lg") return "size-4";
888
955
  switch (size) {
889
956
  case "tiny":
890
957
  return "size-3";
@@ -909,10 +976,10 @@ function resolveShadowClass(shadow) {
909
976
  const level = shadow === true ? "md" : shadow;
910
977
  return SHADOW_CLASSES[level];
911
978
  }
912
- function ButtonContent({ loading, prefix, suffix, size, children }) {
913
- const iconSizeClass = getIconSizeClass(size);
979
+ function ButtonContent({ loading, prefix, suffix, size, iconSize: iconSize2, children }) {
980
+ const iconSizeClass = getIconSizeClass(size, iconSize2);
914
981
  return /* @__PURE__ */ jsxs(Fragment, { children: [
915
- loading && /* @__PURE__ */ jsx(Spinner, { className: getSpinnerSizeClass(size) }),
982
+ loading && /* @__PURE__ */ jsx(Spinner, { className: getSpinnerSizeClass(size, iconSize2) }),
916
983
  prefix != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("shrink-0", iconSizeClass), children: prefix }),
917
984
  children,
918
985
  suffix != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("shrink-0", iconSizeClass), children: suffix })
@@ -923,6 +990,7 @@ var Button = ({
923
990
  variant,
924
991
  size,
925
992
  shape,
993
+ iconSize: iconSize2,
926
994
  asChild = false,
927
995
  loading = false,
928
996
  disabled,
@@ -940,11 +1008,21 @@ var Button = ({
940
1008
  Comp,
941
1009
  {
942
1010
  ref,
943
- className: cn(buttonVariants({ variant, size, shape }), shadowClass, className),
1011
+ className: cn(buttonVariants({ variant, size, shape, iconSize: iconSize2 }), shadowClass, className),
944
1012
  disabled: isDisabled,
945
1013
  "aria-busy": loading || void 0,
946
1014
  ...props,
947
- children: asChild ? children : /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
1015
+ children: asChild ? children : /* @__PURE__ */ jsx(
1016
+ ButtonContent,
1017
+ {
1018
+ loading,
1019
+ prefix,
1020
+ suffix,
1021
+ size,
1022
+ iconSize: iconSize2,
1023
+ children
1024
+ }
1025
+ )
948
1026
  }
949
1027
  );
950
1028
  };
@@ -954,6 +1032,7 @@ var ButtonLink = ({
954
1032
  variant,
955
1033
  size,
956
1034
  shape,
1035
+ iconSize: iconSize2,
957
1036
  prefix,
958
1037
  suffix,
959
1038
  shadow,
@@ -973,14 +1052,24 @@ var ButtonLink = ({
973
1052
  {
974
1053
  ref,
975
1054
  className: cn(
976
- buttonVariants({ variant, size, shape }),
1055
+ buttonVariants({ variant, size, shape, iconSize: iconSize2 }),
977
1056
  shadowClass,
978
1057
  loading && "pointer-events-none opacity-50",
979
1058
  className
980
1059
  ),
981
1060
  ...loadingProps,
982
1061
  ...props,
983
- children: /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
1062
+ children: /* @__PURE__ */ jsx(
1063
+ ButtonContent,
1064
+ {
1065
+ loading,
1066
+ prefix,
1067
+ suffix,
1068
+ size,
1069
+ iconSize: iconSize2,
1070
+ children
1071
+ }
1072
+ )
984
1073
  }
985
1074
  );
986
1075
  };