@famgia/omnify-typescript 0.0.145 → 0.0.147
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-2Q2T4NRP.js → chunk-PA7B7ZFK.js} +30 -18
- package/dist/chunk-PA7B7ZFK.js.map +1 -0
- package/dist/index.cjs +30 -78
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +56 -40
- package/dist/index.d.ts +56 -40
- package/dist/index.js +2 -62
- package/dist/index.js.map +1 -1
- package/dist/plugin.cjs +61 -23
- package/dist/plugin.cjs.map +1 -1
- package/dist/plugin.js +33 -7
- package/dist/plugin.js.map +1 -1
- package/package.json +11 -11
- package/dist/chunk-2Q2T4NRP.js.map +0 -1
- package/stubs/JapaneseAddressField.tsx.stub +0 -289
- package/stubs/JapaneseBankField.tsx.stub +0 -212
- package/stubs/JapaneseNameField.tsx.stub +0 -194
- package/stubs/components-index.ts.stub +0 -13
- package/stubs/form-validation.ts.stub +0 -123
- package/stubs/rules/index.ts.stub +0 -51
- package/stubs/rules/kana.ts.stub +0 -294
- package/stubs/use-form-mutation.ts.stub +0 -119
- package/stubs/zod-i18n.ts.stub +0 -34
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { JapaneseNameField } from './JapaneseNameField';
|
|
2
|
-
import { JapaneseAddressField } from './JapaneseAddressField';
|
|
3
|
-
import { JapaneseBankField } from './JapaneseBankField';
|
|
4
|
-
|
|
5
|
-
// Namespace style exports (recommended)
|
|
6
|
-
export const OmnifyForm = {
|
|
7
|
-
JapaneseName: JapaneseNameField,
|
|
8
|
-
JapaneseAddress: JapaneseAddressField,
|
|
9
|
-
JapaneseBank: JapaneseBankField,
|
|
10
|
-
} as const;
|
|
11
|
-
|
|
12
|
-
// Legacy exports (backward compatible)
|
|
13
|
-
export { JapaneseNameField, JapaneseAddressField, JapaneseBankField };
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Form validation utilities for Ant Design + Zod
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ AUTO-GENERATED by Omnify - DO NOT EDIT
|
|
5
|
-
* This file is overwritten on every `npx omnify generate`
|
|
6
|
-
*
|
|
7
|
-
* Compatible with Zod v4.x
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { RuleObject } from 'antd/es/form';
|
|
11
|
-
import type { z } from 'zod';
|
|
12
|
-
import { getZodMessage } from './zod-i18n';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Convert Zod schema to Ant Design Form rule with i18n support
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // Set locale once at component level
|
|
19
|
-
* setZodLocale('ja');
|
|
20
|
-
*
|
|
21
|
-
* // Use without passing locale
|
|
22
|
-
* <Form.Item
|
|
23
|
-
* name="email"
|
|
24
|
-
* rules={[zodRule(customerSchemas.email, 'メールアドレス')]}
|
|
25
|
-
* >
|
|
26
|
-
* <Input />
|
|
27
|
-
* </Form.Item>
|
|
28
|
-
*/
|
|
29
|
-
export function zodRule<T extends z.ZodTypeAny>(
|
|
30
|
-
schema: T,
|
|
31
|
-
displayName?: string
|
|
32
|
-
): RuleObject {
|
|
33
|
-
const field = displayName ?? 'この項目';
|
|
34
|
-
|
|
35
|
-
return {
|
|
36
|
-
validator: async (_, value) => {
|
|
37
|
-
// 空チェック - 必須として扱う
|
|
38
|
-
if (value === undefined || value === null || value === '') {
|
|
39
|
-
if (schema.safeParse(undefined).success) return;
|
|
40
|
-
throw new Error(getZodMessage('required', { displayName: field }));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const result = schema.safeParse(value);
|
|
44
|
-
if (result.success) return;
|
|
45
|
-
|
|
46
|
-
// 最初のZodエラーを取得
|
|
47
|
-
const issue = result.error.issues[0];
|
|
48
|
-
if (!issue) {
|
|
49
|
-
throw new Error(getZodMessage('required', { displayName: field }));
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// エラータイプに基づいて翻訳(Zod v4対応)
|
|
53
|
-
const issueAny = issue as unknown as Record<string, unknown>;
|
|
54
|
-
switch (issue.code) {
|
|
55
|
-
case 'too_small': {
|
|
56
|
-
const origin = issueAny.origin as string | undefined;
|
|
57
|
-
const minimum = issueAny.minimum as number;
|
|
58
|
-
if (origin === 'string' && minimum === 1) {
|
|
59
|
-
throw new Error(getZodMessage('required', { displayName: field }));
|
|
60
|
-
}
|
|
61
|
-
if (origin === 'string') {
|
|
62
|
-
throw new Error(getZodMessage('minLength', { displayName: field, min: minimum }));
|
|
63
|
-
}
|
|
64
|
-
throw new Error(getZodMessage('min', { displayName: field, min: minimum }));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
case 'too_big': {
|
|
68
|
-
const origin = issueAny.origin as string | undefined;
|
|
69
|
-
const maximum = issueAny.maximum as number;
|
|
70
|
-
if (origin === 'string') {
|
|
71
|
-
throw new Error(getZodMessage('maxLength', { displayName: field, max: maximum }));
|
|
72
|
-
}
|
|
73
|
-
throw new Error(getZodMessage('max', { displayName: field, max: maximum }));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Zod v4: 'invalid_string' → 'invalid_format'
|
|
77
|
-
case 'invalid_format': {
|
|
78
|
-
const format = issueAny.format as string | undefined;
|
|
79
|
-
if (format === 'email') {
|
|
80
|
-
throw new Error(getZodMessage('email', { displayName: field }));
|
|
81
|
-
}
|
|
82
|
-
if (format === 'url') {
|
|
83
|
-
throw new Error(getZodMessage('url', { displayName: field }));
|
|
84
|
-
}
|
|
85
|
-
if (format === 'regex') {
|
|
86
|
-
throw new Error(getZodMessage('pattern', { displayName: field }));
|
|
87
|
-
}
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
case 'invalid_type': {
|
|
92
|
-
const expected = issueAny.expected as string | undefined;
|
|
93
|
-
// Zod v4: チェックはexpectedフィールドを使用
|
|
94
|
-
if (expected && value === undefined) {
|
|
95
|
-
throw new Error(getZodMessage('required', { displayName: field }));
|
|
96
|
-
}
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// フォールバック: Zodのオリジナルメッセージを使用
|
|
102
|
-
throw new Error(issue.message);
|
|
103
|
-
},
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Create required rule with i18n message
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* <Form.Item
|
|
112
|
-
* name="name"
|
|
113
|
-
* rules={[requiredRule('名前')]}
|
|
114
|
-
* >
|
|
115
|
-
* <Input />
|
|
116
|
-
* </Form.Item>
|
|
117
|
-
*/
|
|
118
|
-
export function requiredRule(displayName: string): RuleObject {
|
|
119
|
-
return {
|
|
120
|
-
required: true,
|
|
121
|
-
message: getZodMessage('required', { displayName }),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Japanese validation rules
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ AUTO-GENERATED by Omnify - DO NOT EDIT
|
|
5
|
-
* This file is overwritten on every `npx omnify generate`
|
|
6
|
-
*
|
|
7
|
-
* Usage with Zod:
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { z } from 'zod';
|
|
10
|
-
* import { kanaString, KATAKANA_PATTERN } from '@/omnify/lib/rules';
|
|
11
|
-
*
|
|
12
|
-
* // Method 1: Use kanaString helper
|
|
13
|
-
* const schema = z.object({
|
|
14
|
-
* name_kana: kanaString(), // 全角カタカナ (default)
|
|
15
|
-
* });
|
|
16
|
-
*
|
|
17
|
-
* // Method 2: Use pattern directly
|
|
18
|
-
* const schema2 = z.object({
|
|
19
|
-
* name_kana: z.string().regex(KATAKANA_PATTERN, '全角カタカナで入力してください'),
|
|
20
|
-
* });
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
export {
|
|
25
|
-
// Kana validation
|
|
26
|
-
kanaRules,
|
|
27
|
-
createKanaRegex,
|
|
28
|
-
validateKana,
|
|
29
|
-
getKanaPattern,
|
|
30
|
-
getKanaErrorMessage,
|
|
31
|
-
// Zod helpers
|
|
32
|
-
kanaString,
|
|
33
|
-
withKana,
|
|
34
|
-
// Pattern constants
|
|
35
|
-
KATAKANA_PATTERN,
|
|
36
|
-
KATAKANA_HALF_PATTERN,
|
|
37
|
-
HIRAGANA_PATTERN,
|
|
38
|
-
KANA_ANY_PATTERN,
|
|
39
|
-
// Presets
|
|
40
|
-
KATAKANA_FULL_WIDTH,
|
|
41
|
-
KATAKANA_HALF_WIDTH,
|
|
42
|
-
HIRAGANA,
|
|
43
|
-
KANA_ANY,
|
|
44
|
-
KATAKANA_WITH_NUMBERS,
|
|
45
|
-
// Types
|
|
46
|
-
type KanaRuleOptions,
|
|
47
|
-
} from './kana';
|
|
48
|
-
|
|
49
|
-
// Re-export as convenient aliases
|
|
50
|
-
export { getKanaPattern as kanaPattern } from './kana';
|
|
51
|
-
export { createKanaRegex as kanaRegex } from './kana';
|
package/stubs/rules/kana.ts.stub
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Japanese Kana Validation Rules
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ AUTO-GENERATED by Omnify - DO NOT EDIT
|
|
5
|
-
* This file is overwritten on every `npx omnify generate`
|
|
6
|
-
*
|
|
7
|
-
* Provides configurable validation for Japanese character input:
|
|
8
|
-
* - 全角カタカナ (Full-width Katakana) - default
|
|
9
|
-
* - 半角カタカナ (Half-width Katakana)
|
|
10
|
-
* - ひらがな (Hiragana)
|
|
11
|
-
* - Mixed modes
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export interface KanaRuleOptions {
|
|
15
|
-
/** Allow full-width katakana (ア-ン) - default: true */
|
|
16
|
-
fullWidthKatakana?: boolean;
|
|
17
|
-
/** Allow half-width katakana (ア-ン) - default: false */
|
|
18
|
-
halfWidthKatakana?: boolean;
|
|
19
|
-
/** Allow hiragana (あ-ん) - default: false */
|
|
20
|
-
hiragana?: boolean;
|
|
21
|
-
/** Allow numbers (0-9, 0-9) - default: false */
|
|
22
|
-
allowNumbers?: boolean;
|
|
23
|
-
/** Allow full-width numbers (0-9) - default: false */
|
|
24
|
-
fullWidthNumbers?: boolean;
|
|
25
|
-
/** Allow half-width numbers (0-9) - default: false */
|
|
26
|
-
halfWidthNumbers?: boolean;
|
|
27
|
-
/** Allow spaces (full-width and half-width) - default: true */
|
|
28
|
-
allowSpaces?: boolean;
|
|
29
|
-
/** Allow specific special characters - default: ['ー', '・'] */
|
|
30
|
-
allowSpecialChars?: string[];
|
|
31
|
-
/** Custom error message */
|
|
32
|
-
message?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Character ranges
|
|
36
|
-
const CHAR_RANGES = {
|
|
37
|
-
// Full-width Katakana: ァ-ヶ (U+30A1-U+30F6) + ー (U+30FC)
|
|
38
|
-
fullWidthKatakana: 'ァ-ヶー',
|
|
39
|
-
// Half-width Katakana: ヲ-゚ (U+FF66-U+FF9F)
|
|
40
|
-
halfWidthKatakana: 'ヲ-゚',
|
|
41
|
-
// Hiragana: ぁ-ゖ (U+3041-U+3096)
|
|
42
|
-
hiragana: 'ぁ-ゖ',
|
|
43
|
-
// Full-width numbers: 0-9
|
|
44
|
-
fullWidthNumbers: '0-9',
|
|
45
|
-
// Half-width numbers: 0-9
|
|
46
|
-
halfWidthNumbers: '0-9',
|
|
47
|
-
// Full-width space: (U+3000)
|
|
48
|
-
fullWidthSpace: ' ',
|
|
49
|
-
// Half-width space
|
|
50
|
-
halfWidthSpace: ' ',
|
|
51
|
-
// Common special chars for names
|
|
52
|
-
defaultSpecialChars: ['ー', '・'],
|
|
53
|
-
} as const;
|
|
54
|
-
|
|
55
|
-
// Default options: 全角カタカナ + spaces + ー・
|
|
56
|
-
const DEFAULT_OPTIONS: Required<KanaRuleOptions> = {
|
|
57
|
-
fullWidthKatakana: true,
|
|
58
|
-
halfWidthKatakana: false,
|
|
59
|
-
hiragana: false,
|
|
60
|
-
allowNumbers: false,
|
|
61
|
-
fullWidthNumbers: false,
|
|
62
|
-
halfWidthNumbers: false,
|
|
63
|
-
allowSpaces: true,
|
|
64
|
-
allowSpecialChars: ['ー', '・'],
|
|
65
|
-
message: '',
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Build regex pattern from options
|
|
70
|
-
*/
|
|
71
|
-
function buildKanaPattern(options: KanaRuleOptions = {}): string {
|
|
72
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
73
|
-
const parts: string[] = [];
|
|
74
|
-
|
|
75
|
-
if (opts.fullWidthKatakana) {
|
|
76
|
-
parts.push(CHAR_RANGES.fullWidthKatakana);
|
|
77
|
-
}
|
|
78
|
-
if (opts.halfWidthKatakana) {
|
|
79
|
-
parts.push(CHAR_RANGES.halfWidthKatakana);
|
|
80
|
-
}
|
|
81
|
-
if (opts.hiragana) {
|
|
82
|
-
parts.push(CHAR_RANGES.hiragana);
|
|
83
|
-
}
|
|
84
|
-
if (opts.allowNumbers || opts.fullWidthNumbers) {
|
|
85
|
-
parts.push(CHAR_RANGES.fullWidthNumbers);
|
|
86
|
-
}
|
|
87
|
-
if (opts.allowNumbers || opts.halfWidthNumbers) {
|
|
88
|
-
parts.push(CHAR_RANGES.halfWidthNumbers);
|
|
89
|
-
}
|
|
90
|
-
if (opts.allowSpaces) {
|
|
91
|
-
parts.push(CHAR_RANGES.fullWidthSpace);
|
|
92
|
-
parts.push(CHAR_RANGES.halfWidthSpace);
|
|
93
|
-
}
|
|
94
|
-
if (opts.allowSpecialChars && opts.allowSpecialChars.length > 0) {
|
|
95
|
-
// Escape special regex chars
|
|
96
|
-
const escaped = opts.allowSpecialChars.map(c =>
|
|
97
|
-
c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
98
|
-
).join('');
|
|
99
|
-
parts.push(escaped);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return `^[${parts.join('')}]*$`;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get default error message based on options
|
|
107
|
-
*/
|
|
108
|
-
function getDefaultMessage(options: KanaRuleOptions = {}, locale: string = 'ja'): string {
|
|
109
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
110
|
-
|
|
111
|
-
const messages: Record<string, Record<string, string>> = {
|
|
112
|
-
ja: {
|
|
113
|
-
fullWidthKatakana: '全角カタカナ',
|
|
114
|
-
halfWidthKatakana: '半角カタカナ',
|
|
115
|
-
hiragana: 'ひらがな',
|
|
116
|
-
mixed: 'カナ文字',
|
|
117
|
-
},
|
|
118
|
-
en: {
|
|
119
|
-
fullWidthKatakana: 'full-width katakana',
|
|
120
|
-
halfWidthKatakana: 'half-width katakana',
|
|
121
|
-
hiragana: 'hiragana',
|
|
122
|
-
mixed: 'kana characters',
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const msg = messages[locale] ?? messages['ja'];
|
|
127
|
-
|
|
128
|
-
// Determine what type to show in message
|
|
129
|
-
let type = msg.mixed;
|
|
130
|
-
if (opts.fullWidthKatakana && !opts.halfWidthKatakana && !opts.hiragana) {
|
|
131
|
-
type = msg.fullWidthKatakana;
|
|
132
|
-
} else if (opts.halfWidthKatakana && !opts.fullWidthKatakana && !opts.hiragana) {
|
|
133
|
-
type = msg.halfWidthKatakana;
|
|
134
|
-
} else if (opts.hiragana && !opts.fullWidthKatakana && !opts.halfWidthKatakana) {
|
|
135
|
-
type = msg.hiragana;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (locale === 'ja') {
|
|
139
|
-
return `${type}で入力してください`;
|
|
140
|
-
}
|
|
141
|
-
return `Please enter in ${type}`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Create a kana validation regex
|
|
146
|
-
*/
|
|
147
|
-
export function createKanaRegex(options: KanaRuleOptions = {}): RegExp {
|
|
148
|
-
return new RegExp(buildKanaPattern(options));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Validate a string against kana rules
|
|
153
|
-
*/
|
|
154
|
-
export function validateKana(value: string, options: KanaRuleOptions = {}): boolean {
|
|
155
|
-
if (!value) return true; // Empty is valid (use required for that)
|
|
156
|
-
const regex = createKanaRegex(options);
|
|
157
|
-
return regex.test(value);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get kana validation pattern string (for Zod .regex())
|
|
162
|
-
*/
|
|
163
|
-
export function getKanaPattern(options: KanaRuleOptions = {}): string {
|
|
164
|
-
return buildKanaPattern(options);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Get error message for kana validation
|
|
169
|
-
*/
|
|
170
|
-
export function getKanaErrorMessage(options: KanaRuleOptions = {}, locale: string = 'ja'): string {
|
|
171
|
-
return options.message ?? getDefaultMessage(options, locale);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ============================================================================
|
|
175
|
-
// Preset configurations
|
|
176
|
-
// ============================================================================
|
|
177
|
-
|
|
178
|
-
/** 全角カタカナ (Full-width Katakana) - Default for Japanese names */
|
|
179
|
-
export const KATAKANA_FULL_WIDTH: KanaRuleOptions = {
|
|
180
|
-
fullWidthKatakana: true,
|
|
181
|
-
halfWidthKatakana: false,
|
|
182
|
-
hiragana: false,
|
|
183
|
-
allowSpaces: true,
|
|
184
|
-
allowSpecialChars: ['ー', '・'],
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
/** 半角カタカナ (Half-width Katakana) - Legacy systems */
|
|
188
|
-
export const KATAKANA_HALF_WIDTH: KanaRuleOptions = {
|
|
189
|
-
fullWidthKatakana: false,
|
|
190
|
-
halfWidthKatakana: true,
|
|
191
|
-
hiragana: false,
|
|
192
|
-
allowSpaces: true,
|
|
193
|
-
allowSpecialChars: ['ー'], // Half-width prolonged sound mark
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
/** ひらがな (Hiragana) */
|
|
197
|
-
export const HIRAGANA: KanaRuleOptions = {
|
|
198
|
-
fullWidthKatakana: false,
|
|
199
|
-
halfWidthKatakana: false,
|
|
200
|
-
hiragana: true,
|
|
201
|
-
allowSpaces: true,
|
|
202
|
-
allowSpecialChars: ['ー'],
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
/** カタカナ + ひらがな (Any kana) */
|
|
206
|
-
export const KANA_ANY: KanaRuleOptions = {
|
|
207
|
-
fullWidthKatakana: true,
|
|
208
|
-
halfWidthKatakana: true,
|
|
209
|
-
hiragana: true,
|
|
210
|
-
allowSpaces: true,
|
|
211
|
-
allowSpecialChars: ['ー', '・', 'ー'],
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
/** 全角カタカナ + 数字 (Full-width katakana with numbers) */
|
|
215
|
-
export const KATAKANA_WITH_NUMBERS: KanaRuleOptions = {
|
|
216
|
-
fullWidthKatakana: true,
|
|
217
|
-
halfWidthKatakana: false,
|
|
218
|
-
hiragana: false,
|
|
219
|
-
allowNumbers: true,
|
|
220
|
-
allowSpaces: true,
|
|
221
|
-
allowSpecialChars: ['ー', '・'],
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// ============================================================================
|
|
225
|
-
// Pattern strings for Zod .regex()
|
|
226
|
-
// ============================================================================
|
|
227
|
-
|
|
228
|
-
/** Pattern: 全角カタカナ + スペース + ー・ (for z.string().regex()) */
|
|
229
|
-
export const KATAKANA_PATTERN = /^[ァ-ヶー・ ]*$/;
|
|
230
|
-
|
|
231
|
-
/** Pattern: 半角カタカナ (for z.string().regex()) */
|
|
232
|
-
export const KATAKANA_HALF_PATTERN = /^[ヲ-゚ー ]*$/;
|
|
233
|
-
|
|
234
|
-
/** Pattern: ひらがな (for z.string().regex()) */
|
|
235
|
-
export const HIRAGANA_PATTERN = /^[ぁ-ゖー ]*$/;
|
|
236
|
-
|
|
237
|
-
/** Pattern: すべてのかな (for z.string().regex()) */
|
|
238
|
-
export const KANA_ANY_PATTERN = /^[ァ-ヶぁ-ゖヲ-゚ー・ー ]*$/;
|
|
239
|
-
|
|
240
|
-
// ============================================================================
|
|
241
|
-
// Zod refinement helpers
|
|
242
|
-
// ============================================================================
|
|
243
|
-
|
|
244
|
-
import { z } from 'zod';
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Create Zod string schema with kana validation
|
|
248
|
-
* @example
|
|
249
|
-
* const schema = z.object({
|
|
250
|
-
* name_kana: kanaString(), // 全角カタカナ (default)
|
|
251
|
-
* name_kana2: kanaString({ hiragana: true }), // カタカナ + ひらがな
|
|
252
|
-
* });
|
|
253
|
-
*/
|
|
254
|
-
export function kanaString(options: KanaRuleOptions = {}) {
|
|
255
|
-
const opts = { ...KATAKANA_FULL_WIDTH, ...options };
|
|
256
|
-
const regex = createKanaRegex(opts);
|
|
257
|
-
const message = getKanaErrorMessage(opts);
|
|
258
|
-
|
|
259
|
-
return z.string().regex(regex, { message });
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Add kana validation to existing Zod string schema
|
|
264
|
-
* @example
|
|
265
|
-
* const schema = z.string().min(1).pipe(withKana());
|
|
266
|
-
*/
|
|
267
|
-
export function withKana(options: KanaRuleOptions = {}) {
|
|
268
|
-
return kanaString(options);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Default export
|
|
272
|
-
export const kanaRules = {
|
|
273
|
-
createRegex: createKanaRegex,
|
|
274
|
-
validate: validateKana,
|
|
275
|
-
getPattern: getKanaPattern,
|
|
276
|
-
getMessage: getKanaErrorMessage,
|
|
277
|
-
// Zod helpers
|
|
278
|
-
string: kanaString,
|
|
279
|
-
// Presets
|
|
280
|
-
presets: {
|
|
281
|
-
fullWidthKatakana: KATAKANA_FULL_WIDTH,
|
|
282
|
-
halfWidthKatakana: KATAKANA_HALF_WIDTH,
|
|
283
|
-
hiragana: HIRAGANA,
|
|
284
|
-
any: KANA_ANY,
|
|
285
|
-
withNumbers: KATAKANA_WITH_NUMBERS,
|
|
286
|
-
},
|
|
287
|
-
// Pattern constants for direct use
|
|
288
|
-
patterns: {
|
|
289
|
-
katakana: KATAKANA_PATTERN,
|
|
290
|
-
katakanaHalf: KATAKANA_HALF_PATTERN,
|
|
291
|
-
hiragana: HIRAGANA_PATTERN,
|
|
292
|
-
any: KANA_ANY_PATTERN,
|
|
293
|
-
},
|
|
294
|
-
};
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* useFormMutation - Form mutation with auto Laravel error handling
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ AUTO-GENERATED by Omnify - DO NOT EDIT
|
|
5
|
-
* This file is overwritten on every `npx omnify generate`
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* const mutation = useFormMutation({
|
|
9
|
-
* form,
|
|
10
|
-
* mutationFn: (data) => axios.post('/api/customers', data),
|
|
11
|
-
* invalidateKeys: [['customers']],
|
|
12
|
-
* successMessage: '保存しました',
|
|
13
|
-
* });
|
|
14
|
-
*
|
|
15
|
-
* <Form form={form} onFinish={mutation.mutate}>
|
|
16
|
-
* ...
|
|
17
|
-
* <Button loading={mutation.isPending}>保存</Button>
|
|
18
|
-
* </Form>
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
22
|
-
import { App } from 'antd';
|
|
23
|
-
import type { FormInstance } from 'antd';
|
|
24
|
-
|
|
25
|
-
// =============================================================================
|
|
26
|
-
// Types
|
|
27
|
-
// =============================================================================
|
|
28
|
-
|
|
29
|
-
interface UseFormMutationOptions<TData, TResult> {
|
|
30
|
-
/** Ant Design form instance */
|
|
31
|
-
form: FormInstance;
|
|
32
|
-
/** API call function */
|
|
33
|
-
mutationFn: (data: TData) => Promise<TResult>;
|
|
34
|
-
/** Query keys to invalidate on success */
|
|
35
|
-
invalidateKeys?: readonly (readonly unknown[])[];
|
|
36
|
-
/** Success message to show */
|
|
37
|
-
successMessage?: string;
|
|
38
|
-
/** Callback on success */
|
|
39
|
-
onSuccess?: (data: TResult) => void;
|
|
40
|
-
/** Callback on error */
|
|
41
|
-
onError?: (error: unknown) => void;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// =============================================================================
|
|
45
|
-
// Laravel Error Helpers
|
|
46
|
-
// =============================================================================
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Parse Laravel validation errors to Ant Design form format
|
|
50
|
-
*/
|
|
51
|
-
function getFormErrors(error: unknown): { name: string; errors: string[] }[] {
|
|
52
|
-
const data = (error as any)?.response?.data;
|
|
53
|
-
const errors = data?.errors;
|
|
54
|
-
|
|
55
|
-
if (!errors || typeof errors !== 'object') return [];
|
|
56
|
-
|
|
57
|
-
return Object.entries(errors).map(([name, messages]) => ({
|
|
58
|
-
name,
|
|
59
|
-
errors: Array.isArray(messages) ? messages : [String(messages)],
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Get general validation message from Laravel response
|
|
65
|
-
*/
|
|
66
|
-
function getValidationMessage(error: unknown): string | null {
|
|
67
|
-
const data = (error as any)?.response?.data;
|
|
68
|
-
return data?.message || null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// =============================================================================
|
|
72
|
-
// Hook
|
|
73
|
-
// =============================================================================
|
|
74
|
-
|
|
75
|
-
export function useFormMutation<TData, TResult = unknown>({
|
|
76
|
-
form,
|
|
77
|
-
mutationFn,
|
|
78
|
-
invalidateKeys = [],
|
|
79
|
-
successMessage,
|
|
80
|
-
onSuccess,
|
|
81
|
-
onError,
|
|
82
|
-
}: UseFormMutationOptions<TData, TResult>) {
|
|
83
|
-
const queryClient = useQueryClient();
|
|
84
|
-
const { message } = App.useApp();
|
|
85
|
-
|
|
86
|
-
return useMutation({
|
|
87
|
-
mutationFn,
|
|
88
|
-
onSuccess: (data) => {
|
|
89
|
-
// Invalidate queries
|
|
90
|
-
invalidateKeys.forEach((key) => {
|
|
91
|
-
queryClient.invalidateQueries({ queryKey: [...key] });
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// Show success message
|
|
95
|
-
if (successMessage) {
|
|
96
|
-
message.success(successMessage);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Custom callback
|
|
100
|
-
onSuccess?.(data);
|
|
101
|
-
},
|
|
102
|
-
onError: (error) => {
|
|
103
|
-
// Set form field errors from Laravel validation
|
|
104
|
-
const formErrors = getFormErrors(error);
|
|
105
|
-
if (formErrors.length > 0) {
|
|
106
|
-
form.setFields(formErrors);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Show general error message
|
|
110
|
-
const validationMessage = getValidationMessage(error);
|
|
111
|
-
if (validationMessage) {
|
|
112
|
-
message.error(validationMessage);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Custom callback
|
|
116
|
-
onError?.(error);
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
}
|
package/stubs/zod-i18n.ts.stub
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Zod i18n - Localization for Zod validation messages
|
|
3
|
-
*
|
|
4
|
-
* ⚠️ AUTO-GENERATED by Omnify - DO NOT EDIT
|
|
5
|
-
* This file is overwritten on every `npx omnify generate`
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { getMessage, defaultLocale } from '../schemas/i18n';
|
|
9
|
-
|
|
10
|
-
let currentLocale: string = defaultLocale;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Set current locale for Zod validation messages
|
|
14
|
-
*/
|
|
15
|
-
export function setZodLocale(locale: string) {
|
|
16
|
-
currentLocale = locale;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Get current locale
|
|
21
|
-
*/
|
|
22
|
-
export function getZodLocale(): string {
|
|
23
|
-
return currentLocale;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get translated validation message
|
|
28
|
-
*/
|
|
29
|
-
export function getZodMessage(
|
|
30
|
-
key: string,
|
|
31
|
-
params?: Record<string, string | number>
|
|
32
|
-
): string {
|
|
33
|
-
return getMessage(key, currentLocale, params);
|
|
34
|
-
}
|