@jinaan/uikit 0.1.7 → 0.1.8

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.
@@ -0,0 +1,4 @@
1
+ import { type ReactNode } from "react";
2
+ /** Count matching elements anywhere in a static React children tree. */
3
+ export declare function countDescendants(children: ReactNode, types: readonly unknown[]): number;
4
+ //# sourceMappingURL=item-count.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"item-count.d.ts","sourceRoot":"","sources":["../src/item-count.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjE,wEAAwE;AACxE,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,SAAS,OAAO,EAAE,GACxB,MAAM,CAcR"}
package/dist/select.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import * as SelectPrimitive from "@radix-ui/react-select";
2
2
  import { type ComponentPropsWithoutRef } from "react";
3
- export declare const Select: import("react").FC<SelectPrimitive.SelectProps>;
4
3
  export declare const SelectGroup: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectGroupProps & import("react").RefAttributes<HTMLDivElement>>;
5
4
  export declare const SelectValue: import("react").ForwardRefExoticComponent<SelectPrimitive.SelectValueProps & import("react").RefAttributes<HTMLSpanElement>>;
5
+ /** Select root; disabled when there are no items to choose from. */
6
+ export declare function Select({ children, disabled, ...props }: ComponentPropsWithoutRef<typeof SelectPrimitive.Root>): import("react").JSX.Element;
6
7
  export interface SelectTriggerProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {
7
8
  /** `field` fills a form; `inline` mimics the compact app dropdown. */
8
9
  variant?: "field" | "inline";
@@ -1 +1 @@
1
- {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../src/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,OAAO,CAAC;AAIf,eAAO,MAAM,MAAM,iDAAuB,CAAC;AAC3C,eAAO,MAAM,WAAW,6HAAwB,CAAC;AACjD,eAAO,MAAM,WAAW,8HAAwB,CAAC;AAEjD,MAAM,WAAW,kBAAmB,SAAQ,wBAAwB,CAClE,OAAO,eAAe,CAAC,OAAO,CAC/B;IACC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,kHAuBxB,CAAC;AAGH,eAAO,MAAM,aAAa,4LA+BzB,CAAC;AAGF,eAAO,MAAM,UAAU,yLAmBrB,CAAC;AAGH,eAAO,MAAM,WAAW,0LAStB,CAAC"}
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../src/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAEL,KAAK,wBAAwB,EAE9B,MAAM,OAAO,CAAC;AAKf,eAAO,MAAM,WAAW,6HAAwB,CAAC;AACjD,eAAO,MAAM,WAAW,8HAAwB,CAAC;AAEjD,oEAAoE;AACpE,wBAAgB,MAAM,CAAC,EACrB,QAAQ,EACR,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,wBAAwB,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,+BAQvD;AAED,MAAM,WAAW,kBAAmB,SAAQ,wBAAwB,CAClE,OAAO,eAAe,CAAC,OAAO,CAC/B;IACC,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9B;AAED,eAAO,MAAM,aAAa,kHAwBxB,CAAC;AAGH,eAAO,MAAM,aAAa,4LA+BzB,CAAC;AAGF,eAAO,MAAM,UAAU,yLAmBrB,CAAC;AAGH,eAAO,MAAM,WAAW,0LAStB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jinaan/uikit",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Reusable React and Tailwind UI components for Jinaan projects.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -1,15 +1,52 @@
1
1
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
2
2
  import { Check } from "@phosphor-icons/react";
3
3
  import {
4
+ createContext,
4
5
  forwardRef,
6
+ useContext,
5
7
  type ComponentPropsWithoutRef,
6
8
  type ElementRef,
7
9
  } from "react";
8
10
 
11
+ import { countDescendants } from "./item-count";
9
12
  import { cn } from "./utils";
10
13
 
11
- export const DropdownMenu = DropdownMenuPrimitive.Root;
12
- export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
14
+ const DropdownMenuEmptyContext = createContext(false);
15
+
16
+ /** Menu root; disables its trigger when there are no items. */
17
+ export function DropdownMenu({
18
+ children,
19
+ ...props
20
+ }: ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Root>) {
21
+ const empty =
22
+ countDescendants(children, [
23
+ DropdownMenuItem,
24
+ DropdownMenuCheckboxItem,
25
+ ]) === 0;
26
+
27
+ return (
28
+ <DropdownMenuEmptyContext.Provider value={empty}>
29
+ <DropdownMenuPrimitive.Root {...props}>{children}</DropdownMenuPrimitive.Root>
30
+ </DropdownMenuEmptyContext.Provider>
31
+ );
32
+ }
33
+
34
+ export const DropdownMenuTrigger = forwardRef<
35
+ ElementRef<typeof DropdownMenuPrimitive.Trigger>,
36
+ ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
37
+ >(({ disabled, ...props }, ref) => {
38
+ const empty = useContext(DropdownMenuEmptyContext);
39
+
40
+ return (
41
+ <DropdownMenuPrimitive.Trigger
42
+ ref={ref}
43
+ disabled={disabled || empty}
44
+ {...props}
45
+ />
46
+ );
47
+ });
48
+ DropdownMenuTrigger.displayName = "DropdownMenuTrigger";
49
+
13
50
  export const DropdownMenuGroup = DropdownMenuPrimitive.Group;
14
51
  export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
15
52
 
@@ -0,0 +1,21 @@
1
+ import { Children, isValidElement, type ReactNode } from "react";
2
+
3
+ /** Count matching elements anywhere in a static React children tree. */
4
+ export function countDescendants(
5
+ children: ReactNode,
6
+ types: readonly unknown[],
7
+ ): number {
8
+ let count = 0;
9
+
10
+ Children.forEach(children, (child) => {
11
+ if (!isValidElement(child)) return;
12
+ if (types.some((type) => type === child.type)) {
13
+ count += 1;
14
+ return;
15
+ }
16
+ const nested = (child.props as { children?: ReactNode }).children;
17
+ if (nested) count += countDescendants(nested, types);
18
+ });
19
+
20
+ return count;
21
+ }
package/src/select.tsx CHANGED
@@ -6,12 +6,27 @@ import {
6
6
  type ElementRef,
7
7
  } from "react";
8
8
 
9
+ import { countDescendants } from "./item-count";
9
10
  import { cn } from "./utils";
10
11
 
11
- export const Select = SelectPrimitive.Root;
12
12
  export const SelectGroup = SelectPrimitive.Group;
13
13
  export const SelectValue = SelectPrimitive.Value;
14
14
 
15
+ /** Select root; disabled when there are no items to choose from. */
16
+ export function Select({
17
+ children,
18
+ disabled,
19
+ ...props
20
+ }: ComponentPropsWithoutRef<typeof SelectPrimitive.Root>) {
21
+ const empty = countDescendants(children, [SelectItem]) === 0;
22
+
23
+ return (
24
+ <SelectPrimitive.Root disabled={disabled || empty} {...props}>
25
+ {children}
26
+ </SelectPrimitive.Root>
27
+ );
28
+ }
29
+
15
30
  export interface SelectTriggerProps extends ComponentPropsWithoutRef<
16
31
  typeof SelectPrimitive.Trigger
17
32
  > {
@@ -28,6 +43,7 @@ export const SelectTrigger = forwardRef<
28
43
  className={cn(
29
44
  "flex items-center justify-between gap-2 text-sm text-fg",
30
45
  "focus:outline-none disabled:cursor-not-allowed disabled:opacity-50",
46
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
31
47
  "[&>span]:truncate",
32
48
  variant === "field" &&
33
49
  "h-(--control-h-md) w-full rounded-md border border-line bg-surface px-3 focus:border-primary focus:ring-2 focus:ring-focus/30",