Skip to content

Commit 7a65def

Browse files
georginahalpernGeorgina
andauthored
[Fluent] Add buttonLine, switchPropertyLine; Introduce noCopy mode for tools (#16766)
Introduce switchPropertyLine / buttonLine ![image](https://github.com/user-attachments/assets/f5bce604-6d41-4b93-a96b-91fbceb16d3a) ![image](https://github.com/user-attachments/assets/d8b050ef-fcea-4224-9a99-ea766236d6f8) Also introduced a 'noCopy' mode tools can use to hide copy button for properties (was done using CSS before) Co-authored-by: Georgina <[email protected]>
1 parent 81eea9d commit 7a65def

File tree

7 files changed

+93
-10
lines changed

7 files changed

+93
-10
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Body1, Button, makeStyles, tokens } from "@fluentui/react-components";
2+
import type { ButtonProps as FluentButtonProps } from "@fluentui/react-components";
3+
import { LineContainer } from "./propertyLine";
4+
import type { FunctionComponent } from "react";
5+
6+
const useButtonLineStyles = makeStyles({
7+
button: {
8+
border: `1px solid ${tokens.colorBrandBackground}`,
9+
},
10+
});
11+
12+
type ButtonLineProps = FluentButtonProps & {
13+
label: string;
14+
};
15+
16+
/**
17+
* Wraps a button with a label in a line container
18+
* @param props Button props plus a label
19+
* @returns A button inside a line
20+
*/
21+
export const ButtonLine: FunctionComponent<ButtonLineProps> = (props) => {
22+
const classes = useButtonLineStyles();
23+
return (
24+
<LineContainer>
25+
<Button className={classes.button} {...props}>
26+
<Body1>{props.label}</Body1>
27+
</Button>
28+
</LineContainer>
29+
);
30+
};

packages/dev/sharedUiComponents/src/fluent/hoc/fluentToolWrapper.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ export type ToolHostProps = {
88
* Allows host to pass in a theme
99
*/
1010
customTheme?: Theme;
11+
12+
/**
13+
* Can be set to true to disable the copy button in the tool's property lines. Default is false (copy enabled)
14+
*/
15+
disableCopy?: boolean;
1116
};
1217

13-
export const ToolContext = createContext({ useFluent: false as boolean } as const);
18+
export const ToolContext = createContext({ useFluent: false as boolean, disableCopy: false as boolean } as const);
1419

1520
/**
1621
* For tools which are ready to move over the fluent, wrap the root of the tool (or the panel which you want fluentized) with this component
@@ -24,7 +29,7 @@ export const FluentToolWrapper: FunctionComponent<PropsWithChildren<ToolHostProp
2429

2530
return enableFluent ? (
2631
<FluentProvider theme={props.customTheme || webDarkTheme}>
27-
<ToolContext.Provider value={{ useFluent: true }}>{props.children}</ToolContext.Provider>
32+
<ToolContext.Provider value={{ useFluent: true, disableCopy: !!props.disableCopy }}>{props.children}</ToolContext.Provider>
2833
</FluentProvider>
2934
) : (
3035
props.children

packages/dev/sharedUiComponents/src/fluent/hoc/propertyLine.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Body1Strong, Button, InfoLabel, makeStyles, tokens } from "@fluentui/react-components";
22
import { Add24Filled, Copy24Regular, Subtract24Filled } from "@fluentui/react-icons";
33
import type { FunctionComponent, PropsWithChildren } from "react";
4-
import { useState } from "react";
4+
import { useContext, useState } from "react";
55
import { copyCommandToClipboard } from "../../copyCommandToClipboard";
6+
import { ToolContext } from "./fluentToolWrapper";
67

78
const usePropertyLineStyles = makeStyles({
89
container: {
@@ -62,6 +63,11 @@ export type PropertyLineProps = {
6263
expandedContent?: JSX.Element;
6364
};
6465

66+
export const LineContainer: FunctionComponent<PropsWithChildren> = (props) => {
67+
const classes = usePropertyLineStyles();
68+
return <div className={classes.container}>{props.children}</div>;
69+
};
70+
6571
/**
6672
* A reusable component that renders a property line with a label and child content, and an optional description, copy button, and expandable section.
6773
*
@@ -75,8 +81,10 @@ export const PropertyLine: FunctionComponent<PropsWithChildren<PropertyLineProps
7581

7682
const { label, description, onCopy, expandedContent, children } = props;
7783

84+
const { disableCopy } = useContext(ToolContext);
85+
7886
return (
79-
<div className={classes.container}>
87+
<LineContainer>
8088
<div className={classes.line}>
8189
<InfoLabel className={classes.label} info={description}>
8290
<Body1Strong>{label}</Body1Strong>
@@ -96,13 +104,12 @@ export const PropertyLine: FunctionComponent<PropsWithChildren<PropertyLineProps
96104
/>
97105
)}
98106

99-
{onCopy && (
107+
{onCopy && !disableCopy && (
100108
<Button className={classes.button} id="copyProperty" icon={<Copy24Regular />} onClick={() => copyCommandToClipboard(onCopy())} title="Copy to clipboard" />
101109
)}
102110
</div>
103111
</div>
104-
105112
{expanded && expandedContent && <div className={classes.expandedContent}>{expandedContent}</div>}
106-
</div>
113+
</LineContainer>
107114
);
108115
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { SwitchProps } from "@fluentui/react-components";
2+
import { PropertyLine } from "./propertyLine";
3+
import type { PropertyLineProps } from "./propertyLine";
4+
import type { FunctionComponent } from "react";
5+
import { Switch } from "../primitives/switch";
6+
7+
/**
8+
* Wraps a switch in a property line
9+
* @param props - The properties for the switch and property line
10+
* @returns A React element representing the property line with a switch
11+
*/
12+
export const SwitchPropertyLine: FunctionComponent<PropertyLineProps & SwitchProps> = (props) => {
13+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
14+
const { label, ...switchProps } = props;
15+
// Ensure the label gets passed to the PropertyLine component and not to the underlying switch
16+
return (
17+
<PropertyLine {...props}>
18+
<Switch {...switchProps} />
19+
</PropertyLine>
20+
);
21+
};

packages/dev/sharedUiComponents/src/lines/buttonLineComponent.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import * as React from "react";
2+
import { ButtonLine } from "../fluent/hoc/buttonLine";
3+
import { ToolContext } from "../fluent/hoc/fluentToolWrapper";
24

35
export interface IButtonLineComponentProps {
46
label: string;
@@ -13,12 +15,19 @@ export class ButtonLineComponent extends React.Component<IButtonLineComponentPro
1315
super(props);
1416
}
1517

16-
override render() {
18+
renderFluent() {
19+
return <ButtonLine label={this.props.label} icon={this.props.icon} title={this.props.label} onClick={this.props.onClick} disabled={this.props.isDisabled} />;
20+
}
21+
renderOriginal() {
1722
return (
1823
<div className={"buttonLine" + (this.props.isDisabled ? " disabled" : "")}>
1924
{this.props.icon && <img src={this.props.icon} title={this.props.iconLabel} alt={this.props.iconLabel} className="icon" />}
2025
<button onClick={() => this.props.onClick()}>{this.props.label}</button>
2126
</div>
2227
);
2328
}
29+
30+
override render() {
31+
return <ToolContext.Consumer>{({ useFluent }) => (useFluent ? this.renderFluent() : this.renderOriginal())}</ToolContext.Consumer>;
32+
}
2433
}

packages/dev/sharedUiComponents/src/lines/checkBoxLineComponent.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import type { IconDefinition } from "@fortawesome/fontawesome-common-types";
66
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
77
import { conflictingValuesPlaceholder } from "./targetsProxy";
88
import copyIcon from "../imgs/copy.svg";
9+
import { ToolContext } from "../fluent/hoc/fluentToolWrapper";
10+
import { SwitchPropertyLine } from "../fluent/hoc/switchPropertyLine";
911

1012
export interface ICheckBoxLineComponentProps {
1113
label?: string;
@@ -129,7 +131,7 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
129131
}
130132
}
131133

132-
override render() {
134+
renderOriginal() {
133135
const icons = this.props.large ? Icons.size40 : Icons.size30;
134136
const icon = this.state.isConflict ? icons.mixed : this.state.isSelected ? icons.on : icons.off;
135137
return (
@@ -167,4 +169,13 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
167169
</div>
168170
);
169171
}
172+
173+
renderFluent() {
174+
// This same component renders a readonly 'check' icon, and an editable switch -- will introduce the icon in next PR as it will be a diff component
175+
return <SwitchPropertyLine label={this.props.label || ""} checked={this.state.isSelected} onChange={() => this.onChange()} disabled={!!this.props.disabled} />;
176+
}
177+
178+
override render() {
179+
return <ToolContext.Consumer>{({ useFluent }) => (useFluent ? this.renderFluent() : this.renderOriginal())}</ToolContext.Consumer>;
180+
}
170181
}

packages/tools/nodeEditor/src/graphEditor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ export class GraphEditor extends React.Component<IGraphEditorProps, IGraphEditor
633633
override render() {
634634
return (
635635
<Portal globalState={this.props.globalState}>
636-
<FluentToolWrapper>
636+
<FluentToolWrapper disableCopy={true}>
637637
<SplitContainer
638638
id="node-editor-graph-root"
639639
direction={SplitDirection.Horizontal}

0 commit comments

Comments
 (0)