@astryxdesign/core 0.4.2 → 0.4.3-canary.551a8de
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/CHANGELOG.md +45 -0
- package/README.md +79 -45
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +3 -19
- package/dist/Banner/Banner.d.ts +9 -2
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +84 -33
- package/dist/Banner/index.d.ts +14 -12
- package/dist/Banner/index.d.ts.map +1 -1
- package/dist/Banner/index.js +10 -8
- package/dist/Chat/ChatTokenizedText.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts +38 -4
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +98 -31
- package/dist/ComplexSelector/index.d.ts +2 -2
- package/dist/ComplexSelector/index.d.ts.map +1 -1
- package/dist/ComplexSelector/index.js +1 -1
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +55 -12
- package/dist/MobileNav/MobileNav.d.ts +12 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +102 -30
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +4 -1
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +2 -4
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -1
- package/dist/Table/columnUtils.d.ts.map +1 -1
- package/dist/Table/columnUtils.js +4 -1
- package/dist/TextArea/TextArea.d.ts +6 -3
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +17 -6
- package/dist/TreeList/TreeList.js +2 -1
- package/dist/astryx.css +8 -4
- package/dist/theme/defineTheme.d.ts +30 -7
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +36 -47
- package/dist/theme/expandColorScale.d.ts +17 -2
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +63 -33
- package/dist/theme/mergeComponents.d.ts +20 -0
- package/dist/theme/mergeComponents.d.ts.map +1 -0
- package/dist/theme/mergeComponents.js +56 -0
- package/dist/theme/onMediaTokens.d.ts +6 -1
- package/dist/theme/onMediaTokens.d.ts.map +1 -1
- package/dist/theme/onMediaTokens.js +11 -3
- package/dist/utils/characters.d.ts +27 -0
- package/dist/utils/characters.d.ts.map +1 -0
- package/dist/utils/characters.js +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/package.json +4 -8
- package/src/Avatar/Avatar.test.tsx +6 -1
- package/src/Avatar/Avatar.tsx +3 -21
- package/src/Banner/Banner.doc.mjs +12 -10
- package/src/Banner/Banner.test.tsx +108 -0
- package/src/Banner/Banner.tsx +124 -38
- package/src/Banner/index.ts +15 -13
- package/src/Chat/ChatTokenizedText.tsx +1 -1
- package/src/ComplexSelector/ComplexSelector.doc.mjs +55 -6
- package/src/ComplexSelector/ComplexSelector.test.tsx +197 -6
- package/src/ComplexSelector/ComplexSelector.tsx +156 -28
- package/src/ComplexSelector/index.ts +3 -1
- package/src/Markdown/parser.test.ts +53 -0
- package/src/Markdown/parser.ts +53 -12
- package/src/MobileNav/MobileNav.tsx +128 -37
- package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +426 -0
- package/src/MobileNav/MobileNavCloseTiming.test.ts +58 -0
- package/src/MobileNav/MobileNavCloseVisibility.test.tsx +172 -0
- package/src/PowerSearch/PowerSearch.test.tsx +48 -3
- package/src/PowerSearch/PowerSearch.tsx +4 -1
- package/src/PowerSearch/formatFilterValue.test.ts +22 -0
- package/src/PowerSearch/formatFilterValue.ts +2 -4
- package/src/Switch/Switch.test.tsx +16 -0
- package/src/Switch/Switch.tsx +7 -0
- package/src/Table/Table.test.tsx +6 -0
- package/src/Table/columnUtils.ts +3 -1
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextArea/TextArea.test.tsx +72 -0
- package/src/TextArea/TextArea.tsx +26 -8
- package/src/TreeList/TreeList.doc.mjs +2 -2
- package/src/TreeList/TreeList.tsx +1 -1
- package/src/__tests__/stubMatchMedia.test.ts +79 -0
- package/src/__tests__/stubMatchMedia.ts +95 -0
- package/src/theme/defineTheme.test.ts +127 -0
- package/src/theme/defineTheme.ts +70 -55
- package/src/theme/expandColorScale.test.ts +138 -0
- package/src/theme/expandColorScale.ts +89 -44
- package/src/theme/extensibleAxes.test.ts +365 -0
- package/src/theme/mergeComponents.ts +59 -0
- package/src/theme/onMediaTokens.ts +9 -2
- package/src/utils/characters.test.ts +141 -0
- package/src/utils/characters.ts +88 -0
- package/src/utils/index.ts +2 -0
- package/dist/astryx.umd.js +0 -147
- package/dist/astryx.umd.js.map +0 -7
package/dist/Banner/index.js
CHANGED
|
@@ -12,27 +12,29 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Extensible
|
|
15
|
+
* Extensible container map for Banner.
|
|
16
16
|
*
|
|
17
|
-
* Theme packages can add custom
|
|
17
|
+
* Theme packages can add custom container types via TypeScript module augmentation:
|
|
18
18
|
* @example
|
|
19
19
|
* ```
|
|
20
20
|
* declare module '@astryxdesign/core/Banner' {
|
|
21
|
-
* interface
|
|
22
|
-
* '
|
|
21
|
+
* interface BannerContainerMap {
|
|
22
|
+
* 'floating': true;
|
|
23
23
|
* }
|
|
24
24
|
* }
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
/**
|
|
28
|
-
* Extensible
|
|
28
|
+
* Extensible status map for Banner.
|
|
29
29
|
*
|
|
30
|
-
* Theme packages can add custom
|
|
30
|
+
* Theme packages can add custom statuses via TypeScript module augmentation.
|
|
31
|
+
* A status the library does not know falls through to the base treatment: no
|
|
32
|
+
* status fill, no default glyph, and `role="status"`.
|
|
31
33
|
* @example
|
|
32
34
|
* ```
|
|
33
35
|
* declare module '@astryxdesign/core/Banner' {
|
|
34
|
-
* interface
|
|
35
|
-
* '
|
|
36
|
+
* interface BannerStatusMap {
|
|
37
|
+
* 'neutral': true;
|
|
36
38
|
* }
|
|
37
39
|
* }
|
|
38
40
|
* ```
|
|
@@ -45,7 +45,7 @@ function isCustomToken(token) {
|
|
|
45
45
|
return 'render' in token && typeof token.render === 'function';
|
|
46
46
|
}
|
|
47
47
|
function escapeRegExp(str) {
|
|
48
|
-
return str.replace(/[.*+?^${}()|[
|
|
48
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// =============================================================================
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file ComplexSelector.tsx
|
|
3
|
-
* @input Uses React, StyleX, Field, usePopover
|
|
4
|
-
* @output Exports
|
|
3
|
+
* @input Uses React, StyleX, Field, Icon slots, Layer positioning, and usePopover
|
|
4
|
+
* @output Exports a rich-selector shell with exact token-sized input and ghost triggers, plus an imperative open/close handle
|
|
5
5
|
* @position Core implementation; consumed by index.ts
|
|
6
6
|
*
|
|
7
7
|
* SYNC: When modified, update:
|
|
@@ -9,12 +9,16 @@
|
|
|
9
9
|
* - /packages/core/src/ComplexSelector/ComplexSelector.test.tsx
|
|
10
10
|
* - /packages/core/src/ComplexSelector/index.ts
|
|
11
11
|
* - /apps/storybook/stories/ComplexSelector.stories.tsx
|
|
12
|
+
* - /packages/cli/assets/templates/blocks/components/ComplexSelector/ (showcase blocks)
|
|
12
13
|
*/
|
|
13
14
|
import React, { type ReactNode } from 'react';
|
|
14
15
|
import type { StyleXStyles } from '@stylexjs/stylex';
|
|
15
16
|
import type { BaseProps } from '../BaseProps';
|
|
16
17
|
import { type FieldStatusVariant } from '../Field';
|
|
18
|
+
import { type IconType } from '../Icon';
|
|
19
|
+
import type { LayerAlignment, LayerPlacement } from '../Layer/useLayer';
|
|
17
20
|
import type { SizeValue } from '../utils/types';
|
|
21
|
+
export type ComplexSelectorVariant = 'input' | 'ghost';
|
|
18
22
|
export type ComplexSelectorSize = 'sm' | 'md' | 'lg';
|
|
19
23
|
export interface ComplexSelectorRenderState {
|
|
20
24
|
/** Whether the selector surface is open. */
|
|
@@ -26,6 +30,24 @@ export interface ComplexSelectorRenderState {
|
|
|
26
30
|
/** ID of the popup content container. */
|
|
27
31
|
contentId: string;
|
|
28
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Imperative control surface for ComplexSelector, accessed via the `handleRef`
|
|
35
|
+
* prop. Methods drive the same popover machinery as the built-in trigger, so
|
|
36
|
+
* they respect focus restoration, light dismiss, and Escape. Prefer these
|
|
37
|
+
* callbacks over mirroring open state in the parent — the selector owns its
|
|
38
|
+
* visibility, and imperative calls avoid the focus-management pitfalls of
|
|
39
|
+
* syncing an external `isOpen` prop.
|
|
40
|
+
*/
|
|
41
|
+
export interface ComplexSelectorHandle {
|
|
42
|
+
/** Open the selector surface. No-op when disabled or already open. */
|
|
43
|
+
open(): void;
|
|
44
|
+
/** Close the selector surface. Restores focus to the trigger. */
|
|
45
|
+
close(): void;
|
|
46
|
+
/** Toggle the selector surface open or closed. */
|
|
47
|
+
toggle(): void;
|
|
48
|
+
/** Whether the selector surface is currently open. Reads live state. */
|
|
49
|
+
isOpen(): boolean;
|
|
50
|
+
}
|
|
29
51
|
export interface ComplexSelectorStatus {
|
|
30
52
|
type: 'warning' | 'error' | 'success';
|
|
31
53
|
message?: string;
|
|
@@ -65,10 +87,22 @@ export interface ComplexSelectorProps<Value> extends Omit<BaseProps<HTMLDivEleme
|
|
|
65
87
|
labelTooltip?: string;
|
|
66
88
|
/** Trigger and field size. */
|
|
67
89
|
size?: ComplexSelectorSize;
|
|
90
|
+
/** Visual trigger style. Ghost matches toolbar buttons. */
|
|
91
|
+
variant?: ComplexSelectorVariant;
|
|
92
|
+
/** Icon displayed at the start of the trigger. */
|
|
93
|
+
startIcon?: ReactNode | IconType;
|
|
68
94
|
/** Width of the field. */
|
|
69
95
|
width?: SizeValue;
|
|
70
96
|
/** Popup placement. */
|
|
71
|
-
placement?:
|
|
97
|
+
placement?: LayerPlacement;
|
|
98
|
+
/** Popup alignment along the placement axis. */
|
|
99
|
+
alignment?: LayerAlignment;
|
|
100
|
+
/**
|
|
101
|
+
* Imperative handle for programmatic open/close control. Exposes open,
|
|
102
|
+
* close, toggle, and the isOpen query. Use this instead of mirroring open
|
|
103
|
+
* state in the parent — the selector owns its visibility.
|
|
104
|
+
*/
|
|
105
|
+
handleRef?: React.Ref<ComplexSelectorHandle>;
|
|
72
106
|
/** StyleX styles for the popup content container. */
|
|
73
107
|
contentXstyle?: StyleXStyles;
|
|
74
108
|
/** Test ID for the trigger container. */
|
|
@@ -101,7 +135,7 @@ export interface ComplexSelectorProps<Value> extends Omit<BaseProps<HTMLDivEleme
|
|
|
101
135
|
* </ComplexSelector>
|
|
102
136
|
* ```
|
|
103
137
|
*/
|
|
104
|
-
export declare function ComplexSelector<Value>({ label, value, onChange, changeAction, children, triggerLabel, placeholder: placeholderFromProps, isLabelHidden, description, isOptional, isRequired, isDisabled, isLoading, status, statusVariant, labelTooltip, size, width, placement, contentXstyle, xstyle, className, style, 'data-testid': testId, onClick: onClickProp, ...props }: ComplexSelectorProps<Value>): React.JSX.Element;
|
|
138
|
+
export declare function ComplexSelector<Value>({ label, value, onChange, changeAction, children, triggerLabel, placeholder: placeholderFromProps, isLabelHidden, description, isOptional, isRequired, isDisabled, isLoading, status, statusVariant, labelTooltip, size, variant, startIcon, width, placement, alignment, handleRef, contentXstyle, xstyle, className, style, 'data-testid': testId, onClick: onClickProp, ...props }: ComplexSelectorProps<Value>): React.JSX.Element;
|
|
105
139
|
export declare namespace ComplexSelector {
|
|
106
140
|
var displayName: string;
|
|
107
141
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComplexSelector.d.ts","sourceRoot":"","sources":["../../src/ComplexSelector/ComplexSelector.tsx"],"names":[],"mappings":"AAIA
|
|
1
|
+
{"version":3,"file":"ComplexSelector.d.ts","sourceRoot":"","sources":["../../src/ComplexSelector/ComplexSelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file ComplexSelector.tsx
|
|
7
|
-
* @input Uses React, StyleX, Field, usePopover
|
|
8
|
-
* @output Exports
|
|
7
|
+
* @input Uses React, StyleX, Field, Icon slots, Layer positioning, and usePopover
|
|
8
|
+
* @output Exports a rich-selector shell with exact token-sized input and ghost triggers, plus an imperative open/close handle
|
|
9
9
|
* @position Core implementation; consumed by index.ts
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update:
|
|
@@ -13,18 +13,19 @@
|
|
|
13
13
|
* - /packages/core/src/ComplexSelector/ComplexSelector.test.tsx
|
|
14
14
|
* - /packages/core/src/ComplexSelector/index.ts
|
|
15
15
|
* - /apps/storybook/stories/ComplexSelector.stories.tsx
|
|
16
|
+
* - /packages/cli/assets/templates/blocks/components/ComplexSelector/ (showcase blocks)
|
|
16
17
|
*/
|
|
17
|
-
import React, { useCallback, useId, useOptimistic, useTransition } from 'react';
|
|
18
|
+
import React, { useCallback, useId, useImperativeHandle, useOptimistic, useRef, useTransition } from 'react';
|
|
18
19
|
import * as stylex from '@stylexjs/stylex';
|
|
19
20
|
import { Field, inputWrapperStyles } from "../Field/index.js";
|
|
20
|
-
import { Icon } from "../Icon/index.js";
|
|
21
|
+
import { Icon, renderIconSlot } from "../Icon/index.js";
|
|
21
22
|
import { Spinner } from "../Spinner/index.js";
|
|
22
23
|
import { useTranslator } from "../i18n/index.js";
|
|
23
24
|
import { layerAnimations } from "../Layer/layerAnimations.stylex.js";
|
|
24
25
|
import { usePopover } from "../Popover/usePopover.js";
|
|
25
26
|
import "../theme/tokens.stylex.js";
|
|
26
|
-
import { colorVars, durationVars, easeVars, radiusVars, sizeVars, spacingVars, typographyVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
27
|
-
import { mergeProps } from "../utils/index.js";
|
|
27
|
+
import { colorVars, durationVars, easeVars, fontWeightVars, radiusVars, sizeVars, spacingVars, typographyVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
28
|
+
import { isRenderable, mergeProps } from "../utils/index.js";
|
|
28
29
|
import { composeEventHandlers } from "../utils/composeEventHandlers.js";
|
|
29
30
|
import { focusOutlineStyles } from "../utils/focusOutline.stylex.js";
|
|
30
31
|
import { themeProps } from "../utils/themeProps.js";
|
|
@@ -82,6 +83,22 @@ const styles = {
|
|
|
82
83
|
kMwMTN: "xv1l7n4",
|
|
83
84
|
$$css: true
|
|
84
85
|
},
|
|
86
|
+
triggerGhost: {
|
|
87
|
+
kzqmXN: "x14atkfc",
|
|
88
|
+
kMzoRj: "xc342km",
|
|
89
|
+
kWkggS: "xjbqb8w",
|
|
90
|
+
kKwaWg: "x1ilzqfv xq8i9tn",
|
|
91
|
+
kGVxlE: "x1gnnqk1 x1irk71m x15ysqaf",
|
|
92
|
+
k63SB2: "x1e4wzip",
|
|
93
|
+
k1ekBW: "xrafxwg",
|
|
94
|
+
k3aq6I: "x3oybdh xk4oym4",
|
|
95
|
+
$$css: true
|
|
96
|
+
},
|
|
97
|
+
triggerGhostDisabled: {
|
|
98
|
+
kKwaWg: "x18o3ruo",
|
|
99
|
+
k3aq6I: "x1c071of x1pdlv7q",
|
|
100
|
+
$$css: true
|
|
101
|
+
},
|
|
85
102
|
triggerIcon: {
|
|
86
103
|
kmuXW: "x2lah0s",
|
|
87
104
|
$$css: true
|
|
@@ -109,15 +126,15 @@ const styles = {
|
|
|
109
126
|
$$css: true
|
|
110
127
|
},
|
|
111
128
|
sm: {
|
|
112
|
-
|
|
129
|
+
kZKoxP: "x6k0iem",
|
|
113
130
|
$$css: true
|
|
114
131
|
},
|
|
115
132
|
md: {
|
|
116
|
-
|
|
133
|
+
kZKoxP: "x1ueg155",
|
|
117
134
|
$$css: true
|
|
118
135
|
},
|
|
119
136
|
lg: {
|
|
120
|
-
|
|
137
|
+
kZKoxP: "xssyfek",
|
|
121
138
|
$$css: true
|
|
122
139
|
},
|
|
123
140
|
disabled: {
|
|
@@ -125,6 +142,16 @@ const styles = {
|
|
|
125
142
|
$$css: true
|
|
126
143
|
}
|
|
127
144
|
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Imperative control surface for ComplexSelector, accessed via the `handleRef`
|
|
148
|
+
* prop. Methods drive the same popover machinery as the built-in trigger, so
|
|
149
|
+
* they respect focus restoration, light dismiss, and Escape. Prefer these
|
|
150
|
+
* callbacks over mirroring open state in the parent — the selector owns its
|
|
151
|
+
* visibility, and imperative calls avoid the focus-management pitfalls of
|
|
152
|
+
* syncing an external `isOpen` prop.
|
|
153
|
+
*/
|
|
154
|
+
|
|
128
155
|
/**
|
|
129
156
|
* A selector shell for rich, custom selection surfaces.
|
|
130
157
|
*
|
|
@@ -170,8 +197,12 @@ export function ComplexSelector({
|
|
|
170
197
|
statusVariant = 'attached',
|
|
171
198
|
labelTooltip,
|
|
172
199
|
size = 'md',
|
|
200
|
+
variant = 'input',
|
|
201
|
+
startIcon,
|
|
173
202
|
width,
|
|
174
203
|
placement = 'below',
|
|
204
|
+
alignment = 'start',
|
|
205
|
+
handleRef,
|
|
175
206
|
contentXstyle,
|
|
176
207
|
xstyle,
|
|
177
208
|
className,
|
|
@@ -182,28 +213,62 @@ export function ComplexSelector({
|
|
|
182
213
|
}) {
|
|
183
214
|
const t = useTranslator();
|
|
184
215
|
const placeholder = placeholderFromProps ?? t('@astryx.selector.placeholder');
|
|
216
|
+
const effectiveStatusVariant = variant === 'ghost' && statusVariant === 'attached' ? 'detached' : statusVariant;
|
|
185
217
|
const triggerId = useId();
|
|
186
218
|
const labelId = useId();
|
|
187
219
|
const contentId = useId();
|
|
188
220
|
const descriptionId = useId();
|
|
189
221
|
const statusMessageId = useId();
|
|
190
222
|
const ariaDescribedBy = [description ? descriptionId : null, status?.message ? statusMessageId : null].filter(id => id != null).join(' ') || undefined;
|
|
223
|
+
const triggerRef = useRef(null);
|
|
224
|
+
const lastHideTimeRef = useRef(0);
|
|
191
225
|
const [isPending, startTransition] = useTransition();
|
|
192
226
|
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
|
|
193
227
|
const isBusy = isLoading || isPending;
|
|
228
|
+
const handlePopoverHide = useCallback(() => {
|
|
229
|
+
lastHideTimeRef.current = Date.now();
|
|
230
|
+
triggerRef.current?.focus();
|
|
231
|
+
}, []);
|
|
194
232
|
const popover = usePopover({
|
|
195
233
|
dialogLabel: label,
|
|
196
234
|
hasCloseButton: false,
|
|
197
235
|
hasAutoFocus: true,
|
|
198
|
-
// The popup's theme target belongs on the SURFACE — the element painting
|
|
199
|
-
// background, radius and elevation — which `usePopover` owns. Rendered on
|
|
200
|
-
// the content box below it, a theme's background or radius rule paints the
|
|
201
|
-
// wrong box.
|
|
202
236
|
surfaceTarget: 'complex-selector-popup',
|
|
203
|
-
onHide:
|
|
204
|
-
document.getElementById(triggerId)?.focus();
|
|
205
|
-
}
|
|
237
|
+
onHide: handlePopoverHide
|
|
206
238
|
});
|
|
239
|
+
const isOpen = popover.isOpen;
|
|
240
|
+
const handleTriggerClick = useCallback(() => {
|
|
241
|
+
if (isDisabled || Date.now() - lastHideTimeRef.current < 50) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (popover.isOpen) {
|
|
245
|
+
popover.hide();
|
|
246
|
+
} else {
|
|
247
|
+
popover.show();
|
|
248
|
+
}
|
|
249
|
+
}, [isDisabled, popover]);
|
|
250
|
+
const close = useCallback(() => {
|
|
251
|
+
popover.hide();
|
|
252
|
+
}, [popover]);
|
|
253
|
+
useImperativeHandle(handleRef, () => ({
|
|
254
|
+
open: () => {
|
|
255
|
+
if (!isDisabled) {
|
|
256
|
+
popover.show();
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
close: () => popover.hide(),
|
|
260
|
+
toggle: () => {
|
|
261
|
+
if (isDisabled) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (popover.isOpen) {
|
|
265
|
+
popover.hide();
|
|
266
|
+
} else {
|
|
267
|
+
popover.show();
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
isOpen: () => popover.isOpen
|
|
271
|
+
}), [isDisabled, popover]);
|
|
207
272
|
const commitValue = useCallback(nextValue => {
|
|
208
273
|
onChange?.(nextValue);
|
|
209
274
|
if (changeAction) {
|
|
@@ -214,11 +279,15 @@ export function ComplexSelector({
|
|
|
214
279
|
}
|
|
215
280
|
}, [changeAction, onChange, setOptimisticValue, startTransition]);
|
|
216
281
|
const triggerContent = triggerLabel ?? placeholder;
|
|
282
|
+
const startIconSlot = renderIconSlot(startIcon, {
|
|
283
|
+
size: 'sm',
|
|
284
|
+
color: 'secondary'
|
|
285
|
+
});
|
|
217
286
|
const content = /*#__PURE__*/_jsx("div", {
|
|
218
287
|
id: contentId,
|
|
219
288
|
...stylex.props(styles.content, contentXstyle),
|
|
220
|
-
children: children(optimisticValue, commitValue,
|
|
221
|
-
isOpen
|
|
289
|
+
children: children(optimisticValue, commitValue, close, {
|
|
290
|
+
isOpen,
|
|
222
291
|
isBusy,
|
|
223
292
|
triggerId,
|
|
224
293
|
contentId
|
|
@@ -229,12 +298,9 @@ export function ComplexSelector({
|
|
|
229
298
|
ref: popover.triggerRef,
|
|
230
299
|
"data-testid": testId,
|
|
231
300
|
...props,
|
|
232
|
-
onClick: composeEventHandlers(onClickProp,
|
|
233
|
-
if (!isDisabled) {
|
|
234
|
-
popover.toggle();
|
|
235
|
-
}
|
|
236
|
-
}),
|
|
301
|
+
onClick: composeEventHandlers(onClickProp, handleTriggerClick),
|
|
237
302
|
...mergeProps(themeProps('complex-selector', {
|
|
303
|
+
variant,
|
|
238
304
|
size,
|
|
239
305
|
status: status?.type ?? null
|
|
240
306
|
}), stylex.props(inputWrapperStyles.base, styles.triggerContainer, styles[size],
|
|
@@ -242,12 +308,13 @@ export function ComplexSelector({
|
|
|
242
308
|
// inside it), but it must still be a KEYBOARD ring: `:focus-within`
|
|
243
309
|
// matched a mouse click on the trigger and drew the outline for
|
|
244
310
|
// pointer users too. `focusWithin` here is `:has(:focus-visible)`.
|
|
245
|
-
focusOutlineStyles.focusWithin, isDisabled && inputWrapperStyles.disabled, isDisabled && styles.disabled, triggerLabel == null && styles.placeholder, xstyle), className, style),
|
|
246
|
-
children: [/*#__PURE__*/_jsx("button", {
|
|
311
|
+
focusOutlineStyles.focusWithin, variant === 'ghost' && styles.triggerGhost, isDisabled && inputWrapperStyles.disabled, variant === 'ghost' && isDisabled && styles.triggerGhostDisabled, isDisabled && styles.disabled, triggerLabel == null && styles.placeholder, xstyle), className, style),
|
|
312
|
+
children: [isRenderable(startIconSlot) && startIconSlot, /*#__PURE__*/_jsx("button", {
|
|
313
|
+
ref: triggerRef,
|
|
247
314
|
id: triggerId,
|
|
248
315
|
type: "button",
|
|
249
316
|
"aria-haspopup": "dialog",
|
|
250
|
-
"aria-expanded":
|
|
317
|
+
"aria-expanded": isOpen,
|
|
251
318
|
"aria-controls": contentId,
|
|
252
319
|
"aria-describedby": ariaDescribedBy,
|
|
253
320
|
"aria-labelledby": labelId,
|
|
@@ -256,7 +323,7 @@ export function ComplexSelector({
|
|
|
256
323
|
"aria-busy": isBusy || undefined,
|
|
257
324
|
disabled: isDisabled,
|
|
258
325
|
onKeyDown: event => {
|
|
259
|
-
if (event.key === 'ArrowDown' && !
|
|
326
|
+
if (event.key === 'ArrowDown' && !isOpen && !isDisabled) {
|
|
260
327
|
event.preventDefault();
|
|
261
328
|
popover.show();
|
|
262
329
|
}
|
|
@@ -281,14 +348,14 @@ export function ComplexSelector({
|
|
|
281
348
|
// IS the trigger's icon element — one node carrying the box, the
|
|
282
349
|
// color, the rotation, and the theme target.
|
|
283
350
|
,
|
|
284
|
-
xstyle: [styles.triggerIcon, styles.triggerIconRotation,
|
|
351
|
+
xstyle: [styles.triggerIcon, styles.triggerIconRotation, isOpen && styles.triggerIconOpen],
|
|
285
352
|
...themeProps('complex-selector-indicator-icon', {
|
|
286
|
-
state:
|
|
353
|
+
state: isOpen ? 'expanded' : 'collapsed'
|
|
287
354
|
})
|
|
288
355
|
})]
|
|
289
356
|
}), popover.render(content, {
|
|
290
357
|
placement,
|
|
291
|
-
alignment
|
|
358
|
+
alignment,
|
|
292
359
|
offset: spacingVars['--spacing-1'],
|
|
293
360
|
xstyle: [styles.popover, layerAnimations[placement]]
|
|
294
361
|
})]
|
|
@@ -308,7 +375,7 @@ export function ComplexSelector({
|
|
|
308
375
|
message: status.message,
|
|
309
376
|
messageID: status.message ? statusMessageId : undefined
|
|
310
377
|
} : undefined,
|
|
311
|
-
statusVariant:
|
|
378
|
+
statusVariant: effectiveStatusVariant,
|
|
312
379
|
labelTooltip: labelTooltip,
|
|
313
380
|
width: width,
|
|
314
381
|
children: selectorContent
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file index.ts
|
|
3
|
-
* @output Exports ComplexSelector and types
|
|
3
|
+
* @output Exports ComplexSelector and its trigger-size contract types
|
|
4
4
|
* @position Public API entry point
|
|
5
5
|
*/
|
|
6
|
-
export { ComplexSelector, type ComplexSelectorProps, type ComplexSelectorRenderState, type ComplexSelectorSize, type ComplexSelectorStatus, } from './ComplexSelector';
|
|
6
|
+
export { ComplexSelector, type ComplexSelectorHandle, type ComplexSelectorProps, type ComplexSelectorRenderState, type ComplexSelectorSize, type ComplexSelectorStatus, type ComplexSelectorVariant, } from './ComplexSelector';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ComplexSelector/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EACL,eAAe,EACf,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ComplexSelector/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EACL,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/Markdown/parser.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAMH,MAAM,MAAM,UAAU,GAClB;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAC/B;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,GACtC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,GACxC;IAAC,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,GAC/C;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GAC/B;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,GACpD;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GACzC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,GACpC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAC,CAAC;AAEpB,MAAM,MAAM,SAAS,GACjB;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,GACvE;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,GAC3C;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,GACtD;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,SAAS,EAAE,CAAA;CAAC,GAC3C;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,SAAS,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC;CACzB,GACD;IAAC,IAAI,EAAE,IAAI,CAAA;CAAC,GACZ;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,SAAS,EAAE,CAAA;CAAC,CAAC;AACtE,MAAM,MAAM,aAAa,GAAG;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAC,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAMhE;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;+DAC2D;IAC3D,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB,CAAC;
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/Markdown/parser.ts"],"names":[],"mappings":"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"}
|
package/dist/Markdown/parser.js
CHANGED
|
@@ -203,7 +203,7 @@ function matchReferenceLink(text, start, linkDefs, opts) {
|
|
|
203
203
|
// matches nothing.
|
|
204
204
|
const label = rawLabel === '' ? linkText : rawLabel;
|
|
205
205
|
const href = linkDefs.get(normalizeLinkLabel(label));
|
|
206
|
-
if (href != null) {
|
|
206
|
+
if (href != null && isSafeUrl(href)) {
|
|
207
207
|
return {
|
|
208
208
|
node: {
|
|
209
209
|
type: 'link',
|
|
@@ -222,7 +222,7 @@ function matchReferenceLink(text, start, linkDefs, opts) {
|
|
|
222
222
|
return null;
|
|
223
223
|
}
|
|
224
224
|
const href = linkDefs.get(normalizeLinkLabel(linkText));
|
|
225
|
-
if (href == null) {
|
|
225
|
+
if (href == null || !isSafeUrl(href)) {
|
|
226
226
|
return null;
|
|
227
227
|
}
|
|
228
228
|
return {
|
|
@@ -304,6 +304,27 @@ function isWordChar(ch) {
|
|
|
304
304
|
return /\w/.test(ch);
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// URL scheme sanitization
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Reject URLs with dangerous schemes (javascript:, vbscript:, data:) that
|
|
313
|
+
* could execute arbitrary code when rendered as link hrefs or image srcs.
|
|
314
|
+
* Returns true if the URL is safe to use, false otherwise.
|
|
315
|
+
*/
|
|
316
|
+
function isSafeUrl(url) {
|
|
317
|
+
// Trim and collapse whitespace/control chars that browsers tolerate but
|
|
318
|
+
// could bypass a naive prefix check (e.g. "java\nscript:alert(1)").
|
|
319
|
+
// eslint-disable-next-line no-control-regex -- control chars are the bypass
|
|
320
|
+
const normalized = url.replace(/[\x00-\x1f\x7f]/g, '').trim();
|
|
321
|
+
const lower = normalized.toLowerCase();
|
|
322
|
+
if (lower.startsWith('javascript:') || lower.startsWith('vbscript:') || lower.startsWith('data:text/html')) {
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
|
|
307
328
|
// ---------------------------------------------------------------------------
|
|
308
329
|
// Inline parser
|
|
309
330
|
// ---------------------------------------------------------------------------
|
|
@@ -419,11 +440,20 @@ function parseInlineImpl(text, opts) {
|
|
|
419
440
|
if (altClose !== -1 && text[altClose + 1] === '(') {
|
|
420
441
|
const srcClose = findClosingParen(text, altClose + 2);
|
|
421
442
|
if (srcClose !== -1) {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
443
|
+
const src = text.slice(altClose + 2, srcClose);
|
|
444
|
+
if (!isSafeUrl(src)) {
|
|
445
|
+
// Dangerous scheme — emit as plain text.
|
|
446
|
+
nodes.push({
|
|
447
|
+
type: 'text',
|
|
448
|
+
content: text.slice(i, srcClose + 1)
|
|
449
|
+
});
|
|
450
|
+
} else {
|
|
451
|
+
nodes.push({
|
|
452
|
+
type: 'image',
|
|
453
|
+
src,
|
|
454
|
+
alt: text.slice(i + 2, altClose)
|
|
455
|
+
});
|
|
456
|
+
}
|
|
427
457
|
i = srcClose + 1;
|
|
428
458
|
continue;
|
|
429
459
|
}
|
|
@@ -459,11 +489,20 @@ function parseInlineImpl(text, opts) {
|
|
|
459
489
|
if (textClose !== -1 && text[textClose + 1] === '(') {
|
|
460
490
|
const urlClose = findClosingParen(text, textClose + 2);
|
|
461
491
|
if (urlClose !== -1) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
492
|
+
const href = text.slice(textClose + 2, urlClose);
|
|
493
|
+
if (!isSafeUrl(href)) {
|
|
494
|
+
// Dangerous scheme — emit as plain text instead of a link.
|
|
495
|
+
nodes.push({
|
|
496
|
+
type: 'text',
|
|
497
|
+
content: text.slice(i, urlClose + 1)
|
|
498
|
+
});
|
|
499
|
+
} else {
|
|
500
|
+
nodes.push({
|
|
501
|
+
type: 'link',
|
|
502
|
+
href,
|
|
503
|
+
children: parseInlineImpl(text.slice(i + 1, textClose), opts)
|
|
504
|
+
});
|
|
505
|
+
}
|
|
467
506
|
i = urlClose + 1;
|
|
468
507
|
continue;
|
|
469
508
|
}
|
|
@@ -690,6 +729,10 @@ function scanAutolinksInText(text) {
|
|
|
690
729
|
let m;
|
|
691
730
|
while ((m = re.exec(text)) !== null) {
|
|
692
731
|
const url = m[1];
|
|
732
|
+
// Skip dangerous URL schemes (javascript:, vbscript:, data:text/html)
|
|
733
|
+
if (!isSafeUrl(url)) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
693
736
|
matches.push({
|
|
694
737
|
start: m.index,
|
|
695
738
|
end: m.index + m[0].length,
|
|
@@ -23,6 +23,18 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { type ReactNode } from 'react';
|
|
25
25
|
import type { BaseProps } from '../BaseProps';
|
|
26
|
+
/**
|
|
27
|
+
* Shortest duration in a `transition-duration` list, in ms; null if unreadable.
|
|
28
|
+
*
|
|
29
|
+
* Browsers serialise computed `<time>` values in seconds — an authored `410ms`
|
|
30
|
+
* reads back as `"0.41s"` and a list as `"0.41s, 0.12s"` — so the seconds branch
|
|
31
|
+
* is the one that runs outside tests. jsdom echoes an inline `250ms` back as-is
|
|
32
|
+
* and never resolves `var()`, so both units and the unreadable case are covered
|
|
33
|
+
* directly in MobileNavCloseTiming.test.ts rather than through the component.
|
|
34
|
+
*
|
|
35
|
+
* @internal Exported for unit tests.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseShortestDurationMs(value: string): number | null;
|
|
26
38
|
export interface MobileNavProps extends Omit<BaseProps, 'title'> {
|
|
27
39
|
/** Ref forwarded to the root element */
|
|
28
40
|
ref?: React.Ref<HTMLDialogElement>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileNav.d.ts","sourceRoot":"","sources":["../../src/MobileNav/MobileNav.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAcf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"MobileNav.d.ts","sourceRoot":"","sources":["../../src/MobileNav/MobileNav.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAcf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA4J5C;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkBpE;AAmCD,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC;IAC9D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAEhC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,EACxB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,gBAAgB,EAC9B,QAAQ,EACR,MAAM,EACN,KAAW,EACX,IAAa,EACb,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,MAAM,EACN,SAAS,EACT,KAAK,EACL,OAAO,EAAE,WAAW,EACpB,GAAG,EACH,GAAG,IAAI,EACR,EAAE,cAAc,+BAgMhB;yBA/Me,SAAS"}
|