@wallarm-org/design-system 1.6.2 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/EmptyState/EmptyState.js +14 -10
- package/dist/components/EmptyState/EmptyStateContext.d.ts +3 -0
- package/dist/components/EmptyState/EmptyStateContext.js +5 -0
- package/dist/components/EmptyState/EmptyStateIllustration.js +2 -1
- package/dist/components/EmptyState/EmptyStateMessage.js +6 -1
- package/dist/components/EmptyState/EmptyStateTitle.js +6 -1
- package/dist/components/EmptyState/classes.d.ts +27 -0
- package/dist/components/EmptyState/classes.js +27 -4
- package/dist/components/FilterInput/FilterInputField/ChipsWithGaps.js +2 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.d.ts +5 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/FilterInputChip.js +12 -1
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/Segment.d.ts +6 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/Segment.js +10 -3
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/applyEditCaret.d.ts +1 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/applyEditCaret.js +10 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/index.d.ts +1 -0
- package/dist/components/FilterInput/FilterInputField/FilterInputChip/index.js +1 -0
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js +4 -1
- package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFocusManagement.js +16 -5
- package/dist/components/FilterInput/hooks/useFilterInputExpression/buildChips.js +6 -0
- package/dist/components/FilterInput/types.d.ts +16 -0
- package/dist/icons/Shapes.d.ts +3 -0
- package/dist/icons/Shapes.js +12 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/metadata/components.json +1141 -633
- package/dist/theme/Pixel.stories.tsx +9 -1
- package/dist/theme/index.css +1 -0
- package/dist/theme/semantic.css +28 -0
- package/dist/theme/utilities/empty-state-medallion.css +18 -0
- package/package.json +1 -1
|
@@ -2,18 +2,22 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { TestIdProvider } from "../../utils/testId.js";
|
|
4
4
|
import { emptyStateVariants } from "./classes.js";
|
|
5
|
+
import { EmptyStateProvider } from "./EmptyStateContext.js";
|
|
5
6
|
const EmptyState = ({ ref, type = 'collection-empty', className, children, 'data-testid': testId, ...props })=>/*#__PURE__*/ jsx(TestIdProvider, {
|
|
6
7
|
value: testId,
|
|
7
|
-
children: /*#__PURE__*/ jsx(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
children: /*#__PURE__*/ jsx(EmptyStateProvider, {
|
|
9
|
+
value: type,
|
|
10
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
11
|
+
...props,
|
|
12
|
+
ref: ref,
|
|
13
|
+
role: "status",
|
|
14
|
+
"data-slot": "empty-state",
|
|
15
|
+
"data-testid": testId,
|
|
16
|
+
className: cn(emptyStateVariants({
|
|
17
|
+
type
|
|
18
|
+
}), className),
|
|
19
|
+
children: children
|
|
20
|
+
})
|
|
17
21
|
})
|
|
18
22
|
});
|
|
19
23
|
EmptyState.displayName = 'EmptyState';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
const EmptyStateContext = /*#__PURE__*/ createContext('collection-empty');
|
|
3
|
+
const EmptyStateProvider = EmptyStateContext.Provider;
|
|
4
|
+
const useEmptyStateType = ()=>useContext(EmptyStateContext);
|
|
5
|
+
export { EmptyStateProvider, useEmptyStateType };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
+
import { emptyStateIllustrationVariants } from "./classes.js";
|
|
4
5
|
const EmptyStateIllustration = ({ ref, className, children, ...props })=>{
|
|
5
6
|
const testId = useTestId('illustration');
|
|
6
7
|
return /*#__PURE__*/ jsx("div", {
|
|
@@ -8,7 +9,7 @@ const EmptyStateIllustration = ({ ref, className, children, ...props })=>{
|
|
|
8
9
|
ref: ref,
|
|
9
10
|
"data-slot": "empty-state-illustration",
|
|
10
11
|
"data-testid": testId,
|
|
11
|
-
className: cn(
|
|
12
|
+
className: cn(emptyStateIllustrationVariants(), className),
|
|
12
13
|
children: children
|
|
13
14
|
});
|
|
14
15
|
};
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
+
import { emptyStateMessageVariants } from "./classes.js";
|
|
5
|
+
import { useEmptyStateType } from "./EmptyStateContext.js";
|
|
4
6
|
const EmptyStateMessage = ({ ref, className, children, ...props })=>{
|
|
5
7
|
const testId = useTestId('message');
|
|
8
|
+
const type = useEmptyStateType();
|
|
6
9
|
return /*#__PURE__*/ jsx("div", {
|
|
7
10
|
...props,
|
|
8
11
|
ref: ref,
|
|
9
12
|
"data-slot": "empty-state-message",
|
|
10
13
|
"data-testid": testId,
|
|
11
|
-
className: cn(
|
|
14
|
+
className: cn(emptyStateMessageVariants({
|
|
15
|
+
type
|
|
16
|
+
}), className),
|
|
12
17
|
children: children
|
|
13
18
|
});
|
|
14
19
|
};
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../utils/cn.js";
|
|
3
3
|
import { useTestId } from "../../utils/testId.js";
|
|
4
|
+
import { emptyStateTitleVariants } from "./classes.js";
|
|
5
|
+
import { useEmptyStateType } from "./EmptyStateContext.js";
|
|
4
6
|
const EmptyStateTitle = ({ ref, className, children, ...props })=>{
|
|
5
7
|
const testId = useTestId('title');
|
|
8
|
+
const type = useEmptyStateType();
|
|
6
9
|
return /*#__PURE__*/ jsx("p", {
|
|
7
10
|
...props,
|
|
8
11
|
ref: ref,
|
|
9
12
|
"data-testid": testId,
|
|
10
13
|
"data-slot": "empty-state-title",
|
|
11
|
-
className: cn(
|
|
14
|
+
className: cn(emptyStateTitleVariants({
|
|
15
|
+
type
|
|
16
|
+
}), className),
|
|
12
17
|
children: children
|
|
13
18
|
});
|
|
14
19
|
};
|
|
@@ -2,3 +2,30 @@ export type EmptyStateType = 'collection-empty' | 'no-results';
|
|
|
2
2
|
export declare const emptyStateVariants: (props?: ({
|
|
3
3
|
type?: "collection-empty" | "no-results" | null | undefined;
|
|
4
4
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
5
|
+
/**
|
|
6
|
+
* The medallion: a 36px raised tile holding a 20px glyph, which with `p-8` fills
|
|
7
|
+
* the content box exactly — the hairline is an inset ring in the shadow list,
|
|
8
|
+
* not a real border, so it doesn't eat into the padding. `text-xl` sets the
|
|
9
|
+
* 20px em box, so an icon left at its default `size='inherit'` lands on spec
|
|
10
|
+
* without every call site restating a size.
|
|
11
|
+
*
|
|
12
|
+
* The Figma master's placeholder is 16px at 10px padding, but every applied
|
|
13
|
+
* instance and the medallion spec sheet itself use 20px at 8px — the file is
|
|
14
|
+
* inconsistent here, and the 20/8 pairing is the one that fills the tile.
|
|
15
|
+
*
|
|
16
|
+
* There is deliberately no unframed variant — the spec never shows a bare glyph,
|
|
17
|
+
* at either scale, so an illustration always carries the tile.
|
|
18
|
+
*
|
|
19
|
+
* `rounded-[15px]` is off the radius scale on purpose: it's the value Figma
|
|
20
|
+
* reports for this node, and fitting a superellipse to the rendered outline
|
|
21
|
+
* agrees — a plain circular corner at r=14.5 matches to 0.29px, and r=15 to
|
|
22
|
+
* 0.35px, while the nearest token (16) is off by 0.73px. There is no corner
|
|
23
|
+
* smoothing on this shape, so no `corner-shape` is needed.
|
|
24
|
+
*/
|
|
25
|
+
export declare const emptyStateIllustrationVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
26
|
+
export declare const emptyStateMessageVariants: (props?: ({
|
|
27
|
+
type?: "collection-empty" | "no-results" | null | undefined;
|
|
28
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
29
|
+
export declare const emptyStateTitleVariants: (props?: ({
|
|
30
|
+
type?: "collection-empty" | "no-results" | null | undefined;
|
|
31
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import { cva } from "class-variance-authority";
|
|
2
|
-
const emptyStateVariants = cva('flex flex-col items-center text-center
|
|
2
|
+
const emptyStateVariants = cva('flex flex-col items-center text-center m-[0_auto]', {
|
|
3
3
|
variants: {
|
|
4
4
|
type: {
|
|
5
|
-
'collection-empty': 'max-w-[560px] min-w-[256px]',
|
|
6
|
-
'no-results': 'w-[240px]
|
|
5
|
+
'collection-empty': 'gap-16 py-24 max-w-[560px] min-w-[256px]',
|
|
6
|
+
'no-results': 'gap-8 py-8 w-[240px]'
|
|
7
7
|
}
|
|
8
8
|
},
|
|
9
9
|
defaultVariants: {
|
|
10
10
|
type: 'collection-empty'
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
|
-
|
|
13
|
+
const emptyStateIllustrationVariants = cva('empty-state-medallion flex items-center justify-center shrink-0 size-36 rounded-[15px] p-8 text-xl text-icon-secondary');
|
|
14
|
+
const emptyStateMessageVariants = cva('flex flex-col items-center', {
|
|
15
|
+
variants: {
|
|
16
|
+
type: {
|
|
17
|
+
'collection-empty': 'gap-8',
|
|
18
|
+
'no-results': 'gap-4'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
type: 'collection-empty'
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const emptyStateTitleVariants = cva('text-center break-words', {
|
|
26
|
+
variants: {
|
|
27
|
+
type: {
|
|
28
|
+
'collection-empty': 'font-pixel text-base leading-base text-text-primary',
|
|
29
|
+
'no-results': 'font-sans-display text-sm font-medium text-text-secondary'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
defaultVariants: {
|
|
33
|
+
type: 'collection-empty'
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
export { emptyStateIllustrationVariants, emptyStateMessageVariants, emptyStateTitleVariants, emptyStateVariants };
|
|
@@ -30,6 +30,8 @@ const ChipsWithGaps = ({ chips, hideLeadingGap, hideTrailingGap, onChipClick, on
|
|
|
30
30
|
valueSeparator: chip.valueSeparator,
|
|
31
31
|
errorValueIndices: chip.errorValueIndices,
|
|
32
32
|
disabled: chip.disabled,
|
|
33
|
+
valueMaxWidth: chip.valueMaxWidth,
|
|
34
|
+
caretMode: chip.caretMode,
|
|
33
35
|
pair: chip.pair,
|
|
34
36
|
onRemove: chip.disabled ? void 0 : ()=>onChipRemove(chip.id),
|
|
35
37
|
onSegmentClick: chip.disabled ? void 0 : (segment, anchorEl)=>onChipClick(chip.id, segment, anchorEl),
|
|
@@ -20,6 +20,11 @@ export interface FilterInputChipProps extends Omit<HTMLAttributes<HTMLDivElement
|
|
|
20
20
|
building?: boolean;
|
|
21
21
|
/** When true, the chip cannot be edited or removed (dimmed appearance) */
|
|
22
22
|
disabled?: boolean;
|
|
23
|
+
/** Caps the applied value segment at this width (px), truncating with an
|
|
24
|
+
* ellipsis; lifts the chip's default max-width so it grows to fit (AS-1064). */
|
|
25
|
+
valueMaxWidth?: number;
|
|
26
|
+
/** `'end'` places the caret at the end on value inline-edit; omit to select all (AS-1064). */
|
|
27
|
+
caretMode?: 'end';
|
|
23
28
|
/** Second paired triplet (two-step fields). The paired attribute is fixed. */
|
|
24
29
|
pair?: FilterInputChipData['pair'];
|
|
25
30
|
onRemove?: () => void;
|
|
@@ -9,7 +9,7 @@ import { FilterInputRemoveButton } from "./FilterInputRemoveButton.js";
|
|
|
9
9
|
import { PairSeparator } from "./PairSeparator.js";
|
|
10
10
|
import { Segment } from "./Segment.js";
|
|
11
11
|
import { SEGMENT_VARIANT } from "./segmentVariant.js";
|
|
12
|
-
const FilterInputChip = ({ ref, chipId, attribute, attributeDescription, operator, value, error = false, valueParts, valueSeparator, errorValueIndices, building = false, disabled = false, pair, onRemove, onSegmentClick, onPairSegmentClick, className, ...props })=>{
|
|
12
|
+
const FilterInputChip = ({ ref, chipId, attribute, attributeDescription, operator, value, error = false, valueParts, valueSeparator, errorValueIndices, building = false, disabled = false, valueMaxWidth, caretMode, pair, onRemove, onSegmentClick, onPairSegmentClick, className, style, ...props })=>{
|
|
13
13
|
const interactive = !disabled;
|
|
14
14
|
const internalRef = useRef(null);
|
|
15
15
|
const editing = useEditingContext();
|
|
@@ -75,6 +75,10 @@ const FilterInputChip = ({ ref, chipId, attribute, attributeDescription, operato
|
|
|
75
75
|
disabled,
|
|
76
76
|
building
|
|
77
77
|
}), pair ? 'max-w-[380px]' : 'max-w-[320px]', className),
|
|
78
|
+
style: valueMaxWidth && !pair ? {
|
|
79
|
+
maxWidth: 'none',
|
|
80
|
+
...style
|
|
81
|
+
} : style,
|
|
78
82
|
"data-slot": "filter-input-condition-chip",
|
|
79
83
|
...building && {
|
|
80
84
|
'data-building': ''
|
|
@@ -104,10 +108,17 @@ const FilterInputChip = ({ ref, chipId, attribute, attributeDescription, operato
|
|
|
104
108
|
(value || baseActiveSegment === SEGMENT_VARIANT.value || !pair && effectiveError === SEGMENT_VARIANT.value) && /*#__PURE__*/ jsx(Segment, {
|
|
105
109
|
variant: SEGMENT_VARIANT.value,
|
|
106
110
|
className: value || pair ? pair ? 'max-w-[90px] shrink-0' : 'min-w-0' : emptyValueHitTarget,
|
|
111
|
+
...valueMaxWidth && value && !pair && {
|
|
112
|
+
style: {
|
|
113
|
+
maxWidth: valueMaxWidth
|
|
114
|
+
}
|
|
115
|
+
},
|
|
107
116
|
error: baseActiveSegment !== SEGMENT_VARIANT.value && (true === effectiveError || effectiveError === SEGMENT_VARIANT.value),
|
|
108
117
|
valueParts: valueParts,
|
|
109
118
|
valueSeparator: valueSeparator,
|
|
110
119
|
errorValueIndices: errorValueIndices,
|
|
120
|
+
caretMode: caretMode,
|
|
121
|
+
valueMaxWidth: valueMaxWidth,
|
|
111
122
|
onClick: interactive ? (e)=>handleSegmentClick(SEGMENT_VARIANT.value, e) : void 0,
|
|
112
123
|
onMouseDown: interactive && building ? handleSegmentMouseDown : void 0,
|
|
113
124
|
...segmentEditProps(SEGMENT_VARIANT.value),
|
|
@@ -18,5 +18,11 @@ export type SegmentProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
18
18
|
valueSeparator?: string;
|
|
19
19
|
/** Indices of invalid values in valueParts */
|
|
20
20
|
errorValueIndices?: number[];
|
|
21
|
+
/** `'end'` places the caret at the end on edit; omit for default select-all (AS-1064). */
|
|
22
|
+
caretMode?: 'end';
|
|
23
|
+
/** Caps the edit input's width (px) to match the applied value cap, so the
|
|
24
|
+
* segment keeps the same width entering/leaving edit instead of snapping to
|
|
25
|
+
* the default MAX_INPUT_WIDTH. Value variant only (AS-1064). */
|
|
26
|
+
valueMaxWidth?: number;
|
|
21
27
|
};
|
|
22
28
|
export declare const Segment: FC<SegmentProps>;
|
|
@@ -2,12 +2,13 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useCallback, useContext, useEffect, useRef } from "react";
|
|
3
3
|
import { cn } from "../../../../utils/cn.js";
|
|
4
4
|
import { FilterInputContext } from "../../FilterInputContext/FilterInputContext.js";
|
|
5
|
+
import { applyEditCaret } from "./applyEditCaret.js";
|
|
5
6
|
import { editingValueMinWidth, segmentContainer, segmentTextVariants } from "./classes.js";
|
|
6
7
|
import { CHAR_WIDTH_PX } from "./constants.js";
|
|
7
8
|
import { MultiValueSegment } from "./MultiValueSegment.js";
|
|
8
9
|
import { useSizerWidth } from "./model/useSizerWidth.js";
|
|
9
10
|
import { SEGMENT_VARIANT } from "./segmentVariant.js";
|
|
10
|
-
const Segment = ({ ref, variant, children, className, error, editing, editText, onEditChange, onEditKeyDown, onEditBlur, valueParts, valueSeparator = ', ', errorValueIndices, ...props })=>{
|
|
11
|
+
const Segment = ({ ref, variant, children, className, error, editing, editText, onEditChange, onEditKeyDown, onEditBlur, valueParts, valueSeparator = ', ', errorValueIndices, caretMode, valueMaxWidth, ...props })=>{
|
|
11
12
|
const textRef = useRef(null);
|
|
12
13
|
const inputRef = useRef(null);
|
|
13
14
|
const sizerRef = useRef(null);
|
|
@@ -28,7 +29,7 @@ const Segment = ({ ref, variant, children, className, error, editing, editText,
|
|
|
28
29
|
const outerFrame = requestAnimationFrame(()=>{
|
|
29
30
|
innerFrame = requestAnimationFrame(()=>{
|
|
30
31
|
inputRef.current?.focus();
|
|
31
|
-
inputRef.current
|
|
32
|
+
applyEditCaret(inputRef.current);
|
|
32
33
|
});
|
|
33
34
|
});
|
|
34
35
|
return ()=>{
|
|
@@ -40,7 +41,10 @@ const Segment = ({ ref, variant, children, className, error, editing, editText,
|
|
|
40
41
|
]);
|
|
41
42
|
const inputWidth = useSizerWidth({
|
|
42
43
|
sizerRef,
|
|
43
|
-
text: editText ?? ''
|
|
44
|
+
text: editText ?? '',
|
|
45
|
+
...variant === SEGMENT_VARIANT.value && valueMaxWidth && {
|
|
46
|
+
maxWidth: valueMaxWidth
|
|
47
|
+
}
|
|
44
48
|
});
|
|
45
49
|
const setInputRef = useCallback((node)=>{
|
|
46
50
|
inputRef.current = node;
|
|
@@ -76,6 +80,9 @@ const Segment = ({ ref, variant, children, className, error, editing, editText,
|
|
|
76
80
|
onKeyDown: onEditKeyDown,
|
|
77
81
|
onBlur: onEditBlur,
|
|
78
82
|
"aria-label": `Filter ${variant}`,
|
|
83
|
+
...'end' === caretMode && {
|
|
84
|
+
'data-caret-mode': 'end'
|
|
85
|
+
},
|
|
79
86
|
className: cn(segmentTextVariants({
|
|
80
87
|
variant,
|
|
81
88
|
error
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const applyEditCaret: (input: HTMLInputElement | null) => void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { type ConnectorVariant, FilterInputConnectorChip, type FilterInputConnectorChipProps, } from '../FilterInputConnectorChip';
|
|
2
|
+
export { applyEditCaret } from './applyEditCaret';
|
|
2
3
|
export { type EditingContextValue, EditingProvider, useEditingContext, } from './context/EditingContext';
|
|
3
4
|
export { type ChipSegment, FilterInputChip, type FilterInputChipProps, type PairSegment, } from './FilterInputChip';
|
|
4
5
|
export { FilterInputRemoveButton } from './FilterInputRemoveButton';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { FilterInputConnectorChip } from "../FilterInputConnectorChip/index.js";
|
|
2
|
+
export { applyEditCaret } from "./applyEditCaret.js";
|
|
2
3
|
export { EditingProvider, useEditingContext } from "./context/EditingContext.js";
|
|
3
4
|
export { FilterInputChip } from "./FilterInputChip.js";
|
|
4
5
|
export { FilterInputRemoveButton } from "./FilterInputRemoveButton.js";
|
package/dist/components/FilterInput/hooks/useFilterInputAutocomplete/useFilterInputAutocomplete.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback } from "react";
|
|
2
2
|
import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
|
|
3
3
|
import { useDateRange } from "../../FilterInputMenu/FilterInputDateValueMenu/hooks.js";
|
|
4
|
+
import { isMultiSelectOperator } from "../../lib/index.js";
|
|
4
5
|
import { deriveAutocompleteValues } from "./lib/index.js";
|
|
5
6
|
import { useAutocompleteState } from "./useAutocompleteState.js";
|
|
6
7
|
import { useBlurCommit } from "./useBlurCommit.js";
|
|
@@ -218,6 +219,8 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
218
219
|
buildingBase,
|
|
219
220
|
editingSide: editing.editingSide
|
|
220
221
|
});
|
|
222
|
+
const isMultiValueValueEdit = null != editing.editingChipId && editing.editingSegment === SEGMENT_VARIANT.value && null != selectedOperator && isMultiSelectOperator(selectedOperator);
|
|
223
|
+
const liveSegmentFilterText = isMultiValueValueEdit && null != buildingMultiValue && '' === editing.segmentMenuFilterText ? buildingMultiValue : editing.segmentFilterText;
|
|
221
224
|
return {
|
|
222
225
|
inputText,
|
|
223
226
|
menuState,
|
|
@@ -260,7 +263,7 @@ const useFilterInputAutocomplete = ({ fields, conditions, chips, upsertCondition
|
|
|
260
263
|
editingChipId: editing.editingChipId,
|
|
261
264
|
editingSegment: editing.editingSegment,
|
|
262
265
|
editingSide: editing.editingSide,
|
|
263
|
-
segmentFilterText:
|
|
266
|
+
segmentFilterText: liveSegmentFilterText,
|
|
264
267
|
segmentMenuFilterText: editing.segmentMenuFilterText,
|
|
265
268
|
handleSegmentFilterChange,
|
|
266
269
|
cancelSegmentEdit,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
-
import { SEGMENT_VARIANT } from "../../FilterInputField/FilterInputChip/index.js";
|
|
2
|
+
import { SEGMENT_VARIANT, applyEditCaret } from "../../FilterInputField/FilterInputChip/index.js";
|
|
3
3
|
import { isMenuRelated, nextBuildingMenu } from "../../lib/index.js";
|
|
4
4
|
const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText, selectedField, selectedOperator, containerRef, inputRef, editingSegment, segmentAttributeInputRef, segmentOperatorInputRef, segmentValueInputRef, blurCommitRef, commitBuildingOnBlur, hasIncompleteBuilding, setIsFocused, setMenuState, resetMenuAnchor, resetState })=>{
|
|
5
5
|
const handleFocus = useCallback((e)=>{
|
|
@@ -12,12 +12,19 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
12
12
|
const handleBlur = useCallback((e)=>{
|
|
13
13
|
if (handlingBlurRef.current) return;
|
|
14
14
|
const related = e.relatedTarget;
|
|
15
|
-
if (containerRef.current?.contains(related)) return;
|
|
16
15
|
if (isMenuRelated(related)) return;
|
|
16
|
+
if (null != related && (related === segmentAttributeInputRef.current || related === segmentOperatorInputRef.current || related === segmentValueInputRef.current)) return;
|
|
17
17
|
handlingBlurRef.current = true;
|
|
18
18
|
try {
|
|
19
|
+
const focusStaysInside = !!containerRef.current?.contains(related);
|
|
20
|
+
if ((null != editingSegment || !focusStaysInside) && blurCommitRef.current?.()) {
|
|
21
|
+
setIsFocused(false);
|
|
22
|
+
related?.focus();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (focusStaysInside) return;
|
|
19
26
|
setIsFocused(false);
|
|
20
|
-
const committed =
|
|
27
|
+
const committed = commitBuildingOnBlur();
|
|
21
28
|
if (!committed) if (hasIncompleteBuilding()) setMenuState('closed');
|
|
22
29
|
else resetState();
|
|
23
30
|
related?.focus();
|
|
@@ -33,7 +40,11 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
33
40
|
resetState,
|
|
34
41
|
setIsFocused,
|
|
35
42
|
setMenuState,
|
|
36
|
-
inputRef
|
|
43
|
+
inputRef,
|
|
44
|
+
editingSegment,
|
|
45
|
+
segmentAttributeInputRef,
|
|
46
|
+
segmentOperatorInputRef,
|
|
47
|
+
segmentValueInputRef
|
|
37
48
|
]);
|
|
38
49
|
const prevFocusedRef = useRef(false);
|
|
39
50
|
useEffect(()=>{
|
|
@@ -87,7 +98,7 @@ const useFocusManagement = ({ menuState, isFocused, conditionsLength, inputText,
|
|
|
87
98
|
if (!dest) return;
|
|
88
99
|
if (document.activeElement === dest) return;
|
|
89
100
|
dest.focus();
|
|
90
|
-
if (editingSegment) dest
|
|
101
|
+
if (editingSegment) applyEditCaret(dest);
|
|
91
102
|
});
|
|
92
103
|
});
|
|
93
104
|
return ()=>{
|
|
@@ -39,6 +39,12 @@ const buildBaseChip = (i, condition, field)=>({
|
|
|
39
39
|
...field?.description && {
|
|
40
40
|
attributeDescription: field.description
|
|
41
41
|
},
|
|
42
|
+
...field?.valueMaxWidth && {
|
|
43
|
+
valueMaxWidth: field.valueMaxWidth
|
|
44
|
+
},
|
|
45
|
+
...field?.caretMode && {
|
|
46
|
+
caretMode: field.caretMode
|
|
47
|
+
},
|
|
42
48
|
operator: condition.operator ? getOperatorLabel(condition.operator, field?.type || DEFAULT_FIELD_TYPE) : void 0,
|
|
43
49
|
...condition.disabled && {
|
|
44
50
|
disabled: true
|
|
@@ -38,6 +38,10 @@ export interface FilterInputChipData {
|
|
|
38
38
|
errorValueIndices?: number[];
|
|
39
39
|
/** When true, the chip cannot be edited or removed */
|
|
40
40
|
disabled?: boolean;
|
|
41
|
+
/** Applied value-segment width cap in px (see FieldMetadata.valueMaxWidth). */
|
|
42
|
+
valueMaxWidth?: number;
|
|
43
|
+
/** Caret placement on value inline-edit (see FieldMetadata.caretMode). */
|
|
44
|
+
caretMode?: 'end';
|
|
41
45
|
/** Second paired triplet (display) for two-step fields. */
|
|
42
46
|
pair?: {
|
|
43
47
|
attribute: string;
|
|
@@ -199,6 +203,18 @@ export interface FieldMetadata {
|
|
|
199
203
|
* set it while an async options fetch is in flight.
|
|
200
204
|
*/
|
|
201
205
|
loadingOptions?: boolean;
|
|
206
|
+
/**
|
|
207
|
+
* Caps the applied value segment at this width in px: a longer value truncates
|
|
208
|
+
* with a trailing ellipsis while the full value is preserved for matching. When
|
|
209
|
+
* set, the chip's default max-width is lifted so it grows to fit the wider value.
|
|
210
|
+
* Omit to keep the chip's default cap. (AS-1064: long parameter-path expressions.)
|
|
211
|
+
*/
|
|
212
|
+
valueMaxWidth?: number;
|
|
213
|
+
/**
|
|
214
|
+
* `'end'` places the caret at the end of the value on inline-edit (natural for
|
|
215
|
+
* long values); omit to select the whole value so typing replaces it. (AS-1064)
|
|
216
|
+
*/
|
|
217
|
+
caretMode?: 'end';
|
|
202
218
|
}
|
|
203
219
|
/**
|
|
204
220
|
* A labeled group of filter fields for the field-selection menu, referenced by
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from "./SvgIcon.js";
|
|
3
|
+
const Shapes = (props)=>/*#__PURE__*/ jsx(SvgIcon, {
|
|
4
|
+
...props,
|
|
5
|
+
viewBox: "0 0 24 24",
|
|
6
|
+
children: /*#__PURE__*/ jsx("path", {
|
|
7
|
+
d: "M9 13C10.105 13 11 13.895 11 15V20C11 21.105 10.105 22 9 22H4C2.895 22 2 21.105 2 20V15C2 13.895 2.895 13 4 13H9ZM17.5 13C19.985 13 22 15.015 22 17.5C22 19.985 19.985 22 17.5 22C15.015 22 13 19.985 13 17.5C13 15.015 15.015 13 17.5 13ZM4 20H9V15H4V20ZM17.5 15C16.119 15 15 16.119 15 17.5C15 18.881 16.119 20 17.5 20C18.881 20 20 18.881 20 17.5C20 16.119 18.881 15 17.5 15ZM12.169 1.647C12.314 1.661 12.457 1.692 12.594 1.742L12.794 1.83L12.981 1.943C13.161 2.068 13.315 2.226 13.435 2.41C13.438 2.416 13.443 2.422 13.446 2.428L17.148 8.371C17.287 8.584 17.377 8.824 17.41 9.075L17.422 9.19L17.425 9.307C17.424 9.577 17.358 9.843 17.233 10.084C17.09 10.359 16.875 10.59 16.61 10.751C16.346 10.912 16.041 10.999 15.731 11H8.3V10.999C8.005 11.006 7.713 10.937 7.453 10.797C7.178 10.648 6.948 10.425 6.791 10.154C6.634 9.883 6.555 9.573 6.562 9.26C6.57 8.946 6.664 8.641 6.834 8.378L10.554 2.467L10.555 2.469C10.695 2.233 10.889 2.034 11.123 1.891C11.373 1.738 11.658 1.651 11.95 1.641L12.169 1.647ZM8.806 9H15.184L12.011 3.905L8.806 9Z",
|
|
8
|
+
fill: "currentColor"
|
|
9
|
+
})
|
|
10
|
+
});
|
|
11
|
+
Shapes.displayName = 'ShapesIcon';
|
|
12
|
+
export { Shapes };
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -438,6 +438,7 @@ export { Ses } from './Ses';
|
|
|
438
438
|
export { SesNeutral } from './SesNeutral';
|
|
439
439
|
export { Settings } from './Settings';
|
|
440
440
|
export { Settings2 } from './Settings2';
|
|
441
|
+
export { Shapes } from './Shapes';
|
|
441
442
|
export { Share } from './Share';
|
|
442
443
|
export { Sheet } from './Sheet';
|
|
443
444
|
export { Shield } from './Shield';
|
package/dist/icons/index.js
CHANGED
|
@@ -438,6 +438,7 @@ export { Ses } from "./Ses.js";
|
|
|
438
438
|
export { SesNeutral } from "./SesNeutral.js";
|
|
439
439
|
export { Settings } from "./Settings.js";
|
|
440
440
|
export { Settings2 } from "./Settings2.js";
|
|
441
|
+
export { Shapes } from "./Shapes.js";
|
|
441
442
|
export { Share } from "./Share.js";
|
|
442
443
|
export { Sheet } from "./Sheet.js";
|
|
443
444
|
export { Shield } from "./Shield.js";
|