@astryxdesign/core 0.4.2-canary.bb07062 → 0.4.2-canary.e60974e

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @file ComplexSelector.tsx
3
- * @input Uses React, StyleX, Field, usePopover
4
- * @output Exports ComplexSelector component for custom selector surfaces
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?: 'above' | 'below' | 'start' | 'end';
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":"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"}
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 ComplexSelector component for custom selector surfaces
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,17 +13,18 @@
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 { colorVars, durationVars, easeVars, fontWeightVars, radiusVars, sizeVars, spacingVars, typographyVars, typeScaleVars } from "../theme/tokens.stylex.js";
27
28
  import { mergeProps } from "../utils/index.js";
28
29
  import { composeEventHandlers } from "../utils/composeEventHandlers.js";
29
30
  import { focusOutlineStyles } from "../utils/focusOutline.stylex.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
- kAzted: "x1gdqauq",
129
+ kZKoxP: "x6k0iem",
113
130
  $$css: true
114
131
  },
115
132
  md: {
116
- kAzted: "x1uogy3y",
133
+ kZKoxP: "x1ueg155",
117
134
  $$css: true
118
135
  },
119
136
  lg: {
120
- kAzted: "x1xf4nls",
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) {
@@ -217,8 +282,8 @@ export function ComplexSelector({
217
282
  const content = /*#__PURE__*/_jsx("div", {
218
283
  id: contentId,
219
284
  ...stylex.props(styles.content, contentXstyle),
220
- children: children(optimisticValue, commitValue, popover.hide, {
221
- isOpen: popover.isOpen,
285
+ children: children(optimisticValue, commitValue, close, {
286
+ isOpen,
222
287
  isBusy,
223
288
  triggerId,
224
289
  contentId
@@ -229,25 +294,21 @@ export function ComplexSelector({
229
294
  ref: popover.triggerRef,
230
295
  "data-testid": testId,
231
296
  ...props,
232
- onClick: composeEventHandlers(onClickProp, () => {
233
- if (!isDisabled) {
234
- popover.toggle();
235
- }
236
- }),
297
+ onClick: composeEventHandlers(onClickProp, handleTriggerClick),
237
298
  ...mergeProps(themeProps('complex-selector', {
299
+ variant,
238
300
  size,
239
301
  status: status?.type ?? null
240
- }), stylex.props(inputWrapperStyles.base, styles.triggerContainer, styles[size],
241
- // The ring belongs to the wrapper (the focusable `<button>` sits
242
- // inside it), but it must still be a KEYBOARD ring: `:focus-within`
243
- // matched a mouse click on the trigger and drew the outline for
244
- // 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", {
302
+ }), stylex.props(inputWrapperStyles.base, styles.triggerContainer, styles[size], variant === 'input' && focusOutlineStyles.focusWithin, variant === 'ghost' && styles.triggerGhost, variant === 'ghost' && focusOutlineStyles.focusWithin, isDisabled && inputWrapperStyles.disabled, variant === 'ghost' && isDisabled && styles.triggerGhostDisabled, isDisabled && styles.disabled, triggerLabel == null && styles.placeholder, xstyle), className, style),
303
+ children: [startIcon && renderIconSlot(startIcon, {
304
+ size: 'sm',
305
+ color: 'secondary'
306
+ }), /*#__PURE__*/_jsx("button", {
307
+ ref: triggerRef,
247
308
  id: triggerId,
248
309
  type: "button",
249
310
  "aria-haspopup": "dialog",
250
- "aria-expanded": popover.isOpen,
311
+ "aria-expanded": isOpen,
251
312
  "aria-controls": contentId,
252
313
  "aria-describedby": ariaDescribedBy,
253
314
  "aria-labelledby": labelId,
@@ -256,7 +317,7 @@ export function ComplexSelector({
256
317
  "aria-busy": isBusy || undefined,
257
318
  disabled: isDisabled,
258
319
  onKeyDown: event => {
259
- if (event.key === 'ArrowDown' && !popover.isOpen && !isDisabled) {
320
+ if (event.key === 'ArrowDown' && !isOpen && !isDisabled) {
260
321
  event.preventDefault();
261
322
  popover.show();
262
323
  }
@@ -281,14 +342,14 @@ export function ComplexSelector({
281
342
  // IS the trigger's icon element — one node carrying the box, the
282
343
  // color, the rotation, and the theme target.
283
344
  ,
284
- xstyle: [styles.triggerIcon, styles.triggerIconRotation, popover.isOpen && styles.triggerIconOpen],
345
+ xstyle: [styles.triggerIcon, styles.triggerIconRotation, isOpen && styles.triggerIconOpen],
285
346
  ...themeProps('complex-selector-indicator-icon', {
286
- state: popover.isOpen ? 'expanded' : 'collapsed'
347
+ state: isOpen ? 'expanded' : 'collapsed'
287
348
  })
288
349
  })]
289
350
  }), popover.render(content, {
290
351
  placement,
291
- alignment: 'start',
352
+ alignment,
292
353
  offset: spacingVars['--spacing-1'],
293
354
  xstyle: [styles.popover, layerAnimations[placement]]
294
355
  })]
@@ -308,7 +369,7 @@ export function ComplexSelector({
308
369
  message: status.message,
309
370
  messageID: status.message ? statusMessageId : undefined
310
371
  } : undefined,
311
- statusVariant: statusVariant,
372
+ statusVariant: effectiveStatusVariant,
312
373
  labelTooltip: labelTooltip,
313
374
  width: width,
314
375
  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,GAC3B,MAAM,mBAAmB,CAAC"}
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"}
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file index.ts
7
- * @output Exports ComplexSelector and types
7
+ * @output Exports ComplexSelector and its trigger-size contract types
8
8
  * @position Public API entry point
9
9
  */
10
10
  export { ComplexSelector } from "./ComplexSelector.js";