@onerjs/shared-ui-components 8.41.5 → 8.41.7
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/fluent/hoc/childWindow.js +3 -16
- package/fluent/hoc/childWindow.js.map +1 -1
- package/fluent/hoc/propertyLines/propertyLine.js +15 -2
- package/fluent/hoc/propertyLines/propertyLine.js.map +1 -1
- package/fluent/primitives/accordion.contexts.d.ts +12 -13
- package/fluent/primitives/accordion.contexts.js +49 -42
- package/fluent/primitives/accordion.contexts.js.map +1 -1
- package/fluent/primitives/accordion.js +20 -13
- package/fluent/primitives/accordion.js.map +1 -1
- package/fluent/primitives/spinButton.js +54 -20
- package/fluent/primitives/spinButton.js.map +1 -1
- package/fluent/primitives/toast.js +1 -1
- package/fluent/primitives/toast.js.map +1 -1
- package/fluent/primitives/toggleButton.js +3 -3
- package/fluent/primitives/toggleButton.js.map +1 -1
- package/nodeGraphSystem/graphFrame.d.ts +0 -2
- package/nodeGraphSystem/graphFrame.js +15 -18
- package/nodeGraphSystem/graphFrame.js.map +1 -1
- package/nodeGraphSystem/graphFrame.module.scss +5 -10
- package/nodeGraphSystem/graphNode.module.scss +3 -5
- package/package.json +1 -1
|
@@ -58,17 +58,20 @@ const useStyles = makeStyles({
|
|
|
58
58
|
flexGrow: 1,
|
|
59
59
|
justifyContent: "end",
|
|
60
60
|
},
|
|
61
|
-
sectionEmpty: {
|
|
62
|
-
display: "none",
|
|
63
|
-
},
|
|
64
61
|
sectionItemContainer: {
|
|
65
62
|
display: "flex",
|
|
66
63
|
flexDirection: "row",
|
|
64
|
+
alignItems: "center",
|
|
65
|
+
},
|
|
66
|
+
sectionItemContent: {
|
|
67
|
+
flexGrow: 1,
|
|
68
|
+
minWidth: 0, // Allow content to shrink below its intrinsic width when buttons are shown
|
|
69
|
+
overflow: "hidden",
|
|
67
70
|
},
|
|
68
71
|
sectionItemButtons: {
|
|
69
72
|
display: "flex",
|
|
70
73
|
flexDirection: "row",
|
|
71
|
-
alignItems: "
|
|
74
|
+
alignItems: "center",
|
|
72
75
|
marginRight: tokens.spacingHorizontalXS,
|
|
73
76
|
},
|
|
74
77
|
pinnedContainer: {
|
|
@@ -99,11 +102,10 @@ const AccordionMenuBar = () => {
|
|
|
99
102
|
const { state, dispatch, features } = accordionCtx;
|
|
100
103
|
const { editMode } = state;
|
|
101
104
|
return (_jsxs("div", { className: classes.menuBar, children: [_jsx(AccordionSearchBox, {}), _jsxs("div", { className: classes.menuBarControls, children: [features.hiding && editMode && (_jsxs(_Fragment, { children: [_jsx(Button, { title: "Show all", icon: EyeFilled, appearance: "subtle", onClick: () => dispatch({ type: "SHOW_ALL" }) }), _jsx(Button, { title: "Hide all", icon: EyeOffRegular, appearance: "subtle", onClick: () => {
|
|
102
|
-
// Hide all visible
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
dispatch({ type: "HIDE_ALL_VISIBLE", visibleItemIds: [] });
|
|
105
|
+
// Hide all visible (non-hidden) items using the registered item IDs
|
|
106
|
+
const { registeredItemIds, state: currentState } = accordionCtx;
|
|
107
|
+
const visibleItemIds = Array.from(registeredItemIds.keys()).filter((id) => !currentState.hiddenIds.includes(id));
|
|
108
|
+
dispatch({ type: "HIDE_ALL_VISIBLE", visibleItemIds });
|
|
107
109
|
} })] })), (features.pinning || features.hiding) && (_jsx(Button, { title: "Edit mode", icon: editMode ? CheckmarkFilled : EditRegular, appearance: editMode ? "primary" : "subtle", onClick: () => dispatch({ type: "SET_EDIT_MODE", enabled: !editMode }) }))] })] }));
|
|
108
110
|
};
|
|
109
111
|
/**
|
|
@@ -117,9 +119,9 @@ const AccordionSectionBlock = (props) => {
|
|
|
117
119
|
AccordionSectionBlock.displayName = "AccordionSectionBlock";
|
|
118
120
|
const { children, sectionId } = props;
|
|
119
121
|
const accordionCtx = useContext(AccordionContext);
|
|
120
|
-
const sectionContext = useAccordionSectionBlockContext(props);
|
|
122
|
+
const { context: sectionContext, isEmpty } = useAccordionSectionBlockContext(props);
|
|
121
123
|
if (accordionCtx) {
|
|
122
|
-
return (_jsx(AccordionSectionBlockContext.Provider, { value: sectionContext, children: _jsx(AccordionItem, { value: sectionId, children: children }) }));
|
|
124
|
+
return (_jsx(AccordionSectionBlockContext.Provider, { value: sectionContext, children: !isEmpty && _jsx(AccordionItem, { value: sectionId, children: children }) }));
|
|
123
125
|
}
|
|
124
126
|
return _jsx(AccordionItem, { value: sectionId, children: children });
|
|
125
127
|
};
|
|
@@ -144,12 +146,17 @@ export const AccordionSectionItem = (props) => {
|
|
|
144
146
|
useEffect(() => {
|
|
145
147
|
setCtrlMode(ctrlPressed && mouseOver);
|
|
146
148
|
}, [ctrlPressed, mouseOver]);
|
|
149
|
+
// Override disableCopy so copy buttons appear when ctrl+hovering on this item or when edit mode is active
|
|
150
|
+
const parentToolContext = useContext(ToolContext);
|
|
151
|
+
const editMode = accordionCtx?.state.editMode ?? false;
|
|
152
|
+
const showCopy = ctrlMode || editMode;
|
|
153
|
+
const itemToolContext = useMemo(() => (showCopy ? { ...parentToolContext, disableCopy: false } : parentToolContext), [parentToolContext, showCopy]);
|
|
147
154
|
// If static item or no context, just render children
|
|
148
155
|
if (staticItem || !accordionCtx || !itemState) {
|
|
149
156
|
return _jsx(_Fragment, { children: children });
|
|
150
157
|
}
|
|
151
158
|
const { pinnedContainerRef, features } = accordionCtx;
|
|
152
|
-
const { isNested, isPinned, isHidden, isMatch, pinnedIndex, inEditMode, actions } = itemState;
|
|
159
|
+
const { isNested, isPinned, isHidden, isMatch, pinnedIndex, canMoveUp, inEditMode, actions } = itemState;
|
|
153
160
|
// Nested items just render children (don't show controls)
|
|
154
161
|
if (isNested) {
|
|
155
162
|
return _jsx(_Fragment, { children: children });
|
|
@@ -160,7 +167,7 @@ export const AccordionSectionItem = (props) => {
|
|
|
160
167
|
}
|
|
161
168
|
const pinnedContainer = isPinned ? pinnedContainerRef.current : null;
|
|
162
169
|
const showControls = inEditMode || ctrlMode;
|
|
163
|
-
const itemElement = (_jsxs("div", { className: classes.sectionItemContainer, style: isPinned ? { order: pinnedIndex } : undefined, onMouseMove: () => setMouseOver(true), onMouseLeave: () => setMouseOver(false), children: [showControls && (_jsxs("div", { className: classes.sectionItemButtons, children: [features.hiding && (_jsx(Button, { title: isHidden ? "Unhide" : "Hide", icon: isHidden ? EyeOffRegular : EyeFilled, appearance: "transparent", onClick: actions.toggleHidden })), features.pinning && (_jsxs(_Fragment, { children: [_jsx(Button, { title: isPinned ? "Unpin" : "Pin", icon: isPinned ? PinFilled : PinRegular, appearance: "transparent", onClick: actions.togglePinned }), isPinned &&
|
|
170
|
+
const itemElement = (_jsx(ToolContext.Provider, { value: itemToolContext, children: _jsxs("div", { className: classes.sectionItemContainer, style: isPinned ? { order: pinnedIndex } : undefined, onMouseMove: () => setMouseOver(true), onMouseLeave: () => setMouseOver(false), children: [showControls && (_jsxs("div", { className: classes.sectionItemButtons, children: [features.hiding && (_jsx(Button, { title: isHidden ? "Unhide" : "Hide", icon: isHidden ? EyeOffRegular : EyeFilled, appearance: "transparent", onClick: actions.toggleHidden })), features.pinning && (_jsxs(_Fragment, { children: [_jsx(Button, { title: isPinned ? "Unpin" : "Pin", icon: isPinned ? PinFilled : PinRegular, appearance: "transparent", onClick: actions.togglePinned }), isPinned && _jsx(Button, { icon: ArrowCircleUpRegular, appearance: "transparent", disabled: !canMoveUp, onClick: actions.movePinnedUp })] }))] })), _jsx(AccordionItemDepthContext.Provider, { value: true, children: _jsx("div", { className: classes.sectionItemContent, children: children }) })] }) }));
|
|
164
171
|
return pinnedContainer ? _jsx(Portal, { mountNode: pinnedContainer, children: itemElement }) : itemElement;
|
|
165
172
|
};
|
|
166
173
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/accordion.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { AccordionPanelProps, AccordionToggleData, AccordionToggleEvent, AccordionProps as FluentAccordionProps } from \"@fluentui/react-components\";\r\nimport type { ForwardRefExoticComponent, FunctionComponent, PropsWithChildren, RefAttributes } from \"react\";\r\n\r\nimport {\r\n AccordionHeader,\r\n AccordionItem,\r\n AccordionPanel,\r\n Divider,\r\n Accordion as FluentAccordion,\r\n MessageBar,\r\n MessageBarBody,\r\n Portal,\r\n SearchBox,\r\n Subtitle2Stronger,\r\n makeStyles,\r\n tokens,\r\n} from \"@fluentui/react-components\";\r\nimport { ArrowCircleUpRegular, CheckmarkFilled, EditRegular, EyeFilled, EyeOffRegular, FilterRegular, PinFilled, PinRegular } from \"@fluentui/react-icons\";\r\nimport { Children, forwardRef, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\r\n\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\nimport { useKeyState } from \"../hooks/keyboardHooks\";\r\nimport {\r\n AccordionContext,\r\n AccordionItemDepthContext,\r\n AccordionSectionBlockContext,\r\n useAccordionContext,\r\n useAccordionSectionBlockContext,\r\n useAccordionSectionItemState,\r\n} from \"./accordion.contexts\";\r\nimport { Button } from \"./button\";\r\nimport { CustomTokens } from \"./utils\";\r\n\r\nconst useStyles = makeStyles({\r\n accordion: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n height: \"100%\",\r\n },\r\n accordionBody: {\r\n overflowX: \"hidden\",\r\n overflowY: \"auto\",\r\n paddingBottom: tokens.spacingVerticalM, // bottom padding since there is no divider at the bottom\r\n },\r\n divider: {\r\n paddingTop: CustomTokens.dividerGap,\r\n paddingBottom: CustomTokens.dividerGap,\r\n },\r\n dividerSmall: {\r\n paddingTop: CustomTokens.dividerGapSmall,\r\n paddingBottom: CustomTokens.dividerGapSmall,\r\n },\r\n panelDiv: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n overflow: \"hidden\",\r\n },\r\n highlightDiv: {\r\n borderRadius: tokens.borderRadiusLarge,\r\n animationDuration: \"1s\",\r\n animationTimingFunction: \"ease-in-out\",\r\n animationIterationCount: \"5\",\r\n animationFillMode: \"forwards\",\r\n animationName: {\r\n from: {\r\n boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,\r\n },\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n \"50%\": {\r\n boxShadow: `inset 0 0 12px ${tokens.colorBrandBackground}`,\r\n },\r\n to: {\r\n boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,\r\n },\r\n },\r\n },\r\n menuBar: {\r\n display: \"flex\",\r\n },\r\n menuBarControls: {\r\n display: \"flex\",\r\n flexGrow: 1,\r\n justifyContent: \"end\",\r\n },\r\n sectionEmpty: {\r\n display: \"none\",\r\n },\r\n sectionItemContainer: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n },\r\n sectionItemButtons: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n alignItems: \"start\",\r\n marginRight: tokens.spacingHorizontalXS,\r\n },\r\n pinnedContainer: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n },\r\n pinnedContainerEmpty: {\r\n \"&:not(:only-child)\": {\r\n display: \"none\",\r\n },\r\n },\r\n searchBox: {\r\n width: \"100%\",\r\n },\r\n});\r\n\r\n/**\r\n * Renders the menu bar and control buttons.\r\n *\r\n * @returns `div`, or `undefined` if all features are disabled.\r\n */\r\nconst AccordionMenuBar: FunctionComponent = () => {\r\n AccordionMenuBar.displayName = \"AccordionMenuBar\";\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n\r\n if (!accordionCtx) {\r\n return null;\r\n }\r\n\r\n const { state, dispatch, features } = accordionCtx;\r\n const { editMode } = state;\r\n\r\n return (\r\n <div className={classes.menuBar}>\r\n <AccordionSearchBox />\r\n <div className={classes.menuBarControls}>\r\n {features.hiding && editMode && (\r\n <>\r\n <Button title=\"Show all\" icon={EyeFilled} appearance=\"subtle\" onClick={() => dispatch({ type: \"SHOW_ALL\" })} />\r\n <Button\r\n title=\"Hide all\"\r\n icon={EyeOffRegular}\r\n appearance=\"subtle\"\r\n onClick={() => {\r\n // Hide all visible items - we pass all non-hidden, matching items\r\n // For simplicity, we dispatch with an empty array; the actual filtering\r\n // would need to be done with knowledge of all registered items.\r\n // This is a limitation - in a full implementation, you'd track registered items.\r\n dispatch({ type: \"HIDE_ALL_VISIBLE\", visibleItemIds: [] });\r\n }}\r\n />\r\n </>\r\n )}\r\n {(features.pinning || features.hiding) && (\r\n <Button\r\n title=\"Edit mode\"\r\n icon={editMode ? CheckmarkFilled : EditRegular}\r\n appearance={editMode ? \"primary\" : \"subtle\"}\r\n onClick={() => dispatch({ type: \"SET_EDIT_MODE\", enabled: !editMode })}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Props: `AccordionSectionBlock`.\r\n */\r\nexport type AccordionSectionBlockProps = {\r\n /** The ID of the `AccordionSectionBlock`, unique within the `Accordion` instance. */\r\n sectionId: string;\r\n};\r\n\r\n/**\r\n * Wrapper component that must encapsulate the section headers and panels.\r\n * - Stores the section ID for use in `AccordionSectionItem`.\r\n *\r\n * @param props - `AccordionSectionBlockProps`\r\n * @returns `AccordionSectionBlockContext.Provider`, or `AccordionItem` if all features are disabled.\r\n */\r\nconst AccordionSectionBlock: FunctionComponent<PropsWithChildren<AccordionSectionBlockProps>> = (props) => {\r\n AccordionSectionBlock.displayName = \"AccordionSectionBlock\";\r\n const { children, sectionId } = props;\r\n const accordionCtx = useContext(AccordionContext);\r\n const sectionContext = useAccordionSectionBlockContext(props);\r\n\r\n if (accordionCtx) {\r\n return (\r\n <AccordionSectionBlockContext.Provider value={sectionContext}>\r\n <AccordionItem value={sectionId}>{children}</AccordionItem>\r\n </AccordionSectionBlockContext.Provider>\r\n );\r\n }\r\n\r\n return <AccordionItem value={sectionId}>{children}</AccordionItem>;\r\n};\r\n\r\n/**\r\n * Props: `AccordionSectionItem`.\r\n */\r\nexport type AccordionSectionItemProps = {\r\n /** The ID of the `AccordionSectionItem`, unique within the `AccordionSectionBlock` instance. */\r\n uniqueId: string;\r\n /** The searchable text label for the item. */\r\n label?: string;\r\n /** Whether the item is not interactable. */\r\n staticItem?: boolean;\r\n};\r\n\r\n/**\r\n * Wrapper component that must encapsulate individual items.\r\n * - Renders the pin button and tracks the pinned state of the item.\r\n * - Renders the hide button and tracks the hidden state of the item.\r\n * - Filters items based on the current search term.\r\n *\r\n * @param props - `AccordionSectionItemProps`\r\n * @returns `Portal` if pinned; `null` if hidden/filtered; `children` otherwise.\r\n */\r\nexport const AccordionSectionItem: FunctionComponent<PropsWithChildren<AccordionSectionItemProps>> = (props) => {\r\n AccordionSectionItem.displayName = \"AccordionSectionItem\";\r\n const { children, staticItem } = props;\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n const itemState = useAccordionSectionItemState(props);\r\n const [ctrlMode, setCtrlMode] = useState(false);\r\n const ctrlPressed = useKeyState(\"Control\");\r\n const [mouseOver, setMouseOver] = useState(false);\r\n\r\n useEffect(() => {\r\n setCtrlMode(ctrlPressed && mouseOver);\r\n }, [ctrlPressed, mouseOver]);\r\n\r\n // If static item or no context, just render children\r\n if (staticItem || !accordionCtx || !itemState) {\r\n return <>{children}</>;\r\n }\r\n\r\n const { pinnedContainerRef, features } = accordionCtx;\r\n const { isNested, isPinned, isHidden, isMatch, pinnedIndex, inEditMode, actions } = itemState;\r\n\r\n // Nested items just render children (don't show controls)\r\n if (isNested) {\r\n return <>{children}</>;\r\n }\r\n\r\n // If hidden (and not in edit mode) or doesn't match search, don't render\r\n if ((isHidden && !inEditMode) || !isMatch) {\r\n return null;\r\n }\r\n\r\n const pinnedContainer = isPinned ? pinnedContainerRef.current : null;\r\n const showControls = inEditMode || ctrlMode;\r\n\r\n const itemElement = (\r\n <div\r\n className={classes.sectionItemContainer}\r\n style={isPinned ? { order: pinnedIndex } : undefined}\r\n onMouseMove={() => setMouseOver(true)}\r\n onMouseLeave={() => setMouseOver(false)}\r\n >\r\n {showControls && (\r\n <div className={classes.sectionItemButtons}>\r\n {features.hiding && (\r\n <Button title={isHidden ? \"Unhide\" : \"Hide\"} icon={isHidden ? EyeOffRegular : EyeFilled} appearance=\"transparent\" onClick={actions.toggleHidden} />\r\n )}\r\n {features.pinning && (\r\n <>\r\n <Button title={isPinned ? \"Unpin\" : \"Pin\"} icon={isPinned ? PinFilled : PinRegular} appearance=\"transparent\" onClick={actions.togglePinned} />\r\n {isPinned && (\r\n <Button title=\"Move up\" icon={ArrowCircleUpRegular} appearance=\"transparent\" disabled={pinnedIndex === 0} onClick={actions.movePinnedUp} />\r\n )}\r\n </>\r\n )}\r\n </div>\r\n )}\r\n <AccordionItemDepthContext.Provider value={true}>{children}</AccordionItemDepthContext.Provider>\r\n </div>\r\n );\r\n\r\n return pinnedContainer ? <Portal mountNode={pinnedContainer}>{itemElement}</Portal> : itemElement;\r\n};\r\n\r\n/**\r\n * Renders the Pinned section container and defines the portal target for the pinned items.\r\n *\r\n * @returns `div`\r\n */\r\nconst AccordionPinnedContainer: FunctionComponent = () => {\r\n AccordionPinnedContainer.displayName = \"AccordionPinnedContainer\";\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n\r\n return (\r\n <div ref={accordionCtx?.pinnedContainerRef} className={classes.pinnedContainer}>\r\n <MessageBar className={classes.pinnedContainerEmpty}>\r\n <MessageBarBody>No pinned items</MessageBarBody>\r\n </MessageBar>\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Renders the search box for filtering items.\r\n *\r\n * @returns `SearchBox`, or `null` if the feature is disabled.\r\n */\r\nconst AccordionSearchBox: FunctionComponent = () => {\r\n AccordionSearchBox.displayName = \"AccordionSearchBox\";\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n\r\n if (!accordionCtx?.features.search) {\r\n return null;\r\n }\r\n\r\n const { state, dispatch } = accordionCtx;\r\n\r\n return (\r\n <SearchBox\r\n className={classes.searchBox}\r\n appearance=\"underline\"\r\n contentBefore={<FilterRegular />}\r\n placeholder=\"Filter\"\r\n value={state.searchTerm}\r\n onChange={(_, data) => dispatch({ type: \"SET_SEARCH_TERM\", term: data.value })}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * Props: `AccordionSection`.\r\n */\r\nexport type AccordionSectionProps = {\r\n /** The text label shown in the section header. */\r\n title: string;\r\n /** Indicates whether the `AccordionSection` is initially collapsed. */\r\n collapseByDefault?: boolean;\r\n};\r\n\r\n/**\r\n * Wrapper component that must encapsulate the section body.\r\n *\r\n * @param props - `AccordionSectionProps`\r\n * @returns `div`\r\n */\r\nexport const AccordionSection: FunctionComponent<PropsWithChildren<AccordionSectionProps>> = (props) => {\r\n AccordionSection.displayName = \"AccordionSection\";\r\n const classes = useStyles();\r\n\r\n return <div className={classes.panelDiv}>{props.children}</div>;\r\n};\r\n\r\n/**\r\n * Props: `Accordion`.\r\n */\r\nexport type AccordionProps = {\r\n /** The unique ID of the `Accordion` instance. */\r\n uniqueId?: string;\r\n /** The list of sections to be highlighted. */\r\n highlightSections?: readonly string[];\r\n /** Enables the pinned items feature. */\r\n enablePinnedItems?: boolean;\r\n /** Enables the hidden items feature. */\r\n enableHiddenItems?: boolean;\r\n /** Enables the search items feature. */\r\n enableSearchItems?: boolean;\r\n};\r\n\r\nconst StringAccordion = FluentAccordion as ForwardRefExoticComponent<FluentAccordionProps<string> & RefAttributes<HTMLDivElement>>;\r\n\r\nexport const Accordion = forwardRef<HTMLDivElement, PropsWithChildren<AccordionProps>>((props, ref) => {\r\n Accordion.displayName = \"Accordion\";\r\n const { children, highlightSections, ...rest } = props;\r\n const classes = useStyles();\r\n const { size } = useContext(ToolContext);\r\n const accordionCtx = useAccordionContext(props);\r\n const hasPinning = accordionCtx?.features.pinning ?? false;\r\n\r\n const pinnedSectionElement = useMemo(() => {\r\n return (\r\n hasPinning && (\r\n <AccordionSection title=\"Pinned\" collapseByDefault={false}>\r\n <AccordionPinnedContainer />\r\n </AccordionSection>\r\n )\r\n );\r\n }, [hasPinning]);\r\n\r\n // Prevents sections contents from unmounting when closed, allowing their elements to be used in the Pinned section.\r\n const preventUnmountMotion: AccordionPanelProps[\"collapseMotion\"] = useMemo(() => {\r\n // https://github.com/microsoft/fluentui/issues/34309#issuecomment-2824364945\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n return hasPinning ? { children: (Component, props) => <Component {...props} unmountOnExit={false} /> } : undefined;\r\n }, [hasPinning]);\r\n\r\n const validChildren = useMemo(() => {\r\n return (\r\n Children.map([pinnedSectionElement, children], (child) => {\r\n if (isValidElement(child)) {\r\n const childProps = child.props as Partial<AccordionSectionProps>;\r\n if (childProps.title) {\r\n return {\r\n title: childProps.title,\r\n collapseByDefault: childProps.collapseByDefault,\r\n content: child,\r\n };\r\n }\r\n }\r\n return null;\r\n })?.filter(Boolean) ?? []\r\n );\r\n }, [children]);\r\n\r\n // Tracks open items, and used to tell the Accordion which sections should be expanded.\r\n const [openItems, setOpenItems] = useState(validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title));\r\n\r\n // Tracks closed items, which is needed so that when the children change, we only update the open/closed state\r\n // (depending on the collapseByDefault prop) for items that have not been explicitly opened or closed.\r\n const [closedItems, setClosedItems] = useState(validChildren.filter((child) => child.collapseByDefault).map((child) => child.title));\r\n\r\n const internalOpenItemsRef = useRef<string[] | undefined>(openItems);\r\n\r\n // When highlight sections is requested, we temporarily override the open items, but if highlight sections is cleared,\r\n // then we revert back to the normal open items tracking.\r\n useLayoutEffect(() => {\r\n if (highlightSections) {\r\n internalOpenItemsRef.current = [...openItems];\r\n setOpenItems([...highlightSections]);\r\n } else {\r\n setOpenItems([...(internalOpenItemsRef.current ?? [])]);\r\n internalOpenItemsRef.current = undefined;\r\n }\r\n }, [highlightSections]);\r\n\r\n useEffect(() => {\r\n for (const defaultOpenItem of validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title)) {\r\n // If a child is not marked as collapseByDefault, then it should be opened by default, and\r\n // it is only \"default\" if it hasn't already been explicitly added to the opened or closed list.\r\n if (!closedItems.includes(defaultOpenItem) && !openItems.includes(defaultOpenItem)) {\r\n setOpenItems((prev) => [...prev, defaultOpenItem]);\r\n }\r\n }\r\n }, [validChildren]);\r\n\r\n const onToggle = useCallback((event: AccordionToggleEvent, data: AccordionToggleData<string>) => {\r\n if (data.openItems.includes(data.value)) {\r\n setOpenItems((prev) => [...prev, data.value]);\r\n setClosedItems((prev) => prev.filter((item) => item !== data.value));\r\n } else {\r\n setClosedItems((prev) => [...prev, data.value]);\r\n setOpenItems((prev) => prev.filter((item) => item !== data.value));\r\n }\r\n }, []);\r\n\r\n return (\r\n <StringAccordion ref={ref} className={classes.accordion} collapsible multiple onToggle={onToggle} openItems={openItems} {...rest}>\r\n <AccordionContext.Provider value={accordionCtx}>\r\n <AccordionMenuBar />\r\n <div className={classes.accordionBody}>\r\n {validChildren.map((child, index) => {\r\n const isHighlighted = highlightSections?.includes(child.title);\r\n return (\r\n <AccordionSectionBlock key={child.content.key ?? child.title} sectionId={child.title}>\r\n <div className={isHighlighted ? classes.highlightDiv : undefined}>\r\n <AccordionHeader size={size}>\r\n <Subtitle2Stronger>{child.title}</Subtitle2Stronger>\r\n </AccordionHeader>\r\n <AccordionPanel collapseMotion={preventUnmountMotion}>\r\n <div className={classes.panelDiv}>{child.content}</div>\r\n </AccordionPanel>\r\n </div>\r\n {index < validChildren.length - 1 && <Divider inset={true} className={size === \"small\" ? classes.dividerSmall : classes.divider} />}\r\n </AccordionSectionBlock>\r\n );\r\n })}\r\n </div>\r\n </AccordionContext.Provider>\r\n </StringAccordion>\r\n );\r\n});\r\n"]}
|
|
1
|
+
{"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/accordion.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { AccordionPanelProps, AccordionToggleData, AccordionToggleEvent, AccordionProps as FluentAccordionProps } from \"@fluentui/react-components\";\r\nimport type { ForwardRefExoticComponent, FunctionComponent, PropsWithChildren, RefAttributes } from \"react\";\r\n\r\nimport {\r\n AccordionHeader,\r\n AccordionItem,\r\n AccordionPanel,\r\n Divider,\r\n Accordion as FluentAccordion,\r\n MessageBar,\r\n MessageBarBody,\r\n Portal,\r\n SearchBox,\r\n Subtitle2Stronger,\r\n makeStyles,\r\n tokens,\r\n} from \"@fluentui/react-components\";\r\nimport { ArrowCircleUpRegular, CheckmarkFilled, EditRegular, EyeFilled, EyeOffRegular, FilterRegular, PinFilled, PinRegular } from \"@fluentui/react-icons\";\r\nimport { Children, forwardRef, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\r\n\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\nimport { useKeyState } from \"../hooks/keyboardHooks\";\r\nimport {\r\n AccordionContext,\r\n AccordionItemDepthContext,\r\n AccordionSectionBlockContext,\r\n useAccordionContext,\r\n useAccordionSectionBlockContext,\r\n useAccordionSectionItemState,\r\n} from \"./accordion.contexts\";\r\nimport { Button } from \"./button\";\r\nimport { CustomTokens } from \"./utils\";\r\n\r\nconst useStyles = makeStyles({\r\n accordion: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n height: \"100%\",\r\n },\r\n accordionBody: {\r\n overflowX: \"hidden\",\r\n overflowY: \"auto\",\r\n paddingBottom: tokens.spacingVerticalM, // bottom padding since there is no divider at the bottom\r\n },\r\n divider: {\r\n paddingTop: CustomTokens.dividerGap,\r\n paddingBottom: CustomTokens.dividerGap,\r\n },\r\n dividerSmall: {\r\n paddingTop: CustomTokens.dividerGapSmall,\r\n paddingBottom: CustomTokens.dividerGapSmall,\r\n },\r\n panelDiv: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n overflow: \"hidden\",\r\n },\r\n highlightDiv: {\r\n borderRadius: tokens.borderRadiusLarge,\r\n animationDuration: \"1s\",\r\n animationTimingFunction: \"ease-in-out\",\r\n animationIterationCount: \"5\",\r\n animationFillMode: \"forwards\",\r\n animationName: {\r\n from: {\r\n boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,\r\n },\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n \"50%\": {\r\n boxShadow: `inset 0 0 12px ${tokens.colorBrandBackground}`,\r\n },\r\n to: {\r\n boxShadow: `inset 0 0 4px ${tokens.colorTransparentBackground}`,\r\n },\r\n },\r\n },\r\n menuBar: {\r\n display: \"flex\",\r\n },\r\n menuBarControls: {\r\n display: \"flex\",\r\n flexGrow: 1,\r\n justifyContent: \"end\",\r\n },\r\n sectionItemContainer: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n alignItems: \"center\",\r\n },\r\n sectionItemContent: {\r\n flexGrow: 1,\r\n minWidth: 0, // Allow content to shrink below its intrinsic width when buttons are shown\r\n overflow: \"hidden\",\r\n },\r\n sectionItemButtons: {\r\n display: \"flex\",\r\n flexDirection: \"row\",\r\n alignItems: \"center\",\r\n marginRight: tokens.spacingHorizontalXS,\r\n },\r\n pinnedContainer: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n },\r\n pinnedContainerEmpty: {\r\n \"&:not(:only-child)\": {\r\n display: \"none\",\r\n },\r\n },\r\n searchBox: {\r\n width: \"100%\",\r\n },\r\n});\r\n\r\n/**\r\n * Renders the menu bar and control buttons.\r\n *\r\n * @returns `div`, or `undefined` if all features are disabled.\r\n */\r\nconst AccordionMenuBar: FunctionComponent = () => {\r\n AccordionMenuBar.displayName = \"AccordionMenuBar\";\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n\r\n if (!accordionCtx) {\r\n return null;\r\n }\r\n\r\n const { state, dispatch, features } = accordionCtx;\r\n const { editMode } = state;\r\n\r\n return (\r\n <div className={classes.menuBar}>\r\n <AccordionSearchBox />\r\n <div className={classes.menuBarControls}>\r\n {features.hiding && editMode && (\r\n <>\r\n <Button title=\"Show all\" icon={EyeFilled} appearance=\"subtle\" onClick={() => dispatch({ type: \"SHOW_ALL\" })} />\r\n <Button\r\n title=\"Hide all\"\r\n icon={EyeOffRegular}\r\n appearance=\"subtle\"\r\n onClick={() => {\r\n // Hide all visible (non-hidden) items using the registered item IDs\r\n const { registeredItemIds, state: currentState } = accordionCtx;\r\n const visibleItemIds = Array.from(registeredItemIds.keys()).filter((id) => !currentState.hiddenIds.includes(id));\r\n dispatch({ type: \"HIDE_ALL_VISIBLE\", visibleItemIds });\r\n }}\r\n />\r\n </>\r\n )}\r\n {(features.pinning || features.hiding) && (\r\n <Button\r\n title=\"Edit mode\"\r\n icon={editMode ? CheckmarkFilled : EditRegular}\r\n appearance={editMode ? \"primary\" : \"subtle\"}\r\n onClick={() => dispatch({ type: \"SET_EDIT_MODE\", enabled: !editMode })}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Props: `AccordionSectionBlock`.\r\n */\r\nexport type AccordionSectionBlockProps = {\r\n /** The ID of the `AccordionSectionBlock`, unique within the `Accordion` instance. */\r\n sectionId: string;\r\n};\r\n\r\n/**\r\n * Wrapper component that must encapsulate the section headers and panels.\r\n * - Stores the section ID for use in `AccordionSectionItem`.\r\n *\r\n * @param props - `AccordionSectionBlockProps`\r\n * @returns `AccordionSectionBlockContext.Provider`, or `AccordionItem` if all features are disabled.\r\n */\r\nconst AccordionSectionBlock: FunctionComponent<PropsWithChildren<AccordionSectionBlockProps>> = (props) => {\r\n AccordionSectionBlock.displayName = \"AccordionSectionBlock\";\r\n const { children, sectionId } = props;\r\n const accordionCtx = useContext(AccordionContext);\r\n const { context: sectionContext, isEmpty } = useAccordionSectionBlockContext(props);\r\n\r\n if (accordionCtx) {\r\n return (\r\n <AccordionSectionBlockContext.Provider value={sectionContext}>\r\n {!isEmpty && <AccordionItem value={sectionId}>{children}</AccordionItem>}\r\n </AccordionSectionBlockContext.Provider>\r\n );\r\n }\r\n\r\n return <AccordionItem value={sectionId}>{children}</AccordionItem>;\r\n};\r\n\r\n/**\r\n * Props: `AccordionSectionItem`.\r\n */\r\nexport type AccordionSectionItemProps = {\r\n /** The ID of the `AccordionSectionItem`, unique within the `AccordionSectionBlock` instance. */\r\n uniqueId: string;\r\n /** The searchable text label for the item. */\r\n label?: string;\r\n /** Whether the item is not interactable. */\r\n staticItem?: boolean;\r\n};\r\n\r\n/**\r\n * Wrapper component that must encapsulate individual items.\r\n * - Renders the pin button and tracks the pinned state of the item.\r\n * - Renders the hide button and tracks the hidden state of the item.\r\n * - Filters items based on the current search term.\r\n *\r\n * @param props - `AccordionSectionItemProps`\r\n * @returns `Portal` if pinned; `null` if hidden/filtered; `children` otherwise.\r\n */\r\nexport const AccordionSectionItem: FunctionComponent<PropsWithChildren<AccordionSectionItemProps>> = (props) => {\r\n AccordionSectionItem.displayName = \"AccordionSectionItem\";\r\n const { children, staticItem } = props;\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n const itemState = useAccordionSectionItemState(props);\r\n const [ctrlMode, setCtrlMode] = useState(false);\r\n const ctrlPressed = useKeyState(\"Control\");\r\n const [mouseOver, setMouseOver] = useState(false);\r\n\r\n useEffect(() => {\r\n setCtrlMode(ctrlPressed && mouseOver);\r\n }, [ctrlPressed, mouseOver]);\r\n\r\n // Override disableCopy so copy buttons appear when ctrl+hovering on this item or when edit mode is active\r\n const parentToolContext = useContext(ToolContext);\r\n const editMode = accordionCtx?.state.editMode ?? false;\r\n const showCopy = ctrlMode || editMode;\r\n const itemToolContext = useMemo(() => (showCopy ? { ...parentToolContext, disableCopy: false } : parentToolContext), [parentToolContext, showCopy]);\r\n\r\n // If static item or no context, just render children\r\n if (staticItem || !accordionCtx || !itemState) {\r\n return <>{children}</>;\r\n }\r\n\r\n const { pinnedContainerRef, features } = accordionCtx;\r\n const { isNested, isPinned, isHidden, isMatch, pinnedIndex, canMoveUp, inEditMode, actions } = itemState;\r\n\r\n // Nested items just render children (don't show controls)\r\n if (isNested) {\r\n return <>{children}</>;\r\n }\r\n\r\n // If hidden (and not in edit mode) or doesn't match search, don't render\r\n if ((isHidden && !inEditMode) || !isMatch) {\r\n return null;\r\n }\r\n\r\n const pinnedContainer = isPinned ? pinnedContainerRef.current : null;\r\n const showControls = inEditMode || ctrlMode;\r\n\r\n const itemElement = (\r\n <ToolContext.Provider value={itemToolContext}>\r\n <div\r\n className={classes.sectionItemContainer}\r\n style={isPinned ? { order: pinnedIndex } : undefined}\r\n onMouseMove={() => setMouseOver(true)}\r\n onMouseLeave={() => setMouseOver(false)}\r\n >\r\n {showControls && (\r\n <div className={classes.sectionItemButtons}>\r\n {features.hiding && (\r\n <Button title={isHidden ? \"Unhide\" : \"Hide\"} icon={isHidden ? EyeOffRegular : EyeFilled} appearance=\"transparent\" onClick={actions.toggleHidden} />\r\n )}\r\n {features.pinning && (\r\n <>\r\n <Button title={isPinned ? \"Unpin\" : \"Pin\"} icon={isPinned ? PinFilled : PinRegular} appearance=\"transparent\" onClick={actions.togglePinned} />\r\n {isPinned && <Button icon={ArrowCircleUpRegular} appearance=\"transparent\" disabled={!canMoveUp} onClick={actions.movePinnedUp} />}\r\n </>\r\n )}\r\n </div>\r\n )}\r\n <AccordionItemDepthContext.Provider value={true}>\r\n <div className={classes.sectionItemContent}>{children}</div>\r\n </AccordionItemDepthContext.Provider>\r\n </div>\r\n </ToolContext.Provider>\r\n );\r\n\r\n return pinnedContainer ? <Portal mountNode={pinnedContainer}>{itemElement}</Portal> : itemElement;\r\n};\r\n\r\n/**\r\n * Renders the Pinned section container and defines the portal target for the pinned items.\r\n *\r\n * @returns `div`\r\n */\r\nconst AccordionPinnedContainer: FunctionComponent = () => {\r\n AccordionPinnedContainer.displayName = \"AccordionPinnedContainer\";\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n\r\n return (\r\n <div ref={accordionCtx?.pinnedContainerRef} className={classes.pinnedContainer}>\r\n <MessageBar className={classes.pinnedContainerEmpty}>\r\n <MessageBarBody>No pinned items</MessageBarBody>\r\n </MessageBar>\r\n </div>\r\n );\r\n};\r\n\r\n/**\r\n * Renders the search box for filtering items.\r\n *\r\n * @returns `SearchBox`, or `null` if the feature is disabled.\r\n */\r\nconst AccordionSearchBox: FunctionComponent = () => {\r\n AccordionSearchBox.displayName = \"AccordionSearchBox\";\r\n const classes = useStyles();\r\n const accordionCtx = useContext(AccordionContext);\r\n\r\n if (!accordionCtx?.features.search) {\r\n return null;\r\n }\r\n\r\n const { state, dispatch } = accordionCtx;\r\n\r\n return (\r\n <SearchBox\r\n className={classes.searchBox}\r\n appearance=\"underline\"\r\n contentBefore={<FilterRegular />}\r\n placeholder=\"Filter\"\r\n value={state.searchTerm}\r\n onChange={(_, data) => dispatch({ type: \"SET_SEARCH_TERM\", term: data.value })}\r\n />\r\n );\r\n};\r\n\r\n/**\r\n * Props: `AccordionSection`.\r\n */\r\nexport type AccordionSectionProps = {\r\n /** The text label shown in the section header. */\r\n title: string;\r\n /** Indicates whether the `AccordionSection` is initially collapsed. */\r\n collapseByDefault?: boolean;\r\n};\r\n\r\n/**\r\n * Wrapper component that must encapsulate the section body.\r\n *\r\n * @param props - `AccordionSectionProps`\r\n * @returns `div`\r\n */\r\nexport const AccordionSection: FunctionComponent<PropsWithChildren<AccordionSectionProps>> = (props) => {\r\n AccordionSection.displayName = \"AccordionSection\";\r\n const classes = useStyles();\r\n\r\n return <div className={classes.panelDiv}>{props.children}</div>;\r\n};\r\n\r\n/**\r\n * Props: `Accordion`.\r\n */\r\nexport type AccordionProps = {\r\n /** The unique ID of the `Accordion` instance. */\r\n uniqueId?: string;\r\n /** The list of sections to be highlighted. */\r\n highlightSections?: readonly string[];\r\n /** Enables the pinned items feature. */\r\n enablePinnedItems?: boolean;\r\n /** Enables the hidden items feature. */\r\n enableHiddenItems?: boolean;\r\n /** Enables the search items feature. */\r\n enableSearchItems?: boolean;\r\n};\r\n\r\nconst StringAccordion = FluentAccordion as ForwardRefExoticComponent<FluentAccordionProps<string> & RefAttributes<HTMLDivElement>>;\r\n\r\nexport const Accordion = forwardRef<HTMLDivElement, PropsWithChildren<AccordionProps>>((props, ref) => {\r\n Accordion.displayName = \"Accordion\";\r\n const { children, highlightSections, ...rest } = props;\r\n const classes = useStyles();\r\n const { size } = useContext(ToolContext);\r\n const accordionCtx = useAccordionContext(props);\r\n const hasPinning = accordionCtx?.features.pinning ?? false;\r\n\r\n const pinnedSectionElement = useMemo(() => {\r\n return (\r\n hasPinning && (\r\n <AccordionSection title=\"Pinned\" collapseByDefault={false}>\r\n <AccordionPinnedContainer />\r\n </AccordionSection>\r\n )\r\n );\r\n }, [hasPinning]);\r\n\r\n // Prevents sections contents from unmounting when closed, allowing their elements to be used in the Pinned section.\r\n const preventUnmountMotion: AccordionPanelProps[\"collapseMotion\"] = useMemo(() => {\r\n // https://github.com/microsoft/fluentui/issues/34309#issuecomment-2824364945\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n return hasPinning ? { children: (Component, props) => <Component {...props} unmountOnExit={false} /> } : undefined;\r\n }, [hasPinning]);\r\n\r\n const validChildren = useMemo(() => {\r\n return (\r\n Children.map([pinnedSectionElement, children], (child) => {\r\n if (isValidElement(child)) {\r\n const childProps = child.props as Partial<AccordionSectionProps>;\r\n if (childProps.title) {\r\n return {\r\n title: childProps.title,\r\n collapseByDefault: childProps.collapseByDefault,\r\n content: child,\r\n };\r\n }\r\n }\r\n return null;\r\n })?.filter(Boolean) ?? []\r\n );\r\n }, [children]);\r\n\r\n // Tracks open items, and used to tell the Accordion which sections should be expanded.\r\n const [openItems, setOpenItems] = useState(validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title));\r\n\r\n // Tracks closed items, which is needed so that when the children change, we only update the open/closed state\r\n // (depending on the collapseByDefault prop) for items that have not been explicitly opened or closed.\r\n const [closedItems, setClosedItems] = useState(validChildren.filter((child) => child.collapseByDefault).map((child) => child.title));\r\n\r\n const internalOpenItemsRef = useRef<string[] | undefined>(openItems);\r\n\r\n // When highlight sections is requested, we temporarily override the open items, but if highlight sections is cleared,\r\n // then we revert back to the normal open items tracking.\r\n useLayoutEffect(() => {\r\n if (highlightSections) {\r\n internalOpenItemsRef.current = [...openItems];\r\n setOpenItems([...highlightSections]);\r\n } else {\r\n setOpenItems([...(internalOpenItemsRef.current ?? [])]);\r\n internalOpenItemsRef.current = undefined;\r\n }\r\n }, [highlightSections]);\r\n\r\n useEffect(() => {\r\n for (const defaultOpenItem of validChildren.filter((child) => !child.collapseByDefault).map((child) => child.title)) {\r\n // If a child is not marked as collapseByDefault, then it should be opened by default, and\r\n // it is only \"default\" if it hasn't already been explicitly added to the opened or closed list.\r\n if (!closedItems.includes(defaultOpenItem) && !openItems.includes(defaultOpenItem)) {\r\n setOpenItems((prev) => [...prev, defaultOpenItem]);\r\n }\r\n }\r\n }, [validChildren]);\r\n\r\n const onToggle = useCallback((event: AccordionToggleEvent, data: AccordionToggleData<string>) => {\r\n if (data.openItems.includes(data.value)) {\r\n setOpenItems((prev) => [...prev, data.value]);\r\n setClosedItems((prev) => prev.filter((item) => item !== data.value));\r\n } else {\r\n setClosedItems((prev) => [...prev, data.value]);\r\n setOpenItems((prev) => prev.filter((item) => item !== data.value));\r\n }\r\n }, []);\r\n\r\n return (\r\n <StringAccordion ref={ref} className={classes.accordion} collapsible multiple onToggle={onToggle} openItems={openItems} {...rest}>\r\n <AccordionContext.Provider value={accordionCtx}>\r\n <AccordionMenuBar />\r\n <div className={classes.accordionBody}>\r\n {validChildren.map((child, index) => {\r\n const isHighlighted = highlightSections?.includes(child.title);\r\n return (\r\n <AccordionSectionBlock key={child.content.key ?? child.title} sectionId={child.title}>\r\n <div className={isHighlighted ? classes.highlightDiv : undefined}>\r\n <AccordionHeader size={size}>\r\n <Subtitle2Stronger>{child.title}</Subtitle2Stronger>\r\n </AccordionHeader>\r\n <AccordionPanel collapseMotion={preventUnmountMotion}>\r\n <div className={classes.panelDiv}>{child.content}</div>\r\n </AccordionPanel>\r\n </div>\r\n {index < validChildren.length - 1 && <Divider inset={true} className={size === \"small\" ? classes.dividerSmall : classes.divider} />}\r\n </AccordionSectionBlock>\r\n );\r\n })}\r\n </div>\r\n </AccordionContext.Provider>\r\n </StringAccordion>\r\n );\r\n});\r\n"]}
|
|
@@ -31,7 +31,13 @@ export const SpinButton = forwardRef((props, ref) => {
|
|
|
31
31
|
const [isFocusedShiftKeyPressed, setIsFocusedShiftKeyPressed] = useState(false);
|
|
32
32
|
// step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin
|
|
33
33
|
const step = CoerceStepValue(props.step ?? 1, isUnfocusedAltKeyPressed || isFocusedAltKeyPressed, isUnfocusedShiftKeyPressed || isFocusedShiftKeyPressed);
|
|
34
|
-
const
|
|
34
|
+
const stepPrecision = Math.max(0, CalculatePrecision(step));
|
|
35
|
+
const valuePrecision = Math.max(0, CalculatePrecision(value));
|
|
36
|
+
// Display precision: controls how many decimals are shown in the formatted displayValue. Cap at 4 to avoid wild numbers
|
|
37
|
+
const displayPrecision = Math.min(4, Math.max(stepPrecision, valuePrecision));
|
|
38
|
+
// Set to large const to prevent Fluent from rounding user-entered values on commit
|
|
39
|
+
// We control display formatting ourselves via displayValue, so this only affects internal rounding. The value stored internally will still have max precision
|
|
40
|
+
const fluentPrecision = 20;
|
|
35
41
|
useEffect(() => {
|
|
36
42
|
if (props.value !== lastCommittedValue.current) {
|
|
37
43
|
lastCommittedValue.current = props.value;
|
|
@@ -59,6 +65,30 @@ export const SpinButton = forwardRef((props, ref) => {
|
|
|
59
65
|
tryCommitValue(data.value);
|
|
60
66
|
}
|
|
61
67
|
};
|
|
68
|
+
// Strip the unit suffix (e.g. "deg" or " deg") from the raw input value before evaluating expressions.
|
|
69
|
+
const stripUnit = (val) => {
|
|
70
|
+
if (!props.unit) {
|
|
71
|
+
return val;
|
|
72
|
+
}
|
|
73
|
+
const regex = new RegExp("\\s*" + props.unit + "$");
|
|
74
|
+
const match = val.match(regex);
|
|
75
|
+
if (match) {
|
|
76
|
+
return val.slice(0, -match[0].length);
|
|
77
|
+
}
|
|
78
|
+
return val;
|
|
79
|
+
};
|
|
80
|
+
// Allow arbitrary expressions, primarily for math operations (e.g. 10*60 for 10 minutes in seconds).
|
|
81
|
+
// Use Function constructor to safely evaluate the expression without allowing access to scope.
|
|
82
|
+
// If the expression is invalid, fallback to NaN which will be caught by validateValue and prevent committing.
|
|
83
|
+
const evaluateExpression = (rawValue) => {
|
|
84
|
+
const val = stripUnit(rawValue).trim();
|
|
85
|
+
try {
|
|
86
|
+
return Number(Function(`"use strict";return (${val})`)());
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return NaN;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
62
92
|
const handleKeyDown = (event) => {
|
|
63
93
|
if (event.key === "Alt") {
|
|
64
94
|
setIsFocusedAltKeyPressed(true);
|
|
@@ -66,28 +96,32 @@ export const SpinButton = forwardRef((props, ref) => {
|
|
|
66
96
|
else if (event.key === "Shift") {
|
|
67
97
|
setIsFocusedShiftKeyPressed(true);
|
|
68
98
|
}
|
|
99
|
+
// Evaluate on Enter in keyDown (before Fluent's internal commit clears the raw text
|
|
100
|
+
// and re-renders with the truncated displayValue).
|
|
101
|
+
if (event.key === "Enter") {
|
|
102
|
+
const currVal = evaluateExpression(event.target.value);
|
|
103
|
+
if (!isNaN(currVal)) {
|
|
104
|
+
setValue(currVal);
|
|
105
|
+
tryCommitValue(currVal);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
69
108
|
HandleKeyDown(event);
|
|
70
109
|
};
|
|
71
110
|
const handleKeyUp = (event) => {
|
|
72
111
|
event.stopPropagation(); // Prevent event propagation
|
|
73
|
-
if (event.key
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
return NaN;
|
|
89
|
-
}
|
|
90
|
-
})(event.target.value);
|
|
112
|
+
if (event.key === "Alt") {
|
|
113
|
+
setIsFocusedAltKeyPressed(false);
|
|
114
|
+
}
|
|
115
|
+
else if (event.key === "Shift") {
|
|
116
|
+
setIsFocusedShiftKeyPressed(false);
|
|
117
|
+
}
|
|
118
|
+
// Skip Enter — it's handled in keyDown before Fluent's internal commit
|
|
119
|
+
// clears the raw text and replaces it with the truncated displayValue.
|
|
120
|
+
if (event.key === "Enter") {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const currVal = evaluateExpression(event.target.value);
|
|
124
|
+
if (!isNaN(currVal)) {
|
|
91
125
|
setValue(currVal);
|
|
92
126
|
tryCommitValue(currVal);
|
|
93
127
|
}
|
|
@@ -98,7 +132,7 @@ export const SpinButton = forwardRef((props, ref) => {
|
|
|
98
132
|
const inputSlot = {
|
|
99
133
|
className: mergeClasses(classes.inputSlot, props.inputClassName),
|
|
100
134
|
};
|
|
101
|
-
const spinButton = (_jsx(FluentSpinButton, { ref: ref, ...props, appearance: "outline", input: inputSlot, step: step, id: id, size: size, precision:
|
|
135
|
+
const spinButton = (_jsx(FluentSpinButton, { ref: ref, ...props, appearance: "outline", input: inputSlot, step: step, id: id, size: size, precision: fluentPrecision, displayValue: `${value.toFixed(displayPrecision)}${props.unit ? " " + props.unit : ""}`, value: value, onChange: handleChange, onKeyDown: handleKeyDown, onKeyUp: handleKeyUp, onBlur: HandleOnBlur, className: mergedClassName }));
|
|
102
136
|
return props.infoLabel ? (_jsxs("div", { className: classes.container, children: [_jsx(InfoLabel, { ...props.infoLabel, htmlFor: id }), spinButton] })) : (spinButton);
|
|
103
137
|
});
|
|
104
138
|
//# sourceMappingURL=spinButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spinButton.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/spinButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import { SpinButton as FluentSpinButton, mergeClasses, useId } from \"@fluentui/react-components\";\r\nimport type { SpinButtonOnChangeData, SpinButtonChangeEvent } from \"@fluentui/react-components\";\r\nimport type { KeyboardEvent } from \"react\";\r\nimport { forwardRef, useEffect, useState, useRef, useContext } from \"react\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { InfoLabel } from \"./infoLabel\";\r\nimport { CalculatePrecision, HandleKeyDown, HandleOnBlur, useInputStyles } from \"./utils\";\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\nimport { useKeyState } from \"../hooks/keyboardHooks\";\r\n\r\nfunction CoerceStepValue(step: number, isAltKeyPressed: boolean, isShiftKeyPressed: boolean): number {\r\n // When the alt key is pressed, decrease step by a factor of 10.\r\n if (isAltKeyPressed) {\r\n return step * 0.1;\r\n }\r\n\r\n // When the shift key is pressed, increase step by a factor of 10.\r\n if (isShiftKeyPressed) {\r\n return step * 10;\r\n }\r\n\r\n return step;\r\n}\r\n\r\nexport type SpinButtonProps = PrimitiveProps<number> & {\r\n min?: number;\r\n max?: number;\r\n /** Determines how much the spinbutton increments with the arrow keys. Note this also determines the precision value (# of decimals in display value)\r\n * i.e. if step = 1, precision = 0. step = 0.0089, precision = 4. step = 300, precision = 2. step = 23.00, precision = 2. */\r\n step?: number;\r\n unit?: string;\r\n forceInt?: boolean;\r\n validator?: (value: number) => boolean;\r\n /** Optional className for the input element */\r\n inputClassName?: string;\r\n};\r\n\r\nexport const SpinButton = forwardRef<HTMLInputElement, SpinButtonProps>((props, ref) => {\r\n SpinButton.displayName = \"SpinButton\";\r\n const classes = useInputStyles();\r\n const { size } = useContext(ToolContext);\r\n\r\n const { min, max } = props;\r\n\r\n const [value, setValue] = useState(props.value);\r\n const lastCommittedValue = useRef(props.value);\r\n\r\n // When the input does not have keyboard focus\r\n const isUnfocusedAltKeyPressed = useKeyState(\"Alt\");\r\n const isUnfocusedShiftKeyPressed = useKeyState(\"Shift\");\r\n\r\n // When the input does have keyboard focus\r\n const [isFocusedAltKeyPressed, setIsFocusedAltKeyPressed] = useState(false);\r\n const [isFocusedShiftKeyPressed, setIsFocusedShiftKeyPressed] = useState(false);\r\n\r\n // step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin\r\n const step = CoerceStepValue(props.step ?? 1, isUnfocusedAltKeyPressed || isFocusedAltKeyPressed, isUnfocusedShiftKeyPressed || isFocusedShiftKeyPressed);\r\n const precision = Math.min(4, Math.max(0, CalculatePrecision(step))); // Cap precision at 4 to avoid wild numbers\r\n\r\n useEffect(() => {\r\n if (props.value !== lastCommittedValue.current) {\r\n lastCommittedValue.current = props.value;\r\n setValue(props.value); // Update local state when props.value changes\r\n }\r\n }, [props.value]);\r\n\r\n const validateValue = (numericValue: number): boolean => {\r\n const outOfBounds = (min !== undefined && numericValue < min) || (max !== undefined && numericValue > max);\r\n const failsValidator = props.validator && !props.validator(numericValue);\r\n const failsIntCheck = props.forceInt ? !Number.isInteger(numericValue) : false;\r\n const invalid = !!outOfBounds || !!failsValidator || isNaN(numericValue) || !!failsIntCheck;\r\n return !invalid;\r\n };\r\n\r\n const tryCommitValue = (currVal: number) => {\r\n // Only commit if valid and different from last committed value\r\n if (validateValue(currVal) && currVal !== lastCommittedValue.current) {\r\n lastCommittedValue.current = currVal;\r\n props.onChange(currVal);\r\n }\r\n };\r\n\r\n const handleChange = (event: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n if (data.value != null && !Number.isNaN(data.value)) {\r\n setValue(data.value);\r\n tryCommitValue(data.value);\r\n }\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\r\n if (event.key === \"Alt\") {\r\n setIsFocusedAltKeyPressed(true);\r\n } else if (event.key === \"Shift\") {\r\n setIsFocusedShiftKeyPressed(true);\r\n }\r\n\r\n HandleKeyDown(event);\r\n };\r\n\r\n const handleKeyUp = (event: KeyboardEvent<HTMLInputElement>) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n\r\n if (event.key !== \"Enter\") {\r\n if (event.key === \"Alt\") {\r\n setIsFocusedAltKeyPressed(false);\r\n } else if (event.key === \"Shift\") {\r\n setIsFocusedShiftKeyPressed(false);\r\n }\r\n\r\n // Allow arbitrary expressions, primarily for math operations (e.g. 10*60 for 10 minutes in seconds).\r\n // Use Function constructor to safely evaluate the expression without allowing access to scope.\r\n // If the expression is invalid, fallback to NaN which will be caught by validateValue and prevent committing.\r\n const currVal = ((val: string): number => {\r\n try {\r\n return Number(Function(`\"use strict\";return (${val})`)());\r\n } catch {\r\n return NaN;\r\n }\r\n })((event.target as any).value);\r\n\r\n setValue(currVal);\r\n tryCommitValue(currVal);\r\n }\r\n };\r\n\r\n const id = useId(\"spin-button\");\r\n const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : \"\", props.className);\r\n\r\n // Build input slot from inputClassName\r\n const inputSlot = {\r\n className: mergeClasses(classes.inputSlot, props.inputClassName),\r\n };\r\n\r\n const spinButton = (\r\n <FluentSpinButton\r\n ref={ref}\r\n {...props}\r\n appearance=\"outline\"\r\n input={inputSlot}\r\n step={step}\r\n id={id}\r\n size={size}\r\n precision={precision}\r\n displayValue={`${value.toFixed(precision)}${props.unit ? \" \" + props.unit : \"\"}`}\r\n value={value}\r\n onChange={handleChange}\r\n onKeyDown={handleKeyDown}\r\n onKeyUp={handleKeyUp}\r\n onBlur={HandleOnBlur}\r\n className={mergedClassName}\r\n />\r\n );\r\n\r\n return props.infoLabel ? (\r\n <div className={classes.container}>\r\n <InfoLabel {...props.infoLabel} htmlFor={id} />\r\n {spinButton}\r\n </div>\r\n ) : (\r\n spinButton\r\n );\r\n});\r\n"]}
|
|
1
|
+
{"version":3,"file":"spinButton.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/spinButton.tsx"],"names":[],"mappings":"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","sourcesContent":["import { SpinButton as FluentSpinButton, mergeClasses, useId } from \"@fluentui/react-components\";\r\nimport type { SpinButtonOnChangeData, SpinButtonChangeEvent } from \"@fluentui/react-components\";\r\nimport type { KeyboardEvent } from \"react\";\r\nimport { forwardRef, useEffect, useState, useRef, useContext } from \"react\";\r\nimport type { PrimitiveProps } from \"./primitive\";\r\nimport { InfoLabel } from \"./infoLabel\";\r\nimport { CalculatePrecision, HandleKeyDown, HandleOnBlur, useInputStyles } from \"./utils\";\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\nimport { useKeyState } from \"../hooks/keyboardHooks\";\r\n\r\nfunction CoerceStepValue(step: number, isAltKeyPressed: boolean, isShiftKeyPressed: boolean): number {\r\n // When the alt key is pressed, decrease step by a factor of 10.\r\n if (isAltKeyPressed) {\r\n return step * 0.1;\r\n }\r\n\r\n // When the shift key is pressed, increase step by a factor of 10.\r\n if (isShiftKeyPressed) {\r\n return step * 10;\r\n }\r\n\r\n return step;\r\n}\r\n\r\nexport type SpinButtonProps = PrimitiveProps<number> & {\r\n min?: number;\r\n max?: number;\r\n /** Determines how much the spinbutton increments with the arrow keys. Note this also determines the precision value (# of decimals in display value)\r\n * i.e. if step = 1, precision = 0. step = 0.0089, precision = 4. step = 300, precision = 2. step = 23.00, precision = 2. */\r\n step?: number;\r\n unit?: string;\r\n forceInt?: boolean;\r\n validator?: (value: number) => boolean;\r\n /** Optional className for the input element */\r\n inputClassName?: string;\r\n};\r\n\r\nexport const SpinButton = forwardRef<HTMLInputElement, SpinButtonProps>((props, ref) => {\r\n SpinButton.displayName = \"SpinButton\";\r\n const classes = useInputStyles();\r\n const { size } = useContext(ToolContext);\r\n\r\n const { min, max } = props;\r\n\r\n const [value, setValue] = useState(props.value);\r\n const lastCommittedValue = useRef(props.value);\r\n\r\n // When the input does not have keyboard focus\r\n const isUnfocusedAltKeyPressed = useKeyState(\"Alt\");\r\n const isUnfocusedShiftKeyPressed = useKeyState(\"Shift\");\r\n\r\n // When the input does have keyboard focus\r\n const [isFocusedAltKeyPressed, setIsFocusedAltKeyPressed] = useState(false);\r\n const [isFocusedShiftKeyPressed, setIsFocusedShiftKeyPressed] = useState(false);\r\n\r\n // step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin\r\n const step = CoerceStepValue(props.step ?? 1, isUnfocusedAltKeyPressed || isFocusedAltKeyPressed, isUnfocusedShiftKeyPressed || isFocusedShiftKeyPressed);\r\n const stepPrecision = Math.max(0, CalculatePrecision(step));\r\n const valuePrecision = Math.max(0, CalculatePrecision(value));\r\n // Display precision: controls how many decimals are shown in the formatted displayValue. Cap at 4 to avoid wild numbers\r\n const displayPrecision = Math.min(4, Math.max(stepPrecision, valuePrecision));\r\n // Set to large const to prevent Fluent from rounding user-entered values on commit\r\n // We control display formatting ourselves via displayValue, so this only affects internal rounding. The value stored internally will still have max precision\r\n const fluentPrecision = 20;\r\n\r\n useEffect(() => {\r\n if (props.value !== lastCommittedValue.current) {\r\n lastCommittedValue.current = props.value;\r\n setValue(props.value); // Update local state when props.value changes\r\n }\r\n }, [props.value]);\r\n\r\n const validateValue = (numericValue: number): boolean => {\r\n const outOfBounds = (min !== undefined && numericValue < min) || (max !== undefined && numericValue > max);\r\n const failsValidator = props.validator && !props.validator(numericValue);\r\n const failsIntCheck = props.forceInt ? !Number.isInteger(numericValue) : false;\r\n const invalid = !!outOfBounds || !!failsValidator || isNaN(numericValue) || !!failsIntCheck;\r\n return !invalid;\r\n };\r\n\r\n const tryCommitValue = (currVal: number) => {\r\n // Only commit if valid and different from last committed value\r\n if (validateValue(currVal) && currVal !== lastCommittedValue.current) {\r\n lastCommittedValue.current = currVal;\r\n props.onChange(currVal);\r\n }\r\n };\r\n\r\n const handleChange = (event: SpinButtonChangeEvent, data: SpinButtonOnChangeData) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n if (data.value != null && !Number.isNaN(data.value)) {\r\n setValue(data.value);\r\n tryCommitValue(data.value);\r\n }\r\n };\r\n\r\n // Strip the unit suffix (e.g. \"deg\" or \" deg\") from the raw input value before evaluating expressions.\r\n const stripUnit = (val: string): string => {\r\n if (!props.unit) {\r\n return val;\r\n }\r\n\r\n const regex = new RegExp(\"\\\\s*\" + props.unit + \"$\");\r\n const match = val.match(regex);\r\n\r\n if (match) {\r\n return val.slice(0, -match[0].length);\r\n }\r\n return val;\r\n };\r\n\r\n // Allow arbitrary expressions, primarily for math operations (e.g. 10*60 for 10 minutes in seconds).\r\n // Use Function constructor to safely evaluate the expression without allowing access to scope.\r\n // If the expression is invalid, fallback to NaN which will be caught by validateValue and prevent committing.\r\n const evaluateExpression = (rawValue: string): number => {\r\n const val = stripUnit(rawValue).trim();\r\n try {\r\n return Number(Function(`\"use strict\";return (${val})`)());\r\n } catch {\r\n return NaN;\r\n }\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\r\n if (event.key === \"Alt\") {\r\n setIsFocusedAltKeyPressed(true);\r\n } else if (event.key === \"Shift\") {\r\n setIsFocusedShiftKeyPressed(true);\r\n }\r\n\r\n // Evaluate on Enter in keyDown (before Fluent's internal commit clears the raw text\r\n // and re-renders with the truncated displayValue).\r\n if (event.key === \"Enter\") {\r\n const currVal = evaluateExpression((event.target as HTMLInputElement).value);\r\n if (!isNaN(currVal)) {\r\n setValue(currVal);\r\n tryCommitValue(currVal);\r\n }\r\n }\r\n\r\n HandleKeyDown(event);\r\n };\r\n\r\n const handleKeyUp = (event: KeyboardEvent<HTMLInputElement>) => {\r\n event.stopPropagation(); // Prevent event propagation\r\n\r\n if (event.key === \"Alt\") {\r\n setIsFocusedAltKeyPressed(false);\r\n } else if (event.key === \"Shift\") {\r\n setIsFocusedShiftKeyPressed(false);\r\n }\r\n\r\n // Skip Enter — it's handled in keyDown before Fluent's internal commit\r\n // clears the raw text and replaces it with the truncated displayValue.\r\n if (event.key === \"Enter\") {\r\n return;\r\n }\r\n\r\n const currVal = evaluateExpression((event.target as any).value);\r\n\r\n if (!isNaN(currVal)) {\r\n setValue(currVal);\r\n tryCommitValue(currVal);\r\n }\r\n };\r\n\r\n const id = useId(\"spin-button\");\r\n const mergedClassName = mergeClasses(classes.input, !validateValue(value) ? classes.invalid : \"\", props.className);\r\n\r\n // Build input slot from inputClassName\r\n const inputSlot = {\r\n className: mergeClasses(classes.inputSlot, props.inputClassName),\r\n };\r\n\r\n const spinButton = (\r\n <FluentSpinButton\r\n ref={ref}\r\n {...props}\r\n appearance=\"outline\"\r\n input={inputSlot}\r\n step={step}\r\n id={id}\r\n size={size}\r\n precision={fluentPrecision}\r\n displayValue={`${value.toFixed(displayPrecision)}${props.unit ? \" \" + props.unit : \"\"}`}\r\n value={value}\r\n onChange={handleChange}\r\n onKeyDown={handleKeyDown}\r\n onKeyUp={handleKeyUp}\r\n onBlur={HandleOnBlur}\r\n className={mergedClassName}\r\n />\r\n );\r\n\r\n return props.infoLabel ? (\r\n <div className={classes.container}>\r\n <InfoLabel {...props.infoLabel} htmlFor={id} />\r\n {spinButton}\r\n </div>\r\n ) : (\r\n spinButton\r\n );\r\n});\r\n"]}
|
|
@@ -9,7 +9,7 @@ export const ToastProvider = ({ children }) => {
|
|
|
9
9
|
const showToast = useCallback((message) => {
|
|
10
10
|
dispatchToast(_jsx(Toast, { children: _jsx(ToastTitle, { children: message }) }), { intent: "info", timeout: 2000 });
|
|
11
11
|
}, [dispatchToast]);
|
|
12
|
-
return (_jsxs(ToastContext.Provider, { value: { showToast }, children: [children, _jsx(FluentProvider, { applyStylesToPortals: true, targetDocument: targetDocument, children: _jsx(Toaster, { toasterId: toasterId, position: "bottom
|
|
12
|
+
return (_jsxs(ToastContext.Provider, { value: { showToast }, children: [children, _jsx(FluentProvider, { applyStylesToPortals: true, targetDocument: targetDocument, children: _jsx(Toaster, { toasterId: toasterId, position: "bottom" }) })] }));
|
|
13
13
|
};
|
|
14
14
|
/**
|
|
15
15
|
* Hook to show toast notifications.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toast.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/toast.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC9H,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAM/D,MAAM,YAAY,GAAG,aAAa,CAAmB,EAAE,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAC;AAE9E,MAAM,CAAC,MAAM,aAAa,GAAyC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAChF,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,EAAE,aAAa,EAAE,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,EAAE,cAAc,EAAE,GAAG,SAAS,EAAE,CAAC;IAEvC,MAAM,SAAS,GAAG,WAAW,CACzB,CAAC,OAAe,EAAE,EAAE;QAChB,aAAa,CACT,KAAC,KAAK,cACF,KAAC,UAAU,cAAE,OAAO,GAAc,GAC9B,EACR,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CACpC,CAAC;IACN,CAAC,EACD,CAAC,aAAa,CAAC,CAClB,CAAC;IAEF,OAAO,CACH,MAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,SAAS,EAAE,aACtC,QAAQ,EACT,KAAC,cAAc,IAAC,oBAAoB,QAAC,cAAc,EAAE,cAAc,YAC/D,KAAC,OAAO,IAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAC,
|
|
1
|
+
{"version":3,"file":"toast.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/toast.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAC9H,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAM/D,MAAM,YAAY,GAAG,aAAa,CAAmB,EAAE,SAAS,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAC;AAE9E,MAAM,CAAC,MAAM,aAAa,GAAyC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IAChF,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,EAAE,aAAa,EAAE,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,EAAE,cAAc,EAAE,GAAG,SAAS,EAAE,CAAC;IAEvC,MAAM,SAAS,GAAG,WAAW,CACzB,CAAC,OAAe,EAAE,EAAE;QAChB,aAAa,CACT,KAAC,KAAK,cACF,KAAC,UAAU,cAAE,OAAO,GAAc,GAC9B,EACR,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CACpC,CAAC;IACN,CAAC,EACD,CAAC,aAAa,CAAC,CAClB,CAAC;IAEF,OAAO,CACH,MAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,SAAS,EAAE,aACtC,QAAQ,EACT,KAAC,cAAc,IAAC,oBAAoB,QAAC,cAAc,EAAE,cAAc,YAC/D,KAAC,OAAO,IAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAC,QAAQ,GAAG,GACtC,IACG,CAC3B,CAAC;AACN,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,QAAQ;IACpB,OAAO,UAAU,CAAC,YAAY,CAAC,CAAC;AACpC,CAAC","sourcesContent":["import type { FunctionComponent, PropsWithChildren } from \"react\";\r\n\r\nimport { FluentProvider, Toast, Toaster, ToastTitle, useFluent, useId, useToastController } from \"@fluentui/react-components\";\r\nimport { createContext, useCallback, useContext } from \"react\";\r\n\r\ntype ToastContextType = {\r\n showToast: (message: string) => void;\r\n};\r\n\r\nconst ToastContext = createContext<ToastContextType>({ showToast: () => {} });\r\n\r\nexport const ToastProvider: FunctionComponent<PropsWithChildren> = ({ children }) => {\r\n const toasterId = useId(\"toaster\");\r\n const { dispatchToast } = useToastController(toasterId);\r\n const { targetDocument } = useFluent();\r\n\r\n const showToast = useCallback(\r\n (message: string) => {\r\n dispatchToast(\r\n <Toast>\r\n <ToastTitle>{message}</ToastTitle>\r\n </Toast>,\r\n { intent: \"info\", timeout: 2000 }\r\n );\r\n },\r\n [dispatchToast]\r\n );\r\n\r\n return (\r\n <ToastContext.Provider value={{ showToast }}>\r\n {children}\r\n <FluentProvider applyStylesToPortals targetDocument={targetDocument}>\r\n <Toaster toasterId={toasterId} position=\"bottom\" />\r\n </FluentProvider>\r\n </ToastContext.Provider>\r\n );\r\n};\r\n\r\n/**\r\n * Hook to show toast notifications.\r\n * @returns Object with showToast function that accepts a message string\r\n */\r\nexport function useToast() {\r\n return useContext(ToastContext);\r\n}\r\n"]}
|
|
@@ -24,12 +24,12 @@ export const ToggleButton = (props) => {
|
|
|
24
24
|
const classes = useStyles();
|
|
25
25
|
const [checked, setChecked] = useState(value);
|
|
26
26
|
const toggle = useCallback(() => {
|
|
27
|
-
setChecked((
|
|
28
|
-
const enabled = !
|
|
27
|
+
setChecked((prevChecked) => {
|
|
28
|
+
const enabled = !prevChecked;
|
|
29
29
|
onChange(enabled);
|
|
30
30
|
return enabled;
|
|
31
31
|
});
|
|
32
|
-
}, [
|
|
32
|
+
}, [onChange]);
|
|
33
33
|
useEffect(() => {
|
|
34
34
|
setChecked(props.value);
|
|
35
35
|
}, [props.value]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggleButton.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/toggleButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE5F,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGrE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,SAAS,GAAG,UAAU,CAAC;IACzB,MAAM,EAAE;QACJ,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,QAAQ;KAC3B;CACJ,CAAC,CAAC;AASH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAyC,CAAC,KAAK,EAAE,EAAE;IACxE,YAAY,CAAC,WAAW,GAAG,cAAc,CAAC;IAC1C,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAC5B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,UAAU,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"toggleButton.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/toggleButton.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE5F,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGrE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,SAAS,GAAG,UAAU,CAAC;IACzB,MAAM,EAAE;QACJ,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,QAAQ;KAC3B;CACJ,CAAC,CAAC;AASH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAyC,CAAC,KAAK,EAAE,EAAE;IACxE,YAAY,CAAC,WAAW,GAAG,cAAc,CAAC;IAC1C,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,EAAE,GAAG,KAAK,CAAC;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,SAAS,EAAE,CAAC;IAC5B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,UAAU,CAAC,CAAC,WAAW,EAAE,EAAE;YACvB,MAAM,OAAO,GAAG,CAAC,WAAW,CAAC;YAC7B,QAAQ,CAAC,OAAO,CAAC,CAAC;YAClB,OAAO,OAAO,CAAC;QACnB,CAAC,CAAC,CAAC;IACP,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,SAAS,CAAC,GAAG,EAAE;QACX,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAElB,OAAO,CACH,KAAC,OAAO,IAAC,OAAO,EAAE,KAAK,IAAI,EAAE,YACzB,KAAC,kBAAkB,IACf,SAAS,EAAE,OAAO,CAAC,MAAM,EACzB,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAC,KAAK,CAAC,WAAW,KAAG,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAC,KAAK,CAAC,aAAa,KAAG,CAAC,CAAC,CAAC,KAAC,KAAK,CAAC,WAAW,KAAG,EAC7G,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,GACjB,GACI,CACb,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { ToggleButton as FluentToggleButton, makeStyles } from \"@fluentui/react-components\";\r\nimport type { ButtonProps } from \"./button\";\r\nimport { useCallback, useContext, useEffect, useState } from \"react\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport type { FluentIcon } from \"@fluentui/react-icons\";\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\nimport { Tooltip } from \"./tooltip\";\r\n\r\nconst useStyles = makeStyles({\r\n button: {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n },\r\n});\r\n\r\ntype ToggleButtonProps = Omit<ButtonProps, \"icon\" | \"onClick\"> & {\r\n value: boolean;\r\n checkedIcon: FluentIcon;\r\n uncheckedIcon?: FluentIcon;\r\n onChange: (checked: boolean) => void;\r\n};\r\n\r\n/**\r\n * Toggles between two states using a button with icons.\r\n * If no disabledIcon is provided, the button will toggle between visual enabled/disabled states without an icon change\r\n *\r\n * @param props\r\n * @returns\r\n */\r\nexport const ToggleButton: FunctionComponent<ToggleButtonProps> = (props) => {\r\n ToggleButton.displayName = \"ToggleButton\";\r\n const { value, onChange, title, appearance = \"subtle\" } = props;\r\n const { size } = useContext(ToolContext);\r\n const classes = useStyles();\r\n const [checked, setChecked] = useState(value);\r\n const toggle = useCallback(() => {\r\n setChecked((prevChecked) => {\r\n const enabled = !prevChecked;\r\n onChange(enabled);\r\n return enabled;\r\n });\r\n }, [onChange]);\r\n\r\n useEffect(() => {\r\n setChecked(props.value);\r\n }, [props.value]);\r\n\r\n return (\r\n <Tooltip content={title ?? \"\"}>\r\n <FluentToggleButton\r\n className={classes.button}\r\n size={size}\r\n icon={checked ? <props.checkedIcon /> : props.uncheckedIcon ? <props.uncheckedIcon /> : <props.checkedIcon />}\r\n appearance={appearance}\r\n checked={checked}\r\n onClick={toggle}\r\n />\r\n </Tooltip>\r\n );\r\n};\r\n"]}
|
|
@@ -28,7 +28,6 @@ export declare class GraphFrame {
|
|
|
28
28
|
private _headerTextElement;
|
|
29
29
|
private _headerCollapseElement;
|
|
30
30
|
private _headerCloseElement;
|
|
31
|
-
private _headerFocusElement;
|
|
32
31
|
private _commentsElement;
|
|
33
32
|
private _portContainer;
|
|
34
33
|
private _outputPortContainer;
|
|
@@ -58,7 +57,6 @@ export declare class GraphFrame {
|
|
|
58
57
|
private readonly _closeSVG;
|
|
59
58
|
private readonly _expandSVG;
|
|
60
59
|
private readonly _collapseSVG;
|
|
61
|
-
private readonly _focusSVG;
|
|
62
60
|
get id(): number;
|
|
63
61
|
get isCollapsed(): boolean;
|
|
64
62
|
private _createInputPort;
|
|
@@ -271,6 +271,10 @@ export class GraphFrame {
|
|
|
271
271
|
this._ownerCanvas._frameIsMoving = true;
|
|
272
272
|
// Need to delegate the outside ports to the frame
|
|
273
273
|
if (value) {
|
|
274
|
+
// Exit focus mode when collapsing
|
|
275
|
+
if (this._isFocused) {
|
|
276
|
+
this.switchFocusMode();
|
|
277
|
+
}
|
|
274
278
|
this.element.classList.add(styles.collapsed);
|
|
275
279
|
this.element.classList.remove(styles.expanded);
|
|
276
280
|
this._headerElement.classList.add(styles.collapsedHeader);
|
|
@@ -308,7 +312,7 @@ export class GraphFrame {
|
|
|
308
312
|
// UI
|
|
309
313
|
if (this._isCollapsed) {
|
|
310
314
|
this._headerCollapseElement.innerHTML = this._expandSVG;
|
|
311
|
-
this._headerCollapseElement.title = "Expand";
|
|
315
|
+
this._headerCollapseElement.title = "Expand (Shift+click for focus mode)";
|
|
312
316
|
}
|
|
313
317
|
else {
|
|
314
318
|
this._headerCollapseElement.innerHTML = this._collapseSVG;
|
|
@@ -428,7 +432,6 @@ export class GraphFrame {
|
|
|
428
432
|
this._closeSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M16,15l5.85,5.84-1,1L15,15.93,9.15,21.78l-1-1L14,15,8.19,9.12l1-1L15,14l5.84-5.84,1,1Z"/></g></svg>`;
|
|
429
433
|
this._expandSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-6.75,6.75H11.06V14.44h3.38V11.06h1.12v3.38h3.38v1.12H15.56v3.38H14.44Z"/></g></svg>`;
|
|
430
434
|
this._collapseSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-2.25,6.75H11.06V14.44h7.88Z"/></g></svg>`;
|
|
431
|
-
this._focusSVG = `<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6.24992 4.5C5.28344 4.5 4.49996 5.2835 4.49996 6.25V17.75C4.49996 18.7165 5.28344 19.5 6.24992 19.5H17.7496C18.7161 19.5 19.4996 18.7165 19.4996 17.75V13.75C19.4996 13.3358 19.8354 13 20.2496 13C20.6638 13 20.9995 13.3358 20.9995 13.75V17.75C20.9995 19.5449 19.5445 21 17.7496 21H6.24992C4.45504 21 3 19.5449 3 17.75V6.25C3 4.45507 4.45504 3 6.24992 3H10.2498C10.664 3 10.9998 3.33579 10.9998 3.75C10.9998 4.16421 10.664 4.5 10.2498 4.5H6.24992ZM12.9997 3.75C12.9997 3.33579 13.3355 3 13.7497 3H20.25C20.6642 3 21 3.33579 21 3.75V10.25C21 10.6642 20.6642 11 20.25 11C19.8358 11 19.5 10.6642 19.5 10.25V5.56074L14.28 10.7804C13.9871 11.0732 13.5123 11.0732 13.2194 10.7803C12.9265 10.4874 12.9265 10.0125 13.2194 9.71964L18.4395 4.5H13.7497C13.3355 4.5 12.9997 4.16421 12.9997 3.75Z" /></svg>`;
|
|
432
435
|
this._isFocused = false;
|
|
433
436
|
this._initResizing = (evt) => {
|
|
434
437
|
evt.stopPropagation();
|
|
@@ -870,21 +873,6 @@ export class GraphFrame {
|
|
|
870
873
|
this._headerTextElement = root.ownerDocument.createElement("div");
|
|
871
874
|
this._headerTextElement.classList.add(styles["frame-box-header-title"]);
|
|
872
875
|
this._headerElement.appendChild(this._headerTextElement);
|
|
873
|
-
// Focus
|
|
874
|
-
this._headerFocusElement = root.ownerDocument.createElement("div");
|
|
875
|
-
this._headerFocusElement.classList.add(styles["frame-box-header-focus"]);
|
|
876
|
-
this._headerFocusElement.classList.add(styles["frame-box-header-button"]);
|
|
877
|
-
this._headerFocusElement.title = "Switch focus mode";
|
|
878
|
-
this._headerFocusElement.ondragstart = () => false;
|
|
879
|
-
this._headerFocusElement.addEventListener("pointerdown", (evt) => {
|
|
880
|
-
evt.stopPropagation();
|
|
881
|
-
});
|
|
882
|
-
this._headerFocusElement.addEventListener("pointerup", (evt) => {
|
|
883
|
-
evt.stopPropagation();
|
|
884
|
-
this.switchFocusMode();
|
|
885
|
-
});
|
|
886
|
-
this._headerFocusElement.innerHTML = this._focusSVG;
|
|
887
|
-
this._headerElement.appendChild(this._headerFocusElement);
|
|
888
876
|
// Collapse
|
|
889
877
|
this._headerCollapseElement = root.ownerDocument.createElement("div");
|
|
890
878
|
this._headerCollapseElement.classList.add(styles["frame-box-header-collapse"]);
|
|
@@ -898,7 +886,16 @@ export class GraphFrame {
|
|
|
898
886
|
this._headerCollapseElement.addEventListener("pointerup", (evt) => {
|
|
899
887
|
evt.stopPropagation();
|
|
900
888
|
this._headerCollapseElement.classList.remove("down");
|
|
901
|
-
|
|
889
|
+
if (evt.shiftKey) {
|
|
890
|
+
// Shift+click toggles focus mode without changing collapse state
|
|
891
|
+
if (this._isCollapsed) {
|
|
892
|
+
this.isCollapsed = false;
|
|
893
|
+
}
|
|
894
|
+
this.switchFocusMode();
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
this.isCollapsed = !this.isCollapsed;
|
|
898
|
+
}
|
|
902
899
|
});
|
|
903
900
|
this._headerCollapseElement.innerHTML = this._collapseSVG;
|
|
904
901
|
this._headerElement.appendChild(this._headerCollapseElement);
|