इस पेज का अनुवाद मशीन द्वारा किया गया है और इसमें त्रुटियाँ हो सकती हैं। मूल अंग्रेज़ी पढ़ें

एलिमेंट

Resizable

एक resizable group पैनलों को अगल-बगल या ऊपर-नीचे रखता है, और दो पैनलों के बीच की हर सीमा पर एक हैंडल देता है: दस्तावेज़ के बगल में साइडबार, कंसोल के ऊपर एडिटर, डिटेल के बगल में सूची। उपयोगकर्ता हैंडल को खींचकर सीमा को सरकाता है, और हर पैनल उन आकारों के भीतर रहता है जिनकी ऐप उसे अनुमति देती है। ResizablePanelGroup व्यवहार को संभालता है: ड्रैग, जो फ़्रेम-दर-फ़्रेम नेटिव रूप से चलता है, जगह का बँटवारा, resize कर्सर और उंगली के लिए बड़ा टच क्षेत्र। रूप-रंग ऐप का है: हैंडल एक बैंड है जिसकी अपनी कोई रेखा, रंग या ग्रिप नहीं होती, और वह जो कुछ बनाता है वह ऐप का इंडिकेटर है; पैनल ऐप के व्यू हैं।

el-resizable.tsx
el-resizable.tsxLive
import { mount, signal, Text, View } from "nsh";
import { ResizablePanel, ResizablePanelGroup } from "nsh/base";
import { desktop, Log, Panel, Segmented, Split, ui, wide } from "./palette";

// The sizes are the app's: the group reports them when a drag ends, and the
// app passes them back as each panel's `size`.
function App() {
  const sidebar = signal(desktop ? 220 : 140);
  const consoleSize = signal(120);
  const showConsole = signal<"Shown" | "Hidden">("Shown");
  const events = signal<string[]>([]);
  const log = (line: string) => events.set([line, ...events()].slice(0, 4));
  const round = (sizes: number[]) => sizes.map((s) => Math.round(s)).join(" · ");

  // The handles' look: a hairline that lights up under the pointer and while dragged.
  const handle = "bg-border group-hover:bg-muted-foreground group-active:bg-primary";

  const label = (title: string, detail: string) => (
    <View style={{ gap: 4 }}>
      <Text style={{ fontSize: 13, fontWeight: "600", color: ui().text }}>{title}</Text>
      <Text style={{ fontSize: 12, color: ui().muted }}>{detail}</Text>
    </View>
  );

  return (
    <View style={{ flex: 1, backgroundColor: ui().page, padding: 20, paddingTop: 24, gap: 14 }}>
      <Text style={{ fontSize: 22, fontWeight: "700", color: ui().text }}>resizable</Text>
      <Text style={{ color: ui().muted }}>
        {desktop ? "Drag a line between two panels" : "Drag a line between two panels with your finger"}
      </Text>

      <Split
        grow
        width={640}
        inspector={
          <>
            <Panel title="sizes">
              <Text style={{ fontSize: 13, fontVariant: ["tabular-nums"], color: ui().text }}>
                {`sidebar ${Math.round(sidebar())} · console ${Math.round(consoleSize())}`}
              </Text>
            </Panel>
            <Segmented label="console" options={["Shown", "Hidden"] as const} value={showConsole()} onChange={(v) => showConsole.set(v)} />
            <Log title="onResize" lines={events()} minHeight={96} />
          </>
        }
      >
        <View style={{ height: wide() ? 360 : 300, ...ui().card, borderRadius: 14, overflow: "hidden" }}>
          <ResizablePanelGroup
            axis="horizontal"
            handleClass={handle}
            handleAccessibilityLabel="Resize the sidebar"
            onResize={({ sizes }) => log(`row: ${round(sizes)}`)}
          >
            <ResizablePanel size={sidebar()} minSize={100} maxSize={320} onResize={({ size }) => sidebar.set(size)}>
              <View style={{ flex: 1, padding: 14, gap: 10, backgroundColor: ui().inset.backgroundColor }}>
                {label("Files", `${Math.round(sidebar())} pt, 100 to 320`)}
              </View>
            </ResizablePanel>
            <ResizablePanel minSize={120}>
              <ResizablePanelGroup
                axis="vertical"
                handleClass={handle}
                handleAccessibilityLabel="Resize the console"
                onResize={({ sizes }) => log(`column: ${round(sizes)}`)}
              >
                <ResizablePanel minSize={80}>
                  <View style={{ flex: 1, padding: 14 }}>{label("Editor", "Takes the room left")}</View>
                </ResizablePanel>
                <ResizablePanel
                  size={consoleSize()}
                  minSize={60}
                  fixed
                  visible={showConsole() === "Shown"}
                  onResize={({ size }) => consoleSize.set(size)}
                >
                  <View style={{ flex: 1, padding: 14 }}>{label("Console", "Fixed: keeps its height")}</View>
                </ResizablePanel>
              </ResizablePanelGroup>
            </ResizablePanel>
          </ResizablePanelGroup>
        </View>
      </Split>
    </View>
  );
}

mount(App);
use nsh_base::{h_resizable, resizable_panel, theme};
use nsh_core::prelude::*;

fn workspace() -> impl IntoElement {
    h_resizable()
        .handle_style(|s| s.bg(move || theme().border()))
        .handle_accessibility_label("Resize the sidebar")
        .on_resize(|sizes: &Vec<Points>| log::info!("sizes: {sizes:?}"))
        .child(
            resizable_panel()
                .size(px(240.0))
                .size_range(px(160.0)..px(480.0))
                .p_4()
                .child(text("Files").text_color(move || theme().muted_foreground())),
        )
        .child(
            resizable_panel()
                .p_4()
                .child(text("Editor").text_color(move || theme().foreground())),
        )
}

ResizablePanelGroup और ResizablePanel nsh/base से आते हैं, जो Rust में nsh-base crate है। पैनल ग्रुप के सीधे चाइल्ड होते हैं। Rust में h_resizable() और v_resizable() हर अक्ष पर एक ग्रुप बनाते हैं (resizable_panel_group().axis(..) अक्ष को मान के रूप में लेता है) और resizable_panel() एक पैनल बनाता है, जिसमें हर prop के लिए एक setter, हर इवेंट के लिए एक listener, टाइप्ड स्टाइल मेथड और उनकी सामग्री के लिए .child(..) होता है; .size_range(min..max) दोनों सीमाएँ एक साथ सेट करता है।

#आकार

पैनल का size वह आकार है जो वह चाहता है, उसके minSize और maxSize के भीतर। जिन पैनलों में यह नहीं होता वे बची हुई जगह को बराबर बाँटते हैं, उनकी सामग्री चाहे जो हो; जब हर पैनल का आकार तय होता है, तो बची हुई जगह उन्हीं के अनुपात में बाँटी जाती है। जब उपयोगकर्ता किसी हैंडल को खींचता है, तो ग्रुप कोर में ही पैनलों के बीच जगह को खिसकाता है, बीच में JS के बिना:

  • हैंडल से पहले वाले पैनल को बढ़ाने पर जगह उसके बाद वाले पैनलों से ली जाती है, सबसे नज़दीकी से शुरू करके, हर एक को उसके minSize तक घटाते हुए, और fixed पैनलों को छोड़ते हुए।
  • उसे उसके minSize से नीचे घटाने पर जगह उससे पहले वाले पैनलों से ली जाती है।
  • कोई भी पैनल अपने maxSize से ज़्यादा नहीं बढ़ता, और पैनलों का योग कभी ग्रुप से अधिक नहीं होता।

जब कोई ड्रैग आकार बदलकर खत्म होता है, तो ग्रुप हर दिखाई देने वाले पैनल का आकार बताता है, उसी क्रम में जिसमें वे लेआउट में हैं (ग्रुप पर onResize), और जिस पैनल का आकार बदला वह अपना आकार बताता है (पैनल पर onResize)। ड्रैग से हिले पैनल उपयोगकर्ता के आकार तब तक रखते हैं जब तक ऐप नया size नहीं देती; ऐप रिपोर्ट किए गए आकारों को size के रूप में वापस देकर उन्हें ग्रुप के जीवनकाल के बाद भी बनाए रखती है, ताकि स्टोरेज से बहाल किया गया लेआउट उसी आकार में खुले जिसमें उपयोगकर्ता ने उसे छोड़ा था। केवल ड्रैग और स्क्रीन रीडर के स्टेप रिपोर्ट करते हैं: विंडो का आकार बदलना या किसी पैनल को दिखाना या छिपाना कुछ रिपोर्ट नहीं करता।

जब ग्रुप बढ़ता या घटता है (विंडो का आकार बदलने पर), तो आकार वाले पैनल उसे बनाए रखते हैं और बिना आकार वाले पैनल अंतर को ले लेते हैं। जब ग्रुप आकारों के लिए बहुत छोटा हो, तो पैनल सिकुड़ते हैं, fixed पैनलों (साइडबार, इंस्पेक्टर) को छोड़कर, और जगह लौटने पर वे अपने आकार पर वापस आ जाते हैं। visible={false} वाला पैनल कोई जगह नहीं लेता: बाकी उसकी जगह बाँट लेते हैं, और दोबारा दिखाए जाने पर वह अपने आकार में लौट आता है।

<ResizablePanelGroup axis="vertical" handleClass="bg-border">
  <ResizablePanel>
    <Editor />
  </ResizablePanel>
  <ResizablePanel size={180} minSize={120} fixed visible={consoleOpen()}>
    <Console />
  </ResizablePanel>
</ResizablePanelGroup>

#हैंडल

हर दो दिखाई देने वाले पैनलों के बीच की सीमा पर एक हैंडल होता है: अक्ष के आर-पार 9 पॉइंट मोटा एक बैंड, जो सीमा पर केंद्रित होता है, और जिस पर उसके अक्ष का resize कर्सर दिखता है। टच स्क्रीन पर इसका टच क्षेत्र दोनों ओर 10 पॉइंट और आगे तक जाता है, ताकि एक पॉइंट की रेखा भी आसानी से पकड़ी जा सके। हैंडल एक group है: वह जो कुछ बनाता है वह ऐप का इंडिकेटर है, जिसे handleClass / handleStyle से स्टाइल किया जाता है: आर-पार 1 पॉइंट और सीमा की पूरी लंबाई, इसलिए अकेला bg-border किसी भी अक्ष पर बाल जैसी पतली रेखा है, और w-[3px] या h-[3px] उसे मोटा करता है, और उसकी group-hover: और group-active: क्लासें बैंड के ऊपर पॉइंटर और प्रेस या ड्रैग का अनुसरण करती हैं। केवल एक रेखा से अधिक के लिए (बिंदुओं की ग्रिप, एक आइकन), renderHandle इंडिकेटर की सामग्री बनाता है, जिसे हैंडल का index, axis और state बताया जाता है; स्थिति बदलने पर यह दोबारा बनता है, प्रति ड्रैग कुछ ही बार, हर मूवमेंट पर कभी नहीं। एनिमेट होने वाली ग्रिप हैंडल का थंब है (handleThumbClass / handleThumbStyle): रेखा पर केंद्रित एक व्यू, जो सीधा बनता है और क्षैतिज रेखा पर एक चौथाई घुमा दिया जाता है ताकि एक ही क्लास दोनों अक्षों के लिए काम करे, जिसे group-hover: और group-active: क्लासें दिखाती और ट्रांज़िशन करती हैं; पूरे ड्रैग के दौरान हैंडल दबा रहता है, पॉइंटर कहीं भी जाए।

<ResizablePanelGroup
  handleClass="w-[3px] items-center justify-center bg-border"
  renderHandle={(handle) => (
    <View class={handle.state === "dragging" ? "h-8 w-1 rounded-full bg-primary" : "h-6 w-1 rounded-full bg-muted-foreground"} />
  )}
>
  {/* panels */}
</ResizablePanelGroup>

disabled हर हैंडल को उसकी जगह पर रखता है (लॉक किया हुआ लेआउट)।

#Props

#ResizablePanelGroup

PropRustटाइपडिफ़ॉल्टविवरण
axish_resizable(), v_resizable(), .axis(..)"horizontal" | "vertical""horizontal"अगल-बगल (हैंडल बाएँ-दाएँ खींचे जाते हैं) या ऊपर-नीचे (ऊपर-नीचे खींचे जाते हैं)।
disabled.disabled(..)booleanfalseकोई ड्रैग नहीं: हैंडल अपनी जगह पर रहते हैं।
handleClass, handleStyle.handle_style(|s| ..)string, StyleProp<ViewStyle>कोई नहींहर हैंडल का इंडिकेटर, सीमा पर हैंडल के बैंड में: अक्ष के आर-पार 1 पॉइंट और सीमा की पूरी लंबाई, जब तक वह कुछ और न कहे (w-[3px], h-[3px]); group-hover: और group-active: बैंड का अनुसरण करते हैं।
handleThumbClass, handleThumbStyle.handle_thumb_class(..), .handle_thumb_style(|s| ..)string, StyleProp<ViewStyle>कोई नहींहर हैंडल का थंब: रेखा पर केंद्रित एक ग्रिप, जो ऊर्ध्वाधर रेखा की तरह सीधी बनती है और क्षैतिज रेखा पर एक चौथाई घुमा दी जाती है, ताकि एक ही क्लास दोनों अक्षों के लिए काम करे। हैंडल के होवर, प्रेस और ड्रैग के दौरान यह वही व्यू बना रहता है, इसलिए group-hover: और group-active: क्लासें इसे ट्रांज़िशन करती हैं (h-11 w-[3px] rounded-full bg-muted-foreground opacity-0 scale-y-0 transition group-hover:opacity-40 group-hover:scale-y-[0.45] group-active:opacity-90 group-active:scale-y-100)।
renderHandle.render_handle(|handle| ..)(handle: ResizeHandleContext) => JSX.Elementकोई नहींहर इंडिकेटर के अंदर क्या है, जो हैंडल का state बदलने पर दोबारा बनता है।
handleAccessibilityLabel.handle_accessibility_label(..)stringकोई नहींस्क्रीन रीडर हर हैंडल के लिए क्या बोलते हैं: वह क्या resize करता है। वे इसे एक बार में 10 पॉइंट समायोजित करते हैं।
children.child(..)JSX.Elementकोई नहींResizablePanel, इसके सीधे चाइल्ड।
class, styleस्टाइल मेथडstring, StyleProp<ViewStyle>size-fullग्रुप स्वयं; यह अपने पैरेंट को भरता है, जब तक उसकी क्लास कुछ और न कहे।

#ResizablePanel

PropRustटाइपडिफ़ॉल्टविवरण
size.size(..)numberकोई नहींग्रुप के अक्ष के अनुदिश वह लंबाई जो यह चाहता है, पॉइंट में, minSize और maxSize के भीतर; नया मान इसका आकार बदल देता है। इसके बिना यह बची हुई जगह बाँटता है।
minSize.min_size(..), .size_range(..)number100सबसे छोटा आकार जो यह पा सकता है।
maxSize.max_size(..), .size_range(..)numberकोई सीमा नहींसबसे बड़ा आकार जो यह पा सकता है।
fixed.fixed(..)booleanfalseग्रुप के पैनलों के लिए बहुत छोटा होने पर अपना आकार बनाए रखता है; अपने हैंडल को खींचने पर यह फिर भी resize होता है। यह एक size लेता है।
visible.visible(..)booleantrueछिपा होने पर यह कोई जगह नहीं लेता और बाकी इसकी जगह बाँट लेते हैं।
children.child(..)JSX.Elementकोई नहींइसकी सामग्री।
class, styleस्टाइल मेथडstring, StyleProp<ViewStyle>कोई नहींपैनल की अपनी सतह। अक्ष के अनुदिश इसका आकार ग्रुप तय करता है।

#ResizeHandleContext

फ़ील्डटाइपविवरण
indexnumberindexवें दिखाई देने वाले पैनल के बाद की सीमा।
axis"horizontal" | "vertical"वह अक्ष जिसके अनुदिश यह resize करता है।
state"idle" | "hovered" | "pressed" | "dragging"पॉइंटर या उंगली इसके साथ कितनी दूर गई है।

#इवेंट

इवेंटRustविवरण
onResize (ResizablePanelGroup).on_resize(|sizes: &Vec<Points>| ..)कोई ड्रैग खत्म हुआ और उसने किसी हैंडल को हिलाया, या किसी स्क्रीन रीडर ने उसे समायोजित किया: sizes, हर दिखाई देने वाले पैनल का आकार, उसी क्रम में जिसमें वे लेआउट में हैं (बाएँ से दाएँ, ऊपर से नीचे)।
onResize (ResizablePanel).on_resize(|size: &Points| ..)कोई ड्रैग खत्म हुआ और उसने इस पैनल का आकार बदला: size, नया आकार, जिसे इसके size के रूप में वापस देना है।

#पार्ट्स

पार्टअंदरस्टाइलस्टेट
ग्रुपResizablePanelGroup का class, style
पैनलग्रुपResizablePanel का class, style
हैंडल का इंडिकेटरहैंडल का बैंड, किसी सीमा परhandleClass, handleStyle, renderHandleपॉइंटर के नीचे group-hover:, दबे रहने या ड्रैग के दौरान group-active:; renderHandle में state
हैंडल का थंबहैंडल की रेखा पर केंद्रितhandleThumbClass, handleThumbStylegroup-hover:, group-active: (ड्रैग खत्म होने तक दबा हुआ)

#सुगम्यता

  • स्क्रीन रीडर के लिए हर हैंडल एक समायोज्य एलिमेंट है, जिसका लेबल handleAccessibilityLabel है। इसका मान उससे पहले वाले पैनल का आकार है, उस पैनल के minSize और maxSize के भीतर।
  • VoiceOver में हैंडल पर ऊपर या नीचे स्वाइप करना, या TalkBack की वॉल्यूम कुंजियाँ, उसे 10 पॉइंट हिलाती हैं, ठीक ड्रैग की तरह; ग्रुप इसे onResize के साथ रिपोर्ट करता है। disabled ग्रुप के हैंडल अपनी जगह पर रहते हैं।
  • पैनलों की सामग्री ऐप की है और उसे वैसे ही पढ़ा जाता है जैसे कहीं और।

लेबल, रोल और घोषणाओं के सामान्य विवरण के लिए Accessibility देखें।

#प्लेटफ़ॉर्म नोट्स

  • डेस्कटॉप (macOS, Windows, Linux, GPUI) और वेब: हैंडल के ऊपर पॉइंटर कॉलम या रो का resize कर्सर दिखाता है, और माउस या टचपैड से ड्रैग सीमा को हिलाता है।
  • iOS, Android और Mac Catalyst: उंगली हैंडल को खींचती है, ऐसे टच क्षेत्र के भीतर जो बैंड से दोनों ओर 10 पॉइंट चौड़ा है।
  • दाएँ-से-बाएँ लेआउट में पैनल और उनके आकार लेआउट के क्रम का पालन करते हैं।
  • हर प्लेटफ़ॉर्म वही बनाता है जो ऐप स्टाइल करती है: इंडिकेटर और पैनल।
  • Dock के स्प्लिट resizable ग्रुप हैं: उनका आकार उसी तरह बदला जाता है।