@agentero/design-system 0.34.2 → 0.35.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/mcp/manifests/components.html +324 -60
- package/mcp/manifests/components.json +149 -1
- package/package.json +5 -1
- package/src/input-tel/index.d.ts +2 -0
- package/src/input-tel/index.js +2 -0
- package/src/input-tel/input-tel.d.ts +42 -0
- package/src/input-tel/input-tel.js +46 -0
- package/src/input-tel/mask.d.ts +51 -0
- package/src/input-tel/mask.js +39 -0
|
@@ -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">37 components ok</span><span class="filter-pill ok" aria-disabled="true">305 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>
|
|
597
|
+
Using <code>react-component-meta</code>. Generation took <strong>5.0s</strong>.
|
|
598
598
|
</div>
|
|
599
599
|
<h2 class="section-title">Components</h2>
|
|
600
600
|
<div class="grid" role="list">
|
|
@@ -7901,6 +7901,270 @@ several search fields does not read "Clear search" twice.</div>
|
|
|
7901
7901
|
</div>
|
|
7902
7902
|
|
|
7903
7903
|
|
|
7904
|
+
</div>
|
|
7905
|
+
</article>
|
|
7906
|
+
<article
|
|
7907
|
+
class="card
|
|
7908
|
+
no-error
|
|
7909
|
+
no-info
|
|
7910
|
+
no-story-error
|
|
7911
|
+
no-doc-error"
|
|
7912
|
+
role="listitem"
|
|
7913
|
+
aria-label="InputTel">
|
|
7914
|
+
<div class="head">
|
|
7915
|
+
<div class="title">
|
|
7916
|
+
<h2><span class="status-dot dot-ok"></span> InputTel</h2>
|
|
7917
|
+
<div class="badges">
|
|
7918
|
+
<label for="c-21-components-inputtel-props" class="badge ok as-toggle">1 prop type</label>
|
|
7919
|
+
|
|
7920
|
+
<label for="c-21-components-inputtel-stories" class="badge ok as-toggle">11 stories</label>
|
|
7921
|
+
|
|
7922
|
+
|
|
7923
|
+
</div>
|
|
7924
|
+
</div>
|
|
7925
|
+
<div class="meta" title="./src/input-tel/input-tel.stories.tsx">components-inputtel · ./src/input-tel/input-tel.stories.tsx</div>
|
|
7926
|
+
<div>US phone input with a +1 prefix that masks as you type</div>
|
|
7927
|
+
<div class="hint">InputTel is a US phone number field that masks as you type: the digits are
|
|
7928
|
+
laid out as `(555) 123-4567`, anything else is dropped and the caret stays
|
|
7929
|
+
next to the digit just edited. It is an `Input` of `type="tel"` inside an
|
|
7930
|
+
`InputGroup` frame with a `+1` prefix; `onChange` receives the native event
|
|
7931
|
+
with the masked text already in `event.target.value`.</div>
|
|
7932
|
+
<div class="kv"><span class="chip">summary: US phone input with a +1 prefix that masks as you type</span><span class="chip">dataAttribute: {string} data-slot - Always set to "input-tel" on the frame</span><span class="chip">example: <FieldText>
|
|
7933
|
+
<Label>Phone number</Label>
|
|
7934
|
+
<InputTel name="phone" autoComplete="tel-national" placeholder="(555) 000-0000" />
|
|
7935
|
+
</FieldText></span></div>
|
|
7936
|
+
</div>
|
|
7937
|
+
|
|
7938
|
+
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
7939
|
+
|
|
7940
|
+
|
|
7941
|
+
<input id="c-21-components-inputtel-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
7942
|
+
|
|
7943
|
+
|
|
7944
|
+
<input id="c-21-components-inputtel-props" class="tg tg-props" type="checkbox" hidden />
|
|
7945
|
+
|
|
7946
|
+
<div class="panels">
|
|
7947
|
+
|
|
7948
|
+
|
|
7949
|
+
|
|
7950
|
+
<div class="panel panel-props">
|
|
7951
|
+
<div class="note ok">
|
|
7952
|
+
<div class="row">
|
|
7953
|
+
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
7954
|
+
<span class="badge ok">1 prop type</span>
|
|
7955
|
+
</div>
|
|
7956
|
+
<pre><code>Component: src/input-tel/input-tel.tsx::InputTel</code></pre>
|
|
7957
|
+
<pre><code>Props:</code></pre>
|
|
7958
|
+
<pre><code>/**
|
|
7959
|
+
* Control height. Defaults to `'md'`.
|
|
7960
|
+
* - `sm` (32px) — dense layouts where vertical space is tight.
|
|
7961
|
+
* - `md` (40px) — standard form density.
|
|
7962
|
+
* - `lg` (48px) — low-density forms and larger touch targets. Also raises
|
|
7963
|
+
* the text to `base` and the corner radius to `lg`.
|
|
7964
|
+
*/
|
|
7965
|
+
size?: "sm" | "md" | "lg"</code></pre>
|
|
7966
|
+
</div>
|
|
7967
|
+
</div>
|
|
7968
|
+
|
|
7969
|
+
<div class="panel panel-stories">
|
|
7970
|
+
|
|
7971
|
+
|
|
7972
|
+
|
|
7973
|
+
<div class="note ok">
|
|
7974
|
+
<div class="row">
|
|
7975
|
+
<span class="ex-name">Imports</span>
|
|
7976
|
+
</div>
|
|
7977
|
+
<pre><code>import { Button, Field, FieldText, InputContext, InputTel, Label } from "@agentero/design-system";</code></pre>
|
|
7978
|
+
</div>
|
|
7979
|
+
|
|
7980
|
+
|
|
7981
|
+
<div class="note ok">
|
|
7982
|
+
<div class="row">
|
|
7983
|
+
<span class="ex-name">Default</span>
|
|
7984
|
+
<span class="badge ok">story ok</span>
|
|
7985
|
+
</div>
|
|
7986
|
+
<div>Phone field with a +1 prefix masking the digits as they are typed</div>
|
|
7987
|
+
<div class="hint">An uncontrolled phone field with its `+1` prefix. Typing the ten digits lays
|
|
7988
|
+
them out as `(555) 123-4567`, and every `onChange` call carries the masked
|
|
7989
|
+
text in `event.target.value`; the prefix never enters the value.</div>
|
|
7990
|
+
<pre><code>const Default = () => <InputTel
|
|
7991
|
+
aria-label="Phone number"
|
|
7992
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;</code></pre>
|
|
7993
|
+
</div>
|
|
7994
|
+
<div class="note ok">
|
|
7995
|
+
<div class="row">
|
|
7996
|
+
<span class="ex-name">Controlled</span>
|
|
7997
|
+
<span class="badge ok">story ok</span>
|
|
7998
|
+
</div>
|
|
7999
|
+
<div>Controlled phone field storing the masked value</div>
|
|
8000
|
+
<div class="hint">A controlled phone field. The state that owns the value stores what
|
|
8001
|
+
`event.target.value` reports, which is already masked, and the input shows
|
|
8002
|
+
it back unchanged. A partial number carries the separator that comes before
|
|
8003
|
+
the next digit, so six digits read `(555) 123-`.</div>
|
|
8004
|
+
<pre><code>const Controlled = () => {
|
|
8005
|
+
const [phone, setPhone] = useState('');
|
|
8006
|
+
|
|
8007
|
+
return (
|
|
8008
|
+
<InputTel
|
|
8009
|
+
aria-label="Phone number"
|
|
8010
|
+
value={phone}
|
|
8011
|
+
onChange={event => {
|
|
8012
|
+
setPhone(event.target.value);
|
|
8013
|
+
args.onChange?.(event);
|
|
8014
|
+
}} />
|
|
8015
|
+
);
|
|
8016
|
+
};</code></pre>
|
|
8017
|
+
</div>
|
|
8018
|
+
<div class="note ok">
|
|
8019
|
+
<div class="row">
|
|
8020
|
+
<span class="ex-name">Caret In The Middle</span>
|
|
8021
|
+
<span class="badge ok">story ok</span>
|
|
8022
|
+
</div>
|
|
8023
|
+
<div>Caret staying put when a digit is inserted mid-number</div>
|
|
8024
|
+
<div class="hint">Editing in the middle of a full number: a digit typed after `(5` shifts the
|
|
8025
|
+
rest right, the eleventh digit falls off the end and the caret stays after
|
|
8026
|
+
the digit just typed instead of jumping to the end.</div>
|
|
8027
|
+
<pre><code>const CaretInTheMiddle = () => <InputTel
|
|
8028
|
+
aria-label="Phone number"
|
|
8029
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;</code></pre>
|
|
8030
|
+
</div>
|
|
8031
|
+
<div class="note ok">
|
|
8032
|
+
<div class="row">
|
|
8033
|
+
<span class="ex-name">Backspace Over Mask Characters</span>
|
|
8034
|
+
<span class="badge ok">story ok</span>
|
|
8035
|
+
</div>
|
|
8036
|
+
<div>Backspace trimming the separators the mask added</div>
|
|
8037
|
+
<div class="hint">Backspace over the mask's own characters: after `555` the field shows
|
|
8038
|
+
`(555) `, and deleting backwards trims the separators along with the digit
|
|
8039
|
+
under the caret instead of leaving a dangling `) `.</div>
|
|
8040
|
+
<pre><code>const BackspaceOverMaskCharacters = () => <InputTel
|
|
8041
|
+
aria-label="Phone number"
|
|
8042
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;</code></pre>
|
|
8043
|
+
</div>
|
|
8044
|
+
<div class="note ok">
|
|
8045
|
+
<div class="row">
|
|
8046
|
+
<span class="ex-name">Paste</span>
|
|
8047
|
+
<span class="badge ok">story ok</span>
|
|
8048
|
+
</div>
|
|
8049
|
+
<div>Pasted number reduced to its digits and masked</div>
|
|
8050
|
+
<div class="hint">A pasted number in any format is reduced to its digits and masked, so
|
|
8051
|
+
`555-123-4567` from a clipboard ends up as `(555) 123-4567`.</div>
|
|
8052
|
+
<pre><code>const Paste = () => <InputTel
|
|
8053
|
+
aria-label="Phone number"
|
|
8054
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;</code></pre>
|
|
8055
|
+
</div>
|
|
8056
|
+
<div class="note ok">
|
|
8057
|
+
<div class="row">
|
|
8058
|
+
<span class="ex-name">Paste With Country Code</span>
|
|
8059
|
+
<span class="badge ok">story ok</span>
|
|
8060
|
+
</div>
|
|
8061
|
+
<div>Pasted number with a +1 country code</div>
|
|
8062
|
+
<div class="hint">A number that carries the `+1` country code, as copied from a signature or
|
|
8063
|
+
filled in by the browser's autofill, loses the code and keeps its ten
|
|
8064
|
+
national digits: `+1 (555) 123-4567` ends up as `(555) 123-4567`.</div>
|
|
8065
|
+
<pre><code>const PasteWithCountryCode = () => <InputTel
|
|
8066
|
+
aria-label="Phone number"
|
|
8067
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;</code></pre>
|
|
8068
|
+
</div>
|
|
8069
|
+
<div class="note ok">
|
|
8070
|
+
<div class="row">
|
|
8071
|
+
<span class="ex-name">Inside Field Text</span>
|
|
8072
|
+
<span class="badge ok">story ok</span>
|
|
8073
|
+
</div>
|
|
8074
|
+
<div>Label and description reaching the input through the field</div>
|
|
8075
|
+
<div class="hint">Inside a `FieldText` the input takes its label, description and states from
|
|
8076
|
+
the field, and the masked value still reaches a handler the field provides.</div>
|
|
8077
|
+
<pre><code>const InsideFieldText = () => (
|
|
8078
|
+
<FieldText>
|
|
8079
|
+
<Label>Phone number</Label>
|
|
8080
|
+
<InputTel />
|
|
8081
|
+
<Field.Description>We only call about your account.</Field.Description>
|
|
8082
|
+
</FieldText>
|
|
8083
|
+
);</code></pre>
|
|
8084
|
+
</div>
|
|
8085
|
+
<div class="note ok">
|
|
8086
|
+
<div class="row">
|
|
8087
|
+
<span class="ex-name">With React Hook Form</span>
|
|
8088
|
+
<span class="badge ok">story ok</span>
|
|
8089
|
+
</div>
|
|
8090
|
+
<div>Masked value reaching react-hook-form through register</div>
|
|
8091
|
+
<div class="hint">Registered with react-hook-form, the form receives the masked value: the
|
|
8092
|
+
`register` handler reads `event.target.value` like any other change.</div>
|
|
8093
|
+
<pre><code>const WithReactHookForm = () => {
|
|
8094
|
+
const { register, handleSubmit } = useForm<ContactValues>({
|
|
8095
|
+
defaultValues: { phone: '' }
|
|
8096
|
+
});
|
|
8097
|
+
|
|
8098
|
+
return (
|
|
8099
|
+
<form
|
|
8100
|
+
aria-label="Contact"
|
|
8101
|
+
noValidate
|
|
8102
|
+
onSubmit={handleSubmit(values => onSubmit(values))}
|
|
8103
|
+
style={{ display: 'grid', gap: '1rem' }}>
|
|
8104
|
+
<InputTel aria-label="Phone number" {...register('phone')} />
|
|
8105
|
+
<Button type="submit">Save</Button>
|
|
8106
|
+
</form>
|
|
8107
|
+
);
|
|
8108
|
+
};</code></pre>
|
|
8109
|
+
</div>
|
|
8110
|
+
<div class="note ok">
|
|
8111
|
+
<div class="row">
|
|
8112
|
+
<span class="ex-name">Disabled</span>
|
|
8113
|
+
<span class="badge ok">story ok</span>
|
|
8114
|
+
</div>
|
|
8115
|
+
<div>Disabled phone field</div>
|
|
8116
|
+
<div class="hint">A disabled phone field keeps its masked value and takes no input.</div>
|
|
8117
|
+
<pre><code>const Disabled = () => <InputTel
|
|
8118
|
+
aria-label="Phone number"
|
|
8119
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}
|
|
8120
|
+
disabled
|
|
8121
|
+
defaultValue="(555) 123-4567" />;</code></pre>
|
|
8122
|
+
</div>
|
|
8123
|
+
<div class="note ok">
|
|
8124
|
+
<div class="row">
|
|
8125
|
+
<span class="ex-name">Invalid</span>
|
|
8126
|
+
<span class="badge ok">story ok</span>
|
|
8127
|
+
</div>
|
|
8128
|
+
<div>Invalid field driving the frame's destructive border</div>
|
|
8129
|
+
<div class="hint">`invalid` on the surrounding `FieldText` sets `aria-invalid` on the input,
|
|
8130
|
+
which paints the frame's destructive border, and `Field.Error` is announced
|
|
8131
|
+
with the input.</div>
|
|
8132
|
+
<pre><code>const Invalid = () => (
|
|
8133
|
+
<FieldText invalid>
|
|
8134
|
+
<Label>Phone number</Label>
|
|
8135
|
+
<InputTel defaultValue="(555) 12" />
|
|
8136
|
+
<Field.Error errors={[{ message: 'Enter a 10-digit phone number.' }]} />
|
|
8137
|
+
</FieldText>
|
|
8138
|
+
);</code></pre>
|
|
8139
|
+
</div>
|
|
8140
|
+
<div class="note ok">
|
|
8141
|
+
<div class="row">
|
|
8142
|
+
<span class="ex-name">All Sizes</span>
|
|
8143
|
+
<span class="badge ok">story ok</span>
|
|
8144
|
+
</div>
|
|
8145
|
+
<div>The three sizes side by side</div>
|
|
8146
|
+
<div class="hint">The three sizes match Input's: the frame is 32, 40 or 48px tall.</div>
|
|
8147
|
+
<pre><code>const AllSizes = () => <div style={{ display: 'grid', gap: '1rem' }}>
|
|
8148
|
+
<InputTel
|
|
8149
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}
|
|
8150
|
+
size="sm"
|
|
8151
|
+
aria-label="Small"
|
|
8152
|
+
defaultValue="(555) 123-4567" />
|
|
8153
|
+
<InputTel
|
|
8154
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}
|
|
8155
|
+
size="md"
|
|
8156
|
+
aria-label="Medium"
|
|
8157
|
+
defaultValue="(555) 123-4567" />
|
|
8158
|
+
<InputTel
|
|
8159
|
+
onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}
|
|
8160
|
+
size="lg"
|
|
8161
|
+
aria-label="Large"
|
|
8162
|
+
defaultValue="(555) 123-4567" />
|
|
8163
|
+
</div>;</code></pre>
|
|
8164
|
+
</div>
|
|
8165
|
+
</div>
|
|
8166
|
+
|
|
8167
|
+
|
|
7904
8168
|
</div>
|
|
7905
8169
|
</article>
|
|
7906
8170
|
<article
|
|
@@ -7915,9 +8179,9 @@ several search fields does not read "Clear search" twice.</div>
|
|
|
7915
8179
|
<div class="title">
|
|
7916
8180
|
<h2><span class="status-dot dot-ok"></span> Label</h2>
|
|
7917
8181
|
<div class="badges">
|
|
7918
|
-
<label for="c-
|
|
8182
|
+
<label for="c-22-components-label-props" class="badge ok as-toggle">3 prop types</label>
|
|
7919
8183
|
|
|
7920
|
-
<label for="c-
|
|
8184
|
+
<label for="c-22-components-label-stories" class="badge ok as-toggle">5 stories</label>
|
|
7921
8185
|
|
|
7922
8186
|
|
|
7923
8187
|
</div>
|
|
@@ -7937,10 +8201,10 @@ still has to carry `required` / `aria-required`.</div>
|
|
|
7937
8201
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
7938
8202
|
|
|
7939
8203
|
|
|
7940
|
-
<input id="c-
|
|
8204
|
+
<input id="c-22-components-label-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
7941
8205
|
|
|
7942
8206
|
|
|
7943
|
-
<input id="c-
|
|
8207
|
+
<input id="c-22-components-label-props" class="tg tg-props" type="checkbox" hidden />
|
|
7944
8208
|
|
|
7945
8209
|
<div class="panels">
|
|
7946
8210
|
|
|
@@ -8064,9 +8328,9 @@ field's control with no `htmlFor`. An explicit `htmlFor` still wins.</div>
|
|
|
8064
8328
|
<div class="title">
|
|
8065
8329
|
<h2><span class="status-dot dot-ok"></span> Loading</h2>
|
|
8066
8330
|
<div class="badges">
|
|
8067
|
-
<label for="c-
|
|
8331
|
+
<label for="c-23-components-loading-props" class="badge ok as-toggle">1 prop type</label>
|
|
8068
8332
|
|
|
8069
|
-
<label for="c-
|
|
8333
|
+
<label for="c-23-components-loading-stories" class="badge ok as-toggle">7 stories</label>
|
|
8070
8334
|
|
|
8071
8335
|
|
|
8072
8336
|
</div>
|
|
@@ -8083,10 +8347,10 @@ parent font size via `em`-based size variants (`sm`, `md`, `lg`).</div>
|
|
|
8083
8347
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
8084
8348
|
|
|
8085
8349
|
|
|
8086
|
-
<input id="c-
|
|
8350
|
+
<input id="c-23-components-loading-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
8087
8351
|
|
|
8088
8352
|
|
|
8089
|
-
<input id="c-
|
|
8353
|
+
<input id="c-23-components-loading-props" class="tg tg-props" type="checkbox" hidden />
|
|
8090
8354
|
|
|
8091
8355
|
<div class="panels">
|
|
8092
8356
|
|
|
@@ -8237,9 +8501,9 @@ against the dark background.</div>
|
|
|
8237
8501
|
<div class="title">
|
|
8238
8502
|
<h2><span class="status-dot dot-ok"></span> Modal.Root</h2>
|
|
8239
8503
|
<div class="badges">
|
|
8240
|
-
<label for="c-
|
|
8504
|
+
<label for="c-24-components-modal-props" class="badge ok as-toggle">5 prop types</label>
|
|
8241
8505
|
|
|
8242
|
-
<label for="c-
|
|
8506
|
+
<label for="c-24-components-modal-stories" class="badge ok as-toggle">6 stories</label>
|
|
8243
8507
|
|
|
8244
8508
|
|
|
8245
8509
|
</div>
|
|
@@ -8285,10 +8549,10 @@ import { Modal } from '@agentero/design-system/modal';
|
|
|
8285
8549
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
8286
8550
|
|
|
8287
8551
|
|
|
8288
|
-
<input id="c-
|
|
8552
|
+
<input id="c-24-components-modal-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
8289
8553
|
|
|
8290
8554
|
|
|
8291
|
-
<input id="c-
|
|
8555
|
+
<input id="c-24-components-modal-props" class="tg tg-props" type="checkbox" hidden />
|
|
8292
8556
|
|
|
8293
8557
|
<div class="panels">
|
|
8294
8558
|
|
|
@@ -8508,9 +8772,9 @@ announced as an `alertdialog`. Only the footer actions close it.</div>
|
|
|
8508
8772
|
<div class="title">
|
|
8509
8773
|
<h2><span class="status-dot dot-ok"></span> Pagination</h2>
|
|
8510
8774
|
<div class="badges">
|
|
8511
|
-
<label for="c-
|
|
8775
|
+
<label for="c-25-components-pagination-props" class="badge ok as-toggle">5 prop types</label>
|
|
8512
8776
|
|
|
8513
|
-
<label for="c-
|
|
8777
|
+
<label for="c-25-components-pagination-stories" class="badge ok as-toggle">7 stories</label>
|
|
8514
8778
|
|
|
8515
8779
|
|
|
8516
8780
|
</div>
|
|
@@ -8540,10 +8804,10 @@ const [page, setPage] = useState(1);
|
|
|
8540
8804
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
8541
8805
|
|
|
8542
8806
|
|
|
8543
|
-
<input id="c-
|
|
8807
|
+
<input id="c-25-components-pagination-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
8544
8808
|
|
|
8545
8809
|
|
|
8546
|
-
<input id="c-
|
|
8810
|
+
<input id="c-25-components-pagination-props" class="tg tg-props" type="checkbox" hidden />
|
|
8547
8811
|
|
|
8548
8812
|
<div class="panels">
|
|
8549
8813
|
|
|
@@ -8698,9 +8962,9 @@ entries summary follow along.</div>
|
|
|
8698
8962
|
<div class="title">
|
|
8699
8963
|
<h2><span class="status-dot dot-ok"></span> Popover.Root</h2>
|
|
8700
8964
|
<div class="badges">
|
|
8701
|
-
<label for="c-
|
|
8965
|
+
<label for="c-26-components-popover-props" class="badge ok as-toggle">5 prop types</label>
|
|
8702
8966
|
|
|
8703
|
-
<label for="c-
|
|
8967
|
+
<label for="c-26-components-popover-stories" class="badge ok as-toggle">5 stories</label>
|
|
8704
8968
|
|
|
8705
8969
|
|
|
8706
8970
|
</div>
|
|
@@ -8729,10 +8993,10 @@ import { Popover } from '@agentero/design-system/popover';
|
|
|
8729
8993
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
8730
8994
|
|
|
8731
8995
|
|
|
8732
|
-
<input id="c-
|
|
8996
|
+
<input id="c-26-components-popover-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
8733
8997
|
|
|
8734
8998
|
|
|
8735
|
-
<input id="c-
|
|
8999
|
+
<input id="c-26-components-popover-props" class="tg tg-props" type="checkbox" hidden />
|
|
8736
9000
|
|
|
8737
9001
|
<div class="panels">
|
|
8738
9002
|
|
|
@@ -8931,9 +9195,9 @@ focus returning to its trigger once the modal closes.</div>
|
|
|
8931
9195
|
<div class="title">
|
|
8932
9196
|
<h2><span class="status-dot dot-ok"></span> Progress</h2>
|
|
8933
9197
|
<div class="badges">
|
|
8934
|
-
<label for="c-
|
|
9198
|
+
<label for="c-27-components-progress-props" class="badge ok as-toggle">4 prop types</label>
|
|
8935
9199
|
|
|
8936
|
-
<label for="c-
|
|
9200
|
+
<label for="c-27-components-progress-stories" class="badge ok as-toggle">4 stories</label>
|
|
8937
9201
|
|
|
8938
9202
|
|
|
8939
9203
|
</div>
|
|
@@ -8952,10 +9216,10 @@ with `currentColor`, so recolor it with a plain text class — e.g.
|
|
|
8952
9216
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
8953
9217
|
|
|
8954
9218
|
|
|
8955
|
-
<input id="c-
|
|
9219
|
+
<input id="c-27-components-progress-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
8956
9220
|
|
|
8957
9221
|
|
|
8958
|
-
<input id="c-
|
|
9222
|
+
<input id="c-27-components-progress-props" class="tg tg-props" type="checkbox" hidden />
|
|
8959
9223
|
|
|
8960
9224
|
<div class="panels">
|
|
8961
9225
|
|
|
@@ -9074,7 +9338,7 @@ percentage: number</code></pre>
|
|
|
9074
9338
|
<div class="badges">
|
|
9075
9339
|
|
|
9076
9340
|
|
|
9077
|
-
<label for="c-
|
|
9341
|
+
<label for="c-28-components-skeleton-stories" class="badge ok as-toggle">4 stories</label>
|
|
9078
9342
|
|
|
9079
9343
|
|
|
9080
9344
|
</div>
|
|
@@ -9091,7 +9355,7 @@ shape it with Tailwind classes to mirror the content it stands in for.</div>
|
|
|
9091
9355
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
9092
9356
|
|
|
9093
9357
|
|
|
9094
|
-
<input id="c-
|
|
9358
|
+
<input id="c-28-components-skeleton-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
9095
9359
|
|
|
9096
9360
|
|
|
9097
9361
|
|
|
@@ -9187,9 +9451,9 @@ shape it with Tailwind classes to mirror the content it stands in for.</div>
|
|
|
9187
9451
|
<div class="title">
|
|
9188
9452
|
<h2><span class="status-dot dot-ok"></span> Switch</h2>
|
|
9189
9453
|
<div class="badges">
|
|
9190
|
-
<label for="c-
|
|
9454
|
+
<label for="c-29-components-switch-props" class="badge ok as-toggle">8 prop types</label>
|
|
9191
9455
|
|
|
9192
|
-
<label for="c-
|
|
9456
|
+
<label for="c-29-components-switch-stories" class="badge ok as-toggle">7 stories</label>
|
|
9193
9457
|
|
|
9194
9458
|
|
|
9195
9459
|
</div>
|
|
@@ -9205,10 +9469,10 @@ a Checkbox for a single boolean that applies instantly, and pair it with a
|
|
|
9205
9469
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
9206
9470
|
|
|
9207
9471
|
|
|
9208
|
-
<input id="c-
|
|
9472
|
+
<input id="c-29-components-switch-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
9209
9473
|
|
|
9210
9474
|
|
|
9211
|
-
<input id="c-
|
|
9475
|
+
<input id="c-29-components-switch-props" class="tg tg-props" type="checkbox" hidden />
|
|
9212
9476
|
|
|
9213
9477
|
<div class="panels">
|
|
9214
9478
|
|
|
@@ -9389,9 +9653,9 @@ size?: "sm" | "md"</code></pre>
|
|
|
9389
9653
|
<div class="title">
|
|
9390
9654
|
<h2><span class="status-dot dot-ok"></span> Table.Root</h2>
|
|
9391
9655
|
<div class="badges">
|
|
9392
|
-
<label for="c-
|
|
9656
|
+
<label for="c-30-components-table-props" class="badge ok as-toggle">6 prop types</label>
|
|
9393
9657
|
|
|
9394
|
-
<label for="c-
|
|
9658
|
+
<label for="c-30-components-table-stories" class="badge ok as-toggle">10 stories</label>
|
|
9395
9659
|
|
|
9396
9660
|
|
|
9397
9661
|
</div>
|
|
@@ -9422,10 +9686,10 @@ import { Table } from '@agentero/design-system/table';
|
|
|
9422
9686
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
9423
9687
|
|
|
9424
9688
|
|
|
9425
|
-
<input id="c-
|
|
9689
|
+
<input id="c-30-components-table-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
9426
9690
|
|
|
9427
9691
|
|
|
9428
|
-
<input id="c-
|
|
9692
|
+
<input id="c-30-components-table-props" class="tg tg-props" type="checkbox" hidden />
|
|
9429
9693
|
|
|
9430
9694
|
<div class="panels">
|
|
9431
9695
|
|
|
@@ -9643,9 +9907,9 @@ keeps its padding.</div>
|
|
|
9643
9907
|
<div class="title">
|
|
9644
9908
|
<h2><span class="status-dot dot-ok"></span> Tabs.Root</h2>
|
|
9645
9909
|
<div class="badges">
|
|
9646
|
-
<label for="c-
|
|
9910
|
+
<label for="c-31-components-tabs-props" class="badge ok as-toggle">9 prop types</label>
|
|
9647
9911
|
|
|
9648
|
-
<label for="c-
|
|
9912
|
+
<label for="c-31-components-tabs-stories" class="badge ok as-toggle">8 stories</label>
|
|
9649
9913
|
|
|
9650
9914
|
|
|
9651
9915
|
</div>
|
|
@@ -9676,10 +9940,10 @@ import { Tabs } from '@agentero/design-system/tabs';
|
|
|
9676
9940
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
9677
9941
|
|
|
9678
9942
|
|
|
9679
|
-
<input id="c-
|
|
9943
|
+
<input id="c-31-components-tabs-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
9680
9944
|
|
|
9681
9945
|
|
|
9682
|
-
<input id="c-
|
|
9946
|
+
<input id="c-31-components-tabs-props" class="tg tg-props" type="checkbox" hidden />
|
|
9683
9947
|
|
|
9684
9948
|
<div class="panels">
|
|
9685
9949
|
|
|
@@ -9900,9 +10164,9 @@ tablist role is announced.</div>
|
|
|
9900
10164
|
<div class="title">
|
|
9901
10165
|
<h2><span class="status-dot dot-ok"></span> Tag</h2>
|
|
9902
10166
|
<div class="badges">
|
|
9903
|
-
<label for="c-
|
|
10167
|
+
<label for="c-32-components-tag-props" class="badge ok as-toggle">8 prop types</label>
|
|
9904
10168
|
|
|
9905
|
-
<label for="c-
|
|
10169
|
+
<label for="c-32-components-tag-stories" class="badge ok as-toggle">12 stories</label>
|
|
9906
10170
|
|
|
9907
10171
|
|
|
9908
10172
|
</div>
|
|
@@ -9921,10 +10185,10 @@ it an interactive link or button, which adds the pointer cursor and hover fill.<
|
|
|
9921
10185
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
9922
10186
|
|
|
9923
10187
|
|
|
9924
|
-
<input id="c-
|
|
10188
|
+
<input id="c-32-components-tag-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
9925
10189
|
|
|
9926
10190
|
|
|
9927
|
-
<input id="c-
|
|
10191
|
+
<input id="c-32-components-tag-props" class="tg tg-props" type="checkbox" hidden />
|
|
9928
10192
|
|
|
9929
10193
|
<div class="panels">
|
|
9930
10194
|
|
|
@@ -10349,9 +10613,9 @@ leading + trailing icons, and icon-only.</div>
|
|
|
10349
10613
|
<div class="title">
|
|
10350
10614
|
<h2><span class="status-dot dot-ok"></span> TextArea</h2>
|
|
10351
10615
|
<div class="badges">
|
|
10352
|
-
<label for="c-
|
|
10616
|
+
<label for="c-33-components-textarea-props" class="badge ok as-toggle">1 prop type</label>
|
|
10353
10617
|
|
|
10354
|
-
<label for="c-
|
|
10618
|
+
<label for="c-33-components-textarea-stories" class="badge ok as-toggle">6 stories</label>
|
|
10355
10619
|
|
|
10356
10620
|
|
|
10357
10621
|
</div>
|
|
@@ -10368,10 +10632,10 @@ states. It wires nothing on its own: `id`, `aria-invalid` and
|
|
|
10368
10632
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
10369
10633
|
|
|
10370
10634
|
|
|
10371
|
-
<input id="c-
|
|
10635
|
+
<input id="c-33-components-textarea-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
10372
10636
|
|
|
10373
10637
|
|
|
10374
|
-
<input id="c-
|
|
10638
|
+
<input id="c-33-components-textarea-props" class="tg tg-props" type="checkbox" hidden />
|
|
10375
10639
|
|
|
10376
10640
|
<div class="panels">
|
|
10377
10641
|
|
|
@@ -10503,9 +10767,9 @@ size and the minimum height shows three rows.</div>
|
|
|
10503
10767
|
<div class="title">
|
|
10504
10768
|
<h2><span class="status-dot dot-ok"></span> Toast</h2>
|
|
10505
10769
|
<div class="badges">
|
|
10506
|
-
<label for="c-
|
|
10770
|
+
<label for="c-34-components-toast-props" class="badge ok as-toggle">11 prop types</label>
|
|
10507
10771
|
|
|
10508
|
-
<label for="c-
|
|
10772
|
+
<label for="c-34-components-toast-stories" class="badge ok as-toggle">11 stories</label>
|
|
10509
10773
|
|
|
10510
10774
|
|
|
10511
10775
|
</div>
|
|
@@ -10524,10 +10788,10 @@ common feedback patterns.</div>
|
|
|
10524
10788
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
10525
10789
|
|
|
10526
10790
|
|
|
10527
|
-
<input id="c-
|
|
10791
|
+
<input id="c-34-components-toast-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
10528
10792
|
|
|
10529
10793
|
|
|
10530
|
-
<input id="c-
|
|
10794
|
+
<input id="c-34-components-toast-props" class="tg tg-props" type="checkbox" hidden />
|
|
10531
10795
|
|
|
10532
10796
|
<div class="panels">
|
|
10533
10797
|
|
|
@@ -10956,9 +11220,9 @@ action (e.g., a sync icon for a sync-in-progress toast).</div>
|
|
|
10956
11220
|
<div class="title">
|
|
10957
11221
|
<h2><span class="status-dot dot-ok"></span> Tooltip</h2>
|
|
10958
11222
|
<div class="badges">
|
|
10959
|
-
<label for="c-
|
|
11223
|
+
<label for="c-35-components-tooltip-props" class="badge ok as-toggle">12 prop types</label>
|
|
10960
11224
|
|
|
10961
|
-
<label for="c-
|
|
11225
|
+
<label for="c-35-components-tooltip-stories" class="badge ok as-toggle">5 stories</label>
|
|
10962
11226
|
|
|
10963
11227
|
|
|
10964
11228
|
</div>
|
|
@@ -10977,10 +11241,10 @@ on hover or focus.</div>
|
|
|
10977
11241
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
10978
11242
|
|
|
10979
11243
|
|
|
10980
|
-
<input id="c-
|
|
11244
|
+
<input id="c-35-components-tooltip-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
10981
11245
|
|
|
10982
11246
|
|
|
10983
|
-
<input id="c-
|
|
11247
|
+
<input id="c-35-components-tooltip-props" class="tg tg-props" type="checkbox" hidden />
|
|
10984
11248
|
|
|
10985
11249
|
<div class="panels">
|
|
10986
11250
|
|
|
@@ -11152,9 +11416,9 @@ sideOffset?: number = 4</code></pre>
|
|
|
11152
11416
|
<div class="title">
|
|
11153
11417
|
<h2><span class="status-dot dot-ok"></span> ValidationList</h2>
|
|
11154
11418
|
<div class="badges">
|
|
11155
|
-
<label for="c-
|
|
11419
|
+
<label for="c-36-components-validationlist-props" class="badge ok as-toggle">2 prop types</label>
|
|
11156
11420
|
|
|
11157
|
-
<label for="c-
|
|
11421
|
+
<label for="c-36-components-validationlist-stories" class="badge ok as-toggle">4 stories</label>
|
|
11158
11422
|
|
|
11159
11423
|
|
|
11160
11424
|
</div>
|
|
@@ -11175,10 +11439,10 @@ your form validation; it does not own the input or block submission.</div>
|
|
|
11175
11439
|
<!-- ⬇️ Hidden toggles must be siblings BEFORE .panels -->
|
|
11176
11440
|
|
|
11177
11441
|
|
|
11178
|
-
<input id="c-
|
|
11442
|
+
<input id="c-36-components-validationlist-stories" class="tg tg-stories" type="checkbox" hidden />
|
|
11179
11443
|
|
|
11180
11444
|
|
|
11181
|
-
<input id="c-
|
|
11445
|
+
<input id="c-36-components-validationlist-props" class="tg tg-props" type="checkbox" hidden />
|
|
11182
11446
|
|
|
11183
11447
|
<div class="panels">
|
|
11184
11448
|
|
|
@@ -6941,6 +6941,154 @@
|
|
|
6941
6941
|
],
|
|
6942
6942
|
"import": "import { Field, FieldText, InputSearch, Label } from \"@agentero/design-system\";"
|
|
6943
6943
|
},
|
|
6944
|
+
"components-inputtel": {
|
|
6945
|
+
"id": "components-inputtel",
|
|
6946
|
+
"name": "InputTel",
|
|
6947
|
+
"path": "./src/input-tel/input-tel.stories.tsx",
|
|
6948
|
+
"jsDocTags": {
|
|
6949
|
+
"summary": [
|
|
6950
|
+
"US phone input with a +1 prefix that masks as you type"
|
|
6951
|
+
],
|
|
6952
|
+
"dataAttribute": [
|
|
6953
|
+
"{string} data-slot - Always set to \"input-tel\" on the frame"
|
|
6954
|
+
],
|
|
6955
|
+
"example": [
|
|
6956
|
+
"<FieldText>\n <Label>Phone number</Label>\n <InputTel name=\"phone\" autoComplete=\"tel-national\" placeholder=\"(555) 000-0000\" />\n</FieldText>"
|
|
6957
|
+
]
|
|
6958
|
+
},
|
|
6959
|
+
"description": "InputTel is a US phone number field that masks as you type: the digits are\nlaid out as `(555) 123-4567`, anything else is dropped and the caret stays\nnext to the digit just edited. It is an `Input` of `type=\"tel\"` inside an\n`InputGroup` frame with a `+1` prefix; `onChange` receives the native event\nwith the masked text already in `event.target.value`.",
|
|
6960
|
+
"summary": "US phone input with a +1 prefix that masks as you type",
|
|
6961
|
+
"reactComponentMeta": {
|
|
6962
|
+
"displayName": "InputTel",
|
|
6963
|
+
"exportName": "InputTel",
|
|
6964
|
+
"filePath": "/home/runner/work/design-system/design-system/src/input-tel/input-tel.tsx",
|
|
6965
|
+
"description": "InputTel is a US phone number field that masks as you type: the digits the\nuser enters are laid out as `(555) 123-4567` while typing, pasting or\ndeleting, anything that is not a digit is dropped, and the caret stays next\nto the digit just edited instead of jumping to the end. A leading `+1`\ncountry code, as pasted or filled in by the browser's autofill, is dropped\ntoo; past that, the eleventh digit and beyond are ignored. `onChange`\nreceives the native change event with the masked text already in\n`event.target.value`, so a controlled field, an uncontrolled one and one\nregistered with react-hook-form all store `(555) 123-4567`, never the bare\ndigits.\n\nIt is an [Input](?path=/docs/components-input--docs) of `type=\"tel\"` inside\nan [InputGroup](?path=/docs/components-inputgroup--docs) frame that always\nshows a `+1` prefix in front of the number. The prefix is part of the frame,\nnot of the value. `className` styles the frame. Every other prop goes to the\n`<input>`: the `ref`, `id`, `name`, `value`, `onChange`, `aria-*` and every\nother standard attribute, such as `placeholder`, `autoComplete` or\n`required`. Only `type` is not accepted. Inside a `FieldText` the input\ntakes its label, messages and states from the field as a plain `Input` does.\nThe invalid state comes from `aria-invalid`, and the frame paints the\ndestructive border.\n\nDo not use it for international numbers or extensions; the mask only knows\nthe ten-digit US format. For free-form text that happens to hold a number,\nuse `Input`.",
|
|
6966
|
+
"jsDocTags": {
|
|
6967
|
+
"summary": [
|
|
6968
|
+
"US phone input with a +1 prefix that masks as you type"
|
|
6969
|
+
],
|
|
6970
|
+
"dataAttribute": [
|
|
6971
|
+
"{string} data-slot - Always set to \"input-tel\" on the frame"
|
|
6972
|
+
],
|
|
6973
|
+
"example": [
|
|
6974
|
+
"<FieldText>\n <Label>Phone number</Label>\n <InputTel name=\"phone\" autoComplete=\"tel-national\" placeholder=\"(555) 000-0000\" />\n</FieldText>"
|
|
6975
|
+
]
|
|
6976
|
+
},
|
|
6977
|
+
"props": {
|
|
6978
|
+
"size": {
|
|
6979
|
+
"name": "size",
|
|
6980
|
+
"required": false,
|
|
6981
|
+
"type": {
|
|
6982
|
+
"name": "enum",
|
|
6983
|
+
"raw": "\"sm\" | \"md\" | \"lg\"",
|
|
6984
|
+
"value": [
|
|
6985
|
+
{
|
|
6986
|
+
"value": "\"sm\""
|
|
6987
|
+
},
|
|
6988
|
+
{
|
|
6989
|
+
"value": "\"md\""
|
|
6990
|
+
},
|
|
6991
|
+
{
|
|
6992
|
+
"value": "\"lg\""
|
|
6993
|
+
}
|
|
6994
|
+
]
|
|
6995
|
+
},
|
|
6996
|
+
"description": "Control height. Defaults to `'md'`.\n- `sm` (32px) — dense layouts where vertical space is tight.\n- `md` (40px) — standard form density.\n- `lg` (48px) — low-density forms and larger touch targets. Also raises\n the text to `base` and the corner radius to `lg`.",
|
|
6997
|
+
"defaultValue": null,
|
|
6998
|
+
"parent": {
|
|
6999
|
+
"name": "InputProps",
|
|
7000
|
+
"fileName": "src/input/input.tsx"
|
|
7001
|
+
},
|
|
7002
|
+
"declarations": [
|
|
7003
|
+
{
|
|
7004
|
+
"name": "TypeLiteral",
|
|
7005
|
+
"fileName": "src/input/input.tsx"
|
|
7006
|
+
}
|
|
7007
|
+
]
|
|
7008
|
+
}
|
|
7009
|
+
}
|
|
7010
|
+
},
|
|
7011
|
+
"stories": [
|
|
7012
|
+
{
|
|
7013
|
+
"id": "components-inputtel--default",
|
|
7014
|
+
"name": "Default",
|
|
7015
|
+
"snippet": "const Default = () => <InputTel\n aria-label=\"Phone number\"\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;",
|
|
7016
|
+
"description": "An uncontrolled phone field with its `+1` prefix. Typing the ten digits lays\nthem out as `(555) 123-4567`, and every `onChange` call carries the masked\ntext in `event.target.value`; the prefix never enters the value.",
|
|
7017
|
+
"summary": "Phone field with a +1 prefix masking the digits as they are typed"
|
|
7018
|
+
},
|
|
7019
|
+
{
|
|
7020
|
+
"id": "components-inputtel--controlled",
|
|
7021
|
+
"name": "Controlled",
|
|
7022
|
+
"snippet": "const Controlled = () => {\n const [phone, setPhone] = useState('');\n\n return (\n <InputTel\n aria-label=\"Phone number\"\n value={phone}\n onChange={event => {\n setPhone(event.target.value);\n args.onChange?.(event);\n }} />\n );\n};",
|
|
7023
|
+
"description": "A controlled phone field. The state that owns the value stores what\n`event.target.value` reports, which is already masked, and the input shows\nit back unchanged. A partial number carries the separator that comes before\nthe next digit, so six digits read `(555) 123-`.",
|
|
7024
|
+
"summary": "Controlled phone field storing the masked value"
|
|
7025
|
+
},
|
|
7026
|
+
{
|
|
7027
|
+
"id": "components-inputtel--caret-in-the-middle",
|
|
7028
|
+
"name": "Caret In The Middle",
|
|
7029
|
+
"snippet": "const CaretInTheMiddle = () => <InputTel\n aria-label=\"Phone number\"\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;",
|
|
7030
|
+
"description": "Editing in the middle of a full number: a digit typed after `(5` shifts the\nrest right, the eleventh digit falls off the end and the caret stays after\nthe digit just typed instead of jumping to the end.",
|
|
7031
|
+
"summary": "Caret staying put when a digit is inserted mid-number"
|
|
7032
|
+
},
|
|
7033
|
+
{
|
|
7034
|
+
"id": "components-inputtel--backspace-over-mask-characters",
|
|
7035
|
+
"name": "Backspace Over Mask Characters",
|
|
7036
|
+
"snippet": "const BackspaceOverMaskCharacters = () => <InputTel\n aria-label=\"Phone number\"\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;",
|
|
7037
|
+
"description": "Backspace over the mask's own characters: after `555` the field shows\n`(555) `, and deleting backwards trims the separators along with the digit\nunder the caret instead of leaving a dangling `) `.",
|
|
7038
|
+
"summary": "Backspace trimming the separators the mask added"
|
|
7039
|
+
},
|
|
7040
|
+
{
|
|
7041
|
+
"id": "components-inputtel--paste",
|
|
7042
|
+
"name": "Paste",
|
|
7043
|
+
"snippet": "const Paste = () => <InputTel\n aria-label=\"Phone number\"\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;",
|
|
7044
|
+
"description": "A pasted number in any format is reduced to its digits and masked, so\n`555-123-4567` from a clipboard ends up as `(555) 123-4567`.",
|
|
7045
|
+
"summary": "Pasted number reduced to its digits and masked"
|
|
7046
|
+
},
|
|
7047
|
+
{
|
|
7048
|
+
"id": "components-inputtel--paste-with-country-code",
|
|
7049
|
+
"name": "Paste With Country Code",
|
|
7050
|
+
"snippet": "const PasteWithCountryCode = () => <InputTel\n aria-label=\"Phone number\"\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)} />;",
|
|
7051
|
+
"description": "A number that carries the `+1` country code, as copied from a signature or\nfilled in by the browser's autofill, loses the code and keeps its ten\nnational digits: `+1 (555) 123-4567` ends up as `(555) 123-4567`.",
|
|
7052
|
+
"summary": "Pasted number with a +1 country code"
|
|
7053
|
+
},
|
|
7054
|
+
{
|
|
7055
|
+
"id": "components-inputtel--inside-field-text",
|
|
7056
|
+
"name": "Inside Field Text",
|
|
7057
|
+
"snippet": "const InsideFieldText = () => (\n <FieldText>\n <Label>Phone number</Label>\n <InputTel />\n <Field.Description>We only call about your account.</Field.Description>\n </FieldText>\n);",
|
|
7058
|
+
"description": "Inside a `FieldText` the input takes its label, description and states from\nthe field, and the masked value still reaches a handler the field provides.",
|
|
7059
|
+
"summary": "Label and description reaching the input through the field"
|
|
7060
|
+
},
|
|
7061
|
+
{
|
|
7062
|
+
"id": "components-inputtel--with-react-hook-form",
|
|
7063
|
+
"name": "With React Hook Form",
|
|
7064
|
+
"snippet": "const WithReactHookForm = () => {\n const { register, handleSubmit } = useForm<ContactValues>({\n defaultValues: { phone: '' }\n });\n\n return (\n <form\n aria-label=\"Contact\"\n noValidate\n onSubmit={handleSubmit(values => onSubmit(values))}\n style={{ display: 'grid', gap: '1rem' }}>\n <InputTel aria-label=\"Phone number\" {...register('phone')} />\n <Button type=\"submit\">Save</Button>\n </form>\n );\n};",
|
|
7065
|
+
"description": "Registered with react-hook-form, the form receives the masked value: the\n`register` handler reads `event.target.value` like any other change.",
|
|
7066
|
+
"summary": "Masked value reaching react-hook-form through register"
|
|
7067
|
+
},
|
|
7068
|
+
{
|
|
7069
|
+
"id": "components-inputtel--disabled",
|
|
7070
|
+
"name": "Disabled",
|
|
7071
|
+
"snippet": "const Disabled = () => <InputTel\n aria-label=\"Phone number\"\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}\n disabled\n defaultValue=\"(555) 123-4567\" />;",
|
|
7072
|
+
"description": "A disabled phone field keeps its masked value and takes no input.",
|
|
7073
|
+
"summary": "Disabled phone field"
|
|
7074
|
+
},
|
|
7075
|
+
{
|
|
7076
|
+
"id": "components-inputtel--invalid",
|
|
7077
|
+
"name": "Invalid",
|
|
7078
|
+
"snippet": "const Invalid = () => (\n <FieldText invalid>\n <Label>Phone number</Label>\n <InputTel defaultValue=\"(555) 12\" />\n <Field.Error errors={[{ message: 'Enter a 10-digit phone number.' }]} />\n </FieldText>\n);",
|
|
7079
|
+
"description": "`invalid` on the surrounding `FieldText` sets `aria-invalid` on the input,\nwhich paints the frame's destructive border, and `Field.Error` is announced\nwith the input.",
|
|
7080
|
+
"summary": "Invalid field driving the frame's destructive border"
|
|
7081
|
+
},
|
|
7082
|
+
{
|
|
7083
|
+
"id": "components-inputtel--all-sizes",
|
|
7084
|
+
"name": "All Sizes",
|
|
7085
|
+
"snippet": "const AllSizes = () => <div style={{ display: 'grid', gap: '1rem' }}>\n <InputTel\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}\n size=\"sm\"\n aria-label=\"Small\"\n defaultValue=\"(555) 123-4567\" />\n <InputTel\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}\n size=\"md\"\n aria-label=\"Medium\"\n defaultValue=\"(555) 123-4567\" />\n <InputTel\n onChange={fn((event: ChangeEvent<HTMLInputElement>) => event.target.value)}\n size=\"lg\"\n aria-label=\"Large\"\n defaultValue=\"(555) 123-4567\" />\n</div>;",
|
|
7086
|
+
"description": "The three sizes match Input's: the frame is 32, 40 or 48px tall.",
|
|
7087
|
+
"summary": "The three sizes side by side"
|
|
7088
|
+
}
|
|
7089
|
+
],
|
|
7090
|
+
"import": "import { Button, Field, FieldText, InputContext, InputTel, Label } from \"@agentero/design-system\";"
|
|
7091
|
+
},
|
|
6944
7092
|
"components-input": {
|
|
6945
7093
|
"id": "components-input",
|
|
6946
7094
|
"name": "Input",
|
|
@@ -9907,6 +10055,6 @@
|
|
|
9907
10055
|
},
|
|
9908
10056
|
"meta": {
|
|
9909
10057
|
"docgen": "react-component-meta",
|
|
9910
|
-
"durationMs":
|
|
10058
|
+
"durationMs": 4990
|
|
9911
10059
|
}
|
|
9912
10060
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentero/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "A React component library built with Tailwind CSS v4 and Radix UI primitives",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -105,6 +105,10 @@
|
|
|
105
105
|
"types": "./src/input-search/index.d.ts",
|
|
106
106
|
"import": "./src/input-search/index.js"
|
|
107
107
|
},
|
|
108
|
+
"./input-tel": {
|
|
109
|
+
"types": "./src/input-tel/index.d.ts",
|
|
110
|
+
"import": "./src/input-tel/index.js"
|
|
111
|
+
},
|
|
108
112
|
"./label": {
|
|
109
113
|
"types": "./src/label/index.d.ts",
|
|
110
114
|
"import": "./src/label/index.js"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { InputProps } from '../input';
|
|
2
|
+
export type InputTelProps = Omit<InputProps, 'type'>;
|
|
3
|
+
/**
|
|
4
|
+
* InputTel is a US phone number field that masks as you type: the digits the
|
|
5
|
+
* user enters are laid out as `(555) 123-4567` while typing, pasting or
|
|
6
|
+
* deleting, anything that is not a digit is dropped, and the caret stays next
|
|
7
|
+
* to the digit just edited instead of jumping to the end. A leading `+1`
|
|
8
|
+
* country code, as pasted or filled in by the browser's autofill, is dropped
|
|
9
|
+
* too; past that, the eleventh digit and beyond are ignored. `onChange`
|
|
10
|
+
* receives the native change event with the masked text already in
|
|
11
|
+
* `event.target.value`, so a controlled field, an uncontrolled one and one
|
|
12
|
+
* registered with react-hook-form all store `(555) 123-4567`, never the bare
|
|
13
|
+
* digits.
|
|
14
|
+
*
|
|
15
|
+
* It is an [Input](?path=/docs/components-input--docs) of `type="tel"` inside
|
|
16
|
+
* an [InputGroup](?path=/docs/components-inputgroup--docs) frame that always
|
|
17
|
+
* shows a `+1` prefix in front of the number. The prefix is part of the frame,
|
|
18
|
+
* not of the value. `className` styles the frame. Every other prop goes to the
|
|
19
|
+
* `<input>`: the `ref`, `id`, `name`, `value`, `onChange`, `aria-*` and every
|
|
20
|
+
* other standard attribute, such as `placeholder`, `autoComplete` or
|
|
21
|
+
* `required`. Only `type` is not accepted. Inside a `FieldText` the input
|
|
22
|
+
* takes its label, messages and states from the field as a plain `Input` does.
|
|
23
|
+
* The invalid state comes from `aria-invalid`, and the frame paints the
|
|
24
|
+
* destructive border.
|
|
25
|
+
*
|
|
26
|
+
* Do not use it for international numbers or extensions; the mask only knows
|
|
27
|
+
* the ten-digit US format. For free-form text that happens to hold a number,
|
|
28
|
+
* use `Input`.
|
|
29
|
+
*
|
|
30
|
+
* @summary US phone input with a +1 prefix that masks as you type
|
|
31
|
+
* @dataAttribute {string} data-slot - Always set to "input-tel" on the frame
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* <FieldText>
|
|
35
|
+
* <Label>Phone number</Label>
|
|
36
|
+
* <InputTel name="phone" autoComplete="tel-national" placeholder="(555) 000-0000" />
|
|
37
|
+
* </FieldText>
|
|
38
|
+
*/
|
|
39
|
+
export declare const InputTel: {
|
|
40
|
+
(props: InputTelProps): import("react/jsx-runtime").JSX.Element;
|
|
41
|
+
displayName: string;
|
|
42
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { mergeRefs as e } from "../../lib/merge-props.js";
|
|
3
|
+
import { InputContext as t, useInputContext as n } from "../input/context.js";
|
|
4
|
+
import { Input as r } from "../input/input.js";
|
|
5
|
+
import { InputGroup as i } from "../input-group/index.js";
|
|
6
|
+
import { US_PHONE_MASK as a, applyMask as o, getCursorPosition as s, getDeletionType as c, toNationalDigits as l } from "./mask.js";
|
|
7
|
+
import { useMemo as u, useRef as d } from "react";
|
|
8
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
9
|
+
//#region src/input-tel/input-tel.tsx
|
|
10
|
+
var m = (m) => {
|
|
11
|
+
let { className: h, onChange: g, ref: _, ...v } = n(m), y = d(null), b = u(() => e(y, _), [_]), x = (e) => {
|
|
12
|
+
let t = c(e.nativeEvent.inputType), { value: n, selectionStart: r } = e.target, i = o({
|
|
13
|
+
value: l(n),
|
|
14
|
+
mask: a,
|
|
15
|
+
maskSymbol: ".",
|
|
16
|
+
trimNonMaskCharsLeftover: t === "backward"
|
|
17
|
+
}), u = s({
|
|
18
|
+
cursorPositionAfterInput: r ?? 0,
|
|
19
|
+
phoneAfterInput: n,
|
|
20
|
+
phoneAfterFormatted: i,
|
|
21
|
+
deletion: t
|
|
22
|
+
});
|
|
23
|
+
e.target.value = i;
|
|
24
|
+
let d = () => {
|
|
25
|
+
let e = y.current;
|
|
26
|
+
e && e === document.activeElement && e.setSelectionRange(u, u);
|
|
27
|
+
};
|
|
28
|
+
g ? (g(e), Promise.resolve().then(d)) : d();
|
|
29
|
+
};
|
|
30
|
+
return /* @__PURE__ */ p(i.Root, {
|
|
31
|
+
"data-slot": "input-tel",
|
|
32
|
+
className: h,
|
|
33
|
+
children: [/* @__PURE__ */ f(i.Text, { children: "+1" }), /* @__PURE__ */ f(t, {
|
|
34
|
+
value: null,
|
|
35
|
+
children: /* @__PURE__ */ f(r, {
|
|
36
|
+
...v,
|
|
37
|
+
type: "tel",
|
|
38
|
+
ref: b,
|
|
39
|
+
onChange: x
|
|
40
|
+
})
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
m.displayName = "InputTel";
|
|
45
|
+
//#endregion
|
|
46
|
+
export { m as InputTel };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** The US phone mask InputTel applies: three groups of 3, 3 and 4 digits. */
|
|
2
|
+
export declare const US_PHONE_MASK = "(...) ...-....";
|
|
3
|
+
/** The character that marks a digit slot in a mask. */
|
|
4
|
+
export declare const MASK_SYMBOL = ".";
|
|
5
|
+
/**
|
|
6
|
+
* Reduces a phone number in any format to its national digits: drops
|
|
7
|
+
* everything that is not a digit and, past ten digits, the leading `1` of the
|
|
8
|
+
* `+1` country code. No US area code starts with `1`, so a national number is
|
|
9
|
+
* never cut.
|
|
10
|
+
*/
|
|
11
|
+
export declare const toNationalDigits: (value: string) => string;
|
|
12
|
+
type ApplyMaskArgs = {
|
|
13
|
+
value: string;
|
|
14
|
+
mask: string;
|
|
15
|
+
maskSymbol: string;
|
|
16
|
+
/**
|
|
17
|
+
* @description Removes all non-maskSymbol chars from the result's ending if the value is shorter than the mask
|
|
18
|
+
* @example
|
|
19
|
+
* value: "1234"
|
|
20
|
+
* mask: "(....) ...."
|
|
21
|
+
* if true -> "(1234"
|
|
22
|
+
* if false -> "(1234) "
|
|
23
|
+
*/
|
|
24
|
+
trimNonMaskCharsLeftover?: boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Places each character of `value` in the next `maskSymbol` slot of `mask`,
|
|
28
|
+
* keeping the mask's own characters in between. A value longer than the mask
|
|
29
|
+
* is cut; a shorter one stops at its last character, followed by the
|
|
30
|
+
* separators up to the next slot unless `trimNonMaskCharsLeftover` is set.
|
|
31
|
+
*/
|
|
32
|
+
export declare const applyMask: ({ value, mask, maskSymbol, trimNonMaskCharsLeftover }: ApplyMaskArgs) => string;
|
|
33
|
+
export declare const isNumeric: (str?: string) => boolean;
|
|
34
|
+
type GetCursorPositionProps = {
|
|
35
|
+
phoneAfterInput: string;
|
|
36
|
+
phoneAfterFormatted: string;
|
|
37
|
+
cursorPositionAfterInput: number;
|
|
38
|
+
deletion?: 'forward' | 'backward' | undefined;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Finds where the caret should sit in the formatted phone after an edit, so
|
|
42
|
+
* that it stays after the digit the user just typed or removed instead of
|
|
43
|
+
* jumping to the end when the mask characters move around it.
|
|
44
|
+
*/
|
|
45
|
+
export declare const getCursorPosition: ({ phoneAfterInput, phoneAfterFormatted, cursorPositionAfterInput, deletion }: GetCursorPositionProps) => number;
|
|
46
|
+
/**
|
|
47
|
+
* Reads the `inputType` of a native `input` event and tells whether the edit
|
|
48
|
+
* removed characters, and in which direction. `undefined` for an insertion.
|
|
49
|
+
*/
|
|
50
|
+
export declare const getDeletionType: (inputType?: string) => "forward" | "backward" | undefined;
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/input-tel/mask.ts
|
|
2
|
+
var e = "(...) ...-....", t = (e) => {
|
|
3
|
+
let t = e.replace(/\D/g, "");
|
|
4
|
+
return t.length > 10 && t.startsWith("1") ? t.slice(1) : t;
|
|
5
|
+
}, n = ({ value: e, mask: t, maskSymbol: n, trimNonMaskCharsLeftover: r = !1 }) => {
|
|
6
|
+
if (!e) return "";
|
|
7
|
+
let i = "", a = 0;
|
|
8
|
+
for (let o of t.split("")) {
|
|
9
|
+
if (a >= e.length) {
|
|
10
|
+
if (!r && o !== n) {
|
|
11
|
+
i += o;
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
o === n ? (i += e[a], a += 1) : i += o;
|
|
17
|
+
}
|
|
18
|
+
return i;
|
|
19
|
+
}, r = (e) => e ? /^\d+$/.test(e) : !1, i = ({ phoneAfterInput: e, phoneAfterFormatted: t, cursorPositionAfterInput: n, deletion: i }) => {
|
|
20
|
+
let a = null;
|
|
21
|
+
for (let t = n - 1; t >= 0; --t) if (r(e[t])) {
|
|
22
|
+
a = t;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
if (a === null) {
|
|
26
|
+
for (let n = 0; n < e.length; n += 1) if (r(t[n])) return n;
|
|
27
|
+
return e.length;
|
|
28
|
+
}
|
|
29
|
+
let o = 0;
|
|
30
|
+
for (let t = 0; t < a; t += 1) r(e[t]) && (o += 1);
|
|
31
|
+
let s = 0, c = 0;
|
|
32
|
+
for (let e = 0; e < t.length && (s += 1, r(t[e]) && (c += 1), !(c >= o + 1)); e += 1);
|
|
33
|
+
if (i !== "backward") for (; !r(t[s]) && s < t.length;) s += 1;
|
|
34
|
+
return s;
|
|
35
|
+
}, a = (e) => {
|
|
36
|
+
if (e?.toLocaleLowerCase().includes("delete") ?? !1) return e?.toLocaleLowerCase().includes("forward") ? "forward" : "backward";
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { e as US_PHONE_MASK, n as applyMask, i as getCursorPosition, a as getDeletionType, r as isNumeric, t as toNationalDigits };
|