@agentero/design-system 0.27.1 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -1
- package/lib/merge-props.d.ts +42 -0
- package/lib/merge-props.js +24 -0
- package/mcp/manifests/components.html +1258 -71
- package/mcp/manifests/components.json +1033 -9
- package/package.json +22 -1
- package/src/alert/alert.js +28 -28
- package/src/avatar/avatar.js +22 -22
- package/src/avatar-group/avatar-group.js +6 -6
- package/src/button/button.js +7 -7
- package/src/data-table/data-table.js +36 -36
- package/src/field/context.d.ts +70 -0
- package/src/field/context.js +6 -0
- package/src/field/field.d.ts +216 -0
- package/src/field/field.js +132 -0
- package/src/field/icons.d.ts +9 -0
- package/src/field/icons.js +14 -0
- package/src/field/index.d.ts +30 -0
- package/src/field/index.js +13 -0
- package/src/field-text/field-text.d.ts +28 -0
- package/src/field-text/field-text.js +26 -0
- package/src/field-text/index.d.ts +2 -0
- package/src/field-text/index.js +2 -0
- package/src/form/form.d.ts +60 -0
- package/src/form/form.js +16 -0
- package/src/form/index.d.ts +7 -0
- package/src/form/index.js +5 -0
- package/src/form-text/form-text.d.ts +136 -0
- package/src/form-text/form-text.js +40 -0
- package/src/form-text/index.d.ts +2 -0
- package/src/form-text/index.js +2 -0
- package/src/input/context.d.ts +17 -0
- package/src/input/context.js +10 -0
- package/src/input/index.d.ts +1 -0
- package/src/input/index.js +3 -2
- package/src/input/input.d.ts +7 -7
- package/src/input/input.js +16 -11
- package/src/label/context.d.ts +13 -0
- package/src/label/context.js +7 -0
- package/src/label/index.d.ts +1 -0
- package/src/label/index.js +3 -2
- package/src/label/label.d.ts +6 -1
- package/src/label/label.js +19 -17
- package/src/modal/modal.js +23 -23
- package/src/progress/progress.js +9 -9
- package/src/switch/switch.js +7 -7
- package/src/table/table.js +28 -28
- package/src/tabs/tabs.js +26 -26
- package/src/tag/tag.js +7 -7
|
@@ -588,13 +588,13 @@
|
|
|
588
588
|
<header>
|
|
589
589
|
<div class="wrap">
|
|
590
590
|
<h1>Manifest Debugger</h1>
|
|
591
|
-
<div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">
|
|
591
|
+
<div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">31 components ok</span><span class="filter-pill ok" aria-disabled="true">250 stories ok</span></div>
|
|
592
592
|
</div>
|
|
593
593
|
</header>
|
|
594
594
|
<main>
|
|
595
595
|
<div class="wrap">
|
|
596
596
|
<div class="note ok" style="margin-bottom: 16px;">
|
|
597
|
-
Using <code>react-component-meta</code>. Generation took <strong>4.
|
|
597
|
+
Using <code>react-component-meta</code>. Generation took <strong>4.3s</strong>.
|
|
598
598
|
</div>
|
|
599
599
|
<h2 class="section-title">Components</h2>
|
|
600
600
|
<div class="grid" role="list">
|
|
@@ -4487,6 +4487,1170 @@ actions outright unless the user needs to see them and understand why.</div>
|
|
|
4487
4487
|
</div>
|
|
4488
4488
|
|
|
4489
4489
|
|
|
4490
|
+
</div>
|
|
4491
|
+
</article>
|
|
4492
|
+
<article
|
|
4493
|
+
class="card
|
|
4494
|
+
no-error
|
|
4495
|
+
no-info
|
|
4496
|
+
no-story-error
|
|
4497
|
+
no-doc-error"
|
|
4498
|
+
role="listitem"
|
|
4499
|
+
aria-label="Field.Root">
|
|
4500
|
+
<div class="head">
|
|
4501
|
+
<div class="title">
|
|
4502
|
+
<h2><span class="status-dot dot-ok"></span> Field.Root</h2>
|
|
4503
|
+
<div class="badges">
|
|
4504
|
+
<label for="c-11-components-field-props" class="badge ok as-toggle">6 prop types</label>
|
|
4505
|
+
|
|
4506
|
+
<label for="c-11-components-field-stories" class="badge ok as-toggle">16 stories</label>
|
|
4507
|
+
|
|
4508
|
+
|
|
4509
|
+
</div>
|
|
4510
|
+
</div>
|
|
4511
|
+
<div class="meta" title="./src/field/field.stories.tsx">components-field · ./src/field/field.stories.tsx</div>
|
|
4512
|
+
<div>Wraps a label, control, description and error into one field</div>
|
|
4513
|
+
<div class="hint">Field lays out a single form field — label, control, helper text and error —
|
|
4514
|
+
and wires the accessibility relationships between them. `Field.Root`
|
|
4515
|
+
generates the ids and shares them through context: `Label` reads
|
|
4516
|
+
`LabelContext`, `Field.Description` and `Field.Error` read `FieldContext`,
|
|
4517
|
+
and a `Field<X>` such as `FieldText` provides the control's context. Nobody
|
|
4518
|
+
passes an `id` by hand.
|
|
4519
|
+
|
|
4520
|
+
Presentational and form-library agnostic: pass `invalid` and the error
|
|
4521
|
+
messages from whatever validates the form. Spacing between fields belongs to
|
|
4522
|
+
`Field.Group`, never to a margin on the field itself.
|
|
4523
|
+
|
|
4524
|
+
`Field.Description` and `Field.Error` register themselves with the root, so
|
|
4525
|
+
the control's `aria-describedby` lists exactly the messages on screen and is
|
|
4526
|
+
absent when there is none.</div>
|
|
4527
|
+
<div class="kv"><span class="chip">summary: Wraps a label, control, description and error into one field</span><span class="chip">example: <Field.Root invalid={!!error} required>
|
|
4528
|
+
<Field.Label>Email</Field.Label>
|
|
4529
|
+
<Input type="email" />
|
|
4530
|
+
<Field.Description>We only use this for policy documents.</Field.Description>
|
|
4531
|
+
<Field.Error errors={[error]} />
|
|
4532
|
+
</Field.Root></span></div>
|
|
4533
|
+
</div>
|
|
4534
|
+
|
|
4535
|
+
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
4536
|
+
|
|
4537
|
+
|
|
4538
|
+
<input id="c-11-components-field-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4539
|
+
|
|
4540
|
+
|
|
4541
|
+
<input id="c-11-components-field-props" class="tg tg-props" type="checkbox" hidden />
|
|
4542
|
+
|
|
4543
|
+
<div class="panels">
|
|
4544
|
+
|
|
4545
|
+
|
|
4546
|
+
|
|
4547
|
+
<div class="panel panel-props">
|
|
4548
|
+
<div class="note ok">
|
|
4549
|
+
<div class="row">
|
|
4550
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
4551
|
+
<span class="badge ok">6 prop types</span>
|
|
4552
|
+
</div>
|
|
4553
|
+
<pre><code>Component: src/field/index.ts::Field</code></pre>
|
|
4554
|
+
<pre><code>Props:</code></pre>
|
|
4555
|
+
<pre><code>/**
|
|
4556
|
+
* `id` for the control. Generated when omitted. Set it here, not on the
|
|
4557
|
+
* control, so the label and the messages keep pointing at the right element.
|
|
4558
|
+
*/
|
|
4559
|
+
controlId?: string
|
|
4560
|
+
|
|
4561
|
+
/**
|
|
4562
|
+
* Disables the control through its context and sets `data-disabled` on the root.
|
|
4563
|
+
*/
|
|
4564
|
+
disabled?: boolean = false
|
|
4565
|
+
|
|
4566
|
+
/**
|
|
4567
|
+
* Marks the field as failing validation: sets `data-invalid` on the root and
|
|
4568
|
+
* `aria-invalid` on the control through its context, which drives the
|
|
4569
|
+
* control's destructive border. The label keeps its color by design.
|
|
4570
|
+
*/
|
|
4571
|
+
invalid?: boolean = false
|
|
4572
|
+
|
|
4573
|
+
/**
|
|
4574
|
+
* Layout of the field. `vertical` (default) stacks label, control and
|
|
4575
|
+
* messages. `horizontal` is one row at every width: the first child fills it
|
|
4576
|
+
* and the rest keep their natural width, aligned to the right, so the
|
|
4577
|
+
* controls of stacked fields line up. `responsive` stacks below `28rem` and
|
|
4578
|
+
* behaves like `horizontal` from there, measured on the field itself, so it
|
|
4579
|
+
* needs no particular wrapper. In both, `Field.Content` groups a control with
|
|
4580
|
+
* its messages, or a label with its description.
|
|
4581
|
+
*/
|
|
4582
|
+
orientation?: "horizontal" | "vertical" | "responsive" = 'vertical'
|
|
4583
|
+
|
|
4584
|
+
/**
|
|
4585
|
+
* Makes the control read-only through its context (focusable and copyable,
|
|
4586
|
+
* not editable, still submitted) and sets `data-readonly` on the root.
|
|
4587
|
+
*/
|
|
4588
|
+
readOnly?: boolean = false
|
|
4589
|
+
|
|
4590
|
+
/**
|
|
4591
|
+
* Single source of truth for a required field: the `Label` shows its
|
|
4592
|
+
* asterisk and the control receives `required`, both through context.
|
|
4593
|
+
*/
|
|
4594
|
+
required?: boolean = false</code></pre>
|
|
4595
|
+
</div>
|
|
4596
|
+
</div>
|
|
4597
|
+
|
|
4598
|
+
<div class="panel panel-stories">
|
|
4599
|
+
|
|
4600
|
+
|
|
4601
|
+
|
|
4602
|
+
<div class="note ok">
|
|
4603
|
+
<div class="row">
|
|
4604
|
+
<span class="ex-name">Imports</span>
|
|
4605
|
+
</div>
|
|
4606
|
+
<pre><code>import { Field, FieldContext, Label } from "@agentero/design-system";</code></pre>
|
|
4607
|
+
</div>
|
|
4608
|
+
|
|
4609
|
+
|
|
4610
|
+
<div class="note ok">
|
|
4611
|
+
<div class="row">
|
|
4612
|
+
<span class="ex-name">Default</span>
|
|
4613
|
+
<span class="badge ok">story ok</span>
|
|
4614
|
+
</div>
|
|
4615
|
+
<div>Default vertical field with label, control and description</div>
|
|
4616
|
+
<div class="hint">A vertical field with a label, a control and helper text. The label points
|
|
4617
|
+
at the control and the description is referenced by it — neither needed an
|
|
4618
|
+
explicit `id`.</div>
|
|
4619
|
+
<pre><code>const Default = () => <Field.Root
|
|
4620
|
+
orientation="vertical"
|
|
4621
|
+
invalid={false}
|
|
4622
|
+
disabled={false}
|
|
4623
|
+
readOnly={false}
|
|
4624
|
+
required={false}>
|
|
4625
|
+
<Label>Email</Label>
|
|
4626
|
+
<DemoInput placeholder="you@example.com" />
|
|
4627
|
+
<Field.Description>We only use this to send policy documents.</Field.Description>
|
|
4628
|
+
</Field.Root>;</code></pre>
|
|
4629
|
+
</div>
|
|
4630
|
+
<div class="note ok">
|
|
4631
|
+
<div class="row">
|
|
4632
|
+
<span class="ex-name">Required</span>
|
|
4633
|
+
<span class="badge ok">story ok</span>
|
|
4634
|
+
</div>
|
|
4635
|
+
<div>Required field driven from the root alone</div>
|
|
4636
|
+
<div class="hint">`required` on the root is the single source of truth: the label shows its
|
|
4637
|
+
asterisk and the control receives `required`, both through context.</div>
|
|
4638
|
+
<pre><code>const Required = () => <Field.Root
|
|
4639
|
+
orientation="vertical"
|
|
4640
|
+
invalid={false}
|
|
4641
|
+
disabled={false}
|
|
4642
|
+
readOnly={false}
|
|
4643
|
+
required>
|
|
4644
|
+
<Label>Full name</Label>
|
|
4645
|
+
<DemoInput placeholder="Jane Doe" />
|
|
4646
|
+
</Field.Root>;</code></pre>
|
|
4647
|
+
</div>
|
|
4648
|
+
<div class="note ok">
|
|
4649
|
+
<div class="row">
|
|
4650
|
+
<span class="ex-name">Optional</span>
|
|
4651
|
+
<span class="badge ok">story ok</span>
|
|
4652
|
+
</div>
|
|
4653
|
+
<div>Optional field with the muted label suffix</div>
|
|
4654
|
+
<div class="hint">`optional` on the label appends the muted suffix; the control stays
|
|
4655
|
+
non-required.</div>
|
|
4656
|
+
<pre><code>const Optional = () => <Field.Root
|
|
4657
|
+
orientation="vertical"
|
|
4658
|
+
invalid={false}
|
|
4659
|
+
disabled={false}
|
|
4660
|
+
readOnly={false}
|
|
4661
|
+
required={false}>
|
|
4662
|
+
<Label optional>Phone number</Label>
|
|
4663
|
+
<DemoInput type="tel" placeholder="+1 (555) 000-0000" />
|
|
4664
|
+
</Field.Root>;</code></pre>
|
|
4665
|
+
</div>
|
|
4666
|
+
<div class="note ok">
|
|
4667
|
+
<div class="row">
|
|
4668
|
+
<span class="ex-name">With Tooltip</span>
|
|
4669
|
+
<span class="badge ok">story ok</span>
|
|
4670
|
+
</div>
|
|
4671
|
+
<div>Label with a tooltip trigger beside it</div>
|
|
4672
|
+
<div class="hint">`Field.Label` puts an info button beside the caption. It is a sibling of the
|
|
4673
|
+
`<label>`, so it keeps its own accessible name, clicking it does not focus
|
|
4674
|
+
the control, and the control's name stays clean. It opens on focus too.</div>
|
|
4675
|
+
<pre><code>const WithTooltip = () => <Field.Root
|
|
4676
|
+
orientation="vertical"
|
|
4677
|
+
invalid={false}
|
|
4678
|
+
disabled={false}
|
|
4679
|
+
readOnly={false}
|
|
4680
|
+
required>
|
|
4681
|
+
<Field.Label tooltip="Issued by the IRS to identify your business.">Tax ID</Field.Label>
|
|
4682
|
+
<DemoInput placeholder="XX-XXXXXXX" />
|
|
4683
|
+
</Field.Root>;</code></pre>
|
|
4684
|
+
</div>
|
|
4685
|
+
<div class="note ok">
|
|
4686
|
+
<div class="row">
|
|
4687
|
+
<span class="ex-name">Invalid</span>
|
|
4688
|
+
<span class="badge ok">story ok</span>
|
|
4689
|
+
</div>
|
|
4690
|
+
<div>Invalid field with a single error message</div>
|
|
4691
|
+
<div class="hint">`invalid` on the root sets `data-invalid` for styling and `aria-invalid` on
|
|
4692
|
+
the control, which drives its destructive border; the label keeps its color
|
|
4693
|
+
by design. `Field.Error` takes the error objects as they come from a form
|
|
4694
|
+
library.</div>
|
|
4695
|
+
<pre><code>const Invalid = () => <Field.Root
|
|
4696
|
+
orientation="vertical"
|
|
4697
|
+
invalid
|
|
4698
|
+
disabled={false}
|
|
4699
|
+
readOnly={false}
|
|
4700
|
+
required={false}>
|
|
4701
|
+
<Label>Email</Label>
|
|
4702
|
+
<DemoInput type="email" defaultValue="not-an-email" />
|
|
4703
|
+
<Field.Error errors={[{ message: 'Enter a valid email address.' }]} />
|
|
4704
|
+
</Field.Root>;</code></pre>
|
|
4705
|
+
</div>
|
|
4706
|
+
<div class="note ok">
|
|
4707
|
+
<div class="row">
|
|
4708
|
+
<span class="ex-name">Multiple Errors</span>
|
|
4709
|
+
<span class="badge ok">story ok</span>
|
|
4710
|
+
</div>
|
|
4711
|
+
<div>Several errors rendered as a de-duplicated list</div>
|
|
4712
|
+
<div class="hint">Several errors render as a list, de-duplicated by message.</div>
|
|
4713
|
+
<pre><code>const MultipleErrors = () => <Field.Root
|
|
4714
|
+
orientation="vertical"
|
|
4715
|
+
invalid
|
|
4716
|
+
disabled={false}
|
|
4717
|
+
readOnly={false}
|
|
4718
|
+
required={false}>
|
|
4719
|
+
<Label>Password</Label>
|
|
4720
|
+
<DemoInput type="password" defaultValue="abc" />
|
|
4721
|
+
<Field.Error
|
|
4722
|
+
errors={[
|
|
4723
|
+
{ message: 'Use at least 8 characters.' },
|
|
4724
|
+
{ message: 'Include a number.' },
|
|
4725
|
+
{ message: 'Use at least 8 characters.' }
|
|
4726
|
+
]} />
|
|
4727
|
+
</Field.Root>;</code></pre>
|
|
4728
|
+
</div>
|
|
4729
|
+
<div class="note ok">
|
|
4730
|
+
<div class="row">
|
|
4731
|
+
<span class="ex-name">Error With Types</span>
|
|
4732
|
+
<span class="badge ok">story ok</span>
|
|
4733
|
+
</div>
|
|
4734
|
+
<div>Every rule a single error collected, rendered as a list</div>
|
|
4735
|
+
<div class="hint">One error whose `types` lists every rule that failed renders as that same
|
|
4736
|
+
list. A form library fills it when it collects all the failures instead of
|
|
4737
|
+
stopping at the first (react-hook-form's `criteriaMode: 'all'`), leaving only
|
|
4738
|
+
the first one in `message`, so the messages take precedence over it. A rule
|
|
4739
|
+
that failed without a message of its own contributes nothing.</div>
|
|
4740
|
+
<pre><code>const ErrorWithTypes = () => <Field.Root
|
|
4741
|
+
orientation="vertical"
|
|
4742
|
+
invalid
|
|
4743
|
+
disabled={false}
|
|
4744
|
+
readOnly={false}
|
|
4745
|
+
required={false}>
|
|
4746
|
+
<Label>Password</Label>
|
|
4747
|
+
<DemoInput type="password" defaultValue="short" />
|
|
4748
|
+
<Field.Error
|
|
4749
|
+
errors={[
|
|
4750
|
+
{
|
|
4751
|
+
message: 'At least one uppercase letter.',
|
|
4752
|
+
types: {
|
|
4753
|
+
uppercase: 'At least one uppercase letter.',
|
|
4754
|
+
number: 'At least one number.',
|
|
4755
|
+
length: ['At least 10 characters.'],
|
|
4756
|
+
unnamed: true
|
|
4757
|
+
}
|
|
4758
|
+
}
|
|
4759
|
+
]} />
|
|
4760
|
+
</Field.Root>;</code></pre>
|
|
4761
|
+
</div>
|
|
4762
|
+
<div class="note ok">
|
|
4763
|
+
<div class="row">
|
|
4764
|
+
<span class="ex-name">No Error</span>
|
|
4765
|
+
<span class="badge ok">story ok</span>
|
|
4766
|
+
</div>
|
|
4767
|
+
<div>Error stays mounted and renders nothing while valid</div>
|
|
4768
|
+
<div class="hint">`Field.Error` renders nothing without a message, so it can stay mounted and
|
|
4769
|
+
receive `undefined` entries while the field is valid. With no description
|
|
4770
|
+
either, the control carries no `aria-describedby` at all.</div>
|
|
4771
|
+
<pre><code>const NoError = () => <Field.Root
|
|
4772
|
+
orientation="vertical"
|
|
4773
|
+
invalid={false}
|
|
4774
|
+
disabled={false}
|
|
4775
|
+
readOnly={false}
|
|
4776
|
+
required={false}>
|
|
4777
|
+
<Label>Email</Label>
|
|
4778
|
+
<DemoInput type="email" />
|
|
4779
|
+
<Field.Error errors={[undefined]} />
|
|
4780
|
+
</Field.Root>;</code></pre>
|
|
4781
|
+
</div>
|
|
4782
|
+
<div class="note ok">
|
|
4783
|
+
<div class="row">
|
|
4784
|
+
<span class="ex-name">Disabled</span>
|
|
4785
|
+
<span class="badge ok">story ok</span>
|
|
4786
|
+
</div>
|
|
4787
|
+
<div>Disabled field driven from the root</div>
|
|
4788
|
+
<div class="hint">`disabled` on the root disables the control through context and sets
|
|
4789
|
+
`data-disabled` for styling.</div>
|
|
4790
|
+
<pre><code>const Disabled = () => <Field.Root
|
|
4791
|
+
orientation="vertical"
|
|
4792
|
+
invalid={false}
|
|
4793
|
+
disabled
|
|
4794
|
+
readOnly={false}
|
|
4795
|
+
required={false}>
|
|
4796
|
+
<Label>Agency</Label>
|
|
4797
|
+
<DemoInput defaultValue="Acme Insurance" />
|
|
4798
|
+
<Field.Description>Managed by your administrator.</Field.Description>
|
|
4799
|
+
</Field.Root>;</code></pre>
|
|
4800
|
+
</div>
|
|
4801
|
+
<div class="note ok">
|
|
4802
|
+
<div class="row">
|
|
4803
|
+
<span class="ex-name">Read Only</span>
|
|
4804
|
+
<span class="badge ok">story ok</span>
|
|
4805
|
+
</div>
|
|
4806
|
+
<div>Read-only field driven from the root</div>
|
|
4807
|
+
<div class="hint">`readOnly` on the root makes the control read-only through context and sets
|
|
4808
|
+
`data-readonly` for styling. Unlike `disabled`, the value stays focusable,
|
|
4809
|
+
copyable and submitted.</div>
|
|
4810
|
+
<pre><code>const ReadOnly = () => <Field.Root
|
|
4811
|
+
orientation="vertical"
|
|
4812
|
+
invalid={false}
|
|
4813
|
+
disabled={false}
|
|
4814
|
+
readOnly
|
|
4815
|
+
required={false}>
|
|
4816
|
+
<Label>Policy number</Label>
|
|
4817
|
+
<DemoInput defaultValue="POL-2049-118" />
|
|
4818
|
+
<Field.Description>Assigned by the carrier; contact support to change it.</Field.Description>
|
|
4819
|
+
</Field.Root>;</code></pre>
|
|
4820
|
+
</div>
|
|
4821
|
+
<div class="note ok">
|
|
4822
|
+
<div class="row">
|
|
4823
|
+
<span class="ex-name">Horizontal</span>
|
|
4824
|
+
<span class="badge ok">story ok</span>
|
|
4825
|
+
</div>
|
|
4826
|
+
<div>Horizontal field, one row at every width, controls right-aligned</div>
|
|
4827
|
+
<div class="hint">`horizontal` is one row at every width. The first child fills the row and
|
|
4828
|
+
everything after it keeps its natural width, aligned to the right edge, so
|
|
4829
|
+
the controls of stacked fields line up whatever their labels measure. Wrap a
|
|
4830
|
+
label with its description, or a control with its messages, in
|
|
4831
|
+
`Field.Content`. A control sets its own width: `Input` is `w-full`, so it
|
|
4832
|
+
gets one here.</div>
|
|
4833
|
+
<pre><code>const Horizontal = () => (
|
|
4834
|
+
<Field.Group className="w-[40rem]">
|
|
4835
|
+
<Field.Root orientation="horizontal" data-testid="short">
|
|
4836
|
+
<Label>Full name</Label>
|
|
4837
|
+
<DemoInput defaultValue="Rafa Moro" className="w-72" />
|
|
4838
|
+
</Field.Root>
|
|
4839
|
+
|
|
4840
|
+
<Field.Root orientation="horizontal" data-testid="long">
|
|
4841
|
+
<Label>Title</Label>
|
|
4842
|
+
<Field.Content className="w-72">
|
|
4843
|
+
<DemoInput placeholder="Software engineer" />
|
|
4844
|
+
<Field.Description>Shown on your public profile.</Field.Description>
|
|
4845
|
+
</Field.Content>
|
|
4846
|
+
</Field.Root>
|
|
4847
|
+
|
|
4848
|
+
<Field.Root orientation="horizontal" data-testid="switch">
|
|
4849
|
+
<Field.Content>
|
|
4850
|
+
<Label>Auto-renew</Label>
|
|
4851
|
+
<Field.Description>Renews the policy automatically before it expires.</Field.Description>
|
|
4852
|
+
</Field.Content>
|
|
4853
|
+
<DemoInput type="checkbox" className="size-5" />
|
|
4854
|
+
</Field.Root>
|
|
4855
|
+
|
|
4856
|
+
<div className="w-[20rem]" data-testid="narrow">
|
|
4857
|
+
<Field.Root orientation="horizontal">
|
|
4858
|
+
<Label>Email</Label>
|
|
4859
|
+
<DemoInput type="email" placeholder="you@example.com" className="w-40" />
|
|
4860
|
+
</Field.Root>
|
|
4861
|
+
</div>
|
|
4862
|
+
</Field.Group>
|
|
4863
|
+
);</code></pre>
|
|
4864
|
+
</div>
|
|
4865
|
+
<div class="note ok">
|
|
4866
|
+
<div class="row">
|
|
4867
|
+
<span class="ex-name">Responsive</span>
|
|
4868
|
+
<span class="badge ok">story ok</span>
|
|
4869
|
+
</div>
|
|
4870
|
+
<div>Responsive field that stacks when narrow</div>
|
|
4871
|
+
<div class="hint">`responsive` stacks the parts below `28rem` and behaves like `horizontal`
|
|
4872
|
+
from there: first child fills, the rest keep their width on the right. It
|
|
4873
|
+
measures the field itself, so it needs no particular wrapper. A width that
|
|
4874
|
+
should only apply once horizontal goes behind `@md/field:`.</div>
|
|
4875
|
+
<pre><code>const Responsive = () => (
|
|
4876
|
+
<div className="flex flex-col gap-8">
|
|
4877
|
+
<div className="w-full max-w-[40rem]" data-testid="wide">
|
|
4878
|
+
<Field.Root orientation="responsive">
|
|
4879
|
+
<Label>Email</Label>
|
|
4880
|
+
<Field.Content className="@md/field:w-72">
|
|
4881
|
+
<DemoInput type="email" placeholder="you@example.com" />
|
|
4882
|
+
<Field.Description>
|
|
4883
|
+
We only use this to send policy documents, and never to contact you about anything
|
|
4884
|
+
else.
|
|
4885
|
+
</Field.Description>
|
|
4886
|
+
</Field.Content>
|
|
4887
|
+
</Field.Root>
|
|
4888
|
+
</div>
|
|
4889
|
+
|
|
4890
|
+
<div className="w-full max-w-[20rem]" data-testid="narrow">
|
|
4891
|
+
<Field.Root orientation="responsive">
|
|
4892
|
+
<Label>Email</Label>
|
|
4893
|
+
<Field.Content>
|
|
4894
|
+
<DemoInput type="email" placeholder="you@example.com" />
|
|
4895
|
+
<Field.Description>We only use this to send policy documents.</Field.Description>
|
|
4896
|
+
</Field.Content>
|
|
4897
|
+
</Field.Root>
|
|
4898
|
+
</div>
|
|
4899
|
+
</div>
|
|
4900
|
+
);</code></pre>
|
|
4901
|
+
</div>
|
|
4902
|
+
<div class="note ok">
|
|
4903
|
+
<div class="row">
|
|
4904
|
+
<span class="ex-name">Group</span>
|
|
4905
|
+
<span class="badge ok">story ok</span>
|
|
4906
|
+
</div>
|
|
4907
|
+
<div>Several fields stacked in a group</div>
|
|
4908
|
+
<div class="hint">`Field.Group` stacks fields and owns the space between them. Each field gets
|
|
4909
|
+
its own ids, so several on one page never collide.</div>
|
|
4910
|
+
<pre><code>const Group = () => (
|
|
4911
|
+
<Field.Group>
|
|
4912
|
+
<Field.Root required>
|
|
4913
|
+
<Label>Full name</Label>
|
|
4914
|
+
<DemoInput placeholder="Jane Doe" />
|
|
4915
|
+
</Field.Root>
|
|
4916
|
+
|
|
4917
|
+
<Field.Root required invalid>
|
|
4918
|
+
<Label>Email</Label>
|
|
4919
|
+
<DemoInput type="email" defaultValue="not-an-email" />
|
|
4920
|
+
<Field.Error>Enter a valid email address.</Field.Error>
|
|
4921
|
+
</Field.Root>
|
|
4922
|
+
|
|
4923
|
+
<Field.Root>
|
|
4924
|
+
<Label optional>Phone number</Label>
|
|
4925
|
+
<DemoInput type="tel" placeholder="+1 (555) 000-0000" />
|
|
4926
|
+
</Field.Root>
|
|
4927
|
+
</Field.Group>
|
|
4928
|
+
);</code></pre>
|
|
4929
|
+
</div>
|
|
4930
|
+
<div class="note ok">
|
|
4931
|
+
<div class="row">
|
|
4932
|
+
<span class="ex-name">Standalone Outside Field</span>
|
|
4933
|
+
<span class="badge ok">story ok</span>
|
|
4934
|
+
</div>
|
|
4935
|
+
<div>Label and Field.Error used without a Field.Root</div>
|
|
4936
|
+
<div class="hint">Outside a `Field.Root` every part reads a `null` context and works on its own
|
|
4937
|
+
props alone: `Label` needs its `htmlFor`, `Field.Error` its own `id`.</div>
|
|
4938
|
+
<pre><code>const StandaloneOutsideField = () => (
|
|
4939
|
+
<div className="flex flex-col gap-2">
|
|
4940
|
+
<Label htmlFor="standalone-email">Email</Label>
|
|
4941
|
+
<DemoInput id="standalone-email" type="email" aria-describedby="standalone-error" />
|
|
4942
|
+
<Field.Error id="standalone-error">Something went wrong.</Field.Error>
|
|
4943
|
+
</div>
|
|
4944
|
+
);</code></pre>
|
|
4945
|
+
</div>
|
|
4946
|
+
<div class="note ok">
|
|
4947
|
+
<div class="row">
|
|
4948
|
+
<span class="ex-name">Own Props Win</span>
|
|
4949
|
+
<span class="badge ok">story ok</span>
|
|
4950
|
+
</div>
|
|
4951
|
+
<div>Explicit props on a part win over the field's context</div>
|
|
4952
|
+
<div class="hint">A context is a default, never an override: an explicit `htmlFor` or `id` on a
|
|
4953
|
+
part wins over what `Field.Root` provides.</div>
|
|
4954
|
+
<pre><code>const OwnPropsWin = () => (
|
|
4955
|
+
<Field.Root>
|
|
4956
|
+
<Label htmlFor="own-input">Email</Label>
|
|
4957
|
+
<input id="own-input" type="email" className={inputRecipe()} />
|
|
4958
|
+
<Field.Description id="own-description">Points wherever you say.</Field.Description>
|
|
4959
|
+
</Field.Root>
|
|
4960
|
+
);</code></pre>
|
|
4961
|
+
</div>
|
|
4962
|
+
<div class="note ok">
|
|
4963
|
+
<div class="row">
|
|
4964
|
+
<span class="ex-name">Errors From Context</span>
|
|
4965
|
+
<span class="badge ok">story ok</span>
|
|
4966
|
+
</div>
|
|
4967
|
+
<div>Errors supplied to a bare Field.Error through context</div>
|
|
4968
|
+
<div class="hint">`FieldContext` is an extension point: re-provided under the root with the
|
|
4969
|
+
errors, a bare `<Field.Error />` renders them — here with `useState` and no
|
|
4970
|
+
form library. `InputContext` extends the same way with `value`, `onChange`,
|
|
4971
|
+
`onBlur` and `name`; see `FieldText`.</div>
|
|
4972
|
+
<pre><code>const ErrorsFromContext = () => <FieldWithSuppliedErrors />;</code></pre>
|
|
4973
|
+
</div>
|
|
4974
|
+
</div>
|
|
4975
|
+
|
|
4976
|
+
|
|
4977
|
+
</div>
|
|
4978
|
+
</article>
|
|
4979
|
+
<article
|
|
4980
|
+
class="card
|
|
4981
|
+
no-error
|
|
4982
|
+
no-info
|
|
4983
|
+
no-story-error
|
|
4984
|
+
no-doc-error"
|
|
4985
|
+
role="listitem"
|
|
4986
|
+
aria-label="FieldText">
|
|
4987
|
+
<div class="head">
|
|
4988
|
+
<div class="title">
|
|
4989
|
+
<h2><span class="status-dot dot-ok"></span> FieldText</h2>
|
|
4990
|
+
<div class="badges">
|
|
4991
|
+
<label for="c-12-components-fieldtext-props" class="badge ok as-toggle">6 prop types</label>
|
|
4992
|
+
|
|
4993
|
+
<label for="c-12-components-fieldtext-stories" class="badge ok as-toggle">7 stories</label>
|
|
4994
|
+
|
|
4995
|
+
|
|
4996
|
+
</div>
|
|
4997
|
+
</div>
|
|
4998
|
+
<div class="meta" title="./src/field-text/field-text.stories.tsx">components-fieldtext · ./src/field-text/field-text.stories.tsx</div>
|
|
4999
|
+
<div>Field for a single-line text control, wiring the Input inside it</div>
|
|
5000
|
+
<div class="hint">FieldText is a `Field.Root` for a single-line text control. It provides
|
|
5001
|
+
`InputContext`, so the `Input` inside associates itself with the label and
|
|
5002
|
+
the messages and takes `invalid`, `required`, `disabled` and `readOnly` from
|
|
5003
|
+
the field — no `id`, `htmlFor`, `aria-describedby` or `aria-invalid` written
|
|
5004
|
+
by hand.
|
|
5005
|
+
|
|
5006
|
+
It knows nothing about form libraries, and its contexts compose: a provider
|
|
5007
|
+
nested inside it can extend `InputContext` with `value`, `onChange`, `onBlur`
|
|
5008
|
+
and `name`, and `FieldContext` with the errors, as the last story shows.</div>
|
|
5009
|
+
<div class="kv"><span class="chip">summary: Field for a single-line text control, wiring the Input inside it</span><span class="chip">example: <FieldText invalid={!!error} required>
|
|
5010
|
+
<Label>Email</Label>
|
|
5011
|
+
<Input type="email" />
|
|
5012
|
+
<Field.Description>We only use this for policy documents.</Field.Description>
|
|
5013
|
+
<Field.Error errors={[error]} />
|
|
5014
|
+
</FieldText></span></div>
|
|
5015
|
+
</div>
|
|
5016
|
+
|
|
5017
|
+
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5018
|
+
|
|
5019
|
+
|
|
5020
|
+
<input id="c-12-components-fieldtext-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5021
|
+
|
|
5022
|
+
|
|
5023
|
+
<input id="c-12-components-fieldtext-props" class="tg tg-props" type="checkbox" hidden />
|
|
5024
|
+
|
|
5025
|
+
<div class="panels">
|
|
5026
|
+
|
|
5027
|
+
|
|
5028
|
+
|
|
5029
|
+
<div class="panel panel-props">
|
|
5030
|
+
<div class="note ok">
|
|
5031
|
+
<div class="row">
|
|
5032
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5033
|
+
<span class="badge ok">6 prop types</span>
|
|
5034
|
+
</div>
|
|
5035
|
+
<pre><code>Component: src/field-text/index.ts::FieldText</code></pre>
|
|
5036
|
+
<pre><code>Props:</code></pre>
|
|
5037
|
+
<pre><code>/**
|
|
5038
|
+
* `id` for the control. Generated when omitted. Set it here, not on the
|
|
5039
|
+
* control, so the label and the messages keep pointing at the right element.
|
|
5040
|
+
*/
|
|
5041
|
+
controlId?: string
|
|
5042
|
+
|
|
5043
|
+
/**
|
|
5044
|
+
* Disables the control through its context and sets `data-disabled` on the root.
|
|
5045
|
+
*/
|
|
5046
|
+
disabled?: boolean
|
|
5047
|
+
|
|
5048
|
+
/**
|
|
5049
|
+
* Marks the field as failing validation: sets `data-invalid` on the root and
|
|
5050
|
+
* `aria-invalid` on the control through its context, which drives the
|
|
5051
|
+
* control's destructive border. The label keeps its color by design.
|
|
5052
|
+
*/
|
|
5053
|
+
invalid?: boolean
|
|
5054
|
+
|
|
5055
|
+
/**
|
|
5056
|
+
* Layout of the field. `vertical` (default) stacks label, control and
|
|
5057
|
+
* messages. `horizontal` is one row at every width: the first child fills it
|
|
5058
|
+
* and the rest keep their natural width, aligned to the right, so the
|
|
5059
|
+
* controls of stacked fields line up. `responsive` stacks below `28rem` and
|
|
5060
|
+
* behaves like `horizontal` from there, measured on the field itself, so it
|
|
5061
|
+
* needs no particular wrapper. In both, `Field.Content` groups a control with
|
|
5062
|
+
* its messages, or a label with its description.
|
|
5063
|
+
*/
|
|
5064
|
+
orientation?: "horizontal" | "vertical" | "responsive"
|
|
5065
|
+
|
|
5066
|
+
/**
|
|
5067
|
+
* Makes the control read-only through its context (focusable and copyable,
|
|
5068
|
+
* not editable, still submitted) and sets `data-readonly` on the root.
|
|
5069
|
+
*/
|
|
5070
|
+
readOnly?: boolean
|
|
5071
|
+
|
|
5072
|
+
/**
|
|
5073
|
+
* Single source of truth for a required field: the `Label` shows its
|
|
5074
|
+
* asterisk and the control receives `required`, both through context.
|
|
5075
|
+
*/
|
|
5076
|
+
required?: boolean</code></pre>
|
|
5077
|
+
</div>
|
|
5078
|
+
</div>
|
|
5079
|
+
|
|
5080
|
+
<div class="panel panel-stories">
|
|
5081
|
+
|
|
5082
|
+
|
|
5083
|
+
|
|
5084
|
+
<div class="note ok">
|
|
5085
|
+
<div class="row">
|
|
5086
|
+
<span class="ex-name">Imports</span>
|
|
5087
|
+
</div>
|
|
5088
|
+
<pre><code>import { Field, FieldContext, FieldText, Input, InputContext, Label } from "@agentero/design-system";</code></pre>
|
|
5089
|
+
</div>
|
|
5090
|
+
|
|
5091
|
+
|
|
5092
|
+
<div class="note ok">
|
|
5093
|
+
<div class="row">
|
|
5094
|
+
<span class="ex-name">Default</span>
|
|
5095
|
+
<span class="badge ok">story ok</span>
|
|
5096
|
+
</div>
|
|
5097
|
+
<div>Label, Input and description wired with no ids</div>
|
|
5098
|
+
<div class="hint">The composition consumers write: a label, the design system's `Input` and
|
|
5099
|
+
helper text. The label points at the input and the input is described by the
|
|
5100
|
+
text, all through context.</div>
|
|
5101
|
+
<pre><code>const Default = () => <FieldText
|
|
5102
|
+
orientation="vertical"
|
|
5103
|
+
invalid={false}
|
|
5104
|
+
disabled={false}
|
|
5105
|
+
readOnly={false}
|
|
5106
|
+
required={false}>
|
|
5107
|
+
<Label>Email</Label>
|
|
5108
|
+
<Input type="email" placeholder="you@example.com" />
|
|
5109
|
+
<Field.Description>We only use this to send policy documents.</Field.Description>
|
|
5110
|
+
</FieldText>;</code></pre>
|
|
5111
|
+
</div>
|
|
5112
|
+
<div class="note ok">
|
|
5113
|
+
<div class="row">
|
|
5114
|
+
<span class="ex-name">Required</span>
|
|
5115
|
+
<span class="badge ok">story ok</span>
|
|
5116
|
+
</div>
|
|
5117
|
+
<div>Required field driven from the root alone</div>
|
|
5118
|
+
<div class="hint">`required` on the field reaches both the label's asterisk and the input's
|
|
5119
|
+
`required` attribute.</div>
|
|
5120
|
+
<pre><code>const Required = () => <FieldText
|
|
5121
|
+
orientation="vertical"
|
|
5122
|
+
invalid={false}
|
|
5123
|
+
disabled={false}
|
|
5124
|
+
readOnly={false}
|
|
5125
|
+
required>
|
|
5126
|
+
<Label>Full name</Label>
|
|
5127
|
+
<Input placeholder="Jane Doe" />
|
|
5128
|
+
</FieldText>;</code></pre>
|
|
5129
|
+
</div>
|
|
5130
|
+
<div class="note ok">
|
|
5131
|
+
<div class="row">
|
|
5132
|
+
<span class="ex-name">Invalid</span>
|
|
5133
|
+
<span class="badge ok">story ok</span>
|
|
5134
|
+
</div>
|
|
5135
|
+
<div>Invalid field with the Input styled by aria-invalid</div>
|
|
5136
|
+
<div class="hint">`invalid` on the field sets `aria-invalid` on the input, which drives its
|
|
5137
|
+
destructive border, and the error is announced with the input.</div>
|
|
5138
|
+
<pre><code>const Invalid = () => <FieldText
|
|
5139
|
+
orientation="vertical"
|
|
5140
|
+
invalid
|
|
5141
|
+
disabled={false}
|
|
5142
|
+
readOnly={false}
|
|
5143
|
+
required={false}>
|
|
5144
|
+
<Label>Email</Label>
|
|
5145
|
+
<Input type="email" defaultValue="not-an-email" />
|
|
5146
|
+
<Field.Error errors={[{ message: 'Enter a valid email address.' }]} />
|
|
5147
|
+
</FieldText>;</code></pre>
|
|
5148
|
+
</div>
|
|
5149
|
+
<div class="note ok">
|
|
5150
|
+
<div class="row">
|
|
5151
|
+
<span class="ex-name">Disabled</span>
|
|
5152
|
+
<span class="badge ok">story ok</span>
|
|
5153
|
+
</div>
|
|
5154
|
+
<div>Disabled field driven from the root</div>
|
|
5155
|
+
<div class="hint">`disabled` on the field disables the input through context.</div>
|
|
5156
|
+
<pre><code>const Disabled = () => <FieldText
|
|
5157
|
+
orientation="vertical"
|
|
5158
|
+
invalid={false}
|
|
5159
|
+
disabled
|
|
5160
|
+
readOnly={false}
|
|
5161
|
+
required={false}>
|
|
5162
|
+
<Label>Agency</Label>
|
|
5163
|
+
<Input defaultValue="Acme Insurance" />
|
|
5164
|
+
</FieldText>;</code></pre>
|
|
5165
|
+
</div>
|
|
5166
|
+
<div class="note ok">
|
|
5167
|
+
<div class="row">
|
|
5168
|
+
<span class="ex-name">Read Only</span>
|
|
5169
|
+
<span class="badge ok">story ok</span>
|
|
5170
|
+
</div>
|
|
5171
|
+
<div>Read-only field driven from the root</div>
|
|
5172
|
+
<div class="hint">`readOnly` on the field reaches the input through context. The value stays
|
|
5173
|
+
focusable, copyable and submitted, and the input looks like any other.</div>
|
|
5174
|
+
<pre><code>const ReadOnly = () => <FieldText
|
|
5175
|
+
orientation="vertical"
|
|
5176
|
+
invalid={false}
|
|
5177
|
+
disabled={false}
|
|
5178
|
+
readOnly
|
|
5179
|
+
required={false}>
|
|
5180
|
+
<Label>Policy number</Label>
|
|
5181
|
+
<Input defaultValue="POL-2049-118" />
|
|
5182
|
+
<Field.Description>Assigned by the carrier; contact support to change it.</Field.Description>
|
|
5183
|
+
</FieldText>;</code></pre>
|
|
5184
|
+
</div>
|
|
5185
|
+
<div class="note ok">
|
|
5186
|
+
<div class="row">
|
|
5187
|
+
<span class="ex-name">Own Props Win</span>
|
|
5188
|
+
<span class="badge ok">story ok</span>
|
|
5189
|
+
</div>
|
|
5190
|
+
<div>Input's own props merge with, and win over, the field's context</div>
|
|
5191
|
+
<div class="hint">The context is a default, never an override: an extra `aria-describedby` is
|
|
5192
|
+
concatenated with the field's ids, `className` is merged and `size` passes
|
|
5193
|
+
through untouched.</div>
|
|
5194
|
+
<pre><code>const OwnPropsWin = () => <div className="flex flex-col gap-2">
|
|
5195
|
+
<FieldText
|
|
5196
|
+
orientation="vertical"
|
|
5197
|
+
invalid={false}
|
|
5198
|
+
disabled={false}
|
|
5199
|
+
readOnly={false}
|
|
5200
|
+
required={false}>
|
|
5201
|
+
<Label>Website</Label>
|
|
5202
|
+
<Input type="url" size="lg" className="max-w-xs" aria-describedby="website-hint" />
|
|
5203
|
+
<Field.Description>Include the protocol.</Field.Description>
|
|
5204
|
+
</FieldText>
|
|
5205
|
+
<p id="website-hint" className="text-sm">Shown on your public profile.
|
|
5206
|
+
</p>
|
|
5207
|
+
</div>;</code></pre>
|
|
5208
|
+
</div>
|
|
5209
|
+
<div class="note ok">
|
|
5210
|
+
<div class="row">
|
|
5211
|
+
<span class="ex-name">Controlled From Context</span>
|
|
5212
|
+
<span class="badge ok">story ok</span>
|
|
5213
|
+
</div>
|
|
5214
|
+
<div>Input controlled and errors supplied from outside the field</div>
|
|
5215
|
+
<div class="hint">The contexts are an extension point: a provider nested in the field adds
|
|
5216
|
+
`name`, `value`, `onChange` and `onBlur` to `InputContext`, so a bare
|
|
5217
|
+
`<Input />` becomes controlled, and the errors to `FieldContext`, so a bare
|
|
5218
|
+
`<Field.Error />` renders them — here with `useState` and no form library.
|
|
5219
|
+
The input's own `onChange` still runs, chained after the provider's.</div>
|
|
5220
|
+
<pre><code>const ControlledFromContext = () => <ControlledField />;</code></pre>
|
|
5221
|
+
</div>
|
|
5222
|
+
</div>
|
|
5223
|
+
|
|
5224
|
+
|
|
5225
|
+
</div>
|
|
5226
|
+
</article>
|
|
5227
|
+
<article
|
|
5228
|
+
class="card
|
|
5229
|
+
no-error
|
|
5230
|
+
no-info
|
|
5231
|
+
no-story-error
|
|
5232
|
+
no-doc-error"
|
|
5233
|
+
role="listitem"
|
|
5234
|
+
aria-label="Form.Root">
|
|
5235
|
+
<div class="head">
|
|
5236
|
+
<div class="title">
|
|
5237
|
+
<h2><span class="status-dot dot-ok"></span> Form.Root</h2>
|
|
5238
|
+
<div class="badges">
|
|
5239
|
+
<label for="c-13-components-form-props" class="badge ok as-toggle">3 prop types</label>
|
|
5240
|
+
|
|
5241
|
+
<label for="c-13-components-form-stories" class="badge ok as-toggle">2 stories</label>
|
|
5242
|
+
|
|
5243
|
+
|
|
5244
|
+
</div>
|
|
5245
|
+
</div>
|
|
5246
|
+
<div class="meta" title="./src/form/form.stories.tsx">components-form · ./src/form/form.stories.tsx</div>
|
|
5247
|
+
<div>Form element bound to a react-hook-form instance, shared with its fields</div>
|
|
5248
|
+
<div class="hint">Form is the react-hook-form binding of the design system. `Form.Root` renders
|
|
5249
|
+
the `<form>` and provides the `useForm()` instance to the form fields inside
|
|
5250
|
+
it — `FormText` and the other `Form<X>` components — which bind themselves by
|
|
5251
|
+
`name`. The submit goes through `handleSubmit`, so `onSubmit` only runs with
|
|
5252
|
+
valid, typed values, and the element is always `noValidate`: validation is
|
|
5253
|
+
react-hook-form's, and the `required` a field sets is announced without the
|
|
5254
|
+
browser's own bubble.
|
|
5255
|
+
|
|
5256
|
+
`react-hook-form` is an optional peer dependency: install it in the app and
|
|
5257
|
+
keep a single copy, since the provider and the fields share one context.</div>
|
|
5258
|
+
<div class="kv"><span class="chip">summary: Form element bound to a react-hook-form instance, shared with its fields</span><span class="chip">example: const methods = useForm<Values>({ defaultValues: { agencyName: '', email: '' } });
|
|
5259
|
+
|
|
5260
|
+
<Form.Root methods={methods} onSubmit={saveAgency} aria-label="Agency profile">
|
|
5261
|
+
<FormText name="agencyName" label="Agency name" required rules={{ required: 'Enter the agency name.' }} />
|
|
5262
|
+
<FormText name="email" label="Email" inputProps={{ type: 'email' }} />
|
|
5263
|
+
<Button type="submit">Save</Button>
|
|
5264
|
+
</Form.Root></span></div>
|
|
5265
|
+
</div>
|
|
5266
|
+
|
|
5267
|
+
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5268
|
+
|
|
5269
|
+
|
|
5270
|
+
<input id="c-13-components-form-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5271
|
+
|
|
5272
|
+
|
|
5273
|
+
<input id="c-13-components-form-props" class="tg tg-props" type="checkbox" hidden />
|
|
5274
|
+
|
|
5275
|
+
<div class="panels">
|
|
5276
|
+
|
|
5277
|
+
|
|
5278
|
+
|
|
5279
|
+
<div class="panel panel-props">
|
|
5280
|
+
<div class="note ok">
|
|
5281
|
+
<div class="row">
|
|
5282
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5283
|
+
<span class="badge ok">3 prop types</span>
|
|
5284
|
+
</div>
|
|
5285
|
+
<pre><code>Component: src/form/index.ts::Form</code></pre>
|
|
5286
|
+
<pre><code>Props:</code></pre>
|
|
5287
|
+
<pre><code>/**
|
|
5288
|
+
* Defines a string value that labels the current element.
|
|
5289
|
+
* Accessible name of the form. A `<form>` only becomes a landmark when it is
|
|
5290
|
+
* named, and screen readers list landmarks by name, so it is required.
|
|
5291
|
+
*/
|
|
5292
|
+
aria-label: string
|
|
5293
|
+
|
|
5294
|
+
/**
|
|
5295
|
+
* The object `useForm()` returns. `Form.Root` hands it to every form field
|
|
5296
|
+
* inside through react-hook-form's `FormProvider`, so a `FormText` needs only
|
|
5297
|
+
* its `name`. Create it in the component that owns the form and pass
|
|
5298
|
+
* `defaultValues`: a field whose value is `undefined` on the first render
|
|
5299
|
+
* starts uncontrolled. A form whose resolver transforms the values
|
|
5300
|
+
* (`useForm<Input, Context, Output>`) is accepted as is.
|
|
5301
|
+
*/
|
|
5302
|
+
methods: UseFormReturn<AgencyValues, any, AgencyValues>
|
|
5303
|
+
|
|
5304
|
+
/**
|
|
5305
|
+
* Called with the validated values once validation passes: the resolver's
|
|
5306
|
+
* output when it transforms them, the form's values otherwise. Wrapped in
|
|
5307
|
+
* `methods.handleSubmit`, which prevents the native submit and focuses the
|
|
5308
|
+
* first invalid field; when it is omitted the form validates and does nothing
|
|
5309
|
+
* else.
|
|
5310
|
+
*/
|
|
5311
|
+
onSubmit?: SubmitHandler<AgencyValues></code></pre>
|
|
5312
|
+
</div>
|
|
5313
|
+
</div>
|
|
5314
|
+
|
|
5315
|
+
<div class="panel panel-stories">
|
|
5316
|
+
|
|
5317
|
+
|
|
5318
|
+
|
|
5319
|
+
<div class="note ok">
|
|
5320
|
+
<div class="row">
|
|
5321
|
+
<span class="ex-name">Imports</span>
|
|
5322
|
+
</div>
|
|
5323
|
+
<pre><code>import { Button, Field, Form, FormText } from "@agentero/design-system";</code></pre>
|
|
5324
|
+
</div>
|
|
5325
|
+
|
|
5326
|
+
|
|
5327
|
+
<div class="note ok">
|
|
5328
|
+
<div class="row">
|
|
5329
|
+
<span class="ex-name">Default</span>
|
|
5330
|
+
<span class="badge ok">story ok</span>
|
|
5331
|
+
</div>
|
|
5332
|
+
<div>Form.Root with FormText fields validating on submit</div>
|
|
5333
|
+
<div class="hint">A form with two required fields and a submit button. Submitting empty shows
|
|
5334
|
+
both errors, marks both inputs invalid and focuses the first one — proof that
|
|
5335
|
+
react-hook-form's `ref` reached the inputs. Once filled in, `onSubmit`
|
|
5336
|
+
receives the typed values.</div>
|
|
5337
|
+
<pre><code>const Default = () => <AgencyForm />;</code></pre>
|
|
5338
|
+
</div>
|
|
5339
|
+
<div class="note ok">
|
|
5340
|
+
<div class="row">
|
|
5341
|
+
<span class="ex-name">No Validate</span>
|
|
5342
|
+
<span class="badge ok">story ok</span>
|
|
5343
|
+
</div>
|
|
5344
|
+
<div>Native required never triggers the browser's validation bubble</div>
|
|
5345
|
+
<div class="hint">`required` on a field reaches the native attribute, so assistive technology
|
|
5346
|
+
announces it, but the form renders `noValidate`: without `rules`, submitting
|
|
5347
|
+
the field empty is not blocked by the browser and `onSubmit` still runs.
|
|
5348
|
+
Validation is react-hook-form's alone.</div>
|
|
5349
|
+
<pre><code>const NoValidate = () => <NicknameForm />;</code></pre>
|
|
5350
|
+
</div>
|
|
5351
|
+
</div>
|
|
5352
|
+
|
|
5353
|
+
|
|
5354
|
+
</div>
|
|
5355
|
+
</article>
|
|
5356
|
+
<article
|
|
5357
|
+
class="card
|
|
5358
|
+
no-error
|
|
5359
|
+
no-info
|
|
5360
|
+
no-story-error
|
|
5361
|
+
no-doc-error"
|
|
5362
|
+
role="listitem"
|
|
5363
|
+
aria-label="FormText">
|
|
5364
|
+
<div class="head">
|
|
5365
|
+
<div class="title">
|
|
5366
|
+
<h2><span class="status-dot dot-ok"></span> FormText</h2>
|
|
5367
|
+
<div class="badges">
|
|
5368
|
+
<label for="c-14-components-formtext-props" class="badge ok as-toggle">15 prop types</label>
|
|
5369
|
+
|
|
5370
|
+
<label for="c-14-components-formtext-stories" class="badge ok as-toggle">9 stories</label>
|
|
5371
|
+
|
|
5372
|
+
|
|
5373
|
+
</div>
|
|
5374
|
+
</div>
|
|
5375
|
+
<div class="meta" title="./src/form-text/form-text.stories.tsx">components-formtext · ./src/form-text/form-text.stories.tsx</div>
|
|
5376
|
+
<div>Label, Input, description and error bound to one react-hook-form field</div>
|
|
5377
|
+
<div class="hint">FormText is a complete text field bound to one react-hook-form value: label,
|
|
5378
|
+
`Input`, helper text and validation error in the standard order, wired
|
|
5379
|
+
through `useController`. It renders inside a `Form.Root` and needs only a
|
|
5380
|
+
`name`; `required`, `invalid` and the error reach the label, the input's
|
|
5381
|
+
`aria-*` attributes and the message with no ids written by hand.
|
|
5382
|
+
|
|
5383
|
+
It covers the common case. For another layout — an input with addons, a
|
|
5384
|
+
different control, a message rendered elsewhere — compose `useController`
|
|
5385
|
+
with the `FieldText`, `Label`, `Input` and `Field.*` primitives directly.</div>
|
|
5386
|
+
<div class="kv"><span class="chip">summary: Label, Input, description and error bound to one react-hook-form field</span><span class="chip">example: <FormText
|
|
5387
|
+
name="taxId"
|
|
5388
|
+
label="Tax ID"
|
|
5389
|
+
tooltip="The EIN the IRS issued to the agency."
|
|
5390
|
+
description="Nine digits, with or without the dash."
|
|
5391
|
+
required
|
|
5392
|
+
rules={{ required: 'Enter the tax ID.', pattern: { value: /^\d{2}-?\d{7}$/, message: 'Nine digits.' } }}
|
|
5393
|
+
inputProps={{ inputMode: 'numeric', autoComplete: 'off' }}
|
|
5394
|
+
/></span></div>
|
|
5395
|
+
</div>
|
|
5396
|
+
|
|
5397
|
+
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5398
|
+
|
|
5399
|
+
|
|
5400
|
+
<input id="c-14-components-formtext-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5401
|
+
|
|
5402
|
+
|
|
5403
|
+
<input id="c-14-components-formtext-props" class="tg tg-props" type="checkbox" hidden />
|
|
5404
|
+
|
|
5405
|
+
<div class="panels">
|
|
5406
|
+
|
|
5407
|
+
|
|
5408
|
+
|
|
5409
|
+
<div class="panel panel-props">
|
|
5410
|
+
<div class="note ok">
|
|
5411
|
+
<div class="row">
|
|
5412
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
5413
|
+
<span class="badge ok">15 prop types</span>
|
|
5414
|
+
</div>
|
|
5415
|
+
<pre><code>Component: src/form-text/index.ts::FormText</code></pre>
|
|
5416
|
+
<pre><code>Props:</code></pre>
|
|
5417
|
+
<pre><code>/**
|
|
5418
|
+
* The form's `control`, from `useForm()`. Defaults to the one the
|
|
5419
|
+
* surrounding `Form.Root` provides; pass it explicitly to get `name`
|
|
5420
|
+
* inference without writing the generic, or when the field renders outside
|
|
5421
|
+
* a `Form.Root`. A `control` whose resolver transforms the values is
|
|
5422
|
+
* accepted as is.
|
|
5423
|
+
*/
|
|
5424
|
+
control?: Control<FieldValues, any, FieldValues>
|
|
5425
|
+
|
|
5426
|
+
/**
|
|
5427
|
+
* `id` for the control. Generated when omitted. Set it here, not on the
|
|
5428
|
+
* control, so the label and the messages keep pointing at the right element.
|
|
5429
|
+
*/
|
|
5430
|
+
controlId?: string
|
|
5431
|
+
|
|
5432
|
+
/**
|
|
5433
|
+
* Helper text shown under the control and announced through its
|
|
5434
|
+
* `aria-describedby`. Use it for guidance the user needs before typing; put
|
|
5435
|
+
* details worth a click in `tooltip` instead.
|
|
5436
|
+
*/
|
|
5437
|
+
description?: ReactNode
|
|
5438
|
+
|
|
5439
|
+
/**
|
|
5440
|
+
* Disables the control through its context and sets `data-disabled` on the root.
|
|
5441
|
+
* Disables the input and marks the field. Unlike react-hook-form's own
|
|
5442
|
+
* `disabled` option, the value stays in the submitted data: disabling a
|
|
5443
|
+
* field is a presentation decision, not a change to the form's values.
|
|
5444
|
+
*/
|
|
5445
|
+
disabled?: boolean
|
|
5446
|
+
|
|
5447
|
+
/**
|
|
5448
|
+
* Everything else the `Input` should receive: `type`, `placeholder`,
|
|
5449
|
+
* `maxLength`, `autoComplete`, `size`, `className`… Handlers such as
|
|
5450
|
+
* `onChange` and `onBlur` run after react-hook-form's, which are already
|
|
5451
|
+
* wired.
|
|
5452
|
+
*/
|
|
5453
|
+
inputProps?: FormTextInputProps
|
|
5454
|
+
|
|
5455
|
+
/**
|
|
5456
|
+
* The caption, rendered as the field's label. Text in almost every case.
|
|
5457
|
+
*/
|
|
5458
|
+
label: ReactNode
|
|
5459
|
+
|
|
5460
|
+
/**
|
|
5461
|
+
* Path of the value in the form, nested paths included (`'agency.npn'`).
|
|
5462
|
+
* Type it against the form's values with the generic
|
|
5463
|
+
* (`<FormText<Values> name="agency.npn" />`) or by passing `control`: the
|
|
5464
|
+
* path must then exist and hold a string (`FormTextPath`).
|
|
5465
|
+
*/
|
|
5466
|
+
name: "agencyName"
|
|
5467
|
+
|
|
5468
|
+
/**
|
|
5469
|
+
* Appends a muted " (optional)" to the label. The forms mark optional fields
|
|
5470
|
+
* rather than required ones; ignored when `required` is set.
|
|
5471
|
+
*/
|
|
5472
|
+
optional?: boolean
|
|
5473
|
+
|
|
5474
|
+
/**
|
|
5475
|
+
* Layout of the field. `vertical` (default) stacks label, control and
|
|
5476
|
+
* messages. `horizontal` is one row at every width: the first child fills it
|
|
5477
|
+
* and the rest keep their natural width, aligned to the right, so the
|
|
5478
|
+
* controls of stacked fields line up. `responsive` stacks below `28rem` and
|
|
5479
|
+
* behaves like `horizontal` from there, measured on the field itself, so it
|
|
5480
|
+
* needs no particular wrapper. In both, `Field.Content` groups a control with
|
|
5481
|
+
* its messages, or a label with its description.
|
|
5482
|
+
*/
|
|
5483
|
+
orientation?: "horizontal" | "vertical" | "responsive"
|
|
5484
|
+
|
|
5485
|
+
/**
|
|
5486
|
+
* Makes the control read-only through its context (focusable and copyable,
|
|
5487
|
+
* not editable, still submitted) and sets `data-readonly` on the root.
|
|
5488
|
+
*/
|
|
5489
|
+
readOnly?: boolean
|
|
5490
|
+
|
|
5491
|
+
/**
|
|
5492
|
+
* Single source of truth for a required field: the `Label` shows its
|
|
5493
|
+
* asterisk and the control receives `required`, both through context.
|
|
5494
|
+
* Marks the field required: an asterisk on the label and the native
|
|
5495
|
+
* `required` attribute on the input, which assistive technology announces.
|
|
5496
|
+
* It does not validate — pair it with `rules.required` or a resolver — and it
|
|
5497
|
+
* never triggers the browser bubble, since `Form.Root` renders `noValidate`.
|
|
5498
|
+
*/
|
|
5499
|
+
required?: boolean
|
|
5500
|
+
|
|
5501
|
+
/**
|
|
5502
|
+
* react-hook-form validation rules for this field (`required`, `pattern`,
|
|
5503
|
+
* `validate`…), same as `register`'s. They only validate: `rules.required`
|
|
5504
|
+
* does not mark the field `required` — that is a separate, visible decision.
|
|
5505
|
+
*/
|
|
5506
|
+
rules?: Omit<RegisterOptions<FieldValues, "agencyName">, "disabled" | "valueAsNumber" | "valueAsDate" | "setValueAs">
|
|
5507
|
+
|
|
5508
|
+
/**
|
|
5509
|
+
* Drops the value from the form when the field unmounts, react-hook-form's
|
|
5510
|
+
* `shouldUnregister`. Defaults to `false`: a field revealed by another one
|
|
5511
|
+
* keeps its value while hidden.
|
|
5512
|
+
*/
|
|
5513
|
+
shouldUnregister?: boolean
|
|
5514
|
+
|
|
5515
|
+
/**
|
|
5516
|
+
* Content of an info tooltip rendered beside the label, for details that
|
|
5517
|
+
* would clutter the description. The trigger is a sibling of the label, so
|
|
5518
|
+
* the field's accessible name stays the label text.
|
|
5519
|
+
*/
|
|
5520
|
+
tooltip?: ReactNode
|
|
5521
|
+
|
|
5522
|
+
/**
|
|
5523
|
+
* Preferred side of the tooltip. Defaults to `'top'`.
|
|
5524
|
+
*/
|
|
5525
|
+
tooltipSide?: "right" | "top" | "bottom" | "left"</code></pre>
|
|
5526
|
+
</div>
|
|
5527
|
+
</div>
|
|
5528
|
+
|
|
5529
|
+
<div class="panel panel-stories">
|
|
5530
|
+
|
|
5531
|
+
|
|
5532
|
+
|
|
5533
|
+
<div class="note ok">
|
|
5534
|
+
<div class="row">
|
|
5535
|
+
<span class="ex-name">Imports</span>
|
|
5536
|
+
</div>
|
|
5537
|
+
<pre><code>import { Button, Field, Form, FormText } from "@agentero/design-system";</code></pre>
|
|
5538
|
+
</div>
|
|
5539
|
+
|
|
5540
|
+
|
|
5541
|
+
<div class="note ok">
|
|
5542
|
+
<div class="row">
|
|
5543
|
+
<span class="ex-name">Default</span>
|
|
5544
|
+
<span class="badge ok">story ok</span>
|
|
5545
|
+
</div>
|
|
5546
|
+
<div>Required text field validating on submit</div>
|
|
5547
|
+
<div class="hint">The field consumers write: a `name`, a `label` and the validation rule.
|
|
5548
|
+
Submitting empty renders the error and marks the input invalid; typing
|
|
5549
|
+
clears both and the value reaches `onSubmit`.</div>
|
|
5550
|
+
<pre><code>const Default = () => <AgencyNameForm
|
|
5551
|
+
name="agencyName"
|
|
5552
|
+
label="Agency name"
|
|
5553
|
+
orientation="vertical"
|
|
5554
|
+
required
|
|
5555
|
+
optional={false}
|
|
5556
|
+
disabled={false}
|
|
5557
|
+
readOnly={false} />;</code></pre>
|
|
5558
|
+
</div>
|
|
5559
|
+
<div class="note ok">
|
|
5560
|
+
<div class="row">
|
|
5561
|
+
<span class="ex-name">With Description And Tooltip</span>
|
|
5562
|
+
<span class="badge ok">story ok</span>
|
|
5563
|
+
</div>
|
|
5564
|
+
<div>Helper text under the input and an info tooltip beside the label</div>
|
|
5565
|
+
<div class="hint">`description` is helper text under the input, announced through
|
|
5566
|
+
`aria-describedby`. `tooltip` is an info button beside the label for details
|
|
5567
|
+
worth a click; it is a sibling of the `<label>`, so the field's accessible
|
|
5568
|
+
name stays the label text.</div>
|
|
5569
|
+
<pre><code>const WithDescriptionAndTooltip = () => <TaxIdForm />;</code></pre>
|
|
5570
|
+
</div>
|
|
5571
|
+
<div class="note ok">
|
|
5572
|
+
<div class="row">
|
|
5573
|
+
<span class="ex-name">Optional</span>
|
|
5574
|
+
<span class="badge ok">story ok</span>
|
|
5575
|
+
</div>
|
|
5576
|
+
<div>Optional field with the " (optional)" label suffix</div>
|
|
5577
|
+
<div class="hint">The forms mark optional fields rather than required ones: `optional`
|
|
5578
|
+
appends a muted suffix to the label and leaves the input without the
|
|
5579
|
+
`required` attribute.</div>
|
|
5580
|
+
<pre><code>const Optional = () => <PhoneForm />;</code></pre>
|
|
5581
|
+
</div>
|
|
5582
|
+
<div class="note ok">
|
|
5583
|
+
<div class="row">
|
|
5584
|
+
<span class="ex-name">With Rules</span>
|
|
5585
|
+
<span class="badge ok">story ok</span>
|
|
5586
|
+
</div>
|
|
5587
|
+
<div>Nested path with validation rules, typed through the generic</div>
|
|
5588
|
+
<div class="hint">`rules` are react-hook-form's, and `name` accepts nested paths typed against
|
|
5589
|
+
the form's values through the generic. `rules.required` validates but does
|
|
5590
|
+
not mark the field required: that stays an explicit `required` prop.</div>
|
|
5591
|
+
<pre><code>const WithRules = () => <NpnForm />;</code></pre>
|
|
5592
|
+
</div>
|
|
5593
|
+
<div class="note ok">
|
|
5594
|
+
<div class="row">
|
|
5595
|
+
<span class="ex-name">All Errors</span>
|
|
5596
|
+
<span class="badge ok">story ok</span>
|
|
5597
|
+
</div>
|
|
5598
|
+
<div>Every failed rule listed under criteriaMode 'all'</div>
|
|
5599
|
+
<div class="hint">A form set to react-hook-form's `criteriaMode: 'all'` collects every rule
|
|
5600
|
+
that failed instead of stopping at the first, and the field lists them all.
|
|
5601
|
+
With the default `'firstError'` a single message is rendered, as in the other
|
|
5602
|
+
stories.</div>
|
|
5603
|
+
<pre><code>const AllErrors = () => <PasswordRulesForm />;</code></pre>
|
|
5604
|
+
</div>
|
|
5605
|
+
<div class="note ok">
|
|
5606
|
+
<div class="row">
|
|
5607
|
+
<span class="ex-name">Input Props Chaining</span>
|
|
5608
|
+
<span class="badge ok">story ok</span>
|
|
5609
|
+
</div>
|
|
5610
|
+
<div>Input attributes and a consumer onChange chained after the form's</div>
|
|
5611
|
+
<div class="hint">`inputProps` carries the input's own attributes — `type`, `placeholder`,
|
|
5612
|
+
`maxLength`, `size`… — and its handlers. A consumer `onChange` runs after
|
|
5613
|
+
react-hook-form's: by the time it fires, `getValues` already returns the new
|
|
5614
|
+
value.</div>
|
|
5615
|
+
<pre><code>const InputPropsChaining = () => <MobileForm />;</code></pre>
|
|
5616
|
+
</div>
|
|
5617
|
+
<div class="note ok">
|
|
5618
|
+
<div class="row">
|
|
5619
|
+
<span class="ex-name">Horizontal</span>
|
|
5620
|
+
<span class="badge ok">story ok</span>
|
|
5621
|
+
</div>
|
|
5622
|
+
<div>Horizontal orientation and class names through the root props</div>
|
|
5623
|
+
<div class="hint">Root props pass through: `orientation="horizontal"` lays the label and the
|
|
5624
|
+
control in a row, and `className` on the root or in `inputProps` sizes them.
|
|
5625
|
+
The `Input` is full-width by default, so a settings row gives it a width.
|
|
5626
|
+
`responsive` stacks the field below 28rem and rows it from there.</div>
|
|
5627
|
+
<pre><code>const Horizontal = () => <ProfileForm />;</code></pre>
|
|
5628
|
+
</div>
|
|
5629
|
+
<div class="note ok">
|
|
5630
|
+
<div class="row">
|
|
5631
|
+
<span class="ex-name">Disabled</span>
|
|
5632
|
+
<span class="badge ok">story ok</span>
|
|
5633
|
+
</div>
|
|
5634
|
+
<div>Disabled field whose value is still submitted</div>
|
|
5635
|
+
<div class="hint">`disabled` disables the input and marks the field, and the value still
|
|
5636
|
+
reaches `onSubmit` — unlike react-hook-form's own `disabled` option, which
|
|
5637
|
+
drops it. Use `readOnly` for a value the user can copy but not edit.</div>
|
|
5638
|
+
<pre><code>const Disabled = () => <AccountForm />;</code></pre>
|
|
5639
|
+
</div>
|
|
5640
|
+
<div class="note ok">
|
|
5641
|
+
<div class="row">
|
|
5642
|
+
<span class="ex-name">Set Focus</span>
|
|
5643
|
+
<span class="badge ok">story ok</span>
|
|
5644
|
+
</div>
|
|
5645
|
+
<div>setFocus reaches the input through the merged ref</div>
|
|
5646
|
+
<div class="hint">react-hook-form's `ref` reaches the `<input>`, so `setFocus` and the focus
|
|
5647
|
+
on the first invalid field after submit both work with no ref written by
|
|
5648
|
+
hand.</div>
|
|
5649
|
+
<pre><code>const SetFocus = () => <SetFocusForm />;</code></pre>
|
|
5650
|
+
</div>
|
|
5651
|
+
</div>
|
|
5652
|
+
|
|
5653
|
+
|
|
4490
5654
|
</div>
|
|
4491
5655
|
</article>
|
|
4492
5656
|
<article
|
|
@@ -4501,9 +5665,9 @@ actions outright unless the user needs to see them and understand why.</div>
|
|
|
4501
5665
|
<div class="title">
|
|
4502
5666
|
<h2><span class="status-dot dot-ok"></span> HoverCard.Root</h2>
|
|
4503
5667
|
<div class="badges">
|
|
4504
|
-
<label for="c-
|
|
5668
|
+
<label for="c-15-components-hovercard-props" class="badge ok as-toggle">6 prop types</label>
|
|
4505
5669
|
|
|
4506
|
-
<label for="c-
|
|
5670
|
+
<label for="c-15-components-hovercard-stories" class="badge ok as-toggle">7 stories</label>
|
|
4507
5671
|
|
|
4508
5672
|
|
|
4509
5673
|
</div>
|
|
@@ -4535,10 +5699,10 @@ import { HoverCard } from '@agentero/design-system/hover-card';
|
|
|
4535
5699
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
4536
5700
|
|
|
4537
5701
|
|
|
4538
|
-
<input id="c-
|
|
5702
|
+
<input id="c-15-components-hovercard-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4539
5703
|
|
|
4540
5704
|
|
|
4541
|
-
<input id="c-
|
|
5705
|
+
<input id="c-15-components-hovercard-props" class="tg tg-props" type="checkbox" hidden />
|
|
4542
5706
|
|
|
4543
5707
|
<div class="panels">
|
|
4544
5708
|
|
|
@@ -4785,23 +5949,24 @@ trigger-dense UIs where an instant preview reads as more responsive.</div>
|
|
|
4785
5949
|
<div class="title">
|
|
4786
5950
|
<h2><span class="status-dot dot-ok"></span> Input</h2>
|
|
4787
5951
|
<div class="badges">
|
|
4788
|
-
<label for="c-
|
|
5952
|
+
<label for="c-16-components-input-props" class="badge ok as-toggle">7 prop types</label>
|
|
4789
5953
|
|
|
4790
|
-
<label for="c-
|
|
5954
|
+
<label for="c-16-components-input-stories" class="badge ok as-toggle">9 stories</label>
|
|
4791
5955
|
|
|
4792
5956
|
|
|
4793
5957
|
</div>
|
|
4794
5958
|
</div>
|
|
4795
5959
|
<div class="meta" title="./src/input/input.stories.tsx">components-input · ./src/input/input.stories.tsx</div>
|
|
4796
|
-
<div>Base single-line text control
|
|
4797
|
-
<div class="hint">Input is the base single-line text control.
|
|
4798
|
-
|
|
4799
|
-
|
|
5960
|
+
<div>Base single-line text control that takes its wiring from InputContext</div>
|
|
5961
|
+
<div class="hint">Input is the base single-line text control. When a container such as
|
|
5962
|
+
`FieldText` provides `InputContext`, it picks up `id`, `aria-invalid` and
|
|
5963
|
+
`aria-describedby` on its own; standalone, as here, they are plain props set
|
|
5964
|
+
by hand.
|
|
4800
5965
|
|
|
4801
5966
|
There is no `status` prop. Mark the control `aria-invalid` and the
|
|
4802
5967
|
destructive border follows, so the styling can never disagree with what
|
|
4803
5968
|
assistive technology announces.</div>
|
|
4804
|
-
<div class="kv"><span class="chip">summary: Base single-line text control
|
|
5969
|
+
<div class="kv"><span class="chip">summary: Base single-line text control that takes its wiring from InputContext</span><span class="chip">example: <Label htmlFor="email">Email</Label>
|
|
4805
5970
|
<Input id="email" type="email" placeholder="you@example.com" /></span><span class="chip">example: <Input id="email" aria-invalid aria-describedby="email-error" />
|
|
4806
5971
|
<span id="email-error">Enter a valid email address.</span></span></div>
|
|
4807
5972
|
</div>
|
|
@@ -4809,10 +5974,10 @@ assistive technology announces.</div>
|
|
|
4809
5974
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
4810
5975
|
|
|
4811
5976
|
|
|
4812
|
-
<input id="c-
|
|
5977
|
+
<input id="c-16-components-input-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
4813
5978
|
|
|
4814
5979
|
|
|
4815
|
-
<input id="c-
|
|
5980
|
+
<input id="c-16-components-input-props" class="tg tg-props" type="checkbox" hidden />
|
|
4816
5981
|
|
|
4817
5982
|
<div class="panels">
|
|
4818
5983
|
|
|
@@ -5024,9 +6189,9 @@ they cannot change.</div>
|
|
|
5024
6189
|
<div class="title">
|
|
5025
6190
|
<h2><span class="status-dot dot-ok"></span> Label</h2>
|
|
5026
6191
|
<div class="badges">
|
|
5027
|
-
<label for="c-
|
|
6192
|
+
<label for="c-17-components-label-props" class="badge ok as-toggle">3 prop types</label>
|
|
5028
6193
|
|
|
5029
|
-
<label for="c-
|
|
6194
|
+
<label for="c-17-components-label-stories" class="badge ok as-toggle">5 stories</label>
|
|
5030
6195
|
|
|
5031
6196
|
|
|
5032
6197
|
</div>
|
|
@@ -5046,10 +6211,10 @@ still has to carry `required` / `aria-required`.</div>
|
|
|
5046
6211
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5047
6212
|
|
|
5048
6213
|
|
|
5049
|
-
<input id="c-
|
|
6214
|
+
<input id="c-17-components-label-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5050
6215
|
|
|
5051
6216
|
|
|
5052
|
-
<input id="c-
|
|
6217
|
+
<input id="c-17-components-label-props" class="tg tg-props" type="checkbox" hidden />
|
|
5053
6218
|
|
|
5054
6219
|
<div class="panels">
|
|
5055
6220
|
|
|
@@ -5085,7 +6250,7 @@ required?: boolean = false</code></pre>
|
|
|
5085
6250
|
<div class="row">
|
|
5086
6251
|
<span class="ex-name">Imports</span>
|
|
5087
6252
|
</div>
|
|
5088
|
-
<pre><code>import { Label } from "@agentero/design-system";</code></pre>
|
|
6253
|
+
<pre><code>import { Field, Label } from "@agentero/design-system";</code></pre>
|
|
5089
6254
|
</div>
|
|
5090
6255
|
|
|
5091
6256
|
|
|
@@ -5098,7 +6263,7 @@ required?: boolean = false</code></pre>
|
|
|
5098
6263
|
<div class="hint">A plain caption, associated with its control through `htmlFor`.</div>
|
|
5099
6264
|
<pre><code>const Default = () => <>
|
|
5100
6265
|
<Label htmlFor="email">Email</Label>
|
|
5101
|
-
<input id="email" placeholder="you@example.com" />
|
|
6266
|
+
<input id="email" placeholder="you@example.com" className={inputRecipe()} />
|
|
5102
6267
|
</>;</code></pre>
|
|
5103
6268
|
</div>
|
|
5104
6269
|
<div class="note ok">
|
|
@@ -5130,6 +6295,28 @@ required?: boolean = false</code></pre>
|
|
|
5130
6295
|
dropped, so a mistake never takes the page down.</div>
|
|
5131
6296
|
<pre><code>const RequiredWinsOverOptional = () => <Label optional required>Agency name</Label>;</code></pre>
|
|
5132
6297
|
</div>
|
|
6298
|
+
<div class="note ok">
|
|
6299
|
+
<div class="row">
|
|
6300
|
+
<span class="ex-name">Inside Field</span>
|
|
6301
|
+
<span class="badge ok">story ok</span>
|
|
6302
|
+
</div>
|
|
6303
|
+
<div>Inside a Field the label associates itself; explicit htmlFor wins</div>
|
|
6304
|
+
<div class="hint">Inside a `Field.Root` the label reads `LabelContext` and points at the
|
|
6305
|
+
field's control with no `htmlFor`. An explicit `htmlFor` still wins.</div>
|
|
6306
|
+
<pre><code>const InsideField = () => (
|
|
6307
|
+
<div className="flex flex-col gap-6">
|
|
6308
|
+
<Field.Root>
|
|
6309
|
+
<Label>Email</Label>
|
|
6310
|
+
<FieldInput />
|
|
6311
|
+
</Field.Root>
|
|
6312
|
+
|
|
6313
|
+
<Field.Root>
|
|
6314
|
+
<Label htmlFor="explicit-control">Phone</Label>
|
|
6315
|
+
<input id="explicit-control" className={inputRecipe()} />
|
|
6316
|
+
</Field.Root>
|
|
6317
|
+
</div>
|
|
6318
|
+
);</code></pre>
|
|
6319
|
+
</div>
|
|
5133
6320
|
</div>
|
|
5134
6321
|
|
|
5135
6322
|
|
|
@@ -5147,9 +6334,9 @@ dropped, so a mistake never takes the page down.</div>
|
|
|
5147
6334
|
<div class="title">
|
|
5148
6335
|
<h2><span class="status-dot dot-ok"></span> Loading</h2>
|
|
5149
6336
|
<div class="badges">
|
|
5150
|
-
<label for="c-
|
|
6337
|
+
<label for="c-18-components-loading-props" class="badge ok as-toggle">1 prop type</label>
|
|
5151
6338
|
|
|
5152
|
-
<label for="c-
|
|
6339
|
+
<label for="c-18-components-loading-stories" class="badge ok as-toggle">7 stories</label>
|
|
5153
6340
|
|
|
5154
6341
|
|
|
5155
6342
|
</div>
|
|
@@ -5166,10 +6353,10 @@ parent font size via `em`-based size variants (`sm`, `md`, `lg`).</div>
|
|
|
5166
6353
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5167
6354
|
|
|
5168
6355
|
|
|
5169
|
-
<input id="c-
|
|
6356
|
+
<input id="c-18-components-loading-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5170
6357
|
|
|
5171
6358
|
|
|
5172
|
-
<input id="c-
|
|
6359
|
+
<input id="c-18-components-loading-props" class="tg tg-props" type="checkbox" hidden />
|
|
5173
6360
|
|
|
5174
6361
|
<div class="panels">
|
|
5175
6362
|
|
|
@@ -5320,9 +6507,9 @@ against the dark background.</div>
|
|
|
5320
6507
|
<div class="title">
|
|
5321
6508
|
<h2><span class="status-dot dot-ok"></span> Modal.Root</h2>
|
|
5322
6509
|
<div class="badges">
|
|
5323
|
-
<label for="c-
|
|
6510
|
+
<label for="c-19-components-modal-props" class="badge ok as-toggle">5 prop types</label>
|
|
5324
6511
|
|
|
5325
|
-
<label for="c-
|
|
6512
|
+
<label for="c-19-components-modal-stories" class="badge ok as-toggle">6 stories</label>
|
|
5326
6513
|
|
|
5327
6514
|
|
|
5328
6515
|
</div>
|
|
@@ -5368,10 +6555,10 @@ import { Modal } from '@agentero/design-system/modal';
|
|
|
5368
6555
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5369
6556
|
|
|
5370
6557
|
|
|
5371
|
-
<input id="c-
|
|
6558
|
+
<input id="c-19-components-modal-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5372
6559
|
|
|
5373
6560
|
|
|
5374
|
-
<input id="c-
|
|
6561
|
+
<input id="c-19-components-modal-props" class="tg tg-props" type="checkbox" hidden />
|
|
5375
6562
|
|
|
5376
6563
|
<div class="panels">
|
|
5377
6564
|
|
|
@@ -5568,9 +6755,9 @@ announced as an `alertdialog`. Only the footer actions close it.</div>
|
|
|
5568
6755
|
<div class="title">
|
|
5569
6756
|
<h2><span class="status-dot dot-ok"></span> Pagination</h2>
|
|
5570
6757
|
<div class="badges">
|
|
5571
|
-
<label for="c-
|
|
6758
|
+
<label for="c-20-components-pagination-props" class="badge ok as-toggle">5 prop types</label>
|
|
5572
6759
|
|
|
5573
|
-
<label for="c-
|
|
6760
|
+
<label for="c-20-components-pagination-stories" class="badge ok as-toggle">7 stories</label>
|
|
5574
6761
|
|
|
5575
6762
|
|
|
5576
6763
|
</div>
|
|
@@ -5600,10 +6787,10 @@ const [page, setPage] = useState(1);
|
|
|
5600
6787
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5601
6788
|
|
|
5602
6789
|
|
|
5603
|
-
<input id="c-
|
|
6790
|
+
<input id="c-20-components-pagination-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5604
6791
|
|
|
5605
6792
|
|
|
5606
|
-
<input id="c-
|
|
6793
|
+
<input id="c-20-components-pagination-props" class="tg tg-props" type="checkbox" hidden />
|
|
5607
6794
|
|
|
5608
6795
|
<div class="panels">
|
|
5609
6796
|
|
|
@@ -5758,9 +6945,9 @@ entries summary follow along.</div>
|
|
|
5758
6945
|
<div class="title">
|
|
5759
6946
|
<h2><span class="status-dot dot-ok"></span> Popover.Root</h2>
|
|
5760
6947
|
<div class="badges">
|
|
5761
|
-
<label for="c-
|
|
6948
|
+
<label for="c-21-components-popover-props" class="badge ok as-toggle">5 prop types</label>
|
|
5762
6949
|
|
|
5763
|
-
<label for="c-
|
|
6950
|
+
<label for="c-21-components-popover-stories" class="badge ok as-toggle">5 stories</label>
|
|
5764
6951
|
|
|
5765
6952
|
|
|
5766
6953
|
</div>
|
|
@@ -5789,10 +6976,10 @@ import { Popover } from '@agentero/design-system/popover';
|
|
|
5789
6976
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
5790
6977
|
|
|
5791
6978
|
|
|
5792
|
-
<input id="c-
|
|
6979
|
+
<input id="c-21-components-popover-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
5793
6980
|
|
|
5794
6981
|
|
|
5795
|
-
<input id="c-
|
|
6982
|
+
<input id="c-21-components-popover-props" class="tg tg-props" type="checkbox" hidden />
|
|
5796
6983
|
|
|
5797
6984
|
<div class="panels">
|
|
5798
6985
|
|
|
@@ -5991,9 +7178,9 @@ focus returning to its trigger once the modal closes.</div>
|
|
|
5991
7178
|
<div class="title">
|
|
5992
7179
|
<h2><span class="status-dot dot-ok"></span> Progress</h2>
|
|
5993
7180
|
<div class="badges">
|
|
5994
|
-
<label for="c-
|
|
7181
|
+
<label for="c-22-components-progress-props" class="badge ok as-toggle">4 prop types</label>
|
|
5995
7182
|
|
|
5996
|
-
<label for="c-
|
|
7183
|
+
<label for="c-22-components-progress-stories" class="badge ok as-toggle">4 stories</label>
|
|
5997
7184
|
|
|
5998
7185
|
|
|
5999
7186
|
</div>
|
|
@@ -6012,10 +7199,10 @@ with `currentColor`, so recolor it with a plain text class — e.g.
|
|
|
6012
7199
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
6013
7200
|
|
|
6014
7201
|
|
|
6015
|
-
<input id="c-
|
|
7202
|
+
<input id="c-22-components-progress-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6016
7203
|
|
|
6017
7204
|
|
|
6018
|
-
<input id="c-
|
|
7205
|
+
<input id="c-22-components-progress-props" class="tg tg-props" type="checkbox" hidden />
|
|
6019
7206
|
|
|
6020
7207
|
<div class="panels">
|
|
6021
7208
|
|
|
@@ -6134,7 +7321,7 @@ percentage: number</code></pre>
|
|
|
6134
7321
|
<div class="badges">
|
|
6135
7322
|
|
|
6136
7323
|
|
|
6137
|
-
<label for="c-
|
|
7324
|
+
<label for="c-23-components-skeleton-stories" class="badge ok as-toggle">4 stories</label>
|
|
6138
7325
|
|
|
6139
7326
|
|
|
6140
7327
|
</div>
|
|
@@ -6151,7 +7338,7 @@ shape it with Tailwind classes to mirror the content it stands in for.</div>
|
|
|
6151
7338
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
6152
7339
|
|
|
6153
7340
|
|
|
6154
|
-
<input id="c-
|
|
7341
|
+
<input id="c-23-components-skeleton-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6155
7342
|
|
|
6156
7343
|
|
|
6157
7344
|
|
|
@@ -6247,9 +7434,9 @@ shape it with Tailwind classes to mirror the content it stands in for.</div>
|
|
|
6247
7434
|
<div class="title">
|
|
6248
7435
|
<h2><span class="status-dot dot-ok"></span> Switch</h2>
|
|
6249
7436
|
<div class="badges">
|
|
6250
|
-
<label for="c-
|
|
7437
|
+
<label for="c-24-components-switch-props" class="badge ok as-toggle">8 prop types</label>
|
|
6251
7438
|
|
|
6252
|
-
<label for="c-
|
|
7439
|
+
<label for="c-24-components-switch-stories" class="badge ok as-toggle">7 stories</label>
|
|
6253
7440
|
|
|
6254
7441
|
|
|
6255
7442
|
</div>
|
|
@@ -6265,10 +7452,10 @@ a Checkbox for a single boolean that applies instantly, and pair it with a
|
|
|
6265
7452
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
6266
7453
|
|
|
6267
7454
|
|
|
6268
|
-
<input id="c-
|
|
7455
|
+
<input id="c-24-components-switch-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6269
7456
|
|
|
6270
7457
|
|
|
6271
|
-
<input id="c-
|
|
7458
|
+
<input id="c-24-components-switch-props" class="tg tg-props" type="checkbox" hidden />
|
|
6272
7459
|
|
|
6273
7460
|
<div class="panels">
|
|
6274
7461
|
|
|
@@ -6449,9 +7636,9 @@ size?: "sm" | "md"</code></pre>
|
|
|
6449
7636
|
<div class="title">
|
|
6450
7637
|
<h2><span class="status-dot dot-ok"></span> Table.Root</h2>
|
|
6451
7638
|
<div class="badges">
|
|
6452
|
-
<label for="c-
|
|
7639
|
+
<label for="c-25-components-table-props" class="badge ok as-toggle">6 prop types</label>
|
|
6453
7640
|
|
|
6454
|
-
<label for="c-
|
|
7641
|
+
<label for="c-25-components-table-stories" class="badge ok as-toggle">9 stories</label>
|
|
6455
7642
|
|
|
6456
7643
|
|
|
6457
7644
|
</div>
|
|
@@ -6482,10 +7669,10 @@ import { Table } from '@agentero/design-system/table';
|
|
|
6482
7669
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
6483
7670
|
|
|
6484
7671
|
|
|
6485
|
-
<input id="c-
|
|
7672
|
+
<input id="c-25-components-table-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6486
7673
|
|
|
6487
7674
|
|
|
6488
|
-
<input id="c-
|
|
7675
|
+
<input id="c-25-components-table-props" class="tg tg-props" type="checkbox" hidden />
|
|
6489
7676
|
|
|
6490
7677
|
<div class="panels">
|
|
6491
7678
|
|
|
@@ -6680,9 +7867,9 @@ import { Fragment } from "react";</code></pre>
|
|
|
6680
7867
|
<div class="title">
|
|
6681
7868
|
<h2><span class="status-dot dot-ok"></span> Tabs.Root</h2>
|
|
6682
7869
|
<div class="badges">
|
|
6683
|
-
<label for="c-
|
|
7870
|
+
<label for="c-26-components-tabs-props" class="badge ok as-toggle">9 prop types</label>
|
|
6684
7871
|
|
|
6685
|
-
<label for="c-
|
|
7872
|
+
<label for="c-26-components-tabs-stories" class="badge ok as-toggle">8 stories</label>
|
|
6686
7873
|
|
|
6687
7874
|
|
|
6688
7875
|
</div>
|
|
@@ -6713,10 +7900,10 @@ import { Tabs } from '@agentero/design-system/tabs';
|
|
|
6713
7900
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
6714
7901
|
|
|
6715
7902
|
|
|
6716
|
-
<input id="c-
|
|
7903
|
+
<input id="c-26-components-tabs-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6717
7904
|
|
|
6718
7905
|
|
|
6719
|
-
<input id="c-
|
|
7906
|
+
<input id="c-26-components-tabs-props" class="tg tg-props" type="checkbox" hidden />
|
|
6720
7907
|
|
|
6721
7908
|
<div class="panels">
|
|
6722
7909
|
|
|
@@ -6937,9 +8124,9 @@ tablist role is announced.</div>
|
|
|
6937
8124
|
<div class="title">
|
|
6938
8125
|
<h2><span class="status-dot dot-ok"></span> Tag</h2>
|
|
6939
8126
|
<div class="badges">
|
|
6940
|
-
<label for="c-
|
|
8127
|
+
<label for="c-27-components-tag-props" class="badge ok as-toggle">8 prop types</label>
|
|
6941
8128
|
|
|
6942
|
-
<label for="c-
|
|
8129
|
+
<label for="c-27-components-tag-stories" class="badge ok as-toggle">12 stories</label>
|
|
6943
8130
|
|
|
6944
8131
|
|
|
6945
8132
|
</div>
|
|
@@ -6958,10 +8145,10 @@ it an interactive link or button, which adds the pointer cursor and hover fill.<
|
|
|
6958
8145
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
6959
8146
|
|
|
6960
8147
|
|
|
6961
|
-
<input id="c-
|
|
8148
|
+
<input id="c-27-components-tag-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
6962
8149
|
|
|
6963
8150
|
|
|
6964
|
-
<input id="c-
|
|
8151
|
+
<input id="c-27-components-tag-props" class="tg tg-props" type="checkbox" hidden />
|
|
6965
8152
|
|
|
6966
8153
|
<div class="panels">
|
|
6967
8154
|
|
|
@@ -7386,9 +8573,9 @@ leading + trailing icons, and icon-only.</div>
|
|
|
7386
8573
|
<div class="title">
|
|
7387
8574
|
<h2><span class="status-dot dot-ok"></span> Toast</h2>
|
|
7388
8575
|
<div class="badges">
|
|
7389
|
-
<label for="c-
|
|
8576
|
+
<label for="c-28-components-toast-props" class="badge ok as-toggle">11 prop types</label>
|
|
7390
8577
|
|
|
7391
|
-
<label for="c-
|
|
8578
|
+
<label for="c-28-components-toast-stories" class="badge ok as-toggle">11 stories</label>
|
|
7392
8579
|
|
|
7393
8580
|
|
|
7394
8581
|
</div>
|
|
@@ -7407,10 +8594,10 @@ common feedback patterns.</div>
|
|
|
7407
8594
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
7408
8595
|
|
|
7409
8596
|
|
|
7410
|
-
<input id="c-
|
|
8597
|
+
<input id="c-28-components-toast-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
7411
8598
|
|
|
7412
8599
|
|
|
7413
|
-
<input id="c-
|
|
8600
|
+
<input id="c-28-components-toast-props" class="tg tg-props" type="checkbox" hidden />
|
|
7414
8601
|
|
|
7415
8602
|
<div class="panels">
|
|
7416
8603
|
|
|
@@ -7839,9 +9026,9 @@ action (e.g., a sync icon for a sync-in-progress toast).</div>
|
|
|
7839
9026
|
<div class="title">
|
|
7840
9027
|
<h2><span class="status-dot dot-ok"></span> Tooltip</h2>
|
|
7841
9028
|
<div class="badges">
|
|
7842
|
-
<label for="c-
|
|
9029
|
+
<label for="c-29-components-tooltip-props" class="badge ok as-toggle">12 prop types</label>
|
|
7843
9030
|
|
|
7844
|
-
<label for="c-
|
|
9031
|
+
<label for="c-29-components-tooltip-stories" class="badge ok as-toggle">5 stories</label>
|
|
7845
9032
|
|
|
7846
9033
|
|
|
7847
9034
|
</div>
|
|
@@ -7860,10 +9047,10 @@ on hover or focus.</div>
|
|
|
7860
9047
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
7861
9048
|
|
|
7862
9049
|
|
|
7863
|
-
<input id="c-
|
|
9050
|
+
<input id="c-29-components-tooltip-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
7864
9051
|
|
|
7865
9052
|
|
|
7866
|
-
<input id="c-
|
|
9053
|
+
<input id="c-29-components-tooltip-props" class="tg tg-props" type="checkbox" hidden />
|
|
7867
9054
|
|
|
7868
9055
|
<div class="panels">
|
|
7869
9056
|
|
|
@@ -8035,9 +9222,9 @@ sideOffset?: number = 4</code></pre>
|
|
|
8035
9222
|
<div class="title">
|
|
8036
9223
|
<h2><span class="status-dot dot-ok"></span> ValidationList</h2>
|
|
8037
9224
|
<div class="badges">
|
|
8038
|
-
<label for="c-
|
|
9225
|
+
<label for="c-30-components-validationlist-props" class="badge ok as-toggle">2 prop types</label>
|
|
8039
9226
|
|
|
8040
|
-
<label for="c-
|
|
9227
|
+
<label for="c-30-components-validationlist-stories" class="badge ok as-toggle">4 stories</label>
|
|
8041
9228
|
|
|
8042
9229
|
|
|
8043
9230
|
</div>
|
|
@@ -8058,10 +9245,10 @@ your form validation; it does not own the input or block submission.</div>
|
|
|
8058
9245
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
8059
9246
|
|
|
8060
9247
|
|
|
8061
|
-
<input id="c-
|
|
9248
|
+
<input id="c-30-components-validationlist-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
8062
9249
|
|
|
8063
9250
|
|
|
8064
|
-
<input id="c-
|
|
9251
|
+
<input id="c-30-components-validationlist-props" class="tg tg-props" type="checkbox" hidden />
|
|
8065
9252
|
|
|
8066
9253
|
<div class="panels">
|
|
8067
9254
|
|