Yoga سے کونسول کا لے آؤٹ بنانا
Text.js، WebAssembly میں Yoga کو 1 پوائنٹ اسکیل فیکٹر کے ساتھ چلاتا ہے، اس لیے ہر باکس پورے سیل پر آتا ہے۔ متن کو Intl.Segmenter سے حصوں میں بانٹا اور سیلز میں ناپا جاتا ہے۔
Text.js کے ہر فریم کا لے آؤٹ Yoga بناتا ہے، جو React Native میں استعمال ہونے والا flexbox انجن ہے اور WebAssembly میں کمپائل کیا گیا ہے۔ باکس اور متن ایک ہی Yoga ٹری میں ہوتے ہیں۔ کونسول کریکٹر سیلز کا گرڈ ہے، اس لیے اس سے نکلنے والی ہر پوزیشن اور سائز پورے سیلز کی تعداد میں ہونا چاہیے۔
ایک پوائنٹ ایک سیل کے برابر
Yoga اپنے نتائج کو پوائنٹ اسکیل فیکٹر سے متعین پکسل گرڈ پر راؤنڈ کرتا ہے۔ 2 پر، جیسا کہ Retina اسکرین پر ہوتا ہے، کنارے آدھے پوائنٹس پر آ سکتے ہیں۔ Text.js، Yoga کو ایک بار لوڈ کرتا ہے اور فیکٹر کو 1 پر سیٹ کرتا ہے:
export function initYoga(): Promise<Yoga> { if (yoga !== null) return Promise.resolve(yoga); if (yogaPromise === null) { yogaPromise = loadYoga().then((instance) => { yoga = instance; const config = instance.Config.create(); config.setPointScaleFactor(1); config.setUseWebDefaults(false); yogaConfig = config; return instance; }); yogaPromise.catch(() => { yogaPromise = null; }); } return yogaPromise;}1 کے فیکٹر کے ساتھ، Yoga ہر کنارے کو پورے یونٹ پر راؤنڈ کرتا ہے، اور Text.js ایک یونٹ کو ایک سیل مانتا ہے۔ Yoga ہر کنارے کی مطلق پوزیشن کو راؤنڈ کرتا ہے اور راؤنڈ کیے گئے کناروں سے سائز نکالتا ہے، اس لیے ساتھ والے باکس کا کنارہ مشترک ہوتا ہے۔ 81 کالم کی قطار کو دو width="50%" باکس میں تقسیم کریں تو ایک کو 40 کالم ملتے ہیں اور دوسرے کو 41، نہ کوئی خلا رہتا ہے نہ اوورلیپ۔
Text.js خود CSS کی ڈیفالٹ ترتیبات لاگو کرتا ہے: flexDirection کی ویلیو row اور flexShrink کی ویلیو 1 ہوتی ہے، جیسے براؤزر میں۔
متن کی پیمائش
ٹیکسٹ نوڈز Yoga کے لیف نوڈز ہیں جن میں پیمائش کا فنکشن ہوتا ہے۔ Yoga دستیاب چوڑائی کے ساتھ اسے کال کرتا ہے، اور Text.js متن کا سائز سیلز میں واپس کرتا ہے:
private measure(width: number, widthMode: MeasureMode, _height: number, _heightMode: MeasureMode): { width: number; height: number } { const natural = this.naturalSize(); if (widthMode === MeasureMode.Undefined || Number.isNaN(width)) return natural; const avail = Math.max(0, Math.floor(width)); if (natural.width <= avail) { return { width: widthMode === MeasureMode.Exactly ? avail : natural.width, height: natural.height }; } if ((this.props.wrap ?? "wrap") !== "wrap") return { width: avail, height: natural.height }; const lines = this.getLines(avail); let maxLine = 0; for (const l of lines) if (l.width > maxLine) maxLine = l.width; return { width: widthMode === MeasureMode.Exactly ? avail : Math.min(avail, maxLine), height: lines.length };}جو متن سما جائے، اس کا قدرتی سائز واپس ملتا ہے۔ جو متن نہ سمائے، اسے دستیاب چوڑائی پر ریپ کیا جاتا ہے، اور اس کی اونچائی لائنوں کی تعداد ہوتی ہے۔ نوڈ پچھلا ریپ محفوظ رکھتا ہے، اس لیے اسی چوڑائی کی دوبارہ پیمائش سے متن دوبارہ ریپ نہیں ہوتا۔
گرافیم کلسٹرز کی پیمائش
اسٹرنگ کی length، UTF-16 کوڈ یونٹس گنتی ہے، جس سے یہ زیادہ واضح نہیں ہوتا کہ وہ کتنے سیل بھرتی ہے۔ پہلے Intl.Segmenter سے متن کو گرافیم کلسٹرز میں تقسیم کیا جاتا ہے، اس لیے e کے بعد آنے والا کمبائننگ ایکسنٹ ایک ہی کلسٹر بنتا ہے، اور زیرو وڈتھ جوائنرز سے جڑی ایموجی ترتیب بھی ایک کلسٹر بنتی ہے۔ پھر ہر کلسٹر کو ایک چوڑائی دی جاتی ہے:
| متن | سیل | وجہ |
|---|---|---|
abc | 3 | ہر کریکٹر کے لیے ایک سیل |
你好 | 4 | مشرقی ایشیائی چوڑے کریکٹرز کے لیے دو سیل |
🚀 | 2 | ایموجی پریزنٹیشن کے لیے دو سیل |
é (e + U+0301) | 1 | کمبائننگ مارکس کے لیے کوئی سیل نہیں |
─│┌▼←⠋ | 6 | باکس ڈرائنگ، جیومیٹرک شکلوں، تیروں اور بریل کے لیے ایک سیل مقرر |
بارڈرز، ▼ کے نشان، تیروں اور اسپنر فریمز کو ہمیشہ ایک سیل ناپا جاتا ہے، اس لیے باکس کا بارڈر کبھی اس کے مواد کو لائن سے باہر نہیں دھکیلتا۔
پرنٹ ایبل ASCII کی سیگمنٹیشن نہیں ہوتی، اور دوسری چوڑائیاں ہر کوڈ پوائنٹ اور ہر کلسٹر کے لیے کیش ہوتی ہیں۔
ریپنگ
<Text> ایک wrap موڈ لیتا ہے:
wrap(ڈیفالٹ) اسپیس پر لائن توڑتا ہے، اور جب لفظ لائن سے چوڑا ہو تو لفظ کے اندر بھی۔nowrapایک لائن برقرار رکھتا ہے اور باکس کو اسے کلپ کرنے دیتا ہے۔truncate-end،truncate-middleاورtruncate-startایک لائن برقرار رکھتے ہیں اور جو حصہ نہ سمائے اسے…سے بدل دیتے ہیں۔
ٹرنکیشن بھی سیل گنتی ہے، اس لیے چینی متن کی لائن کریکٹر کی حد پر کاٹی جاتی ہے، اور ایلیپسس ٹھیک ایک سیل لیتا ہے۔
عملی استعمال
یہاں 30 کالم کا سائیڈ بار ایک ایسے پینل کے ساتھ ہے جو باقی چوڑائی لیتا ہے:
<Box flexDirection="row" width="100%" height="100%"> <Box width={30} flexDirection="column" border="rounded" title="Sessions" overflow="hidden"> <Text wrap="truncate-end">session-03 · refactor the renderer pipeline</Text> </Box> <Box flexGrow={1} flexDirection="column" border="single" title="Conversation" paddingX={1}> <Text>Message 0: 你好 🚀</Text> </Box></Box>100 کالم کے کونسول میں سائیڈ بار اپنے بارڈر سمیت 30 کالم لیتا ہے، اور گفتگو کا پینل باقی 70 لیتا ہے۔ بارڈر ہر طرف ایک سیل کا ہوتا ہے، اس لیے سیشن کا عنوان 28 سیلز پر مختصر ہو جاتا ہے۔