@famgia/omnify-typescript 0.0.67 → 0.0.69

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.
Files changed (43) hide show
  1. package/dist/{chunk-4L77AHAC.js → chunk-6I4O23X6.js} +521 -66
  2. package/dist/chunk-6I4O23X6.js.map +1 -0
  3. package/dist/index.cjs +761 -65
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +138 -2
  6. package/dist/index.d.ts +138 -2
  7. package/dist/index.js +227 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/plugin.cjs +624 -75
  10. package/dist/plugin.cjs.map +1 -1
  11. package/dist/plugin.d.cts +6 -0
  12. package/dist/plugin.d.ts +6 -0
  13. package/dist/plugin.js +96 -11
  14. package/dist/plugin.js.map +1 -1
  15. package/package.json +3 -3
  16. package/scripts/postinstall.js +29 -40
  17. package/stubs/JapaneseAddressField.tsx.stub +289 -0
  18. package/stubs/JapaneseBankField.tsx.stub +212 -0
  19. package/stubs/JapaneseNameField.tsx.stub +194 -0
  20. package/stubs/ai-guides/checklists/react.md.stub +108 -0
  21. package/stubs/ai-guides/cursor/react-design.mdc.stub +289 -0
  22. package/stubs/ai-guides/cursor/react-form.mdc.stub +277 -0
  23. package/stubs/ai-guides/cursor/react-services.mdc.stub +304 -0
  24. package/stubs/ai-guides/cursor/react.mdc.stub +254 -0
  25. package/stubs/ai-guides/react/README.md.stub +221 -0
  26. package/stubs/ai-guides/react/antd-guide.md.stub +294 -0
  27. package/stubs/ai-guides/react/checklist.md.stub +108 -0
  28. package/stubs/ai-guides/react/datetime-guide.md.stub +137 -0
  29. package/stubs/ai-guides/react/design-philosophy.md.stub +363 -0
  30. package/stubs/ai-guides/react/i18n-guide.md.stub +211 -0
  31. package/stubs/ai-guides/react/laravel-integration.md.stub +181 -0
  32. package/stubs/ai-guides/react/service-pattern.md.stub +180 -0
  33. package/stubs/ai-guides/react/tanstack-query.md.stub +339 -0
  34. package/stubs/ai-guides/react/types-guide.md.stub +524 -0
  35. package/stubs/components-index.ts.stub +13 -0
  36. package/stubs/form-validation.ts.stub +106 -0
  37. package/stubs/rules/index.ts.stub +48 -0
  38. package/stubs/rules/kana.ts.stub +291 -0
  39. package/stubs/use-form-mutation.ts.stub +117 -0
  40. package/stubs/zod-i18n.ts.stub +32 -0
  41. package/ai-guides/antdesign-guide.md +0 -401
  42. package/ai-guides/typescript-guide.md +0 -310
  43. package/dist/chunk-4L77AHAC.js.map +0 -1
@@ -0,0 +1,289 @@
1
+ ---
2
+ description: Frontend Design System - Japanese Business UI Guidelines
3
+ globs: ["{{TYPESCRIPT_BASE}}/**/*.tsx", "{{TYPESCRIPT_BASE}}/**/*.css"]
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # React Design System
8
+
9
+ ## Overview
10
+
11
+ This design system follows **Japanese Business UI principles**: compact, functional, and minimal.
12
+ Primary color: Violet (#7C3AED).
13
+
14
+ ## Design Principles
15
+
16
+ ### 日本のビジネスUI (Japanese Business UI)
17
+
18
+ 1. **コンパクト (Compact)** - High information density, minimal wasted space
19
+ 2. **機能的 (Functional)** - Prioritize usability and efficiency
20
+ 3. **シンプル (Simple)** - Minimize visual noise, flat design
21
+ 4. **高密度 (High Density)** - More information visible on screen
22
+
23
+ ## Color System
24
+
25
+ ### HSL-Based Color Harmony
26
+
27
+ All colors follow HSL color theory with consistent saturation (~84%) for harmony.
28
+
29
+ ```
30
+ Primary Hue: 258° (Violet)
31
+ ```
32
+
33
+ ### Brand Colors
34
+
35
+ | Role | Hex | HSL | Usage |
36
+ | ----------------- | --------- | -------------- | -------------------------------- |
37
+ | **Primary** | `#7C3AED` | 258°, 84%, 58% | Buttons, links, sidebar, accents |
38
+ | **Primary Light** | `#9061F9` | 258°, 84%, 68% | Hover states, selected items |
39
+ | **Primary Dark** | `#6D28D9` | 258°, 84%, 50% | Active states, sub-menus |
40
+
41
+ ### Semantic Colors (Complementary Harmony)
42
+
43
+ | Role | Hex | HSL | Usage |
44
+ | ----------- | --------- | -------------- | ---------------------------------- |
45
+ | **Success** | `#10B981` | 160°, 84%, 39% | Success messages, positive actions |
46
+ | **Warning** | `#F59E0B` | 38°, 92%, 50% | Warnings, caution states |
47
+ | **Error** | `#EF4444` | 0°, 84%, 60% | Errors, destructive actions |
48
+
49
+ ### Neutral Colors (Violet Undertone)
50
+
51
+ | Role | Hex | Usage |
52
+ | ------------------------ | --------- | ----------------------------- |
53
+ | **Text Primary** | `#1E1B2E` | Main text, headings |
54
+ | **Text Secondary** | `#4B5563` | Secondary text, labels |
55
+ | **Text Tertiary** | `#9CA3AF` | Placeholder, disabled text |
56
+ | **Background Layout** | `#F8F7FA` | Page background (violet-gray) |
57
+ | **Background Container** | `#FFFFFF` | Cards, containers |
58
+ | **Border** | `#E5E7EB` | Borders, dividers |
59
+ | **Border Secondary** | `#F3F4F6` | Subtle borders |
60
+
61
+ ### Color Usage Rules
62
+
63
+ 1. **60-30-10 Rule**: 60% neutral, 30% primary, 10% accent
64
+ 2. **Same Saturation Family**: Keep semantic colors at ~84% saturation
65
+ 3. **Cool Tone Neutrals**: Grays should have slight violet undertone
66
+ 4. **WCAG AA Compliance**: Maintain contrast ratio ≥ 4.5:1 for text
67
+
68
+ ## Typography
69
+
70
+ ### Locale-Specific Font Stacks
71
+
72
+ ```typescript
73
+ const fontFamilies = {
74
+ // Japanese - CJK optimized
75
+ ja: "'Noto Sans JP', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif",
76
+
77
+ // English - Modern western
78
+ en: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
79
+
80
+ // Vietnamese - Light, clean font with diacritics support
81
+ vi: "'Inter', 'Nunito Sans', -apple-system, BlinkMacSystemFont, sans-serif",
82
+ };
83
+ ```
84
+
85
+ ### Font Sizes (Compact)
86
+
87
+ | Token | Size | Usage |
88
+ | ------------------ | ---- | -------------- |
89
+ | `fontSize` | 13px | Base text |
90
+ | `fontSizeLG` | 14px | Large text |
91
+ | `fontSizeHeading1` | 24px | Page titles |
92
+ | `fontSizeHeading2` | 20px | Section titles |
93
+ | `fontSizeHeading3` | 16px | Card titles |
94
+ | `fontSizeHeading4` | 14px | Sub-headings |
95
+ | `fontSizeHeading5` | 13px | Small headings |
96
+
97
+ ### Line Height
98
+
99
+ - Default: `1.5` (compact, suitable for Japanese text)
100
+
101
+ ## Spacing System
102
+
103
+ ### Compact Spacing Scale
104
+
105
+ | Token | Value | Usage |
106
+ | ----------- | ----- | --------------- |
107
+ | `paddingXS` | 4px | Minimal spacing |
108
+ | `paddingSM` | 8px | Small spacing |
109
+ | `padding` | 12px | Default spacing |
110
+ | `paddingLG` | 16px | Large spacing |
111
+ | `marginXS` | 4px | Minimal margin |
112
+ | `marginSM` | 8px | Small margin |
113
+ | `margin` | 12px | Default margin |
114
+ | `marginLG` | 16px | Large margin |
115
+
116
+ ### Layout Spacing
117
+
118
+ - Content margin: `12px`
119
+ - Content padding: `16px`
120
+ - Header height: `48px`
121
+ - Sidebar width: `180px`
122
+
123
+ ## Border Radius
124
+
125
+ ### Subtle, Professional Corners
126
+
127
+ | Token | Value | Usage |
128
+ | ---------------- | ----- | ------------------------ |
129
+ | `borderRadiusSM` | 2px | Tags, badges |
130
+ | `borderRadius` | 4px | Buttons, inputs, cards |
131
+ | `borderRadiusLG` | 6px | Modals, large containers |
132
+
133
+ > **Note**: Japanese business UIs prefer subtle corners over heavily rounded designs.
134
+
135
+ ## Shadows
136
+
137
+ ### Almost Flat Design
138
+
139
+ ```css
140
+ /* Primary shadow - very subtle */
141
+ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.03)"
142
+
143
+ /* Secondary shadow - hover states */
144
+ boxShadowSecondary: "0 1px 3px rgba(0, 0, 0, 0.04)"
145
+ ```
146
+
147
+ > **Note**: Prefer borders over shadows for Japanese business style.
148
+
149
+ ## Control Sizes
150
+
151
+ ### Compact Controls
152
+
153
+ | Token | Value | Usage |
154
+ | ----------------- | ----- | --------------------- |
155
+ | `controlHeightSM` | 28px | Small buttons, inputs |
156
+ | `controlHeight` | 32px | Default controls |
157
+ | `controlHeightLG` | 36px | Large controls |
158
+
159
+ ## Component Guidelines
160
+
161
+ ### Buttons
162
+
163
+ ```typescript
164
+ Button: {
165
+ controlHeight: 32,
166
+ paddingInline: 12,
167
+ fontWeight: 500,
168
+ }
169
+ ```
170
+
171
+ ### Inputs
172
+
173
+ ```typescript
174
+ Input: {
175
+ controlHeight: 32,
176
+ paddingInline: 8,
177
+ }
178
+ ```
179
+
180
+ ### Tables
181
+
182
+ ```typescript
183
+ Table: {
184
+ cellPaddingBlock: 8,
185
+ cellPaddingInline: 8,
186
+ headerBg: "#F8F7FA",
187
+ }
188
+ ```
189
+
190
+ ### Forms
191
+
192
+ ```typescript
193
+ Form: {
194
+ itemMarginBottom: 16,
195
+ verticalLabelPadding: "0 0 4px",
196
+ }
197
+ ```
198
+
199
+ ### Menu (Dark Theme for Sidebar)
200
+
201
+ ```typescript
202
+ Menu: {
203
+ itemHeight: 36,
204
+ itemMarginBlock: 2,
205
+ itemMarginInline: 4,
206
+ darkItemBg: "#7C3AED",
207
+ darkSubMenuItemBg: "#6D28D9",
208
+ darkItemSelectedBg: "#9061F9",
209
+ darkItemSelectedColor: "#FFFFFF",
210
+ darkItemColor: "rgba(255, 255, 255, 0.9)",
211
+ darkItemHoverBg: "rgba(144, 97, 249, 0.6)",
212
+ darkItemHoverColor: "#FFFFFF",
213
+ }
214
+ ```
215
+
216
+ ### Layout
217
+
218
+ ```typescript
219
+ Layout: {
220
+ siderBg: "#7C3AED",
221
+ headerPadding: "0 16px",
222
+ headerHeight: 48,
223
+ }
224
+ ```
225
+
226
+ ## Implementation
227
+
228
+ ### Ant Design Theme Configuration
229
+
230
+ All design tokens are configured in:
231
+ ```
232
+ frontend/src/components/AntdThemeProvider.tsx
233
+ ```
234
+
235
+ ### Google Fonts Loading
236
+
237
+ Fonts are loaded in:
238
+ ```
239
+ frontend/src/app/layout.tsx
240
+ ```
241
+
242
+ Required fonts:
243
+ - Noto Sans JP (Japanese)
244
+ - Inter (English)
245
+ - Be Vietnam Pro (Vietnamese)
246
+
247
+ ## Do's and Don'ts
248
+
249
+ ### ✅ Do
250
+
251
+ - Use compact spacing (8-16px)
252
+ - Keep shadows minimal or none
253
+ - Use subtle border radius (2-6px)
254
+ - Maintain high information density
255
+ - Use locale-specific fonts
256
+ - Follow HSL color harmony
257
+
258
+ ### ❌ Don't
259
+
260
+ - Use excessive padding (>24px)
261
+ - Use heavy shadows
262
+ - Use large border radius (>10px)
263
+ - Leave large empty spaces
264
+ - Mix warm and cool grays
265
+ - Use colors outside the harmony system
266
+
267
+ ## Quick Reference
268
+
269
+ ```typescript
270
+ // Primary colors
271
+ const primary = "#7C3AED";
272
+ const primaryLight = "#9061F9";
273
+ const primaryDark = "#6D28D9";
274
+
275
+ // Semantic colors
276
+ const success = "#10B981";
277
+ const warning = "#F59E0B";
278
+ const error = "#EF4444";
279
+
280
+ // Neutrals
281
+ const textPrimary = "#1E1B2E";
282
+ const bgLayout = "#F8F7FA";
283
+ const border = "#E5E7EB";
284
+
285
+ // Sizes
286
+ const controlHeight = 32;
287
+ const borderRadius = 4;
288
+ const padding = 12;
289
+ ```
@@ -0,0 +1,277 @@
1
+ ---
2
+ description: "Form development guide - Omnify patterns, Zod validation, backend errors"
3
+ globs: ["{{TYPESCRIPT_BASE}}/features/**", "{{TYPESCRIPT_BASE}}/components/**"]
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Form Development Guide
8
+
9
+ ## Quick Start
10
+
11
+ ```tsx
12
+ import { Form, Input, Button, Space, Card, Divider } from 'antd';
13
+ import type { FormInstance } from 'antd';
14
+ import { zodRule, setZodLocale } from '@/omnify/lib';
15
+ import { OmnifyForm } from '@/omnify/components';
16
+ import {
17
+ type Customer,
18
+ type CustomerCreate,
19
+ customerSchemas,
20
+ customerI18n,
21
+ getCustomerFieldLabel,
22
+ getCustomerFieldPlaceholder,
23
+ } from '@/omnify/schemas';
24
+
25
+ const LOCALE = 'ja'; // TODO: Get from context
26
+
27
+ export function CustomerForm({
28
+ form,
29
+ initialValues,
30
+ onSubmit,
31
+ loading = false,
32
+ isEdit = false,
33
+ onCancel,
34
+ }: {
35
+ form: FormInstance<CustomerCreate>;
36
+ initialValues?: Partial<Customer>;
37
+ onSubmit: (values: CustomerCreate) => void;
38
+ loading?: boolean;
39
+ isEdit?: boolean;
40
+ onCancel?: () => void;
41
+ }) {
42
+ // Set locale for validation messages
43
+ setZodLocale(LOCALE);
44
+
45
+ // Helper functions
46
+ const label = (key: string) => getCustomerFieldLabel(key, LOCALE);
47
+ const placeholder = (key: string) => getCustomerFieldPlaceholder(key, LOCALE);
48
+ const rule = (key: keyof typeof customerSchemas) =>
49
+ zodRule(customerSchemas[key], label(key));
50
+
51
+ return (
52
+ <Card>
53
+ <Form
54
+ form={form}
55
+ layout="horizontal"
56
+ labelCol={{ span: 6 }}
57
+ wrapperCol={{ span: 18 }}
58
+ initialValues={initialValues}
59
+ onFinish={onSubmit}
60
+ style={{ maxWidth: 800 }}
61
+ >
62
+ {/* Section: Contact */}
63
+ <Divider orientation="left">Contact</Divider>
64
+
65
+ <Form.Item
66
+ name="email"
67
+ label={label('email')}
68
+ rules={[rule('email')]}
69
+ >
70
+ <Input type="email" placeholder={placeholder('email')} />
71
+ </Form.Item>
72
+
73
+ {/* Submit Buttons */}
74
+ <Form.Item wrapperCol={{ offset: 6, span: 18 }}>
75
+ <Space>
76
+ <Button type="primary" htmlType="submit" loading={loading}>
77
+ {isEdit ? 'Update' : 'Create'}
78
+ </Button>
79
+ {onCancel && <Button onClick={onCancel}>Cancel</Button>}
80
+ </Space>
81
+ </Form.Item>
82
+ </Form>
83
+ </Card>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ## Key Patterns
89
+
90
+ ### 1. Imports
91
+
92
+ ```tsx
93
+ // Omnify utilities
94
+ import { zodRule, setZodLocale } from '@/omnify/lib';
95
+ import { OmnifyForm } from '@/omnify/components';
96
+
97
+ // Model-specific (generated by Omnify)
98
+ import {
99
+ type Customer,
100
+ type CustomerCreate,
101
+ customerSchemas,
102
+ customerI18n,
103
+ getCustomerFieldLabel,
104
+ getCustomerFieldPlaceholder,
105
+ } from '@/omnify/schemas';
106
+ ```
107
+
108
+ ### 2. Helper Functions (MUST define in every form)
109
+
110
+ ```tsx
111
+ const LOCALE = 'ja'; // Get from context in real app
112
+
113
+ // Set locale once at start
114
+ setZodLocale(LOCALE);
115
+
116
+ // Define helper functions
117
+ const label = (key: string) => getCustomerFieldLabel(key, LOCALE);
118
+ const placeholder = (key: string) => getCustomerFieldPlaceholder(key, LOCALE);
119
+ const rule = (key: keyof typeof customerSchemas) =>
120
+ zodRule(customerSchemas[key], label(key));
121
+ ```
122
+
123
+ ### 3. Form.Item Pattern
124
+
125
+ ```tsx
126
+ <Form.Item
127
+ name="email" // Field name (matches backend)
128
+ label={label('email')} // i18n label
129
+ rules={[rule('email')]} // Zod validation
130
+ >
131
+ <Input
132
+ type="email"
133
+ placeholder={placeholder('email')} // i18n placeholder
134
+ />
135
+ </Form.Item>
136
+ ```
137
+
138
+ ### 4. Section Dividers
139
+
140
+ ```tsx
141
+ <Divider orientation="left">Contact Info</Divider>
142
+ ```
143
+
144
+ ## Compound Fields (Japan Plugin)
145
+
146
+ For Japanese compound types, use `OmnifyForm` components:
147
+
148
+ ### JapaneseName
149
+
150
+ ```tsx
151
+ <OmnifyForm.JapaneseName
152
+ schemas={customerSchemas}
153
+ i18n={customerI18n}
154
+ prefix="name"
155
+ required
156
+ />
157
+ ```
158
+
159
+ ### JapaneseAddress
160
+
161
+ ```tsx
162
+ <OmnifyForm.JapaneseAddress
163
+ form={form}
164
+ schemas={customerSchemas}
165
+ i18n={customerI18n}
166
+ prefix="address"
167
+ />
168
+ ```
169
+
170
+ ### JapaneseBank
171
+
172
+ ```tsx
173
+ <OmnifyForm.JapaneseBank
174
+ schemas={customerSchemas}
175
+ i18n={customerI18n}
176
+ prefix="bank"
177
+ />
178
+ ```
179
+
180
+ ## Props Pattern
181
+
182
+ ```tsx
183
+ interface CustomerFormProps {
184
+ form: FormInstance<CustomerCreate>; // REQUIRED - from parent
185
+ initialValues?: Partial<Customer>; // For edit mode
186
+ onSubmit: (values: CustomerCreate) => void;
187
+ loading?: boolean;
188
+ isEdit?: boolean;
189
+ onCancel?: () => void;
190
+ }
191
+ ```
192
+
193
+ ## Page Component (Parent)
194
+
195
+ ```tsx
196
+ import { Form } from 'antd';
197
+ import { useFormMutation } from '@/hooks/useFormMutation';
198
+ import { customerService } from '@/services/customers';
199
+ import { queryKeys } from '@/lib/queryKeys';
200
+ import { CustomerForm } from '@/features/customers/CustomerForm';
201
+ import type { CustomerCreate } from '@/omnify/schemas';
202
+
203
+ export default function CreateCustomerPage() {
204
+ const [form] = Form.useForm<CustomerCreate>();
205
+
206
+ const { mutate, isPending } = useFormMutation({
207
+ form,
208
+ mutationFn: customerService.create,
209
+ invalidateKeys: [queryKeys.customers.all],
210
+ successMessage: "messages.created",
211
+ redirectTo: "/customers",
212
+ });
213
+
214
+ return (
215
+ <CustomerForm
216
+ form={form}
217
+ onSubmit={(values) => mutate(values)}
218
+ loading={isPending}
219
+ />
220
+ );
221
+ }
222
+ ```
223
+
224
+ ## Backend Errors (422)
225
+
226
+ `useFormMutation` automatically handles:
227
+ 1. `form.setFields(getFormErrors(error))` - display on form fields
228
+ 2. `message.error(validationMessage)` - toast message
229
+
230
+ **Field names MUST match Laravel:**
231
+ ```tsx
232
+ // Laravel: { errors: { "name_lastname": ["..."] } }
233
+ <Form.Item name="name_lastname"> // ✅ Matches
234
+ <Form.Item name="lastName"> // ❌ Doesn't match
235
+ ```
236
+
237
+ ## Checklist
238
+
239
+ - [ ] Import from `@/omnify/lib`, `@/omnify/components`, `@/omnify/schemas`
240
+ - [ ] Define `label()`, `placeholder()`, `rule()` helper functions
241
+ - [ ] Call `setZodLocale(LOCALE)` at start
242
+ - [ ] Form receives `form` prop from parent (not create own)
243
+ - [ ] Use `Divider` for sections
244
+ - [ ] Use `OmnifyForm.*` for compound fields (JapaneseName, etc.)
245
+ - [ ] Field names match Laravel field names
246
+ - [ ] Submit buttons with loading state
247
+
248
+ ## Common Mistakes
249
+
250
+ ```tsx
251
+ // ❌ Wrong - Create form instance in form component
252
+ function MyForm() {
253
+ const [form] = Form.useForm(); // DON'T create here
254
+ return <Form form={form}>...
255
+ }
256
+
257
+ // ✅ Correct - Receive from parent
258
+ function MyForm({ form }: { form: FormInstance }) {
259
+ return <Form form={form}>...
260
+ }
261
+ ```
262
+
263
+ ```tsx
264
+ // ❌ Wrong - Inline validation message
265
+ rules={[{ required: true, message: 'Email is required' }]}
266
+
267
+ // ✅ Correct - Use zodRule with i18n
268
+ rules={[rule('email')]}
269
+ ```
270
+
271
+ ```tsx
272
+ // ❌ Wrong - Hardcoded placeholder
273
+ <Input placeholder="Enter email" />
274
+
275
+ // ✅ Correct - Use placeholder helper
276
+ <Input placeholder={placeholder('email')} />
277
+ ```