Skip to content

Commit a54c2f5

Browse files
georginahalpernGeorgina
andauthored
[Fluent] Fix switch, add propertylines for text/link, add checkbox (#16769)
Separate components for text vs link, rather than today's joint textlinecomponent Added checkbox component Fix switch so that it responds to external changes Co-authored-by: Georgina <[email protected]>
1 parent efcf01f commit a54c2f5

File tree

7 files changed

+136
-18
lines changed

7 files changed

+136
-18
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Body1 } from "@fluentui/react-components";
2+
import { PropertyLine } from "./propertyLine";
3+
import { Link } from "../primitives/link";
4+
import type { PropertyLineProps } from "./propertyLine";
5+
import type { FunctionComponent } from "react";
6+
7+
type LinkProps = {
8+
value: string;
9+
tooltip?: string;
10+
onLink?: () => void;
11+
url?: string;
12+
};
13+
14+
/**
15+
* Wraps a link in a property line
16+
* @param props - PropertyLineProps and LinkProps
17+
* @returns property-line wrapped link
18+
*/
19+
export const LinkPropertyLine: FunctionComponent<PropertyLineProps & LinkProps> = (props) => {
20+
return (
21+
<PropertyLine {...props}>
22+
<Link inline appearance="subtle" onClick={() => props.onLink?.()} href={props.url} title={props.tooltip}>
23+
<Body1>{props.value}</Body1>
24+
</Link>
25+
</PropertyLine>
26+
);
27+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Body1 } from "@fluentui/react-components";
2+
import { PropertyLine } from "./propertyLine";
3+
import type { PropertyLineProps } from "./propertyLine";
4+
import type { FunctionComponent } from "react";
5+
6+
type TextProps = {
7+
value: string;
8+
tooltip?: string;
9+
};
10+
11+
/**
12+
* Wraps text in a property line
13+
* @param props - PropertyLineProps and TextProps
14+
* @returns property-line wrapped text
15+
*/
16+
export const TextPropertyLine: FunctionComponent<PropertyLineProps & TextProps> = (props) => {
17+
return (
18+
<PropertyLine {...props}>
19+
<Body1 title={props.tooltip}>{props.value}</Body1>
20+
</PropertyLine>
21+
);
22+
};

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ const VectorSliders: FunctionComponent<VectorSliderProps> = (props) => {
2020
const { vector, ...sliderProps } = props;
2121
return (
2222
<>
23-
<SyncedSliderLine label="X" propertyKey="x" target={vector} {...sliderProps} />
24-
<SyncedSliderLine label="Y" propertyKey="y" target={vector} {...sliderProps} />
25-
<SyncedSliderLine label="Z" propertyKey="z" target={vector} {...sliderProps} />
26-
{vector instanceof Vector4 && <SyncedSliderLine label="W" propertyKey="w" target={vector} {...sliderProps} />}
23+
<SyncedSliderLine {...sliderProps} label="X" propertyKey="x" target={vector} />
24+
<SyncedSliderLine {...sliderProps} label="Y" propertyKey="y" target={vector} />
25+
<SyncedSliderLine {...sliderProps} label="Z" propertyKey="z" target={vector} />
26+
{vector instanceof Vector4 && <SyncedSliderLine {...sliderProps} label="W" propertyKey="w" target={vector} />}
2727
</>
2828
);
2929
};
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// eslint-disable-next-line import/no-internal-modules
2+
3+
import type { CheckboxProps, CheckboxOnChangeData } from "@fluentui/react-components";
4+
import type { ChangeEvent, FunctionComponent } from "react";
5+
6+
import { Checkbox as FluentCheckbox } from "@fluentui/react-components";
7+
import { useEffect, useState } from "react";
8+
9+
/**
10+
* This is a primitive fluent checkbox that can both read and write checked state
11+
* @param props
12+
* @returns Checkbox component
13+
*/
14+
export const Checkbox: FunctionComponent<CheckboxProps> = (props) => {
15+
const [checked, setChecked] = useState(() => props.checked ?? false);
16+
17+
useEffect(() => {
18+
if (props.checked != undefined) {
19+
setChecked(props.checked); // Update local state when props.checked changes
20+
}
21+
}, [props.checked]);
22+
23+
const onChange = (ev: ChangeEvent<HTMLInputElement>, data: CheckboxOnChangeData) => {
24+
props.onChange && props.onChange(ev, data);
25+
setChecked(ev.target.checked);
26+
};
27+
28+
return <FluentCheckbox {...props} checked={checked} onChange={onChange} />;
29+
};

packages/dev/sharedUiComponents/src/fluent/primitives/switch.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { SwitchOnChangeData, SwitchProps as FluentSwitchProps } from "@flue
44
import type { ChangeEvent, FunctionComponent } from "react";
55

66
import { makeStyles, Switch as FluentSwitch } from "@fluentui/react-components";
7-
import { useState } from "react";
7+
import { useEffect, useState } from "react";
88

99
const useSwitchStyles = makeStyles({
1010
switch: {
@@ -24,6 +24,12 @@ export const Switch: FunctionComponent<FluentSwitchProps> = (props) => {
2424
const classes = useSwitchStyles();
2525
const [checked, setChecked] = useState(() => props.checked ?? false);
2626

27+
useEffect(() => {
28+
if (props.checked != undefined) {
29+
setChecked(props.checked); // Update local state when props.checked changes
30+
}
31+
}, [props.checked]);
32+
2733
const onChange = (event: ChangeEvent<HTMLInputElement>, data: SwitchOnChangeData) => {
2834
props.onChange && props.onChange(event, data);
2935
setChecked(event.target.checked);

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { conflictingValuesPlaceholder } from "./targetsProxy";
88
import copyIcon from "../imgs/copy.svg";
99
import { ToolContext } from "../fluent/hoc/fluentToolWrapper";
1010
import { SwitchPropertyLine } from "../fluent/hoc/switchPropertyLine";
11+
import { Checkbox } from "../fluent/primitives/checkbox";
1112

1213
export interface ICheckBoxLineComponentProps {
1314
label?: string;
@@ -171,7 +172,10 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
171172
}
172173

173174
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+
// if faIcons are sent (to mimic a checkbox) use fluent checkbox
176+
if (this.props.faIcons) {
177+
return <Checkbox disabled={this.props.disabled} checked={this.state.isSelected} onClick={() => !this.props.disabled && this.onChange()} />;
178+
}
175179
return <SwitchPropertyLine label={this.props.label || ""} checked={this.state.isSelected} onChange={() => this.onChange()} disabled={!!this.props.disabled} />;
176180
}
177181

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

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import * as React from "react";
22
import copyIcon from "../imgs/copy.svg";
33
import { copyCommandToClipboard } from "../copyCommandToClipboard";
44
import { MergeClassNames } from "../styleHelper";
5+
import { TextPropertyLine } from "../fluent/hoc/textPropertyLine";
6+
import { LinkPropertyLine } from "../fluent/hoc/linkPropertyLine";
7+
import { ToolContext } from "shared-ui-components/fluent/hoc/fluentToolWrapper";
58

69
interface ITextLineComponentProps {
710
label?: string;
@@ -35,43 +38,51 @@ export class TextLineComponent extends React.Component<ITextLineComponentProps>
3538
this.props.onLink();
3639
}
3740

38-
renderContent() {
41+
copyFn() {
42+
const onCopy = this.props.onCopy;
43+
const val = this.props.value;
44+
if (onCopy === true && val !== undefined) {
45+
return () => val;
46+
} else if (typeof onCopy === "function") {
47+
return onCopy;
48+
}
49+
return undefined;
50+
}
51+
52+
renderContent(isLink: boolean, tooltip: string) {
3953
if (this.props.ignoreValue) {
4054
return null;
4155
}
42-
const title = this.props.tooltip ?? this.props.value ?? this.props.label ?? "";
4356

44-
if (this.props.onLink || this.props.url) {
57+
if (isLink) {
4558
return (
46-
<div className="link-value" title={title} onClick={() => this.onLink()}>
59+
<div className="link-value" title={tooltip} onClick={() => this.onLink()}>
4760
{this.props.url ? "doc" : this.props.value || "no name"}
4861
</div>
4962
);
5063
}
5164
return (
52-
<div className="value" title={title} style={{ color: this.props.color ? this.props.color : "" }}>
65+
<div className="value" title={tooltip} style={{ color: this.props.color ? this.props.color : "" }}>
5366
{this.props.value || "no name"}
5467
</div>
5568
);
5669
}
5770

58-
override render() {
71+
renderOriginal(isLink: boolean, tooltip: string) {
5972
return (
6073
<div className={MergeClassNames(["textLine", ["underline", this.props.underline], this.props.additionalClass, ["icon", this.props.onCopy]])}>
6174
{this.props.icon && <img src={this.props.icon} title={this.props.iconLabel} alt={this.props.iconLabel} className="icon" />}
6275
<div className="label" title={this.props.tooltip ?? this.props.label ?? ""}>
6376
{this.props.label ?? ""}
6477
</div>
65-
{this.renderContent()}
78+
{this.renderContent(isLink, tooltip)}
6679
{this.props.onCopy && (
6780
<div
6881
className="copy hoverIcon"
6982
onClick={() => {
70-
const onCopy = this.props.onCopy;
71-
if (onCopy === true && this.props.value !== undefined) {
72-
copyCommandToClipboard(this.props.value);
73-
} else if (typeof onCopy === "function") {
74-
copyCommandToClipboard(onCopy());
83+
const copyFn = this.copyFn();
84+
if (copyFn) {
85+
copyCommandToClipboard(copyFn());
7586
}
7687
}}
7788
title="Copy to clipboard"
@@ -82,4 +93,23 @@ export class TextLineComponent extends React.Component<ITextLineComponentProps>
8293
</div>
8394
);
8495
}
96+
97+
renderFluent(isLink: boolean, tooltip: string) {
98+
const sharedProps = {
99+
tooltip,
100+
label: this.props.label || "",
101+
onCopy: this.copyFn(),
102+
};
103+
if (isLink) {
104+
return <LinkPropertyLine {...sharedProps} value={this.props.url ? "doc" : this.props.value || "no name"} url={this.props.url} onLink={this.props.onLink} />;
105+
} else {
106+
return <TextPropertyLine {...sharedProps} value={this.props.value || ""} />;
107+
}
108+
}
109+
110+
override render() {
111+
const tooltip = this.props.tooltip ?? this.props.value ?? this.props.label ?? "";
112+
const isLink = this.props.onLink !== undefined || this.props.url !== undefined;
113+
return <ToolContext.Consumer>{({ useFluent }) => (useFluent ? this.renderFluent(isLink, tooltip) : this.renderOriginal(isLink, tooltip))}</ToolContext.Consumer>;
114+
}
85115
}

0 commit comments

Comments
 (0)