Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Form: let Form.Item own label, extra and messages for every form control

Đang mở
#69 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
10/100
Loại issue
Tính năng
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
react, typescript
Lĩnh vực
accessibility, frontend

Hướng nghiên cứu

Start with how Form.Item clones props onto its child and where FormItemInputContext is published, then check one shadowed control such as TextInput and the exports.exclude.json mapping used for Dialog to Modal. Read Form.acceptance.test.tsx, which currently uses a plain <input>, to see what acceptance coverage must add. Done means a Form.Item with a failing rule shows one label linked by htmlFor, a red border with one message, and disabled state from <Form disabled>, across every shadowed control.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Problem

Every Astryx form control we re-export (TextInput, TextArea, NumberInput, Switch, CheckboxInput, CheckboxList, RadioList, Selector, MultiSelector, Typeahead, Date/Time inputs, Slider, FileInput, Tokenizer, the ComplexSelector fork) requires its own label and renders its own label, description and status message. Form.Item renders the same things. Inside a Form.Item the control and the item compete, so backend.ai-webui wraps each control in an adapter instead of using it directly:

  • react/src/components/astryxFormControls.tsx: 10 adapters, ~320 call sites. A second, drifted copy lives in packages/backend.ai-ui/src/components/astryxFormControls.tsx.
  • BAISelect, BAICheckbox, BAIUncontrolledInput, BAIDynamicUnitInputNumber, InputNumberWithSlider, plus about 10 one-off local adapters in feature files.
  • ~218 call sites pass the same string to Form.Item label and to the control's label with isLabelHidden. Our own stories and README teach the same pattern (<Form.Item label="Name"><TextInput label="Name" isLabelHidden /></Form.Item>).

What the adapters work around, all of which belong in ui-common:

  1. Label. label: string is required and rendered, so callers duplicate it and hide one copy.
  2. Status never reaches the control. Form.Item publishes FormItemInputContext, but no ui-common component reads it. A failed rule shows the message and leaves the border neutral. README:394 and Form.doc.mjs:105 say controls read it, which nothing does. The webui host adapters read the context and pass { type } with no message and statusVariant="detached", so the result is a red border only. The BUI copy, BAISelect and the local adapters don't, so they have no red border.
  3. Injected props are dropped. Form.Item clones id, disabled, aria-describedby, aria-invalid and aria-required onto the child. Astryx 0.7.0:
    • Selector, MultiSelector, Switch, CheckboxInput and RadioList ignore id, so the item's <label htmlFor> points at nothing.
    • Every control reads isDisabled, not disabled, so <Form disabled> does nothing.
    • aria-invalid follows status only.
  4. Value shape. value is required and non-nullable, so every call site writes ?? '', ?? false or ?? []. Value-first onChange already works with defaultGetValueFromEvent.
  5. Own components.
    • StepNumberInput and ColorPicker have no status.
    • StepNumberInput requires label.
    • UncontrolledInput has no value/onChange pair.
    • BulkEditFormItem passes a placeholder label plus isLabelHidden.

Proposal: match antd's contract

In antd, the item owns the label, extra, help and messages, and injects value/onChange/id. The control reads FormItemInputContext and paints only its border. Apply the same contract to every control that can sit in a Form.Item.

  • Shadow the form controls with ui-common wrappers under the same names, through exports.exclude.json like Dialog→Modal.
  • Don't expose field-chrome props: label, isLabelHidden, description, labelTooltip, labelIcon, isRequired/isOptional, statusVariant, and status.message. They go to Form.Item (label, tooltip, labelExtra, extra, help, required). Outside a form, the accessible name comes from aria-label or aria-labelledby.
  • Status:
    • Read FormItemInputContext when the control sits in a Form.Item.
    • Also accept an antd-style status prop: 'error' | 'warning' | ''.
    • Map it to { type } with no message and a stable statusVariant. Making statusVariant conditional remounts the input and loses focus, as webui learned.
    • validating and success map to no border.
  • Honour injected id, disabled and aria-*. Upstream the id fix where Astryx drops it.
  • Make value optional: undefined means empty.
  • Bring own form components in line: StepNumberInput, ColorPicker, PagedSelector, ComplexSelector fork and UncontrolledInput.
  • Fix docs and stories: the README and Form.doc.mjs examples, and every story using isLabelHidden inside Form.Item.

Decisions needed

  • Checkbox and Switch inline text. It is not the field label; antd uses children. Decide whether to keep it as children or as a renamed prop.

  • Out of scope here, but they keep webui adapters alive:

    • antd prop aliases: allowClear, loading, size.
    • NumberInput clamp on blur.
    • IME Enter guard.
    • tokenSeparators.
    • Selector popup placement.

    Decide whether to add them to ui-common or leave them in the app.

  • Breaking change for 0.2 consumers: needs an upgrade codemod. It should move the control's label/description to the enclosing Form.Item and drop isLabelHidden.

Done when

  • <Form.Item label="Name" name="name" rules={[{ required: true }]}><TextInput /></Form.Item> works with no adapter:
    • one label, linked by htmlFor;
    • a red border and a single message on error;
    • disabled by <Form disabled>.
  • The same holds for every shadowed control.
  • Form.acceptance.test.tsx covers these with real Astryx controls; today it deliberately uses a plain <input>.
  • webui can delete astryxFormControls.tsx (both copies) and the status bridging in BAISelect and BAICheckbox.
Ngôn ngữ chính
TypeScript
Star
2
Fork
0
Merge trung bình
1 ngày 17 giờ
Pull request đã merge (30 ngày)
32

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của lablup/ui-common

Tất cả issue của lablup/ui-common

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.