Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#69 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
10/100
issue の種類
機能追加
明瞭さ
おおむね明確
活発さ
活発
技術スタック
react, typescript

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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.
主要言語
TypeScript
スター
2
フォーク
0
平均マージ
1日 16時間
マージ済み PR(30日)
34

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

lablup/ui-common のほかの issue

lablup/ui-common の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。