@qumra/fanar 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,47 +1,8 @@
1
+ import { B as ButtonVariant, a as ButtonSize, T as Tone } from './lib-DOXggTK6.js';
2
+ export { b as TONE_SOFT, c as TONE_SOLID, d as buttonClasses, e as cn, t as toLatinDigits } from './lib-DOXggTK6.js';
1
3
  import * as react from 'react';
2
4
  import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes, ComponentType, CSSProperties, PointerEvent, KeyboardEvent, RefObject } from 'react';
3
5
 
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
6
  /** سلّم الخط — الدرجة بعد `text-` */
46
7
  declare const TEXT_SCALE: readonly ["micro", "caption", "ui", "body", "lead", "base", "h4", "h3", "h2", "h1", "display", "hero", "title", "mega"];
47
8
  type TextSize = (typeof TEXT_SCALE)[number];
@@ -655,46 +616,53 @@ declare const CURRENCY: {
655
616
  decimals: number;
656
617
  };
657
618
  };
658
- /** صيغة الوحدة المعروضة */
659
- /** الصيغ الصريحةكلٌّ منها يقول شكلاً بعينه */
619
+ /** The displayed unit form */
620
+ /** The explicit forms each names one exact shape */
660
621
  type Base = 'short' | 'word' | 'code' | 'sign';
661
622
  /**
662
- * صيغة الوحدة المعروضة.
623
+ * The displayed unit form.
624
+ *
625
+ * `short` Arabic abbreviation · `word` the word · `code` the ISO code ·
626
+ * `sign` the graphic symbol · `best` whatever the library picks.
663
627
  *
664
- * `short` اختصار عربيّ · `word` الكلمة · `code` رمز ISO · `sign` الرمز
665
- * الرسوميّ · `best` ما تختاره المكتبة.
628
+ * ## `best` is an opinion, not an algorithm
666
629
  *
667
- * ── و`best` ليس خوارزميّة بل رأي ────────────────────────────────────────
668
- * لكل عملة سطر في الجدول يقول أيّ صيغة تُقرأ أسرع **لها هي**، لأن
669
- * الإجابة تختلف بينها:
630
+ * Every currency has a row in the table saying which form reads fastest **for
631
+ * that currency**, because the answer differs between them:
670
632
  *
671
- * · الريال السعوديّرمزه، لأن له رمزاً رسميّاً يعرفه أهله
672
- * · الجنيه والدينار والدرهمكلمتها، فلا رمز رسميّ لها والاختصار
673
- * يُقرأ حرفين قبل أن يُفهم
674
- * · الدولار واليورو والإسترلينيّرموزها، فهي مقروءة عالميّاً
675
- * وأقصر من «دولار»
633
+ * - Saudi riyalits symbol, because it has an official one its readers know
634
+ * - Pound, dinar, dirhamthe word, because they have no official symbol
635
+ * and the abbreviation takes two characters before it means anything
636
+ * - Dollar, euro, sterlingtheir symbols, which read worldwide and are
637
+ * shorter than spelling them out
676
638
  *
677
- * ولو حُسبت هذه بقاعدة واحدة («رمز إن وُجد») لخرج الجنيه `£` وهو
678
- * صحيح تقنيّاً ويُقرأ «إسترلينيّاً» في مصر. الرأي المكتوب لكل عملة
679
- * أصدق من قاعدة تبدو أنظف.
639
+ * Derive these from one rule ("symbol if there is one") and the Egyptian
640
+ * pound comes out as `£` technically correct, and read as *sterling* in
641
+ * Egypt. A written opinion per currency is truer than a rule that looks
642
+ * tidier.
680
643
  *
681
- * ── وفي الإنجليزيّة ────────────────────────────────────────────────────
682
- * `best` يصير الرمز إن وُجد وإلّا رمز ISO — الكلمة العربية لا معنى لها
683
- * في صفحة إنجليزيّة، و«جنيه» لا تُكتب `pound` لأن ذلك يخلطه بالإسترلينيّ.
644
+ * ## In English
645
+ *
646
+ * `best` becomes the symbol where one exists and the ISO code otherwise. The
647
+ * Arabic word means nothing on an English page, and «جنيه» is not rendered as
648
+ * "pound" because that conflates it with sterling.
684
649
  */
685
650
  type SymbolStyle = Base | 'best';
686
651
  type Currency = keyof typeof CURRENCY;
687
652
  /**
688
- * يفحص كود عملة جاءَ من الخادم قبل تمريره إلى `Money`.
653
+ * Checks a currency code coming from the server before passing it to `Money`.
654
+ *
655
+ * ## Why a guard and not `as`
689
656
  *
690
- * ── لماذا حارس لا `as` ──────────────────────────────────────────────────
691
- * `Money.currency` اتّحاد مغلق، والخوادم تُرجع `string`. فكل مستهلك كان
692
- * يكتب `code as Currency` وهذا **إسكات لا فحص**: كود غير معروف
693
- * (`XYZ`، أو حقل فارغ) يمرّ ثم يفشل عند القراءة من الجدول.
657
+ * `Money.currency` is a closed union and servers return `string`, so every
658
+ * caller was writing `code as Currency` which **silences rather than
659
+ * checks**: an unknown code (`XYZ`, or an empty field) passes through and
660
+ * then fails at the table lookup.
694
661
  *
695
- * والحارس يجعل المجهول `undefined و`Money` عندها ترجع إلى عملة المتجر
696
- * من `MoneyProvider` — وهو **السلوك الصحيح**: عرض المبلغ بعملة اللوحة
697
- * أقلّ ضرراً من عرضه برمز خاطئ أو بلا رمز.
662
+ * The guard turns the unknown into `undefined`, and `Money` then falls back
663
+ * to the store currency from `MoneyProvider` — which is the **right**
664
+ * behaviour: showing the amount in the dashboard's currency does less damage
665
+ * than showing it with the wrong symbol, or none.
698
666
  *
699
667
  * ```tsx
700
668
  * <Money value={total} currency={isCurrency(code) ? code : undefined} />
@@ -704,19 +672,21 @@ declare function isCurrency(c?: string | null): c is Currency;
704
672
  declare function MoneyProvider({ currency, locale, children, }: {
705
673
  currency: Currency;
706
674
  /**
707
- * لغة العرض على الخادموسم BCP-47 كامل (`ar-EG` · `ar-MA` · `en`).
675
+ * Display locale on the server a full BCP-47 tag (`ar-EG` · `ar-MA` · `en`).
708
676
  *
709
- * المتصفّح يقرأها من `<html lang>` وحده، فهذه للتصيير من الخادم فقط.
710
- * أهملها ولن يُكسر شيء لكن أوّل رسم سيخرج بأرقام `ar-EG` مهما كانت
711
- * لغة الصفحة. الشرح عند `useMoneyLocale`.
677
+ * The browser reads this from `<html lang>` by itself, so this is for
678
+ * server rendering only. Leave it out and nothing breaks but the first
679
+ * paint will use `ar-EG` digits whatever the page language is. The full
680
+ * explanation is on `useMoneyLocale`.
712
681
  */
713
682
  locale?: string;
714
683
  children: ReactNode;
715
684
  }): react.JSX.Element;
716
685
  /**
717
- * عملة المتجر الحاليّة.
686
+ * The current store currency.
718
687
  *
719
- * لغير `Money`: لاحقة حقل سعر، وعنوان عمود، ونصّ «السعر بالـ…».
688
+ * For everything that is not `Money`: a price field's suffix, a column
689
+ * header, the "priced in …" line.
720
690
  */
721
691
  declare function useCurrency(): Currency;
722
692
  declare const SIZE: {
@@ -734,79 +704,86 @@ declare const TONE: {
734
704
  readonly red: "text-red";
735
705
  };
736
706
  interface MoneyProps {
737
- /** المبلغ بالوحدة الكبرىجنيهات لا قروش */
707
+ /** The amount in major units pounds, not piastres */
738
708
  value: number;
739
- /** استثناء محلّي يغلب عملة المتجرسعر بالدولار في متجر مصريّ */
709
+ /** A local override that beats the store currency a dollar price in an Egyptian store */
740
710
  currency?: Currency;
741
711
  size?: keyof typeof SIZE;
742
712
  /**
743
- * اللون.
713
+ * The colour.
744
714
  *
745
- * الافتراضيّ يرث لون ما حولهوالسالب **لا يُلوَّن تلقائياً**.
746
- * خصم في شلّال ومرتجَع في قائمة كلاهما سالب، والأول محايد والثاني
747
- * يستحقّ الأحمر. الفرق يعرفه السياق لا المكوّن.
715
+ * The default inherits from its surroundings and a negative is **not
716
+ * coloured automatically**. A deduction in a waterfall and a refund in a
717
+ * list are both negative; the first is neutral and the second earns red.
718
+ * Context knows the difference, the component does not.
748
719
  */
749
720
  tone?: keyof typeof TONE;
750
- /** يُظهر `+` على الموجبللفروق لا للأرصدة */
721
+ /** Shows `+` on positivesfor deltas, not balances */
751
722
  signed?: boolean;
752
- /** «٧١٫٤ ألف» بدل «٧١٬٤٠٠»للكروت والرسوم */
723
+ /** "71.4K" instead of "71,400"for stat cards and charts */
753
724
  compact?: boolean;
754
725
  /**
755
- * يُخفي الكسور حين تكون أصفاراً.
726
+ * Hides the decimals when they are zeros.
756
727
  *
757
- * قائمة أسعار كلّها `٫٠٠` تضيف ضجيجاً بلا معلومة. لكن **الفاتورة
758
- * لا تُخفيه**: المبلغ الرسميّ يُكتب كاملاً.
728
+ * A price list that is all `.00` adds noise and no information. But **an
729
+ * invoice does not hide them**: a formal amount is written in full.
759
730
  */
760
731
  trimZeros?: boolean;
761
- /** السعر قبل الخصميُشطب ويوضع بعد الحالي */
732
+ /** The price before the discount struck through, placed after the current one */
762
733
  was?: number;
763
734
  /**
764
- * صيغة الوحدة.
735
+ * The unit form.
765
736
  *
766
- * `short` الاختصار العربيّ (افتراضيّ) · `code` رمز ISO للفاتورة
767
- * والتصدير · `sign` الرمز الرسوميّ حيث يوجد ويحمله الخطّ.
737
+ * `short` the Arabic abbreviation (default) · `code` the ISO code for
738
+ * invoices and exports · `sign` the graphic symbol where one exists and the
739
+ * font carries it.
768
740
  *
769
- * و`sign` يرجع إلى `short` تلقائياً للعملة التي لا رمز لها في الخطّ
770
- * — والقائمة في أعلى الملفّ تقول أيّها.
741
+ * `sign` falls back to `short` automatically for any currency whose symbol
742
+ * is not in the font the table at the top of this file says which.
771
743
  *
772
- * والافتراضيّ يتبع لغة الصفحة: `short` في العربية و`code` في
773
- * الإنجليزية — «ج.م» لا تُقرأ لمن لا يقرأ العربية.
744
+ * The default follows the page language: `short` in Arabic and `code` in
745
+ * English — «ج.م» means nothing to someone who does not read Arabic.
774
746
  */
775
747
  symbol?: SymbolStyle;
776
- /** يُخفي الوحدةلعمود جدول عنوانه يحملها */
748
+ /** Hides the unit for a table column whose header already carries it */
777
749
  hideSymbol?: boolean;
778
750
  className?: string;
779
751
  }
780
752
  /**
781
- * مبلغ.
753
+ * An amount of money.
782
754
  *
783
- * ── لماذا مكوّن لا دالة تنسيق ──────────────────────────────────────────
784
- * الدالة تُرجع نصّاً، والنصّ يفقد ثلاثة أشياء يحتاجها المبلغ: العزل
785
- * الاتجاهيّ حول الرقم، ومنع القطع بين الرقم وعملته، وأرقام بعرض ثابت
786
- * تصطفّ في العمود. كلّها خصائص عرض لا صياغة فمكانها عنصر.
755
+ * ## Why a component and not a format function
756
+ *
757
+ * A function returns a string, and a string loses three things an amount
758
+ * needs: directional isolation around the number, a guarantee the number and
759
+ * its currency never break across lines, and fixed-width digits that line up
760
+ * in a column. All three are presentation, not formatting — so they belong to
761
+ * an element.
787
762
  */
788
763
  declare function Money({ value, currency, size, tone, signed, compact, trimZeros, was, symbol, hideSymbol, className, }: MoneyProps): react.JSX.Element;
789
764
  /**
790
- * وحدة العملة وحدهالعنوان عمود أو لاحقة حقل.
765
+ * The currency unit on its own for a column header or a field suffix.
791
766
  *
792
- * نفس الرجوع: `sign` غير الموجود في الخطّ يعود إلى `short فما يظهر
793
- * في عنوان العمود يطابق ما يظهر في صفوفه دائماً.
767
+ * Same fallback: a `sign` the font does not carry returns `short`, so what
768
+ * appears in the column header always matches what appears in its rows.
794
769
  */
795
770
  /**
796
- * وحدة العملة وحدهالعنوان عمود أو لاحقة حقل.
771
+ * The currency unit on its own for a column header or a field suffix.
797
772
  *
798
- * ترجع `ReactNode` لا نصّاً: وحدة الريال في صيغة `word` **رسم** لأن
799
- * رمزه الرسميّ هو كلمة «ريال» نفسها. من يحتاج نصّاً خالصاً — عنوان
800
- * ملفّ مُصدَّر مثلاًيطلب `code`.
773
+ * Returns a `ReactNode` rather than a string: the riyal's unit in `word` form
774
+ * is **drawn**, because its official symbol is the word "riyal" itself.
775
+ * Anyone who needs plain text the header of an exported file, say — should
776
+ * ask for `code`.
801
777
  */
802
778
  declare function currencySymbol(c?: Currency, style?: SymbolStyle, locale?: string): ReactNode;
803
- /** الاسم المنطوقلقارئ الشاشة وللقوائم المنسدلة */
779
+ /** The spoken name for screen readers and select menus */
804
780
  declare const currencyName: (c?: Currency) => string;
805
781
  /**
806
- * وحدة العملة تابعةً للغة الصفحةلعنوان عمود يحمل عملة صفوفه.
782
+ * The currency unit following the page language for a column header that
783
+ * carries its rows' currency.
807
784
  *
808
- * `currencySymbol` الساكنة لا تعرف اللغة، فعنوان العمود كان يظلّ «ج.م»
809
- * فوق صفوف مكتوبة `EGP`.
785
+ * The static `currencySymbol` does not know the language, so a column header
786
+ * stayed as «ج.م» above rows written `EGP`.
810
787
  */
811
788
  declare function useCurrencySymbol(c?: Currency, style?: SymbolStyle): ReactNode;
812
789
 
@@ -2362,811 +2339,4 @@ declare function Skeleton({ variant, width, className, }: {
2362
2339
  className?: string;
2363
2340
  }): react.JSX.Element;
2364
2341
 
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 };
2342
+ 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, ButtonSize, 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, NumberStepper, type NumberStepperProps, type Option, PROVIDER_LEVEL_LABEL, PROVIDER_LEVEL_LABEL_EN, PageHeader, ParetoChart, type ParetoItem, Phone, type PhoneFormat, type PhoneParts, type PhoneProps, Product3DViewer, type Product3DViewerProps, Progress, ProviderBadge, type ProviderBadgeProps, type ProviderBadgeSize, type ProviderLevel, ProviderMark, type ProviderMarkProps, RADIUS_SCALE, Radio, RadioGroup, type Radius, type Range, RatingInput, type RatingInputProps, type RunwayItem, SHADOW_SCALE, Scrubber, SearchInput, Select, type SelectProps, type Shadow, type ShareItem, ShareList, Sheet, Skeleton, type SortableApi, type SortableItemProps, SortableStatus, Sparkline, Stars, type StarsProps, StatCard, type StatCardProps, Stepper, type StepperStep, StockRunway, Switch, type SymbolStyle, TEXT_SCALE, TOKENS, 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, Tone, Tooltip, TrendChart, type UITextKey, type UploadFile, type UploadState, type UseSortableOptions, VerifiedBadge, type VerifiedBadgeProps, VideoPlayer, type VideoPlayerProps, type VideoSuggestion, WaterfallChart, type WaterfallStep, WhatsAppIcon, coachSeconds, currencyName, currencySymbol, daysBetween, formatBytes, formatDate, formatRange, formatTime, isCurrency, normalizeHex, parsePhone, presets, useAudioLevel, useCoach, useCoachOptional, useCurrency, useCurrencySymbol, useMedia, useMoneyLang, useMoneyLocale, useSortable, useToasts, useUIText };