@docubook/ui-react 2.0.0-beta.4 → 2.0.0-beta.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/dist/base/dropdown.d.ts +4 -1
- package/dist/base/theme-controller.d.ts +4 -2
- package/dist/dropdown.js +18 -9
- package/dist/dropdown.js.map +1 -1
- package/dist/pagination.js +2 -2
- package/dist/pagination.js.map +1 -1
- package/dist/theme-controller.js +42 -31
- package/dist/theme-controller.js.map +1 -1
- package/dist/toggle.js +39 -39
- package/dist/toggle.js.map +1 -1
- package/package.json +1 -1
- package/styles.css +17 -0
package/dist/base/dropdown.d.ts
CHANGED
|
@@ -7,8 +7,11 @@ export interface DropdownProps extends HTMLAttributes<HTMLDetailsElement> {
|
|
|
7
7
|
menuClassName?: string;
|
|
8
8
|
}
|
|
9
9
|
export declare const Dropdown: import("react").ForwardRefExoticComponent<DropdownProps & import("react").RefAttributes<HTMLDetailsElement>>;
|
|
10
|
-
export interface DropdownItemProps extends HTMLAttributes<HTMLLIElement> {
|
|
10
|
+
export interface DropdownItemProps extends Omit<HTMLAttributes<HTMLLIElement>, "onClick" | "onKeyDown"> {
|
|
11
11
|
children?: ReactNode;
|
|
12
|
+
onSelect?: () => void;
|
|
13
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
14
|
+
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
|
|
12
15
|
}
|
|
13
16
|
export declare const DropdownItem: import("react").ForwardRefExoticComponent<DropdownItemProps & import("react").RefAttributes<HTMLLIElement>>;
|
|
14
17
|
export declare const DropdownLink: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLAnchorElement> & {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
1
|
+
import { type InputHTMLAttributes, type ReactNode } from "react";
|
|
2
2
|
import type { Size } from "../utils/types";
|
|
3
3
|
export interface ThemeControllerToggleProps {
|
|
4
4
|
defaultTheme?: string;
|
|
5
5
|
lightTheme?: string;
|
|
6
6
|
darkTheme?: string;
|
|
7
|
+
ariaLabel?: string;
|
|
8
|
+
inputProps?: Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "checked" | "onChange" | "value">;
|
|
7
9
|
onThemeChange?: (theme: string) => void;
|
|
8
10
|
className?: string;
|
|
9
11
|
label?: ReactNode;
|
|
@@ -14,4 +16,4 @@ export interface ThemeControllerToggleProps {
|
|
|
14
16
|
toggle: (checked: boolean) => void;
|
|
15
17
|
}) => ReactNode;
|
|
16
18
|
}
|
|
17
|
-
export declare function ThemeControllerToggle({ defaultTheme, lightTheme, darkTheme, onThemeChange, className, label, size, children, }: ThemeControllerToggleProps): import("react").JSX.Element;
|
|
19
|
+
export declare function ThemeControllerToggle({ defaultTheme, lightTheme, darkTheme, ariaLabel, inputProps, onThemeChange, className, label, size, children, }: ThemeControllerToggleProps): import("react").JSX.Element;
|
package/dist/dropdown.js
CHANGED
|
@@ -27,21 +27,30 @@ var o = t(({ className: t, align: o = "start", disabled: s = !1, trigger: c, chi
|
|
|
27
27
|
});
|
|
28
28
|
});
|
|
29
29
|
o.displayName = "Dropdown";
|
|
30
|
-
var s = t(({ className: t, children: n,
|
|
31
|
-
ref:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
var s = t(({ className: t, children: n, onSelect: r, onClick: a, onKeyDown: o, ...s }, c) => /* @__PURE__ */ i("li", {
|
|
31
|
+
ref: c,
|
|
32
|
+
role: "none",
|
|
33
|
+
...s,
|
|
34
|
+
children: /* @__PURE__ */ i("button", {
|
|
35
|
+
type: "button",
|
|
36
|
+
role: "menuitem",
|
|
37
|
+
onClick: (e) => {
|
|
38
|
+
a?.(e), r?.();
|
|
39
|
+
},
|
|
40
|
+
onKeyDown: o,
|
|
41
|
+
className: e("hover:bg-base-200 text-base-content/80 hover:text-base-content relative flex w-full cursor-pointer items-center gap-2 rounded px-2 py-2 text-left text-sm transition-colors outline-none focus-visible:ring-2", t),
|
|
42
|
+
children: n
|
|
43
|
+
})
|
|
36
44
|
}));
|
|
37
45
|
s.displayName = "DropdownItem";
|
|
38
46
|
var c = t(({ className: t, children: n, href: r, ...a }, o) => /* @__PURE__ */ i("li", {
|
|
39
|
-
role: "
|
|
40
|
-
className: "
|
|
47
|
+
role: "none",
|
|
48
|
+
className: "relative flex rounded outline-none",
|
|
41
49
|
children: /* @__PURE__ */ i("a", {
|
|
42
50
|
ref: o,
|
|
43
51
|
href: r,
|
|
44
|
-
|
|
52
|
+
role: "menuitem",
|
|
53
|
+
className: e("hover:bg-base-200 text-base-content/80 hover:text-base-content flex w-full cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm text-inherit no-underline transition-colors focus-visible:ring-2", t),
|
|
45
54
|
...a,
|
|
46
55
|
children: n
|
|
47
56
|
})
|
package/dist/dropdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown.js","names":[],"sources":["../src/base/dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport { type HTMLAttributes, type ReactNode, forwardRef, useRef, useEffect } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDetailsElement> {\n align?: \"start\" | \"end\";\n disabled?: boolean;\n trigger?: ReactNode;\n children?: ReactNode;\n menuClassName?: string;\n}\n\nexport const Dropdown = forwardRef<HTMLDetailsElement, DropdownProps>(\n (\n { className, align = \"start\", disabled = false, trigger, children, menuClassName, ...props },\n ref\n ) => {\n const detailsRef = useRef<HTMLDetailsElement>(null);\n\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (detailsRef.current && !detailsRef.current.contains(e.target as Node)) {\n detailsRef.current.open = false;\n }\n };\n document.addEventListener(\"click\", handler);\n return () => document.removeEventListener(\"click\", handler);\n }, []);\n\n return (\n <details\n ref={(el) => {\n (detailsRef as React.MutableRefObject<HTMLDetailsElement | null>).current = el;\n if (typeof ref === \"function\") ref(el);\n else if (ref) ref.current = el;\n }}\n className={cn(\"relative\", disabled && \"pointer-events-none opacity-50\", className)}\n {...props}\n >\n <summary className=\"cursor-pointer\" style={{ listStyle: \"none\" }}>\n {trigger}\n </summary>\n <ul\n className={cn(\n \"bg-base-100 rounded-box border-base-300 absolute z-50 mt-1 min-w-[240px] space-y-1 border p-2 shadow-lg\",\n align === \"end\" ? \"right-0\" : \"left-0\",\n menuClassName\n )}\n >\n {children}\n </ul>\n </details>\n );\n }\n);\nDropdown.displayName = \"Dropdown\";\n\nexport interface DropdownItemProps extends HTMLAttributes<HTMLLIElement> {\n children?: ReactNode;\n}\n\nexport const DropdownItem = forwardRef<HTMLLIElement, DropdownItemProps>(\n ({ className, children, ...props }, ref) => (\n <li\n
|
|
1
|
+
{"version":3,"file":"dropdown.js","names":[],"sources":["../src/base/dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport { type HTMLAttributes, type ReactNode, forwardRef, useRef, useEffect } from \"react\";\nimport { cn } from \"../utils/cn\";\n\nexport interface DropdownProps extends HTMLAttributes<HTMLDetailsElement> {\n align?: \"start\" | \"end\";\n disabled?: boolean;\n trigger?: ReactNode;\n children?: ReactNode;\n menuClassName?: string;\n}\n\nexport const Dropdown = forwardRef<HTMLDetailsElement, DropdownProps>(\n (\n { className, align = \"start\", disabled = false, trigger, children, menuClassName, ...props },\n ref\n ) => {\n const detailsRef = useRef<HTMLDetailsElement>(null);\n\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (detailsRef.current && !detailsRef.current.contains(e.target as Node)) {\n detailsRef.current.open = false;\n }\n };\n document.addEventListener(\"click\", handler);\n return () => document.removeEventListener(\"click\", handler);\n }, []);\n\n return (\n <details\n ref={(el) => {\n (detailsRef as React.MutableRefObject<HTMLDetailsElement | null>).current = el;\n if (typeof ref === \"function\") ref(el);\n else if (ref) ref.current = el;\n }}\n className={cn(\"relative\", disabled && \"pointer-events-none opacity-50\", className)}\n {...props}\n >\n <summary className=\"cursor-pointer\" style={{ listStyle: \"none\" }}>\n {trigger}\n </summary>\n <ul\n className={cn(\n \"bg-base-100 rounded-box border-base-300 absolute z-50 mt-1 min-w-[240px] space-y-1 border p-2 shadow-lg\",\n align === \"end\" ? \"right-0\" : \"left-0\",\n menuClassName\n )}\n >\n {children}\n </ul>\n </details>\n );\n }\n);\nDropdown.displayName = \"Dropdown\";\n\nexport interface DropdownItemProps extends Omit<\n HTMLAttributes<HTMLLIElement>,\n \"onClick\" | \"onKeyDown\"\n> {\n children?: ReactNode;\n onSelect?: () => void;\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;\n}\n\nexport const DropdownItem = forwardRef<HTMLLIElement, DropdownItemProps>(\n ({ className, children, onSelect, onClick, onKeyDown, ...props }, ref) => (\n <li ref={ref} role=\"none\" {...props}>\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={(e) => {\n onClick?.(e);\n onSelect?.();\n }}\n onKeyDown={onKeyDown}\n className={cn(\n \"hover:bg-base-200 text-base-content/80 hover:text-base-content relative flex w-full cursor-pointer items-center gap-2 rounded px-2 py-2 text-left text-sm transition-colors outline-none focus-visible:ring-2\",\n className\n )}\n >\n {children}\n </button>\n </li>\n )\n);\nDropdownItem.displayName = \"DropdownItem\";\n\nexport const DropdownLink = forwardRef<\n HTMLAnchorElement,\n HTMLAttributes<HTMLAnchorElement> & { href?: string }\n>(({ className, children, href, ...props }, ref) => (\n <li role=\"none\" className=\"relative flex rounded outline-none\">\n <a\n ref={ref}\n href={href}\n role=\"menuitem\"\n className={cn(\n \"hover:bg-base-200 text-base-content/80 hover:text-base-content flex w-full cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm text-inherit no-underline transition-colors focus-visible:ring-2\",\n className\n )}\n {...props}\n >\n {children}\n </a>\n </li>\n));\nDropdownLink.displayName = \"DropdownLink\";\n"],"mappings":";;;;;AAaA,IAAa,IAAW,GAEpB,EAAE,cAAW,WAAQ,SAAS,cAAW,IAAO,YAAS,aAAU,kBAAe,GAAG,KACrF,MACG;CACH,IAAM,IAAa,EAA2B,IAAI;CAYlD,OAVA,QAAgB;EACd,IAAM,KAAW,MAAkB;GACjC,AAAI,EAAW,WAAW,CAAC,EAAW,QAAQ,SAAS,EAAE,MAAc,MACrE,EAAW,QAAQ,OAAO;EAE9B;EAEA,OADA,SAAS,iBAAiB,SAAS,CAAO,SAC7B,SAAS,oBAAoB,SAAS,CAAO;CAC5D,GAAG,CAAC,CAAC,GAGH,kBAAC,WAAD;EACE,MAAM,MAAO;GAEX,AADA,EAAkE,UAAU,GACxE,OAAO,KAAQ,aAAY,EAAI,CAAE,IAC5B,MAAK,EAAI,UAAU;EAC9B;EACA,WAAW,EAAG,YAAY,KAAY,kCAAkC,CAAS;EACjF,GAAI;EAPN,UAAA,CASE,kBAAC,WAAD;GAAS,WAAU;GAAiB,OAAO,EAAE,WAAW,OAAO;GAC5D,UAAA;EACM,CAAA,GACT,kBAAC,MAAD;GACE,WAAW,EACT,2GACA,MAAU,QAAQ,YAAY,UAC9B,CACF;GAEC;EACC,CAAA,CACG;;AAEb,CACF;AACA,EAAS,cAAc;AAYvB,IAAa,IAAe,GACzB,EAAE,cAAW,aAAU,aAAU,YAAS,cAAW,GAAG,KAAS,MAChE,kBAAC,MAAD;CAAS;CAAK,MAAK;CAAO,GAAI;CAC5B,UAAA,kBAAC,UAAD;EACE,MAAK;EACL,MAAK;EACL,UAAU,MAAM;GAEd,AADA,IAAU,CAAC,GACX,IAAW;EACb;EACW;EACX,WAAW,EACT,iNACA,CACF;EAEC;CACK,CAAA;AACN,CAAA,CAER;AACA,EAAa,cAAc;AAE3B,IAAa,IAAe,GAGzB,EAAE,cAAW,aAAU,SAAM,GAAG,KAAS,MAC1C,kBAAC,MAAD;CAAI,MAAK;CAAO,WAAU;CACxB,UAAA,kBAAC,KAAD;EACO;EACC;EACN,MAAK;EACL,WAAW,EACT,2MACA,CACF;EACA,GAAI;EAEH;CACA,CAAA;AACD,CAAA,CACL;AACD,EAAa,cAAc"}
|
package/dist/pagination.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Fragment as t, jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
|
3
3
|
//#region src/base/pagination.tsx
|
|
4
4
|
function i({ direction: i, label: a, title: o, description: s, icon: c }) {
|
|
5
5
|
let l = i === "prev", u = /* @__PURE__ */ r("div", {
|
|
6
|
-
className: e("text-primary/75 flex items-center gap-1.5 text-sm", l ? "pr-5 pl-3" : "pr-3 pl-5"),
|
|
6
|
+
className: e("text-primary/75 flex items-center gap-1.5 text-sm", l ? "pr-5 pl-3" : "pr-3 pl-5", l && "shrink-0"),
|
|
7
7
|
children: [
|
|
8
8
|
l && c && /* @__PURE__ */ n("span", {
|
|
9
9
|
className: "flex shrink-0 items-center",
|
|
@@ -34,7 +34,7 @@ function i({ direction: i, label: a, title: o, description: s, icon: c }) {
|
|
|
34
34
|
className: e("bg-primary/15 hover:bg-primary/20 hover:ring-primary/30 flex h-16 flex-1 items-center rounded-xl transition-shadow hover:ring-1", l ? "justify-start" : "justify-end"),
|
|
35
35
|
children: l ? /* @__PURE__ */ r(t, { children: [
|
|
36
36
|
u,
|
|
37
|
-
/* @__PURE__ */ n("div", { className: "bg-primary/20 h-8 w-px" }),
|
|
37
|
+
/* @__PURE__ */ n("div", { className: "bg-primary/20 h-8 w-px shrink-0" }),
|
|
38
38
|
d
|
|
39
39
|
] }) : /* @__PURE__ */ r(t, { children: [
|
|
40
40
|
d,
|
package/dist/pagination.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","names":[],"sources":["../src/base/pagination.tsx"],"sourcesContent":["import { cn } from \"../utils/cn\";\nimport type { ReactNode } from \"react\";\n\nexport interface PaginationDocsProps {\n prev?: { href: string; title: string; description?: string };\n next?: { href: string; title: string; description?: string };\n className?: string;\n prevIcon?: ReactNode;\n nextIcon?: ReactNode;\n linkClassName?: string;\n}\n\ninterface PaginationCardProps {\n direction: \"prev\" | \"next\";\n label: string;\n title: string;\n description?: string;\n icon?: ReactNode;\n}\n\nfunction PaginationCard({ direction, label, title, description, icon }: PaginationCardProps) {\n const isPrevious = direction === \"prev\";\n\n const labelNode = (\n <div\n className={cn(\n \"text-primary/75 flex items-center gap-1.5 text-sm\",\n isPrevious ? \"pr-5 pl-3\" : \"pr-3 pl-5\"\n )}\n >\n {isPrevious && icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <span data-component-part=\"pagination-label\">{label}</span>\n {!isPrevious && icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n </div>\n );\n\n const metaNode = (\n <div\n className={cn(\n \"flex min-w-0 flex-col justify-center px-5\",\n isPrevious ? \"items-start text-left\" : \"items-end text-right\"\n )}\n >\n <div\n data-component-part=\"pagination-title\"\n className=\"text-primary w-full truncate text-sm font-semibold\"\n >\n {title}\n </div>\n {description && (\n <span\n data-component-part=\"pagination-description\"\n className=\"text-primary/75 hidden w-full max-w-72 truncate text-xs sm:block\"\n >\n {description}\n </span>\n )}\n </div>\n );\n\n return (\n <div\n className={cn(\n \"bg-primary/15 hover:bg-primary/20 hover:ring-primary/30 flex h-16 flex-1 items-center rounded-xl transition-shadow hover:ring-1\",\n isPrevious ? \"justify-start\" : \"justify-end\"\n )}\n >\n {isPrevious ? (\n <>\n {labelNode}\n <div className=\"bg-primary/20 h-8 w-px\" />\n {metaNode}\n </>\n ) : (\n <>\n {metaNode}\n <div className=\"bg-primary/20 h-8 w-px\" />\n {labelNode}\n </>\n )}\n </div>\n );\n}\n\nexport function PaginationDocs({\n prev,\n next,\n className,\n prevIcon,\n nextIcon,\n linkClassName,\n}: PaginationDocsProps) {\n return (\n <nav\n id=\"pagination\"\n aria-label=\"Pagination\"\n className={cn(\"bg-base-200/50 flex w-full gap-1 rounded-2xl p-1\", className)}\n >\n {prev && (\n <a\n href={prev.href}\n rel=\"prev\"\n data-component-part=\"pagination-prev\"\n className={cn(\n \"group min-w-0 rounded-xl no-underline\",\n next\n ? // Paired with next: minimal link by design (30% of the pill).\n \"text-muted-foreground hover:bg-base-200/60 hover:text-base-content flex w-[calc(30%-2px)] items-center justify-start gap-1.5 rounded-xl px-3 py-3 text-sm transition-colors\"\n : // Alone (last page, no next): rich card mirroring the next-only\n // variant — full width on mobile, half the container above\n // 640px, pushed left like a back button.\n \"w-full sm:mr-auto sm:w-1/2\",\n linkClassName\n )}\n >\n {next ? (\n <>\n {prevIcon && <span className=\"flex shrink-0 items-center\">{prevIcon}</span>}\n <span data-component-part=\"pagination-label\">Previous</span>\n </>\n ) : (\n <PaginationCard\n direction=\"prev\"\n label=\"Previous\"\n title={prev.title}\n description={prev.description}\n icon={prevIcon}\n />\n )}\n </a>\n )}\n {next && (\n <a\n href={next.href}\n rel=\"next\"\n data-component-part=\"pagination-next\"\n className={cn(\n \"group min-w-0 rounded-xl no-underline\",\n // Next-only (e.g. docs index): full width on mobile, half the\n // container above 640px — pushed right like a forward button.\n // With prev: calc-based 70% (minus half the gap) so the pair\n // always fills the pill without overlapping.\n prev ? \"w-[calc(70%-2px)]\" : \"w-full sm:ml-auto sm:w-1/2\",\n linkClassName\n )}\n >\n <PaginationCard\n direction=\"next\"\n label=\"Next\"\n title={next.title}\n description={next.description}\n icon={nextIcon}\n />\n </a>\n )}\n </nav>\n );\n}\n"],"mappings":";;;AAoBA,SAAS,EAAe,EAAE,cAAW,UAAO,UAAO,gBAAa,WAA6B;CAC3F,IAAM,IAAa,MAAc,QAE3B,IACJ,kBAAC,OAAD;EACE,WAAW,EACT,qDACA,IAAa,cAAc,
|
|
1
|
+
{"version":3,"file":"pagination.js","names":[],"sources":["../src/base/pagination.tsx"],"sourcesContent":["import { cn } from \"../utils/cn\";\nimport type { ReactNode } from \"react\";\n\nexport interface PaginationDocsProps {\n prev?: { href: string; title: string; description?: string };\n next?: { href: string; title: string; description?: string };\n className?: string;\n prevIcon?: ReactNode;\n nextIcon?: ReactNode;\n linkClassName?: string;\n}\n\ninterface PaginationCardProps {\n direction: \"prev\" | \"next\";\n label: string;\n title: string;\n description?: string;\n icon?: ReactNode;\n}\n\nfunction PaginationCard({ direction, label, title, description, icon }: PaginationCardProps) {\n const isPrevious = direction === \"prev\";\n\n const labelNode = (\n <div\n className={cn(\n \"text-primary/75 flex items-center gap-1.5 text-sm\",\n isPrevious ? \"pr-5 pl-3\" : \"pr-3 pl-5\",\n isPrevious && \"shrink-0\"\n )}\n >\n {isPrevious && icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n <span data-component-part=\"pagination-label\">{label}</span>\n {!isPrevious && icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n </div>\n );\n\n const metaNode = (\n <div\n className={cn(\n \"flex min-w-0 flex-col justify-center px-5\",\n isPrevious ? \"items-start text-left\" : \"items-end text-right\"\n )}\n >\n <div\n data-component-part=\"pagination-title\"\n className=\"text-primary w-full truncate text-sm font-semibold\"\n >\n {title}\n </div>\n {description && (\n <span\n data-component-part=\"pagination-description\"\n className=\"text-primary/75 hidden w-full max-w-72 truncate text-xs sm:block\"\n >\n {description}\n </span>\n )}\n </div>\n );\n\n return (\n <div\n className={cn(\n \"bg-primary/15 hover:bg-primary/20 hover:ring-primary/30 flex h-16 flex-1 items-center rounded-xl transition-shadow hover:ring-1\",\n isPrevious ? \"justify-start\" : \"justify-end\"\n )}\n >\n {isPrevious ? (\n <>\n {labelNode}\n <div className=\"bg-primary/20 h-8 w-px shrink-0\" />\n {metaNode}\n </>\n ) : (\n <>\n {metaNode}\n <div className=\"bg-primary/20 h-8 w-px\" />\n {labelNode}\n </>\n )}\n </div>\n );\n}\n\nexport function PaginationDocs({\n prev,\n next,\n className,\n prevIcon,\n nextIcon,\n linkClassName,\n}: PaginationDocsProps) {\n return (\n <nav\n id=\"pagination\"\n aria-label=\"Pagination\"\n className={cn(\"bg-base-200/50 flex w-full gap-1 rounded-2xl p-1\", className)}\n >\n {prev && (\n <a\n href={prev.href}\n rel=\"prev\"\n data-component-part=\"pagination-prev\"\n className={cn(\n \"group min-w-0 rounded-xl no-underline\",\n next\n ? // Paired with next: minimal link by design (30% of the pill).\n \"text-muted-foreground hover:bg-base-200/60 hover:text-base-content flex w-[calc(30%-2px)] items-center justify-start gap-1.5 rounded-xl px-3 py-3 text-sm transition-colors\"\n : // Alone (last page, no next): rich card mirroring the next-only\n // variant — full width on mobile, half the container above\n // 640px, pushed left like a back button.\n \"w-full sm:mr-auto sm:w-1/2\",\n linkClassName\n )}\n >\n {next ? (\n <>\n {prevIcon && <span className=\"flex shrink-0 items-center\">{prevIcon}</span>}\n <span data-component-part=\"pagination-label\">Previous</span>\n </>\n ) : (\n <PaginationCard\n direction=\"prev\"\n label=\"Previous\"\n title={prev.title}\n description={prev.description}\n icon={prevIcon}\n />\n )}\n </a>\n )}\n {next && (\n <a\n href={next.href}\n rel=\"next\"\n data-component-part=\"pagination-next\"\n className={cn(\n \"group min-w-0 rounded-xl no-underline\",\n // Next-only (e.g. docs index): full width on mobile, half the\n // container above 640px — pushed right like a forward button.\n // With prev: calc-based 70% (minus half the gap) so the pair\n // always fills the pill without overlapping.\n prev ? \"w-[calc(70%-2px)]\" : \"w-full sm:ml-auto sm:w-1/2\",\n linkClassName\n )}\n >\n <PaginationCard\n direction=\"next\"\n label=\"Next\"\n title={next.title}\n description={next.description}\n icon={nextIcon}\n />\n </a>\n )}\n </nav>\n );\n}\n"],"mappings":";;;AAoBA,SAAS,EAAe,EAAE,cAAW,UAAO,UAAO,gBAAa,WAA6B;CAC3F,IAAM,IAAa,MAAc,QAE3B,IACJ,kBAAC,OAAD;EACE,WAAW,EACT,qDACA,IAAa,cAAc,aAC3B,KAAc,UAChB;EALF,UAAA;GAOG,KAAc,KAAQ,kBAAC,QAAD;IAAM,WAAU;IAA8B,UAAA;GAAW,CAAA;GAChF,kBAAC,QAAD;IAAM,uBAAoB;IAAoB,UAAA;GAAY,CAAA;GACzD,CAAC,KAAc,KAAQ,kBAAC,QAAD;IAAM,WAAU;IAA8B,UAAA;GAAW,CAAA;EAC9E;KAGD,IACJ,kBAAC,OAAD;EACE,WAAW,EACT,6CACA,IAAa,0BAA0B,sBACzC;EAJF,UAAA,CAME,kBAAC,OAAD;GACE,uBAAoB;GACpB,WAAU;GAET,UAAA;EACE,CAAA,GACJ,KACC,kBAAC,QAAD;GACE,uBAAoB;GACpB,WAAU;GAET,UAAA;EACG,CAAA,CAEL;;CAGP,OACE,kBAAC,OAAD;EACE,WAAW,EACT,mIACA,IAAa,kBAAkB,aACjC;EAEC,UAAA,IACC,kBAAA,GAAA,EAAA,UAAA;GACG;GACD,kBAAC,OAAD,EAAK,WAAU,kCAAmC,CAAA;GACjD;EACD,EAAA,CAAA,IAEF,kBAAA,GAAA,EAAA,UAAA;GACG;GACD,kBAAC,OAAD,EAAK,WAAU,yBAA0B,CAAA;GACxC;EACD,EAAA,CAAA;CAED,CAAA;AAET;AAEA,SAAgB,EAAe,EAC7B,SACA,SACA,cACA,aACA,aACA,oBACsB;CACtB,OACE,kBAAC,OAAD;EACE,IAAG;EACH,cAAW;EACX,WAAW,EAAG,oDAAoD,CAAS;EAH7E,UAAA,CAKG,KACC,kBAAC,KAAD;GACE,MAAM,EAAK;GACX,KAAI;GACJ,uBAAoB;GACpB,WAAW,EACT,yCACA,IAEI,gLAIA,8BACJ,CACF;GAEC,UAAA,IACC,kBAAA,GAAA,EAAA,UAAA,CACG,KAAY,kBAAC,QAAD;IAAM,WAAU;IAA8B,UAAA;GAAe,CAAA,GAC1E,kBAAC,QAAD;IAAM,uBAAoB;IAAmB,UAAA;GAAc,CAAA,CAC3D,EAAA,CAAA,IAEF,kBAAC,GAAD;IACE,WAAU;IACV,OAAM;IACN,OAAO,EAAK;IACZ,aAAa,EAAK;IAClB,MAAM;GACP,CAAA;EAEF,CAAA,GAEJ,KACC,kBAAC,KAAD;GACE,MAAM,EAAK;GACX,KAAI;GACJ,uBAAoB;GACpB,WAAW,EACT,yCAKA,IAAO,sBAAsB,8BAC7B,CACF;GAEA,UAAA,kBAAC,GAAD;IACE,WAAU;IACV,OAAM;IACN,OAAO,EAAK;IACZ,aAAa,EAAK;IAClB,MAAM;GACP,CAAA;EACA,CAAA,CAEF;;AAET"}
|
package/dist/theme-controller.js
CHANGED
|
@@ -1,48 +1,59 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "./cn.js";
|
|
3
|
-
import { useEffect as t,
|
|
4
|
-
import { jsx as
|
|
3
|
+
import { useEffect as t, useState as n } from "react";
|
|
4
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
5
5
|
//#region src/base/theme-controller.tsx
|
|
6
|
+
function a() {
|
|
7
|
+
try {
|
|
8
|
+
return typeof window > "u" ? null : window.localStorage.getItem("theme");
|
|
9
|
+
} catch {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
6
13
|
function o(e) {
|
|
7
|
-
typeof document < "u" && document.documentElement.classList.toggle("dark", e
|
|
14
|
+
typeof document < "u" && document.documentElement.classList.toggle("dark", e);
|
|
8
15
|
}
|
|
9
16
|
function s(e) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}, [e]);
|
|
17
|
+
try {
|
|
18
|
+
typeof window < "u" && window.localStorage.setItem("theme", e);
|
|
19
|
+
} catch {}
|
|
14
20
|
}
|
|
15
|
-
function c({ defaultTheme:
|
|
16
|
-
let [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
function c({ defaultTheme: c = "light", lightTheme: l = "light", darkTheme: u = "dark", ariaLabel: d = "Toggle dark mode", inputProps: f, onThemeChange: p, className: m, label: h, size: g = "md", children: _ }) {
|
|
22
|
+
let [v, y] = n(() => c === u);
|
|
23
|
+
t(() => {
|
|
24
|
+
let e = (a() ?? c) === u;
|
|
25
|
+
y(e), o(e);
|
|
26
|
+
}, [c, u]);
|
|
27
|
+
let b = (e) => {
|
|
28
|
+
let t = e ? u : l;
|
|
29
|
+
y(e), o(e), s(t), p?.(t);
|
|
21
30
|
};
|
|
22
|
-
if (
|
|
23
|
-
className:
|
|
24
|
-
children:
|
|
25
|
-
isDark:
|
|
26
|
-
checked:
|
|
27
|
-
toggle:
|
|
31
|
+
if (_) return /* @__PURE__ */ r("div", {
|
|
32
|
+
className: m,
|
|
33
|
+
children: _({
|
|
34
|
+
isDark: v,
|
|
35
|
+
checked: v,
|
|
36
|
+
toggle: b
|
|
28
37
|
})
|
|
29
38
|
});
|
|
30
|
-
let
|
|
39
|
+
let x = /* @__PURE__ */ r("input", {
|
|
31
40
|
type: "checkbox",
|
|
32
|
-
className: e("toggle theme-controller", `toggle-${
|
|
33
|
-
checked:
|
|
34
|
-
value:
|
|
35
|
-
|
|
41
|
+
className: e("toggle theme-controller", `toggle-${g}`),
|
|
42
|
+
checked: v,
|
|
43
|
+
value: u,
|
|
44
|
+
"aria-label": d,
|
|
45
|
+
onChange: (e) => b(e.target.checked),
|
|
46
|
+
...f
|
|
36
47
|
});
|
|
37
|
-
return
|
|
38
|
-
className: e("flex cursor-pointer items-center gap-3",
|
|
39
|
-
children: [
|
|
48
|
+
return h ? /* @__PURE__ */ i("label", {
|
|
49
|
+
className: e("flex cursor-pointer items-center gap-3", m),
|
|
50
|
+
children: [x, /* @__PURE__ */ r("span", {
|
|
40
51
|
className: "text-base-content",
|
|
41
|
-
children:
|
|
52
|
+
children: h
|
|
42
53
|
})]
|
|
43
|
-
}) : /* @__PURE__ */
|
|
44
|
-
className:
|
|
45
|
-
children:
|
|
54
|
+
}) : /* @__PURE__ */ r("div", {
|
|
55
|
+
className: m,
|
|
56
|
+
children: x
|
|
46
57
|
});
|
|
47
58
|
}
|
|
48
59
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-controller.js","names":[],"sources":["../src/base/theme-controller.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect,
|
|
1
|
+
{"version":3,"file":"theme-controller.js","names":[],"sources":["../src/base/theme-controller.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState, type InputHTMLAttributes, type ReactNode } from \"react\";\nimport { cn } from \"../utils/cn\";\nimport type { Size } from \"../utils/types\";\n\nfunction readStoredTheme(): string | null {\n try {\n if (typeof window === \"undefined\") return null;\n return window.localStorage.getItem(\"theme\");\n } catch {\n return null;\n }\n}\n\nfunction applyTheme(isDark: boolean) {\n if (typeof document !== \"undefined\") {\n document.documentElement.classList.toggle(\"dark\", isDark);\n }\n}\n\nfunction writeStoredTheme(theme: string) {\n try {\n if (typeof window !== \"undefined\") {\n window.localStorage.setItem(\"theme\", theme);\n }\n } catch {\n // Storage can be unavailable (private mode, blocked cookies); theme still applies in-memory.\n }\n}\n\n// --- ThemeControllerToggle ---\n\nexport interface ThemeControllerToggleProps {\n defaultTheme?: string;\n lightTheme?: string;\n darkTheme?: string;\n ariaLabel?: string;\n inputProps?: Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"type\" | \"checked\" | \"onChange\" | \"value\"\n >;\n onThemeChange?: (theme: string) => void;\n className?: string;\n label?: ReactNode;\n size?: Size;\n children?: (state: {\n isDark: boolean;\n checked: boolean;\n toggle: (checked: boolean) => void;\n }) => ReactNode;\n}\n\nexport function ThemeControllerToggle({\n defaultTheme = \"light\",\n lightTheme = \"light\",\n darkTheme = \"dark\",\n ariaLabel = \"Toggle dark mode\",\n inputProps,\n onThemeChange,\n className,\n label,\n size = \"md\",\n children,\n}: ThemeControllerToggleProps) {\n // Deterministic initial render so SSR and hydration match. Stored theme syncs after mount.\n const [checked, setChecked] = useState(() => defaultTheme === darkTheme);\n\n useEffect(() => {\n const storedTheme = readStoredTheme() ?? defaultTheme;\n const isDark = storedTheme === darkTheme;\n setChecked(isDark);\n applyTheme(isDark);\n }, [defaultTheme, darkTheme]);\n\n const handleChange = (newChecked: boolean) => {\n const newTheme = newChecked ? darkTheme : lightTheme;\n setChecked(newChecked);\n applyTheme(newChecked);\n writeStoredTheme(newTheme);\n onThemeChange?.(newTheme);\n };\n\n if (children) {\n return (\n <div className={className}>\n {children({ isDark: checked, checked, toggle: handleChange })}\n </div>\n );\n }\n\n const toggleEl = (\n <input\n type=\"checkbox\"\n className={cn(\"toggle theme-controller\", `toggle-${size}`)}\n checked={checked}\n value={darkTheme}\n aria-label={ariaLabel}\n onChange={(e) => handleChange(e.target.checked)}\n {...inputProps}\n />\n );\n\n if (!label) return <div className={className}>{toggleEl}</div>;\n return (\n <label className={cn(\"flex cursor-pointer items-center gap-3\", className)}>\n {toggleEl}\n <span className=\"text-base-content\">{label}</span>\n </label>\n );\n}\n"],"mappings":";;;;;AAMA,SAAS,IAAiC;CACxC,IAAI;EAEF,OADI,OAAO,SAAW,MAAoB,OACnC,OAAO,aAAa,QAAQ,OAAO;CAC5C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,EAAW,GAAiB;CACnC,AAAI,OAAO,WAAa,OACtB,SAAS,gBAAgB,UAAU,OAAO,QAAQ,CAAM;AAE5D;AAEA,SAAS,EAAiB,GAAe;CACvC,IAAI;EACF,AAAI,OAAO,SAAW,OACpB,OAAO,aAAa,QAAQ,SAAS,CAAK;CAE9C,QAAQ,CAER;AACF;AAwBA,SAAgB,EAAsB,EACpC,kBAAe,SACf,gBAAa,SACb,eAAY,QACZ,eAAY,oBACZ,eACA,kBACA,cACA,UACA,UAAO,MACP,eAC6B;CAE7B,IAAM,CAAC,GAAS,KAAc,QAAe,MAAiB,CAAS;CAEvE,QAAgB;EAEd,IAAM,KADc,EAAgB,KAAK,OACV;EAE/B,AADA,EAAW,CAAM,GACjB,EAAW,CAAM;CACnB,GAAG,CAAC,GAAc,CAAS,CAAC;CAE5B,IAAM,KAAgB,MAAwB;EAC5C,IAAM,IAAW,IAAa,IAAY;EAI1C,AAHA,EAAW,CAAU,GACrB,EAAW,CAAU,GACrB,EAAiB,CAAQ,GACzB,IAAgB,CAAQ;CAC1B;CAEA,IAAI,GACF,OACE,kBAAC,OAAD;EAAgB;EACb,UAAA,EAAS;GAAE,QAAQ;GAAS;GAAS,QAAQ;EAAa,CAAC;CACzD,CAAA;CAIT,IAAM,IACJ,kBAAC,SAAD;EACE,MAAK;EACL,WAAW,EAAG,2BAA2B,UAAU,GAAM;EAChD;EACT,OAAO;EACP,cAAY;EACZ,WAAW,MAAM,EAAa,EAAE,OAAO,OAAO;EAC9C,GAAI;CACL,CAAA;CAIH,OADK,IAEH,kBAAC,SAAD;EAAO,WAAW,EAAG,0CAA0C,CAAS;EAAxE,UAAA,CACG,GACD,kBAAC,QAAD;GAAM,WAAU;GAAqB,UAAA;EAAY,CAAA,CAC5C;MALU,kBAAC,OAAD;EAAgB;EAAY,UAAA;CAAc,CAAA;AAO/D"}
|
package/dist/toggle.js
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "./cn.js";
|
|
3
|
-
import { forwardRef as t,
|
|
4
|
-
import { jsx as
|
|
3
|
+
import { forwardRef as t, useCallback as n, useEffect as r, useRef as i, useState as a } from "react";
|
|
4
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
5
5
|
//#region src/base/toggle.tsx
|
|
6
|
-
var
|
|
7
|
-
n(() => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}, [
|
|
13
|
-
let
|
|
14
|
-
ref:
|
|
6
|
+
var c = t(function({ color: t = "primary", size: a = "md", label: c, description: l, indeterminate: u = !1, containerClassName: d, labelClassName: f, descriptionClassName: p, className: m, disabled: h, checked: g, defaultChecked: _, onChange: v, ...y }, b) {
|
|
7
|
+
let x = i(null), S = n((e) => {
|
|
8
|
+
x.current = e, typeof b == "function" ? b(e) : b && (b.current = e);
|
|
9
|
+
}, [b]);
|
|
10
|
+
r(() => {
|
|
11
|
+
x.current && (x.current.indeterminate = u);
|
|
12
|
+
}, [u]);
|
|
13
|
+
let C = /* @__PURE__ */ o("input", {
|
|
14
|
+
ref: S,
|
|
15
15
|
type: "checkbox",
|
|
16
|
-
className: e(`toggle-${t}`, `toggle-${
|
|
17
|
-
disabled:
|
|
18
|
-
checked:
|
|
19
|
-
defaultChecked:
|
|
20
|
-
onChange:
|
|
21
|
-
"data-indeterminate":
|
|
22
|
-
...
|
|
16
|
+
className: e("toggle", `toggle-${t}`, `toggle-${a}`, m),
|
|
17
|
+
disabled: h,
|
|
18
|
+
checked: g,
|
|
19
|
+
defaultChecked: _,
|
|
20
|
+
onChange: v,
|
|
21
|
+
"data-indeterminate": u,
|
|
22
|
+
...y
|
|
23
23
|
});
|
|
24
|
-
return
|
|
25
|
-
className: e("flex items-start gap-3",
|
|
26
|
-
children: [/* @__PURE__ */
|
|
24
|
+
return c ? /* @__PURE__ */ s("label", {
|
|
25
|
+
className: e("flex items-start gap-3", h && "cursor-not-allowed opacity-50", d),
|
|
26
|
+
children: [/* @__PURE__ */ o("div", {
|
|
27
27
|
className: "flex items-center pt-0.5",
|
|
28
|
-
children:
|
|
29
|
-
}), /* @__PURE__ */
|
|
28
|
+
children: C
|
|
29
|
+
}), /* @__PURE__ */ s("div", {
|
|
30
30
|
className: "flex flex-col gap-0.5",
|
|
31
|
-
children: [/* @__PURE__ */
|
|
32
|
-
className: e("text-base-content cursor-pointer",
|
|
33
|
-
children:
|
|
34
|
-
}),
|
|
35
|
-
className: e("text-base-content/60 text-sm",
|
|
36
|
-
children:
|
|
31
|
+
children: [/* @__PURE__ */ o("span", {
|
|
32
|
+
className: e("text-base-content cursor-pointer", f),
|
|
33
|
+
children: c
|
|
34
|
+
}), l && /* @__PURE__ */ o("span", {
|
|
35
|
+
className: e("text-base-content/60 text-sm", p),
|
|
36
|
+
children: l
|
|
37
37
|
})]
|
|
38
38
|
})]
|
|
39
|
-
}) :
|
|
39
|
+
}) : C;
|
|
40
40
|
});
|
|
41
|
-
function
|
|
42
|
-
let [f, p] = r
|
|
41
|
+
function l({ items: t, value: n, defaultValue: r = [], onChange: i, color: c = "primary", size: l = "md", controlled: u = !1, className: d }) {
|
|
42
|
+
let [f, p] = a(r), m = u ? n ?? f : f, h = (e) => {
|
|
43
43
|
let t = m.includes(e) ? m.filter((t) => t !== e) : [...m, e];
|
|
44
|
-
u || p(t),
|
|
44
|
+
u || p(t), i?.(t);
|
|
45
45
|
};
|
|
46
|
-
return /* @__PURE__ */
|
|
46
|
+
return /* @__PURE__ */ o("div", {
|
|
47
47
|
className: e("flex flex-col gap-3", d),
|
|
48
|
-
children: t.map((t) => /* @__PURE__ */
|
|
48
|
+
children: t.map((t) => /* @__PURE__ */ s("label", {
|
|
49
49
|
className: e("flex items-center gap-3", t.disabled && "cursor-not-allowed opacity-50"),
|
|
50
|
-
children: [/* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ o("input", {
|
|
51
51
|
type: "checkbox",
|
|
52
|
-
className: e(`toggle-${c}`, `toggle-${l}`),
|
|
52
|
+
className: e("toggle", `toggle-${c}`, `toggle-${l}`),
|
|
53
53
|
checked: m.includes(t.value),
|
|
54
54
|
disabled: t.disabled,
|
|
55
55
|
onChange: () => !t.disabled && h(t.value)
|
|
56
|
-
}), /* @__PURE__ */
|
|
56
|
+
}), /* @__PURE__ */ o("span", {
|
|
57
57
|
className: "text-base-content cursor-pointer",
|
|
58
58
|
children: t.label
|
|
59
59
|
})]
|
|
@@ -61,6 +61,6 @@ function s({ items: t, value: n, defaultValue: o = [], onChange: s, color: c = "
|
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
//#endregion
|
|
64
|
-
export {
|
|
64
|
+
export { c as Toggle, l as ToggleGroup };
|
|
65
65
|
|
|
66
66
|
//# sourceMappingURL=toggle.js.map
|
package/dist/toggle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.js","names":[],"sources":["../src/base/toggle.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../utils/cn\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { forwardRef, useState, useEffect } from \"react\";\nimport type { Color, Size } from \"../utils/types\";\n\ntype ToggleColor = Color;\ntype ToggleSize = Size;\n\ninterface ToggleProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\" | \"size\"> {\n color?: ToggleColor;\n size?: ToggleSize;\n label?: ReactNode;\n description?: ReactNode;\n indeterminate?: boolean;\n containerClassName?: string;\n labelClassName?: string;\n descriptionClassName?: string;\n}\n\nconst Toggle = forwardRef<HTMLInputElement, ToggleProps>(function Toggle(\n {\n color = \"primary\",\n size = \"md\",\n label,\n description,\n indeterminate = false,\n containerClassName,\n labelClassName,\n descriptionClassName,\n className,\n disabled,\n checked,\n defaultChecked,\n onChange,\n ...props\n },\n ref\n) {\n
|
|
1
|
+
{"version":3,"file":"toggle.js","names":[],"sources":["../src/base/toggle.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"../utils/cn\";\nimport type { InputHTMLAttributes, ReactNode } from \"react\";\nimport { forwardRef, useState, useEffect, useRef, useCallback } from \"react\";\nimport type { Color, Size } from \"../utils/types\";\n\ntype ToggleColor = Color;\ntype ToggleSize = Size;\n\ninterface ToggleProps extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\" | \"size\"> {\n color?: ToggleColor;\n size?: ToggleSize;\n label?: ReactNode;\n description?: ReactNode;\n indeterminate?: boolean;\n containerClassName?: string;\n labelClassName?: string;\n descriptionClassName?: string;\n}\n\nconst Toggle = forwardRef<HTMLInputElement, ToggleProps>(function Toggle(\n {\n color = \"primary\",\n size = \"md\",\n label,\n description,\n indeterminate = false,\n containerClassName,\n labelClassName,\n descriptionClassName,\n className,\n disabled,\n checked,\n defaultChecked,\n onChange,\n ...props\n },\n ref\n) {\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n const setInputRef = useCallback(\n (el: HTMLInputElement | null) => {\n inputRef.current = el;\n if (typeof ref === \"function\") ref(el);\n else if (ref) ref.current = el;\n },\n [ref]\n );\n\n useEffect(() => {\n if (inputRef.current) inputRef.current.indeterminate = indeterminate;\n }, [indeterminate]);\n\n const toggleEl = (\n <input\n ref={setInputRef}\n type=\"checkbox\"\n className={cn(\"toggle\", `toggle-${color}`, `toggle-${size}`, className)}\n disabled={disabled}\n checked={checked}\n defaultChecked={defaultChecked}\n onChange={onChange}\n data-indeterminate={indeterminate}\n {...props}\n />\n );\n\n if (!label) return toggleEl;\n\n return (\n <label\n className={cn(\n \"flex items-start gap-3\",\n disabled && \"cursor-not-allowed opacity-50\",\n containerClassName\n )}\n >\n <div className=\"flex items-center pt-0.5\">{toggleEl}</div>\n <div className=\"flex flex-col gap-0.5\">\n <span className={cn(\"text-base-content cursor-pointer\", labelClassName)}>{label}</span>\n {description && (\n <span className={cn(\"text-base-content/60 text-sm\", descriptionClassName)}>\n {description}\n </span>\n )}\n </div>\n </label>\n );\n});\n\ninterface ToggleGroupItem {\n value: string;\n label: ReactNode;\n disabled?: boolean;\n}\n\ninterface ToggleGroupProps {\n items: ToggleGroupItem[];\n value?: string[];\n defaultValue?: string[];\n onChange?: (value: string[]) => void;\n color?: ToggleColor;\n size?: ToggleSize;\n controlled?: boolean;\n className?: string;\n}\n\nexport function ToggleGroup({\n items,\n value,\n defaultValue = [],\n onChange,\n color = \"primary\",\n size = \"md\",\n controlled = false,\n className,\n}: ToggleGroupProps) {\n const [internalValue, setInternalValue] = useState<string[]>(defaultValue);\n const selectedValues = controlled ? (value ?? internalValue) : internalValue;\n\n const toggle = (itemValue: string) => {\n const next = selectedValues.includes(itemValue)\n ? selectedValues.filter((v) => v !== itemValue)\n : [...selectedValues, itemValue];\n if (!controlled) setInternalValue(next);\n onChange?.(next);\n };\n\n return (\n <div className={cn(\"flex flex-col gap-3\", className)}>\n {items.map((item) => (\n <label\n key={item.value}\n className={cn(\n \"flex items-center gap-3\",\n item.disabled && \"cursor-not-allowed opacity-50\"\n )}\n >\n <input\n type=\"checkbox\"\n className={cn(\"toggle\", `toggle-${color}`, `toggle-${size}`)}\n checked={selectedValues.includes(item.value)}\n disabled={item.disabled}\n onChange={() => !item.disabled && toggle(item.value)}\n />\n <span className=\"text-base-content cursor-pointer\">{item.label}</span>\n </label>\n ))}\n </div>\n );\n}\n\nexport { Toggle };\nexport type { ToggleProps, ToggleGroupProps, ToggleGroupItem, ToggleColor, ToggleSize };\n"],"mappings":";;;;;AAqBA,IAAM,IAAS,EAA0C,SACvD,EACE,WAAQ,WACR,UAAO,MACP,UACA,gBACA,mBAAgB,IAChB,uBACA,mBACA,yBACA,cACA,aACA,YACA,mBACA,aACA,GAAG,KAEL,GACA;CACA,IAAM,IAAW,EAAgC,IAAI,GAE/C,IAAc,GACjB,MAAgC;EAE/B,AADA,EAAS,UAAU,GACf,OAAO,KAAQ,aAAY,EAAI,CAAE,IAC5B,MAAK,EAAI,UAAU;CAC9B,GACA,CAAC,CAAG,CACN;CAEA,QAAgB;EACd,AAAI,EAAS,YAAS,EAAS,QAAQ,gBAAgB;CACzD,GAAG,CAAC,CAAa,CAAC;CAElB,IAAM,IACJ,kBAAC,SAAD;EACE,KAAK;EACL,MAAK;EACL,WAAW,EAAG,UAAU,UAAU,KAAS,UAAU,KAAQ,CAAS;EAC5D;EACD;EACO;EACN;EACV,sBAAoB;EACpB,GAAI;CACL,CAAA;CAKH,OAFK,IAGH,kBAAC,SAAD;EACE,WAAW,EACT,0BACA,KAAY,iCACZ,CACF;EALF,UAAA,CAOE,kBAAC,OAAD;GAAK,WAAU;GAA4B,UAAA;EAAc,CAAA,GACzD,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,QAAD;IAAM,WAAW,EAAG,oCAAoC,CAAc;IAAI,UAAA;GAAY,CAAA,GACrF,KACC,kBAAC,QAAD;IAAM,WAAW,EAAG,gCAAgC,CAAoB;IACrE,UAAA;GACG,CAAA,CAEL;EACA,CAAA,CAAA;MAnBU;AAqBrB,CAAC;AAmBD,SAAgB,EAAY,EAC1B,UACA,UACA,kBAAe,CAAC,GAChB,aACA,WAAQ,WACR,UAAO,MACP,gBAAa,IACb,gBACmB;CACnB,IAAM,CAAC,GAAe,KAAoB,EAAmB,CAAY,GACnE,IAAiB,IAAc,KAAS,IAAiB,GAEzD,KAAU,MAAsB;EACpC,IAAM,IAAO,EAAe,SAAS,CAAS,IAC1C,EAAe,QAAQ,MAAM,MAAM,CAAS,IAC5C,CAAC,GAAG,GAAgB,CAAS;EAEjC,AADK,KAAY,EAAiB,CAAI,GACtC,IAAW,CAAI;CACjB;CAEA,OACE,kBAAC,OAAD;EAAK,WAAW,EAAG,uBAAuB,CAAS;EAChD,UAAA,EAAM,KAAK,MACV,kBAAC,SAAD;GAEE,WAAW,EACT,2BACA,EAAK,YAAY,+BACnB;GALF,UAAA,CAOE,kBAAC,SAAD;IACE,MAAK;IACL,WAAW,EAAG,UAAU,UAAU,KAAS,UAAU,GAAM;IAC3D,SAAS,EAAe,SAAS,EAAK,KAAK;IAC3C,UAAU,EAAK;IACf,gBAAgB,CAAC,EAAK,YAAY,EAAO,EAAK,KAAK;GACpD,CAAA,GACD,kBAAC,QAAD;IAAM,WAAU;IAAoC,UAAA,EAAK;GAAY,CAAA,CAChE;EAdA,GAAA,EAAK,KAcL,CACR;CACE,CAAA;AAET"}
|
package/package.json
CHANGED
package/styles.css
CHANGED
|
@@ -2,3 +2,20 @@
|
|
|
2
2
|
to this file, so consumers can import this stylesheet from any install
|
|
3
3
|
layout and the component classes are still scanned. */
|
|
4
4
|
@source "./src";
|
|
5
|
+
|
|
6
|
+
/* Dynamic variants built via template interpolation (`toggle-${color}`,
|
|
7
|
+
`input-${color}`, `kbd-${size}`, `modal-${placement}`,
|
|
8
|
+
`${breakpoint}:drawer-open`) are invisible to Tailwind's scanner, so
|
|
9
|
+
safelist the full variant sets here. Standalone consumers get them without
|
|
10
|
+
needing their own @source inline. */
|
|
11
|
+
@source inline(
|
|
12
|
+
"toggle toggle-primary toggle-secondary toggle-accent toggle-neutral toggle-success toggle-warning toggle-info toggle-error"
|
|
13
|
+
);
|
|
14
|
+
@source inline("toggle-xs toggle-sm toggle-md toggle-lg");
|
|
15
|
+
@source inline(
|
|
16
|
+
"input-primary input-secondary input-accent input-neutral input-success input-warning input-info input-error"
|
|
17
|
+
);
|
|
18
|
+
@source inline("input-xs input-sm input-md input-lg input-xl");
|
|
19
|
+
@source inline("kbd-xs kbd-sm kbd-md kbd-lg kbd-xl");
|
|
20
|
+
@source inline("modal-top modal-middle modal-bottom");
|
|
21
|
+
@source inline("sm:drawer-open md:drawer-open lg:drawer-open xl:drawer-open 2xl:drawer-open");
|