@korsolutions/ui 0.0.89 → 0.0.91
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 +21 -0
- package/dist/module/components/avatar/components/avatar-image.js.map +1 -1
- package/dist/module/components/badge/badge.js +1 -6
- package/dist/module/components/badge/badge.js.map +1 -1
- package/dist/module/components/badge/variants/default.js +3 -2
- package/dist/module/components/badge/variants/default.js.map +1 -1
- package/dist/module/components/badge/variants/secondary.js +2 -1
- package/dist/module/components/badge/variants/secondary.js.map +1 -1
- package/dist/module/components/card/card-title.js +2 -3
- package/dist/module/components/card/card-title.js.map +1 -1
- package/dist/module/components/combobox/components/combobox-list.js +24 -0
- package/dist/module/components/combobox/components/combobox-list.js.map +1 -0
- package/dist/module/components/combobox/components/combobox-option.js +19 -23
- package/dist/module/components/combobox/components/combobox-option.js.map +1 -1
- package/dist/module/components/combobox/components/combobox-overlay.js +0 -1
- package/dist/module/components/combobox/components/combobox-overlay.js.map +1 -1
- package/dist/module/components/combobox/components/combobox-root.js +62 -11
- package/dist/module/components/combobox/components/combobox-root.js.map +1 -1
- package/dist/module/components/combobox/components/combobox-trigger.js +3 -2
- package/dist/module/components/combobox/components/combobox-trigger.js.map +1 -1
- package/dist/module/components/combobox/context.js.map +1 -1
- package/dist/module/components/combobox/index.js +2 -0
- package/dist/module/components/combobox/index.js.map +1 -1
- package/dist/module/components/menu/components/menu-selection-indicator.js +4 -3
- package/dist/module/components/menu/components/menu-selection-indicator.js.map +1 -1
- package/dist/module/components/portal/portal.js.map +1 -1
- package/dist/module/components/select/components/select-option.js +11 -12
- package/dist/module/components/select/components/select-option.js.map +1 -1
- package/dist/module/components/select/components/select-trigger.js +3 -1
- package/dist/module/components/select/components/select-trigger.js.map +1 -1
- package/dist/module/hooks/use-relative-position.js.map +1 -1
- package/dist/module/utils/normalize-layout.js.map +1 -1
- package/dist/typescript/src/components/avatar/components/avatar-image.d.ts +2 -2
- package/dist/typescript/src/components/avatar/components/avatar-image.d.ts.map +1 -1
- package/dist/typescript/src/components/badge/badge.d.ts.map +1 -1
- package/dist/typescript/src/components/badge/variants/default.d.ts.map +1 -1
- package/dist/typescript/src/components/badge/variants/secondary.d.ts.map +1 -1
- package/dist/typescript/src/components/card/card-title.d.ts +2 -2
- package/dist/typescript/src/components/card/card-title.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/components/combobox-list.d.ts +12 -0
- package/dist/typescript/src/components/combobox/components/combobox-list.d.ts.map +1 -0
- package/dist/typescript/src/components/combobox/components/combobox-option.d.ts +3 -4
- package/dist/typescript/src/components/combobox/components/combobox-option.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/components/combobox-overlay.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/components/combobox-root.d.ts +26 -6
- package/dist/typescript/src/components/combobox/components/combobox-root.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/components/combobox-trigger.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/context.d.ts +6 -2
- package/dist/typescript/src/components/combobox/context.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/index.d.ts +3 -0
- package/dist/typescript/src/components/combobox/index.d.ts.map +1 -1
- package/dist/typescript/src/components/combobox/types.d.ts +2 -3
- package/dist/typescript/src/components/combobox/types.d.ts.map +1 -1
- package/dist/typescript/src/components/input/input.d.ts +1 -1
- package/dist/typescript/src/components/input/input.d.ts.map +1 -1
- package/dist/typescript/src/components/menu/components/menu-selection-indicator.d.ts.map +1 -1
- package/dist/typescript/src/components/select/components/select-option.d.ts.map +1 -1
- package/dist/typescript/src/components/select/components/select-trigger.d.ts.map +1 -1
- package/dist/typescript/src/hooks/use-relative-position.d.ts +2 -2
- package/dist/typescript/src/hooks/use-relative-position.d.ts.map +1 -1
- package/dist/typescript/src/types/element.types.d.ts +3 -10
- package/dist/typescript/src/types/element.types.d.ts.map +1 -1
- package/dist/typescript/src/utils/normalize-layout.d.ts +3 -2
- package/dist/typescript/src/utils/normalize-layout.d.ts.map +1 -1
- package/package.json +8 -1
- package/src/components/avatar/components/avatar-image.tsx +2 -2
- package/src/components/badge/badge.tsx +1 -3
- package/src/components/badge/variants/default.tsx +2 -1
- package/src/components/badge/variants/secondary.tsx +1 -0
- package/src/components/card/card-title.tsx +7 -4
- package/src/components/combobox/components/combobox-list.tsx +32 -0
- package/src/components/combobox/components/combobox-option.tsx +27 -33
- package/src/components/combobox/components/combobox-overlay.tsx +0 -1
- package/src/components/combobox/components/combobox-root.tsx +110 -23
- package/src/components/combobox/components/combobox-trigger.tsx +3 -2
- package/src/components/combobox/context.ts +7 -2
- package/src/components/combobox/index.ts +3 -0
- package/src/components/combobox/types.ts +2 -3
- package/src/components/menu/components/menu-selection-indicator.tsx +5 -4
- package/src/components/portal/portal.tsx +2 -2
- package/src/components/select/components/select-option.tsx +14 -14
- package/src/components/select/components/select-trigger.tsx +11 -6
- package/src/hooks/use-relative-position.ts +4 -4
- package/src/types/element.types.ts +3 -10
- package/src/utils/normalize-layout.ts +3 -2
- package/AGENTS.md +0 -678
- package/babel.config.js +0 -8
- package/bob.config.js +0 -14
- package/tsconfig.json +0 -29
package/AGENTS.md
DELETED
|
@@ -1,678 +0,0 @@
|
|
|
1
|
-
# AGENTS.md - KorUI Library
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This is the main UI component library package (`@korsolutions/ui`), a minimal-dependency, cross-platform UI library for React Native and Expo. Flexible components with beautiful default styling.
|
|
6
|
-
|
|
7
|
-
## Core Principles
|
|
8
|
-
|
|
9
|
-
1. **Minimal Dependencies** - Keep external dependencies to a minimum
|
|
10
|
-
2. **Beautiful Defaults** - Components ship with production-ready styling
|
|
11
|
-
3. **Variant System** - Use themed style hooks for component variants
|
|
12
|
-
4. **Compound Components** - Export components as objects with sub-components
|
|
13
|
-
5. **Type Safety** - Full TypeScript coverage with strict mode enabled
|
|
14
|
-
|
|
15
|
-
## Architecture
|
|
16
|
-
|
|
17
|
-
The library uses a **3-layer architecture**:
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
Layer 1: Primitives (behavior, no styles)
|
|
21
|
-
Layer 2: Components (styled wrappers)
|
|
22
|
-
Layer 3: Variants (themed style hooks)
|
|
23
|
-
↓
|
|
24
|
-
Themes (color tokens, spacing, typography)
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Layer 1: Primitives (`src/primitives/`)
|
|
28
|
-
|
|
29
|
-
Headless UI components providing behavior without visual styles.
|
|
30
|
-
|
|
31
|
-
**Pattern**:
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
// primitives/button/button-root.tsx
|
|
35
|
-
export interface ButtonRootProps {
|
|
36
|
-
children?: React.ReactNode;
|
|
37
|
-
onPress?: () => void;
|
|
38
|
-
isDisabled?: boolean;
|
|
39
|
-
isLoading?: boolean;
|
|
40
|
-
style?: StyleProp<ViewStyle>;
|
|
41
|
-
styles?: ButtonStyles; // Injected by variants
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function ButtonRoot(props: ButtonRootProps) {
|
|
45
|
-
const composedStyle = [props.styles?.root, props.style];
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<ButtonContext.Provider value={{ styles: props.styles }}>
|
|
49
|
-
<Pressable
|
|
50
|
-
style={composedStyle}
|
|
51
|
-
disabled={props.isDisabled}
|
|
52
|
-
onPress={props.onPress}
|
|
53
|
-
>
|
|
54
|
-
{props.children}
|
|
55
|
-
</Pressable>
|
|
56
|
-
</ButtonContext.Provider>
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// primitives/button/index.ts
|
|
61
|
-
export const ButtonPrimitive = {
|
|
62
|
-
Root: ButtonRoot,
|
|
63
|
-
Label: ButtonLabel,
|
|
64
|
-
Spinner: ButtonSpinner,
|
|
65
|
-
};
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
**Key Rules**:
|
|
69
|
-
|
|
70
|
-
- ❌ No inline styles or hardcoded colors
|
|
71
|
-
- ❌ No theme access (`useTheme`)
|
|
72
|
-
- ✅ Accept `styles` prop for variant injection
|
|
73
|
-
- ✅ Provide context for sub-components
|
|
74
|
-
- ✅ Handle behavior (state, events, accessibility)
|
|
75
|
-
|
|
76
|
-
### Layer 2: Components (`src/components/`)
|
|
77
|
-
|
|
78
|
-
Styled components using primitives with variant system.
|
|
79
|
-
|
|
80
|
-
**Pattern**:
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
// components/button/components/button-root.tsx
|
|
84
|
-
export interface ButtonRootProps extends ButtonPrimitiveRootProps {
|
|
85
|
-
variant?: keyof typeof ButtonVariants;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function ButtonRoot(props: ButtonRootProps) {
|
|
89
|
-
const variant = props.variant ?? "default";
|
|
90
|
-
const variantStyles = ButtonVariants[variant]();
|
|
91
|
-
|
|
92
|
-
return <ButtonPrimitive.Root {...props} styles={variantStyles} />;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// components/button/index.ts
|
|
96
|
-
export const Button = {
|
|
97
|
-
Root: ButtonRoot,
|
|
98
|
-
Label: ButtonPrimitive.Label,
|
|
99
|
-
Spinner: ButtonPrimitive.Spinner,
|
|
100
|
-
};
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**Key Rules**:
|
|
104
|
-
|
|
105
|
-
- ✅ Use primitives as base
|
|
106
|
-
- ✅ Apply variants for styling
|
|
107
|
-
- ✅ Default variant is "default"
|
|
108
|
-
- ✅ Re-export primitive sub-components
|
|
109
|
-
- ❌ No direct styling in components
|
|
110
|
-
|
|
111
|
-
### Layer 3: Variants (`src/components/[name]/variants/`)
|
|
112
|
-
|
|
113
|
-
Theme-aware style hooks providing reactive styles.
|
|
114
|
-
|
|
115
|
-
**Pattern**:
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
// components/button/variants/default.tsx
|
|
119
|
-
import { useThemedStyles } from "../../../utils/use-themed-styles";
|
|
120
|
-
import { type ButtonStyles } from "../types";
|
|
121
|
-
|
|
122
|
-
export const useButtonVariantDefault = (): ButtonStyles => {
|
|
123
|
-
return useThemedStyles(
|
|
124
|
-
({ colors, radius, fontSize }): ButtonStyles => ({
|
|
125
|
-
root: {
|
|
126
|
-
backgroundColor: colors.primary,
|
|
127
|
-
borderRadius: radius,
|
|
128
|
-
padding: 12,
|
|
129
|
-
paddingHorizontal: 16,
|
|
130
|
-
},
|
|
131
|
-
label: {
|
|
132
|
-
color: colors.background,
|
|
133
|
-
fontSize: fontSize,
|
|
134
|
-
fontWeight: "600",
|
|
135
|
-
},
|
|
136
|
-
spinner: {
|
|
137
|
-
color: colors.background,
|
|
138
|
-
},
|
|
139
|
-
}),
|
|
140
|
-
);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
// components/button/variants/index.ts
|
|
144
|
-
export const ButtonVariants = {
|
|
145
|
-
default: useButtonVariantDefault,
|
|
146
|
-
secondary: useButtonVariantSecondary,
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
**Key Rules**:
|
|
151
|
-
|
|
152
|
-
- ✅ Always use `useThemedStyles` hook
|
|
153
|
-
- ✅ Return complete style objects
|
|
154
|
-
- ✅ Access theme tokens (colors, radius, fontSize, etc.)
|
|
155
|
-
- ❌ No hardcoded values (use theme)
|
|
156
|
-
- ✅ Each variant is a hook
|
|
157
|
-
|
|
158
|
-
## Component Development Workflow
|
|
159
|
-
|
|
160
|
-
### Step 1: Create Primitive Structure
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
mkdir -p src/primitives/alert/components
|
|
164
|
-
touch src/primitives/alert/components/alert-root.tsx
|
|
165
|
-
touch src/primitives/alert/components/alert-icon.tsx
|
|
166
|
-
touch src/primitives/alert/components/alert-title.tsx
|
|
167
|
-
touch src/primitives/alert/components/alert-description.tsx
|
|
168
|
-
touch src/primitives/alert/context.ts
|
|
169
|
-
touch src/primitives/alert/types.ts
|
|
170
|
-
touch src/primitives/alert/index.ts
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Step 2: Define Types
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
// src/primitives/alert/types.ts
|
|
177
|
-
import type { AlertRootProps } from "./components/alert-root";
|
|
178
|
-
import type { AlertIconProps } from "./components/alert-icon";
|
|
179
|
-
import type { AlertTitleProps } from "./components/alert-title";
|
|
180
|
-
import type { AlertDescriptionProps } from "./components/alert-description";
|
|
181
|
-
|
|
182
|
-
export interface AlertStyles {
|
|
183
|
-
root?: AlertRootProps["style"];
|
|
184
|
-
icon?: AlertIconProps;
|
|
185
|
-
title?: AlertTitleProps["style"];
|
|
186
|
-
description?: AlertDescriptionProps["style"];
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Step 3: Create Context
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
// src/primitives/alert/context.ts
|
|
194
|
-
import { createContext, useContext } from "react";
|
|
195
|
-
import type { AlertStyles } from "./types";
|
|
196
|
-
|
|
197
|
-
export interface AlertContext {
|
|
198
|
-
styles?: AlertStyles;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export const AlertContext = createContext<AlertContext | undefined>(undefined);
|
|
202
|
-
|
|
203
|
-
export const useAlert = () => {
|
|
204
|
-
const context = useContext(AlertContext);
|
|
205
|
-
if (!context) {
|
|
206
|
-
throw new Error("useAlert must be used within Alert");
|
|
207
|
-
}
|
|
208
|
-
return context;
|
|
209
|
-
};
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Step 4: Create Root Component
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
// src/primitives/alert/components/alert-root.tsx
|
|
216
|
-
import React from "react";
|
|
217
|
-
import { type StyleProp, View, type ViewStyle } from "react-native";
|
|
218
|
-
import { AlertContext } from "../context";
|
|
219
|
-
import type { AlertStyles } from "../types";
|
|
220
|
-
|
|
221
|
-
export interface AlertRootProps {
|
|
222
|
-
children?: React.ReactNode;
|
|
223
|
-
style?: StyleProp<ViewStyle>;
|
|
224
|
-
styles?: AlertStyles;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function AlertRoot(props: AlertRootProps) {
|
|
228
|
-
const composedStyle = [props.styles?.root, props.style];
|
|
229
|
-
|
|
230
|
-
return (
|
|
231
|
-
<AlertContext.Provider value={{ styles: props.styles }}>
|
|
232
|
-
<View style={composedStyle}>{props.children}</View>
|
|
233
|
-
</AlertContext.Provider>
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Step 5: Create Sub-Components
|
|
239
|
-
|
|
240
|
-
```typescript
|
|
241
|
-
// src/primitives/alert/components/alert-icon.tsx
|
|
242
|
-
import type { PropsWithRequiredRender, SvgProps } from "@/types/props.types";
|
|
243
|
-
import React from "react";
|
|
244
|
-
import { useAlert } from "../context";
|
|
245
|
-
|
|
246
|
-
export type AlertIconProps = SvgProps;
|
|
247
|
-
|
|
248
|
-
export function AlertIcon({
|
|
249
|
-
render: Component,
|
|
250
|
-
...props
|
|
251
|
-
}: PropsWithRequiredRender<AlertIconProps>) {
|
|
252
|
-
const alert = useAlert();
|
|
253
|
-
|
|
254
|
-
const composedProps = {
|
|
255
|
-
...alert.styles?.icon,
|
|
256
|
-
...props,
|
|
257
|
-
style: [alert.styles?.icon?.style, props.style],
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
return <Component absoluteStrokeWidth {...composedProps} />;
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Step 6: Export Primitive
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
// src/primitives/alert/index.ts
|
|
268
|
-
import { AlertRoot } from "./components/alert-root";
|
|
269
|
-
import { AlertIcon } from "./components/alert-icon";
|
|
270
|
-
import { AlertTitle } from "./components/alert-title";
|
|
271
|
-
import { AlertDescription } from "./components/alert-description";
|
|
272
|
-
|
|
273
|
-
export const AlertPrimitive = {
|
|
274
|
-
Root: AlertRoot,
|
|
275
|
-
Icon: AlertIcon,
|
|
276
|
-
Title: AlertTitle,
|
|
277
|
-
Description: AlertDescription,
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
export type { AlertRootProps } from "./components/alert-root";
|
|
281
|
-
export type { AlertIconProps } from "./components/alert-icon";
|
|
282
|
-
export type { AlertTitleProps } from "./components/alert-title";
|
|
283
|
-
export type { AlertDescriptionProps } from "./components/alert-description";
|
|
284
|
-
export type { AlertStyles } from "./types";
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### Step 7: Create Component Wrapper
|
|
288
|
-
|
|
289
|
-
```bash
|
|
290
|
-
mkdir -p src/components/alert/components
|
|
291
|
-
mkdir -p src/components/alert/variants
|
|
292
|
-
touch src/components/alert/components/alert-root.tsx
|
|
293
|
-
touch src/components/alert/variants/default.tsx
|
|
294
|
-
touch src/components/alert/variants/destructive.tsx
|
|
295
|
-
touch src/components/alert/variants/index.ts
|
|
296
|
-
touch src/components/alert/types.ts
|
|
297
|
-
touch src/components/alert/index.ts
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Step 8: Create Variant
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
// src/components/alert/variants/default.tsx
|
|
304
|
-
import { useThemedStyles } from "../../../utils/use-themed-styles";
|
|
305
|
-
import type { AlertStyles } from "../types";
|
|
306
|
-
|
|
307
|
-
export const useAlertVariantDefault = (): AlertStyles => {
|
|
308
|
-
return useThemedStyles(
|
|
309
|
-
({ colors, radius, fontSize }): AlertStyles => ({
|
|
310
|
-
root: {
|
|
311
|
-
padding: 16,
|
|
312
|
-
backgroundColor: colors.background,
|
|
313
|
-
borderRadius: radius,
|
|
314
|
-
borderWidth: 1,
|
|
315
|
-
borderColor: colors.border,
|
|
316
|
-
flexDirection: "row",
|
|
317
|
-
gap: 12,
|
|
318
|
-
},
|
|
319
|
-
icon: {
|
|
320
|
-
color: colors.foreground,
|
|
321
|
-
size: 20,
|
|
322
|
-
style: {
|
|
323
|
-
marginTop: 2,
|
|
324
|
-
},
|
|
325
|
-
},
|
|
326
|
-
title: {
|
|
327
|
-
fontSize: fontSize,
|
|
328
|
-
fontWeight: "600",
|
|
329
|
-
color: colors.foreground,
|
|
330
|
-
marginBottom: 4,
|
|
331
|
-
},
|
|
332
|
-
description: {
|
|
333
|
-
fontSize: fontSize * 0.875,
|
|
334
|
-
color: colors.mutedForeground,
|
|
335
|
-
lineHeight: 20,
|
|
336
|
-
},
|
|
337
|
-
}),
|
|
338
|
-
);
|
|
339
|
-
};
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Step 9: Create Component
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
// src/components/alert/components/alert-root.tsx
|
|
346
|
-
import { AlertPrimitive } from "@/primitives";
|
|
347
|
-
import type { AlertRootProps as AlertPrimitiveRootProps } from "@/primitives";
|
|
348
|
-
import React from "react";
|
|
349
|
-
import { AlertVariants } from "../variants";
|
|
350
|
-
|
|
351
|
-
export interface AlertRootProps extends AlertPrimitiveRootProps {
|
|
352
|
-
variant?: keyof typeof AlertVariants;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export function AlertRoot(props: AlertRootProps) {
|
|
356
|
-
const variant = props.variant ?? "default";
|
|
357
|
-
const variantStyles = AlertVariants[variant]();
|
|
358
|
-
|
|
359
|
-
return <AlertPrimitive.Root {...props} styles={variantStyles} />;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// src/components/alert/index.ts
|
|
363
|
-
import { AlertPrimitive } from "@/primitives";
|
|
364
|
-
import { AlertRoot } from "./components/alert-root";
|
|
365
|
-
|
|
366
|
-
export const Alert = {
|
|
367
|
-
Root: AlertRoot,
|
|
368
|
-
Icon: AlertPrimitive.Icon,
|
|
369
|
-
Title: AlertPrimitive.Title,
|
|
370
|
-
Description: AlertPrimitive.Description,
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
export type { AlertRootProps } from "./components/alert-root";
|
|
374
|
-
export type { AlertIconProps } from "@/primitives";
|
|
375
|
-
export type { AlertTitleProps } from "@/primitives";
|
|
376
|
-
export type { AlertDescriptionProps } from "@/primitives";
|
|
377
|
-
export type { AlertStyles } from "./types";
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### Step 10: Export from Indices
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
// src/primitives/index.ts
|
|
384
|
-
export * from "./alert";
|
|
385
|
-
// ... other primitives
|
|
386
|
-
|
|
387
|
-
// src/components/index.ts
|
|
388
|
-
export * from "./alert";
|
|
389
|
-
// ... other components
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
## Common Patterns
|
|
393
|
-
|
|
394
|
-
### Context Pattern for Sub-Components
|
|
395
|
-
|
|
396
|
-
Sub-components access styles via context:
|
|
397
|
-
|
|
398
|
-
```typescript
|
|
399
|
-
// In Root component
|
|
400
|
-
<ComponentContext.Provider value={{ styles: props.styles }}>
|
|
401
|
-
{props.children}
|
|
402
|
-
</ComponentContext.Provider>
|
|
403
|
-
|
|
404
|
-
// In sub-component
|
|
405
|
-
const component = useComponent();
|
|
406
|
-
const composedProps = {
|
|
407
|
-
...component.styles?.subComponent,
|
|
408
|
-
...props,
|
|
409
|
-
style: [component.styles?.subComponent?.style, props.style],
|
|
410
|
-
};
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
### Style Composition Order
|
|
414
|
-
|
|
415
|
-
Always compose styles in this order:
|
|
416
|
-
|
|
417
|
-
1. Variant styles (from `styles` prop)
|
|
418
|
-
2. User styles (from `style` prop)
|
|
419
|
-
|
|
420
|
-
```typescript
|
|
421
|
-
const composedStyle = [props.styles?.root, props.style];
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
### SVG Icon Components
|
|
425
|
-
|
|
426
|
-
For components accepting icons:
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
export type IconProps = SvgProps;
|
|
430
|
-
|
|
431
|
-
export function Icon({
|
|
432
|
-
render: Component,
|
|
433
|
-
...props
|
|
434
|
-
}: PropsWithRequiredRender<IconProps>) {
|
|
435
|
-
const composedProps = {
|
|
436
|
-
...context.styles?.icon,
|
|
437
|
-
...props,
|
|
438
|
-
style: [context.styles?.icon?.style, props.style],
|
|
439
|
-
absoluteStrokeWidth: true,
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
return <Component {...composedProps} />;
|
|
443
|
-
}
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
## Theme System
|
|
447
|
-
|
|
448
|
-
### Accessing Theme
|
|
449
|
-
|
|
450
|
-
```typescript
|
|
451
|
-
// In component code (variants only)
|
|
452
|
-
import { useThemedStyles } from "../../../utils/use-themed-styles";
|
|
453
|
-
|
|
454
|
-
const styles = useThemedStyles((theme) => ({
|
|
455
|
-
container: {
|
|
456
|
-
backgroundColor: theme.colors.background,
|
|
457
|
-
borderRadius: theme.radius,
|
|
458
|
-
},
|
|
459
|
-
}));
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Theme Structure
|
|
463
|
-
|
|
464
|
-
```typescript
|
|
465
|
-
interface Theme {
|
|
466
|
-
colors: {
|
|
467
|
-
background: string;
|
|
468
|
-
foreground: string;
|
|
469
|
-
primary: string;
|
|
470
|
-
secondary: string;
|
|
471
|
-
muted: string;
|
|
472
|
-
mutedForeground: string;
|
|
473
|
-
border: string;
|
|
474
|
-
success: string;
|
|
475
|
-
warning: string;
|
|
476
|
-
danger: string;
|
|
477
|
-
// ... more
|
|
478
|
-
};
|
|
479
|
-
radius: number;
|
|
480
|
-
fontSize: number;
|
|
481
|
-
fontFamily: string;
|
|
482
|
-
letterSpacing: number;
|
|
483
|
-
}
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
### Theme Tokens
|
|
487
|
-
|
|
488
|
-
Always use theme tokens instead of hardcoded values:
|
|
489
|
-
|
|
490
|
-
| Token | Usage |
|
|
491
|
-
| ------------------- | -------------------------------- |
|
|
492
|
-
| `colors.background` | Main background color |
|
|
493
|
-
| `colors.foreground` | Main text color |
|
|
494
|
-
| `colors.primary` | Primary action color |
|
|
495
|
-
| `colors.muted` | Subtle background (hover states) |
|
|
496
|
-
| `colors.border` | Border color |
|
|
497
|
-
| `radius` | Border radius value |
|
|
498
|
-
| `fontSize` | Base font size |
|
|
499
|
-
| `fontFamily` | Font family string |
|
|
500
|
-
|
|
501
|
-
## Anti-Patterns (Avoid)
|
|
502
|
-
|
|
503
|
-
### ❌ Inline Styles in Primitives
|
|
504
|
-
|
|
505
|
-
```typescript
|
|
506
|
-
// BAD
|
|
507
|
-
<View style={{ padding: 16, backgroundColor: '#fff' }}>
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
### ✅ Use styles prop
|
|
511
|
-
|
|
512
|
-
```typescript
|
|
513
|
-
// GOOD
|
|
514
|
-
<View style={[props.styles?.root, props.style]}>
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
### ❌ Direct Theme in Primitives
|
|
518
|
-
|
|
519
|
-
```typescript
|
|
520
|
-
// BAD - primitives should not access theme
|
|
521
|
-
const theme = useTheme();
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
### ✅ Theme Only in Variants
|
|
525
|
-
|
|
526
|
-
```typescript
|
|
527
|
-
// GOOD - use in variant hooks
|
|
528
|
-
export const useVariant = (): Styles => {
|
|
529
|
-
return useThemedStyles((theme) => ({
|
|
530
|
-
root: { backgroundColor: theme.colors.background },
|
|
531
|
-
}));
|
|
532
|
-
};
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
### ❌ Hardcoded Colors
|
|
536
|
-
|
|
537
|
-
```typescript
|
|
538
|
-
// BAD
|
|
539
|
-
backgroundColor: "#007AFF";
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### ✅ Theme Colors
|
|
543
|
-
|
|
544
|
-
```typescript
|
|
545
|
-
// GOOD
|
|
546
|
-
backgroundColor: theme.colors.primary;
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
### ❌ String Values for Spacing
|
|
550
|
-
|
|
551
|
-
```typescript
|
|
552
|
-
// BAD
|
|
553
|
-
padding: "16px";
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
### ✅ Number Values
|
|
557
|
-
|
|
558
|
-
```typescript
|
|
559
|
-
// GOOD
|
|
560
|
-
padding: 16;
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
## Type Safety
|
|
564
|
-
|
|
565
|
-
### Export All Types
|
|
566
|
-
|
|
567
|
-
```typescript
|
|
568
|
-
export type { ComponentRootProps } from "./components/component-root";
|
|
569
|
-
export type { ComponentStyles } from "./types";
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### Use PropsWithRequiredRender
|
|
573
|
-
|
|
574
|
-
For components requiring `render` prop:
|
|
575
|
-
|
|
576
|
-
```typescript
|
|
577
|
-
import type { PropsWithRequiredRender, SvgProps } from "@/types/props.types";
|
|
578
|
-
|
|
579
|
-
function Icon(props: PropsWithRequiredRender<SvgProps>) {
|
|
580
|
-
const { render: Component, ...rest } = props;
|
|
581
|
-
return <Component {...rest} />;
|
|
582
|
-
}
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
### StyleProp Types
|
|
586
|
-
|
|
587
|
-
```typescript
|
|
588
|
-
import type { StyleProp, ViewStyle, TextStyle } from "react-native";
|
|
589
|
-
|
|
590
|
-
interface Props {
|
|
591
|
-
style?: StyleProp<ViewStyle>;
|
|
592
|
-
textStyle?: StyleProp<TextStyle>;
|
|
593
|
-
}
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
## Build System
|
|
597
|
-
|
|
598
|
-
### Building the Library
|
|
599
|
-
|
|
600
|
-
```bash
|
|
601
|
-
cd library
|
|
602
|
-
bun build
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
This runs:
|
|
606
|
-
|
|
607
|
-
1. `bob build` - Compiles TypeScript with Babel
|
|
608
|
-
2. `tsc-alias` - Resolves path aliases in type definitions
|
|
609
|
-
|
|
610
|
-
### Build Output
|
|
611
|
-
|
|
612
|
-
```
|
|
613
|
-
dist/
|
|
614
|
-
├── commonjs/ # CommonJS modules
|
|
615
|
-
├── module/ # ES modules (.mjs)
|
|
616
|
-
└── typescript/ # Type definitions (.d.mts)
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
### Package Exports
|
|
620
|
-
|
|
621
|
-
```json
|
|
622
|
-
{
|
|
623
|
-
"exports": {
|
|
624
|
-
".": "./src/index.tsx",
|
|
625
|
-
"./primitives": "./src/primitives/index.ts",
|
|
626
|
-
"./components": "./src/components/index.ts",
|
|
627
|
-
"./hooks": "./src/hooks/index.ts"
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
## Component Checklist
|
|
633
|
-
|
|
634
|
-
- [ ] Primitive created with compound component pattern
|
|
635
|
-
- [ ] Context created for sharing styles
|
|
636
|
-
- [ ] Types defined in `types.ts`
|
|
637
|
-
- [ ] Root component provides context
|
|
638
|
-
- [ ] Sub-components use context for styles
|
|
639
|
-
- [ ] Component wrapper uses primitive
|
|
640
|
-
- [ ] At least one variant created (default)
|
|
641
|
-
- [ ] Variant uses `useThemedStyles`
|
|
642
|
-
- [ ] Exported from primitive index
|
|
643
|
-
- [ ] Exported from component index
|
|
644
|
-
- [ ] TypeScript types exported
|
|
645
|
-
- [ ] No console errors or warnings
|
|
646
|
-
- [ ] Example page created
|
|
647
|
-
- [ ] Added to navigation
|
|
648
|
-
|
|
649
|
-
## Common Issues
|
|
650
|
-
|
|
651
|
-
**Issue**: "Cannot find module @/..."
|
|
652
|
-
|
|
653
|
-
- **Fix**: Check `tsconfig.json` has path alias: `"@/*": ["./src/*"]`
|
|
654
|
-
|
|
655
|
-
**Issue**: Styles not applying
|
|
656
|
-
|
|
657
|
-
- **Fix**: Ensure variant styles passed to primitive via `styles` prop
|
|
658
|
-
|
|
659
|
-
**Issue**: Theme not updating
|
|
660
|
-
|
|
661
|
-
- **Fix**: Use `useThemedStyles` hook, not plain `useMemo`
|
|
662
|
-
|
|
663
|
-
**Issue**: Type errors with compound exports
|
|
664
|
-
|
|
665
|
-
- **Fix**: Export both types and components from index files
|
|
666
|
-
|
|
667
|
-
**Issue**: Build fails
|
|
668
|
-
|
|
669
|
-
- **Fix**: Run `bun build` from library directory, check for TypeScript errors
|
|
670
|
-
|
|
671
|
-
## Resources
|
|
672
|
-
|
|
673
|
-
- **Monorepo docs**: [`../AGENTS.md`](../AGENTS.md)
|
|
674
|
-
- **Example app**: [`../example/AGENTS.md`](../example/AGENTS.md)
|
|
675
|
-
- **Source code**: [`src/`](src/)
|
|
676
|
-
- **Primitives**: [`src/primitives/`](src/primitives/)
|
|
677
|
-
- **Components**: [`src/components/`](src/components/)
|
|
678
|
-
- **Themes**: [`src/themes/`](src/themes/)
|
package/babel.config.js
DELETED