@teja-app/ui 0.0.1
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/README.md +169 -0
- package/dist/components/Button/Button.d.ts +13 -0
- package/dist/components/Button/Button.d.ts.map +1 -0
- package/dist/components/Button/Button.types.d.ts +18 -0
- package/dist/components/Button/Button.types.d.ts.map +1 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.d.ts.map +1 -0
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/hooks/index.cjs +2 -0
- package/dist/hooks/index.cjs.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.cjs +96 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +96 -0
- package/dist/index.js.map +1 -0
- package/dist/tailwind/colors.d.ts +46 -0
- package/dist/tailwind/colors.d.ts.map +1 -0
- package/dist/tailwind/index.cjs +138 -0
- package/dist/tailwind/index.cjs.map +1 -0
- package/dist/tailwind/index.d.ts +17 -0
- package/dist/tailwind/index.d.ts.map +1 -0
- package/dist/tailwind/index.js +138 -0
- package/dist/tailwind/index.js.map +1 -0
- package/dist/tailwind/preset.d.ts +20 -0
- package/dist/tailwind/preset.d.ts.map +1 -0
- package/dist/tailwind/spacing.d.ts +53 -0
- package/dist/tailwind/spacing.d.ts.map +1 -0
- package/dist/tailwind/typography.d.ts +41 -0
- package/dist/tailwind/typography.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +12 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/index.cjs +3027 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3027 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +121 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# @teja-app/ui
|
|
2
|
+
|
|
3
|
+
Shared UI component library for Teja applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @teja-app/ui
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
### 1. Configure Tailwind
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
// tailwind.config.js
|
|
17
|
+
import tejaPreset from '@teja-app/ui/tailwind';
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
presets: [tejaPreset],
|
|
21
|
+
content: [
|
|
22
|
+
"./src/**/*.{js,ts,jsx,tsx}",
|
|
23
|
+
"./node_modules/@teja-app/ui/dist/**/*.{js,mjs}",
|
|
24
|
+
],
|
|
25
|
+
theme: {
|
|
26
|
+
extend: {
|
|
27
|
+
// App-specific overrides
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Use Components
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Button, Input, Modal } from '@teja-app/ui';
|
|
37
|
+
import { cn } from '@teja-app/ui/utils';
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
return (
|
|
41
|
+
<Button variant="primary" size="md">
|
|
42
|
+
Click me
|
|
43
|
+
</Button>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Component Design Philosophy
|
|
49
|
+
|
|
50
|
+
All components follow these principles:
|
|
51
|
+
|
|
52
|
+
### 1. Modularity
|
|
53
|
+
|
|
54
|
+
Each component is self-contained with its own styles, types, and logic. No hidden dependencies between components. Import individually or as a bundle.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
// Individual import
|
|
58
|
+
import { Button } from '@teja-app/ui';
|
|
59
|
+
|
|
60
|
+
// Bundle import
|
|
61
|
+
import { Button, Input, Modal } from '@teja-app/ui';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Extensibility
|
|
65
|
+
|
|
66
|
+
All components accept standard HTML attributes via spread props, support `className` for style overrides, and use `forwardRef` for DOM access.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<Button
|
|
70
|
+
className="my-custom-class"
|
|
71
|
+
data-testid="submit-btn"
|
|
72
|
+
aria-label="Submit form"
|
|
73
|
+
{...otherProps}
|
|
74
|
+
>
|
|
75
|
+
Submit
|
|
76
|
+
</Button>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3. Loose Coupling
|
|
80
|
+
|
|
81
|
+
Components use composition over inheritance. No hard-coded values - everything is configurable via props or Tailwind classes.
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
// Compose with children
|
|
85
|
+
<Button>
|
|
86
|
+
<Icon name="save" />
|
|
87
|
+
Save
|
|
88
|
+
</Button>
|
|
89
|
+
|
|
90
|
+
// Override with className
|
|
91
|
+
<Button className="bg-purple-500 hover:bg-purple-600">
|
|
92
|
+
Custom Color
|
|
93
|
+
</Button>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. Composition Patterns
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
// Slot pattern for complex components
|
|
100
|
+
<Modal>
|
|
101
|
+
<Modal.Header>Title</Modal.Header>
|
|
102
|
+
<Modal.Body>Content</Modal.Body>
|
|
103
|
+
<Modal.Footer>
|
|
104
|
+
<Button variant="ghost">Cancel</Button>
|
|
105
|
+
<Button variant="primary">Save</Button>
|
|
106
|
+
</Modal.Footer>
|
|
107
|
+
</Modal>
|
|
108
|
+
|
|
109
|
+
// Polymorphic components
|
|
110
|
+
<Button as="a" href="/link">
|
|
111
|
+
Link Button
|
|
112
|
+
</Button>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Customization
|
|
116
|
+
|
|
117
|
+
### Tailwind Preset Override
|
|
118
|
+
|
|
119
|
+
Each app can extend the preset and override specific tokens:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
// tailwind.config.js
|
|
123
|
+
import tejaPreset from '@teja-app/ui/tailwind';
|
|
124
|
+
|
|
125
|
+
export default {
|
|
126
|
+
presets: [tejaPreset],
|
|
127
|
+
theme: {
|
|
128
|
+
extend: {
|
|
129
|
+
colors: {
|
|
130
|
+
brand: {
|
|
131
|
+
primary: '#0ea5e9', // Override for portal
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Design Tokens
|
|
140
|
+
|
|
141
|
+
Access individual tokens for custom configurations:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { colors, fontFamily, spacing } from '@teja-app/ui/tailwind';
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## API Reference
|
|
148
|
+
|
|
149
|
+
### Button
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Default | Description |
|
|
152
|
+
|------|------|---------|-------------|
|
|
153
|
+
| `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger'` | `'primary'` | Visual style |
|
|
154
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
155
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
156
|
+
| `disabled` | `boolean` | `false` | Disable button |
|
|
157
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
158
|
+
|
|
159
|
+
### Input
|
|
160
|
+
|
|
161
|
+
| Prop | Type | Default | Description |
|
|
162
|
+
|------|------|---------|-------------|
|
|
163
|
+
| `error` | `string` | - | Error message |
|
|
164
|
+
| `label` | `string` | - | Input label |
|
|
165
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
166
|
+
|
|
167
|
+
## Contributing
|
|
168
|
+
|
|
169
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on adding new components.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ButtonProps } from './Button.types';
|
|
2
|
+
/**
|
|
3
|
+
* Button component with multiple variants, sizes, and loading state.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```tsx
|
|
7
|
+
* <Button variant="primary" size="md">Click me</Button>
|
|
8
|
+
* <Button variant="danger" loading>Deleting...</Button>
|
|
9
|
+
* <Button icon={<SaveIcon />} iconPosition="left">Save</Button>
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export declare const Button: import("react").ForwardRefExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
13
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAC;AAmB7E;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,2GAwElB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
3
|
+
export type ButtonSize = 'sm' | 'md' | 'lg';
|
|
4
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
/** The visual style variant */
|
|
6
|
+
variant?: ButtonVariant;
|
|
7
|
+
/** The size of the button */
|
|
8
|
+
size?: ButtonSize;
|
|
9
|
+
/** Shows a loading spinner when true */
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
/** Icon element to display */
|
|
12
|
+
icon?: ReactNode;
|
|
13
|
+
/** Position of the icon */
|
|
14
|
+
iconPosition?: 'left' | 'right';
|
|
15
|
+
/** Makes the button full width */
|
|
16
|
+
fullWidth?: boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=Button.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE7D,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AACzE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,WAAW,WAAY,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IAC1E,+BAA+B;IAC/B,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,wCAAwC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,kCAAkC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const utils_index = require("./utils/index.cjs");
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const react = require("react");
|
|
6
|
+
const variantStyles = {
|
|
7
|
+
primary: "bg-brand-primary text-white border border-brand-primary hover:bg-brand-primary-hover focus:ring-brand-primary/20",
|
|
8
|
+
secondary: "bg-white text-neutral-900 border border-neutral-300 hover:bg-neutral-50 hover:border-neutral-400 focus:ring-neutral-500/20",
|
|
9
|
+
ghost: "text-neutral-700 hover:text-neutral-900 hover:bg-neutral-100 focus:ring-neutral-500/20",
|
|
10
|
+
danger: "bg-error text-white border border-error hover:bg-error/90 focus:ring-error/20"
|
|
11
|
+
};
|
|
12
|
+
const sizeStyles = {
|
|
13
|
+
sm: "px-3 py-1.5 text-sm h-8",
|
|
14
|
+
md: "px-4 py-2 text-base h-10",
|
|
15
|
+
lg: "px-6 py-3 text-lg h-12"
|
|
16
|
+
};
|
|
17
|
+
const Button = react.forwardRef(
|
|
18
|
+
({
|
|
19
|
+
variant = "primary",
|
|
20
|
+
size = "md",
|
|
21
|
+
loading = false,
|
|
22
|
+
disabled = false,
|
|
23
|
+
icon,
|
|
24
|
+
iconPosition = "left",
|
|
25
|
+
fullWidth = false,
|
|
26
|
+
children,
|
|
27
|
+
className,
|
|
28
|
+
...props
|
|
29
|
+
}, ref) => {
|
|
30
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
31
|
+
"button",
|
|
32
|
+
{
|
|
33
|
+
ref,
|
|
34
|
+
className: utils_index.cn(
|
|
35
|
+
// Base styles
|
|
36
|
+
"inline-flex items-center justify-center gap-2 font-medium rounded-md",
|
|
37
|
+
"transition-colors duration-normal",
|
|
38
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
39
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
40
|
+
// Variant styles
|
|
41
|
+
variantStyles[variant],
|
|
42
|
+
// Size styles
|
|
43
|
+
sizeStyles[size],
|
|
44
|
+
// Width styles
|
|
45
|
+
fullWidth && "w-full",
|
|
46
|
+
// Custom className (allows override)
|
|
47
|
+
className
|
|
48
|
+
),
|
|
49
|
+
disabled: disabled || loading,
|
|
50
|
+
...props,
|
|
51
|
+
children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
53
|
+
"svg",
|
|
54
|
+
{
|
|
55
|
+
className: "animate-spin h-5 w-5",
|
|
56
|
+
fill: "none",
|
|
57
|
+
viewBox: "0 0 24 24",
|
|
58
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
59
|
+
"aria-hidden": "true",
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
62
|
+
"circle",
|
|
63
|
+
{
|
|
64
|
+
className: "opacity-25",
|
|
65
|
+
cx: "12",
|
|
66
|
+
cy: "12",
|
|
67
|
+
r: "10",
|
|
68
|
+
stroke: "currentColor",
|
|
69
|
+
strokeWidth: "4"
|
|
70
|
+
}
|
|
71
|
+
),
|
|
72
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
73
|
+
"path",
|
|
74
|
+
{
|
|
75
|
+
className: "opacity-75",
|
|
76
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z",
|
|
77
|
+
fill: "currentColor"
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading..." })
|
|
84
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
85
|
+
icon && iconPosition === "left" && icon,
|
|
86
|
+
children,
|
|
87
|
+
icon && iconPosition === "right" && icon
|
|
88
|
+
] })
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
Button.displayName = "Button";
|
|
94
|
+
exports.cn = utils_index.cn;
|
|
95
|
+
exports.Button = Button;
|
|
96
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/components/Button/Button.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { cn } from '@/utils';\nimport type { ButtonProps, ButtonVariant, ButtonSize } from './Button.types';\n\nconst variantStyles: Record<ButtonVariant, string> = {\n primary:\n 'bg-brand-primary text-white border border-brand-primary hover:bg-brand-primary-hover focus:ring-brand-primary/20',\n secondary:\n 'bg-white text-neutral-900 border border-neutral-300 hover:bg-neutral-50 hover:border-neutral-400 focus:ring-neutral-500/20',\n ghost:\n 'text-neutral-700 hover:text-neutral-900 hover:bg-neutral-100 focus:ring-neutral-500/20',\n danger:\n 'bg-error text-white border border-error hover:bg-error/90 focus:ring-error/20',\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n sm: 'px-3 py-1.5 text-sm h-8',\n md: 'px-4 py-2 text-base h-10',\n lg: 'px-6 py-3 text-lg h-12',\n};\n\n/**\n * Button component with multiple variants, sizes, and loading state.\n *\n * @example\n * ```tsx\n * <Button variant=\"primary\" size=\"md\">Click me</Button>\n * <Button variant=\"danger\" loading>Deleting...</Button>\n * <Button icon={<SaveIcon />} iconPosition=\"left\">Save</Button>\n * ```\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n disabled = false,\n icon,\n iconPosition = 'left',\n fullWidth = false,\n children,\n className,\n ...props\n },\n ref\n ) => {\n return (\n <button\n ref={ref}\n className={cn(\n // Base styles\n 'inline-flex items-center justify-center gap-2 font-medium rounded-md',\n 'transition-colors duration-normal',\n 'focus:outline-none focus:ring-2 focus:ring-offset-2',\n 'disabled:opacity-50 disabled:cursor-not-allowed',\n // Variant styles\n variantStyles[variant],\n // Size styles\n sizeStyles[size],\n // Width styles\n fullWidth && 'w-full',\n // Custom className (allows override)\n className\n )}\n disabled={disabled || loading}\n {...props}\n >\n {loading ? (\n <>\n <svg\n className=\"animate-spin h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n fill=\"currentColor\"\n />\n </svg>\n <span>Loading...</span>\n </>\n ) : (\n <>\n {icon && iconPosition === 'left' && icon}\n {children}\n {icon && iconPosition === 'right' && icon}\n </>\n )}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n"],"names":["forwardRef","jsx","cn","jsxs","Fragment"],"mappings":";;;;;AAIA,MAAM,gBAA+C;AAAA,EACnD,SACE;AAAA,EACF,WACE;AAAA,EACF,OACE;AAAA,EACF,QACE;AACJ;AAEA,MAAM,aAAyC;AAAA,EAC7C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAYO,MAAM,SAASA,MAAAA;AAAAA,EACpB,CACE;AAAA,IACE,UAAU;AAAA,IACV,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA,eAAe;AAAA,IACf,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,WACEC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAWC,YAAAA;AAAAA;AAAAA,UAET;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,UAEA,cAAc,OAAO;AAAA;AAAA,UAErB,WAAW,IAAI;AAAA;AAAA,UAEf,aAAa;AAAA;AAAA,UAEb;AAAA,QAAA;AAAA,QAEF,UAAU,YAAY;AAAA,QACrB,GAAG;AAAA,QAEH,oBACCC,2BAAAA,KAAAC,WAAAA,UAAA,EACE,UAAA;AAAA,UAAAD,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,eAAY;AAAA,cAEZ,UAAA;AAAA,gBAAAF,2BAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAG;AAAA,oBACH,IAAG;AAAA,oBACH,GAAE;AAAA,oBACF,QAAO;AAAA,oBACP,aAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEdA,2BAAAA;AAAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,GAAE;AAAA,oBACF,MAAK;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACP;AAAA,YAAA;AAAA,UAAA;AAAA,UAEFA,2BAAAA,IAAC,UAAK,UAAA,aAAA,CAAU;AAAA,QAAA,EAAA,CAClB,IAEAE,2BAAAA,KAAAC,WAAAA,UAAA,EACG,UAAA;AAAA,UAAA,QAAQ,iBAAiB,UAAU;AAAA,UACnC;AAAA,UACA,QAAQ,iBAAiB,WAAW;AAAA,QAAA,EAAA,CACvC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,OAAO,cAAc;;;"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @teja-app/ui - Shared UI component library for Teja applications
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { Button, Input, Modal } from '@teja-app/ui';
|
|
7
|
+
* import tejaPreset from '@teja-app/ui/tailwind';
|
|
8
|
+
* import { cn } from '@teja-app/ui/utils';
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export * from './components';
|
|
12
|
+
export { cn } from './utils';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { cn } from "./utils/index.js";
|
|
2
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
const variantStyles = {
|
|
5
|
+
primary: "bg-brand-primary text-white border border-brand-primary hover:bg-brand-primary-hover focus:ring-brand-primary/20",
|
|
6
|
+
secondary: "bg-white text-neutral-900 border border-neutral-300 hover:bg-neutral-50 hover:border-neutral-400 focus:ring-neutral-500/20",
|
|
7
|
+
ghost: "text-neutral-700 hover:text-neutral-900 hover:bg-neutral-100 focus:ring-neutral-500/20",
|
|
8
|
+
danger: "bg-error text-white border border-error hover:bg-error/90 focus:ring-error/20"
|
|
9
|
+
};
|
|
10
|
+
const sizeStyles = {
|
|
11
|
+
sm: "px-3 py-1.5 text-sm h-8",
|
|
12
|
+
md: "px-4 py-2 text-base h-10",
|
|
13
|
+
lg: "px-6 py-3 text-lg h-12"
|
|
14
|
+
};
|
|
15
|
+
const Button = forwardRef(
|
|
16
|
+
({
|
|
17
|
+
variant = "primary",
|
|
18
|
+
size = "md",
|
|
19
|
+
loading = false,
|
|
20
|
+
disabled = false,
|
|
21
|
+
icon,
|
|
22
|
+
iconPosition = "left",
|
|
23
|
+
fullWidth = false,
|
|
24
|
+
children,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
}, ref) => {
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
"button",
|
|
30
|
+
{
|
|
31
|
+
ref,
|
|
32
|
+
className: cn(
|
|
33
|
+
// Base styles
|
|
34
|
+
"inline-flex items-center justify-center gap-2 font-medium rounded-md",
|
|
35
|
+
"transition-colors duration-normal",
|
|
36
|
+
"focus:outline-none focus:ring-2 focus:ring-offset-2",
|
|
37
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
38
|
+
// Variant styles
|
|
39
|
+
variantStyles[variant],
|
|
40
|
+
// Size styles
|
|
41
|
+
sizeStyles[size],
|
|
42
|
+
// Width styles
|
|
43
|
+
fullWidth && "w-full",
|
|
44
|
+
// Custom className (allows override)
|
|
45
|
+
className
|
|
46
|
+
),
|
|
47
|
+
disabled: disabled || loading,
|
|
48
|
+
...props,
|
|
49
|
+
children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
50
|
+
/* @__PURE__ */ jsxs(
|
|
51
|
+
"svg",
|
|
52
|
+
{
|
|
53
|
+
className: "animate-spin h-5 w-5",
|
|
54
|
+
fill: "none",
|
|
55
|
+
viewBox: "0 0 24 24",
|
|
56
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
57
|
+
"aria-hidden": "true",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ jsx(
|
|
60
|
+
"circle",
|
|
61
|
+
{
|
|
62
|
+
className: "opacity-25",
|
|
63
|
+
cx: "12",
|
|
64
|
+
cy: "12",
|
|
65
|
+
r: "10",
|
|
66
|
+
stroke: "currentColor",
|
|
67
|
+
strokeWidth: "4"
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
"path",
|
|
72
|
+
{
|
|
73
|
+
className: "opacity-75",
|
|
74
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z",
|
|
75
|
+
fill: "currentColor"
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
/* @__PURE__ */ jsx("span", { children: "Loading..." })
|
|
82
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
83
|
+
icon && iconPosition === "left" && icon,
|
|
84
|
+
children,
|
|
85
|
+
icon && iconPosition === "right" && icon
|
|
86
|
+
] })
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
Button.displayName = "Button";
|
|
92
|
+
export {
|
|
93
|
+
Button,
|
|
94
|
+
cn
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/components/Button/Button.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport { cn } from '@/utils';\nimport type { ButtonProps, ButtonVariant, ButtonSize } from './Button.types';\n\nconst variantStyles: Record<ButtonVariant, string> = {\n primary:\n 'bg-brand-primary text-white border border-brand-primary hover:bg-brand-primary-hover focus:ring-brand-primary/20',\n secondary:\n 'bg-white text-neutral-900 border border-neutral-300 hover:bg-neutral-50 hover:border-neutral-400 focus:ring-neutral-500/20',\n ghost:\n 'text-neutral-700 hover:text-neutral-900 hover:bg-neutral-100 focus:ring-neutral-500/20',\n danger:\n 'bg-error text-white border border-error hover:bg-error/90 focus:ring-error/20',\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n sm: 'px-3 py-1.5 text-sm h-8',\n md: 'px-4 py-2 text-base h-10',\n lg: 'px-6 py-3 text-lg h-12',\n};\n\n/**\n * Button component with multiple variants, sizes, and loading state.\n *\n * @example\n * ```tsx\n * <Button variant=\"primary\" size=\"md\">Click me</Button>\n * <Button variant=\"danger\" loading>Deleting...</Button>\n * <Button icon={<SaveIcon />} iconPosition=\"left\">Save</Button>\n * ```\n */\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n disabled = false,\n icon,\n iconPosition = 'left',\n fullWidth = false,\n children,\n className,\n ...props\n },\n ref\n ) => {\n return (\n <button\n ref={ref}\n className={cn(\n // Base styles\n 'inline-flex items-center justify-center gap-2 font-medium rounded-md',\n 'transition-colors duration-normal',\n 'focus:outline-none focus:ring-2 focus:ring-offset-2',\n 'disabled:opacity-50 disabled:cursor-not-allowed',\n // Variant styles\n variantStyles[variant],\n // Size styles\n sizeStyles[size],\n // Width styles\n fullWidth && 'w-full',\n // Custom className (allows override)\n className\n )}\n disabled={disabled || loading}\n {...props}\n >\n {loading ? (\n <>\n <svg\n className=\"animate-spin h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n fill=\"currentColor\"\n />\n </svg>\n <span>Loading...</span>\n </>\n ) : (\n <>\n {icon && iconPosition === 'left' && icon}\n {children}\n {icon && iconPosition === 'right' && icon}\n </>\n )}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n"],"names":[],"mappings":";;;AAIA,MAAM,gBAA+C;AAAA,EACnD,SACE;AAAA,EACF,WACE;AAAA,EACF,OACE;AAAA,EACF,QACE;AACJ;AAEA,MAAM,aAAyC;AAAA,EAC7C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAYO,MAAM,SAAS;AAAA,EACpB,CACE;AAAA,IACE,UAAU;AAAA,IACV,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW;AAAA,IACX;AAAA,IACA,eAAe;AAAA,IACf,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA;AAAA,UAET;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,UAEA,cAAc,OAAO;AAAA;AAAA,UAErB,WAAW,IAAI;AAAA;AAAA,UAEf,aAAa;AAAA;AAAA,UAEb;AAAA,QAAA;AAAA,QAEF,UAAU,YAAY;AAAA,QACrB,GAAG;AAAA,QAEH,oBACC,qBAAA,UAAA,EACE,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,eAAY;AAAA,cAEZ,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAG;AAAA,oBACH,IAAG;AAAA,oBACH,GAAE;AAAA,oBACF,QAAO;AAAA,oBACP,aAAY;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEd;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,GAAE;AAAA,oBACF,MAAK;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACP;AAAA,YAAA;AAAA,UAAA;AAAA,UAEF,oBAAC,UAAK,UAAA,aAAA,CAAU;AAAA,QAAA,EAAA,CAClB,IAEA,qBAAA,UAAA,EACG,UAAA;AAAA,UAAA,QAAQ,iBAAiB,UAAU;AAAA,UACnC;AAAA,UACA,QAAQ,iBAAiB,WAAW;AAAA,QAAA,EAAA,CACvC;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEA,OAAO,cAAc;"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design token colors for the Teja UI component library.
|
|
3
|
+
* Based on /business/ux/Patterns/Design-Tokens.md
|
|
4
|
+
*/
|
|
5
|
+
export declare const colors: {
|
|
6
|
+
readonly brand: {
|
|
7
|
+
readonly primary: "#2563EB";
|
|
8
|
+
readonly 'primary-hover': "#1D4ED8";
|
|
9
|
+
readonly secondary: "#64748B";
|
|
10
|
+
};
|
|
11
|
+
readonly success: {
|
|
12
|
+
readonly DEFAULT: "#16A34A";
|
|
13
|
+
readonly light: "#DCFCE7";
|
|
14
|
+
};
|
|
15
|
+
readonly warning: {
|
|
16
|
+
readonly DEFAULT: "#CA8A04";
|
|
17
|
+
readonly light: "#FEF9C3";
|
|
18
|
+
};
|
|
19
|
+
readonly error: {
|
|
20
|
+
readonly DEFAULT: "#DC2626";
|
|
21
|
+
readonly light: "#FEE2E2";
|
|
22
|
+
};
|
|
23
|
+
readonly info: {
|
|
24
|
+
readonly DEFAULT: "#2563EB";
|
|
25
|
+
readonly light: "#DBEAFE";
|
|
26
|
+
};
|
|
27
|
+
readonly neutral: {
|
|
28
|
+
readonly 50: "#F8FAFC";
|
|
29
|
+
readonly 100: "#F1F5F9";
|
|
30
|
+
readonly 200: "#E2E8F0";
|
|
31
|
+
readonly 300: "#CBD5E1";
|
|
32
|
+
readonly 500: "#64748B";
|
|
33
|
+
readonly 700: "#334155";
|
|
34
|
+
readonly 900: "#0F172A";
|
|
35
|
+
};
|
|
36
|
+
readonly status: {
|
|
37
|
+
readonly scheduled: "#3B82F6";
|
|
38
|
+
readonly completed: "#16A34A";
|
|
39
|
+
readonly cancelled: "#6B7280";
|
|
40
|
+
readonly 'no-show': "#EF4444";
|
|
41
|
+
readonly draft: "#F59E0B";
|
|
42
|
+
readonly signed: "#16A34A";
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export type Colors = typeof colors;
|
|
46
|
+
//# sourceMappingURL=colors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../src/tailwind/colors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CT,CAAC;AAEX,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC"}
|