ionbase-ui 0.48.0 → 0.51.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/dist/components/Textarea.d.ts +50 -0
- package/dist/components/Textarea.d.ts.map +1 -0
- package/dist/components/Textarea.js +48 -0
- package/dist/components/Textarea.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/figma-descriptions.json +45 -40
- package/dist/figma-map.json +57 -1
- package/dist/meta/Input.json +0 -1
- package/dist/meta/Textarea.json +520 -0
- package/dist/meta/components.json +521 -2
- package/dist/meta/contrast.json +224 -0
- package/dist/meta/index.json +22 -1
- package/dist/meta/patterns/index.json +1 -1
- package/dist/styles/index.css +1 -0
- package/dist/styles/input.css +34 -15
- package/dist/styles/textarea.css +178 -0
- package/dist/styles/tokens/base.css +0 -1
- package/dist/styles/tokens/theme-dark.css +0 -1
- package/dist/tokens/index.d.ts +0 -6
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +0 -5
- package/dist/tokens/index.js.map +1 -1
- package/llms.txt +2 -2
- package/package.json +1 -1
package/dist/meta/contrast.json
CHANGED
|
@@ -494,6 +494,20 @@
|
|
|
494
494
|
"ratio": 3.12,
|
|
495
495
|
"min": 4.5
|
|
496
496
|
},
|
|
497
|
+
{
|
|
498
|
+
"component": "textarea",
|
|
499
|
+
"context": "ion-textarea",
|
|
500
|
+
"state": "disabled",
|
|
501
|
+
"fg": "--text-disabled",
|
|
502
|
+
"bg": "--surface-disabled",
|
|
503
|
+
"backdrop": "--surface-page",
|
|
504
|
+
"kind": "text",
|
|
505
|
+
"mode": "Dark",
|
|
506
|
+
"fgHex": "#6b7280",
|
|
507
|
+
"bgHex": "#1d2735",
|
|
508
|
+
"ratio": 3.12,
|
|
509
|
+
"min": 4.5
|
|
510
|
+
},
|
|
497
511
|
{
|
|
498
512
|
"component": "toggle",
|
|
499
513
|
"context": "ion-toggle--disabled ion-toggle__label",
|
|
@@ -1110,6 +1124,20 @@
|
|
|
1110
1124
|
"ratio": 4.31,
|
|
1111
1125
|
"min": 4.5
|
|
1112
1126
|
},
|
|
1127
|
+
{
|
|
1128
|
+
"component": "textarea",
|
|
1129
|
+
"context": "ion-textarea",
|
|
1130
|
+
"state": "disabled",
|
|
1131
|
+
"fg": "--text-disabled",
|
|
1132
|
+
"bg": "--surface-disabled",
|
|
1133
|
+
"backdrop": "--surface-page",
|
|
1134
|
+
"kind": "text",
|
|
1135
|
+
"mode": "Light",
|
|
1136
|
+
"fgHex": "#6b7280",
|
|
1137
|
+
"bgHex": "#f0f2f4",
|
|
1138
|
+
"ratio": 4.31,
|
|
1139
|
+
"min": 4.5
|
|
1140
|
+
},
|
|
1113
1141
|
{
|
|
1114
1142
|
"component": "toggle",
|
|
1115
1143
|
"context": "ion-toggle--disabled ion-toggle__label",
|
|
@@ -4934,6 +4962,104 @@
|
|
|
4934
4962
|
"ratio": 6.95,
|
|
4935
4963
|
"min": 4.5
|
|
4936
4964
|
},
|
|
4965
|
+
{
|
|
4966
|
+
"component": "textarea",
|
|
4967
|
+
"context": "ion-textarea",
|
|
4968
|
+
"state": "default",
|
|
4969
|
+
"fg": "--text-tertiary",
|
|
4970
|
+
"bg": "--surface-page",
|
|
4971
|
+
"backdrop": "--surface-page",
|
|
4972
|
+
"kind": "text",
|
|
4973
|
+
"mode": "Dark",
|
|
4974
|
+
"fgHex": "#9ca3b0",
|
|
4975
|
+
"bgHex": "#131923",
|
|
4976
|
+
"ratio": 6.95,
|
|
4977
|
+
"min": 4.5
|
|
4978
|
+
},
|
|
4979
|
+
{
|
|
4980
|
+
"component": "textarea",
|
|
4981
|
+
"context": "ion-textarea--sm",
|
|
4982
|
+
"state": "default",
|
|
4983
|
+
"fg": "--text-tertiary",
|
|
4984
|
+
"bg": "--surface-page",
|
|
4985
|
+
"backdrop": "--surface-page",
|
|
4986
|
+
"kind": "text",
|
|
4987
|
+
"mode": "Dark",
|
|
4988
|
+
"fgHex": "#9ca3b0",
|
|
4989
|
+
"bgHex": "#131923",
|
|
4990
|
+
"ratio": 6.95,
|
|
4991
|
+
"min": 4.5
|
|
4992
|
+
},
|
|
4993
|
+
{
|
|
4994
|
+
"component": "textarea",
|
|
4995
|
+
"context": "ion-textarea--lg",
|
|
4996
|
+
"state": "default",
|
|
4997
|
+
"fg": "--text-tertiary",
|
|
4998
|
+
"bg": "--surface-page",
|
|
4999
|
+
"backdrop": "--surface-page",
|
|
5000
|
+
"kind": "text",
|
|
5001
|
+
"mode": "Dark",
|
|
5002
|
+
"fgHex": "#9ca3b0",
|
|
5003
|
+
"bgHex": "#131923",
|
|
5004
|
+
"ratio": 6.95,
|
|
5005
|
+
"min": 4.5
|
|
5006
|
+
},
|
|
5007
|
+
{
|
|
5008
|
+
"component": "textarea",
|
|
5009
|
+
"context": "ion-textarea",
|
|
5010
|
+
"state": "hover",
|
|
5011
|
+
"fg": "--text-tertiary",
|
|
5012
|
+
"bg": "--surface-page",
|
|
5013
|
+
"backdrop": "--surface-page",
|
|
5014
|
+
"kind": "text",
|
|
5015
|
+
"mode": "Dark",
|
|
5016
|
+
"fgHex": "#9ca3b0",
|
|
5017
|
+
"bgHex": "#131923",
|
|
5018
|
+
"ratio": 6.95,
|
|
5019
|
+
"min": 4.5
|
|
5020
|
+
},
|
|
5021
|
+
{
|
|
5022
|
+
"component": "textarea",
|
|
5023
|
+
"context": "ion-textarea",
|
|
5024
|
+
"state": "focus",
|
|
5025
|
+
"fg": "--text-tertiary",
|
|
5026
|
+
"bg": "--surface-page",
|
|
5027
|
+
"backdrop": "--surface-page",
|
|
5028
|
+
"kind": "text",
|
|
5029
|
+
"mode": "Dark",
|
|
5030
|
+
"fgHex": "#9ca3b0",
|
|
5031
|
+
"bgHex": "#131923",
|
|
5032
|
+
"ratio": 6.95,
|
|
5033
|
+
"min": 4.5
|
|
5034
|
+
},
|
|
5035
|
+
{
|
|
5036
|
+
"component": "textarea",
|
|
5037
|
+
"context": "ion-textarea--invalid",
|
|
5038
|
+
"state": "default",
|
|
5039
|
+
"fg": "--text-tertiary",
|
|
5040
|
+
"bg": "--surface-page",
|
|
5041
|
+
"backdrop": "--surface-page",
|
|
5042
|
+
"kind": "text",
|
|
5043
|
+
"mode": "Dark",
|
|
5044
|
+
"fgHex": "#9ca3b0",
|
|
5045
|
+
"bgHex": "#131923",
|
|
5046
|
+
"ratio": 6.95,
|
|
5047
|
+
"min": 4.5
|
|
5048
|
+
},
|
|
5049
|
+
{
|
|
5050
|
+
"component": "textarea",
|
|
5051
|
+
"context": "ion-textarea--readonly",
|
|
5052
|
+
"state": "default",
|
|
5053
|
+
"fg": "--text-tertiary",
|
|
5054
|
+
"bg": "--surface-page",
|
|
5055
|
+
"backdrop": "--surface-page",
|
|
5056
|
+
"kind": "text",
|
|
5057
|
+
"mode": "Dark",
|
|
5058
|
+
"fgHex": "#9ca3b0",
|
|
5059
|
+
"bgHex": "#131923",
|
|
5060
|
+
"ratio": 6.95,
|
|
5061
|
+
"min": 4.5
|
|
5062
|
+
},
|
|
4937
5063
|
{
|
|
4938
5064
|
"component": "agent-activity",
|
|
4939
5065
|
"context": "ion-agent-activity ion-agent-activity__glyph",
|
|
@@ -5487,6 +5613,104 @@
|
|
|
5487
5613
|
"ratio": 7.09,
|
|
5488
5614
|
"min": 4.5
|
|
5489
5615
|
},
|
|
5616
|
+
{
|
|
5617
|
+
"component": "textarea",
|
|
5618
|
+
"context": "ion-textarea",
|
|
5619
|
+
"state": "default",
|
|
5620
|
+
"fg": "--text-tertiary",
|
|
5621
|
+
"bg": "--surface-page",
|
|
5622
|
+
"backdrop": "--surface-page",
|
|
5623
|
+
"kind": "text",
|
|
5624
|
+
"mode": "Light",
|
|
5625
|
+
"fgHex": "#4b5563",
|
|
5626
|
+
"bgHex": "#f6f8f9",
|
|
5627
|
+
"ratio": 7.09,
|
|
5628
|
+
"min": 4.5
|
|
5629
|
+
},
|
|
5630
|
+
{
|
|
5631
|
+
"component": "textarea",
|
|
5632
|
+
"context": "ion-textarea--sm",
|
|
5633
|
+
"state": "default",
|
|
5634
|
+
"fg": "--text-tertiary",
|
|
5635
|
+
"bg": "--surface-page",
|
|
5636
|
+
"backdrop": "--surface-page",
|
|
5637
|
+
"kind": "text",
|
|
5638
|
+
"mode": "Light",
|
|
5639
|
+
"fgHex": "#4b5563",
|
|
5640
|
+
"bgHex": "#f6f8f9",
|
|
5641
|
+
"ratio": 7.09,
|
|
5642
|
+
"min": 4.5
|
|
5643
|
+
},
|
|
5644
|
+
{
|
|
5645
|
+
"component": "textarea",
|
|
5646
|
+
"context": "ion-textarea--lg",
|
|
5647
|
+
"state": "default",
|
|
5648
|
+
"fg": "--text-tertiary",
|
|
5649
|
+
"bg": "--surface-page",
|
|
5650
|
+
"backdrop": "--surface-page",
|
|
5651
|
+
"kind": "text",
|
|
5652
|
+
"mode": "Light",
|
|
5653
|
+
"fgHex": "#4b5563",
|
|
5654
|
+
"bgHex": "#f6f8f9",
|
|
5655
|
+
"ratio": 7.09,
|
|
5656
|
+
"min": 4.5
|
|
5657
|
+
},
|
|
5658
|
+
{
|
|
5659
|
+
"component": "textarea",
|
|
5660
|
+
"context": "ion-textarea",
|
|
5661
|
+
"state": "hover",
|
|
5662
|
+
"fg": "--text-tertiary",
|
|
5663
|
+
"bg": "--surface-page",
|
|
5664
|
+
"backdrop": "--surface-page",
|
|
5665
|
+
"kind": "text",
|
|
5666
|
+
"mode": "Light",
|
|
5667
|
+
"fgHex": "#4b5563",
|
|
5668
|
+
"bgHex": "#f6f8f9",
|
|
5669
|
+
"ratio": 7.09,
|
|
5670
|
+
"min": 4.5
|
|
5671
|
+
},
|
|
5672
|
+
{
|
|
5673
|
+
"component": "textarea",
|
|
5674
|
+
"context": "ion-textarea",
|
|
5675
|
+
"state": "focus",
|
|
5676
|
+
"fg": "--text-tertiary",
|
|
5677
|
+
"bg": "--surface-page",
|
|
5678
|
+
"backdrop": "--surface-page",
|
|
5679
|
+
"kind": "text",
|
|
5680
|
+
"mode": "Light",
|
|
5681
|
+
"fgHex": "#4b5563",
|
|
5682
|
+
"bgHex": "#f6f8f9",
|
|
5683
|
+
"ratio": 7.09,
|
|
5684
|
+
"min": 4.5
|
|
5685
|
+
},
|
|
5686
|
+
{
|
|
5687
|
+
"component": "textarea",
|
|
5688
|
+
"context": "ion-textarea--invalid",
|
|
5689
|
+
"state": "default",
|
|
5690
|
+
"fg": "--text-tertiary",
|
|
5691
|
+
"bg": "--surface-page",
|
|
5692
|
+
"backdrop": "--surface-page",
|
|
5693
|
+
"kind": "text",
|
|
5694
|
+
"mode": "Light",
|
|
5695
|
+
"fgHex": "#4b5563",
|
|
5696
|
+
"bgHex": "#f6f8f9",
|
|
5697
|
+
"ratio": 7.09,
|
|
5698
|
+
"min": 4.5
|
|
5699
|
+
},
|
|
5700
|
+
{
|
|
5701
|
+
"component": "textarea",
|
|
5702
|
+
"context": "ion-textarea--readonly",
|
|
5703
|
+
"state": "default",
|
|
5704
|
+
"fg": "--text-tertiary",
|
|
5705
|
+
"bg": "--surface-page",
|
|
5706
|
+
"backdrop": "--surface-page",
|
|
5707
|
+
"kind": "text",
|
|
5708
|
+
"mode": "Light",
|
|
5709
|
+
"fgHex": "#4b5563",
|
|
5710
|
+
"bgHex": "#f6f8f9",
|
|
5711
|
+
"ratio": 7.09,
|
|
5712
|
+
"min": 4.5
|
|
5713
|
+
},
|
|
5490
5714
|
{
|
|
5491
5715
|
"component": "alert",
|
|
5492
5716
|
"context": "ion-alert--success",
|
package/dist/meta/index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "ionbase-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"usage": "Pick a component here, then read dist/meta/<Name>.json for its full contract.",
|
|
5
5
|
"hooks": [
|
|
6
6
|
"useToast"
|
|
@@ -621,6 +621,27 @@
|
|
|
621
621
|
"detail": "dist/meta/Tabs.json",
|
|
622
622
|
"hasIntent": true
|
|
623
623
|
},
|
|
624
|
+
"Textarea": {
|
|
625
|
+
"summary": "A multi-line text field. Every size and state is Input's; it wraps and it resizes vertically.",
|
|
626
|
+
"status": "stable",
|
|
627
|
+
"variants": {
|
|
628
|
+
"size": [
|
|
629
|
+
"sm",
|
|
630
|
+
"md",
|
|
631
|
+
"lg"
|
|
632
|
+
],
|
|
633
|
+
"autoCapitalize": [
|
|
634
|
+
"none",
|
|
635
|
+
"off",
|
|
636
|
+
"on",
|
|
637
|
+
"sentences",
|
|
638
|
+
"words",
|
|
639
|
+
"characters"
|
|
640
|
+
]
|
|
641
|
+
},
|
|
642
|
+
"detail": "dist/meta/Textarea.json",
|
|
643
|
+
"hasIntent": true
|
|
644
|
+
},
|
|
624
645
|
"Toast": {
|
|
625
646
|
"summary": "A transient notification on neutral chrome. Intent is carried by the icon, not by a tinted panel.",
|
|
626
647
|
"status": "stable",
|
package/dist/styles/index.css
CHANGED
package/dist/styles/input.css
CHANGED
|
@@ -21,10 +21,12 @@
|
|
|
21
21
|
* padding box, so `padding-x: 12px` would put the text at 13px. The border
|
|
22
22
|
* width is subtracted back out — the same correction Badge and Tabs needed.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
* stroke
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* The subtraction is against the LIVE border width, which used to matter:
|
|
25
|
+
* focus was a 2px inside stroke that ate a further 1px of padding, and
|
|
26
|
+
* subtracting it kept the text from shifting. Every state is 1px as of
|
|
27
|
+
* 5 Sep 2026, so the correction is now constant — but it stays written this
|
|
28
|
+
* way, because it is correct either way and the next state to need a
|
|
29
|
+
* different width gets it for free.
|
|
28
30
|
*/
|
|
29
31
|
.ion-input {
|
|
30
32
|
/*
|
|
@@ -172,9 +174,10 @@
|
|
|
172
174
|
* hover -> focus -> invalid -> read-only -> disabled.
|
|
173
175
|
*
|
|
174
176
|
* Invalid sits after focus and overrides the colour only, never the width. A
|
|
175
|
-
* focused invalid field therefore
|
|
176
|
-
* colour
|
|
177
|
-
*
|
|
177
|
+
* focused invalid field therefore shows the error colour rather than the focus
|
|
178
|
+
* colour — both states are true at once and the more urgent one is shown. That
|
|
179
|
+
* ordering mattered more when the two differed in width as well; it is still
|
|
180
|
+
* the behaviour, and still deliberate.
|
|
178
181
|
*/
|
|
179
182
|
|
|
180
183
|
/*
|
|
@@ -192,23 +195,39 @@
|
|
|
192
195
|
border-color: var(--border-strong);
|
|
193
196
|
}
|
|
194
197
|
|
|
198
|
+
/*
|
|
199
|
+
* 1px, not the 2px this used to carry. See the note on --invalid below: both
|
|
200
|
+
* states were thinned on the same design call, and the trade is the same one.
|
|
201
|
+
*/
|
|
195
202
|
.ion-input:focus-within,
|
|
196
203
|
.ion-input[data-focused='true'] {
|
|
197
|
-
--ion-input-border-width: var(--border-width-thick);
|
|
198
|
-
|
|
199
204
|
border-color: var(--border-focus);
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
/*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
208
|
+
* 1px. THIS COMMENT USED TO ARGUE FOR 2px AND THE ARGUMENT WAS SOUND, so read
|
|
209
|
+
* it before changing anything back:
|
|
210
|
+
*
|
|
211
|
+
* "2px, matching Focus and matching Select. At 1px the invalid state differed
|
|
212
|
+
* from default only in hue, which is the exact failure mode WCAG 1.4.1 is
|
|
213
|
+
* about — error has to be perceivable without relying on colour alone.
|
|
214
|
+
* Reconciled in Figma; Input was the one that was wrong."
|
|
215
|
+
*
|
|
216
|
+
* That defect was found once and fixed once, and thinning the border reopens
|
|
217
|
+
* it: an invalid field now differs from a default field by hue alone. It was
|
|
218
|
+
* changed on an explicit design call on 5 Sep 2026, applied to Input and
|
|
219
|
+
* Textarea and to their Figma sets, and it is recorded here rather than left to
|
|
220
|
+
* look like drift.
|
|
221
|
+
*
|
|
222
|
+
* Select, Checkbox, Radio, Tabs and Menu still carry border-width/thick, so
|
|
223
|
+
* these two are deliberately out of step with the rest of the system.
|
|
224
|
+
*
|
|
225
|
+
* IF THE ERROR STATE NEEDS A NON-COLOUR CUE AGAIN, this is the decision to
|
|
226
|
+
* revisit — and an icon or a message would satisfy 1.4.1 without the border,
|
|
227
|
+
* which is the better fix than putting the 2px back.
|
|
207
228
|
*/
|
|
208
229
|
.ion-input--invalid,
|
|
209
230
|
.ion-input[data-invalid='true'] {
|
|
210
|
-
--ion-input-border-width: var(--border-width-thick);
|
|
211
|
-
|
|
212
231
|
border-color: var(--border-error-strong);
|
|
213
232
|
}
|
|
214
233
|
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Textarea
|
|
3
|
+
*
|
|
4
|
+
* Measured from Figma `Textarea` (1301:334). Three sizes x seven states, and
|
|
5
|
+
* every one of them is Input's — a textarea is an input that wrapped. If the
|
|
6
|
+
* two ever diverge it should be because a design said so, not because one
|
|
7
|
+
* drifted; the shared vocabulary is the point.
|
|
8
|
+
*
|
|
9
|
+
* THE HEIGHT IS DERIVED, NOT TYPED
|
|
10
|
+
*
|
|
11
|
+
* Figma's frame hugs a three-line text node, so the box height falls out of
|
|
12
|
+
* bound padding and a bound line-height rather than a number someone picked:
|
|
13
|
+
*
|
|
14
|
+
* sm 3 x 20 + 2 x 6 = 72
|
|
15
|
+
* md 3 x 24 + 2 x 8 = 88
|
|
16
|
+
* lg 3 x 24 + 2 x 12 = 96
|
|
17
|
+
*
|
|
18
|
+
* `rows={3}` reproduces that in the browser for free, and it keeps working when
|
|
19
|
+
* the type ramp moves. Do not replace it with a fixed `height` — that would
|
|
20
|
+
* pin the box while the text inside it kept scaling.
|
|
21
|
+
*
|
|
22
|
+
* THE RESIZE GRIP IS THE BROWSER'S, AND THIS FILE MUST NOT DRAW ONE
|
|
23
|
+
*
|
|
24
|
+
* `resize: vertical` makes the browser paint the two-diagonal grip in the
|
|
25
|
+
* bottom-right corner. Figma draws that grip too, at border/stronger — but as
|
|
26
|
+
* documentation of a native control, not as a spec for one. The native grip
|
|
27
|
+
* cannot be styled, so a custom one here would not replace it; it would sit
|
|
28
|
+
* beside it and every field would have two.
|
|
29
|
+
*
|
|
30
|
+
* Horizontal resize is off deliberately: a field that can grow wider than its
|
|
31
|
+
* container breaks the layout around it, and no design here asks for it.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
.ion-textarea {
|
|
35
|
+
--ion-textarea-padding-x: var(--spacing-12);
|
|
36
|
+
--ion-textarea-padding-y: var(--spacing-8);
|
|
37
|
+
--ion-textarea-radius: var(--radius-md);
|
|
38
|
+
--ion-textarea-font-size: var(--type-body);
|
|
39
|
+
--ion-textarea-line-height: var(--type-body-line-height);
|
|
40
|
+
--ion-textarea-border-width: var(--border-width-default);
|
|
41
|
+
|
|
42
|
+
display: block;
|
|
43
|
+
width: 100%;
|
|
44
|
+
box-sizing: border-box;
|
|
45
|
+
|
|
46
|
+
/*
|
|
47
|
+
* Same correction Input makes, and for the same reason: Figma draws its
|
|
48
|
+
* stroke INSIDE the frame so padding is measured from the outer edge, while a
|
|
49
|
+
* CSS border sits outside the padding box. Subtracting the live border width
|
|
50
|
+
* puts the text where Figma puts it.
|
|
51
|
+
*/
|
|
52
|
+
padding: var(--ion-textarea-padding-y)
|
|
53
|
+
calc(var(--ion-textarea-padding-x) - var(--ion-textarea-border-width));
|
|
54
|
+
background-color: var(--surface-default);
|
|
55
|
+
border-style: solid;
|
|
56
|
+
border-width: var(--ion-textarea-border-width);
|
|
57
|
+
border-color: var(--border-default);
|
|
58
|
+
border-radius: var(--ion-textarea-radius);
|
|
59
|
+
color: var(--text-secondary);
|
|
60
|
+
font-family: var(--font-family-sans);
|
|
61
|
+
font-size: var(--ion-textarea-font-size);
|
|
62
|
+
line-height: var(--ion-textarea-line-height);
|
|
63
|
+
font-weight: var(--font-weight-regular);
|
|
64
|
+
resize: vertical;
|
|
65
|
+
transition:
|
|
66
|
+
border-color var(--ion-duration-base) var(--ion-ease-out),
|
|
67
|
+
background-color var(--ion-duration-base) var(--ion-ease-out);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.ion-textarea--sm {
|
|
71
|
+
--ion-textarea-padding-y: var(--spacing-6);
|
|
72
|
+
--ion-textarea-radius: var(--radius-sm);
|
|
73
|
+
--ion-textarea-font-size: var(--type-body-sm);
|
|
74
|
+
--ion-textarea-line-height: var(--type-body-sm-line-height);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Large keeps Medium's radius and type ramp — only padding grows, as on Input. */
|
|
78
|
+
.ion-textarea--lg {
|
|
79
|
+
--ion-textarea-padding-x: var(--spacing-16);
|
|
80
|
+
--ion-textarea-padding-y: var(--spacing-12);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/*
|
|
84
|
+
* Figma's Filled state differs from Default only in the value colour, which is
|
|
85
|
+
* exactly the placeholder distinction — so it needs no variant, the same
|
|
86
|
+
* resolution input.css reached.
|
|
87
|
+
*
|
|
88
|
+
* text/tertiary, and THERE IS NO LONGER A text/placeholder TO REACH FOR.
|
|
89
|
+
*
|
|
90
|
+
* The role read 2.38:1 in Light and 2.33:1 in Dark against the 4.5 SC 1.4.3
|
|
91
|
+
* asks, and the criterion does not exempt placeholder text. Writing this file
|
|
92
|
+
* against the Figma binding failed 14 contrast pairings immediately, which is
|
|
93
|
+
* how the defect surfaced at all: no stylesheet had ever used the role, so
|
|
94
|
+
* nothing measured it. It was retired from Figma and the export on 5 Sep 2026
|
|
95
|
+
* rather than exempted, and Input's six bindings moved here too.
|
|
96
|
+
*
|
|
97
|
+
* Base Web makes the same call — `inputPlaceholder` points at `contentTertiary`
|
|
98
|
+
* and there is no placeholder colour. Carbon keeps one, at 2.38:1, and has an
|
|
99
|
+
* open issue about it.
|
|
100
|
+
*/
|
|
101
|
+
.ion-textarea::placeholder {
|
|
102
|
+
color: var(--text-tertiary);
|
|
103
|
+
opacity: 1;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/*
|
|
107
|
+
* State order is deliberate and equal-specificity, so later rules win:
|
|
108
|
+
* hover -> focus -> invalid -> read-only -> disabled.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/*
|
|
112
|
+
* Hover is declared twice, as on Input and Button. Native `:hover` latches on
|
|
113
|
+
* touch until you tap elsewhere; `[data-hovered]` comes from React Aria's
|
|
114
|
+
* useHover, which is pointer-aware. The media query keeps this working without
|
|
115
|
+
* React.
|
|
116
|
+
*/
|
|
117
|
+
@media (hover: hover) {
|
|
118
|
+
.ion-textarea:hover {
|
|
119
|
+
border-color: var(--border-strong);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.ion-textarea[data-hovered='true'] {
|
|
124
|
+
border-color: var(--border-strong);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.ion-textarea:focus,
|
|
128
|
+
.ion-textarea[data-focused='true'] {
|
|
129
|
+
border-color: var(--border-focus);
|
|
130
|
+
outline: none;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* 1px, matching Input as of 0.49.0. Input's stylesheet carries the full note:
|
|
135
|
+
* this width used to be 2px so the error state would not rest on hue alone,
|
|
136
|
+
* which is what WCAG 1.4.1 asks. It was thinned on an explicit design call, and
|
|
137
|
+
* an icon or a message is the better way to restore that cue.
|
|
138
|
+
*/
|
|
139
|
+
.ion-textarea--invalid,
|
|
140
|
+
.ion-textarea[data-invalid='true'] {
|
|
141
|
+
border-color: var(--border-error-strong);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
* Read-only keeps the value legible but drops the field out of the editable
|
|
146
|
+
* palette — page surface, subtle border. It stays resizable, which is what the
|
|
147
|
+
* browser does and what the Figma set shows.
|
|
148
|
+
*/
|
|
149
|
+
.ion-textarea--readonly,
|
|
150
|
+
.ion-textarea[data-readonly='true'] {
|
|
151
|
+
background-color: var(--surface-page);
|
|
152
|
+
border-color: var(--border-subtle);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
* Disabled turns resize off. A disabled textarea cannot be resized in any
|
|
157
|
+
* browser and none of them draw the grip on one, so `resize: none` here is
|
|
158
|
+
* matching the platform rather than making a choice.
|
|
159
|
+
*/
|
|
160
|
+
.ion-textarea:disabled,
|
|
161
|
+
.ion-textarea[data-disabled='true'] {
|
|
162
|
+
background-color: var(--surface-disabled);
|
|
163
|
+
border-color: var(--border-disabled);
|
|
164
|
+
color: var(--text-disabled);
|
|
165
|
+
cursor: not-allowed;
|
|
166
|
+
resize: none;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.ion-textarea:disabled::placeholder,
|
|
170
|
+
.ion-textarea[data-disabled='true']::placeholder {
|
|
171
|
+
color: var(--text-disabled);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@media (prefers-reduced-motion: reduce) {
|
|
175
|
+
.ion-textarea {
|
|
176
|
+
transition: none;
|
|
177
|
+
}
|
|
178
|
+
}
|
package/dist/tokens/index.d.ts
CHANGED
|
@@ -36,7 +36,6 @@ export declare const ui: {
|
|
|
36
36
|
readonly 'text/default': "var(--text-default)";
|
|
37
37
|
readonly 'text/secondary': "var(--text-secondary)";
|
|
38
38
|
readonly 'text/tertiary': "var(--text-tertiary)";
|
|
39
|
-
readonly 'text/placeholder': "var(--text-placeholder)";
|
|
40
39
|
readonly 'text/disabled': "var(--text-disabled)";
|
|
41
40
|
readonly 'text/on-color': "var(--text-on-color)";
|
|
42
41
|
readonly 'text/inverse': "var(--text-inverse)";
|
|
@@ -510,7 +509,6 @@ export declare const tokens: {
|
|
|
510
509
|
readonly 'text/default': "var(--text-default)";
|
|
511
510
|
readonly 'text/secondary': "var(--text-secondary)";
|
|
512
511
|
readonly 'text/tertiary': "var(--text-tertiary)";
|
|
513
|
-
readonly 'text/placeholder': "var(--text-placeholder)";
|
|
514
512
|
readonly 'text/disabled': "var(--text-disabled)";
|
|
515
513
|
readonly 'text/on-color': "var(--text-on-color)";
|
|
516
514
|
readonly 'text/inverse': "var(--text-inverse)";
|
|
@@ -1118,10 +1116,6 @@ export declare const tokenValues: {
|
|
|
1118
1116
|
readonly Light: "{neutral.600}";
|
|
1119
1117
|
readonly Dark: "{neutral.400}";
|
|
1120
1118
|
};
|
|
1121
|
-
readonly "text/placeholder": {
|
|
1122
|
-
readonly Light: "{neutral.400}";
|
|
1123
|
-
readonly Dark: "{neutral.600}";
|
|
1124
|
-
};
|
|
1125
1119
|
readonly "text/disabled": {
|
|
1126
1120
|
readonly Light: "{neutral.500}";
|
|
1127
1121
|
readonly Dark: "{neutral.500}";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAGA,0DAA0D;AAC1D,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Bb,CAAC;AAEX,6CAA6C;AAC7C,eAAO,MAAM,EAAE
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4iDd,CAAC"}
|
package/dist/tokens/index.js
CHANGED
|
@@ -38,7 +38,6 @@ export const ui = {
|
|
|
38
38
|
'text/default': 'var(--text-default)',
|
|
39
39
|
'text/secondary': 'var(--text-secondary)',
|
|
40
40
|
'text/tertiary': 'var(--text-tertiary)',
|
|
41
|
-
'text/placeholder': 'var(--text-placeholder)',
|
|
42
41
|
'text/disabled': 'var(--text-disabled)',
|
|
43
42
|
'text/on-color': 'var(--text-on-color)',
|
|
44
43
|
'text/inverse': 'var(--text-inverse)',
|
|
@@ -640,10 +639,6 @@ export const tokenValues = {
|
|
|
640
639
|
"Light": "{neutral.600}",
|
|
641
640
|
"Dark": "{neutral.400}"
|
|
642
641
|
},
|
|
643
|
-
"text/placeholder": {
|
|
644
|
-
"Light": "{neutral.400}",
|
|
645
|
-
"Dark": "{neutral.600}"
|
|
646
|
-
},
|
|
647
642
|
"text/disabled": {
|
|
648
643
|
"Light": "{neutral.500}",
|
|
649
644
|
"Dark": "{neutral.500}"
|