@qumra/fanar 0.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.
@@ -0,0 +1,3172 @@
1
+ import * as react from 'react';
2
+ import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes, ComponentType, CSSProperties, PointerEvent, KeyboardEvent, RefObject } from 'react';
3
+
4
+ /**
5
+ * دمج كلاسات — المتأخّر بيكسب المتعارِض معه، والباقي بيفضل.
6
+ * بيقبل أي قيمة falsy عشان `cond && 'class'` يشتغل حتى لو cond رقم أو نص.
7
+ */
8
+ type ClassValue = string | false | 0 | 0n | null | undefined;
9
+ declare function cn(...parts: ClassValue[]): string;
10
+ type Tone = 'neutral' | 'brand' | 'amber' | 'green' | 'red' | 'violet';
11
+ declare const TONE_SOFT: Record<Tone, string>;
12
+ declare const TONE_SOLID: Record<Tone, string>;
13
+ /**
14
+ * يحوّل الأرقام العربية-الهندية للاتينية.
15
+ *
16
+ * ── ليه ده لازم ────────────────────────────────────────────────────────
17
+ * لوحة المفاتيح العربية على الموبايل بتكتب `٥٦٤٦`، والمتصفّح مابيعرفش
18
+ * إنها أرقام: `Number('٥٦٤٦')` بيدّي `NaN`، و`type="number"` بيرفضها
19
+ * ويفضّي الحقل من غير ما يقول ليه.
20
+ *
21
+ * فالمستخدم بيكتب رقم صح والحقل بيبان فاضي — وأسوأ حاجة في ده إنه
22
+ * **مابيرميش خطأ**: مفيش رسالة ولا تحقّق، الرقم بيختفي وبس.
23
+ *
24
+ * ── والتحويل فوري ──────────────────────────────────────────────────────
25
+ * وهو بيكتب مش عند الحفظ. لو اتأخّر للحفظ، الحقل بيفضل يعرض `٥٦٤٦`
26
+ * والحسابات اللي بتتفرّج عليه (الربح، الإجمالي) بتشتغل على `NaN` —
27
+ * فالشاشة بتقول رقم والحساب بيقول لأ.
28
+ *
29
+ * بيغطّي التلات مجموعات: العربية-الهندية (٠-٩) والفارسية-الأردية
30
+ * (۰-۹) وعلامتَي العشرية والآلاف العربيتين.
31
+ */
32
+ declare function toLatinDigits(s: string): string;
33
+ type ButtonVariant = 'primary' | 'soft' | 'outline' | 'ghost' | 'danger' | 'link';
34
+ type ButtonSize = 'sm' | 'md' | 'lg' | 'xl';
35
+ /**
36
+ * كلاسات الزرار من غير العنصر نفسه.
37
+ *
38
+ * موجودة عشان اللينك اللي شكله زرار: `<Button>` بيطلّع `<button>`
39
+ * دايماً، والحاجة اللي بتوَدّي لصفحة تانية لازم تبقى `<a>` — الوسط
40
+ * بيضغط عليها يفتح تبويب، وقارئ الشاشة بيقول «رابط» مش «زر».
41
+ * صفحة الهبوط كلها من النوع ده، فالبديل كان نسخ خرايط الأنماط.
42
+ */
43
+ declare function buttonClasses(variant?: ButtonVariant, size?: ButtonSize, extra?: string): string;
44
+
45
+ /** سلّم الخط — الدرجة بعد `text-` */
46
+ declare const TEXT_SCALE: readonly ["micro", "caption", "ui", "body", "lead", "base", "h4", "h3", "h2", "h1", "display", "hero", "title", "mega"];
47
+ type TextSize = (typeof TEXT_SCALE)[number];
48
+ /** نصف القطر بالدور مش بالمقاس — الدرجة بعد `rounded-` */
49
+ declare const RADIUS_SCALE: readonly ["mark", "xs", "sm", "field", "card", "lg", "section", "full"];
50
+ type Radius = (typeof RADIUS_SCALE)[number];
51
+ /** الظل بالدور — الدرجة بعد `shadow-` */
52
+ declare const SHADOW_SCALE: readonly ["raise", "tip", "panel", "pop", "modal", "toast", "sheet"];
53
+ type Shadow = (typeof SHADOW_SCALE)[number];
54
+ /** عرض الحاويات — الدرجة بعد `max-w-` */
55
+ declare const CONTAINER_SCALE: readonly ["page", "shell", "note", "lead"];
56
+ type Container = (typeof CONTAINER_SCALE)[number];
57
+ /** الحركات — الدرجة بعد `animate-` */
58
+ declare const ANIMATE_SCALE: readonly ["qfade", "qslide", "tip", "tip-up", "drawer", "drawer-rtl", "savebar", "skeleton"];
59
+ type Animation = (typeof ANIMATE_SCALE)[number];
60
+ /** أسماء الألوان — الدرجة بعد `bg-` و`text-` و`border-` */
61
+ declare const COLOR_SCALE: readonly ["surface", "bg", "line", "hover", "ink", "ink2", "muted", "muted2", "border", "soft", "soft2", "brand-100", "brand-900", "brand-ink", "brand", "brand-hover", "brand-deep", "skeleton", "tint", "tint2", "mint", "amber-900", "amber", "amber-bg", "amber-ink", "amber-line", "amber-hover", "green", "green-bg", "green-bg2", "green-line", "green-solid", "violet", "violet-bg", "violet-line", "violet-solid", "red-100", "red", "red-bg", "red-line", "danger", "danger-hover", "night", "hero-body", "hero-meta", "hero-dim", "hero-text", "code-bg", "code-plain", "code-key", "code-tag", "code-attr", "code-str", "code-num", "code-note", "code-dim", "code-line", "code-chip"];
62
+ type ColorToken = (typeof COLOR_SCALE)[number];
63
+ /** كل التوكنز بقيمتها في الوضع الفاتح — للكود اللي بياخد اللون كنصّ */
64
+ declare const TOKENS: {
65
+ readonly '--font-sans': "\"Alexandria\", system-ui, sans-serif";
66
+ readonly '--color-surface': "#ffffff";
67
+ readonly '--color-bg': "#f7f9f9";
68
+ readonly '--color-line': "#edf1f1";
69
+ readonly '--color-hover': "#f2f6f6";
70
+ readonly '--color-ink': "#020809";
71
+ readonly '--color-ink2': "#3d4545";
72
+ readonly '--color-muted': "#5f6a6a";
73
+ readonly '--color-muted2': "#687373";
74
+ readonly '--color-border': "#7f8c8c";
75
+ readonly '--color-soft': "#eaf2f3";
76
+ readonly '--color-soft2': "#dceded";
77
+ readonly '--color-brand-100': "#a5c9cc";
78
+ readonly '--color-brand-900': "#0a2528";
79
+ readonly '--color-brand-ink': "#0f4a4e";
80
+ readonly '--color-brand': "#207982";
81
+ readonly '--color-brand-hover': "#1a646c";
82
+ readonly '--color-brand-deep': "#0b3b3e";
83
+ readonly '--color-skeleton': "#d6dcdc";
84
+ readonly '--color-tint': "#f4faf8";
85
+ readonly '--color-tint2': "#eff6f3";
86
+ readonly '--color-mint': "#7dd3c0";
87
+ readonly '--color-amber-900': "#3d2a05";
88
+ readonly '--color-amber': "#f8ac33";
89
+ readonly '--color-amber-bg': "#fef6e9";
90
+ readonly '--color-amber-ink': "#85570f";
91
+ readonly '--color-amber-line': "#fbd79a";
92
+ readonly '--color-amber-hover': "#de9219";
93
+ readonly '--color-green': "#1e7a45";
94
+ readonly '--color-green-bg': "#f1faf4";
95
+ readonly '--color-green-bg2': "#e9f6ee";
96
+ readonly '--color-green-line': "#bfe6ce";
97
+ readonly '--color-green-solid': "#1e7a45";
98
+ readonly '--color-violet': "#4b3e8e";
99
+ readonly '--color-violet-bg': "#edeaf6";
100
+ readonly '--color-violet-line': "#ded8ef";
101
+ readonly '--color-violet-solid': "#6d5eb8";
102
+ readonly '--color-red-100': "#f3a79e";
103
+ readonly '--color-red': "#8e2b20";
104
+ readonly '--color-red-bg': "#fdecea";
105
+ readonly '--color-red-line': "#f3c9c4";
106
+ readonly '--color-danger': "#c94134";
107
+ readonly '--color-danger-hover': "#a3362b";
108
+ readonly '--color-night': "#0b0f12";
109
+ readonly '--color-hero-body': "#bfd9d8";
110
+ readonly '--color-hero-meta': "#8fb3b2";
111
+ readonly '--color-hero-dim': "#5e7a79";
112
+ readonly '--color-hero-text': "#d7e3e2";
113
+ readonly '--color-code-bg': "#1f1f1f";
114
+ readonly '--color-code-plain': "#d4d4d4";
115
+ readonly '--color-code-key': "#569cd6";
116
+ readonly '--color-code-tag': "#4ec9b0";
117
+ readonly '--color-code-attr': "#9cdcfe";
118
+ readonly '--color-code-str': "#ce9178";
119
+ readonly '--color-code-num': "#b5cea8";
120
+ readonly '--color-code-note': "#6a9955";
121
+ readonly '--color-code-dim': "#858585";
122
+ readonly '--color-code-line': "#303031";
123
+ readonly '--color-code-chip': "#f4f7f7";
124
+ readonly '--text-micro': "11px";
125
+ readonly '--text-caption': "12px";
126
+ readonly '--text-ui': "13px";
127
+ readonly '--text-body': "14px";
128
+ readonly '--text-lead': "15px";
129
+ readonly '--text-base': "16px";
130
+ readonly '--text-base--line-height': "initial";
131
+ readonly '--text-h4': "17px";
132
+ readonly '--text-h3': "20px";
133
+ readonly '--text-h2': "24px";
134
+ readonly '--text-h1': "30px";
135
+ readonly '--text-display': "36px";
136
+ readonly '--text-hero': "44px";
137
+ readonly '--text-title': "40px";
138
+ readonly '--text-mega': "54px";
139
+ readonly '--container-page': "1600px";
140
+ readonly '--container-shell': "1600px";
141
+ readonly '--container-note': "340px";
142
+ readonly '--container-lead': "520px";
143
+ readonly '--radius-mark': "3px";
144
+ readonly '--radius-xs': "5px";
145
+ readonly '--radius-sm': "7px";
146
+ readonly '--radius-field': "9px";
147
+ readonly '--radius-card': "12px";
148
+ readonly '--radius-lg': "14px";
149
+ readonly '--radius-section': "18px";
150
+ readonly '--radius-full': "999px";
151
+ readonly '--shadow-raise': "0 1px 3px var(--shadow-color)";
152
+ readonly '--shadow-tip': "0 6px 18px var(--shadow-color)";
153
+ readonly '--shadow-panel': "0 10px 30px var(--shadow-color)";
154
+ readonly '--shadow-pop': "0 18px 44px var(--shadow-color)";
155
+ readonly '--shadow-modal': "0 24px 60px rgb(2 8 9 / 0.28)";
156
+ readonly '--shadow-toast': "0 16px 40px rgb(2 8 9 / 0.26)";
157
+ readonly '--shadow-sheet': "0 -14px 40px rgb(2 8 9 / 0.28), inset 0 1px 0 rgb(255 255 255 / 0.06)";
158
+ readonly '--shadow-color': "rgb(2 8 9 / 0.14)";
159
+ readonly '--animate-qfade': "qfade 0.16s ease-out";
160
+ readonly '--animate-qslide': "qslidein 0.22s ease-out";
161
+ readonly '--animate-tip': "tip-in 0.26s cubic-bezier(0.2, 0.8, 0.2, 1)";
162
+ readonly '--animate-tip-up': "tip-up 0.3s cubic-bezier(0.2, 0.9, 0.2, 1)";
163
+ readonly '--animate-drawer': "drawer-ltr 0.32s cubic-bezier(0.2, 0.9, 0.2, 1)";
164
+ readonly '--animate-drawer-rtl': "drawer-rtl 0.32s cubic-bezier(0.2, 0.9, 0.2, 1)";
165
+ readonly '--animate-savebar': "savebar-in 0.2s cubic-bezier(0.2, 0.8, 0.2, 1)";
166
+ readonly '--animate-skeleton': "skeleton-pulse 1.6s ease-in-out infinite";
167
+ readonly '--num-align': "right";
168
+ readonly '--num-align-far': "left";
169
+ readonly '--num-pad-right': "0.875rem";
170
+ readonly '--num-pad-left': "3.5rem";
171
+ readonly '--num-icon-pad-right': "2.5rem";
172
+ readonly '--num-icon-pad-left': "0.875rem";
173
+ };
174
+ /** التجاوزات في الوضع الداكن — بس اللي بيتغيّر */
175
+ declare const DARK_TOKENS: {
176
+ readonly '--color-surface': "#101718";
177
+ readonly '--color-bg': "#0a0f10";
178
+ readonly '--color-line': "#1e2829";
179
+ readonly '--color-hover': "#1a2425";
180
+ readonly '--color-ink': "#f2f6f6";
181
+ readonly '--color-ink2': "#c7d1d1";
182
+ readonly '--color-muted': "#93a0a0";
183
+ readonly '--color-muted2': "#7a8787";
184
+ readonly '--color-border': "#5e6b6c";
185
+ readonly '--color-soft': "#12363a";
186
+ readonly '--color-soft2': "#17454a";
187
+ readonly '--color-brand-ink': "#7dd3c0";
188
+ readonly '--color-skeleton': "#2c3232";
189
+ readonly '--color-amber': "#f8ac33";
190
+ readonly '--color-amber-bg': "#2b2009";
191
+ readonly '--color-amber-ink': "#f5c77a";
192
+ readonly '--color-amber-line': "#5c4415";
193
+ readonly '--color-green': "#6ecf9a";
194
+ readonly '--color-green-bg': "#0d2119";
195
+ readonly '--color-green-bg2': "#102a22";
196
+ readonly '--color-green-line': "#245140";
197
+ readonly '--color-violet': "#b9aeea";
198
+ readonly '--color-violet-bg': "#1e1a33";
199
+ readonly '--color-violet-line': "#38305c";
200
+ readonly '--color-red': "#f3a79e";
201
+ readonly '--color-red-bg': "#2c1613";
202
+ readonly '--color-red-line': "#5c2a24";
203
+ readonly '--color-code-chip': "#17201f";
204
+ readonly '--shadow-color': "rgb(0 0 0 / 0.55)";
205
+ };
206
+ type TokenName = keyof typeof TOKENS;
207
+
208
+ interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
209
+ variant?: ButtonVariant;
210
+ size?: ButtonSize;
211
+ /** أيقونة قبل النص — بتتقلب مع اتجاه الصفحة تلقائياً */
212
+ icon?: ReactNode;
213
+ /** أيقونة بعد النص */
214
+ iconEnd?: ReactNode;
215
+ /** زرار أيقونة فقط — لازم معاه aria-label */
216
+ iconOnly?: boolean;
217
+ loading?: boolean;
218
+ block?: boolean;
219
+ }
220
+ declare const Button: react.ForwardRefExoticComponent<ButtonProps & react.RefAttributes<HTMLButtonElement>>;
221
+
222
+ /**
223
+ * لغة الصفحة كاملةً — لا `boolean`.
224
+ *
225
+ * ── لماذا اللغة نفسها لا «إنجليزيّ؟ نعم/لا» ────────────────────────────
226
+ * كانت الدالّة تُرجع `boolean`، والتنسيق يختار بين `ar-EG` و`en-US`.
227
+ * وذلك **خطأ في خمس دول عربيّة**: المغرب والجزائر وتونس وليبيا تكتب
228
+ * الأرقام لاتينيّةً بفواصل أوروبيّة (`1.250,50`)، والإمارات لاتينيّةً
229
+ * بفواصل إنجليزيّة (`1,250.50`) — بينما مصر والخليج والمشرق تكتبها
230
+ * عربيّةً هنديّة (`١٬٢٥٠٫٥٠`).
231
+ *
232
+ * فتاجر مغربيّ كان يرى أرقاماً مصريّة. و`Intl` يعرف هذا كلّه بشرط أن
233
+ * يصله `ar-MA` لا `ar-EG`.
234
+ */
235
+ /**
236
+ * لغة العرض على الخادم — يمرّرها التطبيق عبر `MoneyProvider`.
237
+ *
238
+ * ── لماذا سياق ولا يكفي قارئ الـDOM ────────────────────────────────────
239
+ * `langStore` يقرأ `document.documentElement.lang`، و`document` لا وجود
240
+ * له على الخادم. فكانت لقطة الخادم ثابتةً: `() => 'ar'`.
241
+ *
242
+ * وهي **خطأ مقيس**: `ar` المجرّدة افتراضها `latn` في CLDR.
243
+ *
244
+ * Intl.NumberFormat('ar').format(1250.5) → 1,250.50
245
+ * Intl.NumberFormat('ar-EG').format(1250.5) → ١٬٢٥٠٫٥٠
246
+ *
247
+ * فكل مبلغ يُرسم على الخادم كان يخرج بأرقام لاتينيّة، ثم ينقلب هنديّاً
248
+ * بعد الترطيب — ومضة يراها المستخدم، و**عدم تطابق** يشتكي منه React.
249
+ * والعيب يمرّ بلا انتباه لأن الشكل النهائيّ صحيح.
250
+ */
251
+ declare const LocaleCtx: react.Context<string | null>;
252
+ /**
253
+ * لغة العرض.
254
+ *
255
+ * تُقرأ من `<html lang>` في المتصفّح — فتبديل اللغة يسري على كلّ مبلغ بلا
256
+ * تمرير. وعلى الخادم تُؤخذ من `MoneyProvider`، وإن لم يمرّرها التطبيق
257
+ * فـ`ar-EG` (الأغلب) لا `ar` (الخاطئة).
258
+ */
259
+ declare function useMoneyLocale(): string;
260
+ /** `true` لما صفحة إنجليزية */
261
+ declare function useMoneyLang(): boolean;
262
+
263
+ declare const TEXT: {
264
+ readonly close: readonly ["إغلاق", "Close"];
265
+ readonly select: readonly ["اختر…", "Select…"];
266
+ readonly search: readonly ["ابحث…", "Search…"];
267
+ readonly searchEverything: readonly ["ابحث في كل حاجة…", "Search everything…"];
268
+ readonly noResults: readonly ["مافيش نتايج", "No results"];
269
+ readonly searchOrAdd: readonly ["ابحث أو أضف…", "Search or add…"];
270
+ readonly now: readonly ["الآن", "Now"];
271
+ readonly videoPlayer: readonly ["مشغّل الفيديو", "Video player"];
272
+ readonly rating: readonly ["التقييم", "Rating"];
273
+ readonly activeFilters: readonly ["الفلاتر المطبّقة:", "Active filters:"];
274
+ readonly clearAll: readonly ["مسح الكل", "Clear all"];
275
+ readonly row: readonly ["صفّ", "row"];
276
+ readonly dropImages: readonly ["اسحب الصور هنا", "Drop images here"];
277
+ readonly chooseFromDevice: readonly ["اختر من الجهاز", "Choose from device"];
278
+ readonly previousPeriod: readonly ["الفترة السابقة", "Previous period"];
279
+ readonly less: readonly ["أقل", "Less"];
280
+ readonly more: readonly ["أكثر", "More"];
281
+ readonly totalSales: readonly ["إجمالي المبيعات", "Total sales"];
282
+ readonly netToYou: readonly ["صافي لك", "Net to you"];
283
+ readonly verifiedAccount: readonly ["حساب موثّق", "Verified account"];
284
+ readonly grabHint: readonly ["عنصر قابل لإعادة الترتيب. اضغط مسافة لمسكه ثم الأسهم لتحريكه.", "Reorderable item. Press space to grab it, then the arrows to move it."];
285
+ readonly notifications: readonly ["الإشعارات", "Notifications"];
286
+ readonly dismiss: readonly ["إخفاء", "Dismiss"];
287
+ readonly unread: readonly ["غير مقروء", "Unread"];
288
+ readonly noNotifications: readonly ["مفيش إشعارات", "No notifications"];
289
+ readonly noNotificationsDesc: readonly ["أول ما يحصل حاجة تستاهل، هتلاقيها هنا.", "When something worth knowing happens, it lands here."];
290
+ readonly markAllRead: readonly ["تعليم الكل كمقروء", "Mark all as read"];
291
+ readonly viewAllNotifications: readonly ["عرض كل الإشعارات", "View all notifications"];
292
+ readonly newNotifications: readonly ["إشعارات جديدة", "New notifications"];
293
+ readonly reloadPreview: readonly ["إعادة تحميل المعاينة", "Reload preview"];
294
+ readonly previousMonth: readonly ["الشهر اللي قبله", "Previous month"];
295
+ readonly nextMonth: readonly ["الشهر اللي بعده", "Next month"];
296
+ readonly whatIsThisNumber: readonly ["ما معنى هذا الرقم؟", "What does this number mean?"];
297
+ readonly explainToMe: readonly ["اشرح لي", "Explain this"];
298
+ readonly clearSearch: readonly ["مسح البحث", "Clear search"];
299
+ readonly alerts: readonly ["التنبيهات", "Alerts"];
300
+ readonly whatIsThisOption: readonly ["ما هذا الخيار؟", "What is this option?"];
301
+ readonly shouldBeHere: readonly ["المفروض تكون هنا", "Should be here"];
302
+ readonly closeExplainer: readonly ["إغلاق الشرح", "Close explainer"];
303
+ readonly cancelRecording: readonly ["إلغاء التسجيل", "Cancel recording"];
304
+ readonly sendRecording: readonly ["إرسال التسجيل", "Send recording"];
305
+ readonly attachFile: readonly ["إرفاق ملف", "Attach file"];
306
+ readonly recordVoice: readonly ["تسجيل صوتي", "Record a voice note"];
307
+ readonly playbackPosition: readonly ["موضع التشغيل", "Playback position"];
308
+ readonly volume: readonly ["مستوى الصوت", "Volume"];
309
+ readonly hideSuggestions: readonly ["إخفاء الاقتراحات", "Hide suggestions"];
310
+ readonly askShehab: readonly ["اسأل شهاب…", "Ask Shehab…"];
311
+ readonly shehabThinking: readonly ["شهاب بيفكّر…", "Shehab is thinking…"];
312
+ readonly undo: readonly ["تراجع", "Undo"];
313
+ readonly from: readonly ["من", "from"];
314
+ readonly tryAnotherReply: readonly ["جرّب رد تاني", "Try another reply"];
315
+ readonly helpfulReply: readonly ["رد مفيد", "Helpful reply"];
316
+ readonly unhelpfulReply: readonly ["رد مش مفيد", "Unhelpful reply"];
317
+ readonly aiDisclaimer: readonly ["شهاب ممكن يغلط. راجع الأرقام قبل ما تتصرّف عليها.", "Shehab can get things wrong. Check the numbers before acting on them."];
318
+ readonly back10: readonly ["رجوع ١٠ ثواني", "Back 10 seconds"];
319
+ readonly forward10: readonly ["تقديم ١٠ ثواني", "Forward 10 seconds"];
320
+ readonly playbackSpeed: readonly ["سرعة التشغيل", "Playback speed"];
321
+ readonly arabic: readonly ["العربية", "Arabic"];
322
+ readonly seeMore: readonly ["شوف كمان", "See more"];
323
+ readonly pictureInPicture: readonly ["نافذة عائمة", "Picture in picture"];
324
+ };
325
+ type UITextKey = keyof typeof TEXT;
326
+ /**
327
+ * نصوص المكتبة باللغة المعروضة.
328
+ *
329
+ * تُستدعى في جسم المكوّن لا في قيمة الخاصّية الافتراضية — الخطّاف
330
+ * مايتنادش في توقيع دالة. فالنمط:
331
+ *
332
+ * export function Modal({ closeLabel, … }) {
333
+ * const ui = useUIText()
334
+ * …
335
+ * aria-label={closeLabel ?? ui.close}
336
+ */
337
+ declare function useUIText(): Record<"select" | "search" | "row" | "from" | "close" | "searchEverything" | "noResults" | "searchOrAdd" | "now" | "videoPlayer" | "rating" | "activeFilters" | "clearAll" | "dropImages" | "chooseFromDevice" | "previousPeriod" | "less" | "more" | "totalSales" | "netToYou" | "verifiedAccount" | "grabHint" | "notifications" | "dismiss" | "unread" | "noNotifications" | "noNotificationsDesc" | "markAllRead" | "viewAllNotifications" | "newNotifications" | "reloadPreview" | "previousMonth" | "nextMonth" | "whatIsThisNumber" | "explainToMe" | "clearSearch" | "alerts" | "whatIsThisOption" | "shouldBeHere" | "closeExplainer" | "cancelRecording" | "sendRecording" | "attachFile" | "recordVoice" | "playbackPosition" | "volume" | "hideSuggestions" | "askShehab" | "shehabThinking" | "undo" | "tryAnotherReply" | "helpfulReply" | "unhelpfulReply" | "aiDisclaimer" | "back10" | "forward10" | "playbackSpeed" | "arabic" | "seeMore" | "pictureInPicture", string>;
338
+
339
+ type FieldSize = 'sm' | 'md' | 'lg';
340
+ interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
341
+ label?: ReactNode;
342
+ /** فعل ثانوي جنب التسمية — «سجّل بالبريد بدل الهاتف» مثلاً */
343
+ labelAside?: ReactNode;
344
+ hint?: ReactNode;
345
+ error?: ReactNode;
346
+ size?: FieldSize;
347
+ hideLabel?: boolean;
348
+ icon?: ReactNode;
349
+ /** نص في نهاية الحقل — وحدة عملة مثلاً */
350
+ suffix?: ReactNode;
351
+ /** عنصر في نهاية الحقل بيتضغط — زرار إظهار كلمة السر مثلاً */
352
+ action?: ReactNode;
353
+ /** للأرقام — بيثبّت الاتجاه LTR جوّه واجهة عربية */
354
+ numeric?: boolean;
355
+ wrapperClassName?: string;
356
+ }
357
+ declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
358
+ /** حقل بحث — النمط المتكرر في كل شاشة قايمة */
359
+ declare const SearchInput: react.ForwardRefExoticComponent<Omit<InputProps, "icon"> & react.RefAttributes<HTMLInputElement>>;
360
+ interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
361
+ label?: ReactNode;
362
+ hint?: ReactNode;
363
+ error?: ReactNode;
364
+ /** التسمية موجودة لقارئ الشاشة بس مخفية بصرياً */
365
+ hideLabel?: boolean;
366
+ wrapperClassName?: string;
367
+ }
368
+ declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
369
+ interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'size'> {
370
+ label?: ReactNode;
371
+ hint?: ReactNode;
372
+ error?: ReactNode;
373
+ size?: FieldSize;
374
+ hideLabel?: boolean;
375
+ options: {
376
+ value: string;
377
+ label: string;
378
+ }[];
379
+ wrapperClassName?: string;
380
+ }
381
+ /**
382
+ * `<select>` أصلي مقصود — الدروب داون المخصّص بيكسر التنقّل بالكيبورد
383
+ * وبيتعب على الموبايل.
384
+ */
385
+ declare const Select: react.ForwardRefExoticComponent<SelectProps & react.RefAttributes<HTMLSelectElement>>;
386
+ interface ChoiceProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
387
+ label?: ReactNode;
388
+ description?: ReactNode;
389
+ /** الحالة الوسيطة — بعض العناصر التابعة متحدّدة */
390
+ indeterminate?: boolean;
391
+ }
392
+ declare const Checkbox: react.ForwardRefExoticComponent<ChoiceProps & react.RefAttributes<HTMLInputElement>>;
393
+ declare const Radio: react.ForwardRefExoticComponent<Omit<ChoiceProps, "indeterminate"> & react.RefAttributes<HTMLInputElement>>;
394
+ /**
395
+ * مجموعة الراديو لازم تتلفّ في fieldset/legend — من غير كده قارئ الشاشة
396
+ * بيقرا الخيارات من غير ما يعرف السؤال.
397
+ */
398
+ declare function RadioGroup({ label, children, inline, }: {
399
+ label: ReactNode;
400
+ children: ReactNode;
401
+ inline?: boolean;
402
+ }): react.JSX.Element;
403
+ /**
404
+ * `role="switch"` مع `aria-checked`. الإبهام بيتحرّك بـinset-inline-start
405
+ * مش transform، فبيتقلب صح في العربي من غير أي كود إضافي.
406
+ */
407
+ declare function Switch({ checked, onCheckedChange, label, description, disabled, id: idProp, }: {
408
+ checked: boolean;
409
+ onCheckedChange: (v: boolean) => void;
410
+ label?: ReactNode;
411
+ description?: ReactNode;
412
+ disabled?: boolean;
413
+ id?: string;
414
+ }): react.JSX.Element;
415
+
416
+ declare const CURRENCY: {
417
+ SAR: {
418
+ short: string;
419
+ word: string;
420
+ best: "sign";
421
+ code: string;
422
+ sign: react.JSX.Element;
423
+ name: string;
424
+ en: string;
425
+ decimals: number;
426
+ };
427
+ AED: {
428
+ short: string;
429
+ word: string;
430
+ best: "word";
431
+ code: string;
432
+ sign: null;
433
+ name: string;
434
+ en: string;
435
+ decimals: number;
436
+ };
437
+ QAR: {
438
+ short: string;
439
+ word: string;
440
+ best: "word";
441
+ code: string;
442
+ sign: null;
443
+ name: string;
444
+ en: string;
445
+ decimals: number;
446
+ };
447
+ KWD: {
448
+ short: string;
449
+ word: string;
450
+ best: "word";
451
+ code: string;
452
+ sign: null;
453
+ name: string;
454
+ en: string;
455
+ decimals: number;
456
+ };
457
+ BHD: {
458
+ short: string;
459
+ word: string;
460
+ best: "word";
461
+ code: string;
462
+ sign: null;
463
+ name: string;
464
+ en: string;
465
+ decimals: number;
466
+ };
467
+ OMR: {
468
+ short: string;
469
+ word: string;
470
+ best: "word";
471
+ code: string;
472
+ sign: null;
473
+ name: string;
474
+ en: string;
475
+ decimals: number;
476
+ };
477
+ EGP: {
478
+ short: string;
479
+ word: string;
480
+ best: "word";
481
+ code: string;
482
+ sign: react.JSX.Element;
483
+ name: string;
484
+ en: string;
485
+ decimals: number;
486
+ };
487
+ JOD: {
488
+ short: string;
489
+ word: string;
490
+ best: "word";
491
+ code: string;
492
+ sign: null;
493
+ name: string;
494
+ en: string;
495
+ decimals: number;
496
+ };
497
+ IQD: {
498
+ short: string;
499
+ word: string;
500
+ best: "word";
501
+ code: string;
502
+ sign: null;
503
+ name: string;
504
+ en: string;
505
+ decimals: number;
506
+ };
507
+ LBP: {
508
+ short: string;
509
+ word: string;
510
+ best: "word";
511
+ code: string;
512
+ sign: null;
513
+ name: string;
514
+ en: string;
515
+ decimals: number;
516
+ };
517
+ SYP: {
518
+ short: string;
519
+ word: string;
520
+ best: "word";
521
+ code: string;
522
+ sign: null;
523
+ name: string;
524
+ en: string;
525
+ decimals: number;
526
+ };
527
+ YER: {
528
+ short: string;
529
+ word: string;
530
+ best: "word";
531
+ code: string;
532
+ sign: null;
533
+ name: string;
534
+ en: string;
535
+ decimals: number;
536
+ };
537
+ SDG: {
538
+ short: string;
539
+ word: string;
540
+ best: "word";
541
+ code: string;
542
+ sign: null;
543
+ name: string;
544
+ en: string;
545
+ decimals: number;
546
+ };
547
+ MAD: {
548
+ short: string;
549
+ word: string;
550
+ best: "word";
551
+ code: string;
552
+ sign: null;
553
+ name: string;
554
+ en: string;
555
+ decimals: number;
556
+ };
557
+ DZD: {
558
+ short: string;
559
+ word: string;
560
+ best: "word";
561
+ code: string;
562
+ sign: null;
563
+ name: string;
564
+ en: string;
565
+ decimals: number;
566
+ };
567
+ TND: {
568
+ short: string;
569
+ word: string;
570
+ best: "word";
571
+ code: string;
572
+ sign: null;
573
+ name: string;
574
+ en: string;
575
+ decimals: number;
576
+ };
577
+ LYD: {
578
+ short: string;
579
+ word: string;
580
+ best: "word";
581
+ code: string;
582
+ sign: null;
583
+ name: string;
584
+ en: string;
585
+ decimals: number;
586
+ };
587
+ MRU: {
588
+ short: string;
589
+ word: string;
590
+ best: "word";
591
+ code: string;
592
+ sign: null;
593
+ name: string;
594
+ en: string;
595
+ decimals: number;
596
+ };
597
+ SOS: {
598
+ short: string;
599
+ word: string;
600
+ best: "word";
601
+ code: string;
602
+ sign: null;
603
+ name: string;
604
+ en: string;
605
+ decimals: number;
606
+ };
607
+ DJF: {
608
+ short: string;
609
+ word: string;
610
+ best: "word";
611
+ code: string;
612
+ sign: null;
613
+ name: string;
614
+ en: string;
615
+ decimals: number;
616
+ };
617
+ KMF: {
618
+ short: string;
619
+ word: string;
620
+ best: "word";
621
+ code: string;
622
+ sign: null;
623
+ name: string;
624
+ en: string;
625
+ decimals: number;
626
+ };
627
+ USD: {
628
+ short: string;
629
+ word: string;
630
+ best: "sign";
631
+ code: string;
632
+ sign: react.JSX.Element;
633
+ name: string;
634
+ en: string;
635
+ decimals: number;
636
+ };
637
+ EUR: {
638
+ short: string;
639
+ word: string;
640
+ best: "sign";
641
+ code: string;
642
+ sign: react.JSX.Element;
643
+ name: string;
644
+ en: string;
645
+ decimals: number;
646
+ };
647
+ GBP: {
648
+ short: string;
649
+ word: string;
650
+ best: "sign";
651
+ code: string;
652
+ sign: react.JSX.Element;
653
+ name: string;
654
+ en: string;
655
+ decimals: number;
656
+ };
657
+ };
658
+ /** صيغة الوحدة المعروضة */
659
+ /** الصيغ الصريحة — كلٌّ منها يقول شكلاً بعينه */
660
+ type Base = 'short' | 'word' | 'code' | 'sign';
661
+ /**
662
+ * صيغة الوحدة المعروضة.
663
+ *
664
+ * `short` اختصار عربيّ · `word` الكلمة · `code` رمز ISO · `sign` الرمز
665
+ * الرسوميّ · `best` ما تختاره المكتبة.
666
+ *
667
+ * ── و`best` ليس خوارزميّة بل رأي ────────────────────────────────────────
668
+ * لكل عملة سطر في الجدول يقول أيّ صيغة تُقرأ أسرع **لها هي**، لأن
669
+ * الإجابة تختلف بينها:
670
+ *
671
+ * · الريال السعوديّ → رمزه، لأن له رمزاً رسميّاً يعرفه أهله
672
+ * · الجنيه والدينار والدرهم → كلمتها، فلا رمز رسميّ لها والاختصار
673
+ * يُقرأ حرفين قبل أن يُفهم
674
+ * · الدولار واليورو والإسترلينيّ → رموزها، فهي مقروءة عالميّاً
675
+ * وأقصر من «دولار»
676
+ *
677
+ * ولو حُسبت هذه بقاعدة واحدة («رمز إن وُجد») لخرج الجنيه `£` — وهو
678
+ * صحيح تقنيّاً ويُقرأ «إسترلينيّاً» في مصر. الرأي المكتوب لكل عملة
679
+ * أصدق من قاعدة تبدو أنظف.
680
+ *
681
+ * ── وفي الإنجليزيّة ────────────────────────────────────────────────────
682
+ * `best` يصير الرمز إن وُجد وإلّا رمز ISO — الكلمة العربية لا معنى لها
683
+ * في صفحة إنجليزيّة، و«جنيه» لا تُكتب `pound` لأن ذلك يخلطه بالإسترلينيّ.
684
+ */
685
+ type SymbolStyle = Base | 'best';
686
+ type Currency = keyof typeof CURRENCY;
687
+ /**
688
+ * يفحص كود عملة جاءَ من الخادم قبل تمريره إلى `Money`.
689
+ *
690
+ * ── لماذا حارس لا `as` ──────────────────────────────────────────────────
691
+ * `Money.currency` اتّحاد مغلق، والخوادم تُرجع `string`. فكل مستهلك كان
692
+ * يكتب `code as Currency` — وهذا **إسكات لا فحص**: كود غير معروف
693
+ * (`XYZ`، أو حقل فارغ) يمرّ ثم يفشل عند القراءة من الجدول.
694
+ *
695
+ * والحارس يجعل المجهول `undefined`، و`Money` عندها ترجع إلى عملة المتجر
696
+ * من `MoneyProvider` — وهو **السلوك الصحيح**: عرض المبلغ بعملة اللوحة
697
+ * أقلّ ضرراً من عرضه برمز خاطئ أو بلا رمز.
698
+ *
699
+ * ```tsx
700
+ * <Money value={total} currency={isCurrency(code) ? code : undefined} />
701
+ * ```
702
+ */
703
+ declare function isCurrency(c?: string | null): c is Currency;
704
+ declare function MoneyProvider({ currency, locale, children, }: {
705
+ currency: Currency;
706
+ /**
707
+ * لغة العرض على الخادم — وسم BCP-47 كامل (`ar-EG` · `ar-MA` · `en`).
708
+ *
709
+ * المتصفّح يقرأها من `<html lang>` وحده، فهذه للتصيير من الخادم فقط.
710
+ * أهملها ولن يُكسر شيء — لكن أوّل رسم سيخرج بأرقام `ar-EG` مهما كانت
711
+ * لغة الصفحة. الشرح عند `useMoneyLocale`.
712
+ */
713
+ locale?: string;
714
+ children: ReactNode;
715
+ }): react.JSX.Element;
716
+ /**
717
+ * عملة المتجر الحاليّة.
718
+ *
719
+ * لغير `Money`: لاحقة حقل سعر، وعنوان عمود، ونصّ «السعر بالـ…».
720
+ */
721
+ declare function useCurrency(): Currency;
722
+ declare const SIZE: {
723
+ readonly inherit: "";
724
+ readonly sm: "text-caption";
725
+ readonly md: "text-ui";
726
+ readonly lg: "text-body font-extrabold";
727
+ readonly xl: "text-h2 font-black";
728
+ };
729
+ declare const TONE: {
730
+ readonly inherit: "";
731
+ readonly muted: "text-muted";
732
+ readonly ink: "text-ink";
733
+ readonly green: "text-green";
734
+ readonly red: "text-red";
735
+ };
736
+ interface MoneyProps {
737
+ /** المبلغ بالوحدة الكبرى — جنيهات لا قروش */
738
+ value: number;
739
+ /** استثناء محلّي يغلب عملة المتجر — سعر بالدولار في متجر مصريّ */
740
+ currency?: Currency;
741
+ size?: keyof typeof SIZE;
742
+ /**
743
+ * اللون.
744
+ *
745
+ * الافتراضيّ يرث لون ما حوله — والسالب **لا يُلوَّن تلقائياً**.
746
+ * خصم في شلّال ومرتجَع في قائمة كلاهما سالب، والأول محايد والثاني
747
+ * يستحقّ الأحمر. الفرق يعرفه السياق لا المكوّن.
748
+ */
749
+ tone?: keyof typeof TONE;
750
+ /** يُظهر `+` على الموجب — للفروق لا للأرصدة */
751
+ signed?: boolean;
752
+ /** «٧١٫٤ ألف» بدل «٧١٬٤٠٠» — للكروت والرسوم */
753
+ compact?: boolean;
754
+ /**
755
+ * يُخفي الكسور حين تكون أصفاراً.
756
+ *
757
+ * قائمة أسعار كلّها `٫٠٠` تضيف ضجيجاً بلا معلومة. لكن **الفاتورة
758
+ * لا تُخفيه**: المبلغ الرسميّ يُكتب كاملاً.
759
+ */
760
+ trimZeros?: boolean;
761
+ /** السعر قبل الخصم — يُشطب ويوضع بعد الحالي */
762
+ was?: number;
763
+ /**
764
+ * صيغة الوحدة.
765
+ *
766
+ * `short` الاختصار العربيّ (افتراضيّ) · `code` رمز ISO للفاتورة
767
+ * والتصدير · `sign` الرمز الرسوميّ حيث يوجد ويحمله الخطّ.
768
+ *
769
+ * و`sign` يرجع إلى `short` تلقائياً للعملة التي لا رمز لها في الخطّ
770
+ * — والقائمة في أعلى الملفّ تقول أيّها.
771
+ *
772
+ * والافتراضيّ يتبع لغة الصفحة: `short` في العربية و`code` في
773
+ * الإنجليزية — «ج.م» لا تُقرأ لمن لا يقرأ العربية.
774
+ */
775
+ symbol?: SymbolStyle;
776
+ /** يُخفي الوحدة — لعمود جدول عنوانه يحملها */
777
+ hideSymbol?: boolean;
778
+ className?: string;
779
+ }
780
+ /**
781
+ * مبلغ.
782
+ *
783
+ * ── لماذا مكوّن لا دالة تنسيق ──────────────────────────────────────────
784
+ * الدالة تُرجع نصّاً، والنصّ يفقد ثلاثة أشياء يحتاجها المبلغ: العزل
785
+ * الاتجاهيّ حول الرقم، ومنع القطع بين الرقم وعملته، وأرقام بعرض ثابت
786
+ * تصطفّ في العمود. كلّها خصائص عرض لا صياغة — فمكانها عنصر.
787
+ */
788
+ declare function Money({ value, currency, size, tone, signed, compact, trimZeros, was, symbol, hideSymbol, className, }: MoneyProps): react.JSX.Element;
789
+ /**
790
+ * وحدة العملة وحدها — لعنوان عمود أو لاحقة حقل.
791
+ *
792
+ * نفس الرجوع: `sign` غير الموجود في الخطّ يعود إلى `short`، فما يظهر
793
+ * في عنوان العمود يطابق ما يظهر في صفوفه دائماً.
794
+ */
795
+ /**
796
+ * وحدة العملة وحدها — لعنوان عمود أو لاحقة حقل.
797
+ *
798
+ * ترجع `ReactNode` لا نصّاً: وحدة الريال في صيغة `word` **رسم** لأن
799
+ * رمزه الرسميّ هو كلمة «ريال» نفسها. من يحتاج نصّاً خالصاً — عنوان
800
+ * ملفّ مُصدَّر مثلاً — يطلب `code`.
801
+ */
802
+ declare function currencySymbol(c?: Currency, style?: SymbolStyle, locale?: string): ReactNode;
803
+ /** الاسم المنطوق — لقارئ الشاشة وللقوائم المنسدلة */
804
+ declare const currencyName: (c?: Currency) => string;
805
+ /**
806
+ * وحدة العملة تابعةً للغة الصفحة — لعنوان عمود يحمل عملة صفوفه.
807
+ *
808
+ * `currencySymbol` الساكنة لا تعرف اللغة، فعنوان العمود كان يظلّ «ج.م»
809
+ * فوق صفوف مكتوبة `EGP`.
810
+ */
811
+ declare function useCurrencySymbol(c?: Currency, style?: SymbolStyle): ReactNode;
812
+
813
+ type Size = 'sm' | 'md' | 'lg';
814
+ interface NumberStepperProps {
815
+ value: number;
816
+ onChange: (v: number) => void;
817
+ min?: number;
818
+ max?: number;
819
+ step?: number;
820
+ size?: Size;
821
+ /** وحدة صغيرة بجانب الرقم — «قطعة»، «كجم» */
822
+ unit?: ReactNode;
823
+ /**
824
+ * يحلّ محلّ زرّ الناقص عند الحدّ الأدنى.
825
+ *
826
+ * زرّ ناقص معطَّل عند القطعة الواحدة يجعل المستخدم يبحث عن «كيف
827
+ * أزيله». الحدّ الأدنى الحقيقيّ في السلّة صفر ومعناه حذف — فيقولها
828
+ * الزرّ بدل أن يقف صامتاً.
829
+ */
830
+ onRemove?: () => void;
831
+ disabled?: boolean;
832
+ /** وصف الحقل لقارئ الشاشة — «كمية بوكيه ورد أبيض» */
833
+ label?: string;
834
+ className?: string;
835
+ }
836
+ declare function NumberStepper({ value, onChange, min, max, step, size, unit, onRemove, disabled, label, className, }: NumberStepperProps): react.JSX.Element;
837
+
838
+ /**
839
+ * علامة واتساب.
840
+ *
841
+ * ── لماذا مرسومة ولماذا مصمتة ───────────────────────────────────────────
842
+ * كانت `MessageCircle` من lucide، وهي فقاعة كلام عامّة. وفقاعة عامّة
843
+ * بجانب فقاعة الرسائل النصّيّة تجعل الزرّين متشابهين، والمستخدم يقرأ
844
+ * «رسالة» و«رسالة» فيتردّد قبل كلّ ضغطة.
845
+ *
846
+ * والعلامة مصمتة بين أيقونات محدّدة الخطوط عن قصد: علامة الخدمة تُعرف
847
+ * بشكلها لا بأسلوب المجموعة، وتحويلها إلى خطوط لتناسب البقيّة يفقدها
848
+ * الشيء الوحيد الذي تؤدّيه. والمسار من `simple-icons` — لا مرسوم
849
+ * بالتقدير، لأن علامة خدمة تُخمَّن تخرج علامةً أخرى.
850
+ */
851
+ declare function WhatsAppIcon({ size, ...rest }: React.SVGProps<SVGSVGElement> & {
852
+ size?: number;
853
+ }): react.JSX.Element;
854
+ interface PhoneParts {
855
+ /** المفتاح الدوليّ بلا `+` — فارغ إن لم يُعرف */
856
+ dial: string;
857
+ /** الرقم المحلّيّ بلا فواصل */
858
+ local: string;
859
+ /** اسم البلد إن عُرف مفتاحه */
860
+ country?: string;
861
+ }
862
+ /**
863
+ * يفصل المفتاح عن الرقم المحلّيّ.
864
+ *
865
+ * يقبل ما يكتبه الناس فعلاً: `+20 112 505 2692` و`0020112...` و
866
+ * `01125052692` و`(010) 1234-5678`. ويُصدَّر لأن التحقّق والحفظ
867
+ * يحتاجانه خارج العرض.
868
+ */
869
+ declare function parsePhone(raw: string, defaultDial?: string): PhoneParts;
870
+ /**
871
+ * صيغة الفواصل بين المجموعات.
872
+ *
873
+ * `parens` الافتراضيّة: `(101) 234-5678`. القوس يفصل مقدّمة المشغّل
874
+ * عمّا بعدها، والشرطة تربط ما بقي. والفرق عن المسافات وحدها أن
875
+ * المسافة فاصل محايد لا يقول أيّ جزء هو أيّ شيء، بينما القوس يقول
876
+ * «هذا ليس من الرقم بل من المشغّل» — وهو ما يبحث عنه من يقارن رقمين.
877
+ *
878
+ * و`spaces` لمن يريد الصورة الدوليّة الخام: `101 234 5678`.
879
+ */
880
+ type PhoneFormat = 'parens' | 'spaces';
881
+ interface PhoneProps {
882
+ /** الرقم كما هو في البيانات — منسَّقاً أو خاماً */
883
+ value: string;
884
+ /** مفتاح يُفترض للأرقام المحلّيّة */
885
+ defaultDial?: string;
886
+ /** يُظهر آخر أربعة فقط */
887
+ mask?: boolean;
888
+ /** صيغة الفواصل — `parens` افتراضاً */
889
+ format?: PhoneFormat;
890
+ /** زرّ اتصال */
891
+ call?: boolean;
892
+ /** زرّ رسالة نصّيّة */
893
+ sms?: boolean;
894
+ /** زرّ واتساب */
895
+ whatsapp?: boolean;
896
+ /**
897
+ * `inherit` لا مقاس ولا وزن ولا لون — للرقم داخل صفّ يحدّد
898
+ * تنسيقه أصلاً: سطر ثانٍ تحت اسم عميل، أو سطر عنوان فرع.
899
+ * والمكوّن هناك للاتّجاه والتقطيع لا للحجم.
900
+ */
901
+ size?: 'inherit' | 'sm' | 'md';
902
+ className?: string;
903
+ }
904
+ /**
905
+ * رقم هاتف.
906
+ *
907
+ * ── الأرقام لاتينيّة دائماً ─────────────────────────────────────────────
908
+ * على عكس المبالغ. الهاتف **يُنسخ ويُطلَب**: يُلصق في تطبيق اتصال، ويُملى
909
+ * في مكالمة، ويُقارن بما على شاشة الجوّال. والأرقام العربيّة الهنديّة
910
+ * تكسر النسخ في تطبيقات لا تقبلها، وتجعل المقارنة بالشاشة الأخرى عملاً
911
+ * ذهنيّاً بلا مقابل.
912
+ *
913
+ * وهذا استثناء مقصود من قاعدة `[data-num]` — والفرق أن المبلغ يُقرأ
914
+ * والهاتف يُستعمل.
915
+ */
916
+ declare function Phone({ value, defaultDial, format, mask, call, sms, whatsapp, size, className, }: PhoneProps): react.JSX.Element;
917
+
918
+ /**
919
+ * القيم التقنية داخل واجهة عربية.
920
+ *
921
+ * `#C97B8E` في حقل عربي يُعرض `C97B8E#` — علامة الشباك تقفز للطرف
922
+ * الآخر، و`/shop` يصير `shop/`. السبب خوارزمية الاتجاه الثنائي (bidi):
923
+ * الرمز محايد الاتجاه، فيرث اتجاه الفقرة المحيطة به لا اتجاه قيمته.
924
+ *
925
+ * وهذا ليس تجميلاً: التاجر ينسخ القيمة فتُلصق مقلوبة، أو يحاول كتابتها
926
+ * فلا يعرف شكلها الصحيح. والألوان أوّل ما يُعدَّل في أيّ ثيم.
927
+ *
928
+ * العلاج ثلاث خصائص معاً — ولذلك مكوّن واحد لا ثلاثة أسطر تتكرّر:
929
+ * 1. `dir="ltr"` على الحقل نفسه — القيمة تُقرأ من اليسار.
930
+ * 2. `unicode-bidi: isolate` على الحاوية — الحقل لا يزحزح ترتيب ما
931
+ * حوله من نصّ عربي، ولا يتأثّر به.
932
+ * 3. المحاذاة إلى **يمين** الحقل في الصفحة العربية — لأن الحقل جزء من
933
+ * نموذج عربي، فحافّته المرئية تتبع الصفحة لا القيمة. وفي الصفحة
934
+ * الإنجليزية تعود يساراً وحدها.
935
+ *
936
+ * `[dir=rtl]_&` لا `rtl:` — لأن `dir="ltr"` موضوع على العنصر نفسه،
937
+ * فسمة `rtl:` لن تنطبق عليه أبداً؛ والاستعلام لا بدّ أن يسأل عن **جدّه**.
938
+ */
939
+ type TechnicalKind = 'hex' | 'url' | 'slug' | 'code' | 'id';
940
+ interface TechnicalInputProps extends Omit<InputProps, 'numeric' | 'type' | 'dir'> {
941
+ /** نوع القيمة — يضبط لوحة المفاتيح والتلميح فقط، لا يفرض تحقّقاً */
942
+ kind?: TechnicalKind;
943
+ }
944
+ declare const TechnicalInput: react.ForwardRefExoticComponent<TechnicalInputProps & react.RefAttributes<HTMLInputElement>>;
945
+ /**
946
+ * قيمة تقنية تُقرأ ولا تُحرَّر — رقم إصدار، اختصار لوحة مفاتيح، معرّف.
947
+ *
948
+ * نفس علّة الحقل: `⌘K` كان يُعرض `K ⌘`، ورقم الإصدار يتفكّك عند نقطته.
949
+ */
950
+ declare function TechnicalText({ children, className }: {
951
+ children: ReactNode;
952
+ className?: string;
953
+ }): react.JSX.Element;
954
+ /**
955
+ * مربّع لون + كود hex قابل للتحرير.
956
+ *
957
+ * المربّع هو `<input type="color">` الأصلي مخفيّاً خلفه — منتقي النظام
958
+ * أدقّ من أيّ عجلة مرسومة، ويعمل بلوحة المفاتيح دون كود.
959
+ *
960
+ * والوصف تحت التسمية مقصود: التوكن اسمه دوره لا رقمه. «الرئيسي المتوسط
961
+ * (حلقات وفواصل)» يقول للتاجر أين سيظهر اللون قبل أن يغيّره — وهذا ما
962
+ * يفرّق نظام ألوان يُفهَم عن أربعة وعشرين مربّعاً مرعبة.
963
+ */
964
+ declare function ColorField({ label, note, value, onChange, disabled, id: idProp, }: {
965
+ label: ReactNode;
966
+ /** دور اللون في الواجهة — لا اسمه التقني */
967
+ note?: ReactNode;
968
+ value: string;
969
+ onChange: (hex: string) => void;
970
+ disabled?: boolean;
971
+ id?: string;
972
+ }): react.JSX.Element;
973
+ /** يرجّع `#RRGGBB` بحروف كبيرة، أو `null` لو القيمة ليست لوناً بعد */
974
+ declare function normalizeHex(input: string): string | null;
975
+
976
+ interface Product3DViewerProps {
977
+ /** رابط الموديل — GLB أو GLTF */
978
+ src: string;
979
+ /**
980
+ * رابط USDZ — لـQuick Look في iOS.
981
+ *
982
+ * غيابه لا يُعطّل العارض، يُعطّل زرّ «شوفه في مكانك» على iPhone وحده:
983
+ * النظام هناك لا يقرأ GLB. وأندرويد يقرأ `src` نفسه.
984
+ */
985
+ iosSrc?: string;
986
+ /** صورة المنتج — تُرى قبل الموديل، وتبقى مكانه إن سقط */
987
+ poster: string;
988
+ /** وصف المنتج — يقرؤه قارئ الشاشة بدل المشهد */
989
+ alt: string;
990
+ /** دوران بطيء تلقائيّ. يتوقّف عند `prefers-reduced-motion` */
991
+ autoRotate?: boolean;
992
+ onLoad?: () => void;
993
+ onError?: (reason: string) => void;
994
+ /** لحظة الضغط على زرّ الواقع المعزّز — رأس القمع لا نهايته */
995
+ onARLaunch?: () => void;
996
+ className?: string;
997
+ }
998
+ /**
999
+ * عارض منتج مجسّم.
1000
+ *
1001
+ * ── والعنصر يُصنع بالـDOM لا بالـJSX ────────────────────────────────────
1002
+ * `<model-viewer>` عنصر مخصّص، ولا يُعرَّف إلّا بعد أن تصل الحزمة. فكتابته
1003
+ * في JSX تعني رسم وسمٍ مجهول ثمّ انتظار ترقيته — وبينهما إطارٌ يظهر فيه
1004
+ * صندوق بلا مقاس. وصنعه بعد `whenDefined` يجعله كامل السلوك من أوّل
1005
+ * لحظة يدخل فيها الصفحة.
1006
+ *
1007
+ * وفيه ربحٌ ثانٍ: أحداثه أحداث DOM مخصّصة (`progress` · `ar-status`)،
1008
+ * ولا يصلها JSX إلّا بجسر. هنا تُسمع كما هي.
1009
+ */
1010
+ declare function Product3DViewer({ src, iosSrc, poster, alt, autoRotate, onLoad, onError, onARLaunch, className, }: Product3DViewerProps): react.JSX.Element;
1011
+
1012
+ interface TabItem {
1013
+ key: string;
1014
+ label: ReactNode;
1015
+ count?: number;
1016
+ icon?: ComponentType<{
1017
+ size?: number;
1018
+ }>;
1019
+ }
1020
+ /**
1021
+ * `segmented` = مبدّل داخل حبّة رمادية (قناة البيع، شبكة/قايمة).
1022
+ * `pill` = فلاتر مستقلة بحدود (حالة الطلب، تصنيف المنتج).
1023
+ *
1024
+ * الفرق مقصود: الـsegmented بيقول «اختار واحد من دول»، والـpill بيقول
1025
+ * «فلتر شغّال». خلطهم بيخلّي التاجر مش عارف إيه اللي بيبدّل السياق
1026
+ * وإيه اللي بيفلتر.
1027
+ */
1028
+ declare function Tabs({ items, value, onChange, variant, label, className, }: {
1029
+ items: TabItem[];
1030
+ value: string;
1031
+ onChange: (key: string) => void;
1032
+ variant?: 'pill' | 'segmented';
1033
+ /** وصف المجموعة لقارئ الشاشة — «تصنيف السلات»، «حالة الطلب» */
1034
+ label?: string;
1035
+ className?: string;
1036
+ }): react.JSX.Element;
1037
+ interface FilterChip {
1038
+ label: string;
1039
+ onClear: () => void;
1040
+ }
1041
+ /**
1042
+ * الفلاتر المطبّقة كشرايح قابلة للإزالة.
1043
+ *
1044
+ * المنتج الحقيقي بيخبّي المطبّق جوّه القوايم المنسدلة، فالتاجر بيفتكر
1045
+ * الجدول فاضي وهو فلتره شغّال على حاجة. الشريحة بتخلّي الفلتر مرئي
1046
+ * وقابل للإلغاء بضغطة.
1047
+ */
1048
+ declare function FilterChips({ chips, onClearAll, label, clearAllLabel, }: {
1049
+ chips: FilterChip[];
1050
+ onClearAll?: () => void;
1051
+ label?: string;
1052
+ clearAllLabel?: string;
1053
+ }): react.JSX.Element | null;
1054
+
1055
+ /**
1056
+ * الـaction sheet — كل حاجة بتطلع من تحت على الموبايل.
1057
+ *
1058
+ * تفاصيل الشكل مقصودة: الخلفية بتغمق **وتتبلّر** فالمحتوى ورا بيرجع
1059
+ * بصرياً؛ راديوس ٢٤px فوق بس لأن الشيت طالع من حافة الشاشة؛ مقبض سحب
1060
+ * كإشارة متعارف عليها؛ و`env(safe-area-inset-bottom)` عشان آخر بند
1061
+ * ما يقعش تحت شريط الإيماءات في الأيفون.
1062
+ */
1063
+ declare function Sheet({ open, title, onClose, action, children, closeLabel, }: {
1064
+ open: boolean;
1065
+ title: string;
1066
+ onClose: () => void;
1067
+ action?: ReactNode;
1068
+ children: ReactNode;
1069
+ closeLabel?: string;
1070
+ }): react.JSX.Element | null;
1071
+ declare function Modal({ open, title, description, onClose, footer, children, size, closeLabel, }: {
1072
+ open: boolean;
1073
+ title: ReactNode;
1074
+ description?: ReactNode;
1075
+ onClose: () => void;
1076
+ footer?: ReactNode;
1077
+ children?: ReactNode;
1078
+ size?: 'sm' | 'md' | 'lg';
1079
+ closeLabel?: string;
1080
+ }): react.JSX.Element | null;
1081
+ /** بيفتح من inline-end — الشمال في العربي واليمين في الإنجليزي، لوحده */
1082
+ declare function Drawer({ open, title, description, onClose, footer, children, bodyClassName, closeLabel, }: {
1083
+ open: boolean;
1084
+ title: ReactNode;
1085
+ description?: ReactNode;
1086
+ onClose: () => void;
1087
+ footer?: ReactNode;
1088
+ children?: ReactNode;
1089
+ /** بديل حشوة الجسم — لقايمة بتمشي من حافة لحافة زي الإشعارات */
1090
+ bodyClassName?: string;
1091
+ closeLabel?: string;
1092
+ }): react.JSX.Element | null;
1093
+ declare function Alert({ tone, title, children, actions, }: {
1094
+ tone?: Tone;
1095
+ title?: ReactNode;
1096
+ children?: ReactNode;
1097
+ actions?: ReactNode;
1098
+ }): react.JSX.Element;
1099
+ declare function Toast({ children, action, icon, }: {
1100
+ children: ReactNode;
1101
+ action?: ReactNode;
1102
+ icon?: ReactNode;
1103
+ }): react.JSX.Element;
1104
+ /**
1105
+ * الحالة الفاضية مش زخرفة — هي أول شاشة التاجر الجديد بيشوفها، ولازم
1106
+ * يكون فيها إجراء واضح يطلّعه منها.
1107
+ */
1108
+ declare function EmptyState({ icon: Icon, title, description, action, }: {
1109
+ icon?: ComponentType<{
1110
+ size?: number;
1111
+ }>;
1112
+ title: ReactNode;
1113
+ description?: ReactNode;
1114
+ action?: ReactNode;
1115
+ }): react.JSX.Element;
1116
+
1117
+ type ToastTone = Extract<Tone, 'brand' | 'green' | 'amber' | 'red'> | 'neutral';
1118
+ interface ToastItem {
1119
+ id: number;
1120
+ tone: ToastTone;
1121
+ title: ReactNode;
1122
+ description?: ReactNode;
1123
+ /** نص زرار التراجع — لو موجود التوست بيستنى أطول */
1124
+ actionLabel?: string;
1125
+ onAction?: () => void;
1126
+ /** بالملي ثانية — `0` يعني ميختفيش لوحده */
1127
+ duration?: number;
1128
+ /** لودر بدل الأيقونة — لأفعال بتاخد وقت */
1129
+ pending?: boolean;
1130
+ }
1131
+ type ToastInput = Omit<ToastItem, 'id'>;
1132
+ declare function useToasts(): {
1133
+ toasts: ToastItem[];
1134
+ push: (input: ToastInput) => number;
1135
+ dismiss: (id: number) => void;
1136
+ update: (id: number, patch: Partial<ToastInput>) => void;
1137
+ clear: () => void;
1138
+ };
1139
+ /**
1140
+ * حاوية التوستات.
1141
+ *
1142
+ * ثابتة تحت في النص على الموبايل وتحت في الجنب على سطح المكتب —
1143
+ * بعيد عن الإبهام وبعيد عن الإجراء الأساسي في الشاشة.
1144
+ */
1145
+ declare function ToastHost({ toasts, onDismiss, closeLabel, }: {
1146
+ toasts: ToastItem[];
1147
+ onDismiss: (id: number) => void;
1148
+ closeLabel?: string;
1149
+ }): react.JSX.Element | null;
1150
+ /**
1151
+ * التولتيب.
1152
+ *
1153
+ * بيظهر على المرور **وعلى التركيز** — لو ظهر على المرور بس بيبقى مخفي
1154
+ * تماماً عن اللي بيتنقّل بالكيبورد. والمحتوى شرح إضافي مش معلومة
1155
+ * أساسية، لأن اللمس مالوش «مرور».
1156
+ */
1157
+ declare function Tooltip({ content, children, side, }: {
1158
+ content: ReactNode;
1159
+ children: ReactNode;
1160
+ side?: 'top' | 'bottom';
1161
+ }): react.JSX.Element;
1162
+
1163
+ interface Option {
1164
+ value: string;
1165
+ label: string;
1166
+ /** سطر تحت الاسم — سعر الشحن، عدد المنتجات… */
1167
+ meta?: string;
1168
+ icon?: ReactNode;
1169
+ disabled?: boolean;
1170
+ }
1171
+ declare function Dropdown({ label, value, onChange, options, placeholder, className, }: {
1172
+ label?: ReactNode;
1173
+ value: string | null;
1174
+ onChange: (value: string) => void;
1175
+ options: Option[];
1176
+ placeholder?: string;
1177
+ className?: string;
1178
+ }): react.JSX.Element;
1179
+ /**
1180
+ * فوق ١٥ خيار البحث بيبقى ضرورة مش رفاهية — التمرير في ٢٧ محافظة
1181
+ * أبطأ من كتابة حرفين.
1182
+ */
1183
+ declare function Combobox({ label, value, onChange, options, placeholder, searchPlaceholder, emptyText, className, }: {
1184
+ label?: ReactNode;
1185
+ value: string | null;
1186
+ onChange: (value: string) => void;
1187
+ options: Option[];
1188
+ placeholder?: string;
1189
+ searchPlaceholder?: string;
1190
+ emptyText?: string;
1191
+ className?: string;
1192
+ }): react.JSX.Element;
1193
+ declare function MultiSelect({ label, values, onChange, options, placeholder, createLabel, onCreate, className, }: {
1194
+ label?: ReactNode;
1195
+ values: string[];
1196
+ onChange: (values: string[]) => void;
1197
+ options: Option[];
1198
+ placeholder?: string;
1199
+ /** نص زرار «أضف …» لما البحث مالوش نتيجة */
1200
+ createLabel?: (query: string) => string;
1201
+ onCreate?: (query: string) => void;
1202
+ className?: string;
1203
+ }): react.JSX.Element;
1204
+ interface CommandItem {
1205
+ id: string;
1206
+ title: string;
1207
+ meta?: string;
1208
+ icon?: ReactNode;
1209
+ group: string;
1210
+ onRun?: () => void;
1211
+ }
1212
+ /**
1213
+ * لوحة الأوامر — ⌘K.
1214
+ *
1215
+ * الفرق عن Combobox إنها **مش حقل اختيار**: بتلاقي وتنفّذ عبر كل المنتج،
1216
+ * فالنتايج متجمّعة بمصدرها (منتجات، طلبات، إعدادات) مش قايمة مسطّحة.
1217
+ */
1218
+ declare function CommandPalette({ open, onClose, items, placeholder, emptyText, }: {
1219
+ open: boolean;
1220
+ onClose: () => void;
1221
+ items: CommandItem[];
1222
+ placeholder?: string;
1223
+ emptyText?: string;
1224
+ }): react.JSX.Element | null;
1225
+
1226
+ interface AccordionItem {
1227
+ key: string;
1228
+ title: ReactNode;
1229
+ description?: ReactNode;
1230
+ icon?: ComponentType<{
1231
+ size?: number;
1232
+ }>;
1233
+ children: ReactNode;
1234
+ }
1235
+ /**
1236
+ * الأكورديون.
1237
+ *
1238
+ * الافتراضي `single` — واحد مفتوح في المرة. ده مقصود في الإعدادات: لما
1239
+ * كل الأقسام تفتح مع بعض الصفحة بترجع تبقى قايمة طويلة والأكورديون
1240
+ * بيفقد فايدته. `multiple` للأسئلة الشائعة اللي القارئ بيقارن فيها.
1241
+ */
1242
+ declare function Accordion({ items, mode, defaultOpen, className, }: {
1243
+ items: AccordionItem[];
1244
+ mode?: 'single' | 'multiple';
1245
+ defaultOpen?: string[];
1246
+ className?: string;
1247
+ }): react.JSX.Element;
1248
+ interface TimelineStep {
1249
+ key: string;
1250
+ title: ReactNode;
1251
+ time?: ReactNode;
1252
+ note?: ReactNode;
1253
+ tone?: Tone;
1254
+ }
1255
+ /**
1256
+ * الخط الزمني — تتبّع الطلب.
1257
+ *
1258
+ * الخطوات قبل `current` مكتملة، و`current` هي الشغّالة، واللي بعدها
1259
+ * لسه. الخط الواصل بيتلوّن للمكتمل بس — ده اللي بيخلّي التاجر يقرا
1260
+ * «فين وصلنا» من غير ما يقرا كلمة.
1261
+ */
1262
+ declare function Timeline({ steps, current, nowLabel, className, }: {
1263
+ steps: TimelineStep[];
1264
+ /** فهرس الخطوة الشغّالة */
1265
+ current: number;
1266
+ /** تسمية الخطوة الحالية — تُترجم من التطبيق */
1267
+ nowLabel?: string;
1268
+ className?: string;
1269
+ }): react.JSX.Element;
1270
+ interface StepperStep {
1271
+ key: string;
1272
+ title: ReactNode;
1273
+ }
1274
+ /**
1275
+ * الستيبر — خطوات الإنشاء.
1276
+ *
1277
+ * الفرق عن `Timeline`: ده **أفقي وقابل للنقر** لأنه بيمثّل مهمة التاجر
1278
+ * نفسه (كمّل إعداد متجرك)، مش حدث حصل بره سيطرته (وصل الشحن فين).
1279
+ */
1280
+ declare function Stepper({ steps, done, onPick, className, }: {
1281
+ steps: StepperStep[];
1282
+ /** مفاتيح الخطوات المكتملة */
1283
+ done: string[];
1284
+ onPick?: (key: string) => void;
1285
+ className?: string;
1286
+ }): react.JSX.Element;
1287
+
1288
+ interface Column<T> {
1289
+ key: string;
1290
+ header: ReactNode;
1291
+ cell: (row: T) => ReactNode;
1292
+ /** يحاذي لنهاية العمود — للأرقام والإجراءات */
1293
+ end?: boolean;
1294
+ }
1295
+ interface DataTableProps<T> {
1296
+ columns: Column<T>[];
1297
+ rows: T[];
1298
+ rowKey: (row: T) => string;
1299
+ /** شبكة CSS للأعمدة، مثال: `34px_2.4fr_1fr_minmax(150px,168px)` */
1300
+ grid: string;
1301
+ /** أقل عرض قبل ما يبدأ التمرير الأفقي جوّه الكرت */
1302
+ minWidth: number;
1303
+ onRowClick?: (row: T) => void;
1304
+ /** بديل الجدول تحت md — الجدول العريض مش مقروء على ٣٩٠px */
1305
+ mobileCard?: (row: T) => ReactNode;
1306
+ empty?: ReactNode;
1307
+ footer?: ReactNode;
1308
+ /**
1309
+ * عدد الصفوف في الصفحة — بيشغّل الترقيم.
1310
+ *
1311
+ * أُغفل = كل الصفوف تُعرض، وهذا هو الافتراض: أغلب جداول اللوحة
1312
+ * عشرة صفوف أو أقلّ، والترقيم عليها يضيف عنصر تحكّم بلا وظيفة.
1313
+ */
1314
+ pageSize?: number;
1315
+ /** ما يُكتب حول أرقام الصفحة — «طلب»، «منتج» */
1316
+ unit?: string;
1317
+ className?: string;
1318
+ }
1319
+ /**
1320
+ * جدول بيانات.
1321
+ *
1322
+ * التمرير الأفقي **جوّه الكرت** مش على الصفحة — الصفحة نفسها عمرها ما
1323
+ * بتفيض. ولو اتحدّد `mobileCard` بيتحوّل لقايمة كروت تحت md، لأن جدول
1324
+ * بـ٦ أعمدة على ٣٩٠px بيخبّي أهم عمود ورا التمرير.
1325
+ */
1326
+ declare function DataTable<T>({ columns, rows, rowKey, grid, minWidth, onRowClick, mobileCard, empty, footer, pageSize, unit, className, }: DataTableProps<T>): react.JSX.Element;
1327
+
1328
+ interface StarsProps {
1329
+ /** عدد النجوم المضيئة — بيتقصّ بين ٠ و٥ */
1330
+ value: number;
1331
+ /** ضلع النجمة بالبكسل */
1332
+ size?: number;
1333
+ className?: string;
1334
+ }
1335
+ /**
1336
+ * عرض التقييم.
1337
+ *
1338
+ * ── الرقم لقارئ الشاشة والنجوم للعين ────────────────────────────────────
1339
+ * الشكل وحده ما يُنطق: خمس أيقونات متتالية بتتقري «صورة صورة صورة صورة
1340
+ * صورة» أو ما تتقريش خالص. فالنجوم `aria-hidden` والرقم في `sr-only`.
1341
+ *
1342
+ * و`4 / 5` بأرقام لاتينية ومحارف لاتينية عن قصد — النسبة مش جملة تُترجم،
1343
+ * وقارئ الشاشة العربي بينطقها صح.
1344
+ */
1345
+ declare function Stars({ value, size, className }: StarsProps): react.JSX.Element;
1346
+ interface RatingInputProps {
1347
+ value: number;
1348
+ onChange: (value: number) => void;
1349
+ disabled?: boolean;
1350
+ /** يُخفي «٤/٥» جنب النجوم */
1351
+ hideValue?: boolean;
1352
+ className?: string;
1353
+ }
1354
+ /**
1355
+ * إدخال التقييم.
1356
+ *
1357
+ * ── خمسة أزرار لا قائمة منسدلة ──────────────────────────────────────────
1358
+ * القائمة بتعرض «٣» وبتسيب النجوم في رأس القارئ. والأزرار بتعرض **اللي
1359
+ * العميل هيشوفه** بالظبط.
1360
+ *
1361
+ * ── وهدف الضغط ٣٦ لا ١٣ ─────────────────────────────────────────────────
1362
+ * النجمة المرسومة ٢٢ بكسل، والزرّ حواليها `size-9`. الرسم الصغير مايمنعش
1363
+ * الهدف الكبير — والإبهام مابيصيبش ١٣ بكسل.
1364
+ *
1365
+ * ── ولا يُفرَّغ بإعادة الضغط ─────────────────────────────────────────────
1366
+ * الضغط على النجمة المختارة بيأكّدها لا بيلغيها. «صفر نجوم» مش تقييم،
1367
+ * ومن ضغط عليها تاني كان بيقصد يتأكّد.
1368
+ */
1369
+ declare function RatingInput({ value, onChange, disabled, hideValue, className }: RatingInputProps): react.JSX.Element;
1370
+
1371
+ interface Range {
1372
+ from: Date | null;
1373
+ to: Date | null;
1374
+ }
1375
+ declare function daysBetween(from: Date, to: Date): number;
1376
+ declare function formatDate(d: Date): string;
1377
+ declare function formatRange(r: Range): string;
1378
+ /** اختصارات جاهزة — دي اللي التاجر بيستخدمها ٩٠٪ من الوقت */
1379
+ declare function presets(today: Date): {
1380
+ key: string;
1381
+ label: string;
1382
+ range: Range;
1383
+ }[];
1384
+ declare function DateRangePicker({ value, onChange, month, onMonthChange, today, className, }: {
1385
+ value: Range;
1386
+ onChange: (range: Range) => void;
1387
+ /** الشهر المعروض — أول يوم فيه */
1388
+ month: Date;
1389
+ onMonthChange: (month: Date) => void;
1390
+ /** «النهارده» بيتحدّد من برّه عشان الديمو يفضل ثابت */
1391
+ today: Date;
1392
+ className?: string;
1393
+ }): react.JSX.Element;
1394
+
1395
+ type UploadState = 'uploading' | 'done' | 'rejected';
1396
+ interface UploadFile {
1397
+ id: string;
1398
+ name: string;
1399
+ /** بالبايت */
1400
+ size: number;
1401
+ state: UploadState;
1402
+ /** ٠ لـ١٠٠ — بيتعرض بس وقت الرفع */
1403
+ progress?: number;
1404
+ /** سبب الرفض — لازم يتكتب، «فشل» لوحدها مش معلومة */
1405
+ error?: string;
1406
+ /** رابط معاينة (object URL أو data URI) */
1407
+ preview?: string;
1408
+ }
1409
+ declare function formatBytes(bytes: number): string;
1410
+ declare function Dropzone({ onFiles, accept, multiple, disabled, title, hint, buttonLabel, className, }: {
1411
+ onFiles: (files: File[]) => void;
1412
+ accept?: string;
1413
+ multiple?: boolean;
1414
+ disabled?: boolean;
1415
+ title?: ReactNode;
1416
+ hint?: ReactNode;
1417
+ buttonLabel?: string;
1418
+ className?: string;
1419
+ }): react.JSX.Element;
1420
+ declare function FileRow({ file, onRemove, coverLabel, isCover, }: {
1421
+ file: UploadFile;
1422
+ onRemove?: () => void;
1423
+ /** شارة «الغلاف» على أول صورة */
1424
+ coverLabel?: string;
1425
+ isCover?: boolean;
1426
+ }): react.JSX.Element;
1427
+
1428
+ interface UseSortableOptions {
1429
+ /** عدد العناصر — لازم يطابق اللي بيتعرض */
1430
+ count: number;
1431
+ /** يتنادى مرّة واحدة عند الإفلات، وبالفهرسين النهائيين */
1432
+ onMove: (from: number, to: number) => void;
1433
+ disabled?: boolean;
1434
+ /**
1435
+ * مسافة التفعيل بالبكسل.
1436
+ *
1437
+ * تحتها الضغطة ضغطة لا سحب — بدونها كل نقرة على بند فيها اهتزاز
1438
+ * إصبع بتبدأ سحبة، والبند اللي بيُنقر عليه بيتحرّك تحت المؤشّر.
1439
+ */
1440
+ threshold?: number;
1441
+ /** اسم البند لقارئ الشاشة — «البانر الرئيسي» */
1442
+ itemLabel?: (index: number) => string;
1443
+ }
1444
+ interface SortableItemProps {
1445
+ ref: (el: HTMLElement | null) => void;
1446
+ style: CSSProperties;
1447
+ onPointerDown: (e: PointerEvent<HTMLElement>) => void;
1448
+ onKeyDown: (e: KeyboardEvent<HTMLElement>) => void;
1449
+ tabIndex: number;
1450
+ 'aria-roledescription': string;
1451
+ 'data-dragging'?: string;
1452
+ 'data-grabbed'?: string;
1453
+ }
1454
+ interface SortableApi {
1455
+ /** خصائص البند رقم `index` */
1456
+ item: (index: number) => SortableItemProps;
1457
+ /** الفهرس المسحوب الآن — `null` لو مافيش سحب */
1458
+ dragging: number | null;
1459
+ /** الفهرس الممسوك بالكيبورد */
1460
+ grabbed: number | null;
1461
+ /** الفهرس اللي البند هيقع فيه */
1462
+ over: number | null;
1463
+ /** نص يُعرض في منطقة حيّة — الشرح عند `SortableStatus` */
1464
+ message: string;
1465
+ }
1466
+ declare function useSortable({ count, onMove, disabled, threshold, itemLabel, }: UseSortableOptions): SortableApi;
1467
+ /**
1468
+ * المنطقة الحيّة.
1469
+ *
1470
+ * قارئ الشاشة مابيشوفش البند وهو بيتحرّك، فلازم حد يقول له «انتقل
1471
+ * للموضع الثالث من سبعة». ومكانها خارج القائمة عشان إعادة ترتيب
1472
+ * القائمة ماتلغيش النطق في نصّه.
1473
+ */
1474
+ declare function SortableStatus({ message }: {
1475
+ message: string;
1476
+ }): react.JSX.Element;
1477
+
1478
+ interface CarouselProps {
1479
+ /** اسم العارض — يقوله قارئ الشاشة قبل الشرائح */
1480
+ label: string;
1481
+ children: ReactNode;
1482
+ /**
1483
+ * عدد الشرائح المرئيّة. الكسر مقصود ومفيد: `1.15` يُظهر طرف التالية
1484
+ * فيُقرأ «هنا المزيد» بلا سهم ولا نقطة.
1485
+ *
1486
+ * ── والاستجابة للمقاس تُكتب بالأصناف لا بهذه ──────────────────────
1487
+ * تمريرها يطبع `--per` في `style`، والسطريّ يغلب كل صنف — بما فيه
1488
+ * `lg:[--per:3]`. فللعارض المتجاوب: اتركها، واكتب
1489
+ * `className="sm:[--per:2] lg:[--per:3]"`.
1490
+ */
1491
+ perView?: number;
1492
+ /** الفراغ بين الشرائح بالبكسل — من سلّم الأربعة */
1493
+ gap?: number;
1494
+ /** أسهم على حافّتَي المسار */
1495
+ arrows?: boolean;
1496
+ /** نقطة لكل شريحة */
1497
+ dots?: boolean;
1498
+ /** عدّاد «٣ / ١٢» */
1499
+ counter?: boolean;
1500
+ /**
1501
+ * تشغيل تلقائيّ كل كذا مِلّي.
1502
+ *
1503
+ * يقف على المرور وعلى التركيز وعلى إخفاء التبويب، ولا يبدأ أصلاً عند
1504
+ * `prefers-reduced-motion`. ووجوده يفرض زرّ إيقاف ظاهراً — المعيار
1505
+ * 2.2.2 يشترط أن يملك المستخدم إيقاف ما يتحرّك وحده لأكثر من خمس
1506
+ * ثوانٍ، لا أن يُلاحقه.
1507
+ */
1508
+ autoplay?: number;
1509
+ /** الشريحة النشطة — للتحكّم من برّه (شريط المصغّرات مثلاً) */
1510
+ index?: number;
1511
+ onIndexChange?: (index: number) => void;
1512
+ className?: string;
1513
+ /** أصناف على المسار نفسه — للحشو الذي يجب أن يتمرّر مع الشرائح */
1514
+ trackClassName?: string;
1515
+ }
1516
+ /**
1517
+ * عارض شرائح أفقيّ.
1518
+ *
1519
+ * ── ولا سحب بالفأرة ─────────────────────────────────────────────────────
1520
+ * محاكاة السحب تتطلّب ابتلاع `pointerdown` ثمّ تخمين: هل هذه سحبة أم
1521
+ * ضغطة؟ والتخمين يخطئ في الاتجاهين — فيبتلع ضغطة على زرّ داخل الشريحة،
1522
+ * أو يبدأ تحديد نصّ في منتصف السحب. ولوحة اللمس والشاشة اللامسة
1523
+ * تمرّران أصلاً، ويبقى الفأر وحده — وله السهمان.
1524
+ */
1525
+ declare function Carousel({ label, children, perView, gap, arrows, dots, counter, autoplay, index, onIndexChange, className, trackClassName, }: CarouselProps): react.JSX.Element;
1526
+ interface GalleryImage {
1527
+ src: string;
1528
+ /** وصف الصورة — فارغاً إن كانت زخرفةً بحتة */
1529
+ alt: string;
1530
+ }
1531
+ interface GalleryProps {
1532
+ label: string;
1533
+ images: GalleryImage[];
1534
+ /** نسبة العرض إلى الارتفاع — «4/3» · «1/1» · «16/9» */
1535
+ ratio?: string;
1536
+ /**
1537
+ * `cover` يملأ الإطار ويقصّ، و`contain` يُظهر الصورة كاملةً ويترك فراغاً.
1538
+ *
1539
+ * الافتراضيّ `cover` لأن صور المنتج تُلتقط بنسب مختلفة، وشبكةٌ من
1540
+ * إطارات متساوية تُقرأ كتالوجاً بينما الأخرى تُقرأ ملفّات مرفوعة.
1541
+ */
1542
+ fit?: 'cover' | 'contain';
1543
+ /** شريط المصغّرات تحت الصورة */
1544
+ thumbs?: boolean;
1545
+ /** الضغط على الصورة يفتح العارض الكامل */
1546
+ zoom?: boolean;
1547
+ className?: string;
1548
+ }
1549
+ /**
1550
+ * معرض صور — صورة كبيرة ومصغّرات تحتها.
1551
+ *
1552
+ * ── لماذا المصغّرات لا النقاط ───────────────────────────────────────────
1553
+ * النقطة تقول «أنت في الثالثة من ثمانٍ» ولا تقول ما في الثالثة. والصور
1554
+ * محتواها هو هويّتها — فالمصغّرة تُغني عن التنقّل بحثاً: من يريد اللون
1555
+ * الأزرق يراه ويضغطه، لا يمرّ على الأحمر في طريقه إليه.
1556
+ *
1557
+ * وتبقى النقاط خياراً لمَن صوره متشابهة (لقطات شاشة لشيء واحد) —
1558
+ * `thumbs={false}` يستبدل بها نقاطاً.
1559
+ */
1560
+ declare function Gallery({ label, images, ratio, fit, thumbs, zoom, className, }: GalleryProps): react.JSX.Element | null;
1561
+ interface LightboxProps {
1562
+ open: boolean;
1563
+ images: GalleryImage[];
1564
+ index: number;
1565
+ onIndexChange: (index: number) => void;
1566
+ onClose: () => void;
1567
+ label?: string;
1568
+ closeLabel?: string;
1569
+ }
1570
+ /**
1571
+ * صورة على ملء الشاشة.
1572
+ *
1573
+ * ── و`contain` هنا دائماً ───────────────────────────────────────────────
1574
+ * المعرض يقصّ ليصطفّ، وهذا يُفتح ليُرى — والقصّ في الموضع الذي فُتح
1575
+ * لأجله يُلغي سبب فتحه.
1576
+ *
1577
+ * ── ولا قفل للتمرير ─────────────────────────────────────────────────────
1578
+ * `tokens.css` يضع `overflow: hidden` على `body` أصلاً، فصفحة قمرة لا
1579
+ * تتمرّر خلف الطبقة. القفل هنا كان سيكون احتياطاً من شيء غير قائم.
1580
+ */
1581
+ declare function Lightbox({ open, images, index, onIndexChange, onClose, label, closeLabel }: LightboxProps): react.JSX.Element | null;
1582
+
1583
+ /**
1584
+ * إطار المتصفّح.
1585
+ *
1586
+ * المعاينة بلا إطار بتتقري **جزءاً من اللوحة**: التاجر بيشوف بانراً
1587
+ * وشبكة منتجات جوّه صندوق أبيض، فبيحكم عليها كأنها عنصر في شاشة
1588
+ * الإعدادات. والإطار بيقول جملة واحدة قبل أي شيء: «ده متجرك كما يراه
1589
+ * الزائر» — فيتبدّل الحكم من «شكل الصندوق ده حلو؟» إلى «متجري كده
1590
+ * كويس؟».
1591
+ *
1592
+ * ── والنقط الثلاث رمادية لا ملوّنة ──────────────────────────────────────
1593
+ * أحمر وأصفر وأخضر تقليد شكليّ لنافذة ماك، وفي نظام اللون فيه **للحالة**
1594
+ * بس: الأخضر «تمّ» والأصفر «انتبه» والأحمر «خطر». تلات نقط بالألوان دي
1595
+ * فوق معاينة متجر بتقول تلات حالات مالهاش أي معنى هنا، والعين بتفحصها
1596
+ * قبل ما تكتشف إنها زخرفة. فالنقط بلون الحدّ: بتقول «نافذة» وبتسكت.
1597
+ *
1598
+ * ── والقياس الحقيقي مصغَّراً ─────────────────────────────────────────────
1599
+ * `contentWidth` بيخلّي الصفحة **تتبني** على عرضها الحقيقي (١٤٤٠ مثلاً)
1600
+ * وتتعرض مصغّرة عشان تدخل في المساحة المتاحة. ده مش تفصيلة تجميل: من
1601
+ * غيره الصفحة بتتبني على عرض اللوحة — ٩٠٠ بكسل — فبتتكسّر نقاط التوقّف
1602
+ * ويشوف التاجر تخطيط تابلت وهو فاكر إنه بيراجع الديسكتوب.
1603
+ */
1604
+ interface BrowserFrameProps {
1605
+ /** الرابط في شريط العنوان — بلا بروتوكول، الشكل بيقوله */
1606
+ url: string;
1607
+ /** `mobile` بيرسم إطار جهاز بدل نافذة */
1608
+ device?: 'desktop' | 'mobile';
1609
+ /** اسم التبويب — بيرسم شريط تبويبات فوق شريط العنوان */
1610
+ tab?: string;
1611
+ /** أزرار الرجوع والتقدّم — معطّلة، لأنها معاينة مالهاش تاريخ */
1612
+ nav?: boolean;
1613
+ /** شريط تقدّم رفيع تحت شريط العنوان */
1614
+ loading?: boolean;
1615
+ /**
1616
+ * عرض المحتوى الحقيقي بالبكسل.
1617
+ *
1618
+ * لمّا يتحدّد، المحتوى بيتبني عليه ويتعرض مصغّراً — فنقاط التوقّف
1619
+ * بتشتغل زي ما هي على شاشة الزائر.
1620
+ */
1621
+ contentWidth?: number;
1622
+ /** نسبة التصغير الفعلية بعد الحساب — للعرض جنب المعاينة */
1623
+ onScale?: (scale: number) => void;
1624
+ onReload?: () => void;
1625
+ /** المحتوى — لو الصفحة بتتمرّر، حطّ حاوية التمرير هنا */
1626
+ children: ReactNode;
1627
+ className?: string;
1628
+ }
1629
+ declare function BrowserFrame({ url, device, tab, nav, loading, contentWidth, onScale, onReload, children, className, }: BrowserFrameProps): react.JSX.Element;
1630
+
1631
+ interface BarSeries {
1632
+ label: string;
1633
+ values: number[];
1634
+ /** السلسلة المرجعية — تُرسم بتدرّج أفتح خلف الأساسية */
1635
+ muted?: boolean;
1636
+ }
1637
+ /**
1638
+ * الأعمدة — للمقارنة بين فترات أو فئات معدودة.
1639
+ *
1640
+ * السلسلتان جنب بعضهما لا فوق بعض: التكديس يخفي أن أحدهما تراجع
1641
+ * حين يرتفع الآخر.
1642
+ */
1643
+ declare function BarChart({ labels, series, height, formatValue, className, }: {
1644
+ labels: string[];
1645
+ series: BarSeries[];
1646
+ height?: number;
1647
+ formatValue?: (v: number) => string;
1648
+ className?: string;
1649
+ }): react.JSX.Element;
1650
+ /**
1651
+ * خطّ الاتجاه — للسلاسل الطويلة التي تُقرأ كشكل لا كقيم.
1652
+ *
1653
+ * ثلاث علامات على المحور الرأسي فقط. الشبكة الكثيفة تُقرأ كضجيج،
1654
+ * والقيمة الدقيقة مكانها الجدول لا الرسم.
1655
+ */
1656
+ declare function TrendChart({ labels, values, compare, pointLabels, mode, height, formatValue, compareLabel, className, }: {
1657
+ /** علامات المحور — ثلاث أو أربع، لا واحدة لكل نقطة */
1658
+ labels: string[];
1659
+ values: number[];
1660
+ /** الفترة السابقة — تُرسم خطاً باهتاً بلا تعبئة */
1661
+ compare?: number[];
1662
+ /**
1663
+ * اسم كل نقطة — واحد لكل قيمة، للتلميح ولقارئ الشاشة.
1664
+ *
1665
+ * منفصل عن `labels` عمداً: تلك علامات محور متباعدة («قبل ٣٠ يوماً»
1666
+ * · «قبل ١٥» · «اليوم») وعددها ثلاثة بينما النقاط ثلاثون. الخلط
1667
+ * بينهما يجعل التلميح يعرض `undefined` عند كل نقطة بعد الثالثة.
1668
+ */
1669
+ pointLabels?: string[];
1670
+ /** مساحة أو أعمدة — التبديل بينهما يخصّ الصفحة لا الرسم */
1671
+ mode?: 'area' | 'bars';
1672
+ height?: number;
1673
+ formatValue?: (v: number) => string;
1674
+ /** اسم سلسلة المقارنة في التلميح */
1675
+ compareLabel?: string;
1676
+ className?: string;
1677
+ }): react.JSX.Element;
1678
+ interface FunnelStage {
1679
+ key: string;
1680
+ label: string;
1681
+ value: number;
1682
+ /** ماذا يعني التسرّب هنا وما العمل — يُعرض عند أكبر تسرّب */
1683
+ advice?: string;
1684
+ }
1685
+ /**
1686
+ * قمع الشراء.
1687
+ *
1688
+ * أهمّ ما فيه ليس المراحل بل **أكبر تسرّب**: هو المكان الوحيد الذي
1689
+ * يستحقّ عمل هذا الأسبوع. لذلك يُحسب ويُعلَّم ويُشرح، والباقي يبقى
1690
+ * محايداً حتى لا يزاحمه.
1691
+ */
1692
+ declare function FunnelChart({ stages, formatValue, className, }: {
1693
+ stages: FunnelStage[];
1694
+ formatValue?: (v: number) => string;
1695
+ className?: string;
1696
+ }): react.JSX.Element;
1697
+ /**
1698
+ * الخريطة الحرارية — متى يشتري الناس.
1699
+ *
1700
+ * أربع درجات من لون واحد لا تدرّج مستمر: العين لا تفرّق بين ٦٠٪ و٦٥٪
1701
+ * من الشدّة، وأربع فئات تُقرأ فوراً.
1702
+ */
1703
+ declare function Heatmap({ rows, cols, values, formatCell, lowLabel, highLabel, className, }: {
1704
+ rows: string[];
1705
+ cols: string[];
1706
+ /** values[rowIndex][colIndex] */
1707
+ values: number[][];
1708
+ formatCell?: (v: number, row: string, col: string) => string;
1709
+ lowLabel?: string;
1710
+ highLabel?: string;
1711
+ className?: string;
1712
+ }): react.JSX.Element;
1713
+ interface ShareItem {
1714
+ key: string;
1715
+ label: ReactNode;
1716
+ value: number;
1717
+ /** سطر ثانٍ تحت الاسم — في `stacked` فقط */
1718
+ meta?: ReactNode;
1719
+ /**
1720
+ * ما يُكتب في الطرف المقابل بدل الرقم المنسَّق.
1721
+ *
1722
+ * في `stacked` يظهر **قبل** الرقم؛ وفي `inline` يحلّ محلّه — لأن
1723
+ * الصفّ المضغوط ليس فيه مكان لرقمين ونسبة.
1724
+ */
1725
+ trailing?: ReactNode;
1726
+ /** لون الشريط — الافتراضي لون العلامة */
1727
+ tone?: 'brand' | 'amber' | 'red' | 'muted';
1728
+ }
1729
+ /**
1730
+ * قائمة بحصص — للفئات المرتّبة (المصادر، المنتجات، المدن).
1731
+ *
1732
+ * أفضل من الدائرة: الدائرة تجعل مقارنة شريحتين متقاربتين مستحيلة،
1733
+ * والقائمة مرتّبة أصلاً فالترتيب نفسه معلومة.
1734
+ *
1735
+ * ── تخطيطان لا واحد ────────────────────────────────────────────────────
1736
+ * `stacked` للقائمة التي هي **محتوى الكرت**: الاسم والرقم في سطر
1737
+ * والشريط تحتهما، فيتّسع لاسم طويل وسطر وصف.
1738
+ *
1739
+ * `inline` للقائمة التي هي **جزء من كرت**: الاسم والشريط والرقم في صفّ
1740
+ * واحد بارتفاع سطر. توزيع النجوم بجانب متوسّط التقييم لا يحتمل ثلاثة
1741
+ * أسطر لكل نجمة.
1742
+ *
1743
+ * الاثنان وُلدا من شاشتين قائمتين كانتا ترسمان أشرطتهما بأنفسهما —
1744
+ * لا من تخيّل استعمالات.
1745
+ */
1746
+ declare function ShareList({ items, total, layout, showPercent, labelWidth, formatValue, className, }: {
1747
+ items: ShareItem[];
1748
+ /** المجموع الذي تُحسب عليه النسبة — الافتراضي مجموع العناصر */
1749
+ total?: number;
1750
+ layout?: 'stacked' | 'inline';
1751
+ /** النسبة المئوية بجانب الرقم — أطفئها حين يكون العدد نفسه هو المعنى */
1752
+ showPercent?: boolean;
1753
+ /** عرض عمود الاسم في `inline` — ثابت حتى تصطفّ الأشرطة تحت بعضها */
1754
+ labelWidth?: string;
1755
+ /**
1756
+ * `ReactNode` لا `string` — بخلاف `TrendChart`.
1757
+ *
1758
+ * هناك القيمة بتروح جوّه `title=` وهي سمة نصّية، وهنا بتترسم في
1759
+ * الصفحة — فبتقبل عنصراً، و`Money` بيقدر يدخل.
1760
+ */
1761
+ formatValue?: (v: number) => ReactNode;
1762
+ className?: string;
1763
+ }): react.JSX.Element;
1764
+
1765
+ interface WaterfallStep {
1766
+ key: string;
1767
+ label: ReactNode;
1768
+ /** موجب يزيد، وسالب ينقص */
1769
+ value: number;
1770
+ /** سطر يشرح الخصم — «٤٪ عمولة بوّابة الدفع» */
1771
+ meta?: ReactNode;
1772
+ }
1773
+ declare function WaterfallChart({ total, steps, totalLabel, netLabel, formatValue, className, }: {
1774
+ /** نقطة البداية — إجمالي المبيعات قبل أي خصم */
1775
+ total: number;
1776
+ /** الخصومات بقيم سالبة، والإضافات بموجبة */
1777
+ steps: WaterfallStep[];
1778
+ totalLabel?: ReactNode;
1779
+ netLabel?: ReactNode;
1780
+ formatValue?: (v: number) => ReactNode;
1781
+ className?: string;
1782
+ }): react.JSX.Element;
1783
+ /**
1784
+ * الفعليّ مقابل الهدف على مسطرة واحدة.
1785
+ *
1786
+ * ── لماذا شريط لا دائرة ────────────────────────────────────────────────
1787
+ * الدائرة تعرض نسبة، والنسبة وحدها لا تكفي: «٦٨٪ من الهدف» في اليوم
1788
+ * الخامس ممتاز، وفي اليوم الثامن والعشرين كارثة. الشريط يحمل **علامتين**
1789
+ * — الهدف ومقدار ما مضى من الشهر — فيُقرأ الموقف لا الرقم.
1790
+ */
1791
+ declare function GoalBar({ value, goal,
1792
+ /** ما مضى من المدّة ٠–١ — تُرسم كعلامة «المفروض تكون هنا» */
1793
+ pace, label, formatValue, className, }: {
1794
+ value: number;
1795
+ goal: number;
1796
+ pace?: number;
1797
+ label?: ReactNode;
1798
+ formatValue?: (v: number) => string;
1799
+ className?: string;
1800
+ }): react.JSX.Element;
1801
+ interface ParetoItem {
1802
+ key: string;
1803
+ label: ReactNode;
1804
+ value: number;
1805
+ }
1806
+ /**
1807
+ * كم صنفاً يصنع معظم المبيعات.
1808
+ *
1809
+ * ── ما يقوله ولا يقوله `ShareList` ─────────────────────────────────────
1810
+ * `ShareList` يقول «إنستجرام ٤٠٪». وباريتو يقول «أربعة منتجات من ثلاثين
1811
+ * تصنع ٨٠٪ من دخلك» — وهذه جملة تُغيّر قرار الشراء والإعلان معاً.
1812
+ *
1813
+ * الفرق في الخطّ التراكميّ: يُقرأ من اليسار حتى يبلغ ٨٠٪، وعدد الأعمدة
1814
+ * تحته هو الجواب.
1815
+ */
1816
+ declare function ParetoChart({ items, height, threshold, formatValue, className, }: {
1817
+ items: ParetoItem[];
1818
+ height?: number;
1819
+ /** الخطّ الأفقيّ الذي يُقرأ عنده العدد — ٨٠٪ افتراضاً */
1820
+ threshold?: number;
1821
+ formatValue?: (v: number) => string;
1822
+ className?: string;
1823
+ }): react.JSX.Element;
1824
+ interface RunwayItem {
1825
+ key: string;
1826
+ label: ReactNode;
1827
+ /** ما في المخزن الآن */
1828
+ stock: number;
1829
+ /** متوسّط ما يُباع في اليوم */
1830
+ perDay: number;
1831
+ }
1832
+ /**
1833
+ * كم يوماً يكفي المخزون.
1834
+ *
1835
+ * ── لماذا بالأيام لا بالقطع ────────────────────────────────────────────
1836
+ * «٣ قطع» لا تقول شيئاً: ثلاث قطع من صنف يُباع مرّة في الشهر مخزون
1837
+ * فائض، ومن صنف يُباع خمساً في اليوم نفادٌ غداً. القسمة على معدّل
1838
+ * البيع تحوّل الرقم إلى **وقت**، والوقت هو ما يُتصرّف بناءً عليه.
1839
+ *
1840
+ * والترتيب بالأقرب نفاداً — أوّل سطر هو مكالمة المورّد اليوم.
1841
+ */
1842
+ declare function StockRunway({ items,
1843
+ /** ما دون هذا العدد من الأيام يُعلَّم أحمر */
1844
+ urgentDays,
1845
+ /** أقصى ما يُعرض على المسطرة — ما فوقه يبلغ الطرف */
1846
+ horizonDays, className, }: {
1847
+ items: RunwayItem[];
1848
+ urgentDays?: number;
1849
+ horizonDays?: number;
1850
+ className?: string;
1851
+ }): react.JSX.Element;
1852
+
1853
+ interface Chapter {
1854
+ /** بالثواني */
1855
+ at: number;
1856
+ title: string;
1857
+ }
1858
+ declare function Scrubber({ time, duration, buffered, onSeek, chapters, label, size, }: {
1859
+ time: number;
1860
+ duration: number;
1861
+ buffered?: number;
1862
+ onSeek: (to: number) => void;
1863
+ /** علامات على الشريط — فصول الدرس */
1864
+ chapters?: Chapter[];
1865
+ label?: string;
1866
+ size?: 'sm' | 'md';
1867
+ }): react.JSX.Element;
1868
+
1869
+ interface VideoSuggestion {
1870
+ id: string;
1871
+ title: string;
1872
+ poster?: string;
1873
+ /** المدة بالثواني — بتتعرض على الغلاف */
1874
+ duration?: number;
1875
+ onSelect: () => void;
1876
+ }
1877
+ interface VideoPlayerProps {
1878
+ src: string;
1879
+ /** صورة الغلاف قبل التشغيل */
1880
+ poster?: string;
1881
+ title?: string;
1882
+ /** فصول الدرس — علامات على الشريط */
1883
+ chapters?: Chapter[];
1884
+ /** ملف ترجمة WebVTT */
1885
+ captions?: string;
1886
+ /** مقاطع مقترحة — بتظهر قبل النهاية وبعدها */
1887
+ suggestions?: VideoSuggestion[];
1888
+ /**
1889
+ * كام ثانية قبل النهاية تبدأ الاقتراحات تبان.
1890
+ * الافتراضي ١٠ — أقل من كده مش كفاية للقراءة والاختيار، وأكتر
1891
+ * بيقطع آخر ربع المقطع وهو غالباً الخلاصة.
1892
+ */
1893
+ suggestAt?: number;
1894
+ autoPlay?: boolean;
1895
+ loop?: boolean;
1896
+ className?: string;
1897
+ }
1898
+ declare function VideoPlayer({ src, poster, title, chapters, captions, suggestions, suggestAt, autoPlay, loop, className, }: VideoPlayerProps): react.JSX.Element;
1899
+
1900
+ interface AudioPlayerProps {
1901
+ src: string;
1902
+ title?: string;
1903
+ /** سطر تحت العنوان — اسم الدرس، المدة، المتحدّث… */
1904
+ meta?: string;
1905
+ /** صورة مربّعة جنب العنوان */
1906
+ cover?: string;
1907
+ /** `row` صف مضغوط للقوايم · `card` كرت كامل بالموجة */
1908
+ variant?: 'card' | 'row';
1909
+ /**
1910
+ * عدد أعمدة الموجة.
1911
+ *
1912
+ * الافتراضي بيتحسب من العرض الفعلي فالكثافة البصرية تفضل واحدة في
1913
+ * أي مكان. حدّده بس لو عايز شكل مختلف عن كده عن قصد.
1914
+ */
1915
+ bars?: number;
1916
+ /**
1917
+ * مستوى الموجة عند الموضع الحالي — ٠ لـ١، بيتنادى مع كل إطار رسم.
1918
+ *
1919
+ * الرقم من **القمم المحسوبة من الملف** مش من الخرج الفعلي: يعني
1920
+ * مابيحسّش بمستوى الصوت ولا الكتم، بس تكلفته صفر لأن الداتا موجودة
1921
+ * أصلاً للموجة. لو محتاج الخرج الحقيقي أو ترددات، استخدم
1922
+ * `useAudioLevel` بدلها.
1923
+ *
1924
+ * **تحذير:** بيتنادى ٦٠ مرة في الثانية. أي `setState` جوّاه معناه
1925
+ * رندر ٦٠ مرة في الثانية عندك — اكتب على الـDOM مباشرةً بـref.
1926
+ */
1927
+ onLevel?: (level: number) => void;
1928
+ /**
1929
+ * بيتملا بعنصر `<audio>` الداخلي — عشان تقدر توصّله بـ`useAudioLevel`
1930
+ * أو أي حاجة محتاجة العنصر نفسه.
1931
+ */
1932
+ mediaRef?: RefObject<HTMLAudioElement | null>;
1933
+ className?: string;
1934
+ }
1935
+ declare function AudioPlayer({ src, title, meta, cover, variant, bars, onLevel, mediaRef, className, }: AudioPlayerProps): react.JSX.Element;
1936
+
1937
+ interface MediaState {
1938
+ playing: boolean;
1939
+ /** بالثواني */
1940
+ time: number;
1941
+ duration: number;
1942
+ /** آخر ثانية اتحمّلت — المؤشّر بيرسمها كطبقة تحت التقدّم */
1943
+ buffered: number;
1944
+ volume: number;
1945
+ muted: boolean;
1946
+ rate: number;
1947
+ /** بيستنى بيانات — المؤشّر واقف والفيديو مش بيتحرّك */
1948
+ waiting: boolean;
1949
+ ended: boolean;
1950
+ }
1951
+ declare function useMedia<T extends HTMLMediaElement>(): {
1952
+ ref: react.RefObject<T | null>;
1953
+ state: MediaState;
1954
+ toggle: () => void;
1955
+ seek: (to: number) => void;
1956
+ skip: (by: number) => void;
1957
+ setVolume: (v: number) => void;
1958
+ toggleMute: () => void;
1959
+ setRate: (r: number) => void;
1960
+ };
1961
+ /**
1962
+ * الوقت بصيغة m:ss أو h:mm:ss.
1963
+ *
1964
+ * الساعات بتظهر بس لو موجودة — «0:03:12» على مقطع تلات دقايق بيخلّي
1965
+ * العين تقرا رقم زيادة كل مرة.
1966
+ */
1967
+ declare function formatTime(seconds: number): string;
1968
+
1969
+ interface AudioLevel {
1970
+ /** مستوى عام ٠–١ — اقرا `.current` جوّه حلقة رسم عندك */
1971
+ level: RefObject<number>;
1972
+ /** طاقة كل نطاق ترددي ٠–١، من الغليظ للحادّ */
1973
+ bands: RefObject<number[]>;
1974
+ /** التحليل اشتغل فعلاً */
1975
+ ready: boolean;
1976
+ /**
1977
+ * فشل التوصيل — غالباً ملف من دومين تاني من غير هيدرز CORS.
1978
+ * مهم تتعامل معاه: Web Audio بيدّي **أصفار** في الحالة دي مش خطأ،
1979
+ * يعني التأثير بيموت بصمت من غير ما حد يعرف ليه.
1980
+ */
1981
+ failed: boolean;
1982
+ }
1983
+ declare function useAudioLevel(ref: RefObject<HTMLMediaElement | null>, { bands, enabled }?: {
1984
+ bands?: number;
1985
+ enabled?: boolean;
1986
+ }): AudioLevel;
1987
+
1988
+ type ProviderLevel = 1 | 2 | 3;
1989
+ /**
1990
+ * التسميات جوّه المكتبة لا في التطبيق.
1991
+ *
1992
+ * الشارة اللي كل شاشة بتكتب نصّها بإيدها بتتفرّق: «مقدّم محترف» في
1993
+ * السوق و«محترف» في صفحة الخدمة، والاتنين نفس الدرجة. النصّ جزء من
1994
+ * المكوّن زي أسماء العملات في `Money` بالظبط — وهنا هو **الاسم
1995
+ * المتاح الوحيد**، فتفرّقه بيدّي شارتين مالهمش علاقة ببعض.
1996
+ */
1997
+ declare const PROVIDER_LEVEL_LABEL: Record<ProviderLevel, string>;
1998
+ declare const PROVIDER_LEVEL_LABEL_EN: Record<ProviderLevel, string>;
1999
+ interface ProviderMarkProps {
2000
+ level: ProviderLevel;
2001
+ /** ضلع المربّع بالبكسل */
2002
+ size?: number;
2003
+ className?: string;
2004
+ }
2005
+ /**
2006
+ * العلامة وحدها بلا خلفية — لخليّة جدول ضيّقة أو سطر بيحدّد لونه.
2007
+ *
2008
+ * بلا `aria-label`: العلامة زينة جوّه `ProviderBadge` اللي بيحمل الاسم.
2009
+ */
2010
+ declare function ProviderMark({ level, size, className }: ProviderMarkProps): react.JSX.Element;
2011
+ /**
2012
+ * المقاسين.
2013
+ *
2014
+ * `sm` أربعة وعشرين — وده **حدّ الهدف اللمسي** لا رقم مختار. الشارة
2015
+ * بتاخد تركيز (تحت)، واللي بياخد تركيز بيتضغط عليه.
2016
+ */
2017
+ declare const SIZES: {
2018
+ readonly sm: {
2019
+ readonly box: "size-6";
2020
+ readonly mark: 14;
2021
+ };
2022
+ readonly md: {
2023
+ readonly box: "size-7";
2024
+ readonly mark: 16;
2025
+ };
2026
+ };
2027
+ type ProviderBadgeSize = keyof typeof SIZES;
2028
+ interface ProviderBadgeProps {
2029
+ level: ProviderLevel;
2030
+ /**
2031
+ * المقاس — واحد للتلات درجات في نفس الموضع.
2032
+ *
2033
+ * المقاس على المكوّن لا على الدرجة عن قصد: لو «خبير» أكبر من «جديد»
2034
+ * في نفس العمود بيتقري فرق في **وزن السطر** لا فرق في المستوى.
2035
+ */
2036
+ size?: ProviderBadgeSize;
2037
+ className?: string;
2038
+ }
2039
+ /**
2040
+ * ── الاسم مش في التولتيب بس ─────────────────────────────────────────────
2041
+ * التولتيب بيظهر على المرور، **واللمس مالوش مرور**. فالاسم متحطّ في
2042
+ * `aria-label` كمان: قارئ الشاشة بينطقه، ومستخدم اللمس بيوصله لأن
2043
+ * العنصر بياخد تركيز فالضغطة بتفتح التولتيب.
2044
+ *
2045
+ * ── والمربّع بحواف لا دايرة ──────────────────────────────────────────────
2046
+ * الشارة بتقع جنب `Avatar` وهو دايرة. دايرة صغيّرة جنب دايرة كبيرة
2047
+ * بتتقري صورة تانية للمقدّم — والشكل المختلف بيقول «دي علامة مش وش».
2048
+ */
2049
+ declare function ProviderBadge({ level, size, className }: ProviderBadgeProps): react.JSX.Element;
2050
+ interface VerifiedBadgeProps {
2051
+ size?: ProviderBadgeSize;
2052
+ className?: string;
2053
+ }
2054
+ declare function VerifiedBadge({ size, className }: VerifiedBadgeProps): react.JSX.Element;
2055
+
2056
+ /** سطر منطوق مع توقيته — يُضاء أثناء نطقه */
2057
+ interface CoachLine {
2058
+ text: string;
2059
+ start: number;
2060
+ end: number;
2061
+ }
2062
+ /** أين يظهر */
2063
+ interface CoachWhere {
2064
+ /** المسار الذي يظهر فيه — أُغفل = كل المسارات */
2065
+ path?: string;
2066
+ /**
2067
+ * مُعرّف العنصر الذي يتكلّم عنه، من `<Coach id="…">`.
2068
+ *
2069
+ * النصيحة تلتصق به، والشرح الصوتي يُضيئه أثناء الكلام. وإن لم يكن
2070
+ * العنصر في الشاشة وقت الظهور فلا يظهر شيء — إرشاد يشير إلى ما لا
2071
+ * وجود له أسوأ من لا إرشاد.
2072
+ */
2073
+ anchor?: string;
2074
+ }
2075
+ /**
2076
+ * متى يظهر.
2077
+ *
2078
+ * `enter` فور دخول الشاشة · `idle:4s` بعد استقرار المستخدم عليها
2079
+ * · `manual` بنداء `coach.show(id)` من الصفحة.
2080
+ *
2081
+ * والتأخير ليس تجميلاً: الظهور مع تحميل الصفحة يجعل الإرشاد ينافس ما
2082
+ * جاء المستخدم ليقرأه، فيُغلق قبل أن يُقرأ.
2083
+ */
2084
+ type CoachWhen = 'enter' | 'manual' | `idle:${number}s`;
2085
+ interface CoachBase {
2086
+ id: string;
2087
+ where?: CoachWhere;
2088
+ when?: CoachWhen;
2089
+ }
2090
+ /**
2091
+ * نصيحة — جملة واحدة بجانب العنصر.
2092
+ *
2093
+ * أرخص نوع وأكثره استعمالاً: لا ملفّ ولا تسجيل، تُكتب وتنتهي. وهذا
2094
+ * سبب وجوده أصلاً — نصف ما يبدو محتاجاً لشرح صوتي لا يحتاج أكثر من
2095
+ * جملة في مكانها.
2096
+ */
2097
+ interface CoachHint extends CoachBase {
2098
+ kind: 'hint';
2099
+ text: string;
2100
+ /** عنوان اختياري فوق الجملة */
2101
+ title?: string;
2102
+ }
2103
+ /** شرح صوتي — يصف **الشاشة**: أين الأشياء وماذا تعني */
2104
+ interface CoachAudio extends CoachBase {
2105
+ kind: 'audio';
2106
+ /** ما تقوله البطاقة قبل الضغط — الموضوع لا التحية */
2107
+ headline: string;
2108
+ src: string;
2109
+ lines: CoachLine[];
2110
+ meta?: string;
2111
+ }
2112
+ type CoachItem = CoachHint | CoachAudio;
2113
+ /** المدّة من آخر سطر — لا نطلبها من المتصفّح قبل الضغط */
2114
+ declare const coachSeconds: (item: CoachAudio) => number;
2115
+ interface CoachApi {
2116
+ /** يعرض عنصراً بمعرّفه — يتجاوز `when` ولا يتجاوز «مرّة واحدة» */
2117
+ show: (id: string) => void;
2118
+ /** يعرضه ولو سبق أن رآه — لزرار «إيه ده؟» */
2119
+ replay: (id: string) => void;
2120
+ close: () => void;
2121
+ /** ما يُعرض الآن */
2122
+ current: CoachItem | null;
2123
+ seen: (id: string) => boolean;
2124
+ /** ينسى المُشاهَد كلّه — للتجريب ولزرار «أعد الإرشاد» في الإعدادات */
2125
+ reset: () => void;
2126
+ }
2127
+ /** ما يمرّره التطبيق ليرسم الكرة — تبقى `@qumra/manara` خالية من `three` */
2128
+ type CoachOrb = (level: RefObject<number>) => ReactNode;
2129
+ /**
2130
+ * حدود المساحة التي يشغلها الشرح الصوتيّ.
2131
+ *
2132
+ * افتراضها الشاشة كلّها، وهو الصحيح لتطبيق بلا شِلّ. أمّا لوحة لها
2133
+ * شريط جانبيّ وعلويّ فالحاجب فوقهما يعطّل التنقّل بلا سبب: الشرح
2134
+ * يتكلّم عن **المحتوى**، فليحجب المحتوى وحده. والكرة تتوسّط ما بقي
2135
+ * لا وسط الشاشة — وإلّا بدت مزاحة عن مركزها.
2136
+ *
2137
+ * قيم CSS منطقيّة (`insetInlineStart`) لا يمين/يسار، فتنقلب مع اتجاه
2138
+ * الصفحة بلا نسختين.
2139
+ */
2140
+ interface CoachRegion {
2141
+ top?: string;
2142
+ bottom?: string;
2143
+ insetInlineStart?: string;
2144
+ insetInlineEnd?: string;
2145
+ }
2146
+
2147
+ interface CoachProviderProps {
2148
+ items: CoachItem[];
2149
+ /**
2150
+ * المسار الحالي — من الموجّه عندك.
2151
+ *
2152
+ * خاصية لا استنتاج: `@qumra/manara` لا تعتمد على موجّه بعينه، وقراءة
2153
+ * `useLocation` هنا تربط المكتبة كلّها بـ`react-router`.
2154
+ */
2155
+ path?: string;
2156
+ /** يرسم كرة شهاب أثناء الكلام — يتلقّى مرجع مستوى الصوت */
2157
+ orb?: CoachOrb;
2158
+ /** حدود مساحة الشرح — أُغفلت = الشاشة كلّها */
2159
+ region?: CoachRegion;
2160
+ /** مفتاح `localStorage` لما شُوهد */
2161
+ storageKey?: string;
2162
+ /** يوقف الإرشاد كلّه — لوضع العرض أو تفضيل المستخدم */
2163
+ disabled?: boolean;
2164
+ children: ReactNode;
2165
+ }
2166
+ declare function CoachProvider({ items, path, orb, region, storageKey, disabled, children, }: CoachProviderProps): react.JSX.Element;
2167
+ declare function useCoach(): CoachApi;
2168
+ /**
2169
+ * نسخة لا ترمي — لمكوّنات المكتبة نفسها.
2170
+ *
2171
+ * `useCoach` يرمي عمداً: من ناداه في شاشة يريد الإرشاد، والصمت يخفي
2172
+ * الخطأ. أمّا `StatCard` فيُستعمل في معرض المكوّنات وفي شاشات بلا
2173
+ * مزوّد، ولا يصحّ أن يسقط لأن أحدهم لم يشغّل الإرشاد — فيسأل، وإن لم
2174
+ * يجد لم يرسم زرّ الشرح.
2175
+ */
2176
+ declare function useCoachOptional(): CoachApi | null;
2177
+
2178
+ declare function Coach({ id, asChild, children, }: {
2179
+ id: string;
2180
+ /**
2181
+ * يمرّر المرجع إلى الطفل مباشرةً بدل تغليفه.
2182
+ *
2183
+ * استعملها حين يكون الطفل عنصر DOM أو مكوّناً يمرّر `ref` — أي
2184
+ * `<Button>` في هذه المكتبة. وإن لم يمرّره لم يُسجَّل العنصر
2185
+ * وسقط الإرشاد بصمت، ولهذا ليست هي السلوك الافتراضي.
2186
+ */
2187
+ asChild?: boolean;
2188
+ children: ReactNode;
2189
+ }): react.JSX.Element;
2190
+
2191
+ interface ChoiceOption {
2192
+ value: string;
2193
+ label: ReactNode;
2194
+ meta?: ReactNode;
2195
+ /** رقم بيتعرض في الجنب — سعر الشحن مثلاً */
2196
+ price?: ReactNode;
2197
+ icon?: ComponentType<{
2198
+ size?: number;
2199
+ strokeWidth?: number;
2200
+ }>;
2201
+ disabled?: boolean;
2202
+ /** سبب التعطيل — «معطّل» من غير سبب بيسيب المستخدم واقف */
2203
+ lockReason?: string;
2204
+ /**
2205
+ * معرّف شرح في سجلّ الإرشاد — يرسم علامة استفهام تفتحه.
2206
+ *
2207
+ * للخيار الذي لا يكفيه سطر: «كتالوج كامل» يفهمها من عمل واحداً قبلاً،
2208
+ * ومن لم يعملها يحتاج أن يعرف ما الملفّ وماذا فيه قبل أن يختار — لا
2209
+ * بعد أن يختار فيجد نفسه في شاشة رفع لا يريدها.
2210
+ */
2211
+ coachId?: string;
2212
+ }
2213
+ declare function ChoiceCards({ name, value, onChange, options, columns, hideMark, multiple, disabled: allDisabled, className, }: {
2214
+ name: string;
2215
+ /** قايمة لما `multiple` — والمكوّن بيقرا الشكل ده لوحده */
2216
+ value: string | null | string[];
2217
+ onChange: (value: string) => void;
2218
+ options: ChoiceOption[];
2219
+ columns?: 1 | 2 | 3;
2220
+ /**
2221
+ * اختيار متعدّد — تشيك بوكس بدل راديو.
2222
+ *
2223
+ * `onChange` بترجّع **الخيار اللي اتضغط** لا القايمة الجديدة، فاللي
2224
+ * فوق هو اللي بيقرّر يضيف ولا يشيل. المكوّن مايعرفش لو فيه حدّ أقصى
2225
+ * أو خيار بيلغي غيره، واللي عارف هو الشاشة.
2226
+ */
2227
+ multiple?: boolean;
2228
+ /** بيقفل الكل — الكرت اللي اتجاوب عليه بيفضل مقروء ومش قابل للتغيير */
2229
+ disabled?: boolean;
2230
+ /**
2231
+ * يُخفي دائرة الاختيار.
2232
+ *
2233
+ * وظيفتها أن تقول «اختر واحداً» — وهي مفهومة بلا رسم حين يكون
2234
+ * المختار محاطاً بإطار العلامة وأرضيتها وأيقونته معبّأة بلونها.
2235
+ * ثلاث إشارات لشيء واحد، والرابعة زينة. تُترك ظاهرة حين لا يكون
2236
+ * للخيارات أيقونات، فلا يبقى ما يميّز المختار غيرها.
2237
+ */
2238
+ hideMark?: boolean;
2239
+ className?: string;
2240
+ }): react.JSX.Element;
2241
+ /**
2242
+ * خط اتجاه صغير جنب الرقم.
2243
+ *
2244
+ * مالوش محاور ولا شبكة عن قصد — وظيفته يقول «طالع ولا نازل» في نص
2245
+ * صف جدول، مش يتقري منه قيمة. القيمة الدقيقة مكانها العمود اللي جنبه.
2246
+ *
2247
+ * ── و`fluid` لما يبقى هو المحتوى ───────────────────────────────────────
2248
+ * على شاشة تليفون بعرض ٣٢٠ بكسل، ٣٠ عمود بيبقى كل واحد ٨ بكسل بمسافة
2249
+ * ٢ — والعين بتقرا نسيج مش اتجاه. الخط بيقول «طالع ولا نازل» في نظرة،
2250
+ * وده السؤال الوحيد على التليفون.
2251
+ *
2252
+ * `fluid` بيخلّيه يملا العرض المتاح: الـ`viewBox` بيفضل بمقاسه
2253
+ * و`preserveAspectRatio="none"` بيمطّ أفقياً. وعشان المطّ ده السُمك
2254
+ * بيتحسب من الشاشة لا من المقاس (`vectorEffect`)، وإلا الخط بيرفع
2255
+ * على الشاشة العريضة ويرفع أكتر على الضيقة.
2256
+ */
2257
+ declare function Sparkline({ values, width, height, tone, fluid, className, }: {
2258
+ values: number[];
2259
+ width?: number;
2260
+ height?: number;
2261
+ tone?: 'brand' | 'green' | 'red' | 'muted';
2262
+ /** يملا عرض الحاوية بدل المقاس الثابت — `width` بيبقى نسبة الرسم */
2263
+ fluid?: boolean;
2264
+ className?: string;
2265
+ }): react.JSX.Element | null;
2266
+
2267
+ interface BadgeProps {
2268
+ children: ReactNode;
2269
+ tone?: Tone;
2270
+ variant?: 'soft' | 'solid';
2271
+ size?: 'sm' | 'md';
2272
+ /** نقطة حالة قبل النص */
2273
+ dot?: boolean;
2274
+ icon?: ReactNode;
2275
+ className?: string;
2276
+ }
2277
+ /** شارة الحالة — النمط اللي كان مكرر في ١١ ملف قبل الاستخراج */
2278
+ declare function Badge({ children, tone, variant, size, dot, icon, className, }: BadgeProps): react.JSX.Element;
2279
+ declare function Counter({ value, max }: {
2280
+ value: number;
2281
+ max?: number;
2282
+ }): react.JSX.Element | null;
2283
+ type AvatarSize = 'xs' | 'sm' | 'md' | 'lg';
2284
+ declare function Avatar({ name, src, size, square, className, }: {
2285
+ name: string;
2286
+ src?: string;
2287
+ size?: AvatarSize;
2288
+ /** مربع بحواف — للمتاجر والمنتجات بدل الدايرة */
2289
+ square?: boolean;
2290
+ className?: string;
2291
+ }): react.JSX.Element;
2292
+ interface StatCardProps {
2293
+ icon?: ComponentType<{
2294
+ size?: number;
2295
+ strokeWidth?: number;
2296
+ }>;
2297
+ tone?: Tone;
2298
+ label: ReactNode;
2299
+ value: ReactNode;
2300
+ hint?: ReactNode;
2301
+ /**
2302
+ * معرّف شرح في سجلّ الإرشاد — يرسم علامة استفهام تفتحه.
2303
+ *
2304
+ * الرقم بلا تعريفه نصف معلومة: «قيمة يمكن استردادها» يفهمها من كتبها،
2305
+ * ومن يقرأها أول مرّة يسأل: بأي حساب؟ ومن أين؟ والشرح المكتوب تحت كل
2306
+ * رقم يحوّل لوحة إلى كتيّب — فالعلامة تُخفيه حتى يُطلب.
2307
+ *
2308
+ * ولا يُرسم شيء إن لم يكن حول الشاشة `<CoachProvider>`.
2309
+ */
2310
+ coachId?: string;
2311
+ className?: string;
2312
+ }
2313
+ /**
2314
+ * الكرت الإحصائي — كان مكرر في ٦ ملفات.
2315
+ *
2316
+ * مقصود إنه **مالوش نسبة مئوية**: المنتج الحقيقي بيعرض «+100%» على طلبين،
2317
+ * وده رقم بيهزّ الثقة في باقي الأرقام. لو محتاج مقارنة استخدم `hint`
2318
+ * بجملة صريحة، أو `Delta` تحت لما يكون الأساس كبير كفاية.
2319
+ */
2320
+ declare function StatCard({ icon: Icon, tone, label, value, hint, coachId, className, }: StatCardProps): react.JSX.Element;
2321
+ declare function Card({ children, padded, className, }: {
2322
+ children: ReactNode;
2323
+ padded?: boolean;
2324
+ className?: string;
2325
+ }): react.JSX.Element;
2326
+ /**
2327
+ * رأس البطاقة.
2328
+ *
2329
+ * بلا هامش سفليّ: كل بطاقة في اللوحة `flex flex-col gap-*`، والهامش
2330
+ * المدمج كان يُضاف إلى الفجوة فيصير الفراغ تحت العنوان ضعف ما تحت أيّ
2331
+ * شيء آخر فيها. المسافة تخصّ الحاوية لا العنصر.
2332
+ */
2333
+ declare function CardHeader({ title, description, action, coachId, }: {
2334
+ title: ReactNode;
2335
+ description?: ReactNode;
2336
+ action?: ReactNode;
2337
+ /**
2338
+ * معرّف شرح في سجلّ الإرشاد — يرسم علامة استفهام تفتحه.
2339
+ *
2340
+ * للقسم الذي لا يكفيه سطر الوصف: «الخصائص والمتغيّرات» جملة تصفه،
2341
+ * لكنّ من لم يعمل متغيّراً قبلاً يحتاج أن يفهم ماذا يحدث حين يضيف
2342
+ * خاصيّة — وشرح ذلك تحت العنوان يحوّل النموذج إلى كتيّب.
2343
+ */
2344
+ coachId?: string;
2345
+ }): react.JSX.Element;
2346
+ declare function PageHeader({ title, hint, actions, }: {
2347
+ title: ReactNode;
2348
+ hint?: ReactNode;
2349
+ actions?: ReactNode;
2350
+ }): react.JSX.Element;
2351
+ declare function Progress({ value, max, label, tone, className, }: {
2352
+ value: number;
2353
+ max?: number;
2354
+ label?: ReactNode;
2355
+ tone?: Tone;
2356
+ /** للتحكّم في العرض — الشريط المضغوط جنب رقم مش بعرض الكرت */
2357
+ className?: string;
2358
+ }): react.JSX.Element;
2359
+ declare function Skeleton({ variant, width, className, }: {
2360
+ variant?: 'text' | 'block' | 'circle';
2361
+ width?: string;
2362
+ className?: string;
2363
+ }): react.JSX.Element;
2364
+
2365
+ /**
2366
+ * إصدار الصيغة.
2367
+ *
2368
+ * بيتحطّ في كل رسالة عشان المستقبِل يعرف يقرأها. الرسالة بلا `v`
2369
+ * بتتقري على إنها `1` — الرسايل القديمة اتبعتت قبل ما الحقل يوجد.
2370
+ */
2371
+ declare const NOTIFICATION_SCHEMA_VERSION = 1;
2372
+ /**
2373
+ * أولوية الإشعار — تلات درجات، كل واحدة ليها سلوك.
2374
+ *
2375
+ * `low` بيوصل صامت
2376
+ * `normal` الافتراضي
2377
+ * `critical` بيرنّ أعلى ٣٥٪، ومابيتعلّمش مقروء بـ«تعليم الكل»،
2378
+ * وبيتعدّ في `needsAction`
2379
+ *
2380
+ * ── وكانت أربعة ─────────────────────────────────────────────────────────
2381
+ * `high` كانت موجودة في نوع الاتحاد وبس — مافيش سطر واحد بيقراها.
2382
+ * أربع درجات وواحدة فيهم مالهاش أثر أوحش من تلاتة كلهم شغّالين: اللي
2383
+ * بيختار بيقعد يفكّر في فرق مش موجود، واللي بيقرا الكود بيدوّر على
2384
+ * سلوك مش هيلاقيه.
2385
+ *
2386
+ * الرسالة اللي لسه بتبعت `high` بتتقرا `normal` بتحذير — مش برفض.
2387
+ */
2388
+ type NotificationPriority = 'low' | 'normal' | 'critical';
2389
+ declare const NOTIFICATION_PRIORITIES: NotificationPriority[];
2390
+ /**
2391
+ * الإجراء — وجهة لا دالة.
2392
+ *
2393
+ * `href` مسار داخلي (`/orders/1052`) أو رابط كامل. المكتبة مابتنقّلش
2394
+ * بنفسها: بتنادي `onAction` واللي بيستخدمها بيوصّله براوتره. كده نفس
2395
+ * الرسالة بتشتغل في تطبيق React Router وتطبيق Next وصفحة ساكنة.
2396
+ */
2397
+ interface NotificationAction {
2398
+ label: string;
2399
+ href: string;
2400
+ }
2401
+ /**
2402
+ * الرسالة على السلك — ده اللي السيرفر بيبعته وقاعدة البيانات بتخزّنه.
2403
+ *
2404
+ * كل الحقول الاختيارية ليها افتراضي في `parseNotification`، فالسيرفر
2405
+ * بيبعت أقل حاجة والباقي بيتحسب.
2406
+ *
2407
+ * @example
2408
+ * {
2409
+ * "v": 1,
2410
+ * "id": "ntf_01HZY8K3",
2411
+ * "kind": "order.created",
2412
+ * "at": "2026-08-10T14:32:00.000Z",
2413
+ * "title": "طلب جديد #1052",
2414
+ * "body": "مدفوع بالكامل، وفي انتظار التجهيز.",
2415
+ * "priority": "normal",
2416
+ * "data": { "orderId": "1052", "total": 1480, "currency": "EGP" },
2417
+ * "action": { "label": "افتح الطلب", "href": "/orders/1052" }
2418
+ * }
2419
+ */
2420
+ interface NotificationJSON {
2421
+ /** إصدار الصيغة — غيابه بيتقري `1` */
2422
+ v?: number;
2423
+ /** معرّف فريد وثابت. التكرار بيتلغي بيه، فلازم يكون من السيرفر */
2424
+ id: string;
2425
+ /** اسم الحدث `domain.event` — `order.created`, `stock.depleted` */
2426
+ kind: string;
2427
+ /** ISO 8601 بتوقيت UTC — `2026-08-10T14:32:00.000Z` */
2428
+ at: string;
2429
+ title: string;
2430
+ body?: string;
2431
+ /**
2432
+ * وقت القراية بالـISO — `null` أو غياب يعني غير مقروء.
2433
+ *
2434
+ * ── ليه وقت مش بوليان ───────────────────────────────────────────────
2435
+ * `read: true` أحادي: مفيش طريقة تقول «رجّعه غير مقروء»، ولو عملتها
2436
+ * أول مزامنة بتقلبها تاني — لأن القاعدة «المقروء بيكسب» مالهاش
2437
+ * مرجع تقارن بيه.
2438
+ *
2439
+ * الوقت بيدّي نفس الضمانة (الأحدث بيكسب) وبيفتح تلاتة كمان:
2440
+ * «غير مقروء» بيبقى حدث أحدث، والتراجع بيعرف علامته من علامة جهاز
2441
+ * تاني وصلت في نفس اللحظة، و«الوقت لحد القراية» بيتحسب مجاناً.
2442
+ */
2443
+ readAt?: string | null;
2444
+ /** @deprecated استخدم `readAt` — بتتقرا وبتتحوّل، وهتتشال */
2445
+ read?: boolean;
2446
+ priority?: NotificationPriority;
2447
+ /**
2448
+ * مفتاح تجميع — بيلمّ **الكروت الطايرة وبس**.
2449
+ *
2450
+ * الرسالة الجديدة بتحلّ محلّ اللي قبلها من نفس المجموعة في طابور
2451
+ * الكروت. تلات كروت من نفس المصدر بتنزل مع بعض هي الضجيج اللي
2452
+ * بيخلّي التاجر يطفّي الإشعارات.
2453
+ *
2454
+ * ── والصندوق مابيلمّش ──────────────────────────────────────────────
2455
+ * التلاتة بيفضلوا سطور منفصلة. الكرت بيقاطع فبيستاهل اللمّ؛ السطر
2456
+ * بيتقري بمهلة فاللمّ فيه بيخفي معلومة.
2457
+ *
2458
+ * واللمّ الدائم («٣ مواضيع جديدة» كسطر واحد) شغل السيرفر: هو اللي
2459
+ * شايف النافذة الزمنية كلها. اللمّ على العميل بيلمّ اللي وصل
2460
+ * للتبويب ده بس — والكروت مالهاش المشكلة دي لأنها لكل تبويب أصلاً
2461
+ * وبتعيش تواني ومحدّش بيعدّها.
2462
+ */
2463
+ group?: string;
2464
+ /** حمولة الحدث — المكتبة مابتقراهاش، بتمرّرها للي بيستخدمها */
2465
+ data?: Record<string, unknown>;
2466
+ action?: NotificationAction;
2467
+ /**
2468
+ * تسكيت رسالة واحدة — `'none'` وبس.
2469
+ *
2470
+ * الأصل إن الصوت من النوع في السجلّ. ده للاستثناء: نفس النوع بيوصل
2471
+ * صامت في استيراد بالجملة مثلاً. مفيش قيمة تانية — النغمة مش
2472
+ * قابلة للتبديل من الرسالة.
2473
+ */
2474
+ sound?: 'none';
2475
+ }
2476
+ /**
2477
+ * الرسالة بعد التحقّق — دي اللي المكوّنات بتشتغل عليها.
2478
+ *
2479
+ * الفرق عن `NotificationJSON`: التاريخ بقى `Date`، والاختياري اتملى
2480
+ * بافتراضياته. فمفيش مكوّن بيعمل `?? 'normal'` ولا `new Date(...)`
2481
+ * تاني — التطبيع بيحصل مرّة على الحدود.
2482
+ */
2483
+ interface Notification {
2484
+ v: number;
2485
+ id: string;
2486
+ kind: string;
2487
+ at: Date;
2488
+ title: string;
2489
+ body?: string;
2490
+ /** وقت القراية — `null` يعني غير مقروء */
2491
+ readAt: Date | null;
2492
+ /** اختصار لـ`readAt !== null` — محسوب، مش مخزّن */
2493
+ read: boolean;
2494
+ priority: NotificationPriority;
2495
+ group?: string;
2496
+ data: Record<string, unknown>;
2497
+ action?: NotificationAction;
2498
+ sound?: 'none';
2499
+ }
2500
+ /**
2501
+ * دالة الترجمة — من نظام المشروع، مش من المكتبة.
2502
+ *
2503
+ * ── ليه المكتبة مابتترجمش بنفسها ────────────────────────────────────────
2504
+ * أول تنفيذ كان `locale.startsWith('ar') ? '…' : '…'` جوّه السجلّ. ده
2505
+ * بيمشي لنوعين وبيقع عند التاني عشر:
2506
+ *
2507
+ * · النصوص بتبقى مدفونة في كود، فالمترجم مايقدرش يلمسها
2508
+ * · المثنّى والجمع العربي (طلب · طلبين · ٣ طلبات) مستحيل بـ`startsWith`
2509
+ * · ولو المشروع عنده نظام ترجمة، ده بيعمل نظام تاني جنبه
2510
+ *
2511
+ * فالمكتبة بتملك **نقطة التعليق** مش الترجمة: بتنادي `t` بمفتاح وقيم،
2512
+ * و`t` بتيجي من `NotificationProvider`. النصوص بتفضل في الكتالوج،
2513
+ * والجمع شغل النظام المتخصّص فيه، والمكتبة تفضل مش عارفة لغة إيه —
2514
+ * زي ما هي مش عارفة `order.created` يعني إيه.
2515
+ */
2516
+ type NotificationTranslate = (key: string, vars?: Record<string, unknown>) => ReactNode;
2517
+ /**
2518
+ * صوت النوع — نغمة واحدة أو سكوت.
2519
+ *
2520
+ * `notify` هي نغمة الإشعارات الوحيدة، مضمّنة كـdata URI في `chime.ts`
2521
+ * فمفيش ملف يتنسخ ولا مسار يتكسر لما المكتبة تتنقل لمشروع تاني.
2522
+ * و`none` بتسكّت النوع كله — للي بيتقرا ومابيستاهلش مقاطعة.
2523
+ *
2524
+ * والنغمة نفسها **مش قابلة للتبديل**: هي جزء من هوية قمرة زي اللون
2525
+ * والخط. اللي المشروع بيقرّره هو أنهي نوع يرنّ وأنهي نوع يعدّي صامت.
2526
+ */
2527
+ type NotificationSoundName = 'notify' | 'none';
2528
+ /**
2529
+ * تعريف نوع إشعار — الربط بين اسم الحدث وشكله وصوته.
2530
+ *
2531
+ * ده اللي بيخلّي النظام ينفع لأكتر من مشروع: المكتبة مابتعرفش
2532
+ * `order.created` يعني إيه، بتعرف تقرا السجلّ. والمشروع بيسجّل
2533
+ * أنواعه هو.
2534
+ */
2535
+ interface NotificationKind {
2536
+ /** اسم الحدث زي ما بيجي من السيرفر — `order.created` */
2537
+ kind: string;
2538
+ /** اسم مقروء — بيظهر في إعدادات الإشعارات والفلترة */
2539
+ label: string;
2540
+ icon: ComponentType<{
2541
+ size?: number;
2542
+ strokeWidth?: number;
2543
+ }>;
2544
+ /**
2545
+ * نغمة الحالة — والافتراضي محايد عن قصد.
2546
+ *
2547
+ * دي بتقول «الحاجة دي مقلقة» مش «دي من قسم الطلبات». لو كل نوع خد
2548
+ * لون، الصندوق بيبقى قوس قزح والعاجل بيتوّه فيه.
2549
+ */
2550
+ tone?: Tone;
2551
+ /** أولوية النوع لو الرسالة ما حدّدتش */
2552
+ priority?: NotificationPriority;
2553
+ /**
2554
+ * النوع ده يرنّ ولا لأ — الافتراضي `notify`.
2555
+ *
2556
+ * ده القرار الوحيد المتاح في الصوت، وهو قرار منتج مش هوية:
2557
+ * «تحديث تطبيق» مايستاهلش مقاطعة، «فشل تحصيل» يستاهل. النغمة
2558
+ * نفسها والعلوّ والإيقاع ثوابت في المكتبة.
2559
+ */
2560
+ sound?: NotificationSoundName;
2561
+ /**
2562
+ * بناء العنوان من `data` بدل نصّ السيرفر — **اختياري**.
2563
+ *
2564
+ * ── المشكلة اللي بيحلّها ────────────────────────────────────────────
2565
+ * `title` بيتخزّن باللغة اللي كانت وقت الإرسال. التاجر بيبدّل اللغة،
2566
+ * وبيلاقي إشعارات الشهر اللي فات لسه بالقديمة. ده بيحصل في قمرة
2567
+ * فعلاً — التطبيقات عربي وإنجليزي.
2568
+ *
2569
+ * ── وليه اختياري مش الافتراضي ───────────────────────────────────────
2570
+ * لو كل الأنواع بترسم على العميل، تصليح صياغة أو غلطة إملائية بيبقى
2571
+ * محتاج **نشر فرونت**. دلوقتي ده تعديل على السيرفر بيوصل فورًا.
2572
+ * فالنوع اللي عنده قالب بيترجم، واللي مالوش بياخد نصّ السيرفر —
2573
+ * وتتبنّاها نوع نوع للي يستاهل.
2574
+ *
2575
+ * والنوع المش مسجّل بيفضل شغّال بنصّ السيرفر، فالباك إند ينشر نوع
2576
+ * جديد من غير ما يستنّى الفرونت.
2577
+ *
2578
+ * ── والقالب بينادي `t` مابيترجمش ────────────────────────────────────
2579
+ * المفتاح والقيم بس. النصّ في كتالوج مشروعك، والجمع والتشكيل شغل
2580
+ * نظام الترجمة عندك.
2581
+ *
2582
+ * ولو المشروع ما مرّرش `t` للمزوّد، القالب **بيتجاهل** ونصّ السيرفر
2583
+ * بيتعرض — أأمن من مفتاح خام قدّام التاجر.
2584
+ *
2585
+ * @example
2586
+ * {
2587
+ * kind: 'order.created',
2588
+ * title: (n, t) => t('notif.order.created', { id: n.data.orderId }),
2589
+ * }
2590
+ */
2591
+ title?: (n: Notification, t: NotificationTranslate) => ReactNode;
2592
+ /** نفس فكرة `title` للنصّ التحته */
2593
+ body?: (n: Notification, t: NotificationTranslate) => ReactNode;
2594
+ }
2595
+ /**
2596
+ * النوع بعد الحلّ — الشكل والصوت مضمونين، والقوالب لأ.
2597
+ *
2598
+ * غياب `title`/`body` **معنى** مش نقص: يعني «خد نصّ السيرفر». فمفيش
2599
+ * افتراضي يتحطّ لهم، ولو اتحطّ كان هيدوس على نصّ جاي من السيرفر بنصّ
2600
+ * فاضي.
2601
+ */
2602
+ interface ResolvedKind extends Required<Omit<NotificationKind, 'title' | 'body'>> {
2603
+ title?: NotificationKind['title'];
2604
+ body?: NotificationKind['body'];
2605
+ /** النوع ده مش مسجّل، والقيم دي من الاحتياطي */
2606
+ unknown: boolean;
2607
+ }
2608
+ interface NotificationKindRegistry {
2609
+ /** بيرجّع النوع، ولو مش مسجّل بيرجّع الاحتياطي بـ`unknown: true` */
2610
+ get: (kind: string) => ResolvedKind;
2611
+ /** كل الأنواع المسجّلة — لشاشة إعدادات الإشعارات */
2612
+ list: () => ResolvedKind[];
2613
+ has: (kind: string) => boolean;
2614
+ }
2615
+
2616
+ type NotificationParseResult = {
2617
+ ok: true;
2618
+ value: Notification;
2619
+ warnings: string[];
2620
+ } | {
2621
+ ok: false;
2622
+ issues: string[];
2623
+ };
2624
+ interface NotificationBatch {
2625
+ items: Notification[];
2626
+ /** اللي اتعزل — الرسالة الخام وسبب الرفض، عشان يتسجّل مش يتبلع */
2627
+ rejected: {
2628
+ raw: unknown;
2629
+ issues: string[];
2630
+ }[];
2631
+ /** تحذيرات على رسايل عدّت — حقل اتجاهل، إصدار أحدث */
2632
+ warnings: string[];
2633
+ }
2634
+ /**
2635
+ * بيحقّق رسالة واحدة ويطبّعها.
2636
+ *
2637
+ * المطلوب: `id` و`kind` و`at` و`title`. الباقي بياخد افتراضي.
2638
+ * `at` لازم يكون تاريخ ISO مقروء — الرقم أو النص المكسور بيترفض، لأن
2639
+ * `Invalid Date` بيعدّي صامت وبيطلع «NaN من كذا دقيقة» في الواجهة.
2640
+ */
2641
+ interface ParseOptions {
2642
+ /**
2643
+ * سجلّ الأنواع — منه بييجي افتراضي الأولوية لما الرسالة ما تحدّدش.
2644
+ *
2645
+ * من غيره الرسالة اللي مافيهاش `priority` بتاخد `normal` مهما كان
2646
+ * نوعها — يعني `payment.failed` المسجّل `critical` بيوصل عادي،
2647
+ * والسجلّ بيبقى زينة. وده بيكسر أساس النظام: المكتبة مابتعرفش
2648
+ * `order.created` يعني إيه، بتعرف تقرا السجلّ.
2649
+ */
2650
+ kinds?: NotificationKindRegistry;
2651
+ }
2652
+ declare function parseNotification(raw: unknown, options?: ParseOptions): NotificationParseResult;
2653
+ /**
2654
+ * بيحقّق دفعة ويعزل الوحش.
2655
+ *
2656
+ * بيقبل مصفوفة، أو نص JSON، أو كائن فيه `items`/`notifications` —
2657
+ * التلات أشكال اللي الـAPIs بتبعت بيهم. وبيرتّب بالأحدث، وبيلغّي
2658
+ * تكرار الـ`id` (آخر نسخة بتكسب: التحديث بيوصل بنفس المعرّف).
2659
+ */
2660
+ declare function parseNotifications(raw: unknown, options?: ParseOptions): NotificationBatch;
2661
+ /**
2662
+ * بيرجّع الرسالة لصيغتها على السلك — للتخزين أو إعادة الإرسال.
2663
+ *
2664
+ * عكس `parseNotification` بالظبط: `parse(serialize(n))` بيدّي `n`.
2665
+ * لازم يفضل كده، وإلا الرسالة اللي اتخزّنت مابترجعش زي ما دخلت.
2666
+ */
2667
+ declare function serializeNotification(n: Notification): NotificationJSON;
2668
+
2669
+ /**
2670
+ * بينشئ سجلّ أنواع.
2671
+ *
2672
+ * @param kinds الأنواع المسجّلة
2673
+ * @param fallback تجاوز الشكل الاحتياطي للنوع المش معروف
2674
+ *
2675
+ * @example
2676
+ * const KINDS = createKindRegistry([
2677
+ * { kind: 'ticket.assigned', label: 'تذكرة', icon: Ticket, priority: 'critical' },
2678
+ * ])
2679
+ * KINDS.get('ticket.assigned').icon // Ticket
2680
+ * KINDS.get('حاجة.غريبة').unknown // true
2681
+ */
2682
+ declare function createKindRegistry(kinds: NotificationKind[], fallback?: Partial<Omit<ResolvedKind, 'kind' | 'unknown'>>): NotificationKindRegistry;
2683
+ /**
2684
+ * أنواع التجارة الإلكترونية — طقم جاهز لمنتجات قمرة.
2685
+ *
2686
+ * ده **مثال مسجّل** مش جزء من العقد. المشروع التاني بيبني سجلّه
2687
+ * بـ`createKindRegistry` ومابياخدش الطقم ده.
2688
+ *
2689
+ * ── واللون هنا استثناء مش قاعدة ─────────────────────────────────────────
2690
+ * أربعة بس من اتناشر ليهم نغمة: فشل الدفع والمخزون الخالص والطلب
2691
+ * المتعثّر والمرتجع. الباقي محايد. لو كل نوع خد لونه، مافيش حاجة
2692
+ * بتتشاف قبل حاجة — واللون بيبطّل يعني حالة.
2693
+ *
2694
+ * ── و`critical` تلاتة بس ────────────────────────────────────────────────
2695
+ * القاعدة: نزيف **مستمرّ لحد ما حد يتصرّف**. فشل التحصيل والمخزون
2696
+ * الخالص والطلب المتعثّر بيكلّفوا كل يوم بيعدّي؛ المرتجع حصل وخلاص.
2697
+ * والفرق مش أكاديمي: `critical` مابتتمسحش بـ«تعليم الكل»، فلو اتوسّعت
2698
+ * الحماية بتبقى ضجيج مالوش مفتاح إطفاء.
2699
+ *
2700
+ * ── والقوالب على اتنين بس ───────────────────────────────────────────────
2701
+ * `order.created` و`payout.sent` عندهم قالب بينادي `t` بمفتاح وقيم،
2702
+ * فبيترجموا من كتالوج المشروع. الباقي بياخد نصّ السيرفر — عشان تصليح
2703
+ * صياغة يفضل تعديل سيرفر بيوصل فورًا مش نشر فرونت.
2704
+ *
2705
+ * ومن غير `t` على المزوّد، القوالب بتتجاهل والكل بياخد نصّ السيرفر.
2706
+ *
2707
+ * ── والصوت واحد أو ولا حاجة ─────────────────────────────────────────────
2708
+ * النغمة نفسها لكل نوع بيستاهل مقاطعة، و`none` للي بيتقرا ومابيستاهلش:
2709
+ * تحديث تطبيق وملخّص المجتمع. نغمات متعدّدة بتفترض إن التاجر هيحفظ
2710
+ * إن النازلة يعني دفع فشل — وده مابيحصلش، بيسمع رنّة فبيبصّ.
2711
+ * والإلحاح بيتقال بالعلوّ: `critical` بتعلى ٣٥٪.
2712
+ */
2713
+ declare const QUMRA_KINDS: NotificationKind[];
2714
+ /** سجلّ قمرة جاهز — `QUMRA_NOTIFICATIONS.get('order.created')` */
2715
+ declare const QUMRA_NOTIFICATIONS: NotificationKindRegistry;
2716
+
2717
+ /** الصوت الوحيد في المكتبة — `none` بتسكّت النوع */
2718
+ declare const NOTIFICATION_SOUNDS: Exclude<NotificationSoundName, 'none'>[];
2719
+ interface UseNotificationSoundOptions {
2720
+ /** سجلّ الأنواع — منه بييجي صوت كل نوع (`notify` أو `none`) */
2721
+ kinds: NotificationKindRegistry;
2722
+ }
2723
+ interface NotificationSoundApi {
2724
+ /** الصوت اتفكّ وجاهز — قبلها أي `play` بتتبلع */
2725
+ ready: boolean;
2726
+ muted: boolean;
2727
+ setMuted: (muted: boolean) => void;
2728
+ /**
2729
+ * بيفكّ الصوت — **لازم من معالج حدث مستخدم حقيقي**.
2730
+ *
2731
+ * بتتنادى لوحدها على أول ضغطة لو `autoUnlock`. النداء اليدوي لزرار
2732
+ * «شغّل الصوت» في الإعدادات.
2733
+ */
2734
+ unlock: () => Promise<boolean>;
2735
+ /** بيرنّ حسب النوع — بيحترم الكتم والحدّ الأدنى والأولوية */
2736
+ play: (n: Notification) => void;
2737
+ /** بيرنّ حالاً — لزرار «جرّب الصوت» في الإعدادات */
2738
+ preview: () => void;
2739
+ }
2740
+ declare function useNotificationSound({ kinds }: UseNotificationSoundOptions): NotificationSoundApi;
2741
+
2742
+ interface NotificationsApi {
2743
+ /** كل الرسايل، الأحدث الأول */
2744
+ items: Notification[];
2745
+ /** عدد غير المقروء — ده اللي الجرس بيعرضه */
2746
+ unread: number;
2747
+ /**
2748
+ * غير المقروء اللي «تعليم الكل» مش بيمسحه — الحرج.
2749
+ *
2750
+ * مفصول عن `unread` عن قصد: بعد «تعليم الكل» العدّاد بينزل لكن
2751
+ * مش لصفر، وده بيتقرا عطل لو مافيش رقم تاني بيفسّره. والفصل بيسمح
2752
+ * بوزن بصري مختلف — نقطة حمرا مابتروحش أبداً بترجّع نفس الضغط
2753
+ * اللي بيخلّي التاجر يطفّي الإشعارات.
2754
+ */
2755
+ needsAction: number;
2756
+ /** الوارد لسه — اللي الكروت الطايرة بتعرضه */
2757
+ arrivals: Notification[];
2758
+ /** المرفوض من آخر `hydrate`/`receive` — للتسجيل مش للعرض */
2759
+ rejected: NotificationBatch['rejected'];
2760
+ /**
2761
+ * بيحمّل الموجود من قبل — **صامت وإضافي**.
2762
+ *
2763
+ * بيضيف ويحدّث ومابيشيلش. ده نداء أول تحميل، وتحميل صفحة تانية،
2764
+ * وأي دفعة قديمة.
2765
+ */
2766
+ hydrate: (raw: unknown) => NotificationBatch;
2767
+ /**
2768
+ * مزامنة — **صامتة وبتشيل**.
2769
+ *
2770
+ * زي `hydrate` بس بتشيل كمان اللي السيرفر مابعتوش، **جوّه المدى
2771
+ * الزمني اللي الدفعة بتغطّيه وبس**. فمزامنة الصفحة الأولى مابتمسحش
2772
+ * الصفحات اللي تحتها.
2773
+ */
2774
+ sync: (raw: unknown) => NotificationBatch;
2775
+ /**
2776
+ * بيستقبل وارد جديد — بيرنّ وبيطلع طاير.
2777
+ *
2778
+ * بياخد رسالة واحدة أو دفعة. الرسالة المرفوضة بتتعزل ومابتوقّعش
2779
+ * الباقي.
2780
+ */
2781
+ receive: (raw: unknown) => NotificationBatch;
2782
+ /**
2783
+ * إشعار محلّي من غير سيرفر — بيملى `id` و`at` و`v` لوحده.
2784
+ *
2785
+ * للأفعال اللي التطبيق بيعرف نتيجتها فوراً. بيعدّي على نفس
2786
+ * التحقّق، فالمحلّي مابياخدش طريق جانبي.
2787
+ */
2788
+ push: (input: Omit<NotificationJSON, 'id' | 'at' | 'v'> & {
2789
+ id?: string;
2790
+ at?: string;
2791
+ }) => string | null;
2792
+ markRead: (id: string) => void;
2793
+ markAllRead: () => void;
2794
+ /**
2795
+ * رجّعهم غير مقروئين — للتراجع، ولزرار «علّمه كغير مقروء».
2796
+ *
2797
+ * فعل باسمه زي باقي الـAPI (`dismiss` · `markAllRead` · `sync`)
2798
+ * بدل `setRead(ids, false)`: العلَم البوليان بيخلّي مكان النداء
2799
+ * يحتاج قراية التوقيع عشان يتفهم.
2800
+ */
2801
+ markUnread: (ids: string[]) => void;
2802
+ /** بيلغي شاهد الشيل وبيرجّع الرسالة — للتراجع لما السيرفر يرفض */
2803
+ restore: (n: Notification) => void;
2804
+ /**
2805
+ * السيرفر أكّد الشيل — الشاهد مابقاش لازم.
2806
+ *
2807
+ * من غيرها الشاهد بيستنّى انتهاء صلاحيته على الفاضي، والمجموعة
2808
+ * بتكبر مع كل شيل في الجلسة.
2809
+ */
2810
+ confirmDismiss: (id: string) => void;
2811
+ dismiss: (id: string) => void;
2812
+ clearArrival: (id: string) => void;
2813
+ clearAllArrivals: () => void;
2814
+ }
2815
+ interface UseNotificationsOptions {
2816
+ /**
2817
+ * سجلّ الأنواع — منه بييجي افتراضي الأولوية.
2818
+ *
2819
+ * من غيره أي رسالة مافيهاش `priority` بتاخد `normal`، فالنوع
2820
+ * المسجّل `critical` بيوصل عادي و`needsAction` بتعدّ غلط.
2821
+ */
2822
+ kinds?: NotificationKindRegistry;
2823
+ /** رسايل أولية — بتتحمّل صامتة زي `hydrate` */
2824
+ initial?: unknown;
2825
+ /** بيتنادى لكل وارد جديد اتقبل — ده مكان الصوت */
2826
+ onReceive?: (n: Notification) => void;
2827
+ /** بيتنادى لما رسالة تترفض — سجّلها، متبلعهاش */
2828
+ onReject?: (rejected: NotificationBatch['rejected']) => void;
2829
+ }
2830
+ /** `critical` مابيتعلّمش مقروء بـ«تعليم الكل» — «شفته» مش «عالجته» */
2831
+ declare const isBulkReadable: (n: Notification) => boolean;
2832
+ declare function useNotifications({ kinds, initial, onReceive, onReject, }?: UseNotificationsOptions): NotificationsApi;
2833
+
2834
+ /**
2835
+ * تحديث تفاؤلي بتراجع.
2836
+ *
2837
+ * الواجهة بتتغيّر فوراً، والمزامنة بتجري. لو فشلت، `undo` بترجّع
2838
+ * الحالة و`onError` بيقول للمستخدم — لأن التراجع الصامت أوحش من
2839
+ * الفشل نفسه: العدّاد بيرجع يطلع والمستخدم مايعرفش ليه.
2840
+ *
2841
+ * `run` ممكن يرجّع `void` أو وعد، وممكن يرمي متزامن. التلات حالات
2842
+ * بتتعامل واحد — المستدعي اللي مابيزامنش مابيدفعش تمن، واللي
2843
+ * بيزامن مابيحتاجش يلفّ نداءه في `try`.
2844
+ */
2845
+ declare function optimistic(run: (() => void | Promise<void>) | undefined, undo: () => void, onError?: (error: unknown) => void): void;
2846
+ interface UseNotificationCenterOptions extends UseNotificationsOptions {
2847
+ /** سجلّ الأنواع — بيروح للصوت وبيترجّع عشان يتحطّ في المزوّد */
2848
+ kinds: NotificationKindRegistry;
2849
+ /**
2850
+ * اتقرا إشعار — بالفتح أو بـ«تعليم كمقروء».
2851
+ *
2852
+ * ده مكان المزامنة مع السيرفر. العلامة بتتحطّ **قبل** النداء
2853
+ * (تفاؤلياً) عشان الواجهة ما تستناش الشبكة.
2854
+ *
2855
+ * ── ولو السيرفر رفض ─────────────────────────────────────────────────
2856
+ * ارمي أو رجّع وعداً بيترفض، والمكتبة بترجّع العلامة لوحدها. من
2857
+ * غير كده الواجهة بتوعد بحاجة السيرفر مانفّذهاش: التاجر بيشوف
2858
+ * العدّاد وقع، وبيفتح من جهاز تاني فيلاقيه زي ما هو.
2859
+ *
2860
+ * @example
2861
+ * onRead: async (n) => { await api.markRead(n.id) } // الفشل بيرجّع العلامة
2862
+ */
2863
+ onRead?: (n: Notification) => void | Promise<void>;
2864
+ /** اتقرا الكل — نداء واحد بدل نداء لكل رسالة. الفشل بيرجّع الكل */
2865
+ onReadAll?: (ids: string[]) => void | Promise<void>;
2866
+ /** اتشال من الصندوق. الفشل بيرجّع الرسالة لمكانها */
2867
+ onDismiss?: (n: Notification) => void | Promise<void>;
2868
+ /**
2869
+ * فشلت مزامنة مع السيرفر واتراجعنا — اعرض توست هنا.
2870
+ *
2871
+ * التراجع الصامت أوحش من الفشل نفسه: العدّاد بيرجع يطلع والمستخدم
2872
+ * مايعرفش ليه.
2873
+ *
2874
+ * و`items` جوّه السياق عشان الرسالة تبقى مفيدة: «تعذّر حفظ قراية»
2875
+ * بتسأل «قراية إيه؟»، و«تعذّر حفظ قراية ٣ إشعارات» بترد.
2876
+ */
2877
+ onSyncError?: (error: unknown, context: {
2878
+ action: 'read' | 'readAll' | 'dismiss';
2879
+ items: Notification[];
2880
+ }) => void;
2881
+ /**
2882
+ * اتضغط إجراء الإشعار — الوجهة في `n.action.href`.
2883
+ *
2884
+ * وصّلها براوترك. الإشعار بيتعلّم مقروء لوحده قبل النداء.
2885
+ */
2886
+ onOpen?: (n: Notification) => void;
2887
+ }
2888
+ interface NotificationCenter extends NotificationsApi {
2889
+ sound: NotificationSoundApi;
2890
+ /** نفس السجلّ اللي دخل — عشان `NotificationProvider` ياخده من مصدر واحد */
2891
+ kinds: NotificationKindRegistry;
2892
+ /**
2893
+ * الخصائص الجاهزة للمزوّد والأسطح — بتوصّل الفتح والقراءة لوحدها.
2894
+ *
2895
+ * `<NotificationProvider {...inbox.bind.provider}>` بدل ما تكتب
2896
+ * `onAction` و`onOpen` في كل سطح.
2897
+ */
2898
+ bind: {
2899
+ provider: {
2900
+ kinds: NotificationKindRegistry;
2901
+ onAction: (n: Notification) => void;
2902
+ };
2903
+ surface: {
2904
+ items: Notification[];
2905
+ unread: number;
2906
+ needsAction: number;
2907
+ sound: NotificationSoundApi;
2908
+ onMarkAllRead: () => void;
2909
+ onDismiss: (id: string) => void;
2910
+ onOpen: (n: Notification) => void;
2911
+ };
2912
+ };
2913
+ }
2914
+ /**
2915
+ * الحالة والصوت موصولين — نداء واحد.
2916
+ *
2917
+ * @example
2918
+ * const inbox = useNotificationCenter({
2919
+ * kinds: QUMRA_NOTIFICATIONS,
2920
+ * initial: await api.notifications(), // بيتحمّل صامت
2921
+ * })
2922
+ *
2923
+ * <NotificationProvider kinds={inbox.kinds} onAction={(n) => navigate(n.action.href)}>
2924
+ * <NotificationMenu unread={inbox.unread} items={inbox.items} sound={inbox.sound} … />
2925
+ * <NotificationToastHost items={inbox.arrivals} onClose={inbox.clearArrival} />
2926
+ * </NotificationProvider>
2927
+ *
2928
+ * // والوارد من السوكت — بيرنّ وبيطلع طاير
2929
+ * socket.on('notification', inbox.receive)
2930
+ */
2931
+ declare function useNotificationCenter({ kinds, onReceive, onRead, onReadAll, onDismiss, onOpen, onSyncError, ...rest }: UseNotificationCenterOptions): NotificationCenter;
2932
+
2933
+ /**
2934
+ * الوقت النسبي — «من دقيقتين»، «إمبارح»، «من ٣ شهور».
2935
+ *
2936
+ * أقل من نصّ دقيقة بيتقري «الآن» بدل «قبل ٣٠ ثانية»: الفرق مالوش
2937
+ * معنى للقارئ، والرقم اللي بيتغيّر كل ثانية بيسحب العين. والنصّ من
2938
+ * `Intl` — فبيشتغل على أي لغة من غير ما المكتبة تعرفها.
2939
+ *
2940
+ * @param at وقت الإشعار
2941
+ * @param locale اللغة — الافتراضي `ar`
2942
+ * @param now لحقن الوقت في الاختبار
2943
+ */
2944
+ declare function formatRelativeTime(at: Date, locale?: string, now?: Date): string;
2945
+ /**
2946
+ * كل كام يجب إعادة الرسم عشان النصّ يفضل صح.
2947
+ *
2948
+ * «من دقيقة» بيبقى غلط بعد دقيقة، و«من ٣ شهور» بيفضل صح لأسبوع.
2949
+ * المؤقّت بيتظبط على دقّة الوحدة بدل ما يشتغل كل ثانية على قايمة
2950
+ * فيها أربعين سطر.
2951
+ */
2952
+ declare function relativeTickMs(at: Date, now?: Date): number;
2953
+
2954
+ interface NotificationContext {
2955
+ kinds: NotificationKindRegistry;
2956
+ locale: string;
2957
+ t?: NotificationTranslate;
2958
+ onAction?: (n: Notification) => void;
2959
+ }
2960
+ interface NotificationProviderProps {
2961
+ /** سجلّ الأنواع — الافتراضي سجلّ قمرة */
2962
+ kinds?: NotificationKindRegistry;
2963
+ /** لغة الوقت النسبي — الافتراضي `ar` */
2964
+ locale?: string;
2965
+ /**
2966
+ * دالة الترجمة من نظام مشروعك — لقوالب عناوين الأنواع.
2967
+ *
2968
+ * من غيرها القوالب بتتجاهل ونصّ السيرفر بيتعرض. المكتبة مابتترجمش
2969
+ * بنفسها: بتنادي `t(key, vars)` وبس، فالنصوص بتفضل في كتالوجك
2970
+ * والجمع شغل نظامك.
2971
+ */
2972
+ t?: NotificationTranslate;
2973
+ /**
2974
+ * التنقّل لوجهة الإشعار.
2975
+ *
2976
+ * المكتبة مابتنقّلش بنفسها لأن الرسالة بتحمل `href` مش دالة.
2977
+ * خدها من `n.action.href` ووصّلها لراوترك.
2978
+ */
2979
+ onAction?: (n: Notification) => void;
2980
+ children: ReactNode;
2981
+ }
2982
+ /** بيوزّع السجلّ واللغة والتنقّل على كل الأسطح — مرّة في الجذر */
2983
+ declare function NotificationProvider({ kinds, locale, t, onAction, children, }: NotificationProviderProps): react.JSX.Element;
2984
+ declare const useNotificationContext: () => NotificationContext;
2985
+ interface NotificationBellProps {
2986
+ unread: number;
2987
+ /**
2988
+ * منهم كام محتاج إجراء — بيغيّر **شكل** العدّاد مش رقمه.
2989
+ *
2990
+ * نقطة حمرا مابتروحش أبداً بترجّع نفس الضغط اللي بيخلّي التاجر
2991
+ * يطفّي الإشعارات. فالعدّاد بيفضل رقم غير المقروء، والحرج بيتعلّم
2992
+ * بحلقة حواليه — علامة تانية على نفس الرقم مش رقم تاني.
2993
+ */
2994
+ needsAction?: number;
2995
+ onClick: () => void;
2996
+ /** بيوصل لـ`aria-expanded` — الجرس اللي بيفتح لوح لازم يقولها */
2997
+ expanded?: boolean;
2998
+ label?: string;
2999
+ /** «٣ غير مقروءة» — الرقم في `aria-label` مش في الشكل وحده */
3000
+ unreadLabel?: (n: number) => string;
3001
+ className?: string;
3002
+ }
3003
+ /**
3004
+ * زرّ الجرس بعدّاد غير المقروء.
3005
+ *
3006
+ * العدّاد أحمر ومحاط بحلقة من لون الخلفية — من غيرها الرقم بيتلزق في
3007
+ * أي أيقونة وراه وبيتقرا جزء منها. والرقم في `aria-label` كمان: قارئ
3008
+ * الشاشة مابيشوفش الشارة، وجرس بيقول «الإشعارات» وبس بيخلّي اللي بيسمع
3009
+ * يفتح الصندوق كل مرة عشان يعرف فيه جديد ولا لأ.
3010
+ */
3011
+ declare function NotificationBell({ unread, needsAction, onClick, expanded, label, unreadLabel, className, }: NotificationBellProps): react.JSX.Element;
3012
+ interface NotificationRowProps {
3013
+ item: Notification;
3014
+ /** بيتنادى بعد فتح الوجهة — علّمه مقروء هنا */
3015
+ onOpen?: (n: Notification) => void;
3016
+ onDismiss?: (id: string) => void;
3017
+ dismissLabel?: string;
3018
+ unreadLabel?: string;
3019
+ }
3020
+ /**
3021
+ * سطر إشعار واحد.
3022
+ *
3023
+ * غير المقروء بيتعلّم بحاجتين: نقطة وخطّ أتقل. اللون وحده مابيكفيش —
3024
+ * واحد من كل اتني عشر راجل مابيفرّقش بين درجتين رماديين صغيّرين،
3025
+ * والوزن بيتقرا بالعين مهما كان.
3026
+ *
3027
+ * والسطر **مش زرار كله**. الصندوق فيه سطور بتفتح وسطور بتتقري وبس،
3028
+ * ولو السطر كله قابل للضغط اللي عايز يقرا بيدوس بالغلط ويلاقي نفسه في
3029
+ * صفحة تانية. الإجراء زرار له اسم.
3030
+ */
3031
+ declare function NotificationRow({ item, onOpen, onDismiss, dismissLabel, unreadLabel, }: NotificationRowProps): react.JSX.Element;
3032
+ interface NotificationListProps {
3033
+ items: Notification[];
3034
+ onOpen?: (n: Notification) => void;
3035
+ onDismiss?: (id: string) => void;
3036
+ emptyTitle?: ReactNode;
3037
+ emptyDescription?: ReactNode;
3038
+ className?: string;
3039
+ }
3040
+ /** القايمة نفسها — نفسها في اللوح المنسدل وفي الدرج الجانبي بالظبط */
3041
+ declare function NotificationList({ items, onOpen, onDismiss, emptyTitle, emptyDescription, className, }: NotificationListProps): react.JSX.Element;
3042
+ interface NotificationPanelProps extends NotificationListProps {
3043
+ title?: ReactNode;
3044
+ unread?: number;
3045
+ /**
3046
+ * غير المقروء اللي «تعليم الكل» مش بيمسحه.
3047
+ *
3048
+ * لازم يتعرض: العدّاد بينزل من ١٢ لـ٢ وبيقف، واللي مايعرفش ليه
3049
+ * بيدوس تاني ومافيش، فبيتقرا عطل. السطر بيقول السبب مرّة واحدة.
3050
+ */
3051
+ needsAction?: number;
3052
+ onMarkAllRead?: () => void;
3053
+ markAllLabel?: string;
3054
+ /** تذييل «عرض الكل» — من غيره الصندوق بيبقى نهاية الطريق */
3055
+ onViewAll?: () => void;
3056
+ viewAllLabel?: string;
3057
+ /** زرّ كتم الصوت في الترويسة — مرّره من `useNotificationSound` */
3058
+ sound?: {
3059
+ muted: boolean;
3060
+ setMuted: (m: boolean) => void;
3061
+ ready: boolean;
3062
+ };
3063
+ }
3064
+ /**
3065
+ * اللوح المنسدل — صندوق الإشعارات جنب الجرس.
3066
+ *
3067
+ * ارتفاع القايمة محدود و**بيتمرّر جوّه**: اللوح اللي بيطول بطول القايمة
3068
+ * بيوصل لآخر الشاشة وبيقص آخر إشعار من غير ما يبان إنه مقصوص.
3069
+ *
3070
+ * و«تعليم الكل كمقروء» بيختفي لما يبقى مفيش غير مقروء — زرار بيعمل لا
3071
+ * حاجة موجود دايماً بيعلّم المستخدم إن الأزرار هنا مش بترد.
3072
+ */
3073
+ declare function NotificationPanel({ items, title, unread, needsAction, onMarkAllRead, markAllLabel, onViewAll, viewAllLabel, sound, onOpen, onDismiss, emptyTitle, emptyDescription, className, }: NotificationPanelProps): react.JSX.Element;
3074
+ interface SoundToggleProps {
3075
+ muted: boolean;
3076
+ setMuted: (m: boolean) => void;
3077
+ /** الصوت اتفكّ — قبلها الزرار بيقول إنه مقفول من المتصفّح مش من المستخدم */
3078
+ ready: boolean;
3079
+ className?: string;
3080
+ }
3081
+ /**
3082
+ * كتم صوت الإشعارات.
3083
+ *
3084
+ * الحالة التالتة مهمة: **مش مكتوم بس المتصفّح لسه قافل**. الزرار
3085
+ * بيقولها بدل ما يدّعي إن الصوت شغّال — والمستخدم اللي مستني رنّة
3086
+ * مش جاية يستاهل يعرف السبب.
3087
+ */
3088
+ declare function SoundToggle({ muted, setMuted, ready, className }: SoundToggleProps): react.JSX.Element;
3089
+ interface NotificationMenuProps extends Omit<NotificationPanelProps, 'unread'> {
3090
+ unread: number;
3091
+ bellLabel?: string;
3092
+ /**
3093
+ * الحافة اللي اللوح بيتحاذى عليها مع الجرس — الافتراضي `end`.
3094
+ *
3095
+ * الجرس في الشريط العلوي بيبقى ناحية `end`، فاللوح بيتمدّد ناحية
3096
+ * `start` وبيفضل جوّه الشاشة. لو الجرس اتحرّك لازم ده يتقلب.
3097
+ */
3098
+ align?: 'start' | 'end';
3099
+ /**
3100
+ * فوق الجرس ولا تحته — الافتراضي `bottom`.
3101
+ *
3102
+ * الشريط السفلي على الموبايل محتاج `top`: لوح بينزل من جرس على آخر
3103
+ * الشاشة بيطلع كله برّه.
3104
+ */
3105
+ side?: 'top' | 'bottom';
3106
+ className?: string;
3107
+ }
3108
+ /**
3109
+ * الجرس واللوح كوحدة — ده اللي الشريط العلوي بيحطّه.
3110
+ *
3111
+ * الإغلاق بالضغط برّه وبـEscape. والاتنين لازمين: الضغط برّه هو
3112
+ * المتوقّع بالفأرة، وEscape هو المخرج الوحيد للي ماسك كيبورد.
3113
+ */
3114
+ declare function NotificationMenu({ unread, bellLabel, align, side, className, onViewAll, onOpen, ...panel }: NotificationMenuProps): react.JSX.Element;
3115
+ interface NotificationDrawerProps extends NotificationListProps {
3116
+ open: boolean;
3117
+ onClose: () => void;
3118
+ title?: ReactNode;
3119
+ unread?: number;
3120
+ /** زي `NotificationPanel` — الشرح لازم يبان على الموبايل كمان */
3121
+ needsAction?: number;
3122
+ onMarkAllRead?: () => void;
3123
+ markAllLabel?: string;
3124
+ closeLabel?: string;
3125
+ }
3126
+ /**
3127
+ * الدرج الجانبي — نفس الصندوق لكن من حافة الشاشة.
3128
+ *
3129
+ * ليه التنين مش واحد: اللوح المنسدل معلّق في الجرس، وعلى شاشة ٣٦٠
3130
+ * بكسل ده يعني لوح بيغطّي الشاشة وطرفه بره الحافة. والدرج بيفتح من
3131
+ * `inline-end` — الشمال في العربي واليمين في الإنجليزي، لوحده.
3132
+ *
3133
+ * والقايمة جوّاه **هي هي** بلا فرق حرف: اللي شاف إشعاراً على الديسكتوب
3134
+ * وبصّ له على الموبايل لازم يشوف نفس السطر، وإلا بيفتكرهم اتنين.
3135
+ */
3136
+ declare function NotificationDrawer({ open, onClose, items, title, unread, needsAction, onMarkAllRead, markAllLabel, closeLabel, onOpen, onDismiss, emptyTitle, emptyDescription, }: NotificationDrawerProps): react.JSX.Element;
3137
+ /**
3138
+ * ركن الشاشة اللي الطاير بينزل فيه.
3139
+ *
3140
+ * `start`/`end` منطقية مش يمين وشمال: `end` يعني الشمال في العربي
3141
+ * واليمين في الإنجليزي. الجرس بيقلب مكانه مع اللغة، والإشعار لازم
3142
+ * يقلب معاه — وإلا بيجي من ناحية وبيتخزّن في ناحية تانية.
3143
+ */
3144
+ type NotificationPlacement = 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end';
3145
+ interface NotificationToastHostProps {
3146
+ items: Notification[];
3147
+ onClose: (id: string) => void;
3148
+ onOpen?: (n: Notification) => void;
3149
+ /**
3150
+ * الركن — الافتراضي `top-end` عشان يقع جنب الجرس.
3151
+ *
3152
+ * وخلّيه بعيد عن ركن `ToastHost` (`bottom-start` افتراضاً): التوست
3153
+ * بيقول «الفعل اللي عملته حصل» والإشعار بيقول «حاجة جت من برّه»،
3154
+ * ولو الاتنين طلعوا من نفس المكان بيتقروا طابور واحد.
3155
+ */
3156
+ placement?: NotificationPlacement;
3157
+ /** عرض العمود فوق `sm` — تحتها بياخد العرض كله */
3158
+ width?: string;
3159
+ closeLabel?: string;
3160
+ regionLabel?: string;
3161
+ className?: string;
3162
+ }
3163
+ /**
3164
+ * الإشعار الطاير — الكرت اللي بينزل لما حاجة توصل.
3165
+ *
3166
+ * `aria-live="polite"` مش `assertive`: الأخير بيقطع قارئ الشاشة في
3167
+ * نصّ الجملة. الإشعار مقاطعة أصلاً، مايستاهلش يقاطع مرتين — اللي بيقرا
3168
+ * هيسمعه لما يخلّص السطر.
3169
+ */
3170
+ declare function NotificationToastHost({ items, onClose, onOpen, placement, width, closeLabel, regionLabel, className, }: NotificationToastHostProps): react.JSX.Element | null;
3171
+
3172
+ export { ANIMATE_SCALE, Accordion, type AccordionItem, Alert, type Animation, type AudioLevel, AudioPlayer, type AudioPlayerProps, Avatar, type AvatarSize, Badge, type BadgeProps, BarChart, type BarSeries, BrowserFrame, type BrowserFrameProps, Button, type ButtonProps, type ButtonSize, type ButtonVariant, COLOR_SCALE, CONTAINER_SCALE, Card, CardHeader, Carousel, type CarouselProps, type Chapter, Checkbox, ChoiceCards, type ChoiceOption, type ChoiceProps, Coach, type CoachApi, type CoachAudio, type CoachHint, type CoachItem, type CoachLine, type CoachOrb, CoachProvider, type CoachProviderProps, type CoachRegion, type CoachWhen, type CoachWhere, ColorField, type ColorToken, type Column, Combobox, type CommandItem, CommandPalette, type Container, Counter, type Currency, DARK_TOKENS, DataTable, type DataTableProps, DateRangePicker, Drawer, Dropdown, Dropzone, EmptyState, type FieldSize, FileRow, type FilterChip, FilterChips, FunnelChart, type FunnelStage, Gallery, type GalleryImage, type GalleryProps, GoalBar, Heatmap, Input, type InputProps, Lightbox, type LightboxProps, LocaleCtx, type MediaState, Modal, Money, type MoneyProps, MoneyProvider, MultiSelect, NOTIFICATION_PRIORITIES, NOTIFICATION_SCHEMA_VERSION, NOTIFICATION_SOUNDS, type Notification, type NotificationAction, type NotificationBatch, NotificationBell, type NotificationBellProps, type NotificationCenter, NotificationDrawer, type NotificationDrawerProps, type NotificationJSON, type NotificationKind, type NotificationKindRegistry, NotificationList, type NotificationListProps, NotificationMenu, type NotificationMenuProps, NotificationPanel, type NotificationPanelProps, type NotificationParseResult, type NotificationPlacement, type NotificationPriority, NotificationProvider, type NotificationProviderProps, NotificationRow, type NotificationRowProps, type NotificationSoundApi, type NotificationSoundName, NotificationToastHost, type NotificationToastHostProps, type NotificationTranslate, type NotificationsApi, NumberStepper, type NumberStepperProps, type Option, PROVIDER_LEVEL_LABEL, PROVIDER_LEVEL_LABEL_EN, PageHeader, ParetoChart, type ParetoItem, type ParseOptions, Phone, type PhoneFormat, type PhoneParts, type PhoneProps, Product3DViewer, type Product3DViewerProps, Progress, ProviderBadge, type ProviderBadgeProps, type ProviderBadgeSize, type ProviderLevel, ProviderMark, type ProviderMarkProps, QUMRA_KINDS, QUMRA_NOTIFICATIONS, RADIUS_SCALE, Radio, RadioGroup, type Radius, type Range, RatingInput, type RatingInputProps, type ResolvedKind, type RunwayItem, SHADOW_SCALE, Scrubber, SearchInput, Select, type SelectProps, type Shadow, type ShareItem, ShareList, Sheet, Skeleton, type SortableApi, type SortableItemProps, SortableStatus, SoundToggle, type SoundToggleProps, Sparkline, Stars, type StarsProps, StatCard, type StatCardProps, Stepper, type StepperStep, StockRunway, Switch, type SymbolStyle, TEXT_SCALE, TOKENS, TONE_SOFT, TONE_SOLID, type TabItem, Tabs, TechnicalInput, type TechnicalInputProps, type TechnicalKind, TechnicalText, type TextSize, Textarea, type TextareaProps, Timeline, type TimelineStep, Toast, ToastHost, type ToastInput, type ToastItem, type ToastTone, type TokenName, type Tone, Tooltip, TrendChart, type UITextKey, type UploadFile, type UploadState, type UseNotificationCenterOptions, type UseNotificationSoundOptions, type UseNotificationsOptions, type UseSortableOptions, VerifiedBadge, type VerifiedBadgeProps, VideoPlayer, type VideoPlayerProps, type VideoSuggestion, WaterfallChart, type WaterfallStep, WhatsAppIcon, buttonClasses, cn, coachSeconds, createKindRegistry, currencyName, currencySymbol, daysBetween, formatBytes, formatDate, formatRange, formatRelativeTime, formatTime, isBulkReadable, isCurrency, normalizeHex, optimistic, parseNotification, parseNotifications, parsePhone, presets, relativeTickMs, serializeNotification, toLatinDigits, useAudioLevel, useCoach, useCoachOptional, useCurrency, useCurrencySymbol, useMedia, useMoneyLang, useMoneyLocale, useNotificationCenter, useNotificationContext, useNotificationSound, useNotifications, useSortable, useToasts, useUIText };