@famgia/omnify-typescript 0.0.66 → 0.0.68

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/ai-guides/react-form-guide.md +259 -0
  2. package/ai-guides/typescript-guide.md +53 -0
  3. package/dist/{chunk-4L77AHAC.js → chunk-6I4O23X6.js} +521 -66
  4. package/dist/chunk-6I4O23X6.js.map +1 -0
  5. package/dist/index.cjs +761 -65
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +138 -2
  8. package/dist/index.d.ts +138 -2
  9. package/dist/index.js +227 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/plugin.cjs +624 -75
  12. package/dist/plugin.cjs.map +1 -1
  13. package/dist/plugin.d.cts +6 -0
  14. package/dist/plugin.d.ts +6 -0
  15. package/dist/plugin.js +96 -11
  16. package/dist/plugin.js.map +1 -1
  17. package/package.json +4 -3
  18. package/scripts/postinstall.js +29 -40
  19. package/stubs/JapaneseAddressField.tsx.stub +289 -0
  20. package/stubs/JapaneseBankField.tsx.stub +212 -0
  21. package/stubs/JapaneseNameField.tsx.stub +194 -0
  22. package/stubs/ai-guides/checklists/react.md.stub +108 -0
  23. package/stubs/ai-guides/cursor/react-design.mdc.stub +289 -0
  24. package/stubs/ai-guides/cursor/react-form.mdc.stub +277 -0
  25. package/stubs/ai-guides/cursor/react-services.mdc.stub +304 -0
  26. package/stubs/ai-guides/cursor/react.mdc.stub +305 -0
  27. package/stubs/ai-guides/react/README.md.stub +221 -0
  28. package/stubs/ai-guides/react/antd-guide.md.stub +294 -0
  29. package/stubs/ai-guides/react/checklist.md.stub +108 -0
  30. package/stubs/ai-guides/react/datetime-guide.md.stub +137 -0
  31. package/stubs/ai-guides/react/design-philosophy.md.stub +363 -0
  32. package/stubs/ai-guides/react/i18n-guide.md.stub +211 -0
  33. package/stubs/ai-guides/react/laravel-integration.md.stub +181 -0
  34. package/stubs/ai-guides/react/service-pattern.md.stub +180 -0
  35. package/stubs/ai-guides/react/tanstack-query.md.stub +339 -0
  36. package/stubs/ai-guides/react/types-guide.md.stub +524 -0
  37. package/stubs/components-index.ts.stub +13 -0
  38. package/stubs/form-validation.ts.stub +106 -0
  39. package/stubs/rules/index.ts.stub +48 -0
  40. package/stubs/rules/kana.ts.stub +291 -0
  41. package/stubs/use-form-mutation.ts.stub +117 -0
  42. package/stubs/zod-i18n.ts.stub +32 -0
  43. package/dist/chunk-4L77AHAC.js.map +0 -1
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Japanese Kana Validation Rules
3
+ *
4
+ * Provides configurable validation for Japanese character input:
5
+ * - 全角カタカナ (Full-width Katakana) - default
6
+ * - 半角カタカナ (Half-width Katakana)
7
+ * - ひらがな (Hiragana)
8
+ * - Mixed modes
9
+ */
10
+
11
+ export interface KanaRuleOptions {
12
+ /** Allow full-width katakana (ア-ン) - default: true */
13
+ fullWidthKatakana?: boolean;
14
+ /** Allow half-width katakana (ア-ン) - default: false */
15
+ halfWidthKatakana?: boolean;
16
+ /** Allow hiragana (あ-ん) - default: false */
17
+ hiragana?: boolean;
18
+ /** Allow numbers (0-9, 0-9) - default: false */
19
+ allowNumbers?: boolean;
20
+ /** Allow full-width numbers (0-9) - default: false */
21
+ fullWidthNumbers?: boolean;
22
+ /** Allow half-width numbers (0-9) - default: false */
23
+ halfWidthNumbers?: boolean;
24
+ /** Allow spaces (full-width and half-width) - default: true */
25
+ allowSpaces?: boolean;
26
+ /** Allow specific special characters - default: ['ー', '・'] */
27
+ allowSpecialChars?: string[];
28
+ /** Custom error message */
29
+ message?: string;
30
+ }
31
+
32
+ // Character ranges
33
+ const CHAR_RANGES = {
34
+ // Full-width Katakana: ァ-ヶ (U+30A1-U+30F6) + ー (U+30FC)
35
+ fullWidthKatakana: 'ァ-ヶー',
36
+ // Half-width Katakana: ヲ-゚ (U+FF66-U+FF9F)
37
+ halfWidthKatakana: 'ヲ-゚',
38
+ // Hiragana: ぁ-ゖ (U+3041-U+3096)
39
+ hiragana: 'ぁ-ゖ',
40
+ // Full-width numbers: 0-9
41
+ fullWidthNumbers: '0-9',
42
+ // Half-width numbers: 0-9
43
+ halfWidthNumbers: '0-9',
44
+ // Full-width space:  (U+3000)
45
+ fullWidthSpace: ' ',
46
+ // Half-width space
47
+ halfWidthSpace: ' ',
48
+ // Common special chars for names
49
+ defaultSpecialChars: ['ー', '・'],
50
+ } as const;
51
+
52
+ // Default options: 全角カタカナ + spaces + ー・
53
+ const DEFAULT_OPTIONS: Required<KanaRuleOptions> = {
54
+ fullWidthKatakana: true,
55
+ halfWidthKatakana: false,
56
+ hiragana: false,
57
+ allowNumbers: false,
58
+ fullWidthNumbers: false,
59
+ halfWidthNumbers: false,
60
+ allowSpaces: true,
61
+ allowSpecialChars: ['ー', '・'],
62
+ message: '',
63
+ };
64
+
65
+ /**
66
+ * Build regex pattern from options
67
+ */
68
+ function buildKanaPattern(options: KanaRuleOptions = {}): string {
69
+ const opts = { ...DEFAULT_OPTIONS, ...options };
70
+ const parts: string[] = [];
71
+
72
+ if (opts.fullWidthKatakana) {
73
+ parts.push(CHAR_RANGES.fullWidthKatakana);
74
+ }
75
+ if (opts.halfWidthKatakana) {
76
+ parts.push(CHAR_RANGES.halfWidthKatakana);
77
+ }
78
+ if (opts.hiragana) {
79
+ parts.push(CHAR_RANGES.hiragana);
80
+ }
81
+ if (opts.allowNumbers || opts.fullWidthNumbers) {
82
+ parts.push(CHAR_RANGES.fullWidthNumbers);
83
+ }
84
+ if (opts.allowNumbers || opts.halfWidthNumbers) {
85
+ parts.push(CHAR_RANGES.halfWidthNumbers);
86
+ }
87
+ if (opts.allowSpaces) {
88
+ parts.push(CHAR_RANGES.fullWidthSpace);
89
+ parts.push(CHAR_RANGES.halfWidthSpace);
90
+ }
91
+ if (opts.allowSpecialChars && opts.allowSpecialChars.length > 0) {
92
+ // Escape special regex chars
93
+ const escaped = opts.allowSpecialChars.map(c =>
94
+ c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
95
+ ).join('');
96
+ parts.push(escaped);
97
+ }
98
+
99
+ return `^[${parts.join('')}]*$`;
100
+ }
101
+
102
+ /**
103
+ * Get default error message based on options
104
+ */
105
+ function getDefaultMessage(options: KanaRuleOptions = {}, locale: string = 'ja'): string {
106
+ const opts = { ...DEFAULT_OPTIONS, ...options };
107
+
108
+ const messages: Record<string, Record<string, string>> = {
109
+ ja: {
110
+ fullWidthKatakana: '全角カタカナ',
111
+ halfWidthKatakana: '半角カタカナ',
112
+ hiragana: 'ひらがな',
113
+ mixed: 'カナ文字',
114
+ },
115
+ en: {
116
+ fullWidthKatakana: 'full-width katakana',
117
+ halfWidthKatakana: 'half-width katakana',
118
+ hiragana: 'hiragana',
119
+ mixed: 'kana characters',
120
+ },
121
+ };
122
+
123
+ const msg = messages[locale] ?? messages['ja'];
124
+
125
+ // Determine what type to show in message
126
+ let type = msg.mixed;
127
+ if (opts.fullWidthKatakana && !opts.halfWidthKatakana && !opts.hiragana) {
128
+ type = msg.fullWidthKatakana;
129
+ } else if (opts.halfWidthKatakana && !opts.fullWidthKatakana && !opts.hiragana) {
130
+ type = msg.halfWidthKatakana;
131
+ } else if (opts.hiragana && !opts.fullWidthKatakana && !opts.halfWidthKatakana) {
132
+ type = msg.hiragana;
133
+ }
134
+
135
+ if (locale === 'ja') {
136
+ return `${type}で入力してください`;
137
+ }
138
+ return `Please enter in ${type}`;
139
+ }
140
+
141
+ /**
142
+ * Create a kana validation regex
143
+ */
144
+ export function createKanaRegex(options: KanaRuleOptions = {}): RegExp {
145
+ return new RegExp(buildKanaPattern(options));
146
+ }
147
+
148
+ /**
149
+ * Validate a string against kana rules
150
+ */
151
+ export function validateKana(value: string, options: KanaRuleOptions = {}): boolean {
152
+ if (!value) return true; // Empty is valid (use required for that)
153
+ const regex = createKanaRegex(options);
154
+ return regex.test(value);
155
+ }
156
+
157
+ /**
158
+ * Get kana validation pattern string (for Zod .regex())
159
+ */
160
+ export function getKanaPattern(options: KanaRuleOptions = {}): string {
161
+ return buildKanaPattern(options);
162
+ }
163
+
164
+ /**
165
+ * Get error message for kana validation
166
+ */
167
+ export function getKanaErrorMessage(options: KanaRuleOptions = {}, locale: string = 'ja'): string {
168
+ return options.message ?? getDefaultMessage(options, locale);
169
+ }
170
+
171
+ // ============================================================================
172
+ // Preset configurations
173
+ // ============================================================================
174
+
175
+ /** 全角カタカナ (Full-width Katakana) - Default for Japanese names */
176
+ export const KATAKANA_FULL_WIDTH: KanaRuleOptions = {
177
+ fullWidthKatakana: true,
178
+ halfWidthKatakana: false,
179
+ hiragana: false,
180
+ allowSpaces: true,
181
+ allowSpecialChars: ['ー', '・'],
182
+ };
183
+
184
+ /** 半角カタカナ (Half-width Katakana) - Legacy systems */
185
+ export const KATAKANA_HALF_WIDTH: KanaRuleOptions = {
186
+ fullWidthKatakana: false,
187
+ halfWidthKatakana: true,
188
+ hiragana: false,
189
+ allowSpaces: true,
190
+ allowSpecialChars: ['ー'], // Half-width prolonged sound mark
191
+ };
192
+
193
+ /** ひらがな (Hiragana) */
194
+ export const HIRAGANA: KanaRuleOptions = {
195
+ fullWidthKatakana: false,
196
+ halfWidthKatakana: false,
197
+ hiragana: true,
198
+ allowSpaces: true,
199
+ allowSpecialChars: ['ー'],
200
+ };
201
+
202
+ /** カタカナ + ひらがな (Any kana) */
203
+ export const KANA_ANY: KanaRuleOptions = {
204
+ fullWidthKatakana: true,
205
+ halfWidthKatakana: true,
206
+ hiragana: true,
207
+ allowSpaces: true,
208
+ allowSpecialChars: ['ー', '・', 'ー'],
209
+ };
210
+
211
+ /** 全角カタカナ + 数字 (Full-width katakana with numbers) */
212
+ export const KATAKANA_WITH_NUMBERS: KanaRuleOptions = {
213
+ fullWidthKatakana: true,
214
+ halfWidthKatakana: false,
215
+ hiragana: false,
216
+ allowNumbers: true,
217
+ allowSpaces: true,
218
+ allowSpecialChars: ['ー', '・'],
219
+ };
220
+
221
+ // ============================================================================
222
+ // Pattern strings for Zod .regex()
223
+ // ============================================================================
224
+
225
+ /** Pattern: 全角カタカナ + スペース + ー・ (for z.string().regex()) */
226
+ export const KATAKANA_PATTERN = /^[ァ-ヶー・  ]*$/;
227
+
228
+ /** Pattern: 半角カタカナ (for z.string().regex()) */
229
+ export const KATAKANA_HALF_PATTERN = /^[ヲ-゚ー ]*$/;
230
+
231
+ /** Pattern: ひらがな (for z.string().regex()) */
232
+ export const HIRAGANA_PATTERN = /^[ぁ-ゖー  ]*$/;
233
+
234
+ /** Pattern: すべてのかな (for z.string().regex()) */
235
+ export const KANA_ANY_PATTERN = /^[ァ-ヶぁ-ゖヲ-゚ー・ー  ]*$/;
236
+
237
+ // ============================================================================
238
+ // Zod refinement helpers
239
+ // ============================================================================
240
+
241
+ import { z } from 'zod';
242
+
243
+ /**
244
+ * Create Zod string schema with kana validation
245
+ * @example
246
+ * const schema = z.object({
247
+ * name_kana: kanaString(), // 全角カタカナ (default)
248
+ * name_kana2: kanaString({ hiragana: true }), // カタカナ + ひらがな
249
+ * });
250
+ */
251
+ export function kanaString(options: KanaRuleOptions = {}) {
252
+ const opts = { ...KATAKANA_FULL_WIDTH, ...options };
253
+ const regex = createKanaRegex(opts);
254
+ const message = getKanaErrorMessage(opts);
255
+
256
+ return z.string().regex(regex, { message });
257
+ }
258
+
259
+ /**
260
+ * Add kana validation to existing Zod string schema
261
+ * @example
262
+ * const schema = z.string().min(1).pipe(withKana());
263
+ */
264
+ export function withKana(options: KanaRuleOptions = {}) {
265
+ return kanaString(options);
266
+ }
267
+
268
+ // Default export
269
+ export const kanaRules = {
270
+ createRegex: createKanaRegex,
271
+ validate: validateKana,
272
+ getPattern: getKanaPattern,
273
+ getMessage: getKanaErrorMessage,
274
+ // Zod helpers
275
+ string: kanaString,
276
+ // Presets
277
+ presets: {
278
+ fullWidthKatakana: KATAKANA_FULL_WIDTH,
279
+ halfWidthKatakana: KATAKANA_HALF_WIDTH,
280
+ hiragana: HIRAGANA,
281
+ any: KANA_ANY,
282
+ withNumbers: KATAKANA_WITH_NUMBERS,
283
+ },
284
+ // Pattern constants for direct use
285
+ patterns: {
286
+ katakana: KATAKANA_PATTERN,
287
+ katakanaHalf: KATAKANA_HALF_PATTERN,
288
+ hiragana: HIRAGANA_PATTERN,
289
+ any: KANA_ANY_PATTERN,
290
+ },
291
+ };
@@ -0,0 +1,117 @@
1
+ /**
2
+ * useFormMutation - Form mutation with auto Laravel error handling
3
+ * Generated by Omnify. You can customize this file.
4
+ *
5
+ * @example
6
+ * const mutation = useFormMutation({
7
+ * form,
8
+ * mutationFn: (data) => axios.post('/api/customers', data),
9
+ * invalidateKeys: [['customers']],
10
+ * successMessage: '保存しました',
11
+ * });
12
+ *
13
+ * <Form form={form} onFinish={mutation.mutate}>
14
+ * ...
15
+ * <Button loading={mutation.isPending}>保存</Button>
16
+ * </Form>
17
+ */
18
+
19
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
20
+ import { App } from 'antd';
21
+ import type { FormInstance } from 'antd';
22
+
23
+ // =============================================================================
24
+ // Types
25
+ // =============================================================================
26
+
27
+ interface UseFormMutationOptions<TData, TResult> {
28
+ /** Ant Design form instance */
29
+ form: FormInstance;
30
+ /** API call function */
31
+ mutationFn: (data: TData) => Promise<TResult>;
32
+ /** Query keys to invalidate on success */
33
+ invalidateKeys?: readonly (readonly unknown[])[];
34
+ /** Success message to show */
35
+ successMessage?: string;
36
+ /** Callback on success */
37
+ onSuccess?: (data: TResult) => void;
38
+ /** Callback on error */
39
+ onError?: (error: unknown) => void;
40
+ }
41
+
42
+ // =============================================================================
43
+ // Laravel Error Helpers
44
+ // =============================================================================
45
+
46
+ /**
47
+ * Parse Laravel validation errors to Ant Design form format
48
+ */
49
+ function getFormErrors(error: unknown): { name: string; errors: string[] }[] {
50
+ const data = (error as any)?.response?.data;
51
+ const errors = data?.errors;
52
+
53
+ if (!errors || typeof errors !== 'object') return [];
54
+
55
+ return Object.entries(errors).map(([name, messages]) => ({
56
+ name,
57
+ errors: Array.isArray(messages) ? messages : [String(messages)],
58
+ }));
59
+ }
60
+
61
+ /**
62
+ * Get general validation message from Laravel response
63
+ */
64
+ function getValidationMessage(error: unknown): string | null {
65
+ const data = (error as any)?.response?.data;
66
+ return data?.message || null;
67
+ }
68
+
69
+ // =============================================================================
70
+ // Hook
71
+ // =============================================================================
72
+
73
+ export function useFormMutation<TData, TResult = unknown>({
74
+ form,
75
+ mutationFn,
76
+ invalidateKeys = [],
77
+ successMessage,
78
+ onSuccess,
79
+ onError,
80
+ }: UseFormMutationOptions<TData, TResult>) {
81
+ const queryClient = useQueryClient();
82
+ const { message } = App.useApp();
83
+
84
+ return useMutation({
85
+ mutationFn,
86
+ onSuccess: (data) => {
87
+ // Invalidate queries
88
+ invalidateKeys.forEach((key) => {
89
+ queryClient.invalidateQueries({ queryKey: [...key] });
90
+ });
91
+
92
+ // Show success message
93
+ if (successMessage) {
94
+ message.success(successMessage);
95
+ }
96
+
97
+ // Custom callback
98
+ onSuccess?.(data);
99
+ },
100
+ onError: (error) => {
101
+ // Set form field errors from Laravel validation
102
+ const formErrors = getFormErrors(error);
103
+ if (formErrors.length > 0) {
104
+ form.setFields(formErrors);
105
+ }
106
+
107
+ // Show general error message
108
+ const validationMessage = getValidationMessage(error);
109
+ if (validationMessage) {
110
+ message.error(validationMessage);
111
+ }
112
+
113
+ // Custom callback
114
+ onError?.(error);
115
+ },
116
+ });
117
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Zod i18n - Localization for Zod validation messages
3
+ * Generated by Omnify. You can customize this file.
4
+ */
5
+
6
+ import { getMessage, defaultLocale } from '../schemas/i18n.js';
7
+
8
+ let currentLocale: string = defaultLocale;
9
+
10
+ /**
11
+ * Set current locale for Zod validation messages
12
+ */
13
+ export function setZodLocale(locale: string) {
14
+ currentLocale = locale;
15
+ }
16
+
17
+ /**
18
+ * Get current locale
19
+ */
20
+ export function getZodLocale(): string {
21
+ return currentLocale;
22
+ }
23
+
24
+ /**
25
+ * Get translated validation message
26
+ */
27
+ export function getZodMessage(
28
+ key: string,
29
+ params?: Record<string, string | number>
30
+ ): string {
31
+ return getMessage(key, currentLocale, params);
32
+ }