@astryxdesign/core 0.5.0-canary.f4d494c → 0.5.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/Avatar/Avatar.d.ts +1 -25
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +9 -43
- package/dist/Avatar/index.d.ts +2 -2
- package/dist/Avatar/index.d.ts.map +1 -1
- package/dist/Avatar/index.js +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +2 -9
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +2 -5
- package/dist/AvatarGroup/AvatarGroupContext.d.ts +1 -2
- package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +6 -10
- package/dist/DateInput/DateInput.d.ts +0 -43
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +0 -19
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +3 -52
- package/dist/HoverCard/useHoverCard.d.ts +2 -11
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +0 -2
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +2 -6
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +26 -2
- package/dist/astryx.css +0 -21
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +25 -3
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +0 -4
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.js +2 -5
- package/package.json +3 -3
- package/src/Avatar/Avatar.doc.mjs +2 -12
- package/src/Avatar/Avatar.test.tsx +0 -80
- package/src/Avatar/Avatar.tsx +14 -64
- package/src/Avatar/index.ts +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -8
- package/src/AvatarGroup/AvatarGroup.test.tsx +0 -24
- package/src/AvatarGroup/AvatarGroup.tsx +4 -12
- package/src/AvatarGroup/AvatarGroupContext.ts +3 -5
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +4 -10
- package/src/DateInput/DateInput.doc.mjs +0 -16
- package/src/DateInput/DateInput.tsx +0 -52
- package/src/DateInput/DateInputTouch.test.tsx +9 -32
- package/src/DateInput/index.ts +0 -1
- package/src/HoverCard/HoverCard.test.tsx +4 -84
- package/src/HoverCard/HoverCard.tsx +3 -65
- package/src/HoverCard/useHoverCard.tsx +2 -15
- package/src/Indicator/CheckboxIndicator.tsx +8 -14
- package/src/Indicator/Indicator.doc.mjs +0 -2
- package/src/Kbd/Kbd.test.tsx +17 -0
- package/src/Kbd/Kbd.tsx +26 -2
- package/src/hooks/useHotkeys.test.ts +18 -0
- package/src/hooks/useHotkeys.ts +25 -3
- package/src/theme/derivedVarRegistry.test.ts +0 -1
- package/src/theme/derivedVarRegistry.ts +0 -1
- package/src/theme/syntax/tokens.ts +2 -5
- package/dist/DateInput/NativeDateField.d.ts +0 -10
- package/dist/DateInput/NativeDateField.d.ts.map +0 -1
- package/dist/DateInput/NativeDateField.js +0 -477
- package/dist/utils/isApplePlatform.d.ts +0 -18
- package/dist/utils/isApplePlatform.d.ts.map +0 -1
- package/dist/utils/isApplePlatform.js +0 -37
- package/src/DateInput/NativeDateField.test.tsx +0 -565
- package/src/DateInput/NativeDateField.tsx +0 -623
- package/src/utils/isApplePlatform.test.ts +0 -61
- package/src/utils/isApplePlatform.ts +0 -37
|
@@ -155,9 +155,7 @@ export function CheckboxIndicator({
|
|
|
155
155
|
children: isRenderable(children) ? children : /*#__PURE__*/_jsxs(_Fragment, {
|
|
156
156
|
children: [/*#__PURE__*/_jsx("svg", {
|
|
157
157
|
viewBox: "0 0 10 10",
|
|
158
|
-
...
|
|
159
|
-
size
|
|
160
|
-
}), stylex.props(styles.checkmark, checkmarkSizeStyles[size], isChecked && styles.checkmarkVisible)),
|
|
158
|
+
...stylex.props(styles.checkmark, checkmarkSizeStyles[size], isChecked && styles.checkmarkVisible),
|
|
161
159
|
children: /*#__PURE__*/_jsx("path", {
|
|
162
160
|
d: "M8.5 2.5L4 7.5L1.5 5",
|
|
163
161
|
stroke: "currentColor",
|
|
@@ -167,9 +165,7 @@ export function CheckboxIndicator({
|
|
|
167
165
|
strokeLinejoin: "round"
|
|
168
166
|
})
|
|
169
167
|
}), /*#__PURE__*/_jsx("span", {
|
|
170
|
-
...
|
|
171
|
-
size
|
|
172
|
-
}), stylex.props(styles.indeterminateMark, indeterminateSizeStyles[size], isIndeterminate && styles.indeterminateMarkVisible))
|
|
168
|
+
...stylex.props(styles.indeterminateMark, indeterminateSizeStyles[size], isIndeterminate && styles.indeterminateMarkVisible)
|
|
173
169
|
})]
|
|
174
170
|
})
|
|
175
171
|
});
|
package/dist/Kbd/Kbd.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Kbd.d.ts","sourceRoot":"","sources":["../../src/Kbd/Kbd.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,OAAO,KAA6B,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Kbd.d.ts","sourceRoot":"","sources":["../../src/Kbd/Kbd.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,OAAO,KAA6B,MAAM,OAAO,CAAC;AAGlD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAmI5C,MAAM,WAAW,QAAS,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC1D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC;;;;;;;;;;;;OAYG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,GAAG,CAAC,EAAC,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,IAAI,EAAC,EAAE,QAAQ,qBAgC3E;yBAhCe,GAAG"}
|
package/dist/Kbd/Kbd.js
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
import React, { useSyncExternalStore } from 'react';
|
|
16
16
|
import * as stylex from '@stylexjs/stylex';
|
|
17
17
|
import { mergeProps } from "../utils/index.js";
|
|
18
|
-
import { isApplePlatform } from "../utils/isApplePlatform.js";
|
|
19
18
|
import { themeProps } from "../utils/themeProps.js";
|
|
20
19
|
import "../theme/tokens.stylex.js";
|
|
21
20
|
import { colorVars, spacingVars, radiusVars, typographyVars, fontWeightVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
@@ -99,6 +98,31 @@ function subscribeToPlatformChanges() {
|
|
|
99
98
|
function getServerPlatformSnapshot() {
|
|
100
99
|
return false;
|
|
101
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Detects whether the current platform is macOS/iOS.
|
|
104
|
+
* Prefers the User-Agent Client Hints API when it names a platform (modern
|
|
105
|
+
* Chrome/Edge), falls back to navigator.platform (deprecated but universally
|
|
106
|
+
* supported) when it is absent or blank.
|
|
107
|
+
*/
|
|
108
|
+
function detectMac() {
|
|
109
|
+
if (typeof navigator === 'undefined') {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
// Prefer User-Agent Client Hints API (not deprecated)
|
|
113
|
+
const uaData = 'userAgentData' in navigator ? navigator.userAgentData : null;
|
|
114
|
+
if (uaData && typeof uaData === 'object' && 'platform' in uaData) {
|
|
115
|
+
const uaPlatform = uaData.platform;
|
|
116
|
+
// A blank platform is no answer, not a negative one. Builds that rewrite
|
|
117
|
+
// their client-hints identity ship '', so fall through rather than
|
|
118
|
+
// reading it as "not Apple".
|
|
119
|
+
if (typeof uaPlatform === 'string' && uaPlatform.trim() !== '') {
|
|
120
|
+
return /mac/i.test(uaPlatform);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Fallback: navigator.platform (deprecated but still shipped everywhere)
|
|
124
|
+
return /Mac|iPhone|iPad|iPod/.test(navigator.platform ?? '');
|
|
125
|
+
}
|
|
102
126
|
/**
|
|
103
127
|
* Displays a keyboard shortcut as styled <kbd> elements.
|
|
104
128
|
*
|
|
@@ -122,7 +146,7 @@ export function Kbd({
|
|
|
122
146
|
style,
|
|
123
147
|
...rest
|
|
124
148
|
}) {
|
|
125
|
-
const isMac = useSyncExternalStore(subscribeToPlatformChanges,
|
|
149
|
+
const isMac = useSyncExternalStore(subscribeToPlatformChanges, detectMac, getServerPlatformSnapshot);
|
|
126
150
|
const parts = keys.split('+').map(key => key.trim().toLowerCase());
|
|
127
151
|
|
|
128
152
|
// Screen-reader name: the joined spoken labels (e.g. "Command + K"), since
|
package/dist/astryx.css
CHANGED
|
@@ -79,9 +79,6 @@
|
|
|
79
79
|
:root, .x1kvdh9l{--spacing-0:0px;--spacing-0-5:2px;--spacing-1:4px;--spacing-1-5:6px;--spacing-2:8px;--spacing-3:12px;--spacing-4:16px;--spacing-5:20px;--spacing-6:24px;--spacing-7:28px;--spacing-8:32px;--spacing-9:36px;--spacing-10:40px;--spacing-11:44px;--spacing-12:48px;}
|
|
80
80
|
:root, .x1etlgq0{--text-heading-1-size:var(--font-size-2xl);--text-heading-1-weight:var(--font-weight-semibold);--text-heading-1-leading:1.3333;--text-heading-2-size:var(--font-size-xl);--text-heading-2-weight:var(--font-weight-semibold);--text-heading-2-leading:1.4;--text-heading-3-size:var(--font-size-lg);--text-heading-3-weight:var(--font-weight-semibold);--text-heading-3-leading:1.4118;--text-heading-4-size:var(--font-size-base);--text-heading-4-weight:var(--font-weight-semibold);--text-heading-4-leading:1.4286;--text-heading-5-size:var(--font-size-sm);--text-heading-5-weight:var(--font-weight-semibold);--text-heading-5-leading:1.6667;--text-heading-6-size:var(--font-size-xs);--text-heading-6-weight:var(--font-weight-semibold);--text-heading-6-leading:1.6;--text-body-size:var(--font-size-base);--text-body-weight:var(--font-weight-normal);--text-body-leading:1.4286;--text-large-size:var(--font-size-lg);--text-large-weight:var(--font-weight-semibold);--text-large-leading:1.4118;--text-label-size:var(--font-size-base);--text-label-weight:var(--font-weight-medium);--text-label-leading:1.4286;--text-code-size:var(--font-size-base);--text-code-weight:var(--font-weight-normal);--text-code-leading:1.4286;--text-supporting-size:var(--font-size-sm);--text-supporting-weight:var(--font-weight-normal);--text-supporting-leading:1.6667;--text-display-1-size:var(--font-size-5xl);--text-display-1-weight:var(--font-weight-normal);--text-display-1-leading:1.2381;--text-display-2-size:var(--font-size-4xl);--text-display-2-weight:var(--font-weight-normal);--text-display-2-leading:1.2571;--text-display-3-size:var(--font-size-3xl);--text-display-3-weight:var(--font-weight-normal);--text-display-3-leading:1.2414;}
|
|
81
81
|
.xlz5hwt{--_avatar-group-overlap:var(--x---_avatar-group-overlap)}
|
|
82
|
-
.xdarwi0{--_avatar-radius:var(--radius-element)}
|
|
83
|
-
.xeincmr{--_avatar-radius:var(--radius-full)}
|
|
84
|
-
.x877142{--_avatar-radius:var(--radius-none)}
|
|
85
82
|
.xh8ntw8{--_button-radius:calc(var(--radius-element) - var(--spacing-1))}
|
|
86
83
|
.xcw7vlg{--_button-radius:max(var(--radius-element),calc(var(--_chat-composer-radius) - var(--_chat-composer-padding)))}
|
|
87
84
|
.x1rjw8qi{--_button-radius:var(--radius-full)}
|
|
@@ -404,7 +401,6 @@
|
|
|
404
401
|
.x1pjcqnp:not(#\#):not(#\#){border-radius:inherit}
|
|
405
402
|
.x1ws5lxm:not(#\#):not(#\#){border-radius:max(0px,calc(var(--_dropdown-menu-radius,var(--spacing-2)) - var(--_dropdown-menu-padding,var(--spacing-1))))}
|
|
406
403
|
.xc910v0:not(#\#):not(#\#){border-radius:max(0px,calc(var(--_segmented-control-radius) - var(--_segmented-control-padding)))}
|
|
407
|
-
.xbc78cj:not(#\#):not(#\#){border-radius:var(--_avatar-radius)}
|
|
408
404
|
.x1vf2byn:not(#\#):not(#\#){border-radius:var(--_banner-radius,var(--radius-container))}
|
|
409
405
|
.x1jxw6zd:not(#\#):not(#\#){border-radius:var(--_button-radius,var(--radius-element))}
|
|
410
406
|
.xy0xnkn:not(#\#):not(#\#){border-radius:var(--_button-radius,var(--radius-full))}
|
|
@@ -438,7 +434,6 @@
|
|
|
438
434
|
.x98rzlu:not(#\#):not(#\#){flex:1}
|
|
439
435
|
.xxhr3t:not(#\#):not(#\#){gap:0}
|
|
440
436
|
.x1jnr06f:not(#\#):not(#\#){gap:4px}
|
|
441
|
-
.x167g77z:not(#\#):not(#\#){gap:8px}
|
|
442
437
|
.x14kbac9:not(#\#):not(#\#){gap:inherit}
|
|
443
438
|
.x1lsbc85:not(#\#):not(#\#){gap:var(--spacing-0-5)}
|
|
444
439
|
.xsn7fz1:not(#\#):not(#\#){gap:var(--spacing-0)}
|
|
@@ -563,7 +558,6 @@
|
|
|
563
558
|
@media (hover: hover){.x61roa7.x61roa7.x61roa7:where(.x1odsvnm:hover *):not(#\#):not(#\#){border-color:var(--color-border)}}
|
|
564
559
|
@media (hover: hover){.x1xwh4np.x1xwh4np.x1xwh4np:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#){border-color:var(--color-border-emphasized)}}
|
|
565
560
|
@media (hover: hover){.x13nosk6.x13nosk6.x13nosk6:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#){text-decoration:underline}}
|
|
566
|
-
.x1lugfcp:not(#\#):not(#\#):not(#\#){-webkit-appearance:none}
|
|
567
561
|
.x67t5t6:not(#\#):not(#\#):not(#\#){-webkit-backdrop-filter:blur(12px)}
|
|
568
562
|
.x1ua5tub:not(#\#):not(#\#):not(#\#){-webkit-box-orient:vertical}
|
|
569
563
|
.x1yhjpo9:not(#\#):not(#\#):not(#\#){-webkit-line-clamp:var(--x-WebkitLineClamp)}
|
|
@@ -573,7 +567,6 @@
|
|
|
573
567
|
.xt2iwb0:not(#\#):not(#\#):not(#\#){-webkit-mask-image:linear-gradient(transparent,transparent)}
|
|
574
568
|
.x5lxg6s:not(#\#):not(#\#):not(#\#){-webkit-overflow-scrolling:touch}
|
|
575
569
|
.x1i10hfl:not(#\#):not(#\#):not(#\#){-webkit-tap-highlight-color:transparent}
|
|
576
|
-
.xg7jpbn:not(#\#):not(#\#):not(#\#){-webkit-text-fill-color:transparent}
|
|
577
570
|
.xpdipgo:not(#\#):not(#\#):not(#\#){-webkit-touch-callout:none}
|
|
578
571
|
.x8gbvx8:not(#\#):not(#\#):not(#\#){align-content:flex-start}
|
|
579
572
|
.x1pha0wt:not(#\#):not(#\#):not(#\#){align-items:baseline}
|
|
@@ -1153,7 +1146,6 @@
|
|
|
1153
1146
|
.x3oybdh:not(#\#):not(#\#):not(#\#){transform:scale(1)}
|
|
1154
1147
|
.x11lhmoz:not(#\#):not(#\#):not(#\#){transform:translate(-50%,-50%)}
|
|
1155
1148
|
.x1m9mm8y:not(#\#):not(#\#):not(#\#){transform:translate(-50%,50%)}
|
|
1156
|
-
.xv8yid9:not(#\#):not(#\#):not(#\#){transform:translate(25%,25%)}
|
|
1157
1149
|
.x4v1no5:not(#\#):not(#\#):not(#\#){transform:translate(50%,50%)}
|
|
1158
1150
|
.x5i6ehr:not(#\#):not(#\#):not(#\#){transform:translateX(-100%)}
|
|
1159
1151
|
.xuuh30:not(#\#):not(#\#):not(#\#){transform:translateX(-50%)}
|
|
@@ -1303,7 +1295,6 @@
|
|
|
1303
1295
|
.xaafvuh:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1) rotate(0deg)}
|
|
1304
1296
|
.x1nxqau:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1) rotate(90deg)}
|
|
1305
1297
|
.xgtlewx:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1)}
|
|
1306
|
-
.x10fxb7p:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:translate(-25%,25%)}
|
|
1307
1298
|
.xqgnvz5:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:translate(-50%,50%)}
|
|
1308
1299
|
.xoffwj3:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:translate(50%,-50%)}
|
|
1309
1300
|
.x1df3fe5:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:translateX(-100%)}
|
|
@@ -1472,7 +1463,6 @@
|
|
|
1472
1463
|
.xs02d24:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(100% + 1px)}
|
|
1473
1464
|
.x12qplqi:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(100% + var(--container-padding-block-start,0px) + var(--container-padding-block-end,0px))}
|
|
1474
1465
|
.xpa73km:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(100dvh - var(--_app-shell-header-height,0px))}
|
|
1475
|
-
.x1oglpa6:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(max(1rem,var(--text-body-size)) * var(--text-body-leading));height:1lh}
|
|
1476
1466
|
.x1tpcejd:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--_sheet-budget) + 48px)}
|
|
1477
1467
|
.x1uiybsj:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-lg) - 4px)}
|
|
1478
1468
|
.x102lyln:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-lg) - 8px)}
|
|
@@ -1776,13 +1766,7 @@
|
|
|
1776
1766
|
.xxyica1:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{border-radius:inherit}
|
|
1777
1767
|
.x17gn2l9:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{grid-column:1}
|
|
1778
1768
|
.xd54j2p:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset-block:0}
|
|
1779
|
-
.xpsyfx0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{margin-block:0}
|
|
1780
|
-
.x1qqcexc:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{margin-inline:0}
|
|
1781
|
-
.x1x4c3m6:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{padding-block:0}
|
|
1782
|
-
.xtbxizx:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-datetime-edit{padding-block:0}
|
|
1783
1769
|
@starting-style{.x5rzir7.x5rzir7:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){padding-bottom:0}}
|
|
1784
|
-
.xkqr7wz:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{padding-inline:0}
|
|
1785
|
-
.xslb4at:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-datetime-edit{padding-inline:0}
|
|
1786
1770
|
.xvtkv6q:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{transition:background-color .15s ease,width .15s ease}
|
|
1787
1771
|
.x17s1k9h:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{transition:opacity .15s ease}
|
|
1788
1772
|
.x19ds33d:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{align-self:start}
|
|
@@ -1806,15 +1790,12 @@
|
|
|
1806
1790
|
.xc2ndz5:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{content:counter(astryx-list) "."}
|
|
1807
1791
|
.xh3pasq:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{content:var(--_input-clear-hit-content)}
|
|
1808
1792
|
.xhkezso:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{display:block}
|
|
1809
|
-
.xolhmmf:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-calendar-picker-indicator{display:none}
|
|
1810
1793
|
.x3nzp0f:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{font-family:var(--font-family-code)}
|
|
1811
1794
|
.xekda60:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{inset-inline-end:-2px}
|
|
1812
1795
|
.x1unh1gc:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset-inline-end:0}
|
|
1813
1796
|
.xvw6utc:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{inset-inline-start:-2px}
|
|
1814
1797
|
.x1iygr5g:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset-inline-start:0}
|
|
1815
1798
|
.x1km86hw:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset-inline-start:calc(var(--spacing-4) + var(--_codeblock-gutter-width) + var(--spacing-3))}
|
|
1816
|
-
.x15bqym3:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-datetime-edit{line-height:inherit}
|
|
1817
|
-
.x1f74mqm:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{line-height:inherit}
|
|
1818
1799
|
.xph5o2a:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{opacity:0}
|
|
1819
1800
|
.xb3n6bw:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{opacity:1}
|
|
1820
1801
|
.xni466t:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::backdrop{opacity:var(--_sheet-scrim-opacity,1)}
|
|
@@ -1825,7 +1806,6 @@
|
|
|
1825
1806
|
.x1hmns74:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{position:absolute}
|
|
1826
1807
|
.x1j6awrg:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{position:absolute}
|
|
1827
1808
|
.x1wnbjh8:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{text-align:end}
|
|
1828
|
-
.x9rmy9g:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{text-align:start}
|
|
1829
1809
|
.x1fgylwi:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transform-origin:center top}
|
|
1830
1810
|
.xgu12d:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transform-origin:left center}
|
|
1831
1811
|
.x1e8txe:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transform:scaleX(0)}
|
|
@@ -1865,7 +1845,6 @@
|
|
|
1865
1845
|
.xe80sof:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{bottom:-2px}
|
|
1866
1846
|
.x1xrz1ek:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{bottom:0}
|
|
1867
1847
|
.xu6fald:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{height:var(--_sheet-keyboard-inset,0px)}
|
|
1868
|
-
.xec4aax:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{min-height:0}
|
|
1869
1848
|
.x51xajf:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{top:-2px}
|
|
1870
1849
|
.x1m1drc7:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{top:0}
|
|
1871
1850
|
.xkj6t0a:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{width:0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useHotkeys.d.ts","sourceRoot":"","sources":["../../src/hooks/useHotkeys.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useHotkeys.d.ts","sourceRoot":"","sources":["../../src/hooks/useHotkeys.ts"],"names":[],"mappings":"AA6BA;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;;;;;;;;;;;;;;OAeG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAkGD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAkClD"}
|
package/dist/hooks/useHotkeys.js
CHANGED
|
@@ -18,15 +18,13 @@
|
|
|
18
18
|
* unless a hotkey opts in via `allowInInputs`.
|
|
19
19
|
*
|
|
20
20
|
* Platform-aware: `mod` maps to metaKey (⌘) on Apple platforms and
|
|
21
|
-
* ctrlKey elsewhere
|
|
22
|
-
* displayed and handled shortcuts cannot disagree.
|
|
21
|
+
* ctrlKey elsewhere — mirrors the detection used by Kbd.
|
|
23
22
|
*
|
|
24
23
|
* SYNC: When modified, update:
|
|
25
24
|
* - /packages/core/src/hooks/index.ts
|
|
26
25
|
* - /packages/core/src/hooks/useHotkeys.doc.mjs
|
|
27
26
|
*/
|
|
28
27
|
import { useEffect, useRef } from 'react';
|
|
29
|
-
import { isApplePlatform } from "../utils/isApplePlatform.js";
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
* A single keyboard shortcut registration.
|
|
@@ -44,6 +42,30 @@ const KEY_ALIASES = {
|
|
|
44
42
|
plus: '+'
|
|
45
43
|
};
|
|
46
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Detects whether the current platform is macOS/iOS.
|
|
47
|
+
* Prefers the User-Agent Client Hints API when it names a platform (modern
|
|
48
|
+
* Chrome/Edge), falls back to navigator.platform (deprecated but universally
|
|
49
|
+
* supported) when it is absent or blank.
|
|
50
|
+
* Mirrors the detection used by Kbd so displayed and handled shortcuts agree.
|
|
51
|
+
*/
|
|
52
|
+
function isApplePlatform() {
|
|
53
|
+
if (typeof navigator === 'undefined') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const uaData = 'userAgentData' in navigator ? navigator.userAgentData : null;
|
|
57
|
+
if (uaData && typeof uaData === 'object' && 'platform' in uaData) {
|
|
58
|
+
const uaPlatform = uaData.platform;
|
|
59
|
+
// A blank platform is no answer, not a negative one. Builds that rewrite
|
|
60
|
+
// their client-hints identity ship '', so fall through rather than
|
|
61
|
+
// reading it as "not Apple".
|
|
62
|
+
if (typeof uaPlatform === 'string' && uaPlatform.trim() !== '') {
|
|
63
|
+
return /mac/i.test(uaPlatform);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return /Mac|iPhone|iPad|iPod/.test(navigator.platform ?? '');
|
|
67
|
+
}
|
|
68
|
+
|
|
47
69
|
/**
|
|
48
70
|
* Whether the event target is a typing surface where global shortcuts
|
|
49
71
|
* should stay silent by default.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivedVarRegistry.d.ts","sourceRoot":"","sources":["../../src/theme/derivedVarRegistry.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"derivedVarRegistry.d.ts","sourceRoot":"","sources":["../../src/theme/derivedVarRegistry.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CA8ChE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,eAAe,EAAE,CAMnB"}
|
|
@@ -29,7 +29,7 @@ export declare const syntaxTokenDefaults: {
|
|
|
29
29
|
readonly '--color-syntax-tag': "var(--color-text-red)";
|
|
30
30
|
readonly '--color-syntax-attribute': "var(--color-text-teal)";
|
|
31
31
|
readonly '--color-syntax-property': "var(--color-text-cyan)";
|
|
32
|
-
readonly '--color-syntax-punctuation': "var(--color-text-
|
|
32
|
+
readonly '--color-syntax-punctuation': "var(--color-text-disabled)";
|
|
33
33
|
readonly '--color-syntax-background': "var(--color-background-muted)";
|
|
34
34
|
};
|
|
35
35
|
export type SyntaxTokenName = keyof typeof syntaxTokenDefaults;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/theme/syntax/tokens.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../src/theme/syntax/tokens.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;CA6BtB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,mBAAmB,CAAC"}
|
|
@@ -44,11 +44,8 @@ export const syntaxTokenDefaults = {
|
|
|
44
44
|
'--color-syntax-attribute': 'var(--color-text-teal)',
|
|
45
45
|
// property -> cyan text (object properties)
|
|
46
46
|
'--color-syntax-property': 'var(--color-text-cyan)',
|
|
47
|
-
// punctuation ->
|
|
48
|
-
|
|
49
|
-
// controls), and punctuation in a code sample is normal, always-active
|
|
50
|
-
// text — see #5386.
|
|
51
|
-
'--color-syntax-punctuation': 'var(--color-text-secondary)',
|
|
47
|
+
// punctuation -> disabled text (brackets, semicolons)
|
|
48
|
+
'--color-syntax-punctuation': 'var(--color-text-disabled)',
|
|
52
49
|
// background -> muted surface
|
|
53
50
|
'--color-syntax-background': 'var(--color-background-muted)'
|
|
54
51
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.5.0
|
|
3
|
+
"version": "0.5.0",
|
|
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,6 @@
|
|
|
661
661
|
"react-dom": ">=19.0.0"
|
|
662
662
|
},
|
|
663
663
|
"devDependencies": {
|
|
664
|
-
"@astryxdesign/cli": "0.5.0-canary.f4d494c",
|
|
665
664
|
"@babel/cli": "^8.0.4",
|
|
666
665
|
"@babel/core": "^7.29.7",
|
|
667
666
|
"@babel/preset-react": "^8.0.1",
|
|
@@ -670,7 +669,8 @@
|
|
|
670
669
|
"@testing-library/dom": "^10.0.0",
|
|
671
670
|
"@testing-library/jest-dom": "^6.6.0",
|
|
672
671
|
"@testing-library/react": "^16.3.2",
|
|
673
|
-
"rimraf": "^6.0.1"
|
|
672
|
+
"rimraf": "^6.0.1",
|
|
673
|
+
"@astryxdesign/cli": "0.5.0"
|
|
674
674
|
},
|
|
675
675
|
"dependencies": {
|
|
676
676
|
"intl-messageformat": "^11.2.9"
|
|
@@ -19,7 +19,7 @@ export const docs = {
|
|
|
19
19
|
{guidance: true, description: 'Give every interactive avatar (href or onClick) a name or alt. It is the control\'s accessible name, and it warns in development when it is missing.'},
|
|
20
20
|
{guidance: false, description: 'Rely on a status label to name an interactive avatar. "Online" says nothing about where the link goes.'},
|
|
21
21
|
{guidance: false, description: 'Use Avatar for logos, product images, or anything that isn\'t a person or team. Use an image or icon instead.'},
|
|
22
|
-
{guidance: false, description: '
|
|
22
|
+
{guidance: false, description: 'Force a square or custom shape. Avatars are always circular to stay consistent across the system.'},
|
|
23
23
|
],
|
|
24
24
|
anatomy: [
|
|
25
25
|
{name: 'Photo', required: false, description: 'The profile image, loaded from the src URL. Shown when available.'},
|
|
@@ -30,17 +30,13 @@ export const docs = {
|
|
|
30
30
|
},
|
|
31
31
|
theming: {
|
|
32
32
|
targets: [
|
|
33
|
-
{className: 'astryx-avatar', visualProps: ['size'
|
|
33
|
+
{className: 'astryx-avatar', visualProps: ['size']},
|
|
34
34
|
{className: 'astryx-avatar-fallback', visualProps: ['size']},
|
|
35
35
|
{className: 'astryx-avatar-status-dot', visualProps: ['variant']},
|
|
36
36
|
{className: 'astryx-avatar-status-dot-glyph', visualProps: ['shape']},
|
|
37
37
|
],
|
|
38
38
|
vars: [
|
|
39
39
|
{name: '--_avatar-group-overlap', description: 'Negative inline offset applied to every avatar after the first when avatars are stacked in an AvatarGroup. Set from the group size; a more negative value tightens the stack.', default: 'set at runtime from the group avatar size (px)', private: true},
|
|
40
|
-
{name: '--_avatar-radius', description: 'Border radius of the avatar wrapper, content, focus ring, and the AvatarGroupOverflow "+N" chip. Set per shape variant by shapeStyles.', default: 'var(--radius-full)', private: true},
|
|
41
|
-
],
|
|
42
|
-
derived: [
|
|
43
|
-
{property: 'borderRadius', vars: ['--_avatar-radius']},
|
|
44
40
|
],
|
|
45
41
|
},
|
|
46
42
|
description: 'Displays a user avatar with image, initials fallback, and optional status indicator.',
|
|
@@ -71,12 +67,6 @@ export const docs = {
|
|
|
71
67
|
description: "Avatar size. Use a named size ('xsm' 20px, 'sm' 24px, 'md' 36px, 'lg' 48px, 'xl' 128px) or a numeric pixel value. Avatar shares Icon's abbreviated scale, but its tiers are larger because avatars align with media rather than glyphs. Inside an AvatarGroup the group's size wins and this prop is ignored.",
|
|
72
68
|
default: "'md'",
|
|
73
69
|
},
|
|
74
|
-
{
|
|
75
|
-
name: 'shape',
|
|
76
|
-
type: "'circle' | 'rounded' | 'square'",
|
|
77
|
-
description: "Shape variant of the avatar. 'circle' (default) stays fully round. 'rounded' uses the element radius token so it matches UI corner rounding and can be set globally via theme. 'square' has no radius. Status dot positioning adapts automatically: 4-o'clock on circle, bottom-right corner on rounded/square.",
|
|
78
|
-
default: "'circle'",
|
|
79
|
-
},
|
|
80
70
|
{
|
|
81
71
|
name: 'status',
|
|
82
72
|
type: 'ReactNode',
|
|
@@ -6,7 +6,6 @@ import {act, render, screen, fireEvent} from '@testing-library/react';
|
|
|
6
6
|
import userEvent from '@testing-library/user-event';
|
|
7
7
|
import {Avatar} from './Avatar';
|
|
8
8
|
import {AvatarStatusDot} from './AvatarStatusDot';
|
|
9
|
-
import {AvatarGroup} from '../AvatarGroup';
|
|
10
9
|
|
|
11
10
|
describe('Avatar', () => {
|
|
12
11
|
it('exposes role="img" with the name as accessible name', () => {
|
|
@@ -417,85 +416,6 @@ describe('Avatar', () => {
|
|
|
417
416
|
expect(img).toHaveAttribute('src', 'https://example.com/ada.jpg');
|
|
418
417
|
});
|
|
419
418
|
|
|
420
|
-
it('renders without error for all shape variants', () => {
|
|
421
|
-
const shapes = ['circle', 'rounded', 'square'] as const;
|
|
422
|
-
for (const shape of shapes) {
|
|
423
|
-
const {unmount} = render(
|
|
424
|
-
<Avatar
|
|
425
|
-
name="Ana Thomas"
|
|
426
|
-
shape={shape}
|
|
427
|
-
data-testid={`avatar-${shape}`}
|
|
428
|
-
/>,
|
|
429
|
-
);
|
|
430
|
-
expect(screen.getByTestId(`avatar-${shape}`)).toBeInTheDocument();
|
|
431
|
-
unmount();
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
it('defaults to circle shape (no shape prop)', () => {
|
|
436
|
-
render(<Avatar name="Lee" data-testid="avatar-default" />);
|
|
437
|
-
// Should still render with role="img" using the name as the accessible label.
|
|
438
|
-
expect(screen.getByRole('img', {name: 'Lee'})).toBeInTheDocument();
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
it('renders status dot for all shape variants', () => {
|
|
442
|
-
const shapes = ['circle', 'rounded', 'square'] as const;
|
|
443
|
-
const StatusDot = () => <span data-testid="status-dot" />;
|
|
444
|
-
for (const shape of shapes) {
|
|
445
|
-
const {unmount} = render(
|
|
446
|
-
<Avatar
|
|
447
|
-
name="Ana"
|
|
448
|
-
shape={shape}
|
|
449
|
-
status={<StatusDot />}
|
|
450
|
-
data-testid={`avatar-${shape}-status`}
|
|
451
|
-
/>,
|
|
452
|
-
);
|
|
453
|
-
expect(screen.getByTestId('status-dot')).toBeInTheDocument();
|
|
454
|
-
unmount();
|
|
455
|
-
}
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
it('applies shapeStyles to wrapper when rendered inside AvatarGroup', () => {
|
|
459
|
-
render(
|
|
460
|
-
<AvatarGroup>
|
|
461
|
-
<Avatar name="Alice" shape="rounded" data-testid="group-avatar" />
|
|
462
|
-
</AvatarGroup>,
|
|
463
|
-
);
|
|
464
|
-
expect(screen.getByTestId('group-avatar')).toBeInTheDocument();
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
it("an AvatarGroup's shape overrides an individual Avatar's own shape prop, matching how size already works", () => {
|
|
468
|
-
render(
|
|
469
|
-
<AvatarGroup shape="square">
|
|
470
|
-
<Avatar name="Alice" shape="rounded" data-testid="group-avatar" />
|
|
471
|
-
</AvatarGroup>,
|
|
472
|
-
);
|
|
473
|
-
expect(screen.getByTestId('group-avatar')).toHaveAttribute(
|
|
474
|
-
'data-shape',
|
|
475
|
-
'square',
|
|
476
|
-
);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
it("an Avatar's own shape prop applies outside any AvatarGroup", () => {
|
|
480
|
-
render(<Avatar name="Ana" shape="rounded" data-testid="solo-avatar" />);
|
|
481
|
-
expect(screen.getByTestId('solo-avatar')).toHaveAttribute(
|
|
482
|
-
'data-shape',
|
|
483
|
-
'rounded',
|
|
484
|
-
);
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
it('defaults to circle shape inside an AvatarGroup with no explicit shape', () => {
|
|
488
|
-
render(
|
|
489
|
-
<AvatarGroup>
|
|
490
|
-
<Avatar name="Alice" shape="square" data-testid="group-avatar" />
|
|
491
|
-
</AvatarGroup>,
|
|
492
|
-
);
|
|
493
|
-
expect(screen.getByTestId('group-avatar')).toHaveAttribute(
|
|
494
|
-
'data-shape',
|
|
495
|
-
'circle',
|
|
496
|
-
);
|
|
497
|
-
});
|
|
498
|
-
|
|
499
419
|
// --- Name tooltip (tooltip?: string | boolean) ---
|
|
500
420
|
describe('name tooltip', () => {
|
|
501
421
|
const originalShowPopover = HTMLElement.prototype.showPopover;
|
package/src/Avatar/Avatar.tsx
CHANGED
|
@@ -97,11 +97,6 @@ type AvatarNumericSize =
|
|
|
97
97
|
*/
|
|
98
98
|
export type AvatarSize = AvatarNamedSize | AvatarNumericSize;
|
|
99
99
|
|
|
100
|
-
/**
|
|
101
|
-
* Avatar shape options
|
|
102
|
-
*/
|
|
103
|
-
export type AvatarShape = 'circle' | 'rounded' | 'square';
|
|
104
|
-
|
|
105
100
|
/**
|
|
106
101
|
* Resolves named sizes to their numeric pixel values
|
|
107
102
|
*/
|
|
@@ -123,25 +118,6 @@ export function resolveSize(size: AvatarSize): number {
|
|
|
123
118
|
}
|
|
124
119
|
}
|
|
125
120
|
|
|
126
|
-
// Sets one local custom property rather than `borderRadius` directly, so
|
|
127
|
-
// every clipping/ring surface that needs the shape's radius (the wrapper,
|
|
128
|
-
// the interactive focus ring, the content div that actually clips via
|
|
129
|
-
// `overflow: hidden`, and AvatarGroupOverflow's "+N" indicator) reads the
|
|
130
|
-
// same value instead of each hardcoding its own borderRadius independently.
|
|
131
|
-
// A theme override only has to reach this one property, not fight the
|
|
132
|
-
// per-surface StyleX class order to change the shape everywhere at once.
|
|
133
|
-
export const shapeStyles = stylex.create({
|
|
134
|
-
circle: {
|
|
135
|
-
'--_avatar-radius': radiusVars['--radius-full'],
|
|
136
|
-
},
|
|
137
|
-
rounded: {
|
|
138
|
-
'--_avatar-radius': radiusVars['--radius-element'],
|
|
139
|
-
},
|
|
140
|
-
square: {
|
|
141
|
-
'--_avatar-radius': radiusVars['--radius-none'],
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
|
|
145
121
|
/**
|
|
146
122
|
* Base styles for the avatar
|
|
147
123
|
* Uses a wrapper/content structure so status isn't clipped by overflow:hidden
|
|
@@ -151,10 +127,10 @@ const styles = stylex.create({
|
|
|
151
127
|
position: 'relative',
|
|
152
128
|
display: 'inline-flex',
|
|
153
129
|
flexShrink: 0,
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
//
|
|
157
|
-
borderRadius: '
|
|
130
|
+
// The wrapper carries the avatar's box as well as its radius, so a theme
|
|
131
|
+
// rule on the `.astryx-avatar` target reaches both: the size the `size`
|
|
132
|
+
// visual prop selects on is set here, and the content below fills it.
|
|
133
|
+
borderRadius: radiusVars['--radius-full'],
|
|
158
134
|
},
|
|
159
135
|
content: {
|
|
160
136
|
display: 'flex',
|
|
@@ -162,14 +138,9 @@ const styles = stylex.create({
|
|
|
162
138
|
justifyContent: 'center',
|
|
163
139
|
width: '100%',
|
|
164
140
|
height: '100%',
|
|
141
|
+
borderRadius: radiusVars['--radius-full'],
|
|
165
142
|
overflow: 'hidden',
|
|
166
143
|
userSelect: 'none',
|
|
167
|
-
// The content div is the one that actually clips (via overflow: hidden
|
|
168
|
-
// above), so it needs its own border-radius matching the wrapper's.
|
|
169
|
-
// It inherits `--_avatar-radius` from the wrapper, since custom
|
|
170
|
-
// properties cascade to descendants even though border-radius itself
|
|
171
|
-
// does not.
|
|
172
|
-
borderRadius: 'var(--_avatar-radius)',
|
|
173
144
|
},
|
|
174
145
|
image: {
|
|
175
146
|
width: '100%',
|
|
@@ -196,6 +167,9 @@ const styles = stylex.create({
|
|
|
196
167
|
status: {
|
|
197
168
|
position: 'absolute',
|
|
198
169
|
},
|
|
170
|
+
// Visible focus ring for the name-tooltip tab stop, matching the repo-wide
|
|
171
|
+
// focus-visible outline treatment (see Timestamp, Token, Thumbnail). Only
|
|
172
|
+
// applied when a tooltip is active so keyboard users can reveal it.
|
|
199
173
|
// Reset the intrinsic styling of the interactive element (<a>/<button>) so it
|
|
200
174
|
// is a transparent, correctly-sized wrapper around the avatar visuals. The
|
|
201
175
|
// element carries the focus-visible accent ring for keyboard users.
|
|
@@ -213,9 +187,8 @@ const styles = stylex.create({
|
|
|
213
187
|
default: 'pointer',
|
|
214
188
|
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
215
189
|
},
|
|
216
|
-
// Match the avatar's shape
|
|
217
|
-
|
|
218
|
-
borderRadius: 'var(--_avatar-radius)',
|
|
190
|
+
// Match the avatar's circular shape so the focus ring hugs it.
|
|
191
|
+
borderRadius: radiusVars['--radius-full'],
|
|
219
192
|
},
|
|
220
193
|
});
|
|
221
194
|
|
|
@@ -234,7 +207,7 @@ const dynamicStyles = stylex.create({
|
|
|
234
207
|
fontSize: (size: number) => ({
|
|
235
208
|
fontSize: `${size * INITIALS_FONT_SIZE_RATIO}px`,
|
|
236
209
|
}),
|
|
237
|
-
|
|
210
|
+
statusPosition: (size: number) => ({
|
|
238
211
|
bottom: size * CIRCLE_EDGE_OFFSET_RATIO,
|
|
239
212
|
insetInlineEnd: size * CIRCLE_EDGE_OFFSET_RATIO,
|
|
240
213
|
// `insetInlineEnd` anchors to the right edge in LTR / left in RTL, so the
|
|
@@ -244,23 +217,13 @@ const dynamicStyles = stylex.create({
|
|
|
244
217
|
':is([dir="rtl"] *)': 'translate(-50%, 50%)',
|
|
245
218
|
},
|
|
246
219
|
}),
|
|
247
|
-
statusPositionCorner: {
|
|
248
|
-
bottom: 0,
|
|
249
|
-
insetInlineEnd: 0,
|
|
250
|
-
// Same RTL mirroring as statusPositionCircle above: insetInlineEnd
|
|
251
|
-
// anchors to the right edge in LTR / left in RTL, so the outward push
|
|
252
|
-
// must flip sign too.
|
|
253
|
-
transform: {
|
|
254
|
-
default: 'translate(25%, 25%)',
|
|
255
|
-
':is([dir="rtl"] *)': 'translate(-25%, 25%)',
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
220
|
});
|
|
259
221
|
|
|
260
222
|
const BORDER_WIDTH = 2;
|
|
261
223
|
|
|
262
224
|
const groupStyles = stylex.create({
|
|
263
225
|
ring: {
|
|
226
|
+
borderRadius: radiusVars['--radius-full'],
|
|
264
227
|
borderWidth: BORDER_WIDTH,
|
|
265
228
|
borderStyle: 'solid',
|
|
266
229
|
borderColor: colorVars['--color-background-surface'],
|
|
@@ -313,14 +276,6 @@ export interface AvatarProps extends BaseProps<HTMLDivElement> {
|
|
|
313
276
|
* @default 'md'
|
|
314
277
|
*/
|
|
315
278
|
size?: AvatarSize;
|
|
316
|
-
/**
|
|
317
|
-
* Shape variant of the avatar.
|
|
318
|
-
* - 'circle': Full circle (default)
|
|
319
|
-
* - 'rounded': Rounded square
|
|
320
|
-
* - 'square': Sharp square
|
|
321
|
-
* @default 'circle'
|
|
322
|
-
*/
|
|
323
|
-
shape?: AvatarShape;
|
|
324
279
|
/**
|
|
325
280
|
* The primary image source for the avatar.
|
|
326
281
|
*/
|
|
@@ -524,7 +479,6 @@ export function Avatar({
|
|
|
524
479
|
fallbackSrc,
|
|
525
480
|
name,
|
|
526
481
|
size = 'md',
|
|
527
|
-
shape = 'circle',
|
|
528
482
|
src,
|
|
529
483
|
status,
|
|
530
484
|
tooltip = true,
|
|
@@ -584,7 +538,6 @@ export function Avatar({
|
|
|
584
538
|
: undefined;
|
|
585
539
|
const avatarGroup = useAvatarGroup();
|
|
586
540
|
const resolvedSize = avatarGroup?.size ?? size;
|
|
587
|
-
const resolvedShape = avatarGroup?.shape ?? shape;
|
|
588
541
|
const numericSize = useMemo(() => resolveSize(resolvedSize), [resolvedSize]);
|
|
589
542
|
|
|
590
543
|
// Resolve the tooltip content:
|
|
@@ -770,9 +723,7 @@ export function Avatar({
|
|
|
770
723
|
<div
|
|
771
724
|
{...stylex.props(
|
|
772
725
|
styles.status,
|
|
773
|
-
|
|
774
|
-
? dynamicStyles.statusPositionCircle(numericSize)
|
|
775
|
-
: dynamicStyles.statusPositionCorner,
|
|
726
|
+
dynamicStyles.statusPosition(numericSize),
|
|
776
727
|
)}>
|
|
777
728
|
{status}
|
|
778
729
|
</div>
|
|
@@ -785,7 +736,7 @@ export function Avatar({
|
|
|
785
736
|
// tooltip tab-stop focus ring all live here so the interactive
|
|
786
737
|
// `<a>`/`<button>` and the static `<div>` carry the exact same box.
|
|
787
738
|
const rootStylexProps = mergeProps(
|
|
788
|
-
themeProps('avatar', {size: resolvedSize
|
|
739
|
+
themeProps('avatar', {size: resolvedSize}),
|
|
789
740
|
focusOutlineProps.focusVisible(
|
|
790
741
|
styles.wrapper,
|
|
791
742
|
dynamicStyles.size(numericSize),
|
|
@@ -793,7 +744,6 @@ export function Avatar({
|
|
|
793
744
|
avatarGroup && groupStyles.ring,
|
|
794
745
|
avatarGroup && groupStyles.overlap,
|
|
795
746
|
avatarGroup && groupDynamicStyles.overlap(-avatarGroup.overlap),
|
|
796
|
-
shapeStyles[resolvedShape],
|
|
797
747
|
xstyle,
|
|
798
748
|
),
|
|
799
749
|
className,
|