@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/README.md +62 -16
- package/dist/ai.d.ts +342 -0
- package/dist/ai.js +2 -0
- package/dist/chunk-3CTGRTYV.js +1 -0
- package/dist/chunk-APE2XWSN.js +2 -0
- package/dist/chunk-DDRJTIIP.js +2 -0
- package/dist/chunk-JJCKT5OO.js +2 -0
- package/dist/chunk-L3NDN5GB.js +2 -0
- package/dist/chunk-QJPINFN2.js +2 -0
- package/dist/editor.css +204 -0
- package/dist/editor.d.ts +24 -0
- package/dist/editor.js +2 -0
- package/dist/index.d.ts +88 -918
- package/dist/index.js +1 -8085
- package/dist/lib-DOXggTK6.d.ts +42 -0
- package/dist/lib.js +1 -92
- package/dist/notifications.d.ts +846 -0
- package/dist/notifications.js +2 -0
- package/dist/orb.d.ts +21 -0
- package/dist/orb.js +2 -0
- package/dist/tokens.css +36 -333
- package/dist/tokens.js +1 -20
- package/dist/tokens.json +64 -155
- package/package.json +64 -6
- package/dist/chunk-SFA2EQFK.js +0 -159
package/README.md
CHANGED
|
@@ -1,34 +1,80 @@
|
|
|
1
1
|
# `@qumra/fanar`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Qumra's component library and design tokens — **Arabic-first**, Tailwind 4,
|
|
4
|
+
RSC-safe.
|
|
5
|
+
|
|
6
|
+
Every component works in both `dir="rtl"` and `dir="ltr"` with no
|
|
7
|
+
direction-specific code: logical properties only, and the library reads its
|
|
8
|
+
own language from `<html lang>`.
|
|
4
9
|
|
|
5
10
|
```bash
|
|
6
11
|
pnpm add @qumra/fanar
|
|
7
12
|
```
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
## Entry points
|
|
15
|
+
|
|
16
|
+
The package is one install with **seven entry points**. Importing
|
|
17
|
+
`@qumra/fanar` pulls in neither TipTap, nor `three`, nor the notification
|
|
18
|
+
system — each heavy group is behind its own path.
|
|
19
|
+
|
|
20
|
+
| Import | What it gives you | Notes |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| `@qumra/fanar` | Components | client |
|
|
23
|
+
| `@qumra/fanar/lib` | Pure helpers (`cn`, `toLatinDigits`) | server-safe |
|
|
24
|
+
| `@qumra/fanar/tokens` | Token values (`TOKENS`, scales) | server-safe |
|
|
25
|
+
| `@qumra/fanar/notifications` | Notification system | client |
|
|
26
|
+
| `@qumra/fanar/ai` | Assistant surfaces | needs `@qumra/jawab-ai` |
|
|
27
|
+
| `@qumra/fanar/orb` | Animated voice orb | needs `three` |
|
|
28
|
+
| `@qumra/fanar/editor` | Rich-text editor | bundles TipTap |
|
|
29
|
+
|
|
30
|
+
Plus two stylesheets: `@qumra/fanar/tokens.css` and
|
|
31
|
+
`@qumra/fanar/editor.css`.
|
|
32
|
+
|
|
33
|
+
## Setup
|
|
14
34
|
|
|
15
35
|
```css
|
|
36
|
+
/* styles.css */
|
|
16
37
|
@import 'tailwindcss';
|
|
17
38
|
@import '@qumra/fanar/tokens.css';
|
|
18
39
|
```
|
|
19
40
|
|
|
20
|
-
|
|
41
|
+
```tsx
|
|
42
|
+
import { Button, Money } from '@qumra/fanar'
|
|
43
|
+
import { cn } from '@qumra/fanar/lib' // usable from a server component
|
|
44
|
+
import { TOKENS } from '@qumra/fanar/tokens'
|
|
45
|
+
|
|
46
|
+
;<Button variant="primary">
|
|
47
|
+
Pay <Money value={1250} currency="EGP" />
|
|
48
|
+
</Button>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The six rules
|
|
21
52
|
|
|
22
|
-
|
|
23
|
-
حقيقية · الأرقام بـ`data-numeric` · المقاسات من السلّم.
|
|
53
|
+
Every component in this library follows them, and two are enforced by lint:
|
|
24
54
|
|
|
25
|
-
|
|
55
|
+
1. **No hand-written colors.** Every color comes from a token.
|
|
56
|
+
2. **Surfaces use semantic tokens** — `bg-surface`, `text-ink`,
|
|
57
|
+
`border-line`. These flip themselves in dark mode.
|
|
58
|
+
3. **Logical properties only** — `ps-4` not `pl-4`, `start-0` not `left-0`.
|
|
59
|
+
4. **Real elements.** Anything clickable is a `<button>` or an `<a>`; every
|
|
60
|
+
field is a `<label htmlFor>` plus `aria-describedby` for its error.
|
|
61
|
+
5. **Numbers carry `data-numeric`** — pins LTR direction and turns on
|
|
62
|
+
`tabular-nums`.
|
|
63
|
+
6. **Sizes come from the scale** — `text-ui`, `rounded-card`, `shadow-modal`.
|
|
26
64
|
|
|
27
|
-
##
|
|
65
|
+
## Peer dependencies
|
|
28
66
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
67
|
+
`react` and `react-dom` are required. `tailwindcss`, `three`,
|
|
68
|
+
`@google/model-viewer`, and `@qumra/jawab-ai` are **optional** — you only install
|
|
69
|
+
the ones whose entry point you actually import.
|
|
70
|
+
|
|
71
|
+
## Documentation
|
|
72
|
+
|
|
73
|
+
Source, decision log, and a live catalogue with a page per component live in
|
|
74
|
+
the repository. Comments and internal docs there are written in Egyptian
|
|
75
|
+
Arabic: they are the record of why each decision was made, kept in the
|
|
76
|
+
language the team argued them in.
|
|
77
|
+
|
|
78
|
+
## License
|
|
33
79
|
|
|
34
|
-
|
|
80
|
+
UNLICENSED — see `package.json`.
|
package/dist/ai.d.ts
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentType, ReactNode } from 'react';
|
|
3
|
+
import { Json, Reply, AskResult, AskBlock } from '@qumra/jawab-ai';
|
|
4
|
+
|
|
5
|
+
/** أيقونة المساعد — بتاخد حالته فبتوريك هو بيعمل إيه دلوقتي */
|
|
6
|
+
declare function AiAvatar({ state,
|
|
7
|
+
/** مرجع مستوى الصوت ٠–١ — بينبض معاه لما يكون بيتكلم */
|
|
8
|
+
level, size, icon: Icon, }: {
|
|
9
|
+
state?: 'idle' | 'thinking' | 'speaking';
|
|
10
|
+
level?: React.RefObject<number>;
|
|
11
|
+
size?: 'sm' | 'md' | 'lg';
|
|
12
|
+
icon?: ComponentType<{
|
|
13
|
+
size?: number;
|
|
14
|
+
strokeWidth?: number;
|
|
15
|
+
className?: string;
|
|
16
|
+
}>;
|
|
17
|
+
}): react.JSX.Element;
|
|
18
|
+
/**
|
|
19
|
+
* ثلاث نقط بتتحرّك.
|
|
20
|
+
*
|
|
21
|
+
* `role="status"` مع `aria-live` — قارئ الشاشة لازم يعرف إن فيه رد جايّ،
|
|
22
|
+
* وإلا بيبقى قدام سكون مش مفهوم.
|
|
23
|
+
*/
|
|
24
|
+
declare function AiThinking({ label }: {
|
|
25
|
+
label?: string;
|
|
26
|
+
}): react.JSX.Element;
|
|
27
|
+
/**
|
|
28
|
+
* «المساعد عمل كذا».
|
|
29
|
+
*
|
|
30
|
+
* أهم عنصر في الملف ده. النموذج اللي بيغيّر بيانات لازم **يقول إنه
|
|
31
|
+
* غيّر إيه بالظبط** قبل ما المستخدم يكتشف بنفسه — و«تم» لوحدها مش
|
|
32
|
+
* كفاية: لازم اللي اتعمل والرجوع عنه.
|
|
33
|
+
*/
|
|
34
|
+
declare function AiToolCall({ icon: Icon, title, detail, state, onUndo, undoLabel, }: {
|
|
35
|
+
icon?: ComponentType<{
|
|
36
|
+
size?: number;
|
|
37
|
+
}>;
|
|
38
|
+
title: ReactNode;
|
|
39
|
+
/** إيه اللي اتغيّر بالظبط — مش «تم بنجاح» */
|
|
40
|
+
detail?: ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* `reverted` مش `failed`.
|
|
43
|
+
*
|
|
44
|
+
* اللي المستخدم رجع عنه **نجح** — هو بس مارضيوش. لو اتعرض أحمر
|
|
45
|
+
* بمثلّث تحذير بيقرا «حصل خطأ»، فبيدوّر على عطل مش موجود. الرمادي
|
|
46
|
+
* بيقول «اتنفّذ واترجع» — وده الصح.
|
|
47
|
+
*/
|
|
48
|
+
state?: 'running' | 'done' | 'failed' | 'reverted';
|
|
49
|
+
onUndo?: () => void;
|
|
50
|
+
undoLabel?: string;
|
|
51
|
+
}): react.JSX.Element;
|
|
52
|
+
interface AiSource {
|
|
53
|
+
id: string;
|
|
54
|
+
label: string;
|
|
55
|
+
/** رابط داخلي — «شاشة المخزون» مثلاً */
|
|
56
|
+
href?: string;
|
|
57
|
+
onOpen?: () => void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* من فين جه الرد.
|
|
61
|
+
*
|
|
62
|
+
* ده اللي بيحوّل الرد من «كلام» لـ«كلام تقدر تتأكد منه». من غيره
|
|
63
|
+
* المستخدم إما يصدّق أعمى أو يتجاهل — والاتنين مش المطلوب.
|
|
64
|
+
*/
|
|
65
|
+
declare function AiSources({ sources, label }: {
|
|
66
|
+
sources: AiSource[];
|
|
67
|
+
label?: string;
|
|
68
|
+
}): react.JSX.Element | null;
|
|
69
|
+
interface AiMessageProps {
|
|
70
|
+
role: 'user' | 'assistant';
|
|
71
|
+
children: ReactNode;
|
|
72
|
+
/** بيتكتب دلوقتي — بيعرض مؤشّر ويخفي الأفعال */
|
|
73
|
+
streaming?: boolean;
|
|
74
|
+
sources?: AiSource[];
|
|
75
|
+
/** نص خام للنسخ — لو المحتوى مش نص بسيط */
|
|
76
|
+
copyText?: string;
|
|
77
|
+
onRetry?: () => void;
|
|
78
|
+
onFeedback?: (v: 'up' | 'down') => void;
|
|
79
|
+
/** بطاقات الأدوات اللي اتنفّذت مع الرد */
|
|
80
|
+
tools?: ReactNode;
|
|
81
|
+
/**
|
|
82
|
+
* الرسالة تاخد عرض العمود كله بدل ما تتقلّص على محتواها.
|
|
83
|
+
*
|
|
84
|
+
* ── ليه خيار مش سلوك واحد ─────────────────────────────────────────
|
|
85
|
+
* الفقاعة اللي بتتقلّص على كلامها هي الصح في محادثة نصّ: السطر
|
|
86
|
+
* القصير بيبان قصير، والعين بتفرّق بين الرسايل من أطوالها.
|
|
87
|
+
*
|
|
88
|
+
* لكن الرسالة اللي جوّاها **جدول أو رسم أو كروت** مالهاش عرض طبيعي
|
|
89
|
+
* — بتمدّ لآخر المسموح. والنتيجة محادثة أطوالها بتنطّ: ردّ بسطر
|
|
90
|
+
* ضيّق، وتحته ردّ بجدول واخد ٨٨٪، وتحته ردّ برقم. ده بيتقري عطل
|
|
91
|
+
* تخطيط مش تنوّع محتوى.
|
|
92
|
+
*
|
|
93
|
+
* فالنصّ بيتقلّص، والردّ المهيكل بيملا. `ReplyView` بيحطّها دايماً.
|
|
94
|
+
*/
|
|
95
|
+
fill?: boolean;
|
|
96
|
+
}
|
|
97
|
+
declare function AiMessage({ role, children, streaming, sources, copyText, onRetry, onFeedback, tools, fill, }: AiMessageProps): react.JSX.Element;
|
|
98
|
+
/**
|
|
99
|
+
* تنويه إن الرد من نموذج.
|
|
100
|
+
*
|
|
101
|
+
* سطر واحد تحت المحادثة مش تحت كل رسالة — التكرار بيخلّي العين
|
|
102
|
+
* تتجاهله، والمرة الواحدة بتفضل مقروءة.
|
|
103
|
+
*/
|
|
104
|
+
declare function AiDisclaimer({ children }: {
|
|
105
|
+
children?: ReactNode;
|
|
106
|
+
}): react.JSX.Element;
|
|
107
|
+
|
|
108
|
+
/** رقاقات اقتراح — بتختفي أول ما المحادثة تبدأ */
|
|
109
|
+
declare function AiPromptChips({ prompts, onPick }: {
|
|
110
|
+
prompts: string[];
|
|
111
|
+
onPick: (text: string) => void;
|
|
112
|
+
}): react.JSX.Element | null;
|
|
113
|
+
interface AiComposerProps {
|
|
114
|
+
value: string;
|
|
115
|
+
onChange: (v: string) => void;
|
|
116
|
+
onSend: (text: string) => void;
|
|
117
|
+
placeholder?: string;
|
|
118
|
+
/** بيتولّد رد دلوقتي — الزرار بيتحوّل لإيقاف */
|
|
119
|
+
busy?: boolean;
|
|
120
|
+
onStop?: () => void;
|
|
121
|
+
/** بيظهر زرار الميكروفون. الناتج مدة التسجيل بالثواني. */
|
|
122
|
+
onVoice?: (seconds: number) => void;
|
|
123
|
+
onAttach?: () => void;
|
|
124
|
+
disabled?: boolean;
|
|
125
|
+
className?: string;
|
|
126
|
+
}
|
|
127
|
+
declare function AiComposer({ value, onChange, onSend, placeholder, busy, onStop, onVoice, onAttach, disabled, className, }: AiComposerProps): react.JSX.Element;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* نص بيتكشف تدريجياً.
|
|
131
|
+
*
|
|
132
|
+
* بيحاكي البثّ في التصميم، **وبيشتغل مع بثّ حقيقي كمان**: ناد `push`
|
|
133
|
+
* مع كل جزء واصل من السيرفر بدل ما تديه النص كامل من الأول.
|
|
134
|
+
*
|
|
135
|
+
* الكشف بالحرف مش بالكلمة عن قصد — الكلمة بتخلّي السطر يقفز في العربي
|
|
136
|
+
* لأن عرض الكلمات مختلف، والحرف بيدّي تدفّق أنعم.
|
|
137
|
+
*/
|
|
138
|
+
declare function useStreamingText({
|
|
139
|
+
/** حرف كل كام ملي — الافتراضي ١٨ يعني ~٥٥ حرف في الثانية */
|
|
140
|
+
speed, }?: {
|
|
141
|
+
speed?: number;
|
|
142
|
+
}): {
|
|
143
|
+
text: string;
|
|
144
|
+
streaming: boolean;
|
|
145
|
+
start: (text: string) => void;
|
|
146
|
+
push: (chunk: string) => void;
|
|
147
|
+
stop: () => void;
|
|
148
|
+
finish: () => void;
|
|
149
|
+
reset: () => void;
|
|
150
|
+
};
|
|
151
|
+
interface MicLevel {
|
|
152
|
+
/** ٠–١ — اقرا `.current` جوّه حلقة رسم عندك */
|
|
153
|
+
level: React.RefObject<number>;
|
|
154
|
+
recording: boolean;
|
|
155
|
+
/** بالثواني منذ بدء التسجيل */
|
|
156
|
+
seconds: number;
|
|
157
|
+
start: () => Promise<void>;
|
|
158
|
+
stop: () => void;
|
|
159
|
+
/** المستخدم رفض إذن الميكروفون أو مافيش جهاز */
|
|
160
|
+
denied: boolean;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* تسجيل صوتي بمؤشّر مستوى حيّ.
|
|
164
|
+
*
|
|
165
|
+
* المؤشّر مش زخرفة: من غيره المستخدم مش عارف إذا الميكروفون شغّال ولا
|
|
166
|
+
* لأ إلا لما يخلّص ويسمع. المستوى الحيّ بيقول «صوتك واصل» وهو بيتكلم.
|
|
167
|
+
*
|
|
168
|
+
* بيرجّع المستوى في **مرجع** مش حالة — التسجيل بيحدّث ٦٠ مرة في الثانية،
|
|
169
|
+
* والحالة كانت هترسم الواجهة كلها بنفس المعدّل.
|
|
170
|
+
*/
|
|
171
|
+
declare function useMicLevel(): MicLevel;
|
|
172
|
+
|
|
173
|
+
/** سجلّ النوايا — الواجهة بتقول كل نيّة بتروح فين عندها */
|
|
174
|
+
type IntentMap = Record<string, (args: Json | undefined) => void>;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* ردّ المساعد مرسوماً.
|
|
178
|
+
*
|
|
179
|
+
* ── ليه الرسّام هنا لا في `@qumra/jawab-ai` ──────────────────────────────────
|
|
180
|
+
* العقد لازم يقف لوحده عشان الباك‑اند ياخده من غير React. الرسم لأ:
|
|
181
|
+
* هو محتاج نظام تصميم كامل — جدول بترقيم، وكرت إحصائي بقاعدة «مافيش
|
|
182
|
+
* نسبة على أساس صغير»، ورسم بمحاور مضبوطة، وعارض مبالغ بيعرف عملة
|
|
183
|
+
* المتجر. النسخة المستقلّة منه كانت هتعيد بناء ده كله أفقر، والهوية
|
|
184
|
+
* هتطلع «قريبة وغلط» — وده أوحش من اختلاف صريح.
|
|
185
|
+
*
|
|
186
|
+
* فالخطّ بين اللي الطرفين بيتشاركوه (العقد) واللي واحد بس محتاجه (الرسم).
|
|
187
|
+
*/
|
|
188
|
+
interface ReplyViewProps {
|
|
189
|
+
reply: Reply;
|
|
190
|
+
/** بيتكتب دلوقتي — بيعرض المؤشّر ويخفي الأفعال */
|
|
191
|
+
streaming?: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* سجلّ النوايا.
|
|
194
|
+
*
|
|
195
|
+
* الباك‑اند بيبعت `intent: 'cart.recover'` لا `href: '/carts/88'` —
|
|
196
|
+
* هو مايعرفش راوتنج الويب، وأكيد مايعرفش راوتنج الموبايل. الخريطة دي
|
|
197
|
+
* هي اللي بتحوّل النيّة لوجهة، وبتتعرّف في كل تطبيق على حدة.
|
|
198
|
+
*/
|
|
199
|
+
intents?: IntentMap;
|
|
200
|
+
/** بلوك `chips` بيناديها. من غيرها الرقاقات ماتترسمش */
|
|
201
|
+
onSend?: (text: string) => void;
|
|
202
|
+
/** بلوك `draft` بيناديها لما التاجر يضغط «أدرِج» */
|
|
203
|
+
onInsertDraft?: (text: string) => void;
|
|
204
|
+
/** بلوك `ask` بيناديها — التطبيق بيبعت الإجابة كدور جديد */
|
|
205
|
+
onAnswer?: (id: string, result: AskResult) => void;
|
|
206
|
+
/**
|
|
207
|
+
* الردّ ده هو الأخير في المحادثة؟
|
|
208
|
+
*
|
|
209
|
+
* بيخصّ بلوك `ask` بس: السؤال في ردّ قديم بيتعرض مقفول. الإجابة على
|
|
210
|
+
* سؤال اتسأل من تلات أدوار بتجاوب سياق راح، والباك‑اند بيستلم إجابة
|
|
211
|
+
* مالهاش محلّ.
|
|
212
|
+
*/
|
|
213
|
+
live?: boolean;
|
|
214
|
+
onRetry?: () => void;
|
|
215
|
+
onFeedback?: (v: 'up' | 'down') => void;
|
|
216
|
+
className?: string;
|
|
217
|
+
}
|
|
218
|
+
declare function ReplyView({ reply, streaming, intents, onSend, onInsertDraft, onAnswer, live, onRetry, onFeedback, className, }: ReplyViewProps): react.JSX.Element;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* المساعد بيسأل.
|
|
222
|
+
*
|
|
223
|
+
* ── سؤال في المرة ─────────────────────────────────────────────────────
|
|
224
|
+
* التلات أسئلة نازلين مع بعض كانوا **استمارة**: تسع كروت خيارات في
|
|
225
|
+
* عمود واحد، وعلى ٣٩٠px بقت شاشتين تمرير قبل ما تشوف زرار الإرسال.
|
|
226
|
+
* والاستمارة بتتأجّل، والسؤال بيتجاوب.
|
|
227
|
+
*
|
|
228
|
+
* فبقى سؤال في المرة بعدّاد («٢ من ٣») ورجوع. نفس اللي أسئلة كلود
|
|
229
|
+
* بتعمله، وللسبب نفسه: القرار الواحد بيتاخد أسرع لما يبقى القرار
|
|
230
|
+
* الوحيد المعروض.
|
|
231
|
+
*
|
|
232
|
+
* ── وتلات قواعد بتفرق بين مساعدة وإزعاج ───────────────────────────────
|
|
233
|
+
*
|
|
234
|
+
* **بيتقفل بعد الإجابة ومابيختفيش** — وبيتعرض ساعتها **كله مرّة واحدة**
|
|
235
|
+
* لا مقسّم. التقسيم للإدخال؛ السجلّ بيتقرا. والسؤال اللي بيختفي بيسيب
|
|
236
|
+
* الردّ اللي بعده بلا سبب مفهوم.
|
|
237
|
+
*
|
|
238
|
+
* **«غير كده» موجودة دايماً** إلا لو اتقفلت صراحةً — الخيارات تخمين من
|
|
239
|
+
* النموذج، ومن غير مهرب التاجر بيختار أقرب حاجة غلط.
|
|
240
|
+
*
|
|
241
|
+
* **السؤال القديم مايتجاوبش** — اللي حيّ هو آخر دور بس.
|
|
242
|
+
*/
|
|
243
|
+
declare function AskCard({ block, onAnswer, live, }: {
|
|
244
|
+
block: AskBlock;
|
|
245
|
+
onAnswer?: (id: string, result: AskResult) => void;
|
|
246
|
+
/** `false` بيقفله — سؤال من دور قديم */
|
|
247
|
+
live?: boolean;
|
|
248
|
+
}): react.JSX.Element;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* مسوّدة من المساعد — **جوّه الشاشة اللي فيها الشغل**.
|
|
252
|
+
*
|
|
253
|
+
* ── ليه هنا لا في درج «أدوات AI» ──────────────────────────────────────
|
|
254
|
+
* التاجر مابيفتحش لوحته وهو عايز «يستخدم ذكاء اصطناعي» — هو عايز يكتب
|
|
255
|
+
* وصف، أو يردّ على مراجعة، أو يستردّ سلّة. والأداة اللي ساكنة في قسم
|
|
256
|
+
* مستقلّ بتتطلب بعد ما التاجر يفتكر إنها موجودة، وهو مابيفتكرش.
|
|
257
|
+
*
|
|
258
|
+
* ── وأربع قيود بتفصل بين مساعدة وإزعاج ────────────────────────────────
|
|
259
|
+
*
|
|
260
|
+
* **مابيكتبش فوق حاجة.** المسوّدة بتظهر في لوح تحته، و«أدرِج» فعل صريح
|
|
261
|
+
* منك. الأداة اللي بتستبدل اللي كتبته بتخلّيك تخاف تضغط عليها.
|
|
262
|
+
*
|
|
263
|
+
* **بيقول على أيّ حاجة اتبنى.** «من اسم المنتج وتلات صور» — الاقتراح
|
|
264
|
+
* بلا مصدر بيتقري سحراً، والسحر مابيتراجعش.
|
|
265
|
+
*
|
|
266
|
+
* **بيتعاد.** أول ناتج مش دايماً المطلوب، ومن غير إعادة بيفضل الاختيار
|
|
267
|
+
* بين قبول اللي مش عاجبك وترك الأداة.
|
|
268
|
+
*
|
|
269
|
+
* **بيتقال إنه ترجيح لا حقيقة.** `AiDisclaimer` تحت كل مسوّدة.
|
|
270
|
+
*
|
|
271
|
+
* ── وليه في المكتبة مش في التطبيق ─────────────────────────────────────
|
|
272
|
+
* كان في `apps/qumra-webapp/src/components/`. اتنقل هنا لأن بلوك `draft`
|
|
273
|
+
* في العقد بيرسمه، يعني بقى جزء من ردّ المساعد لا مكوّن شاشة — واللوحة
|
|
274
|
+
* والتطبيق الاتنين محتاجينه بنفس الشكل.
|
|
275
|
+
*/
|
|
276
|
+
interface DraftPanelProps {
|
|
277
|
+
/**
|
|
278
|
+
* النصّ المولَّد.
|
|
279
|
+
*
|
|
280
|
+
* دالّة لما الإعادة تدّي غيره — الشاشات بتبعت دالّة، وبلوك `draft`
|
|
281
|
+
* في العقد بيبعت نصّ ثابت (الباك‑اند هو اللي بيولّد، مش الواجهة).
|
|
282
|
+
*/
|
|
283
|
+
draft: string | ((attempt: number) => string);
|
|
284
|
+
/**
|
|
285
|
+
* على أيّ حاجة اتبنت — بيظهر فوقها.
|
|
286
|
+
*
|
|
287
|
+
* `ReactNode` مش `string`: الشاشات بتلفّ الأرقام جوّاها في
|
|
288
|
+
* `<span data-num>` عشان الرقم يتعرض بالخط الصح جوّه جملة عربية.
|
|
289
|
+
*/
|
|
290
|
+
basis: ReactNode;
|
|
291
|
+
/** نصّ العنوان — **بالشغل** لا بالتقنية: «اكتب الوصف» لا «توليد بالـAI» */
|
|
292
|
+
label: string;
|
|
293
|
+
/** بيحطّ المسوّدة في مكانها — من غيره بتفضل للنسخ بس */
|
|
294
|
+
onInsert?: (text: string) => void;
|
|
295
|
+
onClose?: () => void;
|
|
296
|
+
insertLabel?: string;
|
|
297
|
+
className?: string;
|
|
298
|
+
}
|
|
299
|
+
declare function DraftPanel({ draft: source, basis, label, onInsert, onClose, insertLabel, className, }: DraftPanelProps): react.JSX.Element;
|
|
300
|
+
interface AiDraftProps extends Omit<DraftPanelProps, 'onClose'> {
|
|
301
|
+
size?: 'sm' | 'md';
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* الزرار اللي بيفتح اللوح.
|
|
305
|
+
*
|
|
306
|
+
* الزرار في **مكان الشغل** — جنب حقل الوصف، تحت المراجعة، في كرت
|
|
307
|
+
* السلّة — مش في درج «أدوات AI». التاجر مابيفتحش لوحته وهو عايز يستخدم
|
|
308
|
+
* ذكاء اصطناعي؛ هو عايز يكتب وصف. والأداة اللي في قسم مستقلّ بتتطلب بعد
|
|
309
|
+
* ما يفتكر إنها موجودة، وهو مابيفتكرش.
|
|
310
|
+
*/
|
|
311
|
+
declare function AiDraft({ size, ...panel }: AiDraftProps): react.JSX.Element;
|
|
312
|
+
|
|
313
|
+
interface ReplyStreamError {
|
|
314
|
+
code: string;
|
|
315
|
+
message: string;
|
|
316
|
+
/** آخر سؤال اتبعت — عشان زرار «حاول تاني» يبعته من غير ما التاجر يكتبه */
|
|
317
|
+
lastInput: string;
|
|
318
|
+
}
|
|
319
|
+
interface ReplyStream {
|
|
320
|
+
reply: Reply | null;
|
|
321
|
+
streaming: boolean;
|
|
322
|
+
error: ReplyStreamError | null;
|
|
323
|
+
send: (text: string) => void;
|
|
324
|
+
stop: () => void;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* بثّ ردّ من الخادم.
|
|
328
|
+
*
|
|
329
|
+
* ── ليه هوك ومش `fetch` في كل شاشة ────────────────────────────────────
|
|
330
|
+
* المنطق اللي بين الشبكة والشاشة مش سطرين: قصّ الشبكة للأحداث في نصّها،
|
|
331
|
+
* والتجميع، والإلغاء لما التاجر يبعت سؤال تاني وهو لسه بيقرا الرد اللي
|
|
332
|
+
* قبله، وتنضيف الاتصال لما يقفل الدرج. الشاشتين لو كتبوه كل واحدة
|
|
333
|
+
* لوحدها، ينحرفوا — وده بالظبط اللي حصل مع `interface Message`.
|
|
334
|
+
*
|
|
335
|
+
* ── والإلغاء قبل أي حاجة ──────────────────────────────────────────────
|
|
336
|
+
* `AbortController` جديد لكل إرسال، والقديم بيتلغي فوراً. من غيره الردّ
|
|
337
|
+
* القديم بيفضل بيوصل ويكتب فوق الجديد، فالتاجر بيشوف إجابة سؤال سابق
|
|
338
|
+
* تحت سؤاله الحالي.
|
|
339
|
+
*/
|
|
340
|
+
declare function useReplyStream(url: string, init?: RequestInit): ReplyStream;
|
|
341
|
+
|
|
342
|
+
export { AiAvatar, AiComposer, type AiComposerProps, AiDisclaimer, AiDraft, type AiDraftProps, AiMessage, type AiMessageProps, AiPromptChips, type AiSource, AiSources, AiThinking, AiToolCall, AskCard, DraftPanel, type DraftPanelProps, type IntentMap, type MicLevel, type ReplyStream, type ReplyStreamError, ReplyView, type ReplyViewProps, useMicLevel, useReplyStream, useStreamingText };
|
package/dist/ai.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{BarChart,ChoiceCards,DataTable,Money,TrendChart,isCurrency}from"./chunk-QJPINFN2.js";import{Button,Input,Textarea}from"./chunk-L3NDN5GB.js";import{Badge,Card,StatCard,formatTime}from"./chunk-JJCKT5OO.js";import{Alert,Modal,cn,useUIText}from"./chunk-DDRJTIIP.js";import{useEffect,useRef,useState}from"react";import{Bot,Check,Copy,ExternalLink,RotateCcw,ThumbsDown,ThumbsUp,TriangleAlert}from"lucide-react";import{Fragment,jsx,jsxs}from"react/jsx-runtime";function AiAvatar({state="idle",level,size="md",icon:Icon=Bot}){const ring=useRef(null);useEffect(()=>{if(state!=="speaking"||!level)return;let raf=0;const loop=()=>{const v=level.current??0;if(ring.current){ring.current.style.transform=`scale(${1+v**1.6*.9})`;ring.current.style.opacity=String(Math.min(.45,v))}raf=requestAnimationFrame(loop)};raf=requestAnimationFrame(loop);const el=ring.current;return()=>{cancelAnimationFrame(raf);if(el)el.style.opacity="0"}},[state,level]);const box={sm:"size-8",md:"size-9",lg:"size-12"}[size];const px={sm:16,md:18,lg:24}[size];return jsxs("span",{className:"relative inline-flex shrink-0",children:[jsx("span",{ref:ring,"aria-hidden":"true",className:cn("absolute inset-0 rounded-sm bg-brand opacity-0",box),style:{transition:"transform 90ms linear, opacity 90ms linear"}}),jsx("span",{"aria-hidden":"true",className:cn("relative rounded-sm bg-soft border border-soft2 flex items-center justify-center",box,state==="thinking"&&"animate-pulse"),children:jsx(Icon,{size:px,strokeWidth:2,className:"text-brand"})})]})}function AiThinking({label}){const ui=useUIText();return jsxs("span",{role:"status","aria-live":"polite",className:"flex items-center gap-2.5",children:[jsx(AiAvatar,{size:"sm",state:"thinking"}),jsxs("span",{className:"flex items-center gap-2 py-2.5 px-3.5 rounded-card bg-bg border border-line",children:[jsx("span",{"aria-hidden":"true",className:"flex items-center gap-1",children:[0,1,2].map(i=>jsx("span",{className:"size-1.5 rounded-full bg-muted2 animate-bounce",style:{animationDelay:`${i*140}ms`,animationDuration:"900ms"}},i))}),jsx("span",{className:"text-caption text-muted",children:label??ui.shehabThinking})]})]})}function AiToolCall({icon:Icon,title,detail,state="done",onUndo,undoLabel}){const ui=useUIText();const tone={running:"bg-bg border-line text-muted",done:"bg-green-bg2 border-green-line text-green",failed:"bg-red-bg border-red-line text-red",reverted:"bg-bg border-line text-muted2"}[state];const off=state==="reverted";return jsxs("div",{className:cn("flex items-start gap-2.5 p-3 rounded-card border",tone),children:[jsx("span",{"aria-hidden":"true",className:"shrink-0 mt-0.5",children:state==="failed"?jsx(TriangleAlert,{size:15}):off?jsx(RotateCcw,{size:15}):state==="done"?jsx(Check,{size:15}):Icon?jsx(Icon,{size:15}):jsx("span",{className:"block size-3.5 rounded-full border-2 border-current border-t-transparent animate-spin"})}),jsxs("span",{className:"flex flex-col gap-1 min-w-0 flex-1",children:[jsx("span",{className:cn("text-ui font-bold",off?"text-muted":"text-ink"),children:title}),detail&&jsx("span",{className:cn("text-caption leading-[1.7]",off?"text-muted2 line-through":"text-ink2"),children:detail})]}),onUndo&&state==="done"&&jsx("button",{type:"button",onClick:onUndo,className:"shrink-0 text-caption font-bold text-brand-ink cursor-pointer hover:underline underline-offset-4",children:undoLabel??ui.undo})]})}function AiSources({sources,label}){const ui=useUIText();if(sources.length===0)return null;return jsxs("span",{className:"flex items-center gap-1.5 flex-wrap",children:[jsx("span",{className:"text-micro text-muted2",children:label??ui.from}),sources.map(s=>{const inner=jsxs(Fragment,{children:[s.label,jsx(ExternalLink,{size:10,"aria-hidden":"true"})]});const cls="inline-flex items-center gap-1 h-6 px-2 rounded-full bg-soft text-brand-ink text-micro font-bold no-underline cursor-pointer transition-colors hover:bg-soft2";return s.href?jsx("a",{href:s.href,className:cls,children:inner},s.id):jsx("button",{type:"button",onClick:s.onOpen,className:cls,children:inner},s.id)})]})}function AiMessage({role,children,streaming,sources,copyText,onRetry,onFeedback,tools,fill}){const ui=useUIText();const[copied,setCopied]=useState(false);const[vote,setVote]=useState(null);const user=role==="user";const actionable=!user&&!streaming&&(copyText||onRetry||onFeedback);return jsxs("div",{className:cn("flex gap-2.5",fill?"w-full":"max-w-[88%]",user?"self-end":"self-start"),children:[!user&&jsx(AiAvatar,{size:"sm"}),jsxs("div",{className:cn("flex flex-col gap-2 min-w-0",fill&&"flex-1"),children:[jsxs("div",{dir:"auto",className:cn("py-2.5 px-3.5 rounded-card text-ui leading-[1.85] whitespace-pre-line",user?"bg-brand text-white":"bg-bg text-ink border border-line"),children:[children,streaming&&jsx("span",{"aria-hidden":"true",className:"inline-block w-[2px] h-[1em] align-[-2px] ms-0.5 bg-brand animate-pulse"})]}),tools,sources&&sources.length>0&&!streaming&&jsx(AiSources,{sources}),actionable&&jsxs("div",{className:"flex items-center gap-0.5",children:[copyText&&jsx(ActionBtn,{label:copied?"\u0627\u062A\u0646\u0633\u062E":"\u0646\u0633\u062E",onClick:()=>{navigator.clipboard?.writeText(copyText);setCopied(true);setTimeout(()=>setCopied(false),1400)},children:copied?jsx(Check,{size:13,className:"text-green"}):jsx(Copy,{size:13})}),onRetry&&jsx(ActionBtn,{label:ui.tryAnotherReply,onClick:onRetry,children:jsx(RotateCcw,{size:13})}),onFeedback&&jsxs(Fragment,{children:[jsx(ActionBtn,{label:ui.helpfulReply,active:vote==="up",onClick:()=>{setVote("up");onFeedback("up")},children:jsx(ThumbsUp,{size:13})}),jsx(ActionBtn,{label:ui.unhelpfulReply,active:vote==="down",onClick:()=>{setVote("down");onFeedback("down")},children:jsx(ThumbsDown,{size:13})})]})]})]})]})}function ActionBtn({onClick,label,active,children}){return jsx("button",{type:"button",onClick,"aria-label":label,title:label,"aria-pressed":active,className:cn("size-7 rounded-xs inline-flex items-center justify-center cursor-pointer transition-colors",active?"bg-soft text-brand-ink":"text-muted2 hover:bg-hover hover:text-ink"),children})}function AiDisclaimer({children}){const ui=useUIText();return jsx("span",{className:"block text-center text-micro leading-[1.7] text-muted2 [text-wrap:pretty]",children:children??ui.aiDisclaimer})}import{useEffect as useEffect3,useRef as useRef3}from"react";import{ArrowUp,Mic,Paperclip,Square,Trash2}from"lucide-react";import{useCallback,useEffect as useEffect2,useRef as useRef2,useState as useState2}from"react";function useStreamingText({speed=18}={}){const[shown,setShown]=useState2("");const[streaming,setStreaming]=useState2(false);const full=useRef2("");const timer=useRef2(void 0);const stopTimer=useCallback(()=>{clearInterval(timer.current);timer.current=void 0},[]);useEffect2(()=>stopTimer,[stopTimer]);const run=useCallback(()=>{if(timer.current)return;timer.current=setInterval(()=>{setShown(s=>{if(s.length>=full.current.length){stopTimer();setStreaming(false);return s}return full.current.slice(0,s.length+1)})},speed)},[speed,stopTimer]);const start=useCallback(text=>{stopTimer();full.current=text;setShown("");setStreaming(true);run()},[run,stopTimer]);const push=useCallback(chunk=>{full.current+=chunk;setStreaming(true);run()},[run]);const stop=useCallback(()=>{stopTimer();full.current=shown;setStreaming(false)},[shown,stopTimer]);const finish=useCallback(()=>{stopTimer();setShown(full.current);setStreaming(false)},[stopTimer]);const reset=useCallback(()=>{stopTimer();full.current="";setShown("");setStreaming(false)},[stopTimer]);return{text:shown,streaming,start,push,stop,finish,reset}}function useMicLevel(){const level=useRef2(0);const[recording,setRecording]=useState2(false);const[seconds,setSeconds]=useState2(0);const[denied,setDenied]=useState2(false);const stream=useRef2(null);const ctx=useRef2(null);const raf=useRef2(0);const tick=useRef2(void 0);const stop=useCallback(()=>{cancelAnimationFrame(raf.current);clearInterval(tick.current);stream.current?.getTracks().forEach(t=>t.stop());void ctx.current?.close();stream.current=null;ctx.current=null;level.current=0;setRecording(false);setSeconds(0)},[]);useEffect2(()=>stop,[stop]);const start=useCallback(async()=>{if(recording)return;try{const media=await navigator.mediaDevices.getUserMedia({audio:true});const Ctx=window.AudioContext??window.webkitAudioContext;if(!Ctx)throw new Error("\u0645\u0627\u0641\u064A\u0634 Web Audio");const c=new Ctx;const src=c.createMediaStreamSource(media);const analyser=c.createAnalyser();analyser.fftSize=512;analyser.smoothingTimeConstant=.7;src.connect(analyser);stream.current=media;ctx.current=c;setDenied(false);setRecording(true);setSeconds(0);const data=new Uint8Array(analyser.frequencyBinCount);const loop=()=>{analyser.getByteTimeDomainData(data);let sum=0;for(let i=0;i<data.length;i++){const v=(data[i]-128)/128;sum+=v*v}level.current=Math.min(1,Math.sqrt(sum/data.length)*3);raf.current=requestAnimationFrame(loop)};raf.current=requestAnimationFrame(loop);tick.current=setInterval(()=>setSeconds(s=>s+1),1e3)}catch{setDenied(true);setRecording(false)}},[recording]);return{level,recording,seconds,start,stop,denied}}import{jsx as jsx2,jsxs as jsxs2}from"react/jsx-runtime";function AiPromptChips({prompts,onPick}){if(prompts.length===0)return null;return jsx2("div",{className:"flex gap-2 overflow-x-auto pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",children:prompts.map(p=>jsx2("button",{type:"button",dir:"auto",onClick:()=>onPick(p),className:"shrink-0 h-8 px-3 rounded-full border border-border bg-surface text-caption font-bold text-ink2 whitespace-nowrap cursor-pointer transition-colors hover:border-brand hover:text-brand-ink",children:p},p))})}function LiveBars({level,count=28}){const bars=useRef3([]);const history=useRef3(Array.from({length:count},()=>0));useEffect3(()=>{let raf=0;let last=0;const loop=t=>{if(t-last>60){last=t;history.current=[...history.current.slice(1),level.current??0];for(let i=0;i<bars.current.length;i++){const el=bars.current[i];if(el)el.style.height=`${Math.max(10,(history.current[i]??0)*100)}%`}}raf=requestAnimationFrame(loop)};raf=requestAnimationFrame(loop);return()=>cancelAnimationFrame(raf)},[level]);return jsx2("span",{dir:"ltr","aria-hidden":"true",className:"flex-1 min-w-0 h-7 flex items-center gap-0.5",children:Array.from({length:count},(_,i)=>jsx2("span",{ref:el=>{bars.current[i]=el},className:"flex-1 rounded-full bg-brand",style:{height:"10%",transition:"height 70ms linear"}},i))})}function AiComposer({value,onChange,onSend,placeholder,busy,onStop,onVoice,onAttach,disabled,className}){const ui=useUIText();const mic=useMicLevel();const area=useRef3(null);useEffect3(()=>{const el=area.current;if(!el)return;el.style.height="auto";el.style.height=`${Math.min(el.scrollHeight,120)}px`},[value]);function submit(){const text=value.trim();if(!text||busy)return;onSend(text)}if(mic.recording){return jsxs2("div",{className:cn("flex items-center gap-3 h-14 px-3 rounded-lg bg-surface border border-brand",className),children:[jsx2("button",{type:"button",onClick:mic.stop,"aria-label":ui.cancelRecording,className:"size-9 rounded-sm shrink-0 flex items-center justify-center text-muted cursor-pointer transition-colors hover:bg-red-bg hover:text-red",children:jsx2(Trash2,{size:17,"aria-hidden":"true"})}),jsx2(LiveBars,{level:mic.level}),jsx2("span",{"data-num":true,className:"text-ui font-bold text-ink2 shrink-0 tabular-nums",children:formatTime(mic.seconds)}),jsx2("button",{type:"button",onClick:()=>{const s=mic.seconds;mic.stop();onVoice?.(s)},"aria-label":ui.sendRecording,className:"size-9 rounded-sm shrink-0 flex items-center justify-center bg-brand text-white cursor-pointer transition-colors hover:bg-brand-hover",children:jsx2(ArrowUp,{size:17,strokeWidth:2.4,"aria-hidden":"true"})})]})}const canSend=value.trim().length>0;return jsxs2("div",{className:cn("flex flex-col gap-1.5",className),children:[jsxs2("div",{className:cn("flex items-end gap-2 p-2 ps-3.5 rounded-lg bg-surface border border-border","focus-within:border-brand transition-colors",disabled&&"opacity-60 pointer-events-none"),children:[jsx2("label",{htmlFor:"ai-composer",className:"sr-only",children:placeholder??ui.askShehab}),jsx2("textarea",{id:"ai-composer",ref:area,rows:1,value,disabled,placeholder:placeholder??ui.askShehab,onChange:e=>onChange(e.target.value),onKeyDown:e=>{if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();submit()}},className:"flex-1 min-w-0 py-2 bg-transparent border-none outline-none resize-none text-body text-ink placeholder:text-muted2"}),jsxs2("span",{className:"flex items-center gap-0.5 shrink-0",children:[onAttach&&jsx2("button",{type:"button",onClick:onAttach,"aria-label":ui.attachFile,className:"size-9 rounded-sm flex items-center justify-center text-muted cursor-pointer transition-colors hover:bg-hover hover:text-ink",children:jsx2(Paperclip,{size:17,"aria-hidden":"true"})}),onVoice&&!canSend&&!busy&&jsx2("button",{type:"button",onClick:()=>void mic.start(),"aria-label":ui.recordVoice,className:"size-9 rounded-sm flex items-center justify-center text-muted cursor-pointer transition-colors hover:bg-hover hover:text-ink",children:jsx2(Mic,{size:17,"aria-hidden":"true"})}),jsx2("button",{type:"button",onClick:busy?onStop:submit,disabled:!busy&&!canSend,"aria-label":busy?"\u0623\u0648\u0642\u0641 \u0627\u0644\u062A\u0648\u0644\u064A\u062F":"\u0625\u0631\u0633\u0627\u0644",className:cn("size-9 rounded-sm flex items-center justify-center shrink-0 transition-colors",busy?"bg-ink2 text-surface cursor-pointer hover:bg-ink":canSend?"bg-brand text-white cursor-pointer hover:bg-brand-hover":"bg-soft text-brand-ink/40 cursor-not-allowed"),children:busy?jsx2(Square,{size:13,fill:"currentColor","aria-hidden":"true"}):jsx2(ArrowUp,{size:17,strokeWidth:2.4,"aria-hidden":"true"})})]})]}),mic.denied&&jsx2("span",{className:"text-caption text-red",children:"\u0627\u0644\u0645\u064A\u0643\u0631\u0648\u0641\u0648\u0646 \u0645\u0631\u0641\u0648\u0636 \u2014 \u0627\u0633\u0645\u062D \u0644\u0644\u0645\u0648\u0642\u0639 \u0628\u0627\u0644\u0648\u0635\u0648\u0644 \u0644\u0644\u0645\u064A\u0643\u0631\u0648\u0641\u0648\u0646 \u0645\u0646 \u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0627\u0644\u0645\u062A\u0635\u0641\u0651\u062D."})]})}import{useState as useState5}from"react";import{useState as useState3}from"react";import{ArrowRight,Check as Check2,MessageSquarePlus}from"lucide-react";import{OTHER_PREFIX}from"@qumra/jawab-ai";import{jsx as jsx3,jsxs as jsxs3}from"react/jsx-runtime";function AskCard({block,onAnswer,live=true}){const[at,setAt]=useState3(0);const[picked,setPicked]=useState3({});const[other,setOther]=useState3({});const[notes,setNotes]=useState3({});const[noting,setNoting]=useState3({});const[sent,setSent]=useState3(null);const answerable=live&&Boolean(onAnswer)&&!sent;const total=block.questions.length;const q=block.questions[at];const last=at===total-1;function toggle(question,value){setPicked(prev=>{const cur=prev[question.key]??[];if(!question.multi)return{...prev,[question.key]:[value]};return{...prev,[question.key]:cur.includes(value)?cur.filter(v=>v!==value):[...cur,value]}})}function valuesFor(question){const base=picked[question.key]??[];const typed=other[question.key]?.trim();return typed?[...base,OTHER_PREFIX+typed]:base}function labelsFor(question){return valuesFor(question).map(v=>v.startsWith(OTHER_PREFIX)?v.slice(OTHER_PREFIX.length):question.options.find(o=>o.value===v)?.label??v)}const answered=valuesFor(q).length>0;const canGo=q.required===false||answered;function submit(){const result={answers:{},values:{}};const notesOut={};for(const question of block.questions){const values=valuesFor(question);if(values.length===0)continue;result.values[question.key]=values;result.answers[question.label]=labelsFor(question).join("\u060C ");const note=notes[question.key]?.trim();if(note)notesOut[question.label]={notes:note}}if(Object.keys(notesOut).length)result.annotations=notesOut;setSent(result);onAnswer?.(block.id,result)}if(sent){return jsxs3("div",{className:"flex flex-col gap-3 p-4 rounded-card border border-line bg-bg",children:[block.questions.map(question=>jsxs3("div",{className:"flex flex-col gap-1.5",children:[jsx3("span",{className:"text-caption text-muted [text-wrap:pretty]",children:question.label}),jsx3(Picked,{labels:(sent.answers[question.label]??"").split("\u060C ").filter(Boolean),note:sent.annotations?.[question.label]?.notes})]},question.key)),jsxs3("span",{className:"flex items-center gap-1.5 text-caption font-bold text-green",children:[jsx3(Check2,{size:13,strokeWidth:2.6,"aria-hidden":"true"}),"\u0627\u062A\u0628\u0639\u062A"]})]})}return jsxs3("div",{className:"flex flex-col gap-3.5 p-4 rounded-card border border-soft2 bg-tint",children:[jsxs3("span",{className:"flex items-center justify-between gap-3",children:[q.header?jsx3("span",{className:"px-2 h-5 rounded-mark bg-soft text-brand-ink text-micro font-extrabold flex items-center",children:q.header}):jsx3("span",{}),total>1&&jsxs3("span",{className:"flex items-center gap-2 shrink-0",children:[jsx3("span",{"aria-hidden":"true",className:"flex items-center gap-1",children:block.questions.map((qq,i)=>jsx3("span",{className:cn("size-1.5 rounded-full transition-colors",i===at?"bg-brand":i<at?"bg-brand/40":"bg-border/40")},qq.key))}),jsxs3("span",{"data-num":true,className:"text-micro font-bold text-muted whitespace-nowrap",children:[at+1," \u0645\u0646 ",total]})]})]}),jsxs3("div",{className:"flex flex-col gap-2",children:[jsx3("span",{className:"text-ui font-extrabold text-ink [text-wrap:pretty]",children:q.label}),q.hint&&jsx3("span",{className:"text-caption leading-[1.7] text-muted",children:q.hint}),jsx3(ChoiceCards,{name:`${block.id}-${q.key}`,multiple:q.multi,disabled:!answerable,value:q.multi?picked[q.key]??[]:picked[q.key]?.[0]??null,onChange:v=>toggle(q,v),options:q.options.map(o=>({value:o.value,label:o.label,meta:o.description}))}),q.other!==false&&jsx3(Input,{size:"sm",value:other[q.key]??"",onChange:e=>setOther(p=>({...p,[q.key]:e.target.value})),disabled:!answerable,placeholder:q.other?.placeholder??"\u0623\u0648 \u0627\u0643\u062A\u0628 \u0625\u062C\u0627\u0628\u062A\u0643\u2026","aria-label":`\u0625\u062C\u0627\u0628\u0629 \u0623\u062E\u0631\u0649 \u0639\u0644\u0649: ${q.label}`}),noting[q.key]?jsx3(Textarea,{rows:2,value:notes[q.key]??"",onChange:e=>setNotes(p=>({...p,[q.key]:e.target.value})),disabled:!answerable,placeholder:"\u062D\u0627\u062C\u0629 \u062A\u062D\u0628\u0651 \u062A\u0642\u0648\u0644\u0647\u0627 \u0645\u0639 \u0627\u062E\u062A\u064A\u0627\u0631\u0643\u2026","aria-label":`\u0645\u0644\u0627\u062D\u0638\u0629 \u0639\u0644\u0649: ${q.label}`}):answerable&&jsxs3("button",{type:"button",onClick:()=>setNoting(p=>({...p,[q.key]:true})),className:"self-start inline-flex items-center gap-1.5 text-micro font-bold text-muted hover:text-brand cursor-pointer transition-colors",children:[jsx3(MessageSquarePlus,{size:13,"aria-hidden":"true"}),"\u0636\u064A\u0641 \u0645\u0644\u0627\u062D\u0638\u0629"]})]}),answerable&&jsxs3("span",{className:"flex items-center gap-2.5",children:[at>0&&jsx3(Button,{size:"sm",variant:"ghost",onClick:()=>setAt(i=>i-1),children:"\u0631\u062C\u0648\u0639"}),last?jsx3(Button,{size:"sm",onClick:submit,disabled:!canGo,children:block.submitLabel??"\u0627\u0628\u0639\u062A"}):jsx3(Button,{size:"sm",onClick:()=>setAt(i=>i+1),disabled:!canGo,iconEnd:jsx3(ArrowRight,{size:13,className:"rtl:rotate-180","aria-hidden":"true"}),children:"\u0627\u0644\u062A\u0627\u0644\u064A"}),!canGo&&jsx3("span",{className:"text-micro text-muted2",children:"\u0627\u062E\u062A\u0627\u0631 \u0625\u062C\u0627\u0628\u0629 \u0627\u0644\u0623\u0648\u0644"})]})]})}function Picked({labels,note}){if(labels.length===0)return jsx3("span",{className:"text-caption text-muted2",children:"\u0627\u062A\u062E\u0637\u0651\u0649"});return jsxs3("span",{className:"flex flex-col gap-1.5",children:[jsx3("span",{className:"flex flex-wrap gap-1.5",children:labels.map((l,i)=>jsxs3("span",{className:"inline-flex items-center gap-1 h-6 px-2 rounded-mark bg-soft text-brand-ink text-caption font-bold",children:[jsx3(Check2,{size:11,strokeWidth:3,"aria-hidden":"true"}),l]},i))}),note&&jsx3("span",{className:"text-micro leading-[1.7] text-muted border-s-2 border-line ps-2",children:note})]})}import{useEffect as useEffect4,useState as useState4}from"react";import{Check as Check3,Copy as Copy2,RotateCcw as RotateCcw2,Sparkles,X}from"lucide-react";import{Fragment as Fragment2,jsx as jsx4,jsxs as jsxs4}from"react/jsx-runtime";function DraftPanel({draft:source,basis,label,onInsert,onClose,insertLabel="\u0623\u062F\u0631\u0650\u062C",className}){const[attempt,setAttempt]=useState4(0);const[done,setDone]=useState4(false);const{text,streaming,start,finish}=useStreamingText({speed:12});const dynamic=typeof source==="function";useEffect4(()=>{start(dynamic?source(attempt):source)},[attempt,source]);return jsxs4("div",{className:cn("flex flex-col gap-2.5 p-3.5 rounded-card bg-bg border border-line","basis-full order-last w-full",className),children:[jsxs4("span",{className:"flex items-start justify-between gap-3",children:[jsxs4("span",{className:"flex flex-col gap-0.5 min-w-0",children:[jsxs4("span",{className:"flex items-center gap-1.5 text-caption font-extrabold text-ink",children:[jsx4(Sparkles,{size:13,className:"text-brand shrink-0","aria-hidden":"true"}),label]}),jsx4("span",{className:"text-micro leading-[1.65] text-muted",children:basis})]}),onClose&&jsx4("button",{type:"button",onClick:onClose,"aria-label":"\u0625\u063A\u0644\u0627\u0642",className:"shrink-0 size-6 rounded-mark flex items-center justify-center text-muted2 hover:bg-hover hover:text-ink cursor-pointer transition-colors",children:jsx4(X,{size:14,"aria-hidden":"true"})})]}),text===""&&streaming?jsx4(AiThinking,{label:"\u0628\u064A\u0643\u062A\u0628\u2026"}):jsxs4("span",{className:"block text-caption leading-[1.9] text-ink whitespace-pre-wrap [text-wrap:pretty]","aria-live":"polite",children:[text,streaming&&jsx4("span",{"aria-hidden":"true",className:"inline-block w-[2px] h-[1em] align-[-0.15em] ms-0.5 bg-brand animate-pulse"})]}),jsx4("span",{className:"flex items-center gap-2 flex-wrap",children:streaming?jsx4(Button,{size:"sm",variant:"outline",onClick:finish,children:"\u0627\u0639\u0631\u0636\u0647\u0627 \u0643\u0644\u0647\u0627"}):jsxs4(Fragment2,{children:[onInsert&&jsx4(Button,{size:"sm",onClick:()=>{onInsert(text);setDone(true);onClose?.()},icon:jsx4(Check3,{size:13,"aria-hidden":"true"}),children:insertLabel}),jsx4(Button,{size:"sm",variant:"outline",onClick:()=>navigator.clipboard?.writeText(text),icon:jsx4(Copy2,{size:13,"aria-hidden":"true"}),children:"\u0627\u0646\u0633\u062E"}),dynamic&&jsx4(Button,{size:"sm",variant:"ghost",onClick:()=>setAttempt(a=>a+1),icon:jsx4(RotateCcw2,{size:13,"aria-hidden":"true"}),children:"\u0627\u0643\u062A\u0628 \u063A\u064A\u0631\u0647\u0627"})]})}),!streaming&&!done&&jsx4(AiDisclaimer,{children:"\u0645\u0645\u0643\u0646 \u064A\u063A\u0644\u0637 \u2014 \u0627\u0642\u0631\u0627\u0647\u0627 \u0642\u0628\u0644 \u0645\u0627 \u062A\u0646\u0634\u0631\u0647\u0627."})]})}function AiDraft({size="sm",...panel}){const[open,setOpen]=useState4(false);if(!open){return jsx4(Button,{variant:"outline",size,onClick:()=>setOpen(true),icon:jsx4(Sparkles,{size:size==="sm"?13:15,"aria-hidden":"true"}),className:panel.className,children:panel.label})}return jsx4(DraftPanel,{...panel,onClose:()=>setOpen(false)})}import{Fragment as Fragment3,jsx as jsx5}from"react/jsx-runtime";function Markdown({md}){const chunks=md.split(/\n{2,}/);return jsx5(Fragment3,{children:chunks.map((chunk,i)=>{const lines=chunk.split("\n");const bullets=lines.every(l=>/^\s*[-•]\s+/.test(l));const numbers=lines.every(l=>/^\s*\d+[.)]\s+/.test(l));if(bullets||numbers){const items=lines.map(l=>l.replace(/^\s*(?:[-•]|\d+[.)])\s+/,""));const List=numbers?"ol":"ul";return jsx5(List,{className:numbers?"my-2 ps-5 list-decimal marker:text-muted2 flex flex-col gap-1":"my-2 ps-5 list-disc marker:text-muted2 flex flex-col gap-1",children:items.map((it,j)=>jsx5("li",{children:inline(it)},j))},i)}return jsx5("p",{className:"my-2 first:mt-0 last:mb-0 [text-wrap:pretty]",children:inline(chunk)},i)})})}var TOKEN=/(`[^`\n]+`)|(\*\*[^*\n]+\*\*)|(\*[^*\n]+\*)/g;function inline(src){const out=[];let last=0;let m;TOKEN.lastIndex=0;while((m=TOKEN.exec(src))!==null){if(m.index>last)out.push(src.slice(last,m.index));const[full]=m;const key=`${m.index}`;if(full.startsWith("`")){out.push(jsx5("code",{dir:"ltr",className:"px-1 py-px rounded-mark bg-hover text-[0.9em] font-mono text-brand-ink",children:full.slice(1,-1)},key))}else if(full.startsWith("**")){out.push(jsx5("strong",{className:"font-extrabold text-ink",children:full.slice(2,-2)},key))}else{out.push(jsx5("em",{className:"not-italic font-bold",children:full.slice(1,-1)},key))}last=m.index+full.length}if(last<src.length)out.push(src.slice(last));return out}import{Fragment as Fragment4,jsx as jsx6,jsxs as jsxs5}from"react/jsx-runtime";var TONE={good:"green",warn:"amber",bad:"red",plain:"neutral"};var NOTICE_TONE={info:"brand",warn:"amber",danger:"red"};function major(a){return a.minor/10**(a.decimals??2)}function TextBlockView({block}){if(!block.md)return null;return jsx6("div",{className:"text-body leading-[1.95] text-ink2",children:jsx6(Markdown,{md:block.md})})}function MetricBlockView({block}){return jsx6("div",{className:"grid gap-2.5 grid-cols-[repeat(auto-fit,minmax(9.5rem,1fr))]",children:block.items.map((m,i)=>jsx6(StatCard,{tone:TONE[m.tone??"plain"]??"neutral",label:m.label,value:m.amount?jsx6(Money,{value:major(m.amount),currency:isCurrency(m.amount.currency)?m.amount.currency:void 0,compact:true,trimZeros:true}):m.value,hint:m.delta!==void 0?deltaHint(m.delta,m.deltaBasis):void 0},i))})}function deltaHint(delta,basis){const up=delta>0;const flat=delta===0;return jsxs5("span",{className:cn("font-bold",flat?"text-muted2":up?"text-green":"text-red"),children:[flat?"=":up?"\u25B2":"\u25BC"," ",Math.abs(delta),"\u066A",basis?` ${basis}`:""]})}function TableBlockView({block}){const rows=block.rows.map((cells,i)=>{const row={__key:String(i)};block.cols.forEach((c,j)=>{row[c.key]=cells[j]??null});return row});const columns=block.cols.map(c=>({key:c.key,header:c.label,end:c.align==="end",cell:row=>renderCell(row[c.key],c)}));return jsxs5("span",{className:"flex flex-col gap-1.5",children:[block.caption&&jsx6("span",{className:"text-micro text-muted2",children:block.caption}),jsx6(DataTable,{columns,rows,rowKey:r=>r.__key,grid:block.cols.map(c=>c.align==="end"?"1fr":"1.6fr").join("_"),minWidth:block.cols.length*120,mobileCard:row=>jsx6("span",{className:"flex flex-col gap-1",children:block.cols.map(c=>jsxs5("span",{className:"flex items-baseline justify-between gap-3",children:[jsx6("span",{className:"text-micro text-muted2",children:c.label}),jsx6("span",{className:"text-caption text-ink",children:renderCell(row[c.key],c)})]},c.key))})})]})}function renderCell(v,col){if(v===null||v==="")return jsx6("span",{className:"text-muted2",children:"\u2014"});switch(col.format){case"money":return typeof v==="number"?jsx6(Money,{value:v,trimZeros:true}):v;case"badge":return jsx6(Badge,{size:"sm",children:v});case"number":return jsx6("span",{"data-num":true,children:v});default:return v}}function CardsBlockView({block,intents}){return jsx6("div",{className:"grid gap-2.5 grid-cols-[repeat(auto-fill,minmax(13rem,1fr))]",children:block.items.map(c=>jsx6(Card,{children:jsxs5("span",{className:"flex gap-3 items-start",children:[c.img&&jsx6("img",{src:c.img,alt:"",className:"size-12 rounded-sm object-cover bg-hover shrink-0"}),jsxs5("span",{className:"flex flex-col gap-1 min-w-0",children:[jsx6("span",{className:"text-ui font-bold text-ink truncate",children:c.title}),c.subtitle&&jsx6("span",{className:"text-micro text-muted",children:c.subtitle}),c.badge&&jsx6("span",{children:jsx6(Badge,{size:"sm",tone:"brand",children:c.badge})}),c.action&&jsx6(ActionButton,{action:c.action,intents,size:"sm"})]})]})},c.id))})}function ChartBlockView({block}){const labels=block.series.map(p=>String(p.x));const values=block.series.map(p=>p.y);const money=block.unit?.kind==="money";const fmt=v=>block.unit?.kind==="percent"?`${v}\u066A`:v.toLocaleString("ar-EG");if(block.kind==="bar"){return jsx6(BarChart,{labels,series:[{label:"",values}],formatValue:fmt})}return jsx6(TrendChart,{labels:axisLabels(labels),values,pointLabels:labels,formatValue:money?v=>v.toLocaleString("ar-EG"):fmt,height:170})}function axisLabels(all){if(all.length<=3)return all;return[all[0],all[Math.floor(all.length/2)],all[all.length-1]]}function ActionBlockView({block,intents}){const runnable=block.items.filter(a=>intents[a.intent]);if(runnable.length===0)return null;return jsx6("span",{className:"flex flex-wrap gap-2",children:runnable.map((a,i)=>jsx6(ActionButton,{action:a,intents},i))})}function ActionButton({action,intents,size="sm"}){const[asking,setAsking]=useState5(false);const run=intents[action.intent];if(!run)return null;function fire(){setAsking(false);run(action.args)}return jsxs5(Fragment4,{children:[jsx6(Button,{size,variant:action.style==="quiet"?"outline":"primary",onClick:()=>action.confirm?setAsking(true):fire(),children:action.label}),jsx6(Modal,{open:asking,title:action.label,description:action.confirm,onClose:()=>setAsking(false),size:"sm",footer:jsxs5(Fragment4,{children:[jsx6(Button,{variant:"outline",onClick:()=>setAsking(false),children:"\u0625\u0644\u063A\u0627\u0621"}),jsx6(Button,{onClick:fire,children:action.label})]})})]})}function ToolBlockView({block,intents}){const undo=block.undo;const run=undo?intents[undo.intent]:void 0;return jsx6(AiToolCall,{title:block.title,detail:block.detail,state:block.state,onUndo:run&&undo?()=>run(undo.args):void 0,undoLabel:undo?.label})}function NoticeBlockView({block}){return jsx6(Alert,{tone:NOTICE_TONE[block.tone],children:block.text})}function ChipsBlockView({block,onSend}){if(!onSend)return null;const byLabel=new Map(block.items.map(c=>[c.label,c.send]));return jsx6(AiPromptChips,{prompts:block.items.map(c=>c.label),onPick:label=>onSend(byLabel.get(label)??label)})}function BlockView({block,intents,onSend,onInsertDraft,onAnswer,live=true}){switch(block.type){case"text":return jsx6(TextBlockView,{block});case"metric":return jsx6(MetricBlockView,{block});case"table":return jsx6(TableBlockView,{block});case"cards":return jsx6(CardsBlockView,{block,intents});case"chart":return jsx6(ChartBlockView,{block});case"action":return jsx6(ActionBlockView,{block,intents});case"tool":return jsx6(ToolBlockView,{block,intents});case"notice":return jsx6(NoticeBlockView,{block});case"chips":return jsx6(ChipsBlockView,{block,onSend});case"ask":return jsx6(AskCard,{block,onAnswer,live});case"draft":return jsx6(DraftPanel,{draft:block.text,basis:block.basis,label:"\u0645\u0633\u0648\u0651\u062F\u0629",onInsert:onInsertDraft});default:return null}}import{jsx as jsx7,jsxs as jsxs6}from"react/jsx-runtime";var NO_INTENTS={};function ReplyView({reply,streaming,intents=NO_INTENTS,onSend,onInsertDraft,onAnswer,live=true,onRetry,onFeedback,className}){return jsx7(AiMessage,{role:"assistant",fill:true,streaming,sources:reply.sources,copyText:plainText(reply),onRetry,onFeedback,children:jsxs6("span",{className:cn("flex flex-col gap-3",className),children:[reply.blocks.map((block,i)=>jsx7(BlockView,{block,intents,onSend,onInsertDraft,onAnswer,live},i)),reply.disclaimer!==false&&!streaming&&jsx7(AiDisclaimer,{})]})})}function plainText(reply){const parts=[];for(const b of reply.blocks){switch(b.type){case"text":parts.push(b.md);break;case"metric":parts.push(b.items.map(m=>`${m.label}: ${m.value}`).join(" \xB7 "));break;case"table":parts.push([b.cols.map(c=>c.label).join(" "),...b.rows.map(r=>r.map(c=>c??"").join(" "))].join("\n"));break;case"cards":parts.push(b.items.map(c=>c.title).join("\n"));break;case"draft":parts.push(b.text);break;case"tool":parts.push(b.detail?`${b.title} \u2014 ${b.detail}`:b.title);break;case"notice":parts.push(b.text);break;case"ask":parts.push(b.questions.map(q=>q.label).join("\n"));break;case"chart":case"action":case"chips":break}}return parts.filter(Boolean).join("\n\n")}import{useCallback as useCallback2,useEffect as useEffect5,useRef as useRef4,useState as useState6}from"react";import{parseEvent,parseSSE,reduce}from"@qumra/jawab-ai";function useReplyStream(url,init){const[reply,setReply]=useState6(null);const[streaming,setStreaming]=useState6(false);const[error,setError]=useState6(null);const abort=useRef4(null);const lastInput=useRef4("");useEffect5(()=>()=>abort.current?.abort(),[]);const stop=useCallback2(()=>{abort.current?.abort();abort.current=null;setStreaming(false)},[]);const send=useCallback2(text=>{const question=text.trim();if(!question)return;abort.current?.abort();const ctrl=new AbortController;abort.current=ctrl;lastInput.current=question;setError(null);setReply(null);setStreaming(true);void(async()=>{try{const res=await fetch(url,{method:"POST",headers:{"content-type":"application/json",accept:"text/event-stream"},body:JSON.stringify({input:question}),signal:ctrl.signal,...init});if(!res.ok||!res.body){throw new StreamError("http_"+res.status,`\u0627\u0644\u062E\u0627\u062F\u0645 \u0631\u062C\u0651\u0639 ${res.status}`)}const decoder=new TextDecoder;const readerStream=res.body.getReader();let rest="";let state=null;for(;;){const{done,value}=await readerStream.read();if(done)break;rest+=decoder.decode(value,{stream:true});const{events,rest:tail}=parseSSE(rest);rest=tail;for(const raw of events){const ev=parseEvent(raw);if(!ev)continue;if(ev.e==="error")throw new StreamError(ev.code,ev.message);state=reduce(state,ev);setReply(state);if(ev.e==="done")break}}setStreaming(false)}catch(e){if(ctrl.signal.aborted)return;const se=e;setError({code:se.code??"unknown",message:se.message??"\u0627\u0644\u0627\u062A\u0635\u0627\u0644 \u0627\u062A\u0642\u0637\u0639.",lastInput:lastInput.current});setStreaming(false)}})()},[url,init]);return{reply,streaming,error,send,stop}}var StreamError=class extends Error{code;constructor(code,message){super(message);this.name="StreamError";this.code=code}};export{AiAvatar,AiComposer,AiDisclaimer,AiDraft,AiMessage,AiPromptChips,AiSources,AiThinking,AiToolCall,AskCard,DraftPanel,ReplyView,useMicLevel,useReplyStream,useStreamingText};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var TEXT_SCALE=["micro","caption","ui","body","lead","base","h4","h3","h2","h1","display","hero","title","mega"];var RADIUS_SCALE=["mark","xs","sm","field","card","lg","section","full"];var SHADOW_SCALE=["raise","tip","panel","pop","modal","toast","sheet"];var CONTAINER_SCALE=["page","shell","note","lead"];var ANIMATE_SCALE=["qfade","qslide","tip","tip-up","drawer","drawer-rtl","savebar","skeleton"];var COLOR_SCALE=["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"];var TOKENS={"--font-sans":'"Alexandria", system-ui, sans-serif',"--color-surface":"#ffffff","--color-bg":"#f7f9f9","--color-line":"#edf1f1","--color-hover":"#f2f6f6","--color-ink":"#020809","--color-ink2":"#3d4545","--color-muted":"#5f6a6a","--color-muted2":"#687373","--color-border":"#7f8c8c","--color-soft":"#eaf2f3","--color-soft2":"#dceded","--color-brand-100":"#a5c9cc","--color-brand-900":"#0a2528","--color-brand-ink":"#0f4a4e","--color-brand":"#207982","--color-brand-hover":"#1a646c","--color-brand-deep":"#0b3b3e","--color-skeleton":"#d6dcdc","--color-tint":"#f4faf8","--color-tint2":"#eff6f3","--color-mint":"#7dd3c0","--color-amber-900":"#3d2a05","--color-amber":"#f8ac33","--color-amber-bg":"#fef6e9","--color-amber-ink":"#85570f","--color-amber-line":"#fbd79a","--color-amber-hover":"#de9219","--color-green":"#1e7a45","--color-green-bg":"#f1faf4","--color-green-bg2":"#e9f6ee","--color-green-line":"#bfe6ce","--color-green-solid":"#1e7a45","--color-violet":"#4b3e8e","--color-violet-bg":"#edeaf6","--color-violet-line":"#ded8ef","--color-violet-solid":"#6d5eb8","--color-red-100":"#f3a79e","--color-red":"#8e2b20","--color-red-bg":"#fdecea","--color-red-line":"#f3c9c4","--color-danger":"#c94134","--color-danger-hover":"#a3362b","--color-night":"#0b0f12","--color-hero-body":"#bfd9d8","--color-hero-meta":"#8fb3b2","--color-hero-dim":"#5e7a79","--color-hero-text":"#d7e3e2","--color-code-bg":"#1f1f1f","--color-code-plain":"#d4d4d4","--color-code-key":"#569cd6","--color-code-tag":"#4ec9b0","--color-code-attr":"#9cdcfe","--color-code-str":"#ce9178","--color-code-num":"#b5cea8","--color-code-note":"#6a9955","--color-code-dim":"#858585","--color-code-line":"#303031","--color-code-chip":"#f4f7f7","--text-micro":"11px","--text-caption":"12px","--text-ui":"13px","--text-body":"14px","--text-lead":"15px","--text-base":"16px","--text-base--line-height":"initial","--text-h4":"17px","--text-h3":"20px","--text-h2":"24px","--text-h1":"30px","--text-display":"36px","--text-hero":"44px","--text-title":"40px","--text-mega":"54px","--container-page":"1600px","--container-shell":"1600px","--container-note":"340px","--container-lead":"520px","--radius-mark":"3px","--radius-xs":"5px","--radius-sm":"7px","--radius-field":"9px","--radius-card":"12px","--radius-lg":"14px","--radius-section":"18px","--radius-full":"999px","--shadow-raise":"0 1px 3px var(--shadow-color)","--shadow-tip":"0 6px 18px var(--shadow-color)","--shadow-panel":"0 10px 30px var(--shadow-color)","--shadow-pop":"0 18px 44px var(--shadow-color)","--shadow-modal":"0 24px 60px rgb(2 8 9 / 0.28)","--shadow-toast":"0 16px 40px rgb(2 8 9 / 0.26)","--shadow-sheet":"0 -14px 40px rgb(2 8 9 / 0.28), inset 0 1px 0 rgb(255 255 255 / 0.06)","--shadow-color":"rgb(2 8 9 / 0.14)","--animate-qfade":"qfade 0.16s ease-out","--animate-qslide":"qslidein 0.22s ease-out","--animate-tip":"tip-in 0.26s cubic-bezier(0.2, 0.8, 0.2, 1)","--animate-tip-up":"tip-up 0.3s cubic-bezier(0.2, 0.9, 0.2, 1)","--animate-drawer":"drawer-ltr 0.32s cubic-bezier(0.2, 0.9, 0.2, 1)","--animate-drawer-rtl":"drawer-rtl 0.32s cubic-bezier(0.2, 0.9, 0.2, 1)","--animate-savebar":"savebar-in 0.2s cubic-bezier(0.2, 0.8, 0.2, 1)","--animate-skeleton":"skeleton-pulse 1.6s ease-in-out infinite","--num-align":"right","--num-align-far":"left","--num-pad-right":"0.875rem","--num-pad-left":"3.5rem","--num-icon-pad-right":"2.5rem","--num-icon-pad-left":"0.875rem"};var DARK_TOKENS={"--color-surface":"#101718","--color-bg":"#0a0f10","--color-line":"#1e2829","--color-hover":"#1a2425","--color-ink":"#f2f6f6","--color-ink2":"#c7d1d1","--color-muted":"#93a0a0","--color-muted2":"#7a8787","--color-border":"#5e6b6c","--color-soft":"#12363a","--color-soft2":"#17454a","--color-brand-ink":"#7dd3c0","--color-skeleton":"#2c3232","--color-amber":"#f8ac33","--color-amber-bg":"#2b2009","--color-amber-ink":"#f5c77a","--color-amber-line":"#5c4415","--color-green":"#6ecf9a","--color-green-bg":"#0d2119","--color-green-bg2":"#102a22","--color-green-line":"#245140","--color-violet":"#b9aeea","--color-violet-bg":"#1e1a33","--color-violet-line":"#38305c","--color-red":"#f3a79e","--color-red-bg":"#2c1613","--color-red-line":"#5c2a24","--color-code-chip":"#17201f","--shadow-color":"rgb(0 0 0 / 0.55)"};export{TEXT_SCALE,RADIUS_SCALE,SHADOW_SCALE,CONTAINER_SCALE,ANIMATE_SCALE,COLOR_SCALE,TOKENS,DARK_TOKENS};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{cn,useUIText}from"./chunk-DDRJTIIP.js";import{useCallback,useRef,useState}from"react";import{AlertTriangle,CheckCircle2,Info,Loader2,X,XCircle}from"lucide-react";import{jsx,jsxs}from"react/jsx-runtime";function useToasts(){const[toasts,setToasts]=useState([]);const seq=useRef(0);const timers=useRef(new Map);const dismiss=useCallback(id=>{const t=timers.current.get(id);if(t)clearTimeout(t);timers.current.delete(id);setToasts(prev=>prev.filter(x=>x.id!==id))},[]);const push=useCallback(input=>{const id=++seq.current;const duration=input.duration??(input.actionLabel?6500:3800);setToasts(prev=>[...prev.slice(-3),{...input,id}]);if(duration>0&&!input.pending){timers.current.set(id,setTimeout(()=>dismiss(id),duration))}return id},[dismiss]);const update=useCallback((id,patch)=>{setToasts(prev=>prev.map(t=>t.id===id?{...t,...patch}:t))},[]);const clear=useCallback(()=>{timers.current.forEach(clearTimeout);timers.current.clear();setToasts([])},[]);return{toasts,push,dismiss,update,clear}}var TOAST_ICON={neutral:Info,brand:Info,green:CheckCircle2,amber:AlertTriangle,red:XCircle};var TOAST_ACCENT={neutral:"text-muted2",brand:"text-brand-100",green:"text-mint",amber:"text-amber",red:"text-red-100"};function ToastHost({toasts,onDismiss,closeLabel}){const ui=useUIText();if(toasts.length===0)return null;return jsx("div",{role:"region","aria-label":ui.alerts,className:"fixed z-[60] bottom-4 inset-x-4 sm:inset-x-auto sm:start-5 sm:w-[360px] flex flex-col gap-2 pointer-events-none",children:toasts.map(t=>{const Icon=TOAST_ICON[t.tone];return jsxs("div",{role:t.tone==="red"?"alert":"status",className:"pointer-events-auto flex items-start gap-3 p-3.5 rounded-card bg-night text-white shadow-toast animate-[toast-in_.22s_cubic-bezier(.22,.61,.36,1)]",children:[jsx("span",{"aria-hidden":"true",className:cn("shrink-0 mt-0.5",TOAST_ACCENT[t.tone]),children:t.pending?jsx(Loader2,{size:17,className:"animate-spin"}):jsx(Icon,{size:17})}),jsxs("span",{className:"flex-1 min-w-0 flex flex-col gap-0.5",children:[jsx("span",{className:"text-ui font-bold leading-snug",children:t.title}),t.description&&jsx("span",{className:"text-caption leading-[1.6] text-white/65",children:t.description})]}),t.actionLabel&&jsx("button",{type:"button",onClick:()=>{t.onAction?.();onDismiss(t.id)},className:"shrink-0 text-ui font-extrabold text-mint cursor-pointer hover:underline underline-offset-4",children:t.actionLabel}),jsx("button",{type:"button",onClick:()=>onDismiss(t.id),"aria-label":closeLabel??ui.close,className:"shrink-0 text-white/40 hover:text-white cursor-pointer transition-colors",children:jsx(X,{size:15,"aria-hidden":"true"})})]},t.id)})})}function Tooltip({content,children,side="top"}){const[open,setOpen]=useState(false);return jsxs("span",{className:"relative inline-flex",onMouseEnter:()=>setOpen(true),onMouseLeave:()=>setOpen(false),onFocus:()=>setOpen(true),onBlur:()=>setOpen(false),children:[children,open&&jsx("span",{role:"tooltip",className:cn("absolute z-40 start-1/2 -translate-x-1/2 rtl:translate-x-1/2 w-max max-w-[220px] px-2.5 py-1.5 rounded-xs","bg-night text-white text-caption leading-[1.6] text-center shadow-tip","animate-[fade-in_.12s_ease-out] pointer-events-none",side==="top"?"bottom-[calc(100%+7px)]":"top-[calc(100%+7px)]"),children:content})]})}export{useToasts,ToastHost,Tooltip};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var TEXT_SCALE=["micro","caption","ui","body","lead","base","h4","h3","h2","h1","display","hero","title","mega"];var RADIUS_SCALE=["mark","xs","sm","field","card","lg","section","full"];var SHADOW_SCALE=["raise","tip","panel","pop","modal","toast","sheet"];var CONTAINER_SCALE=["page","shell","note","lead"];var ANIMATE_SCALE=["qfade","qslide","tip","tip-up","drawer","drawer-rtl","savebar","skeleton"];var COLOR_SCALE=["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"];var TOKENS={"--font-sans":'"Alexandria", system-ui, sans-serif',"--color-surface":"#ffffff","--color-bg":"#f7f9f9","--color-line":"#edf1f1","--color-hover":"#f2f6f6","--color-ink":"#020809","--color-ink2":"#3d4545","--color-muted":"#5f6a6a","--color-muted2":"#687373","--color-border":"#7f8c8c","--color-soft":"#eaf2f3","--color-soft2":"#dceded","--color-brand-100":"#a5c9cc","--color-brand-900":"#0a2528","--color-brand-ink":"#0f4a4e","--color-brand":"#207982","--color-brand-hover":"#1a646c","--color-brand-deep":"#0b3b3e","--color-skeleton":"#d6dcdc","--color-tint":"#f4faf8","--color-tint2":"#eff6f3","--color-mint":"#7dd3c0","--color-amber-900":"#3d2a05","--color-amber":"#f8ac33","--color-amber-bg":"#fef6e9","--color-amber-ink":"#85570f","--color-amber-line":"#fbd79a","--color-amber-hover":"#de9219","--color-green":"#1e7a45","--color-green-bg":"#f1faf4","--color-green-bg2":"#e9f6ee","--color-green-line":"#bfe6ce","--color-green-solid":"#1e7a45","--color-violet":"#4b3e8e","--color-violet-bg":"#edeaf6","--color-violet-line":"#ded8ef","--color-violet-solid":"#6d5eb8","--color-red-100":"#f3a79e","--color-red":"#8e2b20","--color-red-bg":"#fdecea","--color-red-line":"#f3c9c4","--color-danger":"#c94134","--color-danger-hover":"#a3362b","--color-night":"#0b0f12","--color-hero-body":"#bfd9d8","--color-hero-meta":"#8fb3b2","--color-hero-dim":"#5e7a79","--color-hero-text":"#d7e3e2","--color-code-bg":"#1f1f1f","--color-code-plain":"#d4d4d4","--color-code-key":"#569cd6","--color-code-tag":"#4ec9b0","--color-code-attr":"#9cdcfe","--color-code-str":"#ce9178","--color-code-num":"#b5cea8","--color-code-note":"#6a9955","--color-code-dim":"#858585","--color-code-line":"#303031","--color-code-chip":"#f4f7f7","--text-micro":"11px","--text-caption":"12px","--text-ui":"13px","--text-body":"14px","--text-lead":"15px","--text-base":"16px","--text-base--line-height":"initial","--text-h4":"17px","--text-h3":"20px","--text-h2":"24px","--text-h1":"30px","--text-display":"36px","--text-hero":"44px","--text-title":"40px","--text-mega":"54px","--container-page":"1600px","--container-shell":"1600px","--container-note":"340px","--container-lead":"520px","--radius-mark":"3px","--radius-xs":"5px","--radius-sm":"7px","--radius-field":"9px","--radius-card":"12px","--radius-lg":"14px","--radius-section":"18px","--radius-full":"999px","--shadow-raise":"0 1px 3px var(--shadow-color)","--shadow-tip":"0 6px 18px var(--shadow-color)","--shadow-panel":"0 10px 30px var(--shadow-color)","--shadow-pop":"0 18px 44px var(--shadow-color)","--shadow-modal":"0 24px 60px rgb(2 8 9 / 0.28)","--shadow-toast":"0 16px 40px rgb(2 8 9 / 0.26)","--shadow-sheet":"0 -14px 40px rgb(2 8 9 / 0.28), inset 0 1px 0 rgb(255 255 255 / 0.06)","--shadow-color":"rgb(2 8 9 / 0.14)","--animate-qfade":"qfade 0.16s ease-out","--animate-qslide":"qslidein 0.22s ease-out","--animate-tip":"tip-in 0.26s cubic-bezier(0.2, 0.8, 0.2, 1)","--animate-tip-up":"tip-up 0.3s cubic-bezier(0.2, 0.9, 0.2, 1)","--animate-drawer":"drawer-ltr 0.32s cubic-bezier(0.2, 0.9, 0.2, 1)","--animate-drawer-rtl":"drawer-rtl 0.32s cubic-bezier(0.2, 0.9, 0.2, 1)","--animate-savebar":"savebar-in 0.2s cubic-bezier(0.2, 0.8, 0.2, 1)","--animate-skeleton":"skeleton-pulse 1.6s ease-in-out infinite","--num-align":"right","--num-align-far":"left","--num-pad-right":"0.875rem","--num-pad-left":"3.5rem","--num-icon-pad-right":"2.5rem","--num-icon-pad-left":"0.875rem"};var DARK_TOKENS={"--color-surface":"#101718","--color-bg":"#0a0f10","--color-line":"#1e2829","--color-hover":"#1a2425","--color-ink":"#f2f6f6","--color-ink2":"#c7d1d1","--color-muted":"#93a0a0","--color-muted2":"#7a8787","--color-border":"#5e6b6c","--color-soft":"#12363a","--color-soft2":"#17454a","--color-brand-ink":"#7dd3c0","--color-skeleton":"#2c3232","--color-amber":"#f8ac33","--color-amber-bg":"#2b2009","--color-amber-ink":"#f5c77a","--color-amber-line":"#5c4415","--color-green":"#6ecf9a","--color-green-bg":"#0d2119","--color-green-bg2":"#102a22","--color-green-line":"#245140","--color-violet":"#b9aeea","--color-violet-bg":"#1e1a33","--color-violet-line":"#38305c","--color-red":"#f3a79e","--color-red-bg":"#2c1613","--color-red-line":"#5c2a24","--color-code-chip":"#17201f","--shadow-color":"rgb(0 0 0 / 0.55)"};import{extendTailwindMerge}from"tailwind-merge";var twMerge=extendTailwindMerge({extend:{classGroups:{"font-size":[{text:TEXT_SCALE}],rounded:[{rounded:RADIUS_SCALE}],shadow:[{shadow:SHADOW_SCALE}],"max-w":[{"max-w":CONTAINER_SCALE}],animate:[{animate:ANIMATE_SCALE}]}}});function cn(...parts){return twMerge(parts.filter(p=>typeof p==="string"&&p.length>0).join(" "))}var TONE_SOFT={neutral:"bg-hover text-muted",brand:"bg-soft text-brand-ink",amber:"bg-amber-bg text-amber-ink",green:"bg-green-bg2 text-green",red:"bg-red-bg text-red",violet:"bg-violet-bg text-violet"};var TONE_SOLID={neutral:"bg-ink2 text-surface",brand:"bg-brand text-white",amber:"bg-amber text-amber-900",green:"bg-green-solid text-white",red:"bg-danger text-white",violet:"bg-violet-solid text-white"};function toLatinDigits(s){return s.replace(/[٠-٩۰-۹٫٬]/g,c=>{const code=c.charCodeAt(0);if(code===1643)return".";if(code===1644)return"";const base=code>=1776?1776:1632;return String(code-base)})}var VARIANTS={primary:"bg-brand border-brand text-white hover:bg-brand-hover",soft:"bg-soft border-soft2 text-brand-ink hover:bg-soft2",outline:"bg-surface border-border text-ink2 hover:border-brand hover:text-brand-ink",ghost:"bg-transparent border-transparent text-ink2 hover:bg-hover",danger:"bg-danger border-danger text-white hover:bg-danger-hover",link:"bg-transparent border-transparent text-brand-ink hover:underline underline-offset-4 px-0!"};var SIZES={sm:"h-9 px-3.5 gap-1.5 text-ui rounded-sm",md:"h-11 px-4 gap-2 text-body rounded-field",lg:"h-12 px-5 gap-2 text-lead rounded-card",xl:"h-14 px-5.5 gap-4 text-h3 font-extrabold rounded-field"};function buttonClasses(variant="primary",size="md",extra){return cn("inline-flex items-center justify-center border font-bold whitespace-nowrap","cursor-pointer transition-colors duration-150 select-none","focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand",SIZES[size],VARIANTS[variant],extra)}import{createContext,useCallback,useContext,useSyncExternalStore}from"react";var langStore={subscribe(cb){if(typeof MutationObserver==="undefined")return()=>{};const o=new MutationObserver(cb);o.observe(document.documentElement,{attributes:true,attributeFilter:["lang"]});return()=>o.disconnect()},get:()=>typeof document==="undefined"?"ar-EG":document.documentElement.lang||"ar-EG"};var LocaleCtx=createContext(null);function useMoneyLocale(){const fromProvider=useContext(LocaleCtx);const serverSnapshot=useCallback(()=>fromProvider??"ar-EG",[fromProvider]);return useSyncExternalStore(langStore.subscribe,langStore.get,serverSnapshot)}function useMoneyLang(){return useMoneyLocale().startsWith("en")}var AR=0;var EN=1;var TEXT={close:["\u0625\u063A\u0644\u0627\u0642","Close"],select:["\u0627\u062E\u062A\u0631\u2026","Select\u2026"],search:["\u0627\u0628\u062D\u062B\u2026","Search\u2026"],searchEverything:["\u0627\u0628\u062D\u062B \u0641\u064A \u0643\u0644 \u062D\u0627\u062C\u0629\u2026","Search everything\u2026"],noResults:["\u0645\u0627\u0641\u064A\u0634 \u0646\u062A\u0627\u064A\u062C","No results"],searchOrAdd:["\u0627\u0628\u062D\u062B \u0623\u0648 \u0623\u0636\u0641\u2026","Search or add\u2026"],now:["\u0627\u0644\u0622\u0646","Now"],videoPlayer:["\u0645\u0634\u063A\u0651\u0644 \u0627\u0644\u0641\u064A\u062F\u064A\u0648","Video player"],rating:["\u0627\u0644\u062A\u0642\u064A\u064A\u0645","Rating"],activeFilters:["\u0627\u0644\u0641\u0644\u0627\u062A\u0631 \u0627\u0644\u0645\u0637\u0628\u0651\u0642\u0629:","Active filters:"],clearAll:["\u0645\u0633\u062D \u0627\u0644\u0643\u0644","Clear all"],row:["\u0635\u0641\u0651","row"],dropImages:["\u0627\u0633\u062D\u0628 \u0627\u0644\u0635\u0648\u0631 \u0647\u0646\u0627","Drop images here"],chooseFromDevice:["\u0627\u062E\u062A\u0631 \u0645\u0646 \u0627\u0644\u062C\u0647\u0627\u0632","Choose from device"],previousPeriod:["\u0627\u0644\u0641\u062A\u0631\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629","Previous period"],less:["\u0623\u0642\u0644","Less"],more:["\u0623\u0643\u062B\u0631","More"],totalSales:["\u0625\u062C\u0645\u0627\u0644\u064A \u0627\u0644\u0645\u0628\u064A\u0639\u0627\u062A","Total sales"],netToYou:["\u0635\u0627\u0641\u064A \u0644\u0643","Net to you"],verifiedAccount:["\u062D\u0633\u0627\u0628 \u0645\u0648\u062B\u0651\u0642","Verified account"],grabHint:["\u0639\u0646\u0635\u0631 \u0642\u0627\u0628\u0644 \u0644\u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u062A\u0631\u062A\u064A\u0628. \u0627\u0636\u063A\u0637 \u0645\u0633\u0627\u0641\u0629 \u0644\u0645\u0633\u0643\u0647 \u062B\u0645 \u0627\u0644\u0623\u0633\u0647\u0645 \u0644\u062A\u062D\u0631\u064A\u0643\u0647.","Reorderable item. Press space to grab it, then the arrows to move it."],notifications:["\u0627\u0644\u0625\u0634\u0639\u0627\u0631\u0627\u062A","Notifications"],dismiss:["\u0625\u062E\u0641\u0627\u0621","Dismiss"],unread:["\u063A\u064A\u0631 \u0645\u0642\u0631\u0648\u0621","Unread"],noNotifications:["\u0645\u0641\u064A\u0634 \u0625\u0634\u0639\u0627\u0631\u0627\u062A","No notifications"],noNotificationsDesc:["\u0623\u0648\u0644 \u0645\u0627 \u064A\u062D\u0635\u0644 \u062D\u0627\u062C\u0629 \u062A\u0633\u062A\u0627\u0647\u0644\u060C \u0647\u062A\u0644\u0627\u0642\u064A\u0647\u0627 \u0647\u0646\u0627.","When something worth knowing happens, it lands here."],markAllRead:["\u062A\u0639\u0644\u064A\u0645 \u0627\u0644\u0643\u0644 \u0643\u0645\u0642\u0631\u0648\u0621","Mark all as read"],viewAllNotifications:["\u0639\u0631\u0636 \u0643\u0644 \u0627\u0644\u0625\u0634\u0639\u0627\u0631\u0627\u062A","View all notifications"],newNotifications:["\u0625\u0634\u0639\u0627\u0631\u0627\u062A \u062C\u062F\u064A\u062F\u0629","New notifications"],reloadPreview:["\u0625\u0639\u0627\u062F\u0629 \u062A\u062D\u0645\u064A\u0644 \u0627\u0644\u0645\u0639\u0627\u064A\u0646\u0629","Reload preview"],previousMonth:["\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u0644\u064A \u0642\u0628\u0644\u0647","Previous month"],nextMonth:["\u0627\u0644\u0634\u0647\u0631 \u0627\u0644\u0644\u064A \u0628\u0639\u062F\u0647","Next month"],whatIsThisNumber:["\u0645\u0627 \u0645\u0639\u0646\u0649 \u0647\u0630\u0627 \u0627\u0644\u0631\u0642\u0645\u061F","What does this number mean?"],explainToMe:["\u0627\u0634\u0631\u062D \u0644\u064A","Explain this"],clearSearch:["\u0645\u0633\u062D \u0627\u0644\u0628\u062D\u062B","Clear search"],alerts:["\u0627\u0644\u062A\u0646\u0628\u064A\u0647\u0627\u062A","Alerts"],whatIsThisOption:["\u0645\u0627 \u0647\u0630\u0627 \u0627\u0644\u062E\u064A\u0627\u0631\u061F","What is this option?"],shouldBeHere:["\u0627\u0644\u0645\u0641\u0631\u0648\u0636 \u062A\u0643\u0648\u0646 \u0647\u0646\u0627","Should be here"],closeExplainer:["\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0634\u0631\u062D","Close explainer"],cancelRecording:["\u0625\u0644\u063A\u0627\u0621 \u0627\u0644\u062A\u0633\u062C\u064A\u0644","Cancel recording"],sendRecording:["\u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u062A\u0633\u062C\u064A\u0644","Send recording"],attachFile:["\u0625\u0631\u0641\u0627\u0642 \u0645\u0644\u0641","Attach file"],recordVoice:["\u062A\u0633\u062C\u064A\u0644 \u0635\u0648\u062A\u064A","Record a voice note"],playbackPosition:["\u0645\u0648\u0636\u0639 \u0627\u0644\u062A\u0634\u063A\u064A\u0644","Playback position"],volume:["\u0645\u0633\u062A\u0648\u0649 \u0627\u0644\u0635\u0648\u062A","Volume"],hideSuggestions:["\u0625\u062E\u0641\u0627\u0621 \u0627\u0644\u0627\u0642\u062A\u0631\u0627\u062D\u0627\u062A","Hide suggestions"],askShehab:["\u0627\u0633\u0623\u0644 \u0634\u0647\u0627\u0628\u2026","Ask Shehab\u2026"],shehabThinking:["\u0634\u0647\u0627\u0628 \u0628\u064A\u0641\u0643\u0651\u0631\u2026","Shehab is thinking\u2026"],undo:["\u062A\u0631\u0627\u062C\u0639","Undo"],from:["\u0645\u0646","from"],tryAnotherReply:["\u062C\u0631\u0651\u0628 \u0631\u062F \u062A\u0627\u0646\u064A","Try another reply"],helpfulReply:["\u0631\u062F \u0645\u0641\u064A\u062F","Helpful reply"],unhelpfulReply:["\u0631\u062F \u0645\u0634 \u0645\u0641\u064A\u062F","Unhelpful reply"],aiDisclaimer:["\u0634\u0647\u0627\u0628 \u0645\u0645\u0643\u0646 \u064A\u063A\u0644\u0637. \u0631\u0627\u062C\u0639 \u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0642\u0628\u0644 \u0645\u0627 \u062A\u062A\u0635\u0631\u0651\u0641 \u0639\u0644\u064A\u0647\u0627.","Shehab can get things wrong. Check the numbers before acting on them."],back10:["\u0631\u062C\u0648\u0639 \u0661\u0660 \u062B\u0648\u0627\u0646\u064A","Back 10 seconds"],forward10:["\u062A\u0642\u062F\u064A\u0645 \u0661\u0660 \u062B\u0648\u0627\u0646\u064A","Forward 10 seconds"],playbackSpeed:["\u0633\u0631\u0639\u0629 \u0627\u0644\u062A\u0634\u063A\u064A\u0644","Playback speed"],arabic:["\u0627\u0644\u0639\u0631\u0628\u064A\u0629","Arabic"],seeMore:["\u0634\u0648\u0641 \u0643\u0645\u0627\u0646","See more"],pictureInPicture:["\u0646\u0627\u0641\u0630\u0629 \u0639\u0627\u0626\u0645\u0629","Picture in picture"]};function useUIText(){return useMoneyLang()?BUNDLES[EN]:BUNDLES[AR]}function build(i){const out={};for(const key of Object.keys(TEXT))out[key]=TEXT[key][i];return out}var BUNDLES=[build(AR),build(EN)];import{useEffect,useId}from"react";import{AlertTriangle,CheckCircle2,Info,X,XCircle}from"lucide-react";import{jsx,jsxs}from"react/jsx-runtime";function Sheet({open,title,onClose,action,children,closeLabel}){const ui=useUIText();useEffect(()=>{if(!open)return;function onKey(e){if(e.key==="Escape")onClose()}document.addEventListener("keydown",onKey);return()=>document.removeEventListener("keydown",onKey)},[open,onClose]);if(!open)return null;return jsxs("div",{className:"fixed inset-0 z-50 flex flex-col justify-end",role:"dialog","aria-modal":"true","aria-label":title,children:[jsx("button",{type:"button","aria-label":closeLabel??ui.close,onClick:onClose,className:"flex-1 bg-black/50 backdrop-blur-[3px] cursor-default animate-[fade-in_0.2s_ease-out]"}),jsxs("div",{className:cn("bg-surface rounded-t-section max-h-[82dvh] flex flex-col overflow-hidden shadow-sheet","animate-[sheet-up_0.26s_cubic-bezier(.22,.61,.36,1)]","pb-[env(safe-area-inset-bottom)]"),children:[jsx("button",{type:"button",onClick:onClose,"aria-label":closeLabel??ui.close,className:"shrink-0 pt-3 pb-1.5 flex justify-center cursor-grab active:cursor-grabbing",children:jsx("span",{"aria-hidden":"true",className:"h-1.5 w-11 rounded-full bg-border"})}),jsxs("div",{className:"shrink-0 flex items-center justify-between gap-3 px-5 pb-3",children:[jsx("span",{className:"text-h4 font-black tracking-tight",children:title}),jsxs("span",{className:"flex items-center gap-3",children:[action,jsx("button",{type:"button",onClick:onClose,"aria-label":closeLabel??ui.close,className:"size-9 rounded-full bg-bg flex items-center justify-center text-muted active:bg-hover active:scale-95 transition-transform cursor-pointer",children:jsx(X,{size:17,strokeWidth:2.4,"aria-hidden":"true"})})]})]}),jsx("div",{className:"flex-1 min-h-0 overflow-y-auto px-3 pb-4 flex flex-col overscroll-contain",children})]})]})}function Modal({open,title,description,onClose,footer,children,size="md",closeLabel}){const ui=useUIText();const titleId=useId();useEffect(()=>{if(!open)return;function onKey(e){if(e.key==="Escape")onClose()}document.addEventListener("keydown",onKey);return()=>document.removeEventListener("keydown",onKey)},[open,onClose]);if(!open)return null;const widths={sm:"max-w-md",md:"max-w-xl",lg:"max-w-3xl"};return jsxs("div",{className:"fixed inset-0 z-50 flex items-center justify-center p-4",role:"dialog","aria-modal":"true","aria-labelledby":titleId,children:[jsx("button",{type:"button","aria-label":closeLabel??ui.close,onClick:onClose,className:"absolute inset-0 bg-black/45 backdrop-blur-[2px] cursor-default"}),jsxs("div",{className:cn("relative w-full bg-surface rounded-lg border border-line flex flex-col max-h-[85dvh] animate-qfade shadow-modal",widths[size]),children:[jsxs("header",{className:"shrink-0 flex items-start justify-between gap-4 p-5 border-b border-line",children:[jsxs("div",{className:"flex flex-col gap-1 min-w-0",children:[jsx("h2",{id:titleId,className:"text-h4 font-extrabold text-ink m-0",children:title}),description&&jsx("p",{className:"text-ui text-muted m-0",children:description})]}),jsx("button",{type:"button",onClick:onClose,"aria-label":closeLabel??ui.close,className:"shrink-0 size-8 rounded-sm flex items-center justify-center text-muted hover:bg-hover hover:text-ink transition-colors cursor-pointer",children:jsx(X,{size:17,"aria-hidden":"true"})})]}),children&&jsx("div",{className:"flex-1 min-h-0 overflow-y-auto p-5",children}),footer&&jsx("footer",{className:"shrink-0 flex items-center justify-end gap-2.5 p-5 border-t border-line",children:footer})]})]})}function Drawer({open,title,description,onClose,footer,children,bodyClassName,closeLabel}){const ui=useUIText();const titleId=useId();useEffect(()=>{if(!open)return;function onKey(e){if(e.key==="Escape")onClose()}document.addEventListener("keydown",onKey);return()=>document.removeEventListener("keydown",onKey)},[open,onClose]);if(!open)return null;return jsxs("div",{className:"fixed inset-0 z-50 flex",role:"dialog","aria-modal":"true","aria-labelledby":titleId,children:[jsx("button",{type:"button","aria-label":closeLabel??ui.close,onClick:onClose,className:"flex-1 bg-black/45 backdrop-blur-[2px] cursor-default"}),jsxs("aside",{className:"w-full sm:w-[420px] bg-surface border-s border-line flex flex-col animate-qfade",children:[jsxs("header",{className:"shrink-0 h-16 px-4 border-b border-line flex items-center justify-between gap-3",children:[jsxs("span",{className:"flex flex-col gap-0.5 min-w-0",children:[jsx("span",{id:titleId,className:"text-lead font-extrabold truncate",children:title}),description&&jsx("span",{className:"text-caption text-muted truncate",children:description})]}),jsx("button",{type:"button",onClick:onClose,"aria-label":closeLabel??ui.close,className:"shrink-0 size-8 rounded-sm flex items-center justify-center text-muted hover:bg-hover hover:text-ink transition-colors cursor-pointer",children:jsx(X,{size:17,"aria-hidden":"true"})})]}),children&&jsx("div",{className:cn("flex-1 min-h-0 overflow-y-auto",bodyClassName??"p-4"),children}),footer&&jsx("footer",{className:"shrink-0 p-4 border-t border-line flex gap-2.5",children:footer})]})]})}var ALERT_ICON={neutral:Info,brand:Info,amber:AlertTriangle,green:CheckCircle2,red:XCircle,violet:Info};var ALERT_BORDER={neutral:"border-line",brand:"border-soft2",amber:"border-amber-line",green:"border-green-line",red:"border-red-line",violet:"border-violet-line"};function Alert({tone="brand",title,children,actions}){const Icon=ALERT_ICON[tone];const urgent=tone==="red"||tone==="amber";return jsxs("div",{role:urgent?"alert":"status",className:cn("flex items-start gap-3 p-4 rounded-card border",TONE_SOFT[tone],ALERT_BORDER[tone]),children:[jsx(Icon,{size:18,strokeWidth:2,"aria-hidden":"true"}),jsxs("div",{className:"flex flex-col gap-1.5 flex-1 min-w-0",children:[title&&jsx("span",{className:"text-body font-extrabold",children:title}),children&&jsx("span",{className:"text-ui leading-[1.7] opacity-90 [text-wrap:pretty]",children}),actions&&jsx("span",{className:"flex items-center gap-2 mt-1",children:actions})]})]})}function Toast({children,action,icon}){return jsxs("div",{role:"status","aria-live":"polite",className:"flex items-center gap-3 px-4 py-3.5 rounded-card bg-brand-900 shadow-toast animate-[fade-in_0.18s_ease-out]",children:[icon??jsx(CheckCircle2,{size:17,className:"text-brand-100 shrink-0","aria-hidden":"true"}),jsx("span",{className:"text-body font-bold text-white flex-1",children}),action]})}function EmptyState({icon:Icon,title,description,action}){return jsxs("div",{className:"flex flex-col items-center justify-center gap-2.5 py-12 px-5 text-center",children:[Icon&&jsx("span",{"aria-hidden":"true",className:"size-12 rounded-card bg-hover flex items-center justify-center text-muted mb-1",children:jsx(Icon,{size:21})}),jsx("span",{className:"text-lead font-extrabold text-ink",children:title}),description&&jsx("span",{className:"text-ui leading-[1.75] text-muted max-w-note [text-wrap:pretty]",children:description}),action&&jsx("span",{className:"mt-1",children:action})]})}export{TEXT_SCALE,RADIUS_SCALE,SHADOW_SCALE,CONTAINER_SCALE,ANIMATE_SCALE,COLOR_SCALE,TOKENS,DARK_TOKENS,cn,TONE_SOFT,TONE_SOLID,toLatinDigits,buttonClasses,LocaleCtx,useMoneyLocale,useMoneyLang,useUIText,Sheet,Modal,Drawer,Alert,Toast,EmptyState};
|