@code-plate/iran-cities 1.0.0

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 ADDED
@@ -0,0 +1,257 @@
1
+ # @code-plate/iran-cities
2
+
3
+ لیست کامل و آماده‌ی **استان‌ها و شهرهای ایران** (فارسی + انگلیسی)، بسته‌بندی‌شده به شکل یک کتابخانه‌ی سبک، بدون هیچ وابستگی اجباری، که در **هر پروژه‌ی جاوااسکریپتی/تایپ‌اسکریپتی** قابل استفاده است:
4
+
5
+ - ✅ React / Next.js (App Router و Pages Router)
6
+ - ✅ Vue 2 / Vue 3
7
+ - ✅ Angular
8
+ - ✅ Svelte
9
+ - ✅ Node.js / Express (بک‌اند خالص)
10
+ - ✅ Vanilla JS (مرورگر یا هر باندلر دیگر)
11
+
12
+ هسته‌ی اصلی پکیج **هیچ وابستگی‌ای** ندارد (zero-dependency) و هم به‌صورت **CJS** و هم **ESM** ارائه می‌شود. یک ساب‌پس اختیاری (`@code-plate/iran-cities/react`) هم برای کسانی که در React کار می‌کنند وجود دارد که چند هوک آماده می‌دهد؛ اگر پروژه‌تان React نیست، هرگز این فایل import نمی‌شود و React اصلاً لازم نیست نصب شود.
13
+
14
+ ## نصب
15
+
16
+ ```bash
17
+ npm install @code-plate/iran-cities
18
+ # یا
19
+ yarn add @code-plate/iran-cities
20
+ # یا
21
+ pnpm add @code-plate/iran-cities
22
+ ```
23
+
24
+ ## داده‌ها
25
+
26
+ - `۳۱` استان
27
+ - `۱۲۵۳` شهر
28
+ - هر رکورد شامل `en` (شناسه لاتین kebab-case، مثل `tehran`) و `fa` (نام فارسی، مثل `تهران`) است.
29
+
30
+ ---
31
+
32
+ ## استفاده در جاوااسکریپت / تایپ‌اسکریپت خالص (و Node.js/Express)
33
+
34
+ ```ts
35
+ import {
36
+ getProvinces,
37
+ getProvincesList,
38
+ getProvince,
39
+ getCities,
40
+ getCity,
41
+ getAllCities,
42
+ getProvinceOfCity,
43
+ searchProvinces,
44
+ searchCities,
45
+ getStats,
46
+ } from '@code-plate/iran-cities';
47
+
48
+ // همه‌ی استان‌ها به همراه شهرهایشان
49
+ getProvinces();
50
+ // [{ en: 'alborz', fa: 'البرز', cities: [{ en: 'karaj', fa: 'کرج' }, ...] }, ...]
51
+
52
+ // فقط لیست استان‌ها (بدون شهر) - برای Select/Dropdown
53
+ getProvincesList();
54
+ // [{ en: 'alborz', fa: 'البرز' }, { en: 'ardabil', fa: 'اردبیل' }, ...]
55
+
56
+ // گرفتن یک استان با نام انگلیسی یا فارسی
57
+ getProvince('tehran');
58
+ getProvince('تهران'); // همین نتیجه را می‌دهد
59
+
60
+ // شهرهای یک استان خاص
61
+ getCities('fars'); // بر اساس شناسه انگلیسی
62
+ getCities('فارس'); // یا بر اساس نام فارسی، هر دو یکسان کار می‌کنند
63
+
64
+ // پیدا کردن یک شهر مشخص (در کل کشور یا محدود به یک استان)
65
+ getCity('shiraz');
66
+ getCity('شیراز', 'fars'); // محدود به استان فارس
67
+
68
+ // لیست مسطح (flat) همه‌ی شهرهای کشور همراه با استان مربوطه
69
+ getAllCities();
70
+ // [{ en: 'karaj', fa: 'کرج', provinceEn: 'alborz', provinceFa: 'البرز' }, ...]
71
+
72
+ // پیدا کردن استانِ یک شهر
73
+ getProvinceOfCity('اصفهان'); // => { en: 'isfahan', fa: 'اصفهان', cities: [...] }
74
+
75
+ // جستجوی زنده (autocomplete) در استان‌ها یا شهرها
76
+ searchProvinces('خراسان'); // هر سه استان خراسان را برمی‌گرداند
77
+ searchCities('شهر', { limit: 10 }); // ۱۰ نتیجه‌ی اول شامل «شهر»
78
+ searchCities('mashhad', { locale: 'en' }); // جستجو فقط در نام انگلیسی
79
+
80
+ // آمار کلی
81
+ getStats(); // { provinceCount: 31, cityCount: 1253 }
82
+ ```
83
+
84
+ ### نکته‌ی مهم درباره‌ی جستجو
85
+ تابع‌های `getProvince`, `getCities`, `getCity` و `getProvinceOfCity` به‌صورت **نرمال‌شده** مقایسه می‌کنند؛ یعنی تفاوت «ی» فارسی/«ي» عربی، «ک»/«ك»، نیم‌فاصله، فاصله و خط‌تیره را نادیده می‌گیرند. پس `getCity('كرج')` و `getCity('کرج')` هر دو کار می‌کنند.
86
+
87
+ ---
88
+
89
+ ## استفاده در Node.js / Express (بک‌اند)
90
+
91
+ ```js
92
+ const express = require('express');
93
+ const { getProvincesList, getCities, searchCities } = require('@code-plate/iran-cities');
94
+
95
+ const app = express();
96
+
97
+ app.get('/api/provinces', (req, res) => {
98
+ res.json(getProvincesList());
99
+ });
100
+
101
+ app.get('/api/cities/:province', (req, res) => {
102
+ res.json(getCities(req.params.province));
103
+ });
104
+
105
+ app.get('/api/cities/search', (req, res) => {
106
+ res.json(searchCities(req.query.q ?? '', { limit: 20 }));
107
+ });
108
+ ```
109
+
110
+ ---
111
+
112
+ ## استفاده در React / Next.js
113
+
114
+ برای React یک ساب‌پس اختیاری وجود دارد که چند هوک آماده ارائه می‌دهد:
115
+
116
+ ```tsx
117
+ import { useProvinces, useCities, useProvinceCitySelect, useCitySearch } from '@code-plate/iran-cities/react';
118
+
119
+ function AddressForm() {
120
+ const { provinces, cities, province, setProvince, city, setCity } = useProvinceCitySelect();
121
+
122
+ return (
123
+ <>
124
+ <select value={province} onChange={(e) => setProvince(e.target.value)}>
125
+ <option value="">انتخاب استان</option>
126
+ {provinces.map((p) => (
127
+ <option key={p.en} value={p.en}>{p.fa}</option>
128
+ ))}
129
+ </select>
130
+
131
+ <select value={city} onChange={(e) => setCity(e.target.value)} disabled={!province}>
132
+ <option value="">انتخاب شهر</option>
133
+ {cities.map((c) => (
134
+ <option key={c.en} value={c.en}>{c.fa}</option>
135
+ ))}
136
+ </select>
137
+ </>
138
+ );
139
+ }
140
+ ```
141
+
142
+ جستجوی زنده‌ی شهر (autocomplete):
143
+
144
+ ```tsx
145
+ import { useCitySearch } from '@code-plate/iran-cities/react';
146
+
147
+ function CityAutocomplete() {
148
+ const { query, setQuery, results } = useCitySearch('', { limit: 8 });
149
+
150
+ return (
151
+ <div>
152
+ <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="نام شهر..." />
153
+ <ul>
154
+ {results.map((c) => (
155
+ <li key={`${c.provinceEn}-${c.en}`}>{c.fa} ({c.provinceFa})</li>
156
+ ))}
157
+ </ul>
158
+ </div>
159
+ );
160
+ }
161
+ ```
162
+
163
+ هوک‌های در دسترس در ساب‌پس `react`:
164
+
165
+ | هوک | کاربرد |
166
+ |---|---|
167
+ | `useProvinces()` | لیست استان‌ها |
168
+ | `useCities(provinceQuery)` | شهرهای یک استان، وابسته به تغییر پارامتر |
169
+ | `useProvinceCitySelect()` | state کامل یک فرم استان→شهر (با ریست خودکار شهر هنگام تغییر استان) |
170
+ | `useCitySearch(initialQuery?, options?)` | state جستجوی زنده‌ی شهر |
171
+ | `useProvinceSearch(initialQuery?, options?)` | state جستجوی زنده‌ی استان |
172
+
173
+ > اگر پروژه‌تان Vue، Angular یا هر چیز دیگری است، فقط از مسیر اصلی (`@code-plate/iran-cities`) استفاده کنید و توابع خام (`getProvinces`, `getCities`, ...) را داخل computed/signal/observable خودتان قرار دهید — نیازی به هیچ ابزار اضافه‌ای نیست.
174
+
175
+ ---
176
+
177
+ ## استفاده در Vue 3 (نمونه)
178
+
179
+ ```vue
180
+ <script setup>
181
+ import { ref, computed } from 'vue';
182
+ import { getProvincesList, getCities } from '@code-plate/iran-cities';
183
+
184
+ const provinces = getProvincesList();
185
+ const selectedProvince = ref('');
186
+ const cities = computed(() => getCities(selectedProvince.value));
187
+ </script>
188
+
189
+ <template>
190
+ <select v-model="selectedProvince">
191
+ <option v-for="p in provinces" :key="p.en" :value="p.en">{{ p.fa }}</option>
192
+ </select>
193
+ <select :disabled="!selectedProvince">
194
+ <option v-for="c in cities" :key="c.en" :value="c.en">{{ c.fa }}</option>
195
+ </select>
196
+ </template>
197
+ ```
198
+
199
+ ## استفاده در Angular (نمونه سرویس)
200
+
201
+ ```ts
202
+ import { Injectable } from '@angular/core';
203
+ import { getProvincesList, getCities, type City } from '@code-plate/iran-cities';
204
+
205
+ @Injectable({ providedIn: 'root' })
206
+ export class IranLocationsService {
207
+ getProvinces() {
208
+ return getProvincesList();
209
+ }
210
+ getCitiesOf(provinceEn: string): City[] {
211
+ return getCities(provinceEn);
212
+ }
213
+ }
214
+ ```
215
+
216
+ ---
217
+
218
+ ## API کامل
219
+
220
+ ### توابع اصلی (import از `'@code-plate/iran-cities'`)
221
+
222
+ | تابع | ورودی | خروجی | توضیح |
223
+ |---|---|---|---|
224
+ | `getProvinces()` | - | `Province[]` | همه‌ی استان‌ها به همراه شهرها |
225
+ | `getProvincesList()` | - | `{en, fa}[]` | فقط لیست استان‌ها |
226
+ | `getProvince(query)` | `string` | `Province \| undefined` | یک استان با en یا fa |
227
+ | `getCities(provinceQuery)` | `string` | `City[]` | شهرهای یک استان |
228
+ | `getCity(cityQuery, provinceQuery?)` | `string, string?` | `FlatCity \| undefined` | یک شهر مشخص |
229
+ | `getAllCities()` | - | `FlatCity[]` | همه‌ی شهرها به‌صورت مسطح |
230
+ | `getProvinceOfCity(cityQuery)` | `string` | `Province \| undefined` | استانِ یک شهر |
231
+ | `searchProvinces(query, options?)` | `string, SearchOptions?` | `Province[]` | جستجوی fuzzy استان |
232
+ | `searchCities(query, options?)` | `string, SearchOptions?` | `FlatCity[]` | جستجوی fuzzy شهر |
233
+ | `getStats()` | - | `{provinceCount, cityCount}` | آمار کلی |
234
+
235
+ `SearchOptions`: `{ limit?: number; locale?: 'en' | 'fa' | 'both' }`
236
+
237
+ ### تایپ‌ها
238
+
239
+ ```ts
240
+ interface City { en: string; fa: string; }
241
+ interface Province { en: string; fa: string; cities: City[]; }
242
+ interface FlatCity extends City { provinceEn: string; provinceFa: string; }
243
+ ```
244
+
245
+ ---
246
+
247
+ ## توسعه
248
+
249
+ ```bash
250
+ npm install
251
+ npm run build # خروجی dist/ (cjs + esm + d.ts)
252
+ npm run typecheck
253
+ ```
254
+
255
+ ## لایسنس
256
+
257
+ MIT