@qumra/fanar 0.0.13 → 0.0.14
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 +8 -115
- package/dist/ai.js +1 -1
- package/dist/chunk-ENHEJXVH.js +2 -0
- package/dist/chunk-EXX6U5BJ.js +2 -0
- package/dist/{chunk-NIEWNSOB.js → chunk-GMIBQMMR.js} +1 -1
- package/dist/chunk-VAMRF7HE.js +2 -0
- package/dist/chunk-ZE4S6DBP.js +2 -0
- package/dist/editor.js +1 -1
- package/dist/index.d.ts +174 -293
- package/dist/index.js +1 -1
- package/dist/notifications.js +1 -1
- package/package.json +6 -32
- package/dist/chunk-3EPEIAG2.js +0 -2
- package/dist/chunk-6DTSIOCB.js +0 -2
- package/dist/chunk-CTMW25W5.js +0 -2
- package/dist/chunk-K3TNXSD7.js +0 -2
- package/dist/native/ai.js +0 -1
- package/dist/native/chunk-LZHT3H7B.js +0 -1
- package/dist/native/chunk-RGKCDRSY.js +0 -2
- package/dist/native/editor.js +0 -1
- package/dist/native/index.js +0 -1
- package/dist/native/notifications.js +0 -1
- package/dist/native/orb.js +0 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# `@qumra/fanar`
|
|
2
2
|
|
|
3
3
|
Qumra's component library and design tokens — **Arabic-first**, Tailwind 4,
|
|
4
|
-
RSC-safe
|
|
4
|
+
RSC-safe.
|
|
5
5
|
|
|
6
6
|
Every component works in both `dir="rtl"` and `dir="ltr"` with no
|
|
7
7
|
direction-specific code: logical properties only, and the library reads its
|
|
8
|
-
own language from `<html lang
|
|
8
|
+
own language from `<html lang>`.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
pnpm add @qumra/fanar
|
|
@@ -27,8 +27,8 @@ system — each heavy group is behind its own path.
|
|
|
27
27
|
| `@qumra/fanar/orb` | Animated voice orb | needs `three`, `@react-three/fiber`, `@react-three/drei` |
|
|
28
28
|
| `@qumra/fanar/editor` | Rich-text editor | bundles TipTap |
|
|
29
29
|
|
|
30
|
-
Plus two stylesheets: `@qumra/fanar/tokens.css` and
|
|
31
|
-
|
|
30
|
+
Plus two stylesheets: `@qumra/fanar/tokens.css` and
|
|
31
|
+
`@qumra/fanar/editor.css`.
|
|
32
32
|
|
|
33
33
|
## Setup
|
|
34
34
|
|
|
@@ -48,111 +48,6 @@ import { TOKENS } from '@qumra/fanar/tokens'
|
|
|
48
48
|
</Button>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
## React Native
|
|
52
|
-
|
|
53
|
-
The same package serves native. There is no `@qumra/fanar-native` — a second
|
|
54
|
-
package would mean a second copy of every token, variant, size and prop
|
|
55
|
-
contract, and copies drift.
|
|
56
|
-
|
|
57
|
-
What makes one package work is that the parts that change often are shared
|
|
58
|
-
outright. `buttonClasses('primary', 'md')` returns the **same class string**
|
|
59
|
-
on both platforms; only the final element differs (`<button>` vs
|
|
60
|
-
`<Pressable>`). Change a token, a variant, or a size once, and both platforms
|
|
61
|
-
move together.
|
|
62
|
-
|
|
63
|
-
Resolution is automatic: Metro picks `Button.native.tsx` over `Button.tsx`,
|
|
64
|
-
and the published package routes the `react-native` export condition to a
|
|
65
|
-
native build.
|
|
66
|
-
|
|
67
|
-
### Requirements
|
|
68
|
-
|
|
69
|
-
React Native **0.80+** and [twrnc](https://github.com/jaredh159/tailwind-react-native-classnames).
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
pnpm add @qumra/fanar twrnc lucide-react-native react-native-svg
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
That is the whole native setup. There is **no Metro transformer, no Babel
|
|
76
|
-
preset, no CSS file, and no Tailwind install** — twrnc resolves class strings
|
|
77
|
-
at runtime, and the library builds its Tailwind config from the very same
|
|
78
|
-
`tokens.json` the web `@theme` block is generated from.
|
|
79
|
-
|
|
80
|
-
The earlier NativeWind route needed `metro.config.js` and `babel.config.js`
|
|
81
|
-
changes plus `tailwindcss@4`, `react-native-css` and RN 0.81; the app this
|
|
82
|
-
library targets runs RN 0.80 with a stock Metro config, so that cost was
|
|
83
|
-
real and the runtime route is what ships.
|
|
84
|
-
|
|
85
|
-
### Setup
|
|
86
|
-
|
|
87
|
-
None. Import and render:
|
|
88
|
-
|
|
89
|
-
```tsx
|
|
90
|
-
import { Button, Card, Input } from '@qumra/fanar'
|
|
91
|
-
;<Card>
|
|
92
|
-
<Input label="رقم الهاتف" numeric />
|
|
93
|
-
<Button variant="primary" onPress={save}>
|
|
94
|
-
احفظ
|
|
95
|
-
</Button>
|
|
96
|
-
</Card>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
`onClick` works too — the prop contract is the web one, so a screen written
|
|
100
|
-
once runs on both.
|
|
101
|
-
|
|
102
|
-
### Layout
|
|
103
|
-
|
|
104
|
-
One folder per component, holding both platforms and what they share:
|
|
105
|
-
|
|
106
|
-
```
|
|
107
|
-
src/Button/
|
|
108
|
-
index.tsx web
|
|
109
|
-
index.native.tsx native
|
|
110
|
-
index.test.tsx
|
|
111
|
-
index.native.test.tsx
|
|
112
|
-
src/Form/
|
|
113
|
-
index.tsx
|
|
114
|
-
index.native.tsx
|
|
115
|
-
variants.ts the styles both platforms import
|
|
116
|
-
…
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
`variants.ts` is the point of the whole arrangement: the class strings,
|
|
120
|
-
scales and pure calculations live there, and the two `index` files import
|
|
121
|
-
them. Change a size once and both platforms move. A native file is not
|
|
122
|
-
allowed to define styles of its own — the tests compare what it renders
|
|
123
|
-
against those constants, so drift fails the build.
|
|
124
|
-
|
|
125
|
-
Metro picks `index.native.tsx` over `index.tsx` automatically; TypeScript and
|
|
126
|
-
web bundlers see `index.tsx`.
|
|
127
|
-
|
|
128
|
-
### What is available on native
|
|
129
|
-
|
|
130
|
-
**19 of 23 component modules**, ~105 exports: `Button`, `Form` (8 fields),
|
|
131
|
-
`Display` (9), `Nav`, `Overlay`, `Feedback`, `Menu`, `Money`, `Phone`,
|
|
132
|
-
`Chart` (5), `Commerce` (4), `Choice`, `Disclosure`, `Provider`, `Rating`,
|
|
133
|
-
`NumberStepper`, `DateRange`, `Technical`, `Upload` — plus every pure helper
|
|
134
|
-
and all tokens.
|
|
135
|
-
|
|
136
|
-
Still web-only, each with a reason in `PROGRESS.md`: `Carousel`/`Gallery`/
|
|
137
|
-
`Lightbox`, `DataTable`, `Sortable`, `media` (video/audio players), `coach`,
|
|
138
|
-
`Product3DViewer`, `BrowserFrame`.
|
|
139
|
-
|
|
140
|
-
`src/native/parity.test.ts` fails the build if a new web export is added
|
|
141
|
-
without either porting it or recording why not, so that list cannot grow
|
|
142
|
-
quietly. The `/editor`, `/orb`, `/notifications` and `/ai` entry points
|
|
143
|
-
resolve to stubs that throw a readable message rather than a stray
|
|
144
|
-
`document is not defined`.
|
|
145
|
-
|
|
146
|
-
### Three differences worth knowing
|
|
147
|
-
|
|
148
|
-
1. **React Native does not inherit text styles.** A class string is split
|
|
149
|
-
across the container and the text node automatically
|
|
150
|
-
(`splitTypography`) — you pass one `className` as usual.
|
|
151
|
-
2. **There is no `currentColor`.** Icons take their colour as a prop,
|
|
152
|
-
resolved from the same tokens (`useTextColor`).
|
|
153
|
-
3. **`aria-*` becomes `accessibility*`.** You still write `aria-label`; the
|
|
154
|
-
native components translate it.
|
|
155
|
-
|
|
156
51
|
## The six rules
|
|
157
52
|
|
|
158
53
|
Every component in this library follows them, and two are enforced by lint:
|
|
@@ -169,12 +64,10 @@ Every component in this library follows them, and two are enforced by lint:
|
|
|
169
64
|
|
|
170
65
|
## Peer dependencies
|
|
171
66
|
|
|
172
|
-
`react`
|
|
173
|
-
`@react-three/fiber`, `@react-three/drei`, `@google/model-viewer`,
|
|
174
|
-
`@qumra/jawab-ai
|
|
175
|
-
|
|
176
|
-
install the ones whose entry point and platform you actually use. A web-only
|
|
177
|
-
consumer installs nothing from the native list.
|
|
67
|
+
`react` and `react-dom` are required. `tailwindcss`, `three`,
|
|
68
|
+
`@react-three/fiber`, `@react-three/drei`, `@google/model-viewer`, and
|
|
69
|
+
`@qumra/jawab-ai` are **optional** — you only install the ones whose entry
|
|
70
|
+
point you actually import.
|
|
178
71
|
|
|
179
72
|
This is not a formality. `@react-three/drei` pulls in `camera-controls`,
|
|
180
73
|
which requires Node 22; as a hard dependency it broke `yarn install` on a
|
package/dist/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import{BarChart,ChoiceCards,DataTable,Money,TrendChart,isCurrency}from"./chunk-CTMW25W5.js";import{Button,Input,Textarea}from"./chunk-K3TNXSD7.js";import{Badge,Card,StatCard,formatTime}from"./chunk-NIEWNSOB.js";import{Alert,Modal,cn,useUIText}from"./chunk-6DTSIOCB.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};
|
|
2
|
+
import{BarChart,ChoiceCards,DataTable,Money,TrendChart,isCurrency}from"./chunk-EXX6U5BJ.js";import{Button,Input,Textarea}from"./chunk-VAMRF7HE.js";import{Badge,Card,StatCard,formatTime}from"./chunk-GMIBQMMR.js";import{Alert,Modal,cn,useUIText}from"./chunk-ZE4S6DBP.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,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{cn,useUIText}from"./chunk-ZE4S6DBP.js";import{cloneElement,isValidElement,useCallback,useEffect,useId,useRef,useState}from"react";import{createPortal}from"react-dom";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);const anchor=useRef(null);const tip=useRef(null);const id=useId();const GAP=7;const EDGE=8;const place=useCallback(()=>{const el=tip.current;const host=anchor.current;if(!el||!host)return;const r=host.getBoundingClientRect();const w=el.offsetWidth;const h=el.offsetHeight;const vw=document.documentElement.clientWidth;const vh=document.documentElement.clientHeight;const left=Math.min(Math.max(r.left+r.width/2-w/2,EDGE),Math.max(EDGE,vw-EDGE-w));const above=side==="top"?r.top-GAP-h>=EDGE:r.bottom+GAP+h>vh-EDGE;const top=above?r.top-GAP-h:r.bottom+GAP;el.style.left=`${left}px`;el.style.top=`${Math.min(Math.max(top,EDGE),Math.max(EDGE,vh-EDGE-h))}px`;el.style.visibility="visible"},[side]);useEffect(()=>{if(!open)return;window.addEventListener("scroll",place,{capture:true,passive:true});window.addEventListener("resize",place,{passive:true});return()=>{window.removeEventListener("scroll",place,{capture:true});window.removeEventListener("resize",place)}},[open,place]);const mount=useCallback(el=>{tip.current=el;if(el)place()},[place]);const described=isValidElement(children)?cloneElement(children,{"aria-describedby":open?id:void 0}):children;return jsxs("span",{ref:anchor,className:"relative inline-flex",onMouseEnter:()=>setOpen(true),onMouseLeave:()=>setOpen(false),onFocus:()=>setOpen(true),onBlur:()=>setOpen(false),children:[described,open&&typeof document!=="undefined"&&createPortal(jsx("span",{id,role:"tooltip",ref:mount,style:{visibility:"hidden",left:0,top:0},className:cn("fixed z-[60] 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"),children:content}),document.body)]})}export{useToasts,ToastHost,Tooltip};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import{Coach,useCoachOptional}from"./chunk-GMIBQMMR.js";import{LocaleCtx,cn,useMoneyLocale,useUIText}from"./chunk-ZE4S6DBP.js";import{createContext,useContext}from"react";import{Fragment,jsx,jsxs}from"react/jsx-runtime";function Glyph({children,label,w=24}){return jsx("svg",{viewBox:`0 0 ${w} 24`,width:`${w/24}em`,height:"1em",fill:"none",stroke:"currentColor",strokeWidth:2.1,strokeLinecap:"round",strokeLinejoin:"round",role:"img","aria-label":label,className:"inline-block shrink-0 translate-y-[0.1em]",children})}var Dollar=jsxs(Glyph,{label:"\u062F\u0648\u0644\u0627\u0631",children:[jsx("path",{d:"M12 2.5v19"}),jsx("path",{d:"M16.5 7c0-1.9-2-3.2-4.5-3.2S7.5 5.1 7.5 7s2 2.8 4.5 3.4 4.5 1.5 4.5 3.4-2 3.2-4.5 3.2S7.5 15.7 7.5 13.8"})]});var Euro=jsxs(Glyph,{label:"\u064A\u0648\u0631\u0648",children:[jsx("path",{d:"M17.5 6.4A7 7 0 1 0 17.5 17.6"}),jsx("path",{d:"M3.5 10h10"}),jsx("path",{d:"M3.5 14h10"})]});var Pound=jsxs(Glyph,{label:"\u062C\u0646\u064A\u0647",children:[jsx("path",{d:"M16 6.2A3.7 3.7 0 0 0 9 7.8v6.4a5 5 0 0 1-2 4h11"}),jsx("path",{d:"M6 12h7"})]});var EgyptianPound=jsxs(Glyph,{label:"\u062C\u0646\u064A\u0647 \u0645\u0635\u0631\u064A",w:31,children:[jsx("path",{d:"M10.5 6H3.5v12h7"}),jsx("path",{d:"M3.5 12h5.5"}),jsx("path",{d:"M26.5 6.2A3.7 3.7 0 0 0 19.5 7.8v6.4a5 5 0 0 1-2 4h11"}),jsx("path",{d:"M16.5 12h7"})]});var Riyal=jsx("svg",{viewBox:"0 0 24 24",width:"1em",height:"1em",fill:"currentColor",role:"img","aria-label":"\u0631\u064A\u0627\u0644 \u0633\u0639\u0648\u062F\u064A",className:"inline-block shrink-0 translate-y-[0.08em]",children:jsx("path",{d:"M13.89 3.36L13.89 18.83L21.99 17.11C22.37 16.22 22.62 15.31 22.75 14.36L16.43 15.69L16.43 1.24C15.38 1.82 14.53 2.53 13.89 3.36M2.46 16.08L21.99 11.97C22.37 11.04 22.62 10.12 22.75 9.19L3.19 13.33C2.77 14.24 2.52 15.15 2.46 16.08M13.89 24.0L21.99 22.28C22.37 21.37 22.62 20.45 22.75 19.53L14.58 21.25C14.4 21.65 14.25 22.09 14.13 22.55C14.01 23.01 13.93 23.5 13.89 24.0M1.25 22.22L8.42 20.64C8.98 20.52 9.45 20.21 9.81 19.71L11.14 17.77C11.2 17.67 11.25 17.56 11.29 17.44C11.33 17.32 11.35 17.2 11.35 17.08L11.35 0.0C10.38 0.56 9.54 1.27 8.81 2.12L8.81 18.02L1.98 19.47C1.54 20.47 1.29 21.39 1.25 22.22"})});var CURRENCY={SAR:{short:"\u0631.\u0633",word:"\u0631\u064A\u0627\u0644",best:"sign",code:"SAR",sign:Riyal,name:"\u0631\u064A\u0627\u0644 \u0633\u0639\u0648\u062F\u064A",en:"Saudi riyals",decimals:2},AED:{short:"\u062F.\u0625",word:"\u062F\u0631\u0647\u0645",best:"word",code:"AED",sign:null,name:"\u062F\u0631\u0647\u0645 \u0625\u0645\u0627\u0631\u0627\u062A\u064A",en:"UAE dirhams",decimals:2},QAR:{short:"\u0631.\u0642",word:"\u0631\u064A\u0627\u0644",best:"word",code:"QAR",sign:null,name:"\u0631\u064A\u0627\u0644 \u0642\u0637\u0631\u064A",en:"Qatari riyals",decimals:2},KWD:{short:"\u062F.\u0643",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"KWD",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u0643\u0648\u064A\u062A\u064A",en:"Kuwaiti dinars",decimals:3},BHD:{short:"\u062F.\u0628",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"BHD",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u0628\u062D\u0631\u064A\u0646\u064A",en:"Bahraini dinars",decimals:3},OMR:{short:"\u0631.\u0639",word:"\u0631\u064A\u0627\u0644",best:"word",code:"OMR",sign:null,name:"\u0631\u064A\u0627\u0644 \u0639\u0645\u0627\u0646\u064A",en:"Omani riyals",decimals:3},EGP:{short:"\u062C.\u0645",word:"\u062C\u0646\u064A\u0647",best:"word",code:"EGP",sign:EgyptianPound,name:"\u062C\u0646\u064A\u0647 \u0645\u0635\u0631\u064A",en:"Egyptian pounds",decimals:2},JOD:{short:"\u062F.\u0623",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"JOD",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u0623\u0631\u062F\u0646\u064A",en:"Jordanian dinars",decimals:3},IQD:{short:"\u062F.\u0639",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"IQD",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u0639\u0631\u0627\u0642\u064A",en:"Iraqi dinars",decimals:3},LBP:{short:"\u0644.\u0644",word:"\u0644\u064A\u0631\u0629",best:"word",code:"LBP",sign:null,name:"\u0644\u064A\u0631\u0629 \u0644\u0628\u0646\u0627\u0646\u064A\u0629",en:"Lebanese pounds",decimals:2},SYP:{short:"\u0644.\u0633",word:"\u0644\u064A\u0631\u0629",best:"word",code:"SYP",sign:null,name:"\u0644\u064A\u0631\u0629 \u0633\u0648\u0631\u064A\u0629",en:"Syrian pounds",decimals:2},YER:{short:"\u0631.\u064A",word:"\u0631\u064A\u0627\u0644",best:"word",code:"YER",sign:null,name:"\u0631\u064A\u0627\u0644 \u064A\u0645\u0646\u064A",en:"Yemeni rials",decimals:2},SDG:{short:"\u062C.\u0633",word:"\u062C\u0646\u064A\u0647",best:"word",code:"SDG",sign:null,name:"\u062C\u0646\u064A\u0647 \u0633\u0648\u062F\u0627\u0646\u064A",en:"Sudanese pounds",decimals:2},MAD:{short:"\u062F.\u0645",word:"\u062F\u0631\u0647\u0645",best:"word",code:"MAD",sign:null,name:"\u062F\u0631\u0647\u0645 \u0645\u063A\u0631\u0628\u064A",en:"Moroccan dirhams",decimals:2},DZD:{short:"\u062F.\u062C",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"DZD",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u062C\u0632\u0627\u0626\u0631\u064A",en:"Algerian dinars",decimals:2},TND:{short:"\u062F.\u062A",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"TND",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u062A\u0648\u0646\u0633\u064A",en:"Tunisian dinars",decimals:3},LYD:{short:"\u062F.\u0644",word:"\u062F\u064A\u0646\u0627\u0631",best:"word",code:"LYD",sign:null,name:"\u062F\u064A\u0646\u0627\u0631 \u0644\u064A\u0628\u064A",en:"Libyan dinars",decimals:3},MRU:{short:"\u0623.\u0645",word:"\u0623\u0648\u0642\u064A\u0629",best:"word",code:"MRU",sign:null,name:"\u0623\u0648\u0642\u064A\u0629 \u0645\u0648\u0631\u064A\u062A\u0627\u0646\u064A\u0629",en:"Mauritanian ouguiya",decimals:2},SOS:{short:"\u0634.\u0635",word:"\u0634\u0644\u0646",best:"word",code:"SOS",sign:null,name:"\u0634\u0644\u0646 \u0635\u0648\u0645\u0627\u0644\u064A",en:"Somali shillings",decimals:0},DJF:{short:"\u0641.\u062C",word:"\u0641\u0631\u0646\u0643",best:"word",code:"DJF",sign:null,name:"\u0641\u0631\u0646\u0643 \u062C\u064A\u0628\u0648\u062A\u064A",en:"Djiboutian francs",decimals:0},KMF:{short:"\u0641.\u0642",word:"\u0641\u0631\u0646\u0643",best:"word",code:"KMF",sign:null,name:"\u0641\u0631\u0646\u0643 \u0642\u0645\u0631\u064A",en:"Comorian francs",decimals:0},USD:{short:"$",word:"\u062F\u0648\u0644\u0627\u0631",best:"sign",code:"USD",sign:Dollar,name:"\u062F\u0648\u0644\u0627\u0631 \u0623\u0645\u0631\u064A\u0643\u064A",en:"US dollars",decimals:2},EUR:{short:"\u20AC",word:"\u064A\u0648\u0631\u0648",best:"sign",code:"EUR",sign:Euro,name:"\u064A\u0648\u0631\u0648",en:"euros",decimals:2},GBP:{short:"\xA3",word:"\u0625\u0633\u062A\u0631\u0644\u064A\u0646\u064A",best:"sign",code:"GBP",sign:Pound,name:"\u062C\u0646\u064A\u0647 \u0625\u0633\u062A\u0631\u0644\u064A\u0646\u064A",en:"pounds sterling",decimals:2}};function isCurrency(c){return!!c&&c in CURRENCY}var CurrencyCtx=createContext(null);function MoneyProvider({currency,locale,children}){return jsx(CurrencyCtx.Provider,{value:currency,children:jsx(LocaleCtx.Provider,{value:locale??null,children})})}function useCurrency(){return useContext(CurrencyCtx)??"EGP"}function resolve(style,c,locale){if(style!=="best")return style;if(locale.startsWith("ar"))return c.best;return c.sign?"sign":"code"}var UNIT={short:"text-[0.82em]",word:"text-[0.86em] font-normal tracking-wide",code:"text-[0.78em] font-bold tracking-wide",sign:"text-[0.9em]"};var SIZE={inherit:"",sm:"text-caption",md:"text-ui",lg:"text-body font-extrabold",xl:"text-h2 font-black"};var TONE={inherit:"",muted:"text-muted",ink:"text-ink",green:"text-green",red:"text-red"};function Money({value,currency,size="md",tone="inherit",signed,compact,trimZeros,was,symbol,hideSymbol,className}){const locale=useMoneyLocale();const isEn=locale.startsWith("en");const store=useCurrency();const c=CURRENCY[currency??store];const decimals=c.decimals;const style=resolve(symbol??"best",c,locale);const unit=style==="code"?c.code:style==="word"?c.word:style==="sign"?c.sign??c.short:c.short;return jsxs("span",{className:cn("inline-flex items-baseline gap-1 whitespace-nowrap",SIZE[size],TONE[tone],className),children:[jsx("span",{"data-num":true,children:format(value,decimals,locale,{signed,compact,trimZeros})}),!hideSymbol&&jsxs(Fragment,{children:[jsx("span",{"aria-hidden":"true",className:cn("opacity-65",UNIT[style]),children:unit}),jsx("span",{className:"sr-only",children:locale.startsWith("ar")?c.name:isEn?c.en:c.code})]}),was!==void 0&&was!==value&&jsx("span",{className:"text-[0.82em] text-muted2 line-through decoration-1",children:jsx("span",{"data-num":true,children:format(was,decimals,locale,{compact,trimZeros})})})]})}function format(v,decimals,locale,{signed,compact,trimZeros}){const whole=trimZeros&&Number.isInteger(v);const nf=new Intl.NumberFormat(locale,compact?{notation:"compact",minimumFractionDigits:0,maximumFractionDigits:1}:{minimumFractionDigits:whole?0:decimals,maximumFractionDigits:whole?0:decimals});const sign=v<0?"\u2212":signed&&v>0?"+":"";return sign+nf.format(Math.abs(v))}function currencySymbol(c="EGP",style="best",locale="ar"){const cur=CURRENCY[c];const s=resolve(style,cur,locale);if(s==="code")return cur.code;if(s==="word")return cur.word;if(s==="sign")return cur.sign??cur.short;return cur.short}var currencyName=(c="EGP")=>CURRENCY[c].name;function useCurrencySymbol(c,style){const locale=useMoneyLocale();const store=useCurrency();return currencySymbol(c??store,style??"best",locale)}import{useState}from"react";import{ChevronLeft,ChevronRight}from"lucide-react";import{jsx as jsx2,jsxs as jsxs2}from"react/jsx-runtime";function DataTable({columns,rows,rowKey,grid,minWidth,onRowClick,mobileCard,empty,footer,pageSize,unit,className}){const ui=useUIText();const gridClass=`grid-cols-[${grid}]`;const[page,setPage]=useState(0);const pages=pageSize?Math.max(1,Math.ceil(rows.length/pageSize)):1;const safePage=Math.min(page,Math.max(0,pages-1));const shown=pageSize?rows.slice(safePage*pageSize,safePage*pageSize+pageSize):rows;if(rows.length===0&&empty){return jsx2("div",{className:cn("bg-surface border border-line rounded-card",className),children:empty})}return jsxs2("div",{role:"table",className:cn("bg-surface border border-line rounded-card overflow-clip",className),children:[mobileCard&&jsx2("ul",{className:"md:hidden flex flex-col m-0 p-0 list-none",children:shown.map(row=>jsx2("li",{className:"border-b border-line last:border-0",children:onRowClick?jsx2("button",{type:"button",onClick:()=>onRowClick(row),className:"w-full text-start px-4 py-3 cursor-pointer transition-colors active:bg-hover focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-brand",children:mobileCard(row)}):jsx2("div",{className:"px-4 py-3",children:mobileCard(row)})},rowKey(row)))}),jsx2("div",{className:cn("overflow-x-auto",mobileCard&&"max-md:hidden"),children:jsxs2("div",{style:{minWidth},children:[jsx2("div",{role:"row",className:cn("grid gap-3 items-center px-4 py-3 bg-bg border-b border-line",gridClass),style:{gridTemplateColumns:grid.replace(/_/g," ")},children:columns.map(c=>jsx2("span",{role:"columnheader",className:cn("text-caption font-bold text-muted",c.end&&"text-end"),children:c.header},c.key))}),shown.map(row=>jsx2("div",{role:"row",tabIndex:onRowClick?0:void 0,onKeyDown:onRowClick?e=>{if(e.key==="Enter"||e.key===" "){e.preventDefault();onRowClick(row)}}:void 0,onClick:onRowClick?()=>onRowClick(row):void 0,className:cn("grid gap-3 items-center px-4 py-3 border-b border-line last:border-0 transition-colors",onRowClick&&"cursor-pointer hover:bg-hover focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-brand",!onRowClick&&"hover:bg-hover"),style:{gridTemplateColumns:grid.replace(/_/g," ")},children:columns.map(c=>jsx2("span",{role:"cell",className:cn("min-w-0",c.end&&"flex justify-end"),children:c.cell(row)},c.key))},rowKey(row)))]})}),(footer||pageSize)&&jsxs2("div",{className:"flex items-center justify-between gap-3 px-4 py-3 bg-bg flex-wrap",children:[footer,pageSize&&jsx2(Pager,{page:safePage,pages,from:page*pageSize+1,to:Math.min(rows.length,(page+1)*pageSize),total:rows.length,unit:unit??ui.row,onPage:setPage})]})]})}function Pager({page,pages,from,to,total,unit,onPage}){const ar=new Intl.NumberFormat("ar-EG");const first=page===0;const last=page>=pages-1;const btn=dir=>{const off=dir===-1?first:last;return jsx2("button",{type:"button",disabled:off,"aria-label":dir===-1?"\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0633\u0627\u0628\u0642\u0629":"\u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u062A\u0627\u0644\u064A\u0629",onClick:()=>onPage(page+dir),className:cn("size-8 rounded-sm flex items-center justify-center transition-colors",off?"text-muted2/40 cursor-not-allowed":"text-ink2 hover:bg-hover cursor-pointer"),children:dir===-1?jsx2(ChevronRight,{size:16,className:"rtl:rotate-0 ltr:rotate-180","aria-hidden":"true"}):jsx2(ChevronLeft,{size:16,className:"rtl:rotate-0 ltr:rotate-180","aria-hidden":"true"})})};return jsxs2("div",{className:"flex items-center gap-2 ms-auto",children:[jsxs2("span",{className:"text-caption text-muted",children:[jsxs2("span",{"data-num":true,className:"font-bold text-ink2",children:[ar.format(from),"\u2013",ar.format(to)]})," ","\u0645\u0646"," ",jsx2("span",{"data-num":true,className:"font-bold text-ink2",children:ar.format(total)})," ",unit]}),jsx2("span",{"aria-live":"polite",className:"sr-only",children:`\u0639\u0631\u0636 ${from} \u0625\u0644\u0649 ${to} \u0645\u0646 ${total}`}),btn(-1),btn(1)]})}import{useEffect,useId,useMemo,useRef,useState as useState2}from"react";import{scaleLinear}from"@visx/scale";import{AreaClosed,LinePath}from"@visx/shape";import{curveMonotoneX}from"@visx/curve";import{TooltipWithBounds}from"@visx/tooltip";import{Fragment as Fragment2,jsx as jsx3,jsxs as jsxs3}from"react/jsx-runtime";var clamp=(v,lo=0,hi=100)=>Math.min(hi,Math.max(lo,v));function BarChart({labels,series,height=180,formatValue=String,showValues,className}){const plot=useRef(null);const[at,setAt]=useState2(null);const cols=useRef([]);const[tipX,setTipX]=useState2(0);const[,setW]=useState2(0);useEffect(()=>{const el=plot.current;if(!el)return;const measure=()=>setW(el.clientWidth);measure();const ro=new ResizeObserver(measure);ro.observe(el);return()=>ro.disconnect()},[]);const peak=Math.max(1,...series.flatMap(s=>s.values));const n=labels.length;const plotH=height-26;const single=series.length===1;const numbers=showValues??single;const peakAt=at===null?0:Math.max(...series.map(s=>s.values[at]??0));function activate(i){const el=cols.current[i];if(el)setTipX(el.offsetLeft+el.offsetWidth/2);setAt(i)}function onKey(e){const step=e.key==="ArrowRight"?1:e.key==="ArrowLeft"?-1:0;if(step){e.preventDefault();activate(Math.min(n-1,Math.max(0,(at??0)+step)))}else if(e.key==="Home"){e.preventDefault();activate(0)}else if(e.key==="End"){e.preventDefault();activate(n-1)}else if(e.key==="Escape"){setAt(null)}}return jsxs3("div",{className:cn("flex flex-col gap-2.5",className),children:[series.length>1&&jsx3("div",{className:"flex items-center gap-4 text-micro text-muted",children:series.map(s=>jsxs3("span",{className:"flex items-center gap-1.5",children:[jsx3("span",{"aria-hidden":"true",className:cn("size-2.5 rounded-mark",s.muted?"bg-brand-100":"bg-brand")}),s.label]},s.label))}),jsxs3("div",{ref:plot,className:"relative outline-none focus-visible:ring-2 focus-visible:ring-brand/40 rounded-xs",style:{height},tabIndex:0,role:"img","aria-label":labels.join("\u060C "),onKeyDown:onKey,onPointerLeave:()=>setAt(null),onBlur:()=>setAt(null),children:[[1,.5,0].map(f=>jsx3("span",{"aria-hidden":"true",className:"absolute inset-x-0 border-t border-line flex items-start",style:{top:plotH-plotH*f},children:jsx3("span",{"data-num":true,dir:"auto",className:"text-micro text-muted2 -mt-2 bg-surface pe-1",children:formatValue(Math.round(peak*f))})},f)),jsx3("div",{className:"absolute inset-0 flex items-end gap-1.5",children:labels.map((label,i)=>jsxs3("div",{ref:el=>{cols.current[i]=el},onPointerEnter:()=>activate(i),className:cn("flex-1 flex flex-col items-center justify-end gap-1.5 h-full min-w-0 rounded-xs transition-colors",at===i&&"bg-hover"),children:[jsx3("span",{className:"w-full flex items-end justify-center gap-[3px]",style:{height:plotH},children:series.map(s=>jsx3("span",{className:cn("relative flex justify-center rounded-t-mark transition-[height,background-color] duration-300",series.length>1?"w-1/2":"w-3/5",s.muted?"bg-brand-100":at===null||at===i?"bg-brand":"bg-brand-100"),style:{height:Math.max(2,Math.round((s.values[i]??0)/peak*plotH))},children:numbers&&jsx3("span",{"data-num":true,className:"absolute bottom-full mb-1 text-micro font-bold text-ink whitespace-nowrap",children:formatValue(s.values[i]??0)})},s.label))}),jsx3("span",{className:cn("text-micro truncate max-w-full transition-colors",at===i?"text-ink font-bold":"text-muted2"),children:label})]},label))}),at!==null&&jsxs3(TooltipWithBounds,{unstyled:true,applyPositionStyle:true,left:tipX,top:plotH-peakAt/peak*plotH,dir:"rtl",className:"pointer-events-none rounded-sm border border-line bg-surface px-2.5 py-1.5 shadow-tip flex flex-col gap-0.5",children:[jsx3("span",{className:"text-micro text-muted2",children:labels[at]}),series.map(s=>jsxs3("span",{className:"flex items-center gap-2 text-caption text-ink",children:[series.length>1&&jsx3("span",{className:"text-micro text-muted2",children:s.label}),jsx3("span",{"data-num":true,className:"font-extrabold",children:formatValue(s.values[at]??0)})]},s.label))]})]}),jsx3("span",{className:"sr-only","aria-live":"polite",children:at!==null?[labels[at],...series.map(s=>`${s.label}: ${formatValue(s.values[at]??0)}`)].join(" \u2014 "):""}),jsx3("ul",{className:"sr-only",children:labels.map((label,i)=>jsx3("li",{children:[label,...series.map(s=>`${s.label}: ${formatValue(s.values[i]??0)}`)].join(" \u2014 ")},label))})]})}function TrendChart({labels,values,compare,pointLabels,mode="area",height=200,formatValue=String,compareLabel,className}){const ui=useUIText();const gid=useId().replace(/:/g,"");const plot=useRef(null);const[w,setW]=useState2(0);const[at,setAt]=useState2(null);const H=height-24;const PAD_T=6;useEffect(()=>{const el=plot.current;if(!el)return;const measure=()=>setW(el.clientWidth);measure();const ro=new ResizeObserver(measure);ro.observe(el);return()=>ro.disconnect()},[]);const max=Math.max(1,...values,...compare??[]);const n=values.length;const nameAt=i=>pointLabels?.[i]??(labels.length===n?labels[i]:void 0);const slot=n>0?w/n:w;const bw=slot*.62;const inset=mode==="bars"?slot/2:0;const x=useMemo(()=>scaleLinear({domain:[0,Math.max(1,n-1)],range:[inset,w-inset]}),[n,w,inset]);const y=useMemo(()=>scaleLinear({domain:[0,max],range:[H,PAD_T]}),[max,H]);function pick(clientX){const el=plot.current;if(!el||!w)return;const rect=el.getBoundingClientRect();const i=Math.round(x.invert(clientX-rect.left));setAt(Math.min(n-1,Math.max(0,i)))}function onKey(e){const step=e.key==="ArrowRight"?1:e.key==="ArrowLeft"?-1:0;if(step){e.preventDefault();setAt(p=>Math.min(n-1,Math.max(0,(p??0)+step)))}else if(e.key==="Home"){e.preventDefault();setAt(0)}else if(e.key==="End"){e.preventDefault();setAt(n-1)}else if(e.key==="Escape"){setAt(null)}}return jsxs3("div",{className:cn("flex flex-col gap-2",className),children:[jsxs3("div",{ref:plot,dir:"ltr",className:"relative outline-none focus-visible:ring-2 focus-visible:ring-brand/40 rounded-xs",style:{height:H},tabIndex:0,role:"img","aria-label":`${labels[0]} \u2014 ${labels[labels.length-1]}`,onKeyDown:onKey,onPointerMove:e=>pick(e.clientX),onPointerLeave:()=>setAt(null),onBlur:()=>setAt(null),children:[[1,.5,0].map(f=>jsx3("span",{"aria-hidden":"true",className:"absolute inset-x-0 border-t border-line flex items-start",style:{top:y(max*f)},children:jsx3("span",{"data-num":true,dir:"auto",className:"text-micro text-muted2 -mt-2 bg-surface pe-1",children:formatValue(Math.round(max*f))})},f)),jsxs3("svg",{width:w,height:H,className:"absolute inset-0","aria-hidden":"true",children:[jsx3("defs",{children:jsxs3("linearGradient",{id:`g${gid}`,x1:"0",y1:"0",x2:"0",y2:"1",children:[jsx3("stop",{offset:"0%",stopColor:"currentColor",stopOpacity:"0.16"}),jsx3("stop",{offset:"100%",stopColor:"currentColor",stopOpacity:"0"})]})}),mode==="area"?jsxs3(Fragment2,{children:[jsx3(AreaClosed,{data:values,x:(_,i)=>x(i),y:v=>y(v),yScale:y,curve:curveMonotoneX,className:"text-brand",fill:`url(#g${gid})`,stroke:"none"}),jsx3(LinePath,{data:values,x:(_,i)=>x(i),y:v=>y(v),curve:curveMonotoneX,fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",className:"stroke-brand"})]}):values.map((v,i)=>jsx3("rect",{x:x(i)-bw/2,y:y(v),width:bw,height:Math.max(2,H-y(v)),rx:3,className:at===i?"fill-brand":"fill-brand-100"},i)),compare&&jsx3(LinePath,{data:compare,x:(_,i)=>x(i),y:v=>y(v),curve:curveMonotoneX,fill:"none",strokeWidth:1.5,strokeDasharray:"3 3",strokeLinecap:"round",className:"stroke-brand-100"}),at!==null&&jsxs3(Fragment2,{children:[jsx3("line",{x1:x(at),y1:0,x2:x(at),y2:H,strokeWidth:1,strokeDasharray:"4 4",className:"stroke-brand opacity-45"}),mode==="area"&&jsx3("circle",{cx:x(at),cy:y(values[at]),r:5,strokeWidth:3,className:"fill-surface stroke-brand"})]})]}),at!==null&&w>0&&jsxs3(TooltipWithBounds,{unstyled:true,applyPositionStyle:true,left:x(at),top:y(values[at]),dir:"rtl",className:"pointer-events-none rounded-sm border border-line bg-surface px-2.5 py-1.5 shadow-tip flex flex-col gap-0.5",children:[nameAt(at)&&jsx3("span",{className:"text-micro text-muted2",children:nameAt(at)}),jsx3("span",{"data-num":true,className:"text-caption font-extrabold text-ink",children:formatValue(values[at])}),compare?.[at]!==void 0&&jsxs3("span",{"data-num":true,className:"text-micro text-muted2",children:[compareLabel??ui.previousPeriod,": ",formatValue(compare[at])]})]})]}),jsx3("span",{className:"sr-only","aria-live":"polite",children:at!==null?[nameAt(at),formatValue(values[at])].filter(Boolean).join(": "):""}),jsx3("ul",{className:"sr-only",children:values.map((v,i)=>jsx3("li",{children:[nameAt(i),formatValue(v)].filter(Boolean).join(": ")},i))}),jsx3("div",{dir:"ltr",className:"flex items-center justify-between text-micro text-muted2",children:labels.map(l=>jsx3("span",{children:l},l))})]})}function FunnelChart({stages,formatValue=String,className}){const[at,setAt]=useState2(null);const top=Math.max(1,stages[0]?.value??1);const drops=stages.map((s,i)=>{if(i===0)return null;const prev=stages[i-1].value;return prev>0?(prev-s.value)/prev*100:0});const worst=drops.reduce((acc,d,i)=>d!==null&&d>acc.d?{i,d}:acc,{i:-1,d:-1});return jsxs3("div",{className:cn("flex flex-col",className),children:[stages.map((s,i)=>{const share=clamp(s.value/top*100);const drop=drops[i];const isWorst=i===worst.i;return jsxs3("div",{tabIndex:0,role:"img","aria-label":`${s.label}: ${formatValue(s.value)}`,onPointerEnter:()=>setAt(i),onPointerLeave:()=>setAt(null),onFocus:()=>setAt(i),onBlur:()=>setAt(null),className:cn("flex flex-col rounded-xs outline-none transition-colors","focus-visible:ring-2 focus-visible:ring-brand/40",at===i&&"bg-hover"),children:[drop!==null&&jsxs3("span",{className:cn("flex items-center gap-1.5 ps-1 py-1 text-micro",isWorst?"font-extrabold text-amber-ink":"text-muted2"),children:[jsx3("span",{"aria-hidden":"true",className:cn("w-px h-3",isWorst?"bg-amber":"bg-line")}),jsxs3("span",{"data-num":true,children:["\u2212",drop.toFixed(0),"%"]}),isWorst&&jsx3("span",{children:"\xB7 \u0623\u0643\u0628\u0631 \u062A\u0633\u0631\u0651\u0628"})]}),jsxs3("div",{className:"flex items-center gap-3",children:[jsx3("span",{className:"w-32 sm:w-40 shrink-0 text-ui text-ink2 truncate",children:s.label}),jsx3("span",{className:"flex-1 h-8 rounded-xs bg-hover overflow-clip",children:jsx3("span",{className:cn("block h-full rounded-xs transition-[width] duration-500",isWorst?"bg-amber":"bg-brand"),style:{width:`${share}%`}})}),jsx3("span",{"data-num":true,className:"w-20 shrink-0 text-ui font-extrabold text-ink text-end",children:formatValue(s.value)})]}),at===i&&jsxs3("span",{className:"flex flex-wrap items-center gap-x-3 gap-y-0.5 ps-1 pb-1.5 text-micro text-muted",children:[jsxs3("span",{"data-num":true,children:[share.toFixed(share<10?1:0),"% ","\xB7"," ",stages[0]?.label]}),i>0&&jsxs3("span",{"data-num":true,children:["\u2212",formatValue(Math.max(0,stages[i-1].value-s.value))]})]})]},s.key)}),worst.i>0&&stages[worst.i].advice&&jsx3("span",{className:"mt-3 flex items-start gap-2 p-3 rounded-field bg-amber-bg text-caption leading-[1.7] text-amber-ink",children:stages[worst.i].advice})]})}function Heatmap({rows,cols,values,formatCell=v=>String(v),lowLabel,highLabel,className}){const ui=useUIText();const peak=Math.max(1,...values.flat());const step=v=>v===0?0:Math.min(3,Math.ceil(v/peak*3));const TINT=["bg-hover","bg-brand/25","bg-brand/55","bg-brand"];const grid={gridTemplateColumns:`56px repeat(${cols.length}, minmax(0,1fr))`};return jsxs3("div",{className:cn("flex flex-col gap-1",className),children:[jsxs3("span",{className:"grid gap-1",style:grid,children:[jsx3("span",{}),cols.map(c=>jsx3("span",{"data-num":true,className:"text-micro text-muted2 text-center",children:c},c))]}),rows.map((r,ri)=>jsxs3("span",{className:"grid gap-1 items-center",style:grid,children:[jsx3("span",{className:"text-micro text-muted truncate",children:r}),cols.map((c,ci)=>{const v=values[ri]?.[ci]??0;return jsx3("span",{title:formatCell(v,r,c),className:cn("h-6 rounded-mark transition-colors",TINT[step(v)])},c)})]},r)),jsxs3("span",{className:"flex items-center gap-2 pt-1 text-micro text-muted2",children:[lowLabel??ui.less,jsx3("span",{className:"flex gap-1",children:TINT.map(c=>jsx3("span",{className:cn("size-3 rounded-mark",c)},c))}),highLabel??ui.more]})]})}var SHARE_FILL={brand:"bg-brand",amber:"bg-amber",red:"bg-danger",muted:"bg-border"};function ShareList({items,total,layout="stacked",showPercent=true,labelWidth="6rem",formatValue=String,className}){const sum=total??items.reduce((s,i)=>s+i.value,0);const inline=layout==="inline";return jsx3("div",{className:cn("flex flex-col",inline?"gap-1.5":"gap-3",className),children:items.map(it=>{const pct=sum>0?it.value/sum*100:0;const bar=jsx3("span",{className:cn("rounded-full bg-hover overflow-clip",inline?"flex-1 h-1.5 min-w-0":"block h-1.5"),children:jsx3("span",{className:cn("block h-full rounded-full transition-[width] duration-500",SHARE_FILL[it.tone??"brand"]),style:{width:`${clamp(pct)}%`}})});if(inline){return jsxs3("span",{className:"flex items-center gap-2.5",children:[jsx3("span",{style:{width:labelWidth},className:"shrink-0 text-micro text-muted truncate",children:it.label}),bar,jsx3("span",{"data-num":true,style:{width:labelWidth},className:"shrink-0 text-caption text-muted2 text-end truncate",children:it.trailing??formatValue(it.value)})]},it.key)}return jsxs3("span",{className:"flex flex-col gap-1.5",children:[jsxs3("span",{className:"flex items-center justify-between gap-3",children:[jsxs3("span",{className:"flex flex-col min-w-0",children:[jsx3("span",{className:"text-ui font-bold text-ink truncate",children:it.label}),it.meta&&jsx3("span",{className:"text-micro text-muted truncate",children:it.meta})]}),jsxs3("span",{className:"flex items-center gap-3 shrink-0",children:[it.trailing,jsx3("span",{"data-num":true,className:"text-ui font-extrabold text-ink min-w-[64px] text-end",children:formatValue(it.value)}),showPercent&&jsxs3("span",{"data-num":true,className:"text-micro text-muted2 w-9 text-end",children:[pct.toFixed(0),"%"]})]})]}),bar]},it.key)})})}import{useState as useState3}from"react";import{Check,Info,Lock}from"lucide-react";import{Fragment as Fragment3,jsx as jsx4,jsxs as jsxs4}from"react/jsx-runtime";function ChoiceCards({name,value,onChange,options,columns=1,hideMark,multiple,disabled:allDisabled,className}){const ui=useUIText();const coach=useCoachOptional();const cols={1:"",2:"sm:grid-cols-2",3:"sm:grid-cols-3"}[columns];const picked=Array.isArray(value)?new Set(value):null;return jsx4("div",{role:multiple?"group":"radiogroup",className:cn("grid gap-2.5",cols,className),children:options.map(o=>{const on=picked?picked.has(o.value):o.value===value;const off=o.disabled||allDisabled;const card=jsxs4("label",{className:cn("relative flex items-start gap-3 p-3.5 rounded-card border transition-colors",off?"border-line bg-bg cursor-not-allowed opacity-70":"cursor-pointer hover:border-brand",on&&!off?"border-brand bg-soft":"border-border bg-surface"),children:[jsx4("input",{type:multiple?"checkbox":"radio",name,value:o.value,checked:on,disabled:off,onChange:()=>onChange(o.value),className:"sr-only peer"}),!hideMark&&jsx4("span",{"aria-hidden":"true",className:cn("mt-0.5 size-[19px] border-[1.5px] flex items-center justify-center shrink-0 transition-colors",multiple?"rounded-mark":"rounded-full","peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-brand",on&&!off?"border-brand bg-brand":"border-border bg-surface"),children:on&&!off&&jsx4(Check,{size:12,strokeWidth:3,className:"text-white"})}),o.icon&&jsx4("span",{"aria-hidden":"true",className:cn("size-9 rounded-field flex items-center justify-center shrink-0 transition-colors",on&&!off?"bg-brand text-white":"bg-hover text-muted"),children:jsx4(o.icon,{size:17,strokeWidth:2})}),jsxs4("span",{className:"flex-1 min-w-0 flex flex-col gap-0.5",children:[jsx4("span",{className:"text-body font-extrabold text-ink",children:o.label}),o.meta&&jsx4("span",{className:"text-caption leading-[1.6] text-muted",children:o.meta}),off&&o.lockReason&&jsxs4("span",{className:"inline-flex items-center gap-1 mt-1 text-caption font-bold text-amber-ink",children:[jsx4(Lock,{size:11,"aria-hidden":"true"}),o.lockReason]})]}),o.price&&jsx4("span",{"data-num":true,className:"text-ui font-extrabold text-ink shrink-0",children:o.price}),o.coachId&&coach&&jsx4("button",{type:"button",onClick:e=>{e.preventDefault();e.stopPropagation();coach.replay(o.coachId)},"aria-label":typeof o.label==="string"?`\u0645\u0627 \u0645\u0639\u0646\u0649 \xAB${o.label}\xBB\u061F`:"\u0645\u0627 \u0647\u0630\u0627 \u0627\u0644\u062E\u064A\u0627\u0631\u061F",title:ui.whatIsThisOption,className:cn("self-start ms-auto -me-1 -mt-1 size-7 rounded-full shrink-0 flex items-center justify-center","text-brand cursor-pointer transition-colors","hover:bg-soft hover:text-brand-hover","focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand"),children:jsx4(Info,{size:15,strokeWidth:2,"aria-hidden":"true"})})]});return o.coachId&&coach?jsx4(Coach,{id:o.coachId,children:card},o.value):jsx4("span",{className:"contents",children:card},o.value)})})}function Sparkline({values,width=72,height=24,tone="brand",fluid,labels,formatValue=String,className}){const[at,setAt]=useState3(null);if(values.length<2)return null;const max=Math.max(...values);const min=Math.min(...values);const span=max-min||1;const step=width/(values.length-1);const points=values.map((v,i)=>{const x=i*step;const y=height-(v-min)/span*(height-3)-1.5;return[x,y]});const line=points.map(([x,y],i)=>`${i===0?"M":"L"}${x.toFixed(1)},${y.toFixed(1)}`).join(" ");const area=`${line} L${width},${height} L0,${height} Z`;const stroke={brand:"stroke-brand",green:"stroke-green",red:"stroke-danger",muted:"stroke-muted2"}[tone];const fill={brand:"fill-brand/10",green:"fill-green/10",red:"fill-danger/10",muted:"fill-muted2/10"}[tone];const pct=at===null?0:at/(values.length-1)*100;function pick(e){const el=e.currentTarget;const w=el.clientWidth||1;const x=e.clientX-el.getBoundingClientRect().left;const i=Math.round(x/w*(values.length-1));setAt(Math.min(values.length-1,Math.max(0,i)))}const text={brand:"text-brand",green:"text-green",red:"text-danger",muted:"text-muted2"}[tone];return jsxs4("span",{className:cn("relative block",text,fluid?"w-full":"inline-block w-fit"),onPointerMove:pick,onPointerLeave:()=>setAt(null),children:[jsxs4("svg",{width:fluid?void 0:width,height:fluid?void 0:height,viewBox:`0 0 ${width} ${height}`,preserveAspectRatio:fluid?"none":void 0,"aria-hidden":"true",style:{direction:"ltr"},className:cn(fluid?"w-full block":"shrink-0","overflow-visible",className),children:[jsx4("path",{d:area,className:cn("stroke-none",fill)}),jsx4("path",{d:line,fill:"none",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",vectorEffect:"non-scaling-stroke",className:stroke})]}),at!==null&&jsxs4(Fragment3,{children:[jsx4("span",{"aria-hidden":"true",style:{left:`${pct}%`,top:`${points[at][1]/height*100}%`},className:"pointer-events-none absolute z-10 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-current bg-surface"}),jsxs4("span",{style:{left:`${pct}%`},className:"pointer-events-none absolute bottom-full z-10 mb-1 -translate-x-1/2 whitespace-nowrap rounded-sm border border-line bg-surface px-1.5 py-0.5 shadow-tip text-micro text-ink",children:[labels?.[at]&&jsxs4("span",{className:"text-muted2",children:[labels[at]," \xB7 "]}),jsx4("span",{"data-num":true,className:"font-bold",children:formatValue(values[at])})]})]}),labels&&jsx4("ul",{className:"sr-only",children:values.map((v,i)=>jsxs4("li",{children:[labels[i],": ",formatValue(v)]},i))})]})}export{isCurrency,MoneyProvider,useCurrency,Money,currencySymbol,currencyName,useCurrencySymbol,DataTable,BarChart,TrendChart,FunnelChart,Heatmap,ShareList,ChoiceCards,Sparkline};
|