@studiocubics/components 0.0.20 → 0.0.22
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/Cards/CollectionItemCard/CollectionItemCard.d.ts +1 -1
- package/dist/Cards/CollectionItemCard/CollectionItemCard.js +1 -1
- package/dist/Cards/CollectionItemCard/CollectionItemCard.js.map +1 -1
- package/dist/Display/Accordion/Accordion.js +1 -1
- package/dist/Display/Accordion/Accordion.js.map +1 -1
- package/dist/Display/Toast/Toaster.js +1 -1
- package/dist/Display/Toast/Toaster.js.map +1 -1
- package/dist/Display/Toast/toast.js +1 -1
- package/dist/Display/Toast/toast.js.map +1 -1
- package/dist/Inputs/CloseButton/CloseButton.js +1 -1
- package/dist/Inputs/CloseButton/CloseButton.js.map +1 -1
- package/dist/Inputs/Switch/Switch.d.ts +5 -5
- package/dist/Inputs/Switch/Switch.js +1 -1
- package/dist/Inputs/Switch/Switch.js.map +1 -1
- package/dist/Layout/Drawer/Drawer.js +1 -1
- package/dist/Layout/Drawer/Drawer.js.map +1 -1
- package/dist/Navigation/Breadcrumbs/useBreadcrumbs.js +1 -1
- package/dist/Navigation/Breadcrumbs/useBreadcrumbs.js.map +1 -1
- package/package.json +4 -4
|
@@ -27,7 +27,7 @@ export interface CollectionItemCardBaseProps {
|
|
|
27
27
|
footerContainer?: ComponentProps<"div">;
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
declare const defaultElement = "
|
|
30
|
+
declare const defaultElement = "div";
|
|
31
31
|
type DefaultElement = typeof defaultElement;
|
|
32
32
|
/**
|
|
33
33
|
* Polymorphic props for the CollectionItemCard component.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as i}from"react/jsx-runtime";import t from"./CollectionItemCard.module.css.js";import{cn as s}from"@studiocubics/utils";import{ClampedText as a}from"../../Typography/ClampedText/ClampedText.js";import{Chip as l}from"../../Display/Chip/Chip.js";function
|
|
1
|
+
"use client";import{jsxs as e,jsx as i}from"react/jsx-runtime";import t from"./CollectionItemCard.module.css.js";import{cn as s}from"@studiocubics/utils";import{ClampedText as a}from"../../Typography/ClampedText/ClampedText.js";import{Chip as l}from"../../Display/Chip/Chip.js";function r(r){const{as:o,className:c,ref:m,thumbnail:n,title:d,chip:p,subtitle:h,description:f,footer:u,slotProps:N={},...C}=r,b=o||(r.href?"a":"div"),v=!!r.href||!!r.onClick,y={className:s(c,t.main),ref:m,...C};return e("div",{...N.root,className:s(t.root,v?t.clickable:"",N.root?.className),children:[n&&i("div",{...N.thumbnail,className:s(t.image,N.thumbnail?.className),children:n}),e(b,{...y,children:[e("div",{...N.titleContainer,className:s(t.title,N.titleContainer?.className),children:[p&&("string"==typeof p?i(l,{size:"sm",...N.chip,children:p}):p),i(a,{as:"h4",...N.title,children:d})]}),h&&i(a,{...N.subtitle,as:"div",className:s(t.subtitle,N.subtitle?.className),children:h}),f&&i(a,{...N.description,as:"div",className:s(t.description,N.description?.className),children:f})]}),u&&i("div",{...N.footerContainer,className:s(t.footer,N.footerContainer?.className),children:u})]})}r.displayName="CollectionItemCard";const o=r;export{o as CollectionItemCard};
|
|
2
2
|
//# sourceMappingURL=CollectionItemCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollectionItemCard.js","sources":["../../../src/Cards/CollectionItemCard/CollectionItemCard.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, ElementType, ReactNode } from \"react\";\nimport styles from \"./CollectionItemCard.module.css\";\nimport type {\n PolymorphicComponentProps,\n PolymorphicComponentType,\n} from \"@studiocubics/types\";\nimport { cn } from \"@studiocubics/utils\";\nimport {\n ClampedText,\n type ClampedTextProps,\n} from \"../../Typography/ClampedText/ClampedText\";\nimport { Chip, type ChipProps } from \"../../Display/Chip/Chip\";\n/**\n * Props specific to the CollectionItemCard component.\n *\n * These extend the intrinsic element props of whatever element is passed via `as`.\n * @group CollectionItemCard\n * @category Cards\n */\nexport interface CollectionItemCardBaseProps {\n thumbnail?: ReactNode;\n title: ReactNode;\n chip?: ReactNode;\n subtitle?: ReactNode;\n description?: ReactNode;\n footer?: ReactNode;\n slotProps?: {\n // TODO rename to container\n root?: ComponentProps<\"div\">;\n chip?: ChipProps;\n thumbnail?: ComponentProps<\"div\">;\n titleContainer?: ComponentProps<\"div\">;\n title?: ClampedTextProps;\n subtitle?: ClampedTextProps;\n description?: ClampedTextProps;\n footerContainer?: ComponentProps<\"div\">;\n };\n}\nconst defaultElement = \"
|
|
1
|
+
{"version":3,"file":"CollectionItemCard.js","sources":["../../../src/Cards/CollectionItemCard/CollectionItemCard.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, ElementType, ReactNode } from \"react\";\nimport styles from \"./CollectionItemCard.module.css\";\nimport type {\n PolymorphicComponentProps,\n PolymorphicComponentType,\n} from \"@studiocubics/types\";\nimport { cn } from \"@studiocubics/utils\";\nimport {\n ClampedText,\n type ClampedTextProps,\n} from \"../../Typography/ClampedText/ClampedText\";\nimport { Chip, type ChipProps } from \"../../Display/Chip/Chip\";\n/**\n * Props specific to the CollectionItemCard component.\n *\n * These extend the intrinsic element props of whatever element is passed via `as`.\n * @group CollectionItemCard\n * @category Cards\n */\nexport interface CollectionItemCardBaseProps {\n thumbnail?: ReactNode;\n title: ReactNode;\n chip?: ReactNode;\n subtitle?: ReactNode;\n description?: ReactNode;\n footer?: ReactNode;\n slotProps?: {\n // TODO rename to container\n root?: ComponentProps<\"div\">;\n chip?: ChipProps;\n thumbnail?: ComponentProps<\"div\">;\n titleContainer?: ComponentProps<\"div\">;\n title?: ClampedTextProps;\n subtitle?: ClampedTextProps;\n description?: ClampedTextProps;\n footerContainer?: ComponentProps<\"div\">;\n };\n}\nconst defaultElement = \"div\";\ntype DefaultElement = typeof defaultElement;\n/**\n * Polymorphic props for the CollectionItemCard component.\n *\n * `C` defines the element type rendered by the component (e.g. `\"CollectionItemCard\"`, `\"a\"`, `\"div\"`).\n * All intrinsic props for `C` are supported unless overridden by `CollectionItemCardBaseProps`.\n *\n * @group CollectionItemCard\n * @category Cards\n */\nexport type CollectionItemCardProps<C extends ElementType = DefaultElement> =\n PolymorphicComponentProps<C, CollectionItemCardBaseProps>;\n\n/**\n * Base implementation for the CollectionItemCard component.\n *\n * This is a polymorphic component that defaults to rendering a `<CollectionItemCard>`.\n * Use the `as` prop to change the underlying element.\n *\n * @typeParam C - The intrinsic or custom element type to render.\n *\n * @group CollectionItemCard\n * @category Cards\n */\nfunction CollectionItemCardBase<C extends ElementType = DefaultElement>(\n props: CollectionItemCardProps<C>,\n) {\n const {\n as,\n className,\n ref,\n thumbnail,\n title,\n chip,\n subtitle,\n description,\n footer,\n slotProps = {},\n ...restProps\n } = props;\n const Component = as || (props.href ? \"a\" : defaultElement);\n\n const clickable = !!props.href || !!props.onClick;\n const componentProps = {\n className: cn(className, styles.main),\n ref,\n ...restProps,\n };\n\n return (\n <div\n // TODO rename to container\n {...slotProps.root}\n className={cn(\n styles.root,\n clickable ? styles.clickable : \"\",\n slotProps.root?.className,\n )}\n >\n {thumbnail && (\n <div\n {...slotProps.thumbnail}\n className={cn(styles.image, slotProps.thumbnail?.className)}\n >\n {thumbnail}\n </div>\n )}\n <Component {...componentProps}>\n <div\n {...slotProps.titleContainer}\n className={cn(styles.title, slotProps.titleContainer?.className)}\n >\n {chip &&\n (typeof chip == \"string\" ? (\n <Chip size=\"sm\" {...slotProps.chip}>\n {chip}\n </Chip>\n ) : (\n chip\n ))}\n <ClampedText as=\"h4\" {...slotProps.title}>\n {title}\n </ClampedText>\n </div>\n {subtitle && (\n <ClampedText\n {...slotProps.subtitle}\n as=\"div\"\n className={cn(styles.subtitle, slotProps.subtitle?.className)}\n >\n {subtitle}\n </ClampedText>\n )}\n {description && (\n <ClampedText\n {...slotProps.description}\n as=\"div\"\n className={cn(styles.description, slotProps.description?.className)}\n >\n {description}\n </ClampedText>\n )}\n </Component>\n {footer && (\n <div\n {...slotProps.footerContainer}\n className={cn(styles.footer, slotProps.footerContainer?.className)}\n >\n {footer}\n </div>\n )}\n </div>\n );\n}\nCollectionItemCardBase.displayName = \"CollectionItemCard\";\n\n/**\n * A polymorphic CollectionItemCard component.\n *\n * By default it renders a `<CollectionItemCard>`, but any element can be used via the `as` prop:\n *\n * ```tsx\n * <CollectionItemCard as=\"a\" href=\"/docs\">Read docs</CollectionItemCard>\n * ```\n *\n * @group CollectionItemCard\n * @category Cards\n */\nexport const CollectionItemCard =\n CollectionItemCardBase as PolymorphicComponentType<\n CollectionItemCardBaseProps,\n DefaultElement\n >;\n"],"names":["CollectionItemCardBase","props","as","className","ref","thumbnail","title","chip","subtitle","description","footer","slotProps","restProps","Component","href","clickable","onClick","componentProps","cn","styles","main","_jsxs","root","children","_jsx","image","titleContainer","Chip","size","ClampedText","footerContainer","displayName","CollectionItemCard"],"mappings":"sRAiEA,SAASA,EACPC,GAEA,MAAMC,GACJA,EAAEC,UACFA,EAASC,IACTA,EAAGC,UACHA,EAASC,MACTA,EAAKC,KACLA,EAAIC,SACJA,EAAQC,YACRA,EAAWC,OACXA,EAAMC,UACNA,EAAY,CAAA,KACTC,GACDX,EACEY,EAAYX,IAAOD,EAAMa,KAAO,IAzCjB,OA2CfC,IAAcd,EAAMa,QAAUb,EAAMe,QACpCC,EAAiB,CACrBd,UAAWe,EAAGf,EAAWgB,EAAOC,MAChChB,SACGQ,GAGL,OACES,EAAA,MAAA,IAEMV,EAAUW,KACdnB,UAAWe,EACTC,EAAOG,KACPP,EAAYI,EAAOJ,UAAY,GAC/BJ,EAAUW,MAAMnB,WACjBoB,SAAA,CAEAlB,GACCmB,YACMb,EAAUN,UACdF,UAAWe,EAAGC,EAAOM,MAAOd,EAAUN,WAAWF,oBAEhDE,IAGLgB,EAACR,EAAS,IAAKI,EAAcM,SAAA,CAC3BF,EAAA,MAAA,IACMV,EAAUe,eACdvB,UAAWe,EAAGC,EAAOb,MAAOK,EAAUe,gBAAgBvB,qBAErDI,IACiB,iBAARA,EACNiB,EAACG,EAAI,CAACC,KAAK,QAASjB,EAAUJ,KAAIgB,SAC/BhB,IACI,GAIXiB,EAACK,EAAW,CAAC3B,GAAG,QAASS,EAAUL,eAChCA,OAGJE,GACCgB,EAACK,EAAW,IACNlB,EAAUH,SACdN,GAAG,MACHC,UAAWe,EAAGC,EAAOX,SAAUG,EAAUH,UAAUL,WAAUoB,SAE5Df,IAGJC,GACCe,EAACK,EAAW,IACNlB,EAAUF,YACdP,GAAG,MACHC,UAAWe,EAAGC,EAAOV,YAAaE,EAAUF,aAAaN,WAAUoB,SAElEd,OAINC,GACCc,EAAA,MAAA,IACMb,EAAUmB,gBACd3B,UAAWe,EAAGC,EAAOT,OAAQC,EAAUmB,iBAAiB3B,WAAUoB,SAEjEb,MAKX,CACAV,EAAuB+B,YAAc,qBAc9B,MAAMC,EACXhC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as e}from"react/jsx-runtime";import{createContext as r,useState as
|
|
1
|
+
"use client";import{jsx as e}from"react/jsx-runtime";import{createContext as r,useState as t,useRef as n,useCallback as l}from"react";const u=r(null);function c({children:r,exclusive:c=!1,onChange:i}){const[o,s]=t([]),a=n(-1),m={values:o,register:l(()=>{const e=a.current++;return s(e=>[...e,!1]),e},[]),update:l((e,r)=>{s(t=>{let n=c&&r?new Array(t.length).fill(!1):[...t];return n[e]=r,i?.(n),n})},[c,i])};return e(u.Provider,{value:m,children:r})}export{c as Accordion,u as AccordionContext};
|
|
2
2
|
//# sourceMappingURL=Accordion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.js","sources":["../../../src/Display/Accordion/Accordion.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\ninterface AccordionContextProps {\n values: boolean[];\n register: () => number;\n update: (index: number, checked: boolean) => void;\n}\ninterface AccordionProviderProps {\n children: ReactNode;\n exclusive?: boolean;\n onChange?: (checked: boolean[]) => void;\n}\n\nexport const AccordionContext = createContext<AccordionContextProps | null>(\n null,\n);\n\nexport function Accordion({\n children,\n exclusive = false,\n onChange,\n}: AccordionProviderProps) {\n const [values, setValues] = useState<boolean[]>([]);\n const indexRef = useRef(-1);\n\n const register = useCallback(() => {\n const index = indexRef.current++;\n setValues((prev) => [...prev, false]);\n return index;\n }, []);\n\n const update = useCallback(\n (index: number, checked: boolean) => {\n
|
|
1
|
+
{"version":3,"file":"Accordion.js","sources":["../../../src/Display/Accordion/Accordion.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n type ReactNode,\n useCallback,\n useRef,\n useState,\n} from \"react\";\n\ninterface AccordionContextProps {\n values: boolean[];\n register: () => number;\n update: (index: number, checked: boolean) => void;\n}\ninterface AccordionProviderProps {\n children: ReactNode;\n exclusive?: boolean;\n onChange?: (checked: boolean[]) => void;\n}\n\nexport const AccordionContext = createContext<AccordionContextProps | null>(\n null,\n);\n\nexport function Accordion({\n children,\n exclusive = false,\n onChange,\n}: AccordionProviderProps) {\n const [values, setValues] = useState<boolean[]>([]);\n const indexRef = useRef(-1);\n\n const register = useCallback(() => {\n const index = indexRef.current++;\n setValues((prev) => [...prev, false]);\n return index;\n }, []);\n\n const update = useCallback(\n (index: number, checked: boolean) => {\n setValues((prev) => {\n let next =\n exclusive && checked ? new Array(prev.length).fill(false) : [...prev];\n next[index] = checked;\n onChange?.(next);\n return next;\n });\n },\n [exclusive, onChange],\n );\n const context = { values, register, update };\n\n return (\n <AccordionContext.Provider value={context}>\n {children}\n </AccordionContext.Provider>\n );\n}\n"],"names":["AccordionContext","createContext","Accordion","children","exclusive","onChange","values","setValues","useState","indexRef","useRef","context","register","useCallback","index","current","prev","update","checked","next","Array","length","fill","_jsx","Provider","value"],"mappings":"4IAqBaA,EAAmBC,EAC9B,MAGI,SAAUC,GAAUC,SACxBA,EAAQC,UACRA,GAAY,EAAKC,SACjBA,IAEA,MAAOC,EAAQC,GAAaC,EAAoB,IAC1CC,EAAWC,MAoBXC,EAAU,CAAEL,SAAQM,SAlBTC,EAAY,KAC3B,MAAMC,EAAQL,EAASM,UAEvB,OADAR,EAAWS,GAAS,IAAIA,GAAM,IACvBF,GACN,IAciCG,OAZrBJ,EACb,CAACC,EAAeI,KACdX,EAAWS,IACT,IAAIG,EACFf,GAAac,EAAU,IAAIE,MAAMJ,EAAKK,QAAQC,MAAK,GAAS,IAAIN,GAGlE,OAFAG,EAAKL,GAASI,EACdb,IAAWc,GACJA,KAGX,CAACf,EAAWC,KAId,OACEkB,EAACvB,EAAiBwB,SAAQ,CAACC,MAAOd,EAAOR,SACtCA,GAGP"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsx as t,jsxs as o}from"react/jsx-runtime";import{useState as e,useEffect as s}from"react";import{GlassCard as i}from"../../Cards/GlassCard/GlassCard.js";import{Button as n}from"../../Inputs/Button/Button.js";import{subscribe as r,dismiss as a,addDismissInterceptor as d}from"./toast.js";import
|
|
1
|
+
"use client";import{jsx as t,jsxs as o}from"react/jsx-runtime";import{useState as e,useEffect as s}from"react";import{GlassCard as i}from"../../Cards/GlassCard/GlassCard.js";import{Button as n}from"../../Inputs/Button/Button.js";import{subscribe as r,dismiss as a,addDismissInterceptor as d}from"./toast.js";import p from"./Toaster.module.css.js";function u(e){const{width:s=24,height:i=s,...n}=e;return o("svg",{fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",...n,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:s,height:i,children:[t("path",{d:"M18 6 6 18"}),t("path",{d:"m6 6 12 12"})]})}function m(o){const{defaultPosition:i="top right",peekGap:n=12,exitDuration:a=200,maxToastCount:u=5}=o,[m,c]=e([]),[h,f]=e(new Set);return s(()=>r(c,u),[]),s(()=>{d((t,o)=>{f(e=>{if(e.has(t))return e;const s=new Set(e).add(t);return setTimeout(()=>{o(),f(o=>{const e=new Set(o);return e.delete(t),e})},a),s})})},[a]),t("div",{className:p.root,children:m.map((o,e)=>t(l,{toast:o,defaultPosition:i,dismissing:h,peekGap:n,toasts:m,index:e},o.id))})}function l({toast:s,defaultPosition:r,dismissing:d,peekGap:m,toasts:l,index:c}){const[h,f]=(s.position??r).split(" "),[g,x]=e(!1);return o(i,{className:p.toast,"data-pos-y":h,"data-pos-x":f,"data-color":s.color,onMouseEnter:()=>x(!0),onMouseLeave:()=>x(!1),"data-dismissing":d.has(s.id)?"":void 0,style:{"--peek":c*m+"px",zIndex:g?l.length+1:void 0},children:[t("span",{children:s.message}),t(n,{size:"sm",square:!0,onClick:()=>a(s.id),children:t(u,{})})]},s.id)}export{m as Toaster};
|
|
2
2
|
//# sourceMappingURL=Toaster.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toaster.js","sources":["../../../src/Display/Toast/Toaster.tsx"],"sourcesContent":["\"use client\";\n\nimport type { PositionStringEdge } from \"@studiocubics/types\";\nimport {\n type ComponentProps,\n useState,\n useEffect,\n type CSSProperties,\n} from \"react\";\nimport { GlassCard } from \"../../Cards/GlassCard/GlassCard\";\nimport { Button } from \"../../Inputs/Button/Button\";\nimport { type Toast, addDismissInterceptor, dismiss, subscribe } from \"./toast\";\nimport styles from \"./Toaster.module.css\";\n\nfunction CloseIcon(props: ComponentProps<\"svg\">) {\n const { width = 24, height = width, ...rest } = props;\n return (\n <svg\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...rest}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={width}\n height={height}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport interface ToasterProps {\n defaultPosition?: PositionStringEdge;\n /**\n * Gap between each toast in px\n * @default 8\n */\n peekGap?: number;\n /**\n * Duration of exit animation in ms\n * @default 200\n */\n exitDuration?: number;\n /**\n * @default 5\n */\n maxToastCount?: number;\n}\n\nexport function Toaster(props: ToasterProps) {\n const {\n defaultPosition: defaultPosition = \"top right\",\n peekGap = 12,\n exitDuration = 200,\n maxToastCount = 5,\n } = props;\n const [toasts, setToasts] = useState<Toast[]>([]);\n // Track which toast IDs are currently playing their exit animation\n const [dismissing, setDismissing] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n return subscribe(setToasts, maxToastCount);\n }, []);\n\n useEffect(() => {\n // Register interceptor so all dismiss() calls (auto + manual) go through exit animation\n addDismissInterceptor((id, confirm) => {\n // No-op if already animating out\n setDismissing((prev) => {\n if (prev.has(id)) return prev;\n const next = new Set(prev).add(id);\n setTimeout(() => {\n confirm();\n setDismissing((p) => {\n const n = new Set(p);\n n.delete(id);\n return n;\n });\n }, exitDuration);\n return next;\n });\n });\n }, [exitDuration]);\n\n return (\n <div className={styles.root}>\n {toasts.map((t, i) => (\n <ToastComponent\n key={t.id}\n toast={t}\n defaultPosition={defaultPosition}\n dismissing={dismissing}\n peekGap={peekGap}\n toasts={toasts}\n index={i}\n />\n ))}\n </div>\n );\n}\nfunction ToastComponent({\n toast,\n defaultPosition,\n dismissing,\n peekGap,\n toasts,\n index,\n}: {\n toast: Toast;\n defaultPosition: PositionStringEdge;\n dismissing: Set<string>;\n peekGap: number;\n toasts: Toast[];\n index: number;\n}) {\n const [y, x] = (toast.position ?? defaultPosition).split(\" \");\n const [isHovering, setIsHovering] = useState(false);\n
|
|
1
|
+
{"version":3,"file":"Toaster.js","sources":["../../../src/Display/Toast/Toaster.tsx"],"sourcesContent":["\"use client\";\n\nimport type { PositionStringEdge } from \"@studiocubics/types\";\nimport {\n type ComponentProps,\n useState,\n useEffect,\n type CSSProperties,\n} from \"react\";\nimport { GlassCard } from \"../../Cards/GlassCard/GlassCard\";\nimport { Button } from \"../../Inputs/Button/Button\";\nimport { type Toast, addDismissInterceptor, dismiss, subscribe } from \"./toast\";\nimport styles from \"./Toaster.module.css\";\n\nfunction CloseIcon(props: ComponentProps<\"svg\">) {\n const { width = 24, height = width, ...rest } = props;\n return (\n <svg\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...rest}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={width}\n height={height}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport interface ToasterProps {\n defaultPosition?: PositionStringEdge;\n /**\n * Gap between each toast in px\n * @default 8\n */\n peekGap?: number;\n /**\n * Duration of exit animation in ms\n * @default 200\n */\n exitDuration?: number;\n /**\n * @default 5\n */\n maxToastCount?: number;\n}\n\nexport function Toaster(props: ToasterProps) {\n const {\n defaultPosition: defaultPosition = \"top right\",\n peekGap = 12,\n exitDuration = 200,\n maxToastCount = 5,\n } = props;\n const [toasts, setToasts] = useState<Toast[]>([]);\n // Track which toast IDs are currently playing their exit animation\n const [dismissing, setDismissing] = useState<Set<string>>(new Set());\n\n useEffect(() => {\n return subscribe(setToasts, maxToastCount);\n }, []);\n\n useEffect(() => {\n // Register interceptor so all dismiss() calls (auto + manual) go through exit animation\n addDismissInterceptor((id, confirm) => {\n // No-op if already animating out\n setDismissing((prev) => {\n if (prev.has(id)) return prev;\n const next = new Set(prev).add(id);\n setTimeout(() => {\n confirm();\n setDismissing((p) => {\n const n = new Set(p);\n n.delete(id);\n return n;\n });\n }, exitDuration);\n return next;\n });\n });\n }, [exitDuration]);\n\n return (\n <div className={styles.root}>\n {toasts.map((t, i) => (\n <ToastComponent\n key={t.id}\n toast={t}\n defaultPosition={defaultPosition}\n dismissing={dismissing}\n peekGap={peekGap}\n toasts={toasts}\n index={i}\n />\n ))}\n </div>\n );\n}\nfunction ToastComponent({\n toast,\n defaultPosition,\n dismissing,\n peekGap,\n toasts,\n index,\n}: {\n toast: Toast;\n defaultPosition: PositionStringEdge;\n dismissing: Set<string>;\n peekGap: number;\n toasts: Toast[];\n index: number;\n}) {\n const [y, x] = (toast.position ?? defaultPosition).split(\" \");\n const [isHovering, setIsHovering] = useState(false);\n\n return (\n <GlassCard\n key={toast.id}\n className={styles.toast}\n data-pos-y={y}\n data-pos-x={x}\n data-color={toast.color}\n onMouseEnter={() => setIsHovering(true)}\n onMouseLeave={() => setIsHovering(false)}\n data-dismissing={dismissing.has(toast.id) ? \"\" : undefined}\n style={\n {\n \"--peek\": `${index * peekGap}px`,\n zIndex: isHovering ? toasts.length + 1 : undefined,\n } as CSSProperties\n }\n >\n <span>{toast.message}</span>\n {/* dismiss() goes through interceptor → exit animation → confirmDismiss */}\n <Button size=\"sm\" square onClick={() => dismiss(toast.id)}>\n <CloseIcon />\n </Button>\n </GlassCard>\n );\n}\n"],"names":["CloseIcon","props","width","height","rest","_jsxs","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","xmlns","viewBox","children","_jsx","d","Toaster","defaultPosition","peekGap","exitDuration","maxToastCount","toasts","setToasts","useState","dismissing","setDismissing","Set","useEffect","subscribe","addDismissInterceptor","id","confirm","prev","has","next","add","setTimeout","p","n","delete","className","styles","root","map","t","i","ToastComponent","toast","index","y","x","position","split","isHovering","setIsHovering","GlassCard","color","onMouseEnter","onMouseLeave","undefined","style","zIndex","length","message","Button","size","square","onClick","dismiss"],"mappings":"2VAcA,SAASA,EAAUC,GACjB,MAAMC,MAAEA,EAAQ,GAAEC,OAAEA,EAASD,KAAUE,GAASH,EAChD,OACEI,EAAA,MAAA,CACEC,KAAK,OACLC,OAAO,eACPC,YAAY,IACZC,cAAc,QACdC,eAAe,WACXN,EACJO,MAAM,6BACNC,QAAQ,YACRV,MAAOA,EACPC,OAAQA,EAAMU,SAAA,CAEdC,UAAMC,EAAE,eACRD,EAAA,OAAA,CAAMC,EAAE,iBAGd,CAoBM,SAAUC,EAAQf,GACtB,MACEgB,gBAAiBA,EAAkB,YAAWC,QAC9CA,EAAU,GAAEC,aACZA,EAAe,IAAGC,cAClBA,EAAgB,GACdnB,GACGoB,EAAQC,GAAaC,EAAkB,KAEvCC,EAAYC,GAAiBF,EAAsB,IAAIG,KA0B9D,OAxBAC,EAAU,IACDC,EAAUN,EAAWF,GAC3B,IAEHO,EAAU,KAERE,EAAsB,CAACC,EAAIC,KAEzBN,EAAeO,IACb,GAAIA,EAAKC,IAAIH,GAAK,OAAOE,EACzB,MAAME,EAAO,IAAIR,IAAIM,GAAMG,IAAIL,GAS/B,OARAM,WAAW,KACTL,IACAN,EAAeY,IACb,MAAMC,EAAI,IAAIZ,IAAIW,GAElB,OADAC,EAAEC,OAAOT,GACFQ,KAERnB,GACIe,OAGV,CAACf,IAGFL,EAAA,MAAA,CAAK0B,UAAWC,EAAOC,KAAI7B,SACxBQ,EAAOsB,IAAI,CAACC,EAAGC,IACd/B,EAACgC,EAAc,CAEbC,MAAOH,EACP3B,gBAAiBA,EACjBO,WAAYA,EACZN,QAASA,EACTG,OAAQA,EACR2B,MAAOH,GANFD,EAAEd,MAWjB,CACA,SAASgB,GAAeC,MACtBA,EAAK9B,gBACLA,EAAeO,WACfA,EAAUN,QACVA,EAAOG,OACPA,EAAM2B,MACNA,IASA,MAAOC,EAAGC,IAAMH,EAAMI,UAAYlC,GAAiBmC,MAAM,MAClDC,EAAYC,GAAiB/B,GAAS,GAE7C,OACElB,EAACkD,EAAS,CAERf,UAAWC,EAAOM,MAAK,aACXE,EAAC,aACDC,eACAH,EAAMS,MAClBC,aAAc,IAAMH,GAAc,GAClCI,aAAc,IAAMJ,GAAc,GAAM,kBACvB9B,EAAWS,IAAIc,EAAMjB,IAAM,QAAK6B,EACjDC,MACE,CACE,SAAaZ,EAAQ9B,EAAX,KACV2C,OAAQR,EAAahC,EAAOyC,OAAS,OAAIH,GACzB9C,SAAA,CAGpBC,mBAAOiC,EAAMgB,UAEbjD,EAACkD,EAAM,CAACC,KAAK,KAAKC,QAAM,EAACC,QAAS,IAAMC,EAAQrB,EAAMjB,IAAGjB,SACvDC,EAACd,EAAS,CAAA,OAlBP+C,EAAMjB,GAsBjB"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let n=[],t=3;const
|
|
1
|
+
let n=[],t=3;const e=new Set;let o=null;function i(){e.forEach(t=>t(n))}function c(n,o){return e.add(n),t=o,()=>{e.delete(n)}}function u(n){o=n}function r(e,o){const c=crypto.randomUUID(),u={id:c,message:e,duration:2e4,...o};if(n=[...n,u],n.length>t){n.slice(0,n.length-t).forEach(n=>d(n.id))}i(),u.duration<=2e4&&setTimeout(()=>{d(c)},u.duration)}function d(n){o?o(n,()=>f(n)):f(n)}function f(t){n=n.filter(n=>n.id!==t),i()}export{u as addDismissInterceptor,f as confirmDismiss,d as dismiss,c as subscribe,r as toast};
|
|
2
2
|
//# sourceMappingURL=toast.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.js","sources":["../../../src/Display/Toast/toast.ts"],"sourcesContent":["import type { PositionStringEdge } from \"@studiocubics/types\";\n\nexport type Toast = {\n id: string;\n message: string;\n duration?: number;\n position?: PositionStringEdge;\n color?: \"primary\" | \"secondary\" | \"error\";\n};\nexport type ToastOptions = Omit<Toast, \"id\" | \"message\">;\ntype Listener = (toasts: Toast[]) => void;\n\nlet toasts: Toast[] = [];\nlet maxToastCount = 3; // adjust as needed\n\nconst listeners = new Set<Listener>();\n// Called before actually removing a toast, set by Toaster to trigger exit animation\nlet dismissInterceptor: ((id: string, confirm: () => void) => void) | null =\n null;\n\nfunction emit() {\n listeners.forEach((l) => l(toasts));\n}\n\nexport function subscribe(listener: Listener, max: number) {\n listeners.add(listener);\n maxToastCount = max;\n return () => {\n listeners.delete(listener);\n };\n}\n\n/** Registered by Toaster so it can play the exit animation before removal */\nexport function addDismissInterceptor(fn: typeof dismissInterceptor) {\n dismissInterceptor = fn;\n}\n\nexport function toast(message: string, options?: ToastOptions) {\n const id = crypto.randomUUID();\n\n
|
|
1
|
+
{"version":3,"file":"toast.js","sources":["../../../src/Display/Toast/toast.ts"],"sourcesContent":["import type { PositionStringEdge } from \"@studiocubics/types\";\n\nexport type Toast = {\n id: string;\n message: string;\n duration?: number;\n position?: PositionStringEdge;\n color?: \"primary\" | \"secondary\" | \"error\";\n};\nexport type ToastOptions = Omit<Toast, \"id\" | \"message\">;\ntype Listener = (toasts: Toast[]) => void;\n\nlet toasts: Toast[] = [];\nlet maxToastCount = 3; // adjust as needed\n\nconst listeners = new Set<Listener>();\n// Called before actually removing a toast, set by Toaster to trigger exit animation\nlet dismissInterceptor: ((id: string, confirm: () => void) => void) | null =\n null;\n\nfunction emit() {\n listeners.forEach((l) => l(toasts));\n}\n\nexport function subscribe(listener: Listener, max: number) {\n listeners.add(listener);\n maxToastCount = max;\n return () => {\n listeners.delete(listener);\n };\n}\n\n/** Registered by Toaster so it can play the exit animation before removal */\nexport function addDismissInterceptor(fn: typeof dismissInterceptor) {\n dismissInterceptor = fn;\n}\n\nexport function toast(message: string, options?: ToastOptions) {\n const id = crypto.randomUUID();\n\n const t = {\n id,\n message,\n duration: 20000,\n ...options,\n };\n\n toasts = [...toasts, t];\n\n // Remove oldest toasts if over the limit\n if (toasts.length > maxToastCount) {\n const overflow = toasts.slice(0, toasts.length - maxToastCount);\n overflow.forEach((old) => dismiss(old.id));\n }\n\n emit();\n\n // Its a toast not a lecture!\n if (t.duration <= 20000) {\n setTimeout(() => {\n dismiss(id);\n }, t.duration);\n }\n}\n\nexport function dismiss(id: string) {\n if (dismissInterceptor) {\n // calls confirmDismiss when animation is done\n dismissInterceptor(id, () => confirmDismiss(id));\n } else {\n confirmDismiss(id);\n }\n}\n\n/** Actually removes the toast from state — called after exit animation completes */\nexport function confirmDismiss(id: string) {\n toasts = toasts.filter((t) => t.id !== id);\n emit();\n}\n"],"names":["toasts","maxToastCount","listeners","Set","dismissInterceptor","emit","forEach","l","subscribe","listener","max","add","delete","addDismissInterceptor","fn","toast","message","options","id","crypto","randomUUID","t","duration","length","slice","old","dismiss","setTimeout","confirmDismiss","filter"],"mappings":"AAYA,IAAIA,EAAkB,GAClBC,EAAgB,EAEpB,MAAMC,EAAY,IAAIC,IAEtB,IAAIC,EACF,KAEF,SAASC,IACPH,EAAUI,QAASC,GAAMA,EAAEP,GAC7B,CAEM,SAAUQ,EAAUC,EAAoBC,GAG5C,OAFAR,EAAUS,IAAIF,GACdR,EAAgBS,EACT,KACLR,EAAUU,OAAOH,GAErB,CAGM,SAAUI,EAAsBC,GACpCV,EAAqBU,CACvB,CAEM,SAAUC,EAAMC,EAAiBC,GACrC,MAAMC,EAAKC,OAAOC,aAEZC,EAAI,CACRH,KACAF,UACAM,SAAU,OACPL,GAML,GAHAjB,EAAS,IAAIA,EAAQqB,GAGjBrB,EAAOuB,OAAStB,EAAe,CAChBD,EAAOwB,MAAM,EAAGxB,EAAOuB,OAAStB,GACxCK,QAASmB,GAAQC,EAAQD,EAAIP,IACxC,CAEAb,IAGIgB,EAAEC,UAAY,KAChBK,WAAW,KACTD,EAAQR,IACPG,EAAEC,SAET,CAEM,SAAUI,EAAQR,GAClBd,EAEFA,EAAmBc,EAAI,IAAMU,EAAeV,IAE5CU,EAAeV,EAEnB,CAGM,SAAUU,EAAeV,GAC7BlB,EAASA,EAAO6B,OAAQR,GAAMA,EAAEH,KAAOA,GACvCb,GACF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as t,jsxs as o}from"react/jsx-runtime";import{Button as r}from"../Button/Button.js";import{cn as e}from"@studiocubics/utils";import n from"./CloseButton.module.css.js";function s(r){const{width:e=24,height:n=e,...s}=r;return o("svg",{fill:"none",stroke:"currentColor",
|
|
1
|
+
import{jsx as t,jsxs as o}from"react/jsx-runtime";import{Button as r}from"../Button/Button.js";import{cn as e}from"@studiocubics/utils";import n from"./CloseButton.module.css.js";function s(r){const{width:e=24,height:n=e,...s}=r;return o("svg",{fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",...s,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:e,height:n,children:[t("path",{d:"M18 6 6 18"}),t("path",{d:"m6 6 12 12"})]})}function i(o){const{className:i,...u}=o;return t(r,{square:!0,className:e(n.root,i),...u,children:t(s,{})})}export{i as CloseButton};
|
|
2
2
|
//# sourceMappingURL=CloseButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloseButton.js","sources":["../../../src/Inputs/CloseButton/CloseButton.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { Button, type ButtonProps } from \"../Button/Button\";\nimport { cn } from \"@studiocubics/utils\";\nimport styles from \"./CloseButton.module.css\";\n\nfunction CloseIcon(props: ComponentProps<\"svg\">) {\n const { width = 24, height = width, ...rest } = props;\n return (\n <svg\n fill=\"none\"\n stroke=\"currentColor\"\n
|
|
1
|
+
{"version":3,"file":"CloseButton.js","sources":["../../../src/Inputs/CloseButton/CloseButton.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport { Button, type ButtonProps } from \"../Button/Button\";\nimport { cn } from \"@studiocubics/utils\";\nimport styles from \"./CloseButton.module.css\";\n\nfunction CloseIcon(props: ComponentProps<\"svg\">) {\n const { width = 24, height = width, ...rest } = props;\n return (\n <svg\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n {...rest}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n width={width}\n height={height}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\nexport function CloseButton(props: Omit<ButtonProps, \"children\">) {\n const { className, ...rest } = props;\n return (\n <Button square className={cn(styles.root, className)} {...rest}>\n <CloseIcon />\n </Button>\n );\n}\n"],"names":["CloseIcon","props","width","height","rest","_jsxs","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","xmlns","viewBox","children","_jsx","d","CloseButton","className","Button","square","cn","styles","root"],"mappings":"mLAKA,SAASA,EAAUC,GACjB,MAAMC,MAAEA,EAAQ,GAAEC,OAAEA,EAASD,KAAUE,GAASH,EAChD,OACEI,EAAA,MAAA,CACEC,KAAK,OACLC,OAAO,eACPC,YAAY,IACZC,cAAc,QACdC,eAAe,WACXN,EACJO,MAAM,6BACNC,QAAQ,YACRV,MAAOA,EACPC,OAAQA,EAAMU,SAAA,CAEdC,UAAMC,EAAE,eACRD,EAAA,OAAA,CAAMC,EAAE,iBAGd,CAEM,SAAUC,EAAYf,GAC1B,MAAMgB,UAAEA,KAAcb,GAASH,EAC/B,OACEa,EAACI,EAAM,CAACC,UAAOF,UAAWG,EAAGC,EAAOC,KAAML,MAAgBb,EAAIS,SAC5DC,EAACd,EAAS,CAAA,IAGhB"}
|
|
@@ -5,15 +5,15 @@ import { type ChangeEvent, type ComponentProps, type ReactNode } from "react";
|
|
|
5
5
|
* @group switch
|
|
6
6
|
* @category inputs
|
|
7
7
|
*/
|
|
8
|
-
export interface SwitchProps extends Omit<ComponentProps<"input">, "
|
|
8
|
+
export interface SwitchProps extends Omit<ComponentProps<"input">, "defaultChecked" | "checked" | "onChange" | "size"> {
|
|
9
9
|
/**
|
|
10
|
-
* Default
|
|
10
|
+
* Default checked of the switch in boolean
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
defaultChecked?: boolean;
|
|
13
13
|
/**
|
|
14
14
|
* Value of the switch in boolean
|
|
15
15
|
*/
|
|
16
|
-
|
|
16
|
+
checked?: boolean | null;
|
|
17
17
|
/**
|
|
18
18
|
* Event handler for when the value of the switch changes
|
|
19
19
|
*/
|
|
@@ -41,7 +41,7 @@ export interface SwitchProps extends Omit<ComponentProps<"input">, "defaultValue
|
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* A switch can be used to show on/off state for form inputs, theme toggles etc.
|
|
44
|
-
*
|
|
44
|
+
* //TODO add provider context
|
|
45
45
|
* @group switch
|
|
46
46
|
* @category inputs
|
|
47
47
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useRef as r,useState as c,
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{useRef as r,useState as c,useCallback as n,useEffect as o}from"react";import a from"./Switch.module.css.js";import{cssSafeString as s,cn as u,mergeRefs as i}from"@studiocubics/utils";function l(l){const{checked:d,defaultChecked:m,type:h="checkbox",onChange:p,className:v,ref:b,label:f,"aria-label":k,icon:N,disabled:E,slotProps:L={},color:g,size:C="md",htmlSize:w,...z}=l,X=r(null),x=r(null),S=void 0!==d,[T,W]=c(m??!1),j=S?d??!1:T,y=r(!1),M=r(!1),D=r(0),F=r(j),P=l.id??s(f),q=n(e=>{if(!E&&(S||W(e),X.current&&p)){const t={...new Event("change",{bubbles:!0}),target:X.current,currentTarget:X.current};X.current.checked=e,p(t,e)}},[S,p,E]),A=n(e=>{E||(y.current=!0,M.current=!1,D.current=e)},[E]),B=n(e=>{if(!y.current||E)return;const t=e-D.current;if(Math.abs(t)>10){M.current=!0;const e=t>0;e!==F.current&&q(e)}},[E,q]),G=n(()=>{y.current=!1},[]);return o(()=>{const e=e=>B(e.clientX),t=e=>B(e.touches[0].clientX);return document.addEventListener("mousemove",e),document.addEventListener("mouseup",G),document.addEventListener("touchmove",t),document.addEventListener("touchend",G),()=>{document.removeEventListener("mousemove",e),document.removeEventListener("mouseup",G),document.removeEventListener("touchmove",t),document.removeEventListener("touchend",G)}},[B,G]),o(()=>{S||W(m??!1)},[m,S]),o(()=>{F.current=j},[j]),e("div",{...L.root,"data-color":g,"data-size":C,className:u(L.root?.className,v,a.root,E?a.disabled:""),children:[e("div",{...L.inputWrapper,className:u(a.inputWrapper,L.inputWrapper?.className),children:[t("input",{...z,id:P,size:w,type:h,ref:i(b,X),className:a.input,role:"switch","aria-checked":j,"aria-label":k??f,checked:S?j:void 0,defaultChecked:S?void 0:m,disabled:E,onChange:e=>{const t=e.currentTarget.checked;S||W(t),p&&p(e,t)}}),t("span",{className:u(a.track,j?a.checked:""),onClick:()=>{M.current?M.current=!1:X.current?.click()},"aria-hidden":"true",children:t("span",{ref:x,className:a.thumb,onMouseDown:e=>A(e.clientX),onTouchStart:e=>A(e.touches[0].clientX),children:N})})]}),f&&t("label",{...L.label,htmlFor:P,className:u(L.label?.className,a.label),children:f})]})}export{l as Switch};
|
|
2
2
|
//# sourceMappingURL=Switch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","sources":["../../../src/Inputs/Switch/Switch.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ChangeEvent,\n type ComponentProps,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport styles from \"./Switch.module.css\";\nimport { cn, cssSafeString, mergeRefs } from \"@studiocubics/utils\";\n\n/**\n * Props for the Switch component\n *\n * @group switch\n * @category inputs\n */\nexport interface SwitchProps\n extends Omit<\n ComponentProps<\"input\">,\n \"defaultValue\" | \"value\" | \"onChange\" | \"size\"\n > {\n /**\n * Default value of the switch in boolean\n */\n defaultValue?: boolean;\n /**\n * Value of the switch in boolean\n */\n value?: boolean | null;\n /**\n * Event handler for when the value of the switch changes\n */\n onChange?: (e: ChangeEvent<HTMLInputElement>, checked: boolean) => void;\n /**\n * Label for the switch\n */\n label?: string;\n /**\n * Icon to render in the thumb of the switch\n */\n icon?: ReactNode;\n /**\n * Switch slots props\n */\n slotProps?: {\n root?: ComponentProps<\"div\">;\n inputWrapper?: ComponentProps<\"div\">;\n label?: ComponentProps<\"label\">;\n track?: ComponentProps<\"span\">;\n };\n color?: \"primary\" | \"secondary\" | \"error\";\n size?: \"sm\" | \"md\" | \"lg\";\n htmlSize?: ComponentProps<\"input\">[\"size\"];\n}\n\n/**\n * A switch can be used to show on/off state for form inputs, theme toggles etc.\n *\n * @group switch\n * @category inputs\n */\nexport function Switch(props: SwitchProps) {\n const {\n value,\n defaultValue,\n type = \"checkbox\",\n onChange,\n className,\n ref,\n label,\n \"aria-label\": ariaLabel,\n icon,\n disabled,\n slotProps = {},\n color,\n size = \"md\",\n htmlSize,\n ...rest\n } = props;\n\n const inputRef = useRef<HTMLInputElement>(null);\n const thumbRef = useRef<HTMLSpanElement>(null);\n\n const isControlled = value !== undefined;\n const [internalChecked, setInternalChecked] = useState<boolean>(\n defaultValue ?? false,\n );\n const checked = isControlled ? (value ?? false) : internalChecked;\n\n const isDragging = useRef(false);\n const didDrag = useRef(false);\n const dragStartX = useRef(0);\n\n const checkedRef = useRef(checked);\n const id = props.id ?? cssSafeString(label);\n\n useEffect(() => {\n checkedRef.current = checked;\n }, [checked]);\n\n const triggerChange = useCallback(\n (newChecked: boolean) => {\n if (!isControlled) setInternalChecked(newChecked);\n if (inputRef.current && onChange) {\n const nativeInput = inputRef.current;\n nativeInput.checked = newChecked;\n const nativeEvent = new Event(\"change\", { bubbles: true });\n nativeInput.dispatchEvent(nativeEvent);\n }\n },\n [isControlled, onChange],\n );\n\n const handleDragStart = useCallback(\n (clientX: number) => {\n if (disabled) return;\n isDragging.current = true;\n didDrag.current = false;\n dragStartX.current = clientX;\n },\n [disabled],\n );\n\n const handleDragMove = useCallback(\n (clientX: number) => {\n if (!isDragging.current || disabled) return;\n\n const delta = clientX - dragStartX.current;\n const threshold = 10; // Minimum drag distance to trigger change\n\n if (Math.abs(delta) > threshold) {\n didDrag.current = true;\n const newChecked = delta > 0;\n if (newChecked !== checkedRef.current) {\n triggerChange(newChecked);\n }\n }\n },\n [disabled, triggerChange],\n );\n\n const handleDragEnd = useCallback(() => {\n isDragging.current = false;\n // didDrag.current is intentionally NOT reset here;\n // it stays true until the subsequent click event reads and clears it\n }, []);\n\n useEffect(() => {\n const handleMouseMove = (e: MouseEvent) => handleDragMove(e.clientX);\n const handleTouchMove = (e: TouchEvent) =>\n handleDragMove(e.touches[0].clientX);\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleDragEnd);\n document.addEventListener(\"touchmove\", handleTouchMove);\n document.addEventListener(\"touchend\", handleDragEnd);\n\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleDragEnd);\n document.removeEventListener(\"touchmove\", handleTouchMove);\n document.removeEventListener(\"touchend\", handleDragEnd);\n };\n }, [handleDragMove, handleDragEnd]);\n\n return (\n <div\n // TODO rename to container\n {...slotProps.root}\n data-color={color}\n data-size={size}\n className={cn(\n slotProps.root?.className,\n className,\n styles.root,\n disabled ? styles.disabled : \"\",\n )}\n >\n <div\n {...slotProps.inputWrapper}\n className={cn(styles.inputWrapper, slotProps.inputWrapper?.className)}\n >\n <input\n {...rest}\n id={id}\n size={htmlSize}\n type={type}\n ref={mergeRefs(ref, inputRef)}\n className={styles.input}\n role=\"switch\"\n aria-checked={checked}\n aria-label={ariaLabel ?? label}\n checked={isControlled ? checked : undefined}\n defaultChecked={!isControlled ? defaultValue : undefined}\n disabled={disabled}\n onChange={(e) => {\n const c = e.currentTarget.checked;\n if (!isControlled) setInternalChecked(c);\n if (onChange) onChange(e, c);\n }}\n />\n <span\n className={cn(styles.track, checked ? styles.checked : \"\")}\n onClick={() => {\n if (didDrag.current) {\n didDrag.current = false;\n return;\n }\n inputRef.current?.click();\n }}\n aria-hidden=\"true\"\n >\n <span\n ref={thumbRef}\n className={styles.thumb}\n onMouseDown={(e) => handleDragStart(e.clientX)}\n onTouchStart={(e) => handleDragStart(e.touches[0].clientX)}\n >\n {icon}\n </span>\n </span>\n </div>\n {label && (\n <label\n {...slotProps.label}\n htmlFor={id}\n className={cn(slotProps.label?.className, styles.label)}\n >\n {label}\n </label>\n )}\n </div>\n );\n}\n"],"names":["Switch","props","value","defaultValue","type","onChange","className","ref","label","ariaLabel","icon","disabled","slotProps","color","size","htmlSize","rest","inputRef","useRef","thumbRef","isControlled","undefined","internalChecked","setInternalChecked","useState","checked","isDragging","didDrag","dragStartX","checkedRef","id","cssSafeString","useEffect","current","triggerChange","useCallback","newChecked","nativeInput","nativeEvent","Event","bubbles","dispatchEvent","handleDragStart","clientX","handleDragMove","delta","Math","abs","handleDragEnd","handleMouseMove","e","handleTouchMove","touches","document","addEventListener","removeEventListener","_jsxs","root","cn","styles","children","inputWrapper","_jsx","mergeRefs","input","role","defaultChecked","c","currentTarget","track","onClick","click","thumb","onMouseDown","onTouchStart","htmlFor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Switch.js","sources":["../../../src/Inputs/Switch/Switch.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ChangeEvent,\n type ComponentProps,\n type ReactNode,\n useEffect,\n useRef,\n useState,\n useCallback,\n} from \"react\";\nimport styles from \"./Switch.module.css\";\nimport { cn, cssSafeString, mergeRefs } from \"@studiocubics/utils\";\n\n/**\n * Props for the Switch component\n *\n * @group switch\n * @category inputs\n */\nexport interface SwitchProps\n extends Omit<\n ComponentProps<\"input\">,\n \"defaultChecked\" | \"checked\" | \"onChange\" | \"size\"\n > {\n /**\n * Default checked of the switch in boolean\n */\n defaultChecked?: boolean;\n /**\n * Value of the switch in boolean\n */\n checked?: boolean | null;\n /**\n * Event handler for when the value of the switch changes\n */\n onChange?: (e: ChangeEvent<HTMLInputElement>, checked: boolean) => void;\n /**\n * Label for the switch\n */\n label?: string;\n /**\n * Icon to render in the thumb of the switch\n */\n icon?: ReactNode;\n /**\n * Switch slots props\n */\n slotProps?: {\n root?: ComponentProps<\"div\">;\n inputWrapper?: ComponentProps<\"div\">;\n label?: ComponentProps<\"label\">;\n track?: ComponentProps<\"span\">;\n };\n color?: \"primary\" | \"secondary\" | \"error\";\n size?: \"sm\" | \"md\" | \"lg\";\n htmlSize?: ComponentProps<\"input\">[\"size\"];\n}\n\n/**\n * A switch can be used to show on/off state for form inputs, theme toggles etc.\n * //TODO add provider context\n * @group switch\n * @category inputs\n */\nexport function Switch(props: SwitchProps) {\n const {\n checked,\n defaultChecked,\n type = \"checkbox\",\n onChange,\n className,\n ref,\n label,\n \"aria-label\": ariaLabel,\n icon,\n disabled,\n slotProps = {},\n color,\n size = \"md\",\n htmlSize,\n ...rest\n } = props;\n\n const inputRef = useRef<HTMLInputElement>(null);\n const thumbRef = useRef<HTMLSpanElement>(null);\n\n const isControlled = checked !== undefined;\n const [internalChecked, setInternalChecked] = useState<boolean>(\n defaultChecked ?? false,\n );\n const isOn = isControlled ? (checked ?? false) : internalChecked;\n\n const isDragging = useRef(false);\n const didDrag = useRef(false);\n const dragStartX = useRef(0);\n\n const checkedRef = useRef(isOn);\n const id = props.id ?? cssSafeString(label);\n\n const triggerChange = useCallback(\n (newChecked: boolean) => {\n if (disabled) return;\n if (!isControlled) {\n setInternalChecked(newChecked);\n }\n if (inputRef.current && onChange) {\n const event = {\n ...new Event(\"change\", { bubbles: true }),\n target: inputRef.current,\n currentTarget: inputRef.current,\n } as unknown as ChangeEvent<HTMLInputElement>;\n // keep DOM in sync\n inputRef.current.checked = newChecked;\n onChange(event, newChecked);\n }\n },\n [isControlled, onChange, disabled],\n );\n\n const handleDragStart = useCallback(\n (clientX: number) => {\n if (disabled) return;\n isDragging.current = true;\n didDrag.current = false;\n dragStartX.current = clientX;\n },\n [disabled],\n );\n\n const handleDragMove = useCallback(\n (clientX: number) => {\n if (!isDragging.current || disabled) return;\n\n const delta = clientX - dragStartX.current;\n const threshold = 10; // Minimum drag distance to trigger change\n\n if (Math.abs(delta) > threshold) {\n didDrag.current = true;\n const newChecked = delta > 0;\n if (newChecked !== checkedRef.current) {\n triggerChange(newChecked);\n }\n }\n },\n [disabled, triggerChange],\n );\n\n const handleDragEnd = useCallback(() => {\n isDragging.current = false;\n // didDrag.current is intentionally NOT reset here;\n // it stays true until the subsequent click event reads and clears it\n }, []);\n\n useEffect(() => {\n const handleMouseMove = (e: MouseEvent) => handleDragMove(e.clientX);\n const handleTouchMove = (e: TouchEvent) =>\n handleDragMove(e.touches[0].clientX);\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleDragEnd);\n document.addEventListener(\"touchmove\", handleTouchMove);\n document.addEventListener(\"touchend\", handleDragEnd);\n\n return () => {\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleDragEnd);\n document.removeEventListener(\"touchmove\", handleTouchMove);\n document.removeEventListener(\"touchend\", handleDragEnd);\n };\n }, [handleDragMove, handleDragEnd]);\n\n useEffect(() => {\n if (!isControlled) {\n setInternalChecked(defaultChecked ?? false);\n }\n }, [defaultChecked, isControlled]);\n\n useEffect(() => {\n checkedRef.current = isOn;\n }, [isOn]);\n\n return (\n <div\n // TODO rename to container\n {...slotProps.root}\n data-color={color}\n data-size={size}\n className={cn(\n slotProps.root?.className,\n className,\n styles.root,\n disabled ? styles.disabled : \"\",\n )}\n >\n <div\n {...slotProps.inputWrapper}\n className={cn(styles.inputWrapper, slotProps.inputWrapper?.className)}\n >\n <input\n {...rest}\n id={id}\n size={htmlSize}\n type={type}\n ref={mergeRefs(ref, inputRef)}\n className={styles.input}\n role=\"switch\"\n aria-checked={isOn}\n aria-label={ariaLabel ?? label}\n checked={isControlled ? isOn : undefined}\n defaultChecked={!isControlled ? defaultChecked : undefined}\n disabled={disabled}\n onChange={(e) => {\n const c = e.currentTarget.checked;\n if (!isControlled) setInternalChecked(c);\n if (onChange) onChange(e, c);\n }}\n />\n <span\n className={cn(styles.track, isOn ? styles.checked : \"\")}\n onClick={() => {\n if (didDrag.current) {\n didDrag.current = false;\n return;\n }\n inputRef.current?.click();\n }}\n aria-hidden=\"true\"\n >\n <span\n ref={thumbRef}\n className={styles.thumb}\n onMouseDown={(e) => handleDragStart(e.clientX)}\n onTouchStart={(e) => handleDragStart(e.touches[0].clientX)}\n >\n {icon}\n </span>\n </span>\n </div>\n {label && (\n <label\n {...slotProps.label}\n htmlFor={id}\n className={cn(slotProps.label?.className, styles.label)}\n >\n {label}\n </label>\n )}\n </div>\n );\n}\n"],"names":["Switch","props","checked","defaultChecked","type","onChange","className","ref","label","ariaLabel","icon","disabled","slotProps","color","size","htmlSize","rest","inputRef","useRef","thumbRef","isControlled","undefined","internalChecked","setInternalChecked","useState","isOn","isDragging","didDrag","dragStartX","checkedRef","id","cssSafeString","triggerChange","useCallback","newChecked","current","event","Event","bubbles","target","currentTarget","handleDragStart","clientX","handleDragMove","delta","Math","abs","handleDragEnd","useEffect","handleMouseMove","e","handleTouchMove","touches","document","addEventListener","removeEventListener","_jsxs","root","cn","styles","children","inputWrapper","_jsx","mergeRefs","input","role","c","track","onClick","click","thumb","onMouseDown","onTouchStart","htmlFor"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsxs as o,Fragment as t,jsx as r}from"react/jsx-runtime";import{useDisclosure as e}from"@studiocubics/hooks";import{Button as i}from"../../Inputs/Button/Button.js";import{Dialog as n}from"../Dialog/Dialog.js";import{cn as s}from"@studiocubics/utils";import
|
|
1
|
+
import{jsxs as o,Fragment as t,jsx as r}from"react/jsx-runtime";import{useDisclosure as e}from"@studiocubics/hooks";import{Button as i}from"../../Inputs/Button/Button.js";import{Dialog as n}from"../Dialog/Dialog.js";import{cn as s}from"@studiocubics/utils";import h from"./Drawer.module.css.js";const d=t=>o("svg",{width:"24",height:"24",stroke:"currentColor",...t,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[r("rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}),r("path",{d:"M9 3v18"}),r("path",{d:"m16 15-3-3 3-3"})]}),l=t=>o("svg",{width:"24",height:"24",stroke:"currentColor",...t,xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[r("rect",{width:"18",height:"18",x:"3",y:"3",rx:"2"}),r("path",{d:"M15 3v18"}),r("path",{d:"m8 9 3 3-3 3"})]});function c(c){const{side:m="right",slotProps:p,children:u,className:a,...w}=c,{open:g,handleOpen:f,handleClose:k}=e();return o(t,{children:[r(i,{onClick:f,children:r("left"==m?l:d,{})}),r(n,{open:g,onClose:k,className:s(a,h.drawer),...w,children:u})]})}export{c as Drawer};
|
|
2
2
|
//# sourceMappingURL=Drawer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Drawer.js","sources":["../../../src/Layout/Drawer/Drawer.tsx"],"sourcesContent":["import { useDisclosure } from \"@studiocubics/hooks\";\nimport { Button, type ButtonProps } from \"../../Inputs/Button/Button\";\nimport { Dialog, type DialogProps } from \"../../Layout/Dialog/Dialog\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@studiocubics/utils\";\nimport styles from \"./Drawer.module.css\";\n\nexport interface DrawerProps extends Omit<DialogProps, \"open\" | \"onClose\"> {\n /**\n * @default \"right\"\n */\n side?: \"right\" | \"left\";\n\n slotProps?: {\n button?: ButtonProps;\n };\n}\n\nconst PanelLeft = (props: ComponentProps<\"svg\">) => {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n stroke=\"currentColor\"\n {...props}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n
|
|
1
|
+
{"version":3,"file":"Drawer.js","sources":["../../../src/Layout/Drawer/Drawer.tsx"],"sourcesContent":["import { useDisclosure } from \"@studiocubics/hooks\";\nimport { Button, type ButtonProps } from \"../../Inputs/Button/Button\";\nimport { Dialog, type DialogProps } from \"../../Layout/Dialog/Dialog\";\nimport type { ComponentProps } from \"react\";\nimport { cn } from \"@studiocubics/utils\";\nimport styles from \"./Drawer.module.css\";\n\nexport interface DrawerProps extends Omit<DialogProps, \"open\" | \"onClose\"> {\n /**\n * @default \"right\"\n */\n side?: \"right\" | \"left\";\n\n slotProps?: {\n button?: ButtonProps;\n };\n}\n\nconst PanelLeft = (props: ComponentProps<\"svg\">) => {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n stroke=\"currentColor\"\n {...props}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M9 3v18\" />\n <path d=\"m16 15-3-3 3-3\" />\n </svg>\n );\n};\nconst PanelRight = (props: ComponentProps<\"svg\">) => {\n return (\n <svg\n width=\"24\"\n height=\"24\"\n stroke=\"currentColor\"\n {...props}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M15 3v18\" />\n <path d=\"m8 9 3 3-3 3\" />\n </svg>\n );\n};\n\n/**\n * Opens a drawer from the side of the screen\n */\nexport function Drawer(props: DrawerProps) {\n const { side = \"right\", slotProps, children, className, ...rest } = props;\n const { open, handleOpen, handleClose } = useDisclosure();\n\n return (\n <>\n <Button onClick={handleOpen}>\n {side == \"left\" ? <PanelRight /> : <PanelLeft />}\n </Button>\n <Dialog\n open={open}\n onClose={handleClose}\n className={cn(className, styles.drawer)}\n {...rest}\n >\n {children}\n </Dialog>\n </>\n );\n}\n"],"names":["PanelLeft","props","_jsxs","width","height","stroke","xmlns","viewBox","fill","strokeWidth","strokeLinecap","strokeLinejoin","_jsx","x","y","rx","d","PanelRight","Drawer","side","slotProps","children","className","rest","open","handleOpen","handleClose","useDisclosure","_Fragment","Button","onClick","Dialog","onClose","cn","styles","drawer"],"mappings":"uSAkBA,MAAMA,EAAaC,GAEfC,EAAA,MAAA,CACEC,MAAM,KACNC,OAAO,KACPC,OAAO,kBACHJ,EACJK,MAAM,6BACNC,QAAQ,YACRC,KAAK,OACLC,YAAY,IACZC,cAAc,QACdC,eAAe,kBAEfC,EAAA,OAAA,CAAMT,MAAM,KAAKC,OAAO,KAAKS,EAAE,IAAIC,EAAE,IAAIC,GAAG,MAC5CH,EAAA,OAAA,CAAMI,EAAE,YACRJ,EAAA,OAAA,CAAMI,EAAE,sBAIRC,EAAchB,GAEhBC,EAAA,MAAA,CACEC,MAAM,KACNC,OAAO,KACPC,OAAO,kBACHJ,EACJK,MAAM,6BACNC,QAAQ,YACRC,KAAK,OACLC,YAAY,IACZC,cAAc,QACdC,eAAe,kBAEfC,EAAA,OAAA,CAAMT,MAAM,KAAKC,OAAO,KAAKS,EAAE,IAAIC,EAAE,IAAIC,GAAG,MAC5CH,EAAA,OAAA,CAAMI,EAAE,aACRJ,EAAA,OAAA,CAAMI,EAAE,oBAQR,SAAUE,EAAOjB,GACrB,MAAMkB,KAAEA,EAAO,QAAOC,UAAEA,EAASC,SAAEA,EAAQC,UAAEA,KAAcC,GAAStB,GAC9DuB,KAAEA,EAAIC,WAAEA,EAAUC,YAAEA,GAAgBC,IAE1C,OACEzB,EAAA0B,EAAA,CAAAP,SAAA,CACET,EAACiB,EAAM,CAACC,QAASL,EAAUJ,SACPT,EAAT,QAARO,EAAkBF,EAAiBjB,EAAP,CAAA,KAE/BY,EAACmB,EAAM,CACLP,KAAMA,EACNQ,QAASN,EACTJ,UAAWW,EAAGX,EAAWY,EAAOC,WAC5BZ,EAAIF,SAEPA,MAIT"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function
|
|
1
|
+
function t({activeCrumb:t,crumbs:n,siblingCount:s=0,boundaryCount:h=1}){const i=Array.from(n),u=n.length;if(u<=2*h+2*s+2)return i;const e=Math.min(h,u),l=i.slice(0,e+1),r=i.slice(u-1-e,i.length),a=Math.max(Math.min(t-s,u-h-2*s-1),h+2),o=Math.min(Math.max(t+s,h+2*s+2),r.length>0?u-1-r.length:u-1),p=[];p.push(...l),a>h+2?p.push("ellipsis"):h+1<u-h&&p.push(n[h+1]);for(let t=a;t<=o;t++)p.push(n[t]);o<u-1-h?p.push("ellipsis"):u-h>h&&p.push(n[u-h]);const c=r.filter(t=>!p.includes(t));return p.push(...c),p}export{t as useBreadcrumbs};
|
|
2
2
|
//# sourceMappingURL=useBreadcrumbs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBreadcrumbs.js","sources":["../../../src/Navigation/Breadcrumbs/useBreadcrumbs.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\n\nexport function useBreadcrumbs({\n activeCrumb,\n crumbs,\n siblingCount = 0,\n boundaryCount = 1,\n}: {\n activeCrumb: number;\n crumbs: ReactElement[];\n siblingCount?: number;\n boundaryCount?: number;\n}) {\n const crumbsClone = Array.from(crumbs);\n const count = crumbs.length;\n if (count <= boundaryCount * 2 + siblingCount * 2 + 2) {\n // If total items fit without ellipsis, just return all crumbs\n return crumbsClone;\n }\n const resolvedBoundaryCount = Math.min(boundaryCount, count);\n\n
|
|
1
|
+
{"version":3,"file":"useBreadcrumbs.js","sources":["../../../src/Navigation/Breadcrumbs/useBreadcrumbs.tsx"],"sourcesContent":["import type { ReactElement } from \"react\";\n\nexport function useBreadcrumbs({\n activeCrumb,\n crumbs,\n siblingCount = 0,\n boundaryCount = 1,\n}: {\n activeCrumb: number;\n crumbs: ReactElement[];\n siblingCount?: number;\n boundaryCount?: number;\n}) {\n const crumbsClone = Array.from(crumbs);\n const count = crumbs.length;\n if (count <= boundaryCount * 2 + siblingCount * 2 + 2) {\n // If total items fit without ellipsis, just return all crumbs\n return crumbsClone;\n }\n const resolvedBoundaryCount = Math.min(boundaryCount, count);\n\n const startPages = crumbsClone.slice(0, resolvedBoundaryCount + 1);\n const endPages = crumbsClone.slice(\n count - 1 - resolvedBoundaryCount,\n crumbsClone.length,\n );\n\n const siblingsStart = Math.max(\n Math.min(\n activeCrumb - siblingCount,\n count - boundaryCount - siblingCount * 2 - 1,\n ),\n boundaryCount + 2,\n );\n const siblingsEnd = Math.min(\n Math.max(activeCrumb + siblingCount, boundaryCount + siblingCount * 2 + 2),\n endPages.length > 0 ? count - 1 - endPages.length : count - 1,\n );\n\n const itemList: (ReactElement | \"ellipsis\")[] = [];\n\n // Start pages\n itemList.push(...startPages);\n\n // Ellipsis after start pages\n if (siblingsStart > boundaryCount + 2) {\n itemList.push(\"ellipsis\");\n } else if (boundaryCount + 1 < count - boundaryCount) {\n itemList.push(crumbs[boundaryCount + 1]);\n }\n // Middle pages\n for (let i = siblingsStart; i <= siblingsEnd; i++) {\n itemList.push(crumbs[i]);\n }\n\n // Ellipsis before end pages\n if (siblingsEnd < count - 1 - boundaryCount) {\n itemList.push(\"ellipsis\");\n } else if (count - boundaryCount > boundaryCount) {\n itemList.push(crumbs[count - boundaryCount]);\n }\n\n const endPagesFiltered = endPages.filter((p) => !itemList.includes(p));\n\n itemList.push(...endPagesFiltered);\n\n return itemList;\n}\n"],"names":["useBreadcrumbs","activeCrumb","crumbs","siblingCount","boundaryCount","crumbsClone","Array","from","count","length","resolvedBoundaryCount","Math","min","startPages","slice","endPages","siblingsStart","max","siblingsEnd","itemList","push","i","endPagesFiltered","filter","p","includes"],"mappings":"AAEM,SAAUA,GAAeC,YAC7BA,EAAWC,OACXA,EAAMC,aACNA,EAAe,EAACC,cAChBA,EAAgB,IAOhB,MAAMC,EAAcC,MAAMC,KAAKL,GACzBM,EAAQN,EAAOO,OACrB,GAAID,GAAyB,EAAhBJ,EAAmC,EAAfD,EAAmB,EAElD,OAAOE,EAET,MAAMK,EAAwBC,KAAKC,IAAIR,EAAeI,GAEhDK,EAAaR,EAAYS,MAAM,EAAGJ,EAAwB,GAC1DK,EAAWV,EAAYS,MAC3BN,EAAQ,EAAIE,EACZL,EAAYI,QAGRO,EAAgBL,KAAKM,IACzBN,KAAKC,IACHX,EAAcE,EACdK,EAAQJ,EAA+B,EAAfD,EAAmB,GAE7CC,EAAgB,GAEZc,EAAcP,KAAKC,IACvBD,KAAKM,IAAIhB,EAAcE,EAAcC,EAA+B,EAAfD,EAAmB,GACxEY,EAASN,OAAS,EAAID,EAAQ,EAAIO,EAASN,OAASD,EAAQ,GAGxDW,EAA0C,GAGhDA,EAASC,QAAQP,GAGbG,EAAgBZ,EAAgB,EAClCe,EAASC,KAAK,YACLhB,EAAgB,EAAII,EAAQJ,GACrCe,EAASC,KAAKlB,EAAOE,EAAgB,IAGvC,IAAK,IAAIiB,EAAIL,EAAeK,GAAKH,EAAaG,IAC5CF,EAASC,KAAKlB,EAAOmB,IAInBH,EAAcV,EAAQ,EAAIJ,EAC5Be,EAASC,KAAK,YACLZ,EAAQJ,EAAgBA,GACjCe,EAASC,KAAKlB,EAAOM,EAAQJ,IAG/B,MAAMkB,EAAmBP,EAASQ,OAAQC,IAAOL,EAASM,SAASD,IAInE,OAFAL,EAASC,QAAQE,GAEVH,CACT"}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
7
|
"private": false,
|
|
8
|
-
"version": "0.0.
|
|
8
|
+
"version": "0.0.22",
|
|
9
9
|
"keywords": [
|
|
10
10
|
"@studiocubics",
|
|
11
11
|
"cubics",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"react-dom": ">= 19"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@studiocubics/hooks": "^0.0.
|
|
38
|
-
"@studiocubics/types": "^0.0.
|
|
39
|
-
"@studiocubics/utils": "^0.0.
|
|
37
|
+
"@studiocubics/hooks": "^0.0.22",
|
|
38
|
+
"@studiocubics/types": "^0.0.22",
|
|
39
|
+
"@studiocubics/utils": "^0.0.22"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@eslint/js": "^9.39.1",
|