组合示例

组合示例

工具栏、带校验表单与危险操作确认。

三个真实组合展示如何使用同一套组件完成工具栏切换、带校验表单和危险操作确认。

工具栏以激活状态表达当前视图,图标按钮提供清晰名称。表单使用字段 label、必填规则和保留输入的失败反馈。危险确认使用 L2、取消焦点以及输入/勾选门槛,提交等待时不重复执行。

全部数据和回调在示例 iframe 内,不触发 Git、SSH 或业务后端。下方运行代码就是可以复制的 TSX 文件,Provider 与样式由预览宿主提供。

运行示例

运行与复制源码来自同一 TSX 文件。浮层、状态和主题独立于文档;所有回调只更新本地模拟数据。

真实示例 TSX 独立预览 ↗
查看运行源码
源码文件
import { useState } from 'react';
import { ToolbarButton, StatusButton, CommandButton, DialogIcon, Space } from '@alune/ui';

export default function Example() {
  const [active, setActive] = useState('files');
  const [count, setCount] = useState(0);
  return (
    <div className="example">
      <section className="example-group">
        <h2 className="example-title">视图切换</h2>
        <Space wrap size="middle">
          <ToolbarButton
            label="文件"
            active={active === 'files'}
            onClick={() => setActive('files')}
          >
            <DialogIcon name="folder" />
            文件
          </ToolbarButton>
          <ToolbarButton
            label="历史"
            active={active === 'history'}
            onClick={() => setActive('history')}
          >
            <DialogIcon name="clock" />
            历史
          </ToolbarButton>
        </Space>
      </section>
      <section className="example-group">
        <h2 className="example-title">操作与连接状态</h2>
        <Space wrap size="middle">
          <ToolbarButton
            label="拉取"
            variant="action"
            text="拉取"
            count={2}
            countTone="behind"
            onClick={() => setCount((n) => n + 1)}
          >
            <DialogIcon name="cloud-down" />
          </ToolbarButton>
          <ToolbarButton
            label="运行示例"
            variant="primary"
            text="运行"
            count={count || undefined}
            onClick={() => setCount((n) => n + 1)}
          />
          <ToolbarButton label="不可用操作" variant="action" disabled>
            不可用
          </ToolbarButton>
          <StatusButton label="状态" active>
            已连接
          </StatusButton>
          <CommandButton label="刷新示例" onClick={() => setCount((n) => n + 1)}>
            <DialogIcon name="refresh" />
          </CommandButton>
        </Space>
      </section>
      <p className="example-status" role="status">
        当前:{active} · 操作次数:{count}
      </p>
    </div>
  );
}
真实示例 TSX 独立预览 ↗
查看运行源码
源码文件
import { useState } from 'react';
import { Form, Input, Button, Switch } from '@alune/ui';

export default function Example() {
  const [failure, setFailure] = useState(false);
  const [result, setResult] = useState('');
  const [busy, setBusy] = useState(false);
  return (
    <div className="example example--narrow">
      <label className="example-row">
        <Switch aria-label="模拟提交失败" checked={failure} onChange={setFailure} /> 模拟失败
      </label>
      <Form
        layout="vertical"
        disabled={busy}
        onFinish={async (values) => {
          if (busy) return;
          setBusy(true);
          setResult('正在保存…');
          await new Promise((resolve) => setTimeout(resolve, 600));
          setResult(failure ? '保存失败,请保留输入并重试。' : `已保存:${values.name}`);
          setBusy(false);
        }}
      >
        <Form.Item
          name="name"
          label="配置名称"
          rules={[{ required: true, message: '请填写配置名称' }]}
          extra="名称仅在此示例中使用"
        >
          <Input />
        </Form.Item>
        <Form.Item name="description" label="说明">
          <Input.TextArea />
        </Form.Item>
        <Button type="primary" htmlType="submit" loading={busy}>
          保存配置
        </Button>
      </Form>
      <p className="example-status" role="status">
        {result}
      </p>
    </div>
  );
}
真实示例 TSX 独立预览 ↗
查看运行源码
源码文件
import { useState } from 'react';
import { AluneModal, Button, Input, Radio, Switch, DialogNote } from '@alune/ui';

export default function Example() {
  const [open, setOpen] = useState(false);
  const [level, setLevel] = useState<0 | 1 | 2>(0);
  const [failure, setFailure] = useState(false);
  const [error, setError] = useState('');
  const [result, setResult] = useState('');
  return (
    <div className="example example--narrow">
      <h2 className="example-title">风险等级与提交状态</h2>
      <Radio.Group
        aria-label="风险等级"
        value={level}
        onChange={(e) => setLevel(e.target.value)}
        options={[0, 1, 2].map((value) => ({ value, label: `L${value}` }))}
      />
      <label className="example-row">
        <Switch aria-label="模拟异步失败" checked={failure} onChange={setFailure} /> 模拟异步失败
      </label>
      <div className="example-row">
        <Button
          onClick={() => {
            setError('');
            setOpen(true);
          }}
        >
          打开弹窗
        </Button>
      </div>
      <p className="example-status" role="status">
        {result}
      </p>
      <AluneModal
        open={open}
        title={level === 2 ? '放弃示例更改?' : '保存示例配置'}
        level={level}
        size="md"
        okText={level === 2 ? '放弃更改' : '保存配置'}
        description="只操作本地模拟状态。"
        typedConfirm={level === 2 ? { value: 'main', label: '输入 main 确认' } : undefined}
        acknowledge={level === 2 ? '我了解此操作无法撤销' : undefined}
        onCancel={() => setOpen(false)}
        onOk={async () => {
          await new Promise((resolve) => setTimeout(resolve, 600));
          if (failure) {
            setError('保存失败,输入已保留。');
            throw new Error('模拟失败');
          }
          setResult('操作已完成');
          setOpen(false);
        }}
      >
        <Input aria-label="配置名称" defaultValue="示例配置" />
        {error && (
          <DialogNote tone="danger" title="提交失败">
            {error}
          </DialogNote>
        )}
      </AluneModal>
    </div>
  );
}