@astryxdesign/core 0.5.2-canary.d7c6772 → 0.5.2-canary.dc5565e
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/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +10 -4
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +4 -2
- package/dist/astryx.css +6 -1
- package/package.json +2 -2
- package/src/ComplexSelector/ComplexSelector.spec.md +1 -1
- package/src/Field/Field.doc.mjs +1 -0
- package/src/Field/Field.test.tsx +39 -0
- package/src/Field/Field.tsx +18 -1
- package/src/FieldStatus/FieldStatus.test.tsx +17 -0
- package/src/FieldStatus/FieldStatus.tsx +7 -2
- package/src/Layout/LayoutHeader.doc.mjs +9 -0
- package/src/MultiSelector/MultiSelector.spec.md +1 -1
- package/src/Selector/Selector.spec.md +8 -6
- package/src/TextArea/TextArea.spec.md +1 -1
- package/src/Tokenizer/Tokenizer.spec.md +5 -5
- package/src/Typeahead/Typeahead.spec.md +1 -1
- package/src/theme/derivedVarRegistry.test.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../src/Field/Field.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAM,MAAM,OAAO,CAAC;AAE1C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,4BAA4B,CAAC;AAEnE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"Field.d.ts","sourceRoot":"","sources":["../../src/Field/Field.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAM,MAAM,OAAO,CAAC;AAE1C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,4BAA4B,CAAC;AAEnE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AAmDtC,YAAY,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,EAAE,eAAe,CAAC;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAW,SAAQ,IAAI,CACtC,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,EACpB,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,OAAO,EACP,OAAO,EACP,YAAoB,EACpB,aAAa,EACb,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,SAAS,EACT,MAAM,EACN,YAAY,EACZ,aAA0B,EAC1B,KAAK,EACL,MAAM,EACN,QAAQ,EACR,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,UAAU,+BA2GZ;yBAjIe,KAAK"}
|
package/dist/Field/Field.js
CHANGED
|
@@ -20,7 +20,7 @@ import * as stylex from '@stylexjs/stylex';
|
|
|
20
20
|
import { FieldLabel } from "./FieldLabel.js";
|
|
21
21
|
import { FieldStatus } from "../FieldStatus/FieldStatus.js";
|
|
22
22
|
import "../theme/tokens.stylex.js";
|
|
23
|
-
import { spacingVars, borderVars } from "../theme/tokens.stylex.js";
|
|
23
|
+
import { spacingVars, borderVars, sizeVars } from "../theme/tokens.stylex.js";
|
|
24
24
|
import { mergeProps } from "../utils/index.js";
|
|
25
25
|
import { useDevWarning } from "../hooks/useDevWarning.js";
|
|
26
26
|
import { FormLayoutContext } from "../FormLayout/FormLayoutContext.js";
|
|
@@ -40,6 +40,11 @@ const styles = {
|
|
|
40
40
|
horizontalLabels: {
|
|
41
41
|
k1xSpc: "xjp7ctv",
|
|
42
42
|
$$css: true
|
|
43
|
+
},
|
|
44
|
+
attachedStatusLayer: {
|
|
45
|
+
kVAEAm: "x1n2onr6",
|
|
46
|
+
kY2c9j: "x8knxv4",
|
|
47
|
+
$$css: true
|
|
43
48
|
}
|
|
44
49
|
};
|
|
45
50
|
|
|
@@ -116,7 +121,8 @@ export function Field({
|
|
|
116
121
|
type: status.type,
|
|
117
122
|
message: status.message,
|
|
118
123
|
id: resolvedMessageID,
|
|
119
|
-
variant: statusVariant
|
|
124
|
+
variant: statusVariant,
|
|
125
|
+
xstyle: statusVariant === 'attached' ? styles.attachedStatusLayer : undefined
|
|
120
126
|
}) : null;
|
|
121
127
|
|
|
122
128
|
// ─── Horizontal-labels mode ───────────────────────────────────────────
|
|
@@ -138,7 +144,7 @@ export function Field({
|
|
|
138
144
|
children: labelNode
|
|
139
145
|
}), /*#__PURE__*/_jsxs("div", {
|
|
140
146
|
...{
|
|
141
|
-
className: "x78zum5 xdt5ytf xc8icb0"
|
|
147
|
+
className: "x78zum5 xdt5ytf xc8icb0 x19nvjgn xlumz0n x1qs65gq"
|
|
142
148
|
},
|
|
143
149
|
children: [description && /*#__PURE__*/_jsx(Text, {
|
|
144
150
|
type: "supporting",
|
|
@@ -157,7 +163,7 @@ export function Field({
|
|
|
157
163
|
...props,
|
|
158
164
|
children: [labelNode, statusVariant === 'attached' ? /*#__PURE__*/_jsxs("div", {
|
|
159
165
|
...{
|
|
160
|
-
className: "x78zum5 xdt5ytf xc8icb0"
|
|
166
|
+
className: "x78zum5 xdt5ytf xc8icb0 x19nvjgn xlumz0n x1qs65gq"
|
|
161
167
|
},
|
|
162
168
|
children: [children, statusNode]
|
|
163
169
|
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldStatus.d.ts","sourceRoot":"","sources":["../../src/FieldStatus/FieldStatus.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAU5C,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAKpD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"FieldStatus.d.ts","sourceRoot":"","sources":["../../src/FieldStatus/FieldStatus.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAU5C,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,gBAAgB,CAAC;AAKpD,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,SAAS,CAAC;AAqEnD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,cAAc,CAAC;IACjE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;OAEG;IACH,IAAI,EAAE,eAAe,CAAC;IACtB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,IAAI,EACJ,OAAO,EACP,EAAE,EACF,OAAoB,EACpB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,gBAAgB,qBAsDlB;yBAhEe,WAAW"}
|
|
@@ -36,6 +36,7 @@ const statusIconMap = {
|
|
|
36
36
|
error: 'error',
|
|
37
37
|
success: 'success'
|
|
38
38
|
};
|
|
39
|
+
const ATTACHED_OVERLAP = `var(--_field-status-overlap, ${spacingVars['--spacing-1-5']})`;
|
|
39
40
|
const styles = {
|
|
40
41
|
base: {
|
|
41
42
|
kMv6JI: "x9ynric",
|
|
@@ -44,12 +45,13 @@ const styles = {
|
|
|
44
45
|
$$css: true
|
|
45
46
|
},
|
|
46
47
|
attached: {
|
|
47
|
-
keoZOQ: "
|
|
48
|
-
kLKAdn: "
|
|
48
|
+
keoZOQ: "x3dbumh",
|
|
49
|
+
kLKAdn: "xdgtoc0",
|
|
49
50
|
kGO01o: "x1wesfrj",
|
|
50
51
|
kg3NbH: "xf314gf",
|
|
51
52
|
kVL7Gh: "xquck67",
|
|
52
53
|
kT0f0o: "x14i3lts",
|
|
54
|
+
kfzvcC: "x47corl",
|
|
53
55
|
$$css: true
|
|
54
56
|
},
|
|
55
57
|
detached: {
|
package/dist/astryx.css
CHANGED
|
@@ -114,6 +114,7 @@
|
|
|
114
114
|
.x1fcsqxe{--_dropdown-menu-radius:var(--radius-container)}
|
|
115
115
|
.x13l1x9d{--_fade-delay:0s}
|
|
116
116
|
.x1832zxr{--_field-radius:var(--radius-element)}
|
|
117
|
+
.x19nvjgn{--_field-status-overlap:calc(var(--size-element-md) / 2)}
|
|
117
118
|
.xgzxwq1{--_focus-outline-offset:0}
|
|
118
119
|
.x17wzz1v{--_focus-outline:none}
|
|
119
120
|
.xhg274n{--_hover-delay:0s}
|
|
@@ -352,6 +353,8 @@
|
|
|
352
353
|
.xoa21yc:focus-within{--_reveal-position:static}
|
|
353
354
|
.x11woleg:focus-visible{--indicator-color:var(--color-accent)}
|
|
354
355
|
.x1my2cv6.x1my2cv6:hover:where(:not(:disabled,[aria-disabled="true"])){--indicator-color:var(--color-accent)}
|
|
356
|
+
.x1qs65gq:has(> [data-size="lg"]){--_field-status-overlap:calc(var(--size-element-lg) / 2)}
|
|
357
|
+
.xlumz0n:has(> [data-size="sm"]){--_field-status-overlap:calc(var(--size-element-sm) / 2)}
|
|
355
358
|
.x158n88w:has(:focus-visible){--_tab-strip-bleed:calc(var(--focus-outline-width) + var(--focus-outline-offset))}
|
|
356
359
|
.x1ibt0lz:first-child{--separator-display:none}
|
|
357
360
|
.x1rht92:nth-child(even){--table-row-overlay:var(--color-background-muted)}
|
|
@@ -1295,6 +1298,7 @@
|
|
|
1295
1298
|
.x1yn0g08:not(#\#):not(#\#):not(#\#){word-break:break-all}
|
|
1296
1299
|
.x13faqbe:not(#\#):not(#\#):not(#\#){word-break:break-word}
|
|
1297
1300
|
.x1lldw8n:not(#\#):not(#\#):not(#\#){word-break:normal}
|
|
1301
|
+
.x8knxv4:not(#\#):not(#\#):not(#\#){z-index:-1}
|
|
1298
1302
|
.x1ja2u2z:not(#\#):not(#\#):not(#\#){z-index:0}
|
|
1299
1303
|
.x1vjfegm:not(#\#):not(#\#):not(#\#){z-index:1}
|
|
1300
1304
|
.xfo81ep:not(#\#):not(#\#):not(#\#){z-index:1000}
|
|
@@ -1589,6 +1593,7 @@
|
|
|
1589
1593
|
.xmqyaqf:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * (var(--_tab-strip-bleed)))}
|
|
1590
1594
|
.xvyqdj1:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * anchor-size(height) - 8px)}
|
|
1591
1595
|
.xckg3cf:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--_chat-composer-radius))}
|
|
1596
|
+
.x3dbumh:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--_field-status-overlap,var(--spacing-1-5)))}
|
|
1592
1597
|
.x5j3pgv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--astryx-number-input-padding-block-start,var(--astryx-number-input-padding,var(--spacing-1))))}
|
|
1593
1598
|
.x1sa9bsh:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--container-padding-block-start,0px))}
|
|
1594
1599
|
.x1c40v9y:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--spacing-1-5))}
|
|
@@ -1715,9 +1720,9 @@
|
|
|
1715
1720
|
.x2oz4g1:not(#\#):not(#\#):not(#\#):not(#\#){padding-bottom:var(--spacing-8)}
|
|
1716
1721
|
.xexx8yu:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:0}
|
|
1717
1722
|
.x1htvmrp:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:calc(var(--_chat-composer-padding) + var(--_chat-composer-radius))}
|
|
1723
|
+
.xdgtoc0:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:calc(var(--_field-status-overlap,var(--spacing-1-5)) + var(--spacing-2))}
|
|
1718
1724
|
.x1enrzb7:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:calc(var(--border-width) + var(--spacing-1))}
|
|
1719
1725
|
.x1nex4ik:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:calc(var(--container-padding-block-start) - var(--border-width))}
|
|
1720
|
-
.x1ak3mig:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:calc(var(--spacing-1-5) + var(--spacing-2))}
|
|
1721
1726
|
.x1vjezoa:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:max(var(--spacing-4),env(safe-area-inset-top,0px))}
|
|
1722
1727
|
.x2gtn7z:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:var(--_chat-composer-padding)}
|
|
1723
1728
|
.xlr2r7p:not(#\#):not(#\#):not(#\#):not(#\#){padding-top:var(--_tab-strip-bleed)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.5.2-canary.
|
|
3
|
+
"version": "0.5.2-canary.dc5565e",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -661,7 +661,7 @@
|
|
|
661
661
|
"react-dom": ">=19.0.0"
|
|
662
662
|
},
|
|
663
663
|
"devDependencies": {
|
|
664
|
-
"@astryxdesign/cli": "0.5.2-canary.
|
|
664
|
+
"@astryxdesign/cli": "0.5.2-canary.dc5565e",
|
|
665
665
|
"@babel/cli": "^8.0.4",
|
|
666
666
|
"@babel/core": "^7.29.7",
|
|
667
667
|
"@babel/preset-react": "^8.0.1",
|
|
@@ -18,7 +18,7 @@ verified_by:
|
|
|
18
18
|
scripts/check-knowledge.mjs,
|
|
19
19
|
]
|
|
20
20
|
modules: []
|
|
21
|
-
families: [family:overlay-dismissal]
|
|
21
|
+
families: [family:input-fields, family:overlay-dismissal]
|
|
22
22
|
design_specs: []
|
|
23
23
|
architecture:
|
|
24
24
|
[architecture:component-theming-surface, architecture:layer-runtime]
|
package/src/Field/Field.doc.mjs
CHANGED
|
@@ -39,6 +39,7 @@ export const docs = {
|
|
|
39
39
|
],
|
|
40
40
|
vars: [
|
|
41
41
|
{name: '--_field-radius', description: 'Border radius of input fields', default: 'var(--radius-element)', private: true},
|
|
42
|
+
{name: '--_field-status-overlap', description: 'Amount an attached FieldStatus extends behind the lower half of the control. Set from the rendered control size.', default: 'calc(var(--size-element-md) / 2)', private: true},
|
|
42
43
|
{name: '--_input-clear-hit-inset', description: 'Outset of the clear (\u2715) button\'s invisible hit area, applied to a ::after overlay. 0 on a fine pointer; negative on a coarse one, which grows the 20px button to the 24px touch target without changing what is drawn.', default: '0px', private: true},
|
|
43
44
|
{name: '--_input-clear-hit-content', description: 'Whether the clear (\u2715) button\'s invisible hit overlay exists. `none` on a fine pointer, so no ::after is generated and hover still reaches the glyph; `""` on a coarse one, where the overlay provides the 24px touch target.', default: 'none', private: true},
|
|
44
45
|
],
|
package/src/Field/Field.test.tsx
CHANGED
|
@@ -27,6 +27,45 @@ afterEach(() => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
describe('Field', () => {
|
|
30
|
+
it.each(['sm', 'md', 'lg'] as const)(
|
|
31
|
+
'provides a half-height overlap for an attached %s control',
|
|
32
|
+
size => {
|
|
33
|
+
render(
|
|
34
|
+
<Field
|
|
35
|
+
label="Username"
|
|
36
|
+
inputID="username"
|
|
37
|
+
status={{type: 'warning', message: 'This username may be taken'}}>
|
|
38
|
+
<div data-size={size}>Control</div>
|
|
39
|
+
</Field>,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const status = screen.getByText('This username may be taken');
|
|
43
|
+
expect(
|
|
44
|
+
getComputedStyle(status.parentElement!).getPropertyValue(
|
|
45
|
+
'--_field-status-overlap',
|
|
46
|
+
),
|
|
47
|
+
).toBe(`calc(var(--size-element-${size}) / 2)`);
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
it('layers an attached status behind a custom control', () => {
|
|
52
|
+
render(
|
|
53
|
+
<Field
|
|
54
|
+
label="Username"
|
|
55
|
+
inputID="username"
|
|
56
|
+
status={{type: 'warning', message: 'This username may be taken'}}>
|
|
57
|
+
<input id="username" />
|
|
58
|
+
</Field>,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const status = screen.getByText('This username may be taken');
|
|
62
|
+
const wrapper = status.parentElement!;
|
|
63
|
+
|
|
64
|
+
expect(getComputedStyle(wrapper).isolation).toBe('isolate');
|
|
65
|
+
expect(getComputedStyle(status).position).toBe('relative');
|
|
66
|
+
expect(getComputedStyle(status).zIndex).toBe('-1');
|
|
67
|
+
});
|
|
68
|
+
|
|
30
69
|
it('renders with label', () => {
|
|
31
70
|
render(
|
|
32
71
|
<Field label="Email" inputID="email-input">
|
package/src/Field/Field.tsx
CHANGED
|
@@ -23,7 +23,7 @@ import type {SizeValue} from '../utils/types';
|
|
|
23
23
|
import {FieldLabel} from './FieldLabel';
|
|
24
24
|
import {FieldStatus} from '../FieldStatus/FieldStatus';
|
|
25
25
|
import type {FieldStatusVariant} from '../FieldStatus/FieldStatus';
|
|
26
|
-
import {spacingVars, borderVars} from '../theme/tokens.stylex';
|
|
26
|
+
import {spacingVars, borderVars, sizeVars} from '../theme/tokens.stylex';
|
|
27
27
|
import type {IconType} from '../Icon';
|
|
28
28
|
import {mergeProps} from '../utils';
|
|
29
29
|
import {useDevWarning} from '../hooks/useDevWarning';
|
|
@@ -52,6 +52,20 @@ const styles = stylex.create({
|
|
|
52
52
|
display: 'flex',
|
|
53
53
|
flexDirection: 'column',
|
|
54
54
|
isolation: 'isolate',
|
|
55
|
+
// Extend an attached FieldStatus behind the lower half of the control.
|
|
56
|
+
// Half-height is the maximum effective corner radius CSS can render, even
|
|
57
|
+
// when a theme uses a pill value such as --radius-full (9999px).
|
|
58
|
+
'--_field-status-overlap': {
|
|
59
|
+
default: `calc(${sizeVars['--size-element-md']} / 2)`,
|
|
60
|
+
':has(> [data-size="sm"])': `calc(${sizeVars['--size-element-sm']} / 2)`,
|
|
61
|
+
':has(> [data-size="lg"])': `calc(${sizeVars['--size-element-lg']} / 2)`,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
attachedStatusLayer: {
|
|
65
|
+
// Keep the overlapping background below both Astryx inputs and custom
|
|
66
|
+
// controls. The isolated wrapper contains this negative stacking layer.
|
|
67
|
+
position: 'relative',
|
|
68
|
+
zIndex: -1,
|
|
55
69
|
},
|
|
56
70
|
});
|
|
57
71
|
|
|
@@ -250,6 +264,9 @@ export function Field({
|
|
|
250
264
|
message={status.message}
|
|
251
265
|
id={resolvedMessageID}
|
|
252
266
|
variant={statusVariant}
|
|
267
|
+
xstyle={
|
|
268
|
+
statusVariant === 'attached' ? styles.attachedStatusLayer : undefined
|
|
269
|
+
}
|
|
253
270
|
/>
|
|
254
271
|
) : null;
|
|
255
272
|
|
|
@@ -149,6 +149,23 @@ describe('FieldStatus', () => {
|
|
|
149
149
|
expect(el).toHaveAttribute('data-variant', 'attached');
|
|
150
150
|
expect(el).toHaveClass('attached');
|
|
151
151
|
});
|
|
152
|
+
|
|
153
|
+
it('extends the attached background by the field-provided overlap', () => {
|
|
154
|
+
render(<FieldStatus type="warning" message="msg" data-testid="fs" />);
|
|
155
|
+
const styles = getComputedStyle(screen.getByTestId('fs'));
|
|
156
|
+
|
|
157
|
+
expect(styles.marginTop).toBe(
|
|
158
|
+
'calc(-1 * var(--_field-status-overlap,var(--spacing-1-5)))',
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('does not intercept pointer input over the attached control', () => {
|
|
163
|
+
render(<FieldStatus type="warning" message="msg" data-testid="fs" />);
|
|
164
|
+
|
|
165
|
+
expect(getComputedStyle(screen.getByTestId('fs')).pointerEvents).toBe(
|
|
166
|
+
'none',
|
|
167
|
+
);
|
|
168
|
+
});
|
|
152
169
|
});
|
|
153
170
|
|
|
154
171
|
describe('color styling per status type', () => {
|
|
@@ -46,6 +46,8 @@ const statusIconMap: Record<InputStatusType, IconName> = {
|
|
|
46
46
|
success: 'success',
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
+
const ATTACHED_OVERLAP = `var(--_field-status-overlap, ${spacingVars['--spacing-1-5']})`;
|
|
50
|
+
|
|
49
51
|
const styles = stylex.create({
|
|
50
52
|
base: {
|
|
51
53
|
fontFamily: typographyVars['--font-family-body'],
|
|
@@ -53,12 +55,15 @@ const styles = stylex.create({
|
|
|
53
55
|
lineHeight: typeScaleVars['--text-supporting-leading'],
|
|
54
56
|
},
|
|
55
57
|
attached: {
|
|
56
|
-
marginTop: `calc(-1 * ${
|
|
57
|
-
paddingBlockStart: `calc(${
|
|
58
|
+
marginTop: `calc(-1 * ${ATTACHED_OVERLAP})`,
|
|
59
|
+
paddingBlockStart: `calc(${ATTACHED_OVERLAP} + ${spacingVars['--spacing-2']})`,
|
|
58
60
|
paddingBlockEnd: spacingVars['--spacing-2'],
|
|
59
61
|
paddingInline: spacingVars['--spacing-2'],
|
|
60
62
|
borderEndStartRadius: radiusVars['--radius-element'],
|
|
61
63
|
borderEndEndRadius: radiusVars['--radius-element'],
|
|
64
|
+
// The overlap is visual only. Let pointer input reach the control beneath
|
|
65
|
+
// it instead of allowing the later-painted status box to steal the click.
|
|
66
|
+
pointerEvents: 'none',
|
|
62
67
|
},
|
|
63
68
|
detached: {
|
|
64
69
|
marginTop: spacingVars['--spacing-1'],
|
|
@@ -8,6 +8,15 @@ export const docs = {
|
|
|
8
8
|
displayName: 'Layout Header',
|
|
9
9
|
isHiddenFromOverview: true,
|
|
10
10
|
description: 'Top bar for page titles, app bars, and toolbars.',
|
|
11
|
+
playground: {
|
|
12
|
+
defaults: {
|
|
13
|
+
children: 'Page Title',
|
|
14
|
+
hasDivider: true,
|
|
15
|
+
},
|
|
16
|
+
wrapper: {
|
|
17
|
+
component: 'Layout',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
11
20
|
props: [
|
|
12
21
|
{
|
|
13
22
|
name: 'children',
|
|
@@ -16,7 +16,7 @@ verified_by:
|
|
|
16
16
|
packages/core/src/Selector/Selector.source-build.test.mjs,
|
|
17
17
|
]
|
|
18
18
|
modules: []
|
|
19
|
-
families: []
|
|
19
|
+
families: [family:input-fields]
|
|
20
20
|
design_specs: []
|
|
21
21
|
architecture:
|
|
22
22
|
[
|
|
@@ -71,8 +71,9 @@ connection between the closed trigger and its selection surface.
|
|
|
71
71
|
- Multi-value selection; MultiSelector owns it.
|
|
72
72
|
- Product-specific option content or filtering performed outside the supplied
|
|
73
73
|
option list.
|
|
74
|
-
- Family-wide input
|
|
75
|
-
|
|
74
|
+
- Family-wide input state display, behavior, appearance, size, end-control,
|
|
75
|
+
status-placement, and disabled-reason policy — owned by current
|
|
76
|
+
`family:input-fields`.
|
|
76
77
|
|
|
77
78
|
## Public concepts
|
|
78
79
|
|
|
@@ -266,9 +267,10 @@ in `spec:AST-004` as current runtime behavior.
|
|
|
266
267
|
has changed.
|
|
267
268
|
- `spec:AST-011/DEC-1` owns the additive read-only state: caller-owned policy can
|
|
268
269
|
preserve a focusable, submittable value without exposing selection controls.
|
|
269
|
-
- `family:input-fields`
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
- `family:input-fields` owns family-wide state display, behavior, appearance,
|
|
271
|
+
size, end-control, disabled-reason, and status-placement policy. Selector
|
|
272
|
+
keeps its DEC-1 standalone inline-size exception; this component contract
|
|
273
|
+
owns selection behavior inside that boundary.
|
|
272
274
|
|
|
273
275
|
## Verification map
|
|
274
276
|
|
|
@@ -18,7 +18,7 @@ verified_by:
|
|
|
18
18
|
scripts/check-knowledge.mjs,
|
|
19
19
|
]
|
|
20
20
|
modules: []
|
|
21
|
-
families: [family:overlay-dismissal]
|
|
21
|
+
families: [family:input-fields, family:overlay-dismissal]
|
|
22
22
|
design_specs: []
|
|
23
23
|
architecture:
|
|
24
24
|
[
|
|
@@ -222,10 +222,10 @@ This contract adds no target, state, or visual styling contract.
|
|
|
222
222
|
geometry and package-peer identity out of Tokenizer's public API.
|
|
223
223
|
- The current Typeahead draft records BaseTypeahead's layer delegation but does
|
|
224
224
|
not own Tokenizer's token/input identity or the approved descriptor.
|
|
225
|
-
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
225
|
+
- `family:input-fields` owns family-wide state display, behavior, appearance,
|
|
226
|
+
size, end-control, disabled-reason, and status-placement policy. Tokenizer
|
|
227
|
+
keeps its component-local token/input and source-loading behavior inside that
|
|
228
|
+
boundary.
|
|
229
229
|
- The PowerSearch contract at
|
|
230
230
|
[#5804](https://github.com/facebook/astryx/pull/5804) depends on the approved
|
|
231
231
|
descriptor and owns its own editor width policy. It is dependent draft evidence,
|
|
@@ -20,7 +20,7 @@ verified_by:
|
|
|
20
20
|
scripts/check-knowledge.mjs,
|
|
21
21
|
]
|
|
22
22
|
modules: []
|
|
23
|
-
families: [family:overlay-dismissal]
|
|
23
|
+
families: [family:input-fields, family:overlay-dismissal]
|
|
24
24
|
design_specs: []
|
|
25
25
|
architecture:
|
|
26
26
|
[architecture:component-theming-surface, architecture:layer-runtime]
|
|
@@ -272,6 +272,7 @@ const VARS_WITHOUT_DERIVED_MAPPING = new Set([
|
|
|
272
272
|
'--button-focus-offset',
|
|
273
273
|
'--button-icon-only-aspect',
|
|
274
274
|
'--_avatar-group-overlap',
|
|
275
|
+
'--_field-status-overlap',
|
|
275
276
|
'--_codeblock-gutter-width',
|
|
276
277
|
'--_tab-indicator-bottom',
|
|
277
278
|
// Hit-area outset on a ::after overlay, and whether that overlay is
|