@vritti/quantum-ui 0.1.4 → 0.1.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/TextField.d.ts +2 -1
- package/dist/TextField.js +21 -13
- package/dist/TextField.js.map +1 -1
- package/dist/ThemeToggle.js +1 -1
- package/dist/ThemeToggle.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +104 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/readme.md +0 -472
package/dist/TextField.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ export declare const TextField: default_2.FC<TextFieldProps>;
|
|
|
4
4
|
|
|
5
5
|
declare interface TextFieldProps extends default_2.ComponentProps<'input'> {
|
|
6
6
|
label?: string;
|
|
7
|
-
message?:
|
|
7
|
+
message?: default_2.ReactNode;
|
|
8
8
|
required?: boolean;
|
|
9
9
|
error?: boolean;
|
|
10
|
+
endAdornment?: default_2.ReactNode;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export { }
|
package/dist/TextField.js
CHANGED
|
@@ -95,6 +95,7 @@ const TextField = ({
|
|
|
95
95
|
error = false,
|
|
96
96
|
className,
|
|
97
97
|
id,
|
|
98
|
+
endAdornment,
|
|
98
99
|
...props
|
|
99
100
|
}) => {
|
|
100
101
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", "data-slot": "field", children: [
|
|
@@ -102,21 +103,28 @@ const TextField = ({
|
|
|
102
103
|
label,
|
|
103
104
|
required && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", "aria-hidden": "true", children: "*" })
|
|
104
105
|
] }),
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
Input,
|
|
109
|
+
{
|
|
110
|
+
className: cn(
|
|
111
|
+
className,
|
|
112
|
+
endAdornment && "pr-10"
|
|
113
|
+
),
|
|
114
|
+
"aria-describedby": message ? `${id || "field"}-message` : void 0,
|
|
115
|
+
"aria-required": required,
|
|
116
|
+
"aria-invalid": error,
|
|
117
|
+
required,
|
|
118
|
+
"data-slot": "input",
|
|
119
|
+
...props
|
|
120
|
+
}
|
|
121
|
+
),
|
|
122
|
+
endAdornment && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 flex items-center pr-3", children: endAdornment })
|
|
123
|
+
] }),
|
|
117
124
|
message && /* @__PURE__ */ jsx(
|
|
118
|
-
"
|
|
125
|
+
"div",
|
|
119
126
|
{
|
|
127
|
+
id: `${id || "field"}-message`,
|
|
120
128
|
className: cn("text-xs", error ? "text-destructive" : "text-muted-foreground"),
|
|
121
129
|
role: error ? "alert" : void 0,
|
|
122
130
|
"data-slot": "message",
|
package/dist/TextField.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextField.js","sources":["../shadcn/shadcnInput/Input.tsx","../node_modules/@radix-ui/react-primitive/dist/index.mjs","../node_modules/@radix-ui/react-label/dist/index.mjs","../shadcn/shadcnLabel/Label.tsx","../lib/components/TextField/TextField.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../utils';\n\nfunction Input({ className, type, ...props }: React.ComponentProps<'input'>) {\n return (\n <input\n type={type}\n data-slot='input'\n className={cn(\n 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',\n 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Input };\n","// src/primitive.tsx\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport { createSlot } from \"@radix-ui/react-slot\";\nimport { jsx } from \"react/jsx-runtime\";\nvar NODES = [\n \"a\",\n \"button\",\n \"div\",\n \"form\",\n \"h2\",\n \"h3\",\n \"img\",\n \"input\",\n \"label\",\n \"li\",\n \"nav\",\n \"ol\",\n \"p\",\n \"select\",\n \"span\",\n \"svg\",\n \"ul\"\n];\nvar Primitive = NODES.reduce((primitive, node) => {\n const Slot = createSlot(`Primitive.${node}`);\n const Node = React.forwardRef((props, forwardedRef) => {\n const { asChild, ...primitiveProps } = props;\n const Comp = asChild ? Slot : node;\n if (typeof window !== \"undefined\") {\n window[Symbol.for(\"radix-ui\")] = true;\n }\n return /* @__PURE__ */ jsx(Comp, { ...primitiveProps, ref: forwardedRef });\n });\n Node.displayName = `Primitive.${node}`;\n return { ...primitive, [node]: Node };\n}, {});\nfunction dispatchDiscreteCustomEvent(target, event) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event));\n}\nvar Root = Primitive;\nexport {\n Primitive,\n Root,\n dispatchDiscreteCustomEvent\n};\n//# sourceMappingURL=index.mjs.map\n","\"use client\";\n\n// src/label.tsx\nimport * as React from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { jsx } from \"react/jsx-runtime\";\nvar NAME = \"Label\";\nvar Label = React.forwardRef((props, forwardedRef) => {\n return /* @__PURE__ */ jsx(\n Primitive.label,\n {\n ...props,\n ref: forwardedRef,\n onMouseDown: (event) => {\n const target = event.target;\n if (target.closest(\"button, input, select, textarea\")) return;\n props.onMouseDown?.(event);\n if (!event.defaultPrevented && event.detail > 1) event.preventDefault();\n }\n }\n );\n});\nLabel.displayName = NAME;\nvar Root = Label;\nexport {\n Label,\n Root\n};\n//# sourceMappingURL=index.mjs.map\n","import * as LabelPrimitive from '@radix-ui/react-label';\nimport * as React from 'react';\n\nimport { cn } from '../utils';\n\nfunction Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot='label'\n className={cn(\n 'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import React from 'react';\nimport { Input } from '../../../shadcn/shadcnInput';\nimport { Label } from '../../../shadcn/shadcnLabel';\nimport { cn } from '../../../shadcn/utils';\n\nexport interface TextFieldProps extends React.ComponentProps<'input'> {\n /**\n * Label for the field\n */\n label?: string;\n\n /**\n * Helper or error message to display below the field\n */\n message?:
|
|
1
|
+
{"version":3,"file":"TextField.js","sources":["../shadcn/shadcnInput/Input.tsx","../node_modules/@radix-ui/react-primitive/dist/index.mjs","../node_modules/@radix-ui/react-label/dist/index.mjs","../shadcn/shadcnLabel/Label.tsx","../lib/components/TextField/TextField.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '../utils';\n\nfunction Input({ className, type, ...props }: React.ComponentProps<'input'>) {\n return (\n <input\n type={type}\n data-slot='input'\n className={cn(\n 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',\n 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',\n 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Input };\n","// src/primitive.tsx\nimport * as React from \"react\";\nimport * as ReactDOM from \"react-dom\";\nimport { createSlot } from \"@radix-ui/react-slot\";\nimport { jsx } from \"react/jsx-runtime\";\nvar NODES = [\n \"a\",\n \"button\",\n \"div\",\n \"form\",\n \"h2\",\n \"h3\",\n \"img\",\n \"input\",\n \"label\",\n \"li\",\n \"nav\",\n \"ol\",\n \"p\",\n \"select\",\n \"span\",\n \"svg\",\n \"ul\"\n];\nvar Primitive = NODES.reduce((primitive, node) => {\n const Slot = createSlot(`Primitive.${node}`);\n const Node = React.forwardRef((props, forwardedRef) => {\n const { asChild, ...primitiveProps } = props;\n const Comp = asChild ? Slot : node;\n if (typeof window !== \"undefined\") {\n window[Symbol.for(\"radix-ui\")] = true;\n }\n return /* @__PURE__ */ jsx(Comp, { ...primitiveProps, ref: forwardedRef });\n });\n Node.displayName = `Primitive.${node}`;\n return { ...primitive, [node]: Node };\n}, {});\nfunction dispatchDiscreteCustomEvent(target, event) {\n if (target) ReactDOM.flushSync(() => target.dispatchEvent(event));\n}\nvar Root = Primitive;\nexport {\n Primitive,\n Root,\n dispatchDiscreteCustomEvent\n};\n//# sourceMappingURL=index.mjs.map\n","\"use client\";\n\n// src/label.tsx\nimport * as React from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { jsx } from \"react/jsx-runtime\";\nvar NAME = \"Label\";\nvar Label = React.forwardRef((props, forwardedRef) => {\n return /* @__PURE__ */ jsx(\n Primitive.label,\n {\n ...props,\n ref: forwardedRef,\n onMouseDown: (event) => {\n const target = event.target;\n if (target.closest(\"button, input, select, textarea\")) return;\n props.onMouseDown?.(event);\n if (!event.defaultPrevented && event.detail > 1) event.preventDefault();\n }\n }\n );\n});\nLabel.displayName = NAME;\nvar Root = Label;\nexport {\n Label,\n Root\n};\n//# sourceMappingURL=index.mjs.map\n","import * as LabelPrimitive from '@radix-ui/react-label';\nimport * as React from 'react';\n\nimport { cn } from '../utils';\n\nfunction Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot='label'\n className={cn(\n 'flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',\n className\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","import React from 'react';\nimport { Input } from '../../../shadcn/shadcnInput';\nimport { Label } from '../../../shadcn/shadcnLabel';\nimport { cn } from '../../../shadcn/utils';\n\nexport interface TextFieldProps extends React.ComponentProps<'input'> {\n /**\n * Label for the field\n */\n label?: string;\n\n /**\n * Helper or error message to display below the field\n */\n message?: React.ReactNode;\n\n /**\n * Whether the field is required\n */\n required?: boolean;\n\n /**\n * Whether the message represents an error state\n */\n error?: boolean;\n\n /**\n * Element to display at the end of the input (e.g., icon button)\n */\n endAdornment?: React.ReactNode;\n}\n\n// TextField molecule - Input + Label composition\nexport const TextField: React.FC<TextFieldProps> = ({\n label,\n message,\n required = false,\n error = false,\n className,\n id,\n endAdornment,\n ...props\n}) => {\n return (\n <div className='space-y-2' data-slot='field'>\n {label && (\n <Label data-slot='label'>\n {label}\n {required && (\n <span className='text-destructive ml-1' aria-hidden='true'>\n *\n </span>\n )}\n </Label>\n )}\n\n <div className=\"relative\">\n <Input\n className={cn(\n className,\n endAdornment && 'pr-10'\n )}\n aria-describedby={message ? `${id || 'field'}-message` : undefined}\n aria-required={required}\n aria-invalid={error}\n required={required}\n data-slot='input'\n {...props}\n />\n {endAdornment && (\n <div className=\"absolute inset-y-0 right-0 flex items-center pr-3\">\n {endAdornment}\n </div>\n )}\n </div>\n\n {message && (\n <div\n id={`${id || 'field'}-message`}\n className={cn('text-xs', error ? 'text-destructive' : 'text-muted-foreground')}\n role={error ? 'alert' : undefined}\n data-slot='message'\n >\n {message}\n </div>\n )}\n </div>\n );\n};\n"],"names":["Label","LabelPrimitive.Root"],"mappings":";;;;;;AAIA,SAAS,MAAM,EAAE,SAAA,EAAW,IAAA,EAAM,GAAG,OAAM,EAAkC;AAC3E,EAAA,uBACE,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,WAAA,EAAU,OAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,icAAA;AAAA,QACA,+EAAA;AAAA,QACA,wGAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;;AClBA;AAKA,IAAI,KAAK,GAAG;AACZ,EAAE,GAAG;AACL,EAAE,QAAQ;AACV,EAAE,KAAK;AACP,EAAE,MAAM;AACR,EAAE,IAAI;AACN,EAAE,IAAI;AACN,EAAE,KAAK;AACP,EAAE,OAAO;AACT,EAAE,OAAO;AACT,EAAE,IAAI;AACN,EAAE,KAAK;AACP,EAAE,IAAI;AACN,EAAE,GAAG;AACL,EAAE,QAAQ;AACV,EAAE,MAAM;AACR,EAAE,KAAK;AACP,EAAE;AACF,CAAC;AACD,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,IAAI,KAAK;AAClD,EAAE,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;AAC9C,EAAE,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK;AACzD,IAAI,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,KAAK;AAChD,IAAI,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI;AACtC,IAAI,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;AACvC,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI;AAC3C,IAAI;AACJ,IAAI,uBAAuB,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC;AAC9E,EAAE,CAAC,CAAC;AACJ,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AACxC,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC,IAAI,GAAG,IAAI,EAAE;AACvC,CAAC,EAAE,EAAE,CAAC;;AC9BN,IAAI,IAAI,GAAG,OAAO;AAClB,IAAIA,OAAK,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK;AACtD,EAAE,uBAAuB,GAAG;AAC5B,IAAI,SAAS,CAAC,KAAK;AACnB,IAAI;AACJ,MAAM,GAAG,KAAK;AACd,MAAM,GAAG,EAAE,YAAY;AACvB,MAAM,WAAW,EAAE,CAAC,KAAK,KAAK;AAC9B,QAAQ,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;AACnC,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,iCAAiC,CAAC,EAAE;AAC/D,QAAQ,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC;AAClC,QAAQ,IAAI,CAAC,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,CAAC,cAAc,EAAE;AAC/E,MAAM;AACN;AACA,GAAG;AACH,CAAC,CAAC;AACFA,OAAK,CAAC,WAAW,GAAG,IAAI;AACxB,IAAI,IAAI,GAAGA,OAAK;;AClBhB,SAAS,KAAA,CAAM,EAAE,SAAA,EAAW,GAAG,OAAM,EAAqD;AACxF,EAAA,uBACE,GAAA;AAAA,IAACC,IAAe;AAAA,IAAf;AAAA,MACC,WAAA,EAAU,OAAA;AAAA,MACV,SAAA,EAAW,EAAA;AAAA,QACT,qNAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG;AAAA;AAAA,GACN;AAEJ;;ACiBO,MAAM,YAAsC,CAAC;AAAA,EAClD,KAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,KAAA,GAAQ,KAAA;AAAA,EACR,SAAA;AAAA,EACA,EAAA;AAAA,EACA,YAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EAAY,aAAU,OAAA,EAClC,QAAA,EAAA;AAAA,IAAA,KAAA,oBACC,IAAA,CAAC,KAAA,EAAA,EAAM,WAAA,EAAU,OAAA,EACd,QAAA,EAAA;AAAA,MAAA,KAAA;AAAA,MACA,4BACC,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,uBAAA,EAAwB,aAAA,EAAY,QAAO,QAAA,EAAA,GAAA,EAE3D;AAAA,KAAA,EAEJ,CAAA;AAAA,oBAGF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,EAAA;AAAA,YACT,SAAA;AAAA,YACA,YAAA,IAAgB;AAAA,WAClB;AAAA,UACA,kBAAA,EAAkB,OAAA,GAAU,CAAA,EAAG,EAAA,IAAM,OAAO,CAAA,QAAA,CAAA,GAAa,MAAA;AAAA,UACzD,eAAA,EAAe,QAAA;AAAA,UACf,cAAA,EAAc,KAAA;AAAA,UACd,QAAA;AAAA,UACA,WAAA,EAAU,OAAA;AAAA,UACT,GAAG;AAAA;AAAA,OACN;AAAA,MACC,YAAA,oBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qDACZ,QAAA,EAAA,YAAA,EACH;AAAA,KAAA,EAEJ,CAAA;AAAA,IAEC,OAAA,oBACC,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,EAAA,EAAI,CAAA,EAAG,EAAA,IAAM,OAAO,CAAA,QAAA,CAAA;AAAA,QACpB,SAAA,EAAW,EAAA,CAAG,SAAA,EAAW,KAAA,GAAQ,qBAAqB,uBAAuB,CAAA;AAAA,QAC7E,IAAA,EAAM,QAAQ,OAAA,GAAU,MAAA;AAAA,QACxB,WAAA,EAAU,SAAA;AAAA,QAET,QAAA,EAAA;AAAA;AAAA;AACH,GAAA,EAEJ,CAAA;AAEJ;;;;","x_google_ignoreList":[1,2]}
|
package/dist/ThemeToggle.js
CHANGED
package/dist/ThemeToggle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeToggle.js","sources":["../node_modules/lucide-react/dist/esm/shared/src/utils.js","../node_modules/lucide-react/dist/esm/defaultAttributes.js","../node_modules/lucide-react/dist/esm/Icon.js","../node_modules/lucide-react/dist/esm/createLucideIcon.js","../node_modules/lucide-react/dist/esm/icons/moon.js","../node_modules/lucide-react/dist/esm/icons/sun.js","../lib/components/ThemeToggle/ThemeToggle.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n};\n\nexport { hasA11yProp, mergeClasses, toCamelCase, toKebabCase, toPascalCase };\n//# sourceMappingURL=utils.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.js';\nimport { mergeClasses, hasA11yProp } from './shared/src/utils.js';\n\nconst Icon = forwardRef(\n ({\n color = \"currentColor\",\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = \"\",\n children,\n iconNode,\n ...rest\n }, ref) => createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n className: mergeClasses(\"lucide\", className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n )\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses, toKebabCase, toPascalCase } from './shared/src/utils.js';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\",\n key: \"kfwtm\"\n }\n ]\n];\nconst Moon = createLucideIcon(\"moon\", __iconNode);\n\nexport { __iconNode, Moon as default };\n//# sourceMappingURL=moon.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"4\", key: \"4exip2\" }],\n [\"path\", { d: \"M12 2v2\", key: \"tus03m\" }],\n [\"path\", { d: \"M12 20v2\", key: \"1lh1kg\" }],\n [\"path\", { d: \"m4.93 4.93 1.41 1.41\", key: \"149t6j\" }],\n [\"path\", { d: \"m17.66 17.66 1.41 1.41\", key: \"ptbguv\" }],\n [\"path\", { d: \"M2 12h2\", key: \"1t8f8n\" }],\n [\"path\", { d: \"M20 12h2\", key: \"1q8mjw\" }],\n [\"path\", { d: \"m6.34 17.66-1.41 1.41\", key: \"1m8zz5\" }],\n [\"path\", { d: \"m19.07 4.93-1.41 1.41\", key: \"1shlcs\" }]\n];\nconst Sun = createLucideIcon(\"sun\", __iconNode);\n\nexport { __iconNode, Sun as default };\n//# sourceMappingURL=sun.js.map\n","import React, { useLayoutEffect, useState } from 'react';\nimport { Moon, Sun } from 'lucide-react';\nimport { Button } from '../Button/Button';\n\nexport interface ThemeToggleProps {\n /**\n * Custom className for the toggle button\n */\n className?: string;\n\n /**\n * Size of the toggle button\n */\n size?: 'sm' | 'md' | 'lg';\n}\n\nexport const ThemeToggle: React.FC<ThemeToggleProps> = ({ className, size = 'md' }) => {\n const [isDarkMode, setIsDarkMode] = useState(false);\n\n useLayoutEffect(() => {\n // Check for saved theme preference or system preference\n const savedTheme = localStorage.getItem('theme');\n const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n const shouldUseDark = savedTheme === 'dark' || (!savedTheme && systemPrefersDark);\n\n setIsDarkMode(shouldUseDark);\n document.documentElement.classList.toggle('dark', shouldUseDark);\n }, []);\n\n const toggleTheme = () => {\n const newDarkMode = !isDarkMode;\n setIsDarkMode(newDarkMode);\n\n // Update DOM and localStorage\n document.documentElement.classList.toggle('dark', newDarkMode);\n localStorage.setItem('theme', newDarkMode ? 'dark' : 'light');\n };\n\n return (\n <Button\n variant='ghost'\n size={size === 'md' ? 'default' : size}\n onClick={toggleTheme}\n className={className}\n aria-label={`Switch to ${isDarkMode ? 'light' : 'dark'} theme`}\n >\n <Sun className='h-4 w-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90' />\n <Moon className='absolute h-4 w-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0' />\n </Button>\n );\n};"],"names":["__iconNode"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5]}
|
|
1
|
+
{"version":3,"file":"ThemeToggle.js","sources":["../node_modules/lucide-react/dist/esm/shared/src/utils.js","../node_modules/lucide-react/dist/esm/defaultAttributes.js","../node_modules/lucide-react/dist/esm/Icon.js","../node_modules/lucide-react/dist/esm/createLucideIcon.js","../node_modules/lucide-react/dist/esm/icons/moon.js","../node_modules/lucide-react/dist/esm/icons/sun.js","../lib/components/ThemeToggle/ThemeToggle.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nconst toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\nconst toCamelCase = (string) => string.replace(\n /^([A-Z])|[\\s-_]+(\\w)/g,\n (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()\n);\nconst toPascalCase = (string) => {\n const camelCase = toCamelCase(string);\n return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);\n};\nconst mergeClasses = (...classes) => classes.filter((className, index, array) => {\n return Boolean(className) && className.trim() !== \"\" && array.indexOf(className) === index;\n}).join(\" \").trim();\nconst hasA11yProp = (props) => {\n for (const prop in props) {\n if (prop.startsWith(\"aria-\") || prop === \"role\" || prop === \"title\") {\n return true;\n }\n }\n};\n\nexport { hasA11yProp, mergeClasses, toCamelCase, toKebabCase, toPascalCase };\n//# sourceMappingURL=utils.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nvar defaultAttributes = {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: 24,\n height: 24,\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\"\n};\n\nexport { defaultAttributes as default };\n//# sourceMappingURL=defaultAttributes.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport defaultAttributes from './defaultAttributes.js';\nimport { mergeClasses, hasA11yProp } from './shared/src/utils.js';\n\nconst Icon = forwardRef(\n ({\n color = \"currentColor\",\n size = 24,\n strokeWidth = 2,\n absoluteStrokeWidth,\n className = \"\",\n children,\n iconNode,\n ...rest\n }, ref) => createElement(\n \"svg\",\n {\n ref,\n ...defaultAttributes,\n width: size,\n height: size,\n stroke: color,\n strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,\n className: mergeClasses(\"lucide\", className),\n ...!children && !hasA11yProp(rest) && { \"aria-hidden\": \"true\" },\n ...rest\n },\n [\n ...iconNode.map(([tag, attrs]) => createElement(tag, attrs)),\n ...Array.isArray(children) ? children : [children]\n ]\n )\n);\n\nexport { Icon as default };\n//# sourceMappingURL=Icon.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport { forwardRef, createElement } from 'react';\nimport { mergeClasses, toKebabCase, toPascalCase } from './shared/src/utils.js';\nimport Icon from './Icon.js';\n\nconst createLucideIcon = (iconName, iconNode) => {\n const Component = forwardRef(\n ({ className, ...props }, ref) => createElement(Icon, {\n ref,\n iconNode,\n className: mergeClasses(\n `lucide-${toKebabCase(toPascalCase(iconName))}`,\n `lucide-${iconName}`,\n className\n ),\n ...props\n })\n );\n Component.displayName = toPascalCase(iconName);\n return Component;\n};\n\nexport { createLucideIcon as default };\n//# sourceMappingURL=createLucideIcon.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\",\n key: \"kfwtm\"\n }\n ]\n];\nconst Moon = createLucideIcon(\"moon\", __iconNode);\n\nexport { __iconNode, Moon as default };\n//# sourceMappingURL=moon.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"4\", key: \"4exip2\" }],\n [\"path\", { d: \"M12 2v2\", key: \"tus03m\" }],\n [\"path\", { d: \"M12 20v2\", key: \"1lh1kg\" }],\n [\"path\", { d: \"m4.93 4.93 1.41 1.41\", key: \"149t6j\" }],\n [\"path\", { d: \"m17.66 17.66 1.41 1.41\", key: \"ptbguv\" }],\n [\"path\", { d: \"M2 12h2\", key: \"1t8f8n\" }],\n [\"path\", { d: \"M20 12h2\", key: \"1q8mjw\" }],\n [\"path\", { d: \"m6.34 17.66-1.41 1.41\", key: \"1m8zz5\" }],\n [\"path\", { d: \"m19.07 4.93-1.41 1.41\", key: \"1shlcs\" }]\n];\nconst Sun = createLucideIcon(\"sun\", __iconNode);\n\nexport { __iconNode, Sun as default };\n//# sourceMappingURL=sun.js.map\n","import React, { useLayoutEffect, useState } from 'react';\nimport { Moon, Sun } from 'lucide-react';\nimport { Button } from '../Button/Button';\n\nexport interface ThemeToggleProps {\n /**\n * Custom className for the toggle button\n */\n className?: string;\n\n /**\n * Size of the toggle button\n */\n size?: 'sm' | 'md' | 'lg';\n}\n\nexport const ThemeToggle: React.FC<ThemeToggleProps> = ({ className, size = 'md' }) => {\n const [isDarkMode, setIsDarkMode] = useState(false);\n\n useLayoutEffect(() => {\n // Check for saved theme preference or system preference\n const savedTheme = localStorage.getItem('theme');\n const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n const shouldUseDark = savedTheme === 'dark' || (!savedTheme && systemPrefersDark);\n\n setIsDarkMode(shouldUseDark);\n document.documentElement.classList.toggle('dark', shouldUseDark);\n }, []);\n\n const toggleTheme = () => {\n const newDarkMode = !isDarkMode;\n setIsDarkMode(newDarkMode);\n\n // Update DOM and localStorage\n document.documentElement.classList.toggle('dark', newDarkMode);\n localStorage.setItem('theme', newDarkMode ? 'dark' : 'light');\n };\n\n return (\n <Button\n variant='ghost'\n size={size === 'md' ? 'default' : size}\n onClick={toggleTheme}\n className={className}\n aria-label={`Switch to ${isDarkMode ? 'light' : 'dark'} theme`}\n >\n <Sun className='h-4 w-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90' />\n <Moon className='absolute h-4 w-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0' />\n </Button>\n );\n};"],"names":["__iconNode"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5]}
|
package/dist/index.d.ts
CHANGED
|
@@ -91,13 +91,21 @@ export declare function cn(...inputs: ClassValue[]) {
|
|
|
91
91
|
return twMerge(clsx(inputs));
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
export declare const PasswordField: default_2.FC<PasswordFieldProps>;
|
|
95
|
+
|
|
96
|
+
export declare interface PasswordFieldProps extends Omit<TextFieldProps, 'type' | 'endAdornment'> {
|
|
97
|
+
showStrengthIndicator?: boolean;
|
|
98
|
+
toggleAriaLabel?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
94
101
|
export declare const TextField: default_2.FC<TextFieldProps>;
|
|
95
102
|
|
|
96
103
|
declare interface TextFieldProps extends default_2.ComponentProps<'input'> {
|
|
97
104
|
label?: string;
|
|
98
|
-
message?:
|
|
105
|
+
message?: default_2.ReactNode;
|
|
99
106
|
required?: boolean;
|
|
100
107
|
error?: boolean;
|
|
108
|
+
endAdornment?: default_2.ReactNode;
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
export declare const ThemeToggle: default_2.FC<ThemeToggleProps>;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,109 @@
|
|
|
1
|
-
|
|
1
|
+
import { c as cn } from './utils.js';
|
|
2
2
|
export { B as Button, b as buttonVariants } from './Button.js';
|
|
3
3
|
export { C as Card, a as CardContent, b as CardDescription, c as CardFooter, d as CardHeader, e as CardTitle } from './Card.js';
|
|
4
|
-
|
|
4
|
+
import { T as TextField } from './TextField.js';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
import { c as createLucideIcon } from './ThemeToggle.js';
|
|
5
8
|
export { T as ThemeToggle } from './ThemeToggle.js';
|
|
6
9
|
export { T as Typography } from './Typography.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @license lucide-react v0.544.0 - ISC
|
|
13
|
+
*
|
|
14
|
+
* This source code is licensed under the ISC license.
|
|
15
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
const __iconNode$1 = [
|
|
20
|
+
[
|
|
21
|
+
"path",
|
|
22
|
+
{
|
|
23
|
+
d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",
|
|
24
|
+
key: "ct8e1f"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
["path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242", key: "151rxh" }],
|
|
28
|
+
[
|
|
29
|
+
"path",
|
|
30
|
+
{
|
|
31
|
+
d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",
|
|
32
|
+
key: "13bj9a"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
["path", { d: "m2 2 20 20", key: "1ooewy" }]
|
|
36
|
+
];
|
|
37
|
+
const EyeOff = createLucideIcon("eye-off", __iconNode$1);
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @license lucide-react v0.544.0 - ISC
|
|
41
|
+
*
|
|
42
|
+
* This source code is licensed under the ISC license.
|
|
43
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const __iconNode = [
|
|
48
|
+
[
|
|
49
|
+
"path",
|
|
50
|
+
{
|
|
51
|
+
d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",
|
|
52
|
+
key: "1nclc0"
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
56
|
+
];
|
|
57
|
+
const Eye = createLucideIcon("eye", __iconNode);
|
|
58
|
+
|
|
59
|
+
const getPasswordStrength = (password) => {
|
|
60
|
+
let strength = 0;
|
|
61
|
+
if (password.length >= 8) strength += 1;
|
|
62
|
+
if (/[A-Z]/.test(password)) strength += 1;
|
|
63
|
+
if (/[a-z]/.test(password)) strength += 1;
|
|
64
|
+
if (/[0-9]/.test(password)) strength += 1;
|
|
65
|
+
if (/[^A-Za-z0-9]/.test(password)) strength += 1;
|
|
66
|
+
if (strength < 2) return { label: "Weak", color: "text-red-500", bgColor: "bg-red-500", width: "20%" };
|
|
67
|
+
if (strength < 4) return { label: "Fair", color: "text-yellow-500", bgColor: "bg-yellow-500", width: "60%" };
|
|
68
|
+
return { label: "Strong", color: "text-green-500", bgColor: "bg-green-500", width: "100%" };
|
|
69
|
+
};
|
|
70
|
+
const PasswordField = ({
|
|
71
|
+
showStrengthIndicator = false,
|
|
72
|
+
toggleAriaLabel,
|
|
73
|
+
value = "",
|
|
74
|
+
message,
|
|
75
|
+
error,
|
|
76
|
+
...props
|
|
77
|
+
}) => {
|
|
78
|
+
const [showPassword, setShowPassword] = useState(false);
|
|
79
|
+
const passwordStrength = getPasswordStrength(String(value));
|
|
80
|
+
const enhancedMessage = showStrengthIndicator && value && !error ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
81
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center text-xs", children: [
|
|
82
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Password strength:" }),
|
|
83
|
+
/* @__PURE__ */ jsx("span", { className: passwordStrength.color, children: passwordStrength.label })
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsx("div", { className: "w-full bg-muted rounded-full h-1", children: /* @__PURE__ */ jsx(
|
|
86
|
+
"div",
|
|
87
|
+
{
|
|
88
|
+
className: cn("h-1 rounded-full transition-all duration-300", passwordStrength.bgColor),
|
|
89
|
+
style: { width: passwordStrength.width }
|
|
90
|
+
}
|
|
91
|
+
) }),
|
|
92
|
+
message && /* @__PURE__ */ jsx("div", { children: message })
|
|
93
|
+
] }) : message;
|
|
94
|
+
const eyeIcon = showPassword ? /* @__PURE__ */ jsx(EyeOff, {}) : /* @__PURE__ */ jsx(Eye, {});
|
|
95
|
+
return /* @__PURE__ */ jsx(
|
|
96
|
+
TextField,
|
|
97
|
+
{
|
|
98
|
+
...props,
|
|
99
|
+
type: showPassword ? "text" : "password",
|
|
100
|
+
value,
|
|
101
|
+
message: enhancedMessage,
|
|
102
|
+
error,
|
|
103
|
+
endAdornment: eyeIcon
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export { PasswordField, TextField, cn };
|
|
7
109
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../node_modules/lucide-react/dist/esm/icons/eye-off.js","../node_modules/lucide-react/dist/esm/icons/eye.js","../lib/components/PasswordField/PasswordField.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\",\n key: \"ct8e1f\"\n }\n ],\n [\"path\", { d: \"M14.084 14.158a3 3 0 0 1-4.242-4.242\", key: \"151rxh\" }],\n [\n \"path\",\n {\n d: \"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\",\n key: \"13bj9a\"\n }\n ],\n [\"path\", { d: \"m2 2 20 20\", key: \"1ooewy\" }]\n];\nconst EyeOff = createLucideIcon(\"eye-off\", __iconNode);\n\nexport { __iconNode, EyeOff as default };\n//# sourceMappingURL=eye-off.js.map\n","/**\n * @license lucide-react v0.544.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst __iconNode = [\n [\n \"path\",\n {\n d: \"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\",\n key: \"1nclc0\"\n }\n ],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }]\n];\nconst Eye = createLucideIcon(\"eye\", __iconNode);\n\nexport { __iconNode, Eye as default };\n//# sourceMappingURL=eye.js.map\n","import { Eye, EyeOff } from 'lucide-react';\nimport React, { useState } from 'react';\nimport { cn } from '../../../shadcn/utils';\nimport { TextField, TextFieldProps } from '../TextField/TextField';\n\nexport interface PasswordFieldProps extends Omit<TextFieldProps, 'type' | 'endAdornment'> {\n /**\n * Whether to show password strength indicator\n */\n showStrengthIndicator?: boolean;\n\n /**\n * Custom aria-label for the visibility toggle button\n */\n toggleAriaLabel?: string;\n}\n\n// Helper function to calculate password strength\nconst getPasswordStrength = (password: string) => {\n let strength = 0;\n if (password.length >= 8) strength += 1;\n if (/[A-Z]/.test(password)) strength += 1;\n if (/[a-z]/.test(password)) strength += 1;\n if (/[0-9]/.test(password)) strength += 1;\n if (/[^A-Za-z0-9]/.test(password)) strength += 1;\n\n if (strength < 2) return { label: 'Weak', color: 'text-red-500', bgColor: 'bg-red-500', width: '20%' };\n if (strength < 4) return { label: 'Fair', color: 'text-yellow-500', bgColor: 'bg-yellow-500', width: '60%' };\n return { label: 'Strong', color: 'text-green-500', bgColor: 'bg-green-500', width: '100%' };\n};\n\n// PasswordField component - specialized TextField for password inputs\nexport const PasswordField: React.FC<PasswordFieldProps> = ({\n showStrengthIndicator = false,\n toggleAriaLabel,\n value = '',\n message,\n error,\n ...props\n}) => {\n const [showPassword, setShowPassword] = useState(false);\n\n const togglePasswordVisibility = () => {\n setShowPassword(!showPassword);\n };\n\n const passwordStrength = getPasswordStrength(String(value));\n\n // Combine strength indicator with existing message\n const enhancedMessage =\n showStrengthIndicator && value && !error ? (\n <div className='space-y-2'>\n <div className='flex justify-between items-center text-xs'>\n <span className='text-muted-foreground'>Password strength:</span>\n <span className={passwordStrength.color}>{passwordStrength.label}</span>\n </div>\n <div className='w-full bg-muted rounded-full h-1'>\n <div\n className={cn('h-1 rounded-full transition-all duration-300', passwordStrength.bgColor)}\n style={{ width: passwordStrength.width }}\n />\n </div>\n {message && <div>{message}</div>}\n </div>\n ) : (\n message\n );\n\n const eyeIcon = showPassword ? <EyeOff /> : <Eye />;\n\n return (\n <TextField\n {...props}\n type={showPassword ? 'text' : 'password'}\n value={value}\n message={enhancedMessage}\n error={error}\n endAdornment={eyeIcon}\n />\n );\n};\n"],"names":["__iconNode"],"mappings":"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","x_google_ignoreList":[0,1]}
|
package/package.json
CHANGED
package/readme.md
DELETED
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
# Quantum UI
|
|
2
|
-
|
|
3
|
-
A production-ready React component library built with TypeScript, Material-UI, and semantic design tokens. Quantum UI provides intent-based components with advanced theming, SSR-safe implementation, and zero-flickering user experience across all major React frameworks.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
✨ **Intent-Based Components** - Business-focused APIs (`intent="primary"` vs `color="blue"`)
|
|
8
|
-
🎨 **Dual Font System** - Space Grotesk (display) + Quicksand/Inter (body text)
|
|
9
|
-
🌓 **Zero-Flickering SSR** - Advanced theme script prevents hydration flashes
|
|
10
|
-
📱 **Mobile-First Responsive** - Sophisticated breakpoint system (mobile/tablet/desktop)
|
|
11
|
-
⚡ **Performance Optimized** - Tree-shakeable imports (~0.5-1KB per component)
|
|
12
|
-
🚀 **Framework Agnostic** - Next.js, Remix, Vite, CRA support out of the box
|
|
13
|
-
🎭 **Advanced Animations** - Confidence energy fields with reduced motion support
|
|
14
|
-
🔮 **Glassmorphism Effects** - Backdrop blur and sophisticated visual effects
|
|
15
|
-
📍 **Comprehensive Storybook** - Interactive component documentation
|
|
16
|
-
🔧 **Full TypeScript** - Complete type safety with intelligent autocomplete
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install quantum-ui
|
|
22
|
-
# or
|
|
23
|
-
yarn add quantum-ui
|
|
24
|
-
# or
|
|
25
|
-
pnpm add quantum-ui
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Quick Start
|
|
29
|
-
|
|
30
|
-
### Basic Setup (Vite/CRA)
|
|
31
|
-
|
|
32
|
-
```tsx
|
|
33
|
-
import React from 'react';
|
|
34
|
-
import { ThemeScript, ThemeProvider, Button, Typography, Paper } from 'quantum-ui';
|
|
35
|
-
|
|
36
|
-
function App() {
|
|
37
|
-
return (
|
|
38
|
-
<>
|
|
39
|
-
{/* Add ThemeScript to prevent flickering */}
|
|
40
|
-
<ThemeScript defaultColorScheme='light' />
|
|
41
|
-
|
|
42
|
-
<ThemeProvider defaultColorScheme='light'>
|
|
43
|
-
<Paper variant='elevated'>
|
|
44
|
-
<Typography variant='h1'>Welcome to Quantum UI</Typography>
|
|
45
|
-
<Typography variant='body1' intent='secondary'>
|
|
46
|
-
A modern component library for business applications
|
|
47
|
-
</Typography>
|
|
48
|
-
<Button intent='primary'>Get Started</Button>
|
|
49
|
-
</Paper>
|
|
50
|
-
</ThemeProvider>
|
|
51
|
-
</>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Performance-Optimized Imports
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
// ✅ Tree-shakeable direct imports (recommended for optimal performance)
|
|
60
|
-
import { Button } from 'quantum-ui/Button';
|
|
61
|
-
import { TextField } from 'quantum-ui/TextField';
|
|
62
|
-
import { Paper } from 'quantum-ui/Paper';
|
|
63
|
-
import { Typography } from 'quantum-ui/Typography';
|
|
64
|
-
|
|
65
|
-
// ✅ Theme utilities (barrel import acceptable - small bundle impact)
|
|
66
|
-
import { ThemeProvider, ThemeScript, useTheme } from 'quantum-ui';
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Framework Integration
|
|
70
|
-
|
|
71
|
-
### Next.js Setup
|
|
72
|
-
|
|
73
|
-
#### App Router (app/layout.tsx)
|
|
74
|
-
|
|
75
|
-
```tsx
|
|
76
|
-
import { ThemeScript } from 'quantum-ui';
|
|
77
|
-
|
|
78
|
-
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
79
|
-
return (
|
|
80
|
-
<html lang='en'>
|
|
81
|
-
<head>
|
|
82
|
-
<ThemeScript defaultColorScheme='light' />
|
|
83
|
-
</head>
|
|
84
|
-
<body>{children}</body>
|
|
85
|
-
</html>
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
#### Pages Router (\_document.tsx)
|
|
91
|
-
|
|
92
|
-
```tsx
|
|
93
|
-
import { Html, Head, Main, NextScript } from 'next/document';
|
|
94
|
-
import { ThemeScript } from 'quantum-ui';
|
|
95
|
-
|
|
96
|
-
export default function Document() {
|
|
97
|
-
return (
|
|
98
|
-
<Html>
|
|
99
|
-
<Head />
|
|
100
|
-
<body>
|
|
101
|
-
<ThemeScript defaultColorScheme='light' />
|
|
102
|
-
<Main />
|
|
103
|
-
<NextScript />
|
|
104
|
-
</body>
|
|
105
|
-
</Html>
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
#### App Component (\_app.tsx or layout.tsx)
|
|
111
|
-
|
|
112
|
-
```tsx
|
|
113
|
-
import { ThemeProvider } from 'quantum-ui';
|
|
114
|
-
|
|
115
|
-
export default function App({ Component, pageProps }) {
|
|
116
|
-
return (
|
|
117
|
-
<ThemeProvider defaultColorScheme='light'>
|
|
118
|
-
<Component {...pageProps} />
|
|
119
|
-
</ThemeProvider>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Vite Setup
|
|
125
|
-
|
|
126
|
-
#### index.html
|
|
127
|
-
|
|
128
|
-
```html
|
|
129
|
-
<!DOCTYPE html>
|
|
130
|
-
<html lang="en" data-theme="light">
|
|
131
|
-
<head>
|
|
132
|
-
<meta charset="UTF-8" />
|
|
133
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
134
|
-
<title>Your App</title>
|
|
135
|
-
</head>
|
|
136
|
-
<body>
|
|
137
|
-
<div id="root"></div>
|
|
138
|
-
<script type="module">
|
|
139
|
-
// Add theme script before app loads
|
|
140
|
-
import { getThemeScript } from 'quantum-ui';
|
|
141
|
-
const script = document.createElement('script');
|
|
142
|
-
script.innerHTML = getThemeScript({ defaultColorScheme: 'light' });
|
|
143
|
-
document.head.appendChild(script);
|
|
144
|
-
</script>
|
|
145
|
-
<script type="module" src="/src/main.tsx"></script>
|
|
146
|
-
</body>
|
|
147
|
-
</html>
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
#### main.tsx
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
import React from 'react';
|
|
154
|
-
import ReactDOM from 'react-dom/client';
|
|
155
|
-
import { ThemeProvider } from 'quantum-ui';
|
|
156
|
-
import App from './App';
|
|
157
|
-
|
|
158
|
-
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
159
|
-
<React.StrictMode>
|
|
160
|
-
<ThemeProvider defaultColorScheme='light'>
|
|
161
|
-
<App />
|
|
162
|
-
</ThemeProvider>
|
|
163
|
-
</React.StrictMode>
|
|
164
|
-
);
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Webpack/CRA Setup
|
|
168
|
-
|
|
169
|
-
#### public/index.html
|
|
170
|
-
|
|
171
|
-
```html
|
|
172
|
-
<!DOCTYPE html>
|
|
173
|
-
<html lang="en" data-theme="light">
|
|
174
|
-
<head>
|
|
175
|
-
<meta charset="utf-8" />
|
|
176
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
177
|
-
<title>Your App</title>
|
|
178
|
-
<script>
|
|
179
|
-
// Add theme script manually (copy from getThemeScript() output)
|
|
180
|
-
(function () {
|
|
181
|
-
document.documentElement.classList.add('no-transition');
|
|
182
|
-
try {
|
|
183
|
-
const savedScheme = localStorage.getItem('quantum-color-scheme');
|
|
184
|
-
const validSchemes = ['light', 'dark'];
|
|
185
|
-
const themeToApply = savedScheme && validSchemes.includes(savedScheme) ? savedScheme : 'light';
|
|
186
|
-
document.documentElement.setAttribute('data-theme', themeToApply);
|
|
187
|
-
} catch (e) {
|
|
188
|
-
document.documentElement.setAttribute('data-theme', 'light');
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function enableTransitions() {
|
|
192
|
-
document.documentElement.classList.remove('no-transition');
|
|
193
|
-
document.documentElement.classList.add('loaded');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (document.readyState === 'loading') {
|
|
197
|
-
window.addEventListener('DOMContentLoaded', function () {
|
|
198
|
-
setTimeout(enableTransitions, 100);
|
|
199
|
-
});
|
|
200
|
-
} else {
|
|
201
|
-
setTimeout(enableTransitions, 100);
|
|
202
|
-
}
|
|
203
|
-
})();
|
|
204
|
-
</script>
|
|
205
|
-
</head>
|
|
206
|
-
<body>
|
|
207
|
-
<div id="root"></div>
|
|
208
|
-
</body>
|
|
209
|
-
</html>
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
#### src/App.tsx
|
|
213
|
-
|
|
214
|
-
```tsx
|
|
215
|
-
import React from 'react';
|
|
216
|
-
import { ThemeProvider } from 'quantum-ui';
|
|
217
|
-
import YourComponents from './components';
|
|
218
|
-
|
|
219
|
-
function App() {
|
|
220
|
-
return (
|
|
221
|
-
<ThemeProvider defaultColorScheme='light'>
|
|
222
|
-
<YourComponents />
|
|
223
|
-
</ThemeProvider>
|
|
224
|
-
);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export default App;
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
### Remix Setup
|
|
231
|
-
|
|
232
|
-
#### app/root.tsx
|
|
233
|
-
|
|
234
|
-
```tsx
|
|
235
|
-
import { ThemeScript, ThemeProvider } from 'quantum-ui';
|
|
236
|
-
|
|
237
|
-
export default function App() {
|
|
238
|
-
return (
|
|
239
|
-
<html lang='en'>
|
|
240
|
-
<head>
|
|
241
|
-
<Meta />
|
|
242
|
-
<Links />
|
|
243
|
-
<ThemeScript defaultColorScheme='light' />
|
|
244
|
-
</head>
|
|
245
|
-
<body>
|
|
246
|
-
<ThemeProvider defaultColorScheme='light'>
|
|
247
|
-
<Outlet />
|
|
248
|
-
</ThemeProvider>
|
|
249
|
-
<ScrollRestoration />
|
|
250
|
-
<Scripts />
|
|
251
|
-
<LiveReload />
|
|
252
|
-
</body>
|
|
253
|
-
</html>
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
## Components
|
|
259
|
-
|
|
260
|
-
### Core Components (Production Ready)
|
|
261
|
-
|
|
262
|
-
- **Button** - Intent-based variants (`primary`, `secondary`, `destructive`, `ghost`) with advanced animations
|
|
263
|
-
- **Typography** - Complete text system with semantic intents and responsive scaling
|
|
264
|
-
- **TextField** - State-driven inputs (`normal`, `error`, `success`, `warning`) with glassmorphism styling
|
|
265
|
-
- **Paper** - Surface containers with variants (`standard`, `glass`, `elevated`, `subtle`)
|
|
266
|
-
|
|
267
|
-
### Theme System
|
|
268
|
-
|
|
269
|
-
- **ThemeProvider** - Global theme and color scheme management
|
|
270
|
-
- **ThemeScript** - Prevents theme flickering (add before React loads)
|
|
271
|
-
- **useTheme** - Hook for accessing theme context and toggling modes
|
|
272
|
-
- **useIsClient** - Utility hook for client-only components
|
|
273
|
-
|
|
274
|
-
## Theming API
|
|
275
|
-
|
|
276
|
-
### ThemeScript Configuration
|
|
277
|
-
|
|
278
|
-
```tsx
|
|
279
|
-
<ThemeScript
|
|
280
|
-
defaultColorScheme='dark' // Default: "light"
|
|
281
|
-
storageKey='my-theme-key' // Default: "quantum-color-scheme"
|
|
282
|
-
attribute='data-color-mode' // Default: "data-theme"
|
|
283
|
-
preventFlickering={false} // Default: true
|
|
284
|
-
/>
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### ThemeProvider Configuration
|
|
288
|
-
|
|
289
|
-
```tsx
|
|
290
|
-
<ThemeProvider
|
|
291
|
-
defaultColorScheme='dark' // Must match ThemeScript
|
|
292
|
-
storageKey='my-theme-key' // Must match ThemeScript
|
|
293
|
-
attribute='data-color-mode' // Must match ThemeScript
|
|
294
|
-
>
|
|
295
|
-
<App />
|
|
296
|
-
</ThemeProvider>
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### useTheme Hook
|
|
300
|
-
|
|
301
|
-
```tsx
|
|
302
|
-
function ThemeToggle() {
|
|
303
|
-
const {
|
|
304
|
-
colorScheme, // Current theme: "light" | "dark"
|
|
305
|
-
toggleColorScheme, // Toggle between themes
|
|
306
|
-
setTheme, // Set specific theme
|
|
307
|
-
isHydrated, // Whether React has hydrated
|
|
308
|
-
} = useTheme();
|
|
309
|
-
|
|
310
|
-
return <button onClick={toggleColorScheme}>Current: {colorScheme}</button>;
|
|
311
|
-
}
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
## Component APIs
|
|
315
|
-
|
|
316
|
-
### Button
|
|
317
|
-
|
|
318
|
-
```tsx
|
|
319
|
-
import { Button } from 'quantum-ui/Button';
|
|
320
|
-
import type { ButtonProps } from 'quantum-ui/Button';
|
|
321
|
-
|
|
322
|
-
interface ButtonProps {
|
|
323
|
-
intent?: 'primary' | 'secondary' | 'destructive' | 'ghost';
|
|
324
|
-
size?: 'small' | 'medium' | 'large';
|
|
325
|
-
fullWidth?: boolean;
|
|
326
|
-
disabled?: boolean;
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### Typography
|
|
331
|
-
|
|
332
|
-
```tsx
|
|
333
|
-
import { Typography } from 'quantum-ui/Typography';
|
|
334
|
-
import type { TypographyProps } from 'quantum-ui/Typography';
|
|
335
|
-
|
|
336
|
-
interface TypographyProps {
|
|
337
|
-
intent?: 'primary' | 'secondary' | 'disabled';
|
|
338
|
-
variant?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body1' | 'body2' | 'button' | 'caption' | 'overline';
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### TextField
|
|
343
|
-
|
|
344
|
-
```tsx
|
|
345
|
-
import { TextField } from 'quantum-ui/TextField';
|
|
346
|
-
import type { TextFieldProps } from 'quantum-ui/TextField';
|
|
347
|
-
|
|
348
|
-
interface TextFieldProps {
|
|
349
|
-
state?: 'normal' | 'error' | 'success' | 'warning';
|
|
350
|
-
label?: string;
|
|
351
|
-
message?: string;
|
|
352
|
-
fullWidth?: boolean;
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Paper
|
|
357
|
-
|
|
358
|
-
```tsx
|
|
359
|
-
import { Paper } from 'quantum-ui/Paper';
|
|
360
|
-
import type { PaperProps } from 'quantum-ui/Paper';
|
|
361
|
-
|
|
362
|
-
interface PaperProps {
|
|
363
|
-
variant?: 'standard' | 'glass' | 'elevated' | 'subtle';
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
## Development
|
|
368
|
-
|
|
369
|
-
```bash
|
|
370
|
-
# Install dependencies
|
|
371
|
-
npm install
|
|
372
|
-
|
|
373
|
-
# Start development server
|
|
374
|
-
npm run dev
|
|
375
|
-
|
|
376
|
-
# Run Storybook
|
|
377
|
-
npm run storybook
|
|
378
|
-
|
|
379
|
-
# Build library
|
|
380
|
-
npm run build
|
|
381
|
-
|
|
382
|
-
# Run linting
|
|
383
|
-
npm run lint
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
## Performance Best Practices
|
|
387
|
-
|
|
388
|
-
### Import Strategy
|
|
389
|
-
|
|
390
|
-
```tsx
|
|
391
|
-
// ✅ BEST: Direct component imports (optimal tree-shaking)
|
|
392
|
-
import { Button } from 'quantum-ui/Button';
|
|
393
|
-
import { TextField } from 'quantum-ui/TextField';
|
|
394
|
-
|
|
395
|
-
// ✅ GOOD: Theme utilities barrel import (small bundle impact)
|
|
396
|
-
import { ThemeProvider, useTheme } from 'quantum-ui';
|
|
397
|
-
|
|
398
|
-
// ❌ AVOID: Component barrel imports (larger bundles)
|
|
399
|
-
import { Button, TextField } from 'quantum-ui';
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### Bundle Size Optimization
|
|
403
|
-
|
|
404
|
-
- **Individual components**: ~0.5-1KB gzipped each
|
|
405
|
-
- **Theme system**: ~8KB gzipped (includes MUI theme)
|
|
406
|
-
- **Full library**: Import only what you use for optimal performance
|
|
407
|
-
|
|
408
|
-
## SSR Considerations
|
|
409
|
-
|
|
410
|
-
### Zero Flickering Setup
|
|
411
|
-
|
|
412
|
-
1. **Add ThemeScript** before React loads (prevents flickering)
|
|
413
|
-
2. **Configure ThemeProvider** with matching settings
|
|
414
|
-
3. **Use consistent defaults** across script and provider
|
|
415
|
-
|
|
416
|
-
### Hydration Safety
|
|
417
|
-
|
|
418
|
-
- ThemeProvider ensures no hydration mismatches
|
|
419
|
-
- `isHydrated` flag available for client-only features
|
|
420
|
-
- `useIsClient` hook for conditional rendering
|
|
421
|
-
|
|
422
|
-
## Design System
|
|
423
|
-
|
|
424
|
-
Quantum UI is built on a sophisticated design token system:
|
|
425
|
-
|
|
426
|
-
- **Colors**: Semantic color system with light/dark mode support
|
|
427
|
-
- **Typography**: Responsive font scaling with dual font approach
|
|
428
|
-
- **Spacing**: Consistent spacing scale across all breakpoints
|
|
429
|
-
- **Shadows**: Elevated and glass morphism effects
|
|
430
|
-
- **Animations**: Smooth transitions with reduced motion support
|
|
431
|
-
|
|
432
|
-
## Architecture Highlights
|
|
433
|
-
|
|
434
|
-
### Design Philosophy
|
|
435
|
-
|
|
436
|
-
- **Intent over Style** - Components use semantic intents rather than style props
|
|
437
|
-
- **Theme-First Architecture** - Everything uses CSS variables, zero hardcoded values
|
|
438
|
-
- **Progressive Enhancement** - Mobile-first with desktop refinements
|
|
439
|
-
- **Performance by Design** - React.memo, constant lookups, zero runtime CSS-in-JS
|
|
440
|
-
|
|
441
|
-
### Advanced Features
|
|
442
|
-
|
|
443
|
-
- **Blue Brand Theming** - Universal blue (#0066CC) with subtle input backgrounds
|
|
444
|
-
- **Sophisticated Shadows** - Theme-aware with different opacity for light/dark modes
|
|
445
|
-
- **Animation System** - Confidence animations with accessibility considerations
|
|
446
|
-
- **SSR Excellence** - Zero hydration mismatches across all supported frameworks
|
|
447
|
-
|
|
448
|
-
### Bundle Optimization
|
|
449
|
-
|
|
450
|
-
```bash
|
|
451
|
-
# Individual component sizes (gzipped)
|
|
452
|
-
Button: ~0.7KB
|
|
453
|
-
TextField: ~0.9KB
|
|
454
|
-
Paper: ~0.5KB
|
|
455
|
-
Typography: ~0.6KB
|
|
456
|
-
Theme System: ~8KB (includes MUI theme)
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
## Browser Support
|
|
460
|
-
|
|
461
|
-
- Chrome 90+ (Backdrop filter support)
|
|
462
|
-
- Firefox 88+ (CSS custom properties)
|
|
463
|
-
- Safari 14+ (Modern CSS features)
|
|
464
|
-
- Edge 90+ (Chromium-based)
|
|
465
|
-
|
|
466
|
-
## License
|
|
467
|
-
|
|
468
|
-
MIT License - see LICENSE file for details.
|
|
469
|
-
|
|
470
|
-
---
|
|
471
|
-
|
|
472
|
-
**Status**: All components are production-ready and fully implemented. The codebase represents a mature, sophisticated design system with excellent architecture and performance characteristics.
|