@flopay/ui 0.3.0 → 0.4.0
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/index.cjs +90 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54 -8
- package/dist/index.d.ts +54 -8
- package/dist/index.mjs +85 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/styles/components.css +158 -3
- package/styles/preset.css +2 -0
- package/styles/tokens.css +8 -0
package/dist/index.cjs
CHANGED
|
@@ -24,8 +24,13 @@ __export(index_exports, {
|
|
|
24
24
|
Button: () => Button,
|
|
25
25
|
Card: () => Card,
|
|
26
26
|
Container: () => Container,
|
|
27
|
+
EmptyState: () => EmptyState,
|
|
28
|
+
Field: () => Field,
|
|
29
|
+
Input: () => Input,
|
|
30
|
+
Label: () => Label,
|
|
27
31
|
Section: () => Section,
|
|
28
32
|
SectionHeader: () => SectionHeader,
|
|
33
|
+
Spinner: () => Spinner,
|
|
29
34
|
cn: () => cn
|
|
30
35
|
});
|
|
31
36
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -39,8 +44,21 @@ function cn(...inputs) {
|
|
|
39
44
|
|
|
40
45
|
// src/components/badge.tsx
|
|
41
46
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
var variantClass = {
|
|
48
|
+
neutral: "",
|
|
49
|
+
success: "badge-success",
|
|
50
|
+
warning: "badge-warning",
|
|
51
|
+
danger: "badge-danger",
|
|
52
|
+
info: "badge-info"
|
|
53
|
+
};
|
|
54
|
+
function Badge({
|
|
55
|
+
dot = false,
|
|
56
|
+
variant = "neutral",
|
|
57
|
+
className,
|
|
58
|
+
children,
|
|
59
|
+
...props
|
|
60
|
+
}) {
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: cn("badge", variantClass[variant], className), ...props, children: [
|
|
44
62
|
dot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "badge-dot" }) : null,
|
|
45
63
|
children
|
|
46
64
|
] });
|
|
@@ -48,19 +66,43 @@ function Badge({ dot = false, className, children, ...props }) {
|
|
|
48
66
|
|
|
49
67
|
// src/components/button.tsx
|
|
50
68
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
51
|
-
var
|
|
69
|
+
var variantClass2 = {
|
|
52
70
|
primary: "btn-primary",
|
|
53
71
|
secondary: "btn-secondary",
|
|
54
72
|
outline: "btn-outline"
|
|
55
73
|
};
|
|
56
|
-
function Button({
|
|
57
|
-
|
|
74
|
+
function Button({
|
|
75
|
+
variant = "primary",
|
|
76
|
+
size = "md",
|
|
77
|
+
className,
|
|
78
|
+
type = "button",
|
|
79
|
+
...props
|
|
80
|
+
}) {
|
|
81
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
82
|
+
"button",
|
|
83
|
+
{
|
|
84
|
+
type,
|
|
85
|
+
className: cn(variantClass2[variant], size === "sm" && "btn-sm", className),
|
|
86
|
+
...props
|
|
87
|
+
}
|
|
88
|
+
);
|
|
58
89
|
}
|
|
59
90
|
|
|
60
91
|
// src/components/card.tsx
|
|
61
92
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
62
|
-
function Card({ className, ...props }) {
|
|
63
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
93
|
+
function Card({ padding = "md", interactive = false, className, ...props }) {
|
|
94
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
className: cn(
|
|
98
|
+
"card",
|
|
99
|
+
padding !== "none" && `card-pad-${padding}`,
|
|
100
|
+
interactive && "card-interactive",
|
|
101
|
+
className
|
|
102
|
+
),
|
|
103
|
+
...props
|
|
104
|
+
}
|
|
105
|
+
);
|
|
64
106
|
}
|
|
65
107
|
|
|
66
108
|
// src/components/container.tsx
|
|
@@ -69,16 +111,46 @@ function Container({ className, ...props }) {
|
|
|
69
111
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: cn("container", className), ...props });
|
|
70
112
|
}
|
|
71
113
|
|
|
72
|
-
// src/components/
|
|
114
|
+
// src/components/feedback.tsx
|
|
73
115
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
116
|
+
function Spinner({ center = false, className, ...props }) {
|
|
117
|
+
const spinner = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: cn("spinner", className), role: "status", "aria-label": "Loading", ...props });
|
|
118
|
+
return center ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "spinner-center", children: spinner }) : spinner;
|
|
119
|
+
}
|
|
120
|
+
function EmptyState({ title, description, icon, className }) {
|
|
121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: cn("empty-state", className), children: [
|
|
122
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "empty-state-icon", children: icon }) : null,
|
|
123
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "empty-state-title", children: title }),
|
|
124
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "empty-state-desc", children: description }) : null
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/components/field.tsx
|
|
129
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
130
|
+
function Input({ className, ...props }) {
|
|
131
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { className: cn("field", className), ...props });
|
|
132
|
+
}
|
|
133
|
+
function Label({ className, ...props }) {
|
|
134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { className: cn("field-label", className), ...props });
|
|
135
|
+
}
|
|
136
|
+
function Field({ label, hint, error, htmlFor, className, children }) {
|
|
137
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: cn("field-group", className), children: [
|
|
138
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Label, { htmlFor, children: label }) : null,
|
|
139
|
+
children,
|
|
140
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "field-error", children: error }) : hint ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "field-hint", children: hint }) : null
|
|
141
|
+
] });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/components/section.tsx
|
|
145
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
74
146
|
function Section({ className, ...props }) {
|
|
75
|
-
return /* @__PURE__ */ (0,
|
|
147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("section", { className: cn("section", className), ...props });
|
|
76
148
|
}
|
|
77
149
|
function SectionHeader({ label, title, description, className }) {
|
|
78
|
-
return /* @__PURE__ */ (0,
|
|
79
|
-
label ? /* @__PURE__ */ (0,
|
|
80
|
-
/* @__PURE__ */ (0,
|
|
81
|
-
description ? /* @__PURE__ */ (0,
|
|
150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cn("section-center", className), children: [
|
|
151
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "section-label", children: label }) : null,
|
|
152
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "section-title", children: title }),
|
|
153
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "section-desc", children: description }) : null
|
|
82
154
|
] });
|
|
83
155
|
}
|
|
84
156
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -87,8 +159,13 @@ function SectionHeader({ label, title, description, className }) {
|
|
|
87
159
|
Button,
|
|
88
160
|
Card,
|
|
89
161
|
Container,
|
|
162
|
+
EmptyState,
|
|
163
|
+
Field,
|
|
164
|
+
Input,
|
|
165
|
+
Label,
|
|
90
166
|
Section,
|
|
91
167
|
SectionHeader,
|
|
168
|
+
Spinner,
|
|
92
169
|
cn
|
|
93
170
|
});
|
|
94
171
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/cn.ts","../src/components/badge.tsx","../src/components/button.tsx","../src/components/card.tsx","../src/components/container.tsx","../src/components/section.tsx"],"sourcesContent":["export { cn } from './cn';\nexport type { BadgeProps } from './components/badge';\nexport { Badge } from './components/badge';\nexport type { ButtonProps, ButtonVariant } from './components/button';\nexport { Button } from './components/button';\nexport type { CardProps } from './components/card';\nexport { Card } from './components/card';\nexport type { ContainerProps } from './components/container';\nexport { Container } from './components/container';\nexport type { SectionHeaderProps, SectionProps } from './components/section';\nexport { Section, SectionHeader } from './components/section';\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names, resolving conflicting Tailwind utilities (last wins).\n * Mirrors the helper used across the FloPay frontends so consumers can extend\n * any primitive's classes safely.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Render a leading status dot. */\n dot?: boolean;\n}\n\n/** Pill badge, optionally with a leading status dot. */\nexport function Badge({ dot = false, className, children, ...props }: BadgeProps) {\n return (\n <span className={cn('badge', className)} {...props}>\n {dot ? <span className=\"badge-dot\" /> : null}\n {children}\n </span>\n );\n}\n","import type { ButtonHTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'outline';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n}\n\nconst variantClass: Record<ButtonVariant, string> = {\n primary: 'btn-primary',\n secondary: 'btn-secondary',\n outline: 'btn-outline',\n};\n\nexport function Button({ variant = 'primary', className, type = 'button', ...props }: ButtonProps) {\n return <button type={type} className={cn(variantClass[variant], className)} {...props} />;\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type CardProps = HTMLAttributes<HTMLDivElement>;\n\n/** Bordered surface card with hover elevation. */\nexport function Card({ className, ...props }: CardProps) {\n return <div className={cn('card', className)} {...props} />;\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ContainerProps = HTMLAttributes<HTMLDivElement>;\n\n/** Centered, max-width content wrapper (var(--max-w)) with horizontal padding. */\nexport function Container({ className, ...props }: ContainerProps) {\n return <div className={cn('container', className)} {...props} />;\n}\n","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport type SectionProps = HTMLAttributes<HTMLElement>;\n\n/** Vertical page section with max-width and standard padding. */\nexport function Section({ className, ...props }: SectionProps) {\n return <section className={cn('section', className)} {...props} />;\n}\n\nexport interface SectionHeaderProps {\n /** Small eyebrow label above the title (brand colored). */\n label?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n className?: string;\n}\n\n/** Centered section heading: optional label, title, optional description. */\nexport function SectionHeader({ label, title, description, className }: SectionHeaderProps) {\n return (\n <div className={cn('section-center', className)}>\n {label ? <div className=\"section-label\">{label}</div> : null}\n <h2 className=\"section-title\">{title}</h2>\n {description ? <p className=\"section-desc\">{description}</p> : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAAsC;AACtC,4BAAwB;AAOjB,SAAS,MAAM,QAAsB;AAC1C,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;ACCI;AAFG,SAAS,MAAM,EAAE,MAAM,OAAO,WAAW,UAAU,GAAG,MAAM,GAAe;AAChF,SACE,6CAAC,UAAK,WAAW,GAAG,SAAS,SAAS,GAAI,GAAG,OAC1C;AAAA,UAAM,4CAAC,UAAK,WAAU,aAAY,IAAK;AAAA,IACvC;AAAA,KACH;AAEJ;;;ACAS,IAAAA,sBAAA;AAPT,IAAM,eAA8C;AAAA,EAClD,SAAS;AAAA,EACT,WAAW;AAAA,EACX,SAAS;AACX;AAEO,SAAS,OAAO,EAAE,UAAU,WAAW,WAAW,OAAO,UAAU,GAAG,MAAM,GAAgB;AACjG,SAAO,6CAAC,YAAO,MAAY,WAAW,GAAG,aAAa,OAAO,GAAG,SAAS,GAAI,GAAG,OAAO;AACzF;;;ACVS,IAAAC,sBAAA;AADF,SAAS,KAAK,EAAE,WAAW,GAAG,MAAM,GAAc;AACvD,SAAO,6CAAC,SAAI,WAAW,GAAG,QAAQ,SAAS,GAAI,GAAG,OAAO;AAC3D;;;ACDS,IAAAC,sBAAA;AADF,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAmB;AACjE,SAAO,6CAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GAAI,GAAG,OAAO;AAChE;;;ACDS,IAAAC,sBAAA;AADF,SAAS,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAiB;AAC7D,SAAO,6CAAC,aAAQ,WAAW,GAAG,WAAW,SAAS,GAAI,GAAG,OAAO;AAClE;AAWO,SAAS,cAAc,EAAE,OAAO,OAAO,aAAa,UAAU,GAAuB;AAC1F,SACE,8CAAC,SAAI,WAAW,GAAG,kBAAkB,SAAS,GAC3C;AAAA,YAAQ,6CAAC,SAAI,WAAU,iBAAiB,iBAAM,IAAS;AAAA,IACxD,6CAAC,QAAG,WAAU,iBAAiB,iBAAM;AAAA,IACpC,cAAc,6CAAC,OAAE,WAAU,gBAAgB,uBAAY,IAAO;AAAA,KACjE;AAEJ;","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cn.ts","../src/components/badge.tsx","../src/components/button.tsx","../src/components/card.tsx","../src/components/container.tsx","../src/components/feedback.tsx","../src/components/field.tsx","../src/components/section.tsx"],"sourcesContent":["export { cn } from './cn';\n\nexport type { BadgeProps, BadgeVariant } from './components/badge';\nexport { Badge } from './components/badge';\nexport type { ButtonProps, ButtonSize, ButtonVariant } from './components/button';\nexport { Button } from './components/button';\nexport type { CardPadding, CardProps } from './components/card';\nexport { Card } from './components/card';\nexport type { ContainerProps } from './components/container';\nexport { Container } from './components/container';\nexport type { EmptyStateProps, SpinnerProps } from './components/feedback';\nexport { EmptyState, Spinner } from './components/feedback';\nexport type { FieldProps, InputProps, LabelProps } from './components/field';\nexport { Field, Input, Label } from './components/field';\nexport type { SectionHeaderProps, SectionProps } from './components/section';\nexport { Section, SectionHeader } from './components/section';\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge class names, resolving conflicting Tailwind utilities (last wins).\n * Mirrors the helper used across the FloPay frontends so consumers can extend\n * any primitive's classes safely.\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type BadgeVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Render a leading status dot. */\n dot?: boolean;\n /** Semantic color. `neutral` is the default outlined pill. */\n variant?: BadgeVariant;\n}\n\nconst variantClass: Record<BadgeVariant, string> = {\n neutral: '',\n success: 'badge-success',\n warning: 'badge-warning',\n danger: 'badge-danger',\n info: 'badge-info',\n};\n\n/** Pill badge — neutral by default, or a semantic variant, optionally with a dot. */\nexport function Badge({\n dot = false,\n variant = 'neutral',\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span className={cn('badge', variantClass[variant], className)} {...props}>\n {dot ? <span className=\"badge-dot\" /> : null}\n {children}\n </span>\n );\n}\n","import type { ButtonHTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'outline';\nexport type ButtonSize = 'md' | 'sm';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n}\n\nconst variantClass: Record<ButtonVariant, string> = {\n primary: 'btn-primary',\n secondary: 'btn-secondary',\n outline: 'btn-outline',\n};\n\nexport function Button({\n variant = 'primary',\n size = 'md',\n className,\n type = 'button',\n ...props\n}: ButtonProps) {\n return (\n <button\n type={type}\n className={cn(variantClass[variant], size === 'sm' && 'btn-sm', className)}\n {...props}\n />\n );\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Inner padding. Defaults to `md` (28px); use `none` to supply your own. */\n padding?: CardPadding;\n /** Add pointer cursor + hover elevation (for clickable cards). */\n interactive?: boolean;\n}\n\n/** Bordered surface card. Static by default; opt into hover with `interactive`. */\nexport function Card({ padding = 'md', interactive = false, className, ...props }: CardProps) {\n return (\n <div\n className={cn(\n 'card',\n padding !== 'none' && `card-pad-${padding}`,\n interactive && 'card-interactive',\n className,\n )}\n {...props}\n />\n );\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ContainerProps = HTMLAttributes<HTMLDivElement>;\n\n/** Centered, max-width content wrapper (var(--max-w)) with horizontal padding. */\nexport function Container({ className, ...props }: ContainerProps) {\n return <div className={cn('container', className)} {...props} />;\n}\n","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {\n /** Wrap in a centered, padded block (for loading states in a panel). */\n center?: boolean;\n}\n\n/** Brand-colored loading spinner. */\nexport function Spinner({ center = false, className, ...props }: SpinnerProps) {\n const spinner = (\n <span className={cn('spinner', className)} role=\"status\" aria-label=\"Loading\" {...props} />\n );\n return center ? <div className=\"spinner-center\">{spinner}</div> : spinner;\n}\n\nexport interface EmptyStateProps {\n title: ReactNode;\n description?: ReactNode;\n /** Optional icon rendered in the circular badge above the title. */\n icon?: ReactNode;\n className?: string;\n}\n\n/** Centered \"nothing here yet\" placeholder for empty lists/tables. */\nexport function EmptyState({ title, description, icon, className }: EmptyStateProps) {\n return (\n <div className={cn('empty-state', className)}>\n {icon ? <div className=\"empty-state-icon\">{icon}</div> : null}\n <h3 className=\"empty-state-title\">{title}</h3>\n {description ? <p className=\"empty-state-desc\">{description}</p> : null}\n </div>\n );\n}\n","import type { InputHTMLAttributes, LabelHTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport type InputProps = InputHTMLAttributes<HTMLInputElement>;\n\n/** Token-aligned text input (the `.field` look: border, surface, brand focus ring). */\nexport function Input({ className, ...props }: InputProps) {\n return <input className={cn('field', className)} {...props} />;\n}\n\nexport type LabelProps = LabelHTMLAttributes<HTMLLabelElement>;\n\nexport function Label({ className, ...props }: LabelProps) {\n return <label className={cn('field-label', className)} {...props} />;\n}\n\nexport interface FieldProps {\n label?: ReactNode;\n /** Helper text shown below the control (hidden when `error` is set). */\n hint?: ReactNode;\n /** Error text shown below the control (takes precedence over `hint`). */\n error?: ReactNode;\n /** `htmlFor` for the label, matching the control's id. */\n htmlFor?: string;\n className?: string;\n children: ReactNode;\n}\n\n/** Labelled field wrapper: optional label above and hint/error below the control. */\nexport function Field({ label, hint, error, htmlFor, className, children }: FieldProps) {\n return (\n <div className={cn('field-group', className)}>\n {label ? <Label htmlFor={htmlFor}>{label}</Label> : null}\n {children}\n {error ? (\n <span className=\"field-error\">{error}</span>\n ) : hint ? (\n <span className=\"field-hint\">{hint}</span>\n ) : null}\n </div>\n );\n}\n","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport type SectionProps = HTMLAttributes<HTMLElement>;\n\n/** Vertical page section with max-width and standard padding. */\nexport function Section({ className, ...props }: SectionProps) {\n return <section className={cn('section', className)} {...props} />;\n}\n\nexport interface SectionHeaderProps {\n /** Small eyebrow label above the title (brand colored). */\n label?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n className?: string;\n}\n\n/** Centered section heading: optional label, title, optional description. */\nexport function SectionHeader({ label, title, description, className }: SectionHeaderProps) {\n return (\n <div className={cn('section-center', className)}>\n {label ? <div className=\"section-label\">{label}</div> : null}\n <h2 className=\"section-title\">{title}</h2>\n {description ? <p className=\"section-desc\">{description}</p> : null}\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","variantClass","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClassValue } from 'clsx';
|
|
2
2
|
import * as react from 'react';
|
|
3
|
-
import { HTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
import { HTMLAttributes, ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, LabelHTMLAttributes } from 'react';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Merge class names, resolving conflicting Tailwind utilities (last wins).
|
|
@@ -9,27 +9,73 @@ import { HTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
|
9
9
|
*/
|
|
10
10
|
declare function cn(...inputs: ClassValue[]): string;
|
|
11
11
|
|
|
12
|
+
type BadgeVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
|
12
13
|
interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
13
14
|
/** Render a leading status dot. */
|
|
14
15
|
dot?: boolean;
|
|
16
|
+
/** Semantic color. `neutral` is the default outlined pill. */
|
|
17
|
+
variant?: BadgeVariant;
|
|
15
18
|
}
|
|
16
|
-
/** Pill badge, optionally with a
|
|
17
|
-
declare function Badge({ dot, className, children, ...props }: BadgeProps): react.JSX.Element;
|
|
19
|
+
/** Pill badge — neutral by default, or a semantic variant, optionally with a dot. */
|
|
20
|
+
declare function Badge({ dot, variant, className, children, ...props }: BadgeProps): react.JSX.Element;
|
|
18
21
|
|
|
19
22
|
type ButtonVariant = 'primary' | 'secondary' | 'outline';
|
|
23
|
+
type ButtonSize = 'md' | 'sm';
|
|
20
24
|
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
21
25
|
variant?: ButtonVariant;
|
|
26
|
+
size?: ButtonSize;
|
|
22
27
|
}
|
|
23
|
-
declare function Button({ variant, className, type, ...props }: ButtonProps): react.JSX.Element;
|
|
28
|
+
declare function Button({ variant, size, className, type, ...props }: ButtonProps): react.JSX.Element;
|
|
24
29
|
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
type CardPadding = 'none' | 'sm' | 'md' | 'lg';
|
|
31
|
+
interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
32
|
+
/** Inner padding. Defaults to `md` (28px); use `none` to supply your own. */
|
|
33
|
+
padding?: CardPadding;
|
|
34
|
+
/** Add pointer cursor + hover elevation (for clickable cards). */
|
|
35
|
+
interactive?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Bordered surface card. Static by default; opt into hover with `interactive`. */
|
|
38
|
+
declare function Card({ padding, interactive, className, ...props }: CardProps): react.JSX.Element;
|
|
28
39
|
|
|
29
40
|
type ContainerProps = HTMLAttributes<HTMLDivElement>;
|
|
30
41
|
/** Centered, max-width content wrapper (var(--max-w)) with horizontal padding. */
|
|
31
42
|
declare function Container({ className, ...props }: ContainerProps): react.JSX.Element;
|
|
32
43
|
|
|
44
|
+
interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
|
|
45
|
+
/** Wrap in a centered, padded block (for loading states in a panel). */
|
|
46
|
+
center?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Brand-colored loading spinner. */
|
|
49
|
+
declare function Spinner({ center, className, ...props }: SpinnerProps): react.JSX.Element;
|
|
50
|
+
interface EmptyStateProps {
|
|
51
|
+
title: ReactNode;
|
|
52
|
+
description?: ReactNode;
|
|
53
|
+
/** Optional icon rendered in the circular badge above the title. */
|
|
54
|
+
icon?: ReactNode;
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Centered "nothing here yet" placeholder for empty lists/tables. */
|
|
58
|
+
declare function EmptyState({ title, description, icon, className }: EmptyStateProps): react.JSX.Element;
|
|
59
|
+
|
|
60
|
+
type InputProps = InputHTMLAttributes<HTMLInputElement>;
|
|
61
|
+
/** Token-aligned text input (the `.field` look: border, surface, brand focus ring). */
|
|
62
|
+
declare function Input({ className, ...props }: InputProps): react.JSX.Element;
|
|
63
|
+
type LabelProps = LabelHTMLAttributes<HTMLLabelElement>;
|
|
64
|
+
declare function Label({ className, ...props }: LabelProps): react.JSX.Element;
|
|
65
|
+
interface FieldProps {
|
|
66
|
+
label?: ReactNode;
|
|
67
|
+
/** Helper text shown below the control (hidden when `error` is set). */
|
|
68
|
+
hint?: ReactNode;
|
|
69
|
+
/** Error text shown below the control (takes precedence over `hint`). */
|
|
70
|
+
error?: ReactNode;
|
|
71
|
+
/** `htmlFor` for the label, matching the control's id. */
|
|
72
|
+
htmlFor?: string;
|
|
73
|
+
className?: string;
|
|
74
|
+
children: ReactNode;
|
|
75
|
+
}
|
|
76
|
+
/** Labelled field wrapper: optional label above and hint/error below the control. */
|
|
77
|
+
declare function Field({ label, hint, error, htmlFor, className, children }: FieldProps): react.JSX.Element;
|
|
78
|
+
|
|
33
79
|
type SectionProps = HTMLAttributes<HTMLElement>;
|
|
34
80
|
/** Vertical page section with max-width and standard padding. */
|
|
35
81
|
declare function Section({ className, ...props }: SectionProps): react.JSX.Element;
|
|
@@ -43,4 +89,4 @@ interface SectionHeaderProps {
|
|
|
43
89
|
/** Centered section heading: optional label, title, optional description. */
|
|
44
90
|
declare function SectionHeader({ label, title, description, className }: SectionHeaderProps): react.JSX.Element;
|
|
45
91
|
|
|
46
|
-
export { Badge, type BadgeProps, Button, type ButtonProps, type ButtonVariant, Card, type CardProps, Container, type ContainerProps, Section, SectionHeader, type SectionHeaderProps, type SectionProps, cn };
|
|
92
|
+
export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, type CardPadding, type CardProps, Container, type ContainerProps, EmptyState, type EmptyStateProps, Field, type FieldProps, Input, type InputProps, Label, type LabelProps, Section, SectionHeader, type SectionHeaderProps, type SectionProps, Spinner, type SpinnerProps, cn };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClassValue } from 'clsx';
|
|
2
2
|
import * as react from 'react';
|
|
3
|
-
import { HTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
import { HTMLAttributes, ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, LabelHTMLAttributes } from 'react';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Merge class names, resolving conflicting Tailwind utilities (last wins).
|
|
@@ -9,27 +9,73 @@ import { HTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
|
|
|
9
9
|
*/
|
|
10
10
|
declare function cn(...inputs: ClassValue[]): string;
|
|
11
11
|
|
|
12
|
+
type BadgeVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
|
12
13
|
interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
|
|
13
14
|
/** Render a leading status dot. */
|
|
14
15
|
dot?: boolean;
|
|
16
|
+
/** Semantic color. `neutral` is the default outlined pill. */
|
|
17
|
+
variant?: BadgeVariant;
|
|
15
18
|
}
|
|
16
|
-
/** Pill badge, optionally with a
|
|
17
|
-
declare function Badge({ dot, className, children, ...props }: BadgeProps): react.JSX.Element;
|
|
19
|
+
/** Pill badge — neutral by default, or a semantic variant, optionally with a dot. */
|
|
20
|
+
declare function Badge({ dot, variant, className, children, ...props }: BadgeProps): react.JSX.Element;
|
|
18
21
|
|
|
19
22
|
type ButtonVariant = 'primary' | 'secondary' | 'outline';
|
|
23
|
+
type ButtonSize = 'md' | 'sm';
|
|
20
24
|
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
21
25
|
variant?: ButtonVariant;
|
|
26
|
+
size?: ButtonSize;
|
|
22
27
|
}
|
|
23
|
-
declare function Button({ variant, className, type, ...props }: ButtonProps): react.JSX.Element;
|
|
28
|
+
declare function Button({ variant, size, className, type, ...props }: ButtonProps): react.JSX.Element;
|
|
24
29
|
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
type CardPadding = 'none' | 'sm' | 'md' | 'lg';
|
|
31
|
+
interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
32
|
+
/** Inner padding. Defaults to `md` (28px); use `none` to supply your own. */
|
|
33
|
+
padding?: CardPadding;
|
|
34
|
+
/** Add pointer cursor + hover elevation (for clickable cards). */
|
|
35
|
+
interactive?: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** Bordered surface card. Static by default; opt into hover with `interactive`. */
|
|
38
|
+
declare function Card({ padding, interactive, className, ...props }: CardProps): react.JSX.Element;
|
|
28
39
|
|
|
29
40
|
type ContainerProps = HTMLAttributes<HTMLDivElement>;
|
|
30
41
|
/** Centered, max-width content wrapper (var(--max-w)) with horizontal padding. */
|
|
31
42
|
declare function Container({ className, ...props }: ContainerProps): react.JSX.Element;
|
|
32
43
|
|
|
44
|
+
interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
|
|
45
|
+
/** Wrap in a centered, padded block (for loading states in a panel). */
|
|
46
|
+
center?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Brand-colored loading spinner. */
|
|
49
|
+
declare function Spinner({ center, className, ...props }: SpinnerProps): react.JSX.Element;
|
|
50
|
+
interface EmptyStateProps {
|
|
51
|
+
title: ReactNode;
|
|
52
|
+
description?: ReactNode;
|
|
53
|
+
/** Optional icon rendered in the circular badge above the title. */
|
|
54
|
+
icon?: ReactNode;
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
/** Centered "nothing here yet" placeholder for empty lists/tables. */
|
|
58
|
+
declare function EmptyState({ title, description, icon, className }: EmptyStateProps): react.JSX.Element;
|
|
59
|
+
|
|
60
|
+
type InputProps = InputHTMLAttributes<HTMLInputElement>;
|
|
61
|
+
/** Token-aligned text input (the `.field` look: border, surface, brand focus ring). */
|
|
62
|
+
declare function Input({ className, ...props }: InputProps): react.JSX.Element;
|
|
63
|
+
type LabelProps = LabelHTMLAttributes<HTMLLabelElement>;
|
|
64
|
+
declare function Label({ className, ...props }: LabelProps): react.JSX.Element;
|
|
65
|
+
interface FieldProps {
|
|
66
|
+
label?: ReactNode;
|
|
67
|
+
/** Helper text shown below the control (hidden when `error` is set). */
|
|
68
|
+
hint?: ReactNode;
|
|
69
|
+
/** Error text shown below the control (takes precedence over `hint`). */
|
|
70
|
+
error?: ReactNode;
|
|
71
|
+
/** `htmlFor` for the label, matching the control's id. */
|
|
72
|
+
htmlFor?: string;
|
|
73
|
+
className?: string;
|
|
74
|
+
children: ReactNode;
|
|
75
|
+
}
|
|
76
|
+
/** Labelled field wrapper: optional label above and hint/error below the control. */
|
|
77
|
+
declare function Field({ label, hint, error, htmlFor, className, children }: FieldProps): react.JSX.Element;
|
|
78
|
+
|
|
33
79
|
type SectionProps = HTMLAttributes<HTMLElement>;
|
|
34
80
|
/** Vertical page section with max-width and standard padding. */
|
|
35
81
|
declare function Section({ className, ...props }: SectionProps): react.JSX.Element;
|
|
@@ -43,4 +89,4 @@ interface SectionHeaderProps {
|
|
|
43
89
|
/** Centered section heading: optional label, title, optional description. */
|
|
44
90
|
declare function SectionHeader({ label, title, description, className }: SectionHeaderProps): react.JSX.Element;
|
|
45
91
|
|
|
46
|
-
export { Badge, type BadgeProps, Button, type ButtonProps, type ButtonVariant, Card, type CardProps, Container, type ContainerProps, Section, SectionHeader, type SectionHeaderProps, type SectionProps, cn };
|
|
92
|
+
export { Badge, type BadgeProps, type BadgeVariant, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, type CardPadding, type CardProps, Container, type ContainerProps, EmptyState, type EmptyStateProps, Field, type FieldProps, Input, type InputProps, Label, type LabelProps, Section, SectionHeader, type SectionHeaderProps, type SectionProps, Spinner, type SpinnerProps, cn };
|
package/dist/index.mjs
CHANGED
|
@@ -4,8 +4,21 @@ import {
|
|
|
4
4
|
|
|
5
5
|
// src/components/badge.tsx
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
var variantClass = {
|
|
8
|
+
neutral: "",
|
|
9
|
+
success: "badge-success",
|
|
10
|
+
warning: "badge-warning",
|
|
11
|
+
danger: "badge-danger",
|
|
12
|
+
info: "badge-info"
|
|
13
|
+
};
|
|
14
|
+
function Badge({
|
|
15
|
+
dot = false,
|
|
16
|
+
variant = "neutral",
|
|
17
|
+
className,
|
|
18
|
+
children,
|
|
19
|
+
...props
|
|
20
|
+
}) {
|
|
21
|
+
return /* @__PURE__ */ jsxs("span", { className: cn("badge", variantClass[variant], className), ...props, children: [
|
|
9
22
|
dot ? /* @__PURE__ */ jsx("span", { className: "badge-dot" }) : null,
|
|
10
23
|
children
|
|
11
24
|
] });
|
|
@@ -13,19 +26,43 @@ function Badge({ dot = false, className, children, ...props }) {
|
|
|
13
26
|
|
|
14
27
|
// src/components/button.tsx
|
|
15
28
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
16
|
-
var
|
|
29
|
+
var variantClass2 = {
|
|
17
30
|
primary: "btn-primary",
|
|
18
31
|
secondary: "btn-secondary",
|
|
19
32
|
outline: "btn-outline"
|
|
20
33
|
};
|
|
21
|
-
function Button({
|
|
22
|
-
|
|
34
|
+
function Button({
|
|
35
|
+
variant = "primary",
|
|
36
|
+
size = "md",
|
|
37
|
+
className,
|
|
38
|
+
type = "button",
|
|
39
|
+
...props
|
|
40
|
+
}) {
|
|
41
|
+
return /* @__PURE__ */ jsx2(
|
|
42
|
+
"button",
|
|
43
|
+
{
|
|
44
|
+
type,
|
|
45
|
+
className: cn(variantClass2[variant], size === "sm" && "btn-sm", className),
|
|
46
|
+
...props
|
|
47
|
+
}
|
|
48
|
+
);
|
|
23
49
|
}
|
|
24
50
|
|
|
25
51
|
// src/components/card.tsx
|
|
26
52
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
27
|
-
function Card({ className, ...props }) {
|
|
28
|
-
return /* @__PURE__ */ jsx3(
|
|
53
|
+
function Card({ padding = "md", interactive = false, className, ...props }) {
|
|
54
|
+
return /* @__PURE__ */ jsx3(
|
|
55
|
+
"div",
|
|
56
|
+
{
|
|
57
|
+
className: cn(
|
|
58
|
+
"card",
|
|
59
|
+
padding !== "none" && `card-pad-${padding}`,
|
|
60
|
+
interactive && "card-interactive",
|
|
61
|
+
className
|
|
62
|
+
),
|
|
63
|
+
...props
|
|
64
|
+
}
|
|
65
|
+
);
|
|
29
66
|
}
|
|
30
67
|
|
|
31
68
|
// src/components/container.tsx
|
|
@@ -34,16 +71,46 @@ function Container({ className, ...props }) {
|
|
|
34
71
|
return /* @__PURE__ */ jsx4("div", { className: cn("container", className), ...props });
|
|
35
72
|
}
|
|
36
73
|
|
|
37
|
-
// src/components/
|
|
74
|
+
// src/components/feedback.tsx
|
|
38
75
|
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
76
|
+
function Spinner({ center = false, className, ...props }) {
|
|
77
|
+
const spinner = /* @__PURE__ */ jsx5("span", { className: cn("spinner", className), role: "status", "aria-label": "Loading", ...props });
|
|
78
|
+
return center ? /* @__PURE__ */ jsx5("div", { className: "spinner-center", children: spinner }) : spinner;
|
|
79
|
+
}
|
|
80
|
+
function EmptyState({ title, description, icon, className }) {
|
|
81
|
+
return /* @__PURE__ */ jsxs2("div", { className: cn("empty-state", className), children: [
|
|
82
|
+
icon ? /* @__PURE__ */ jsx5("div", { className: "empty-state-icon", children: icon }) : null,
|
|
83
|
+
/* @__PURE__ */ jsx5("h3", { className: "empty-state-title", children: title }),
|
|
84
|
+
description ? /* @__PURE__ */ jsx5("p", { className: "empty-state-desc", children: description }) : null
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/components/field.tsx
|
|
89
|
+
import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
90
|
+
function Input({ className, ...props }) {
|
|
91
|
+
return /* @__PURE__ */ jsx6("input", { className: cn("field", className), ...props });
|
|
92
|
+
}
|
|
93
|
+
function Label({ className, ...props }) {
|
|
94
|
+
return /* @__PURE__ */ jsx6("label", { className: cn("field-label", className), ...props });
|
|
95
|
+
}
|
|
96
|
+
function Field({ label, hint, error, htmlFor, className, children }) {
|
|
97
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("field-group", className), children: [
|
|
98
|
+
label ? /* @__PURE__ */ jsx6(Label, { htmlFor, children: label }) : null,
|
|
99
|
+
children,
|
|
100
|
+
error ? /* @__PURE__ */ jsx6("span", { className: "field-error", children: error }) : hint ? /* @__PURE__ */ jsx6("span", { className: "field-hint", children: hint }) : null
|
|
101
|
+
] });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/components/section.tsx
|
|
105
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
39
106
|
function Section({ className, ...props }) {
|
|
40
|
-
return /* @__PURE__ */
|
|
107
|
+
return /* @__PURE__ */ jsx7("section", { className: cn("section", className), ...props });
|
|
41
108
|
}
|
|
42
109
|
function SectionHeader({ label, title, description, className }) {
|
|
43
|
-
return /* @__PURE__ */
|
|
44
|
-
label ? /* @__PURE__ */
|
|
45
|
-
/* @__PURE__ */
|
|
46
|
-
description ? /* @__PURE__ */
|
|
110
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("section-center", className), children: [
|
|
111
|
+
label ? /* @__PURE__ */ jsx7("div", { className: "section-label", children: label }) : null,
|
|
112
|
+
/* @__PURE__ */ jsx7("h2", { className: "section-title", children: title }),
|
|
113
|
+
description ? /* @__PURE__ */ jsx7("p", { className: "section-desc", children: description }) : null
|
|
47
114
|
] });
|
|
48
115
|
}
|
|
49
116
|
export {
|
|
@@ -51,8 +118,13 @@ export {
|
|
|
51
118
|
Button,
|
|
52
119
|
Card,
|
|
53
120
|
Container,
|
|
121
|
+
EmptyState,
|
|
122
|
+
Field,
|
|
123
|
+
Input,
|
|
124
|
+
Label,
|
|
54
125
|
Section,
|
|
55
126
|
SectionHeader,
|
|
127
|
+
Spinner,
|
|
56
128
|
cn
|
|
57
129
|
};
|
|
58
130
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/badge.tsx","../src/components/button.tsx","../src/components/card.tsx","../src/components/container.tsx","../src/components/section.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Render a leading status dot. */\n dot?: boolean;\n}\n\n/** Pill badge, optionally with a
|
|
1
|
+
{"version":3,"sources":["../src/components/badge.tsx","../src/components/button.tsx","../src/components/card.tsx","../src/components/container.tsx","../src/components/feedback.tsx","../src/components/field.tsx","../src/components/section.tsx"],"sourcesContent":["import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type BadgeVariant = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\nexport interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Render a leading status dot. */\n dot?: boolean;\n /** Semantic color. `neutral` is the default outlined pill. */\n variant?: BadgeVariant;\n}\n\nconst variantClass: Record<BadgeVariant, string> = {\n neutral: '',\n success: 'badge-success',\n warning: 'badge-warning',\n danger: 'badge-danger',\n info: 'badge-info',\n};\n\n/** Pill badge — neutral by default, or a semantic variant, optionally with a dot. */\nexport function Badge({\n dot = false,\n variant = 'neutral',\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span className={cn('badge', variantClass[variant], className)} {...props}>\n {dot ? <span className=\"badge-dot\" /> : null}\n {children}\n </span>\n );\n}\n","import type { ButtonHTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'outline';\nexport type ButtonSize = 'md' | 'sm';\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n}\n\nconst variantClass: Record<ButtonVariant, string> = {\n primary: 'btn-primary',\n secondary: 'btn-secondary',\n outline: 'btn-outline',\n};\n\nexport function Button({\n variant = 'primary',\n size = 'md',\n className,\n type = 'button',\n ...props\n}: ButtonProps) {\n return (\n <button\n type={type}\n className={cn(variantClass[variant], size === 'sm' && 'btn-sm', className)}\n {...props}\n />\n );\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type CardPadding = 'none' | 'sm' | 'md' | 'lg';\n\nexport interface CardProps extends HTMLAttributes<HTMLDivElement> {\n /** Inner padding. Defaults to `md` (28px); use `none` to supply your own. */\n padding?: CardPadding;\n /** Add pointer cursor + hover elevation (for clickable cards). */\n interactive?: boolean;\n}\n\n/** Bordered surface card. Static by default; opt into hover with `interactive`. */\nexport function Card({ padding = 'md', interactive = false, className, ...props }: CardProps) {\n return (\n <div\n className={cn(\n 'card',\n padding !== 'none' && `card-pad-${padding}`,\n interactive && 'card-interactive',\n className,\n )}\n {...props}\n />\n );\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../cn';\n\nexport type ContainerProps = HTMLAttributes<HTMLDivElement>;\n\n/** Centered, max-width content wrapper (var(--max-w)) with horizontal padding. */\nexport function Container({ className, ...props }: ContainerProps) {\n return <div className={cn('container', className)} {...props} />;\n}\n","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {\n /** Wrap in a centered, padded block (for loading states in a panel). */\n center?: boolean;\n}\n\n/** Brand-colored loading spinner. */\nexport function Spinner({ center = false, className, ...props }: SpinnerProps) {\n const spinner = (\n <span className={cn('spinner', className)} role=\"status\" aria-label=\"Loading\" {...props} />\n );\n return center ? <div className=\"spinner-center\">{spinner}</div> : spinner;\n}\n\nexport interface EmptyStateProps {\n title: ReactNode;\n description?: ReactNode;\n /** Optional icon rendered in the circular badge above the title. */\n icon?: ReactNode;\n className?: string;\n}\n\n/** Centered \"nothing here yet\" placeholder for empty lists/tables. */\nexport function EmptyState({ title, description, icon, className }: EmptyStateProps) {\n return (\n <div className={cn('empty-state', className)}>\n {icon ? <div className=\"empty-state-icon\">{icon}</div> : null}\n <h3 className=\"empty-state-title\">{title}</h3>\n {description ? <p className=\"empty-state-desc\">{description}</p> : null}\n </div>\n );\n}\n","import type { InputHTMLAttributes, LabelHTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport type InputProps = InputHTMLAttributes<HTMLInputElement>;\n\n/** Token-aligned text input (the `.field` look: border, surface, brand focus ring). */\nexport function Input({ className, ...props }: InputProps) {\n return <input className={cn('field', className)} {...props} />;\n}\n\nexport type LabelProps = LabelHTMLAttributes<HTMLLabelElement>;\n\nexport function Label({ className, ...props }: LabelProps) {\n return <label className={cn('field-label', className)} {...props} />;\n}\n\nexport interface FieldProps {\n label?: ReactNode;\n /** Helper text shown below the control (hidden when `error` is set). */\n hint?: ReactNode;\n /** Error text shown below the control (takes precedence over `hint`). */\n error?: ReactNode;\n /** `htmlFor` for the label, matching the control's id. */\n htmlFor?: string;\n className?: string;\n children: ReactNode;\n}\n\n/** Labelled field wrapper: optional label above and hint/error below the control. */\nexport function Field({ label, hint, error, htmlFor, className, children }: FieldProps) {\n return (\n <div className={cn('field-group', className)}>\n {label ? <Label htmlFor={htmlFor}>{label}</Label> : null}\n {children}\n {error ? (\n <span className=\"field-error\">{error}</span>\n ) : hint ? (\n <span className=\"field-hint\">{hint}</span>\n ) : null}\n </div>\n );\n}\n","import type { HTMLAttributes, ReactNode } from 'react';\nimport { cn } from '../cn';\n\nexport type SectionProps = HTMLAttributes<HTMLElement>;\n\n/** Vertical page section with max-width and standard padding. */\nexport function Section({ className, ...props }: SectionProps) {\n return <section className={cn('section', className)} {...props} />;\n}\n\nexport interface SectionHeaderProps {\n /** Small eyebrow label above the title (brand colored). */\n label?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n className?: string;\n}\n\n/** Centered section heading: optional label, title, optional description. */\nexport function SectionHeader({ label, title, description, className }: SectionHeaderProps) {\n return (\n <div className={cn('section-center', className)}>\n {label ? <div className=\"section-label\">{label}</div> : null}\n <h2 className=\"section-title\">{title}</h2>\n {description ? <p className=\"section-desc\">{description}</p> : null}\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","variantClass","jsx","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flopay/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@9.15.0",
|
|
6
6
|
"description": "FloPay shared design system — design tokens, a Tailwind v4 preset, and React primitives shared across landing, demo, docs, and dashboard.",
|
package/styles/components.css
CHANGED
|
@@ -116,6 +116,13 @@
|
|
|
116
116
|
border-color: var(--border-hover);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/* Small / dense modifier — compose with a variant (e.g. "btn-primary btn-sm"). */
|
|
120
|
+
.btn-sm {
|
|
121
|
+
gap: 5px;
|
|
122
|
+
padding: 8px 14px;
|
|
123
|
+
font-size: 13px;
|
|
124
|
+
}
|
|
125
|
+
|
|
119
126
|
/* ── Badge ── */
|
|
120
127
|
.badge {
|
|
121
128
|
display: inline-flex;
|
|
@@ -137,16 +144,58 @@
|
|
|
137
144
|
flex-shrink: 0;
|
|
138
145
|
}
|
|
139
146
|
|
|
147
|
+
/* Semantic variants — compose with .badge (e.g. "badge badge-success"). */
|
|
148
|
+
.badge-success {
|
|
149
|
+
border-color: transparent;
|
|
150
|
+
background: color-mix(in srgb, var(--success) 12%, transparent);
|
|
151
|
+
color: var(--success);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.badge-warning {
|
|
155
|
+
border-color: transparent;
|
|
156
|
+
background: var(--warning-bg);
|
|
157
|
+
color: var(--warning-fg);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.badge-danger {
|
|
161
|
+
border-color: transparent;
|
|
162
|
+
background: color-mix(in srgb, var(--danger) 12%, transparent);
|
|
163
|
+
color: var(--danger);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.badge-info {
|
|
167
|
+
border-color: transparent;
|
|
168
|
+
background: color-mix(in srgb, var(--brand) 12%, transparent);
|
|
169
|
+
color: var(--brand);
|
|
170
|
+
}
|
|
171
|
+
|
|
140
172
|
/* ── Card ── */
|
|
173
|
+
/* Surface only — opt into padding (.card-pad-*) and hover (.card-interactive). */
|
|
141
174
|
.card {
|
|
142
|
-
background: var(--bg);
|
|
175
|
+
background: var(--bg-card);
|
|
143
176
|
border: 1px solid var(--border);
|
|
144
177
|
border-radius: var(--radius-lg);
|
|
145
|
-
padding: 28px;
|
|
146
178
|
transition: box-shadow 0.2s, border-color 0.2s;
|
|
147
179
|
}
|
|
148
180
|
|
|
149
|
-
.card
|
|
181
|
+
.card-pad-sm {
|
|
182
|
+
padding: 16px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.card-pad-md {
|
|
186
|
+
padding: 28px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.card-pad-lg {
|
|
190
|
+
padding: 36px;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.card-interactive {
|
|
194
|
+
cursor: pointer;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.card-interactive:hover {
|
|
198
|
+
border-color: var(--border-hover);
|
|
150
199
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
|
|
151
200
|
}
|
|
152
201
|
|
|
@@ -334,3 +383,109 @@
|
|
|
334
383
|
gap: 12px;
|
|
335
384
|
}
|
|
336
385
|
}
|
|
386
|
+
|
|
387
|
+
/* ── Form fields ── */
|
|
388
|
+
.field {
|
|
389
|
+
width: 100%;
|
|
390
|
+
border: 1px solid var(--border);
|
|
391
|
+
background: var(--bg-card);
|
|
392
|
+
border-radius: var(--radius);
|
|
393
|
+
padding: 9px 12px;
|
|
394
|
+
font-family: var(--font);
|
|
395
|
+
font-size: 14px;
|
|
396
|
+
color: var(--text);
|
|
397
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.field::placeholder {
|
|
401
|
+
color: var(--text-tertiary);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.field:focus {
|
|
405
|
+
outline: none;
|
|
406
|
+
border-color: var(--brand);
|
|
407
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 20%, transparent);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.field[aria-invalid='true'] {
|
|
411
|
+
border-color: var(--danger);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.field[aria-invalid='true']:focus {
|
|
415
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 20%, transparent);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.field-group {
|
|
419
|
+
display: flex;
|
|
420
|
+
flex-direction: column;
|
|
421
|
+
gap: 6px;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.field-label {
|
|
425
|
+
font-size: 13px;
|
|
426
|
+
font-weight: 500;
|
|
427
|
+
color: var(--text);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.field-hint {
|
|
431
|
+
font-size: 12px;
|
|
432
|
+
color: var(--text-tertiary);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.field-error {
|
|
436
|
+
font-size: 12px;
|
|
437
|
+
color: var(--danger);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/* ── Spinner ── */
|
|
441
|
+
.spinner {
|
|
442
|
+
display: inline-block;
|
|
443
|
+
width: 24px;
|
|
444
|
+
height: 24px;
|
|
445
|
+
border: 2px solid var(--border);
|
|
446
|
+
border-top-color: var(--brand);
|
|
447
|
+
border-radius: 50%;
|
|
448
|
+
animation: fp-spin 0.6s linear infinite;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
@keyframes fp-spin {
|
|
452
|
+
to {
|
|
453
|
+
transform: rotate(360deg);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.spinner-center {
|
|
458
|
+
display: flex;
|
|
459
|
+
justify-content: center;
|
|
460
|
+
padding: 64px 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* ── Empty state ── */
|
|
464
|
+
.empty-state {
|
|
465
|
+
text-align: center;
|
|
466
|
+
padding: 64px 24px;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
.empty-state-icon {
|
|
470
|
+
display: inline-flex;
|
|
471
|
+
align-items: center;
|
|
472
|
+
justify-content: center;
|
|
473
|
+
width: 48px;
|
|
474
|
+
height: 48px;
|
|
475
|
+
border-radius: 50%;
|
|
476
|
+
background: var(--bg-muted);
|
|
477
|
+
color: var(--text-tertiary);
|
|
478
|
+
margin-bottom: 16px;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.empty-state-title {
|
|
482
|
+
font-size: 14px;
|
|
483
|
+
font-weight: 500;
|
|
484
|
+
color: var(--text);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.empty-state-desc {
|
|
488
|
+
font-size: 14px;
|
|
489
|
+
color: var(--text-secondary);
|
|
490
|
+
margin-top: 4px;
|
|
491
|
+
}
|
package/styles/preset.css
CHANGED
package/styles/tokens.css
CHANGED
|
@@ -45,6 +45,11 @@
|
|
|
45
45
|
--danger: #dc2626;
|
|
46
46
|
--warning: #f5a623;
|
|
47
47
|
|
|
48
|
+
/* Readable warning pair for soft surfaces (badges/callouts) — the solid
|
|
49
|
+
--warning is too light to use as text. */
|
|
50
|
+
--warning-bg: #fffbeb;
|
|
51
|
+
--warning-fg: #b45309;
|
|
52
|
+
|
|
48
53
|
/* Radius */
|
|
49
54
|
--radius: 8px;
|
|
50
55
|
--radius-lg: 12px;
|
|
@@ -78,4 +83,7 @@
|
|
|
78
83
|
|
|
79
84
|
--accent: #fafafa;
|
|
80
85
|
--accent-hover: #e4e4e7;
|
|
86
|
+
|
|
87
|
+
--warning-bg: #451a03;
|
|
88
|
+
--warning-fg: #fcd34d;
|
|
81
89
|
}
|