@babylonjs/shared-ui-components 8.49.6 → 8.49.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/buttonLine.d.ts +1 -0
- package/fluent/hoc/buttonLine.js +1 -1
- package/fluent/hoc/buttonLine.js.map +1 -1
- package/fluent/hoc/fileUploadLine.js +1 -1
- package/fluent/hoc/fileUploadLine.js.map +1 -1
- package/fluent/hoc/propertyLines/propertyLine.d.ts +9 -1
- package/fluent/hoc/propertyLines/propertyLine.js +5 -3
- package/fluent/hoc/propertyLines/propertyLine.js.map +1 -1
- package/fluent/primitives/accordion.contexts.d.ts +136 -0
- package/fluent/primitives/accordion.contexts.js +253 -0
- package/fluent/primitives/accordion.contexts.js.map +1 -0
- package/fluent/primitives/accordion.d.ts +51 -0
- package/fluent/primitives/accordion.js +176 -11
- package/fluent/primitives/accordion.js.map +1 -1
- package/fluent/primitives/collapse.js +3 -1
- package/fluent/primitives/collapse.js.map +1 -1
- package/fluent/primitives/infoLabel.js +1 -1
- package/fluent/primitives/infoLabel.js.map +1 -1
- package/fluent/primitives/messageBar.d.ts +1 -0
- package/fluent/primitives/messageBar.js +3 -2
- package/fluent/primitives/messageBar.js.map +1 -1
- package/fluent/primitives/utils.d.ts +1 -1
- package/package.json +1 -1
package/fluent/hoc/buttonLine.js
CHANGED
|
@@ -8,6 +8,6 @@ import { Button } from "../primitives/button.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export const ButtonLine = (props) => {
|
|
10
10
|
ButtonLine.displayName = "ButtonLine";
|
|
11
|
-
return (_jsx(LineContainer, { children: _jsx(Button, { ...props }) }));
|
|
11
|
+
return (_jsx(LineContainer, { uniqueId: props.uniqueId ?? props.label, children: _jsx(Button, { ...props }) }));
|
|
12
12
|
};
|
|
13
13
|
//# sourceMappingURL=buttonLine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buttonLine.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/hoc/buttonLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"buttonLine.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/hoc/buttonLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAQ9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAuC,CAAC,KAAK,EAAE,EAAE;IACpE,UAAU,CAAC,WAAW,GAAG,YAAY,CAAC;IAEtC,OAAO,CACH,KAAC,aAAa,IAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,YAClD,KAAC,MAAM,OAAK,KAAK,GAAI,GACT,CACnB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { LineContainer } from \"./propertyLines/propertyLine\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport { Button } from \"../primitives/button\";\r\nimport type { ButtonProps } from \"../primitives/button\";\r\n\r\ntype ButtonLineProps = Omit<ButtonProps, \"label\"> & {\r\n label: string; // Require a label when button is the entire line (by default, label is optional on a button)\r\n uniqueId?: string; // The ID of the property line to be used when the label cannot be used as a persistent ID.\r\n};\r\n\r\n/**\r\n * Wraps a button with a label in a line container\r\n * @param props Button props plus a label\r\n * @returns A button inside a line\r\n */\r\nexport const ButtonLine: FunctionComponent<ButtonLineProps> = (props) => {\r\n ButtonLine.displayName = \"ButtonLine\";\r\n\r\n return (\r\n <LineContainer uniqueId={props.uniqueId ?? props.label}>\r\n <Button {...props} />\r\n </LineContainer>\r\n );\r\n};\r\n"]}
|
|
@@ -8,6 +8,6 @@ import { UploadButton } from "../primitives/uploadButton.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export const FileUploadLine = ({ onClick, label, accept, ...buttonProps }) => {
|
|
10
10
|
FileUploadLine.displayName = "FileUploadLine";
|
|
11
|
-
return (_jsx(LineContainer, { children: _jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
|
|
11
|
+
return (_jsx(LineContainer, { uniqueId: label, children: _jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
|
|
12
12
|
};
|
|
13
13
|
//# sourceMappingURL=fileUploadLine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileUploadLine.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/hoc/fileUploadLine.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAS1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAA2C,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,EAAE,EAAE;IACjH,cAAc,CAAC,WAAW,GAAG,gBAAgB,CAAC;IAE9C,OAAO,CACH,KAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"fileUploadLine.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/hoc/fileUploadLine.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAS1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAA2C,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,WAAW,EAAE,EAAE,EAAE;IACjH,cAAc,CAAC,WAAW,GAAG,gBAAgB,CAAC;IAE9C,OAAO,CACH,KAAC,aAAa,IAAC,QAAQ,EAAE,KAAK,YAC1B,KAAC,YAAY,IAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAM,WAAW,GAAI,GACtE,CACnB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type { FunctionComponent } from \"react\";\r\nimport { LineContainer } from \"./propertyLines/propertyLine\";\r\nimport { UploadButton } from \"../primitives/uploadButton\";\r\nimport type { ButtonProps } from \"../primitives/button\";\r\n\r\ntype FileUploadLineProps = Omit<ButtonProps, \"onClick\" | \"label\"> & {\r\n onClick: (files: FileList) => void;\r\n label: string; // Require a label when button is the entire line (by default, label is optional on an UploadButton\r\n accept: string;\r\n};\r\n\r\n/**\r\n * A full-width line with an upload button.\r\n * For just the button without the line wrapper, use UploadButton directly.\r\n * @returns An UploadButton wrapped in a LineContainer\r\n */\r\nexport const FileUploadLine: FunctionComponent<FileUploadLineProps> = ({ onClick, label, accept, ...buttonProps }) => {\r\n FileUploadLine.displayName = \"FileUploadLine\";\r\n\r\n return (\r\n <LineContainer uniqueId={label}>\r\n <UploadButton onUpload={onClick} accept={accept} label={label} {...buttonProps} />\r\n </LineContainer>\r\n );\r\n};\r\n"]}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import type { FunctionComponent, HTMLProps, PropsWithChildren } from "react";
|
|
2
|
+
import type { AccordionSectionItemProps } from "../../primitives/accordion.js";
|
|
2
3
|
import type { PrimitiveProps } from "../../primitives/primitive.js";
|
|
3
4
|
type BasePropertyLineProps = {
|
|
4
5
|
/**
|
|
5
6
|
* The name of the property to display in the property line.
|
|
6
7
|
*/
|
|
7
8
|
label: string;
|
|
9
|
+
/**
|
|
10
|
+
* The ID of the property line to be used when the label cannot be used as a persistent ID.
|
|
11
|
+
*
|
|
12
|
+
* Note that when a property line is used within an accordion section, this ID must be unique within that section in order
|
|
13
|
+
* for property pinning and filtering to work correctly. If not, error will be shown in console.
|
|
14
|
+
*/
|
|
15
|
+
uniqueId?: string;
|
|
8
16
|
/**
|
|
9
17
|
* Optional description for the property, shown on hover of the info icon
|
|
10
18
|
*/
|
|
@@ -58,6 +66,6 @@ export type PropertyLineProps<ValueT> = BasePropertyLineProps & (NullablePropert
|
|
|
58
66
|
*
|
|
59
67
|
*/
|
|
60
68
|
export declare const PropertyLine: import("react").ForwardRefExoticComponent<PropsWithChildren<PropertyLineProps<any>> & import("react").RefAttributes<HTMLDivElement>>;
|
|
61
|
-
export declare const LineContainer: import("react").ForwardRefExoticComponent<Omit<PropsWithChildren<HTMLProps<HTMLDivElement
|
|
69
|
+
export declare const LineContainer: import("react").ForwardRefExoticComponent<Omit<PropsWithChildren<HTMLProps<HTMLDivElement> & AccordionSectionItemProps>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
62
70
|
export declare const PlaceholderPropertyLine: FunctionComponent<PrimitiveProps<any> & PropertyLineProps<any>>;
|
|
63
71
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Body1, Checkbox, makeStyles, tokens, mergeClasses } from "@fluentui/react-components";
|
|
3
3
|
import { ChevronCircleDown20Regular, ChevronCircleDown16Regular, ChevronCircleRight16Regular, ChevronCircleRight20Regular, CopyRegular, Copy16Regular, } from "@fluentui/react-icons";
|
|
4
|
+
import { AccordionSectionItem } from "../../primitives/accordion.js";
|
|
4
5
|
import { useContext, useState, forwardRef, cloneElement, isValidElement, useRef, useCallback } from "react";
|
|
5
6
|
import { Collapse } from "../../primitives/collapse.js";
|
|
6
7
|
import { copyCommandToClipboard } from "../../../copyCommandToClipboard.js";
|
|
@@ -72,7 +73,7 @@ export const PropertyLine = forwardRef((props, ref) => {
|
|
|
72
73
|
PropertyLine.displayName = "PropertyLine";
|
|
73
74
|
const { disableCopy, size } = useContext(ToolContext);
|
|
74
75
|
const classes = usePropertyLineStyles();
|
|
75
|
-
const { label, onCopy, expandedContent, children, nullable, ignoreNullable } = props;
|
|
76
|
+
const { label, uniqueId, onCopy, expandedContent, children, nullable, ignoreNullable } = props;
|
|
76
77
|
const [expanded, setExpanded] = useState("expandByDefault" in props ? props.expandByDefault : false);
|
|
77
78
|
const cachedVal = useRef(nullable ? props.value : null);
|
|
78
79
|
const { showToast } = useToast();
|
|
@@ -96,7 +97,7 @@ export const PropertyLine = forwardRef((props, ref) => {
|
|
|
96
97
|
defaultValue: undefined, // Don't pass defaultValue to children as there is no guarantee how this will be used and we can't mix controlled + uncontrolled state
|
|
97
98
|
})
|
|
98
99
|
: children;
|
|
99
|
-
return (_jsxs(LineContainer, { ref: ref, children: [_jsxs("div", { className: classes.baseLine, children: [_jsx(InfoLabel, { className: classes.infoLabel, htmlFor: "property", info: description, label: label, flexLabel: true, onContextMenu: onCopy ? handleContextMenu : undefined }), _jsxs("div", { className: classes.rightContent, id: "property", children: [expandedContent && (_jsx(ToggleButton, { title: "Expand/Collapse property", appearance: "transparent", checkedIcon: size === "small" ? ChevronCircleDown16Regular : ChevronCircleDown20Regular, uncheckedIcon: size === "small" ? ChevronCircleRight16Regular : ChevronCircleRight20Regular, value: expanded === true, onChange: setExpanded })), nullable && !ignoreNullable && (
|
|
100
|
+
return (_jsxs(LineContainer, { ref: ref, uniqueId: uniqueId ?? label, label: label, children: [_jsxs("div", { className: classes.baseLine, children: [_jsx(InfoLabel, { className: classes.infoLabel, htmlFor: "property", info: description, label: label, flexLabel: true, onContextMenu: onCopy ? handleContextMenu : undefined }), _jsxs("div", { className: classes.rightContent, id: "property", children: [expandedContent && (_jsx(ToggleButton, { title: "Expand/Collapse property", appearance: "transparent", checkedIcon: size === "small" ? ChevronCircleDown16Regular : ChevronCircleDown20Regular, uncheckedIcon: size === "small" ? ChevronCircleRight16Regular : ChevronCircleRight20Regular, value: expanded === true, onChange: setExpanded })), nullable && !ignoreNullable && (
|
|
100
101
|
// If this is a nullableProperty and ignoreNullable was not sent, display a checkbox used to toggle null ('checked' means 'non null')
|
|
101
102
|
_jsx(Tooltip, { content: props.value == null ? "Enable property" : "Disable property (set to null)", children: _jsx(Checkbox, { className: classes.checkbox, indicator: { className: classes.checkboxIndicator }, checked: !(props.value == null), onChange: (_, data) => {
|
|
102
103
|
if (data.checked) {
|
|
@@ -133,8 +134,9 @@ const useLineStyles = makeStyles({
|
|
|
133
134
|
});
|
|
134
135
|
export const LineContainer = forwardRef((props, ref) => {
|
|
135
136
|
const { size } = useContext(ToolContext);
|
|
137
|
+
const { children, uniqueId, label, ...rest } = props;
|
|
136
138
|
const classes = useLineStyles();
|
|
137
|
-
return (_jsx("div", { ref: ref, className: mergeClasses(classes.container, size == "small" ? classes.containerSmall : undefined), ...
|
|
139
|
+
return (_jsx(AccordionSectionItem, { uniqueId: uniqueId, label: label, children: _jsx("div", { ref: ref, className: mergeClasses(classes.container, size == "small" ? classes.containerSmall : undefined), ...rest, children: children }) }));
|
|
138
140
|
});
|
|
139
141
|
export const PlaceholderPropertyLine = (props) => {
|
|
140
142
|
return (_jsx(PropertyLine, { ...props, children: _jsx(Body1, { children: props.value }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"propertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/propertyLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EACH,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,WAAW,EACX,aAAa,GAChB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC5G,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,MAAM,qBAAqB,GAAG,UAAU,CAAC;IACrC,QAAQ,EAAE;QACN,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,YAAY;QAC5B,KAAK,EAAE,MAAM;KAChB;IACD,SAAS,EAAE;QACP,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,OAAO,EAAE,mDAAmD;QAClE,QAAQ,EAAE,YAAY,CAAC,aAAa;QACpC,SAAS,EAAE,MAAM;KACpB;IACD,YAAY,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,UAAU;KAC7B;IACD,YAAY,EAAE;QACV,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,UAAU;QACxB,UAAU,EAAE,QAAQ;KACvB;IACD,SAAS,EAAE;QACP,UAAU,EAAE,QAAQ;QACpB,SAAS,EAAE,YAAY;KAC1B;IACD,IAAI,EAAE;QACF,WAAW,EAAE,YAAY,CAAC,gBAAgB,EAAE,+GAA+G;KAC9J;IACD,kBAAkB,EAAE;QAChB,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,MAAM,CAAC,kBAAkB;KACzC;IACD,QAAQ,EAAE;QACN,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,MAAM,CAAC,mBAAmB;KAC1C;IACD,iBAAiB,EAAE;QACf,MAAM,EAAE,QAAQ,CAAC,GAAG;QACpB,KAAK,EAAE,QAAQ,CAAC,IAAI;QACpB,MAAM,EAAE,QAAQ,CAAC,IAAI;KACxB;CACJ,CAAC,CAAC;AAiEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAA4D,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC7G,YAAY,CAAC,WAAW,GAAG,cAAc,CAAC;IAC1C,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IAErF,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACrG,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAExD,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEjC,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,IAAI,MAAM,EAAE,CAAC;YACT,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC;YACjC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAExB,MAAM,iBAAiB,GAAG,WAAW,CACjC,CAAC,CAAa,EAAE,EAAE;QACd,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,UAAU,EAAE,CAAC;IACjB,CAAC,EACD,CAAC,UAAU,CAAC,CACf,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,IAAI,MAAM,GAAI,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAC,KAAK,cAAE,KAAK,CAAC,WAAW,GAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1K,6HAA6H;IAC7H,MAAM,iBAAiB,GACnB,CAAC,QAAQ,IAAI,cAAc,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC;QACpD,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE;YACnB,GAAG,QAAQ,CAAC,KAAK;YACjB,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC;YACtE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY;YACxC,YAAY,EAAE,SAAS,EAAE,sIAAsI;SAClK,CAAC;QACJ,CAAC,CAAC,QAAQ,CAAC;IAEnB,OAAO,CACH,MAAC,aAAa,IAAC,GAAG,EAAE,GAAG,aACnB,eAAK,SAAS,EAAE,OAAO,CAAC,QAAQ,aAC5B,KAAC,SAAS,IAAC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAC,UAAU,EAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,QAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,GAAI,EAChK,eAAK,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,EAAC,UAAU,aAC9C,eAAe,IAAI,CAChB,KAAC,YAAY,IACT,KAAK,EAAC,0BAA0B,EAChC,UAAU,EAAC,aAAa,EACxB,WAAW,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,0BAA0B,EACvF,aAAa,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,2BAA2B,EAC3F,KAAK,EAAE,QAAQ,KAAK,IAAI,EACxB,QAAQ,EAAE,WAAW,GACvB,CACL,EAEA,QAAQ,IAAI,CAAC,cAAc,IAAI;4BAC5B,qIAAqI;4BACrI,KAAC,OAAO,IAAC,OAAO,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,gCAAgC,YACxF,KAAC,QAAQ,IACL,SAAS,EAAE,OAAO,CAAC,QAAQ,EAC3B,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,iBAAiB,EAAE,EACnD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;wCAClB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;4CACf,wHAAwH;4CACxH,SAAS,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;wCACvG,CAAC;6CAAM,CAAC;4CACJ,oHAAoH;4CACpH,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;4CAChC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;wCACzB,CAAC;oCACL,CAAC,GACH,GACI,CACb,EACD,cAAK,SAAS,EAAE,OAAO,CAAC,YAAY,YAAG,iBAAiB,GAAO,EAC9D,MAAM,IAAI,CAAC,WAAW,IAAI,CACvB,KAAC,OAAO,IAAC,OAAO,EAAC,mBAAmB,YAChC,KAAC,MAAM,IAAC,SAAS,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,EAAC,aAAa,EAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,GAAI,GACjI,CACb,IACC,IACJ,EACL,eAAe,IAAI,CAChB,KAAC,QAAQ,IAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,YACzB,cAAK,SAAS,EAAE,OAAO,CAAC,kBAAkB,YAAG,eAAe,GAAO,GAC5D,CACd,IACW,CACnB,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,UAAU,CAAC;IAC7B,SAAS,EAAE;QACP,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ,EAAE,gCAAgC;QACzD,SAAS,EAAE,YAAY,CAAC,UAAU;QAClC,SAAS,EAAE,YAAY;QACvB,cAAc,EAAE,QAAQ;QACxB,UAAU,EAAE,MAAM,CAAC,kBAAkB;QACrC,aAAa,EAAE,MAAM,CAAC,kBAAkB;QACxC,SAAS,EAAE,uBAAuB;QAClC,YAAY,EAAE,uBAAuB;QACrC,QAAQ,EAAE;YACN,cAAc,EAAE,MAAM,CAAC,mBAAmB;YAC1C,iBAAiB,EAAE,MAAM,CAAC,mBAAmB;SAChD;KACJ;IACD,cAAc,EAAE;QACZ,SAAS,EAAE,YAAY,CAAC,eAAe;KAC1C;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAA+D,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACjH,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAEhC,OAAO,CACH,cAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,KAAM,KAAK,YACrH,KAAK,CAAC,QAAQ,GACb,CACT,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAoE,CAAC,KAAK,EAAE,EAAE;IAC9G,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,KAAK,cAAE,KAAK,CAAC,KAAK,GAAS,GACjB,CAClB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { Body1, Checkbox, makeStyles, tokens, mergeClasses } from \"@fluentui/react-components\";\r\nimport {\r\n ChevronCircleDown20Regular,\r\n ChevronCircleDown16Regular,\r\n ChevronCircleRight16Regular,\r\n ChevronCircleRight20Regular,\r\n CopyRegular,\r\n Copy16Regular,\r\n} from \"@fluentui/react-icons\";\r\nimport type { FunctionComponent, HTMLProps, PropsWithChildren, MouseEvent } from \"react\";\r\nimport { useContext, useState, forwardRef, cloneElement, isValidElement, useRef, useCallback } from \"react\";\r\nimport { Collapse } from \"../../primitives/collapse\";\r\nimport { copyCommandToClipboard } from \"../../../copyCommandToClipboard\";\r\nimport { ToolContext } from \"../fluentToolWrapper\";\r\nimport type { PrimitiveProps } from \"../../primitives/primitive\";\r\nimport { Link } from \"../../primitives/link\";\r\nimport { ToggleButton } from \"../../primitives/toggleButton\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport { CustomTokens, TokenMap } from \"../../primitives/utils\";\r\nimport { InfoLabel } from \"../../primitives/infoLabel\";\r\nimport { Tooltip } from \"../../primitives/tooltip\";\r\nimport { useToast } from \"../../primitives/toast\";\r\n\r\nconst usePropertyLineStyles = makeStyles({\r\n baseLine: {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"flex-start\",\r\n width: \"100%\",\r\n },\r\n infoLabel: {\r\n display: \"flex\",\r\n flex: \"1 1 0\", // grow=1, shrink =1, basis = 0 initial size before\r\n minWidth: CustomTokens.labelMinWidth,\r\n textAlign: \"left\",\r\n },\r\n rightContent: {\r\n flex: \"0 1 auto\",\r\n minWidth: 0,\r\n overflow: \"hidden\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"flex-end\",\r\n },\r\n childWrapper: {\r\n minWidth: 0,\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n whiteSpace: \"nowrap\",\r\n },\r\n infoPopup: {\r\n whiteSpace: \"normal\",\r\n wordBreak: \"break-word\",\r\n },\r\n copy: {\r\n marginRight: CustomTokens.rightAlignOffset, // Accounts for the padding baked into fluent button / ensures propertyLine looks visually aligned at the right\r\n },\r\n expandedContentDiv: {\r\n overflow: \"hidden\",\r\n paddingLeft: tokens.spacingHorizontalM,\r\n },\r\n checkbox: {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n marginRight: tokens.spacingHorizontalXS,\r\n },\r\n checkboxIndicator: {\r\n margin: TokenMap.px2,\r\n width: TokenMap.px12,\r\n height: TokenMap.px12,\r\n },\r\n});\r\n\r\ntype BasePropertyLineProps = {\r\n /**\r\n * The name of the property to display in the property line.\r\n */\r\n label: string;\r\n /**\r\n * Optional description for the property, shown on hover of the info icon\r\n */\r\n description?: string;\r\n /**\r\n * Optional function returning a string to copy to clipboard.\r\n */\r\n onCopy?: () => string;\r\n /**\r\n * Link to the documentation for this property, available from the info icon either linked from the description (if provided) or default 'docs' text\r\n */\r\n docLink?: string;\r\n};\r\n\r\n// Only require value/onChange/defaultValue props if nullable is true\r\ntype NullableProperty<ValueT> = {\r\n nullable: true;\r\n ignoreNullable: false;\r\n value: ValueT;\r\n onChange: (value: ValueT) => void;\r\n defaultValue?: ValueT;\r\n};\r\n\r\ntype IgnoreNullable<ValueT> = {\r\n ignoreNullable: true;\r\n nullable: false;\r\n value: ValueT;\r\n onChange: (value: ValueT) => void;\r\n defaultValue: ValueT;\r\n};\r\n\r\ntype NonNullableProperty = {\r\n nullable?: false;\r\n ignoreNullable?: false;\r\n};\r\n\r\n// Only expect optional expandByDefault prop if expandedContent is defined\r\ntype ExpandableProperty = {\r\n /**\r\n * If supplied, an 'expand' icon will be shown which, when clicked, renders this component within the property line.\r\n */\r\n expandedContent: JSX.Element;\r\n\r\n /**\r\n * If true, the expanded content will be shown by default.\r\n */\r\n expandByDefault?: boolean;\r\n};\r\n\r\n// If expanded content is undefined, don't expect expandByDefault prop\r\ntype NonExpandableProperty = {\r\n expandedContent?: undefined;\r\n};\r\n\r\nexport type PropertyLineProps<ValueT> = BasePropertyLineProps &\r\n (NullableProperty<ValueT> | NonNullableProperty | IgnoreNullable<ValueT>) &\r\n (ExpandableProperty | NonExpandableProperty);\r\n\r\n/**\r\n * A reusable component that renders a property line with a label and child content, and an optional description, copy button, and expandable section.\r\n *\r\n * @param props - The properties for the PropertyLine component.\r\n * @returns A React element representing the property line.\r\n *\r\n */\r\nexport const PropertyLine = forwardRef<HTMLDivElement, PropsWithChildren<PropertyLineProps<any>>>((props, ref) => {\r\n PropertyLine.displayName = \"PropertyLine\";\r\n const { disableCopy, size } = useContext(ToolContext);\r\n const classes = usePropertyLineStyles();\r\n const { label, onCopy, expandedContent, children, nullable, ignoreNullable } = props;\r\n\r\n const [expanded, setExpanded] = useState(\"expandByDefault\" in props ? props.expandByDefault : false);\r\n const cachedVal = useRef(nullable ? props.value : null);\r\n\r\n const { showToast } = useToast();\r\n\r\n const handleCopy = useCallback(() => {\r\n if (onCopy) {\r\n copyCommandToClipboard(onCopy());\r\n showToast(\"Copied property to clipboard\");\r\n }\r\n }, [onCopy, showToast]);\r\n\r\n const handleContextMenu = useCallback(\r\n (e: MouseEvent) => {\r\n e.preventDefault();\r\n handleCopy();\r\n },\r\n [handleCopy]\r\n );\r\n\r\n const description = props.docLink ? <Link url={props.docLink} value={props.description ?? \"Docs\"} /> : props.description ? <Body1>{props.description}</Body1> : undefined;\r\n\r\n // Process children to handle nullable state -- creating component in disabled state with default value in lieu of null value\r\n const processedChildren =\r\n (nullable || ignoreNullable) && isValidElement(children)\r\n ? cloneElement(children, {\r\n ...children.props,\r\n disabled: children.props.disabled || (nullable && props.value == null),\r\n value: props.value ?? props.defaultValue,\r\n defaultValue: undefined, // Don't pass defaultValue to children as there is no guarantee how this will be used and we can't mix controlled + uncontrolled state\r\n })\r\n : children;\r\n\r\n return (\r\n <LineContainer ref={ref}>\r\n <div className={classes.baseLine}>\r\n <InfoLabel className={classes.infoLabel} htmlFor=\"property\" info={description} label={label} flexLabel onContextMenu={onCopy ? handleContextMenu : undefined} />\r\n <div className={classes.rightContent} id=\"property\">\r\n {expandedContent && (\r\n <ToggleButton\r\n title=\"Expand/Collapse property\"\r\n appearance=\"transparent\"\r\n checkedIcon={size === \"small\" ? ChevronCircleDown16Regular : ChevronCircleDown20Regular}\r\n uncheckedIcon={size === \"small\" ? ChevronCircleRight16Regular : ChevronCircleRight20Regular}\r\n value={expanded === true}\r\n onChange={setExpanded}\r\n />\r\n )}\r\n\r\n {nullable && !ignoreNullable && (\r\n // If this is a nullableProperty and ignoreNullable was not sent, display a checkbox used to toggle null ('checked' means 'non null')\r\n <Tooltip content={props.value == null ? \"Enable property\" : \"Disable property (set to null)\"}>\r\n <Checkbox\r\n className={classes.checkbox}\r\n indicator={{ className: classes.checkboxIndicator }}\r\n checked={!(props.value == null)}\r\n onChange={(_, data) => {\r\n if (data.checked) {\r\n // if checked this means we are returning to non-null, use cached value if exists. If no cached value, use default value\r\n cachedVal.current != null ? props.onChange(cachedVal.current) : props.onChange(props.defaultValue);\r\n } else {\r\n // if moving to un-checked state, this means moving to null value. Cache the old value and tell props.onChange(null)\r\n cachedVal.current = props.value;\r\n props.onChange(null);\r\n }\r\n }}\r\n />\r\n </Tooltip>\r\n )}\r\n <div className={classes.childWrapper}>{processedChildren}</div>\r\n {onCopy && !disableCopy && (\r\n <Tooltip content=\"Copy to Clipboard\">\r\n <Button className={classes.copy} appearance=\"transparent\" icon={size === \"small\" ? Copy16Regular : CopyRegular} onClick={handleCopy} />\r\n </Tooltip>\r\n )}\r\n </div>\r\n </div>\r\n {expandedContent && (\r\n <Collapse visible={!!expanded}>\r\n <div className={classes.expandedContentDiv}>{expandedContent}</div>\r\n </Collapse>\r\n )}\r\n </LineContainer>\r\n );\r\n});\r\n\r\nconst useLineStyles = makeStyles({\r\n container: {\r\n width: \"100%\",\r\n display: \"flex\",\r\n flexDirection: \"column\", // Stack line + expanded content\r\n minHeight: CustomTokens.lineHeight,\r\n boxSizing: \"border-box\",\r\n justifyContent: \"center\",\r\n paddingTop: tokens.spacingVerticalXXS,\r\n paddingBottom: tokens.spacingVerticalXXS,\r\n borderTop: `1px solid transparent`,\r\n borderBottom: `1px solid transparent`,\r\n \":hover\": {\r\n borderTopColor: tokens.colorNeutralStroke2,\r\n borderBottomColor: tokens.colorNeutralStroke2,\r\n },\r\n },\r\n containerSmall: {\r\n minHeight: CustomTokens.lineHeightSmall,\r\n },\r\n});\r\n\r\nexport const LineContainer = forwardRef<HTMLDivElement, PropsWithChildren<HTMLProps<HTMLDivElement>>>((props, ref) => {\r\n const { size } = useContext(ToolContext);\r\n const classes = useLineStyles();\r\n\r\n return (\r\n <div ref={ref} className={mergeClasses(classes.container, size == \"small\" ? classes.containerSmall : undefined)} {...props}>\r\n {props.children}\r\n </div>\r\n );\r\n});\r\n\r\nexport const PlaceholderPropertyLine: FunctionComponent<PrimitiveProps<any> & PropertyLineProps<any>> = (props) => {\r\n return (\r\n <PropertyLine {...props}>\r\n <Body1>{props.value}</Body1>\r\n </PropertyLine>\r\n );\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"propertyLine.js","sourceRoot":"","sources":["../../../../../../dev/sharedUiComponents/src/fluent/hoc/propertyLines/propertyLine.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EACH,0BAA0B,EAC1B,0BAA0B,EAC1B,2BAA2B,EAC3B,2BAA2B,EAC3B,WAAW,EACX,aAAa,GAChB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC5G,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,MAAM,qBAAqB,GAAG,UAAU,CAAC;IACrC,QAAQ,EAAE;QACN,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,YAAY;QAC5B,KAAK,EAAE,MAAM;KAChB;IACD,SAAS,EAAE;QACP,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,OAAO,EAAE,mDAAmD;QAClE,QAAQ,EAAE,YAAY,CAAC,aAAa;QACpC,SAAS,EAAE,MAAM;KACpB;IACD,YAAY,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,cAAc,EAAE,UAAU;KAC7B;IACD,YAAY,EAAE;QACV,QAAQ,EAAE,CAAC;QACX,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,UAAU;QACxB,UAAU,EAAE,QAAQ;KACvB;IACD,SAAS,EAAE;QACP,UAAU,EAAE,QAAQ;QACpB,SAAS,EAAE,YAAY;KAC1B;IACD,IAAI,EAAE;QACF,WAAW,EAAE,YAAY,CAAC,gBAAgB,EAAE,+GAA+G;KAC9J;IACD,kBAAkB,EAAE;QAChB,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,MAAM,CAAC,kBAAkB;KACzC;IACD,QAAQ,EAAE;QACN,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,QAAQ;QACpB,WAAW,EAAE,MAAM,CAAC,mBAAmB;KAC1C;IACD,iBAAiB,EAAE;QACf,MAAM,EAAE,QAAQ,CAAC,GAAG;QACpB,KAAK,EAAE,QAAQ,CAAC,IAAI;QACpB,MAAM,EAAE,QAAQ,CAAC,IAAI;KACxB;CACJ,CAAC,CAAC;AAwEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAA4D,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC7G,YAAY,CAAC,WAAW,GAAG,cAAc,CAAC;IAC1C,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,qBAAqB,EAAE,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;IAE/F,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,iBAAiB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACrG,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAExD,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,EAAE,CAAC;IAEjC,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,IAAI,MAAM,EAAE,CAAC;YACT,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC;YACjC,SAAS,CAAC,8BAA8B,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAExB,MAAM,iBAAiB,GAAG,WAAW,CACjC,CAAC,CAAa,EAAE,EAAE;QACd,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,UAAU,EAAE,CAAC;IACjB,CAAC,EACD,CAAC,UAAU,CAAC,CACf,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAC,IAAI,IAAC,GAAG,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,IAAI,MAAM,GAAI,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAC,KAAK,cAAE,KAAK,CAAC,WAAW,GAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1K,6HAA6H;IAC7H,MAAM,iBAAiB,GACnB,CAAC,QAAQ,IAAI,cAAc,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC;QACpD,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE;YACnB,GAAG,QAAQ,CAAC,KAAK;YACjB,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC;YACtE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY;YACxC,YAAY,EAAE,SAAS,EAAE,sIAAsI;SAClK,CAAC;QACJ,CAAC,CAAC,QAAQ,CAAC;IAEnB,OAAO,CACH,MAAC,aAAa,IAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAAE,KAAK,EAAE,KAAK,aAC9D,eAAK,SAAS,EAAE,OAAO,CAAC,QAAQ,aAC5B,KAAC,SAAS,IAAC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAC,UAAU,EAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,QAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,GAAI,EAChK,eAAK,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,EAAE,EAAC,UAAU,aAC9C,eAAe,IAAI,CAChB,KAAC,YAAY,IACT,KAAK,EAAC,0BAA0B,EAChC,UAAU,EAAC,aAAa,EACxB,WAAW,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,0BAA0B,EACvF,aAAa,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,2BAA2B,EAC3F,KAAK,EAAE,QAAQ,KAAK,IAAI,EACxB,QAAQ,EAAE,WAAW,GACvB,CACL,EAEA,QAAQ,IAAI,CAAC,cAAc,IAAI;4BAC5B,qIAAqI;4BACrI,KAAC,OAAO,IAAC,OAAO,EAAE,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,gCAAgC,YACxF,KAAC,QAAQ,IACL,SAAS,EAAE,OAAO,CAAC,QAAQ,EAC3B,SAAS,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,iBAAiB,EAAE,EACnD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,EAC/B,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;wCAClB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;4CACf,wHAAwH;4CACxH,SAAS,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;wCACvG,CAAC;6CAAM,CAAC;4CACJ,oHAAoH;4CACpH,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;4CAChC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;wCACzB,CAAC;oCACL,CAAC,GACH,GACI,CACb,EACD,cAAK,SAAS,EAAE,OAAO,CAAC,YAAY,YAAG,iBAAiB,GAAO,EAC9D,MAAM,IAAI,CAAC,WAAW,IAAI,CACvB,KAAC,OAAO,IAAC,OAAO,EAAC,mBAAmB,YAChC,KAAC,MAAM,IAAC,SAAS,EAAE,OAAO,CAAC,IAAI,EAAE,UAAU,EAAC,aAAa,EAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,UAAU,GAAI,GACjI,CACb,IACC,IACJ,EACL,eAAe,IAAI,CAChB,KAAC,QAAQ,IAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,YACzB,cAAK,SAAS,EAAE,OAAO,CAAC,kBAAkB,YAAG,eAAe,GAAO,GAC5D,CACd,IACW,CACnB,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,UAAU,CAAC;IAC7B,SAAS,EAAE;QACP,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ,EAAE,gCAAgC;QACzD,SAAS,EAAE,YAAY,CAAC,UAAU;QAClC,SAAS,EAAE,YAAY;QACvB,cAAc,EAAE,QAAQ;QACxB,UAAU,EAAE,MAAM,CAAC,kBAAkB;QACrC,aAAa,EAAE,MAAM,CAAC,kBAAkB;QACxC,SAAS,EAAE,uBAAuB;QAClC,YAAY,EAAE,uBAAuB;QACrC,QAAQ,EAAE;YACN,cAAc,EAAE,MAAM,CAAC,mBAAmB;YAC1C,iBAAiB,EAAE,MAAM,CAAC,mBAAmB;SAChD;KACJ;IACD,cAAc,EAAE;QACZ,SAAS,EAAE,YAAY,CAAC,eAAe;KAC1C;CACJ,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU,CAA2F,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC7I,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACzC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IACrD,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAEhC,OAAO,CACH,KAAC,oBAAoB,IAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,YAClD,cAAK,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,KAAM,IAAI,YACpH,QAAQ,GACP,GACa,CAC1B,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAoE,CAAC,KAAK,EAAE,EAAE;IAC9G,OAAO,CACH,KAAC,YAAY,OAAK,KAAK,YACnB,KAAC,KAAK,cAAE,KAAK,CAAC,KAAK,GAAS,GACjB,CAClB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { Body1, Checkbox, makeStyles, tokens, mergeClasses } from \"@fluentui/react-components\";\r\nimport {\r\n ChevronCircleDown20Regular,\r\n ChevronCircleDown16Regular,\r\n ChevronCircleRight16Regular,\r\n ChevronCircleRight20Regular,\r\n CopyRegular,\r\n Copy16Regular,\r\n} from \"@fluentui/react-icons\";\r\nimport type { FunctionComponent, HTMLProps, PropsWithChildren, MouseEvent } from \"react\";\r\nimport type { AccordionSectionItemProps } from \"../../primitives/accordion\";\r\nimport { AccordionSectionItem } from \"../../primitives/accordion\";\r\nimport { useContext, useState, forwardRef, cloneElement, isValidElement, useRef, useCallback } from \"react\";\r\nimport { Collapse } from \"../../primitives/collapse\";\r\nimport { copyCommandToClipboard } from \"../../../copyCommandToClipboard\";\r\nimport { ToolContext } from \"../fluentToolWrapper\";\r\nimport type { PrimitiveProps } from \"../../primitives/primitive\";\r\nimport { Link } from \"../../primitives/link\";\r\nimport { ToggleButton } from \"../../primitives/toggleButton\";\r\nimport { Button } from \"../../primitives/button\";\r\nimport { CustomTokens, TokenMap } from \"../../primitives/utils\";\r\nimport { InfoLabel } from \"../../primitives/infoLabel\";\r\nimport { Tooltip } from \"../../primitives/tooltip\";\r\nimport { useToast } from \"../../primitives/toast\";\r\n\r\nconst usePropertyLineStyles = makeStyles({\r\n baseLine: {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"flex-start\",\r\n width: \"100%\",\r\n },\r\n infoLabel: {\r\n display: \"flex\",\r\n flex: \"1 1 0\", // grow=1, shrink =1, basis = 0 initial size before\r\n minWidth: CustomTokens.labelMinWidth,\r\n textAlign: \"left\",\r\n },\r\n rightContent: {\r\n flex: \"0 1 auto\",\r\n minWidth: 0,\r\n overflow: \"hidden\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"flex-end\",\r\n },\r\n childWrapper: {\r\n minWidth: 0,\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n whiteSpace: \"nowrap\",\r\n },\r\n infoPopup: {\r\n whiteSpace: \"normal\",\r\n wordBreak: \"break-word\",\r\n },\r\n copy: {\r\n marginRight: CustomTokens.rightAlignOffset, // Accounts for the padding baked into fluent button / ensures propertyLine looks visually aligned at the right\r\n },\r\n expandedContentDiv: {\r\n overflow: \"hidden\",\r\n paddingLeft: tokens.spacingHorizontalM,\r\n },\r\n checkbox: {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n marginRight: tokens.spacingHorizontalXS,\r\n },\r\n checkboxIndicator: {\r\n margin: TokenMap.px2,\r\n width: TokenMap.px12,\r\n height: TokenMap.px12,\r\n },\r\n});\r\n\r\ntype BasePropertyLineProps = {\r\n /**\r\n * The name of the property to display in the property line.\r\n */\r\n label: string;\r\n /**\r\n * The ID of the property line to be used when the label cannot be used as a persistent ID.\r\n *\r\n * Note that when a property line is used within an accordion section, this ID must be unique within that section in order\r\n * for property pinning and filtering to work correctly. If not, error will be shown in console.\r\n */\r\n uniqueId?: string;\r\n /**\r\n * Optional description for the property, shown on hover of the info icon\r\n */\r\n description?: string;\r\n /**\r\n * Optional function returning a string to copy to clipboard.\r\n */\r\n onCopy?: () => string;\r\n /**\r\n * Link to the documentation for this property, available from the info icon either linked from the description (if provided) or default 'docs' text\r\n */\r\n docLink?: string;\r\n};\r\n\r\n// Only require value/onChange/defaultValue props if nullable is true\r\ntype NullableProperty<ValueT> = {\r\n nullable: true;\r\n ignoreNullable: false;\r\n value: ValueT;\r\n onChange: (value: ValueT) => void;\r\n defaultValue?: ValueT;\r\n};\r\n\r\ntype IgnoreNullable<ValueT> = {\r\n ignoreNullable: true;\r\n nullable: false;\r\n value: ValueT;\r\n onChange: (value: ValueT) => void;\r\n defaultValue: ValueT;\r\n};\r\n\r\ntype NonNullableProperty = {\r\n nullable?: false;\r\n ignoreNullable?: false;\r\n};\r\n\r\n// Only expect optional expandByDefault prop if expandedContent is defined\r\ntype ExpandableProperty = {\r\n /**\r\n * If supplied, an 'expand' icon will be shown which, when clicked, renders this component within the property line.\r\n */\r\n expandedContent: JSX.Element;\r\n\r\n /**\r\n * If true, the expanded content will be shown by default.\r\n */\r\n expandByDefault?: boolean;\r\n};\r\n\r\n// If expanded content is undefined, don't expect expandByDefault prop\r\ntype NonExpandableProperty = {\r\n expandedContent?: undefined;\r\n};\r\n\r\nexport type PropertyLineProps<ValueT> = BasePropertyLineProps &\r\n (NullableProperty<ValueT> | NonNullableProperty | IgnoreNullable<ValueT>) &\r\n (ExpandableProperty | NonExpandableProperty);\r\n\r\n/**\r\n * A reusable component that renders a property line with a label and child content, and an optional description, copy button, and expandable section.\r\n *\r\n * @param props - The properties for the PropertyLine component.\r\n * @returns A React element representing the property line.\r\n *\r\n */\r\nexport const PropertyLine = forwardRef<HTMLDivElement, PropsWithChildren<PropertyLineProps<any>>>((props, ref) => {\r\n PropertyLine.displayName = \"PropertyLine\";\r\n const { disableCopy, size } = useContext(ToolContext);\r\n const classes = usePropertyLineStyles();\r\n const { label, uniqueId, onCopy, expandedContent, children, nullable, ignoreNullable } = props;\r\n\r\n const [expanded, setExpanded] = useState(\"expandByDefault\" in props ? props.expandByDefault : false);\r\n const cachedVal = useRef(nullable ? props.value : null);\r\n\r\n const { showToast } = useToast();\r\n\r\n const handleCopy = useCallback(() => {\r\n if (onCopy) {\r\n copyCommandToClipboard(onCopy());\r\n showToast(\"Copied property to clipboard\");\r\n }\r\n }, [onCopy, showToast]);\r\n\r\n const handleContextMenu = useCallback(\r\n (e: MouseEvent) => {\r\n e.preventDefault();\r\n handleCopy();\r\n },\r\n [handleCopy]\r\n );\r\n\r\n const description = props.docLink ? <Link url={props.docLink} value={props.description ?? \"Docs\"} /> : props.description ? <Body1>{props.description}</Body1> : undefined;\r\n\r\n // Process children to handle nullable state -- creating component in disabled state with default value in lieu of null value\r\n const processedChildren =\r\n (nullable || ignoreNullable) && isValidElement(children)\r\n ? cloneElement(children, {\r\n ...children.props,\r\n disabled: children.props.disabled || (nullable && props.value == null),\r\n value: props.value ?? props.defaultValue,\r\n defaultValue: undefined, // Don't pass defaultValue to children as there is no guarantee how this will be used and we can't mix controlled + uncontrolled state\r\n })\r\n : children;\r\n\r\n return (\r\n <LineContainer ref={ref} uniqueId={uniqueId ?? label} label={label}>\r\n <div className={classes.baseLine}>\r\n <InfoLabel className={classes.infoLabel} htmlFor=\"property\" info={description} label={label} flexLabel onContextMenu={onCopy ? handleContextMenu : undefined} />\r\n <div className={classes.rightContent} id=\"property\">\r\n {expandedContent && (\r\n <ToggleButton\r\n title=\"Expand/Collapse property\"\r\n appearance=\"transparent\"\r\n checkedIcon={size === \"small\" ? ChevronCircleDown16Regular : ChevronCircleDown20Regular}\r\n uncheckedIcon={size === \"small\" ? ChevronCircleRight16Regular : ChevronCircleRight20Regular}\r\n value={expanded === true}\r\n onChange={setExpanded}\r\n />\r\n )}\r\n\r\n {nullable && !ignoreNullable && (\r\n // If this is a nullableProperty and ignoreNullable was not sent, display a checkbox used to toggle null ('checked' means 'non null')\r\n <Tooltip content={props.value == null ? \"Enable property\" : \"Disable property (set to null)\"}>\r\n <Checkbox\r\n className={classes.checkbox}\r\n indicator={{ className: classes.checkboxIndicator }}\r\n checked={!(props.value == null)}\r\n onChange={(_, data) => {\r\n if (data.checked) {\r\n // if checked this means we are returning to non-null, use cached value if exists. If no cached value, use default value\r\n cachedVal.current != null ? props.onChange(cachedVal.current) : props.onChange(props.defaultValue);\r\n } else {\r\n // if moving to un-checked state, this means moving to null value. Cache the old value and tell props.onChange(null)\r\n cachedVal.current = props.value;\r\n props.onChange(null);\r\n }\r\n }}\r\n />\r\n </Tooltip>\r\n )}\r\n <div className={classes.childWrapper}>{processedChildren}</div>\r\n {onCopy && !disableCopy && (\r\n <Tooltip content=\"Copy to Clipboard\">\r\n <Button className={classes.copy} appearance=\"transparent\" icon={size === \"small\" ? Copy16Regular : CopyRegular} onClick={handleCopy} />\r\n </Tooltip>\r\n )}\r\n </div>\r\n </div>\r\n {expandedContent && (\r\n <Collapse visible={!!expanded}>\r\n <div className={classes.expandedContentDiv}>{expandedContent}</div>\r\n </Collapse>\r\n )}\r\n </LineContainer>\r\n );\r\n});\r\n\r\nconst useLineStyles = makeStyles({\r\n container: {\r\n width: \"100%\",\r\n display: \"flex\",\r\n flexDirection: \"column\", // Stack line + expanded content\r\n minHeight: CustomTokens.lineHeight,\r\n boxSizing: \"border-box\",\r\n justifyContent: \"center\",\r\n paddingTop: tokens.spacingVerticalXXS,\r\n paddingBottom: tokens.spacingVerticalXXS,\r\n borderTop: `1px solid transparent`,\r\n borderBottom: `1px solid transparent`,\r\n \":hover\": {\r\n borderTopColor: tokens.colorNeutralStroke2,\r\n borderBottomColor: tokens.colorNeutralStroke2,\r\n },\r\n },\r\n containerSmall: {\r\n minHeight: CustomTokens.lineHeightSmall,\r\n },\r\n});\r\n\r\nexport const LineContainer = forwardRef<HTMLDivElement, PropsWithChildren<HTMLProps<HTMLDivElement> & AccordionSectionItemProps>>((props, ref) => {\r\n const { size } = useContext(ToolContext);\r\n const { children, uniqueId, label, ...rest } = props;\r\n const classes = useLineStyles();\r\n\r\n return (\r\n <AccordionSectionItem uniqueId={uniqueId} label={label}>\r\n <div ref={ref} className={mergeClasses(classes.container, size == \"small\" ? classes.containerSmall : undefined)} {...rest}>\r\n {children}\r\n </div>\r\n </AccordionSectionItem>\r\n );\r\n});\r\n\r\nexport const PlaceholderPropertyLine: FunctionComponent<PrimitiveProps<any> & PropertyLineProps<any>> = (props) => {\r\n return (\r\n <PropertyLine {...props}>\r\n <Body1>{props.value}</Body1>\r\n </PropertyLine>\r\n );\r\n};\r\n"]}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { RefObject } from "react";
|
|
2
|
+
import type { AccordionProps, AccordionSectionBlockProps, AccordionSectionItemProps } from "./accordion.js";
|
|
3
|
+
/**
|
|
4
|
+
* Immutable state for the Accordion.
|
|
5
|
+
*/
|
|
6
|
+
export type AccordionState = {
|
|
7
|
+
/** IDs of pinned items (persisted to localStorage). */
|
|
8
|
+
pinnedIds: string[];
|
|
9
|
+
/** IDs of hidden items (persisted to localStorage). */
|
|
10
|
+
hiddenIds: string[];
|
|
11
|
+
/** Current search/filter term. */
|
|
12
|
+
searchTerm: string;
|
|
13
|
+
/** Whether edit mode is active (shows pin/hide controls). */
|
|
14
|
+
editMode: boolean;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Actions that can be dispatched to update accordion state.
|
|
18
|
+
*/
|
|
19
|
+
export type AccordionAction = {
|
|
20
|
+
type: "SET_SEARCH_TERM";
|
|
21
|
+
term: string;
|
|
22
|
+
} | {
|
|
23
|
+
type: "SET_EDIT_MODE";
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
} | {
|
|
26
|
+
type: "TOGGLE_PINNED";
|
|
27
|
+
itemId: string;
|
|
28
|
+
} | {
|
|
29
|
+
type: "TOGGLE_HIDDEN";
|
|
30
|
+
itemId: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: "MOVE_PINNED_UP";
|
|
33
|
+
itemId: string;
|
|
34
|
+
} | {
|
|
35
|
+
type: "SHOW_ALL";
|
|
36
|
+
} | {
|
|
37
|
+
type: "HIDE_ALL_VISIBLE";
|
|
38
|
+
visibleItemIds: string[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Feature flags for the Accordion (immutable after initialization).
|
|
42
|
+
*/
|
|
43
|
+
export type AccordionFeatures = {
|
|
44
|
+
/** Whether pinning is enabled. */
|
|
45
|
+
pinning: boolean;
|
|
46
|
+
/** Whether hiding is enabled. */
|
|
47
|
+
hiding: boolean;
|
|
48
|
+
/** Whether search is enabled. */
|
|
49
|
+
search: boolean;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Context value for the Accordion component.
|
|
53
|
+
*/
|
|
54
|
+
export type AccordionContextValue = {
|
|
55
|
+
/** The unique ID of the Accordion instance. */
|
|
56
|
+
accordionId: string;
|
|
57
|
+
/** State for the Accordion, managed via dispatch function. */
|
|
58
|
+
state: AccordionState;
|
|
59
|
+
/** Dispatch function to update state. */
|
|
60
|
+
dispatch: React.Dispatch<AccordionAction>;
|
|
61
|
+
/** Feature flags. */
|
|
62
|
+
features: AccordionFeatures;
|
|
63
|
+
/** Ref for the pinned items portal container. */
|
|
64
|
+
pinnedContainerRef: RefObject<HTMLDivElement>;
|
|
65
|
+
/** Set of registered item IDs (for duplicate detection). */
|
|
66
|
+
registeredItemIds: React.MutableRefObject<Set<string>>;
|
|
67
|
+
};
|
|
68
|
+
export declare const AccordionContext: import("react").Context<AccordionContextValue | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Hook to create and manage the AccordionContext value.
|
|
71
|
+
*
|
|
72
|
+
* @param props - AccordionProps
|
|
73
|
+
* @returns AccordionContextValue, or undefined if no features are enabled or no uniqueId is provided.
|
|
74
|
+
*/
|
|
75
|
+
export declare function useAccordionContext(props: AccordionProps): AccordionContextValue | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Context value for an AccordionSectionBlock.
|
|
78
|
+
*/
|
|
79
|
+
export type AccordionSectionBlockContextValue = {
|
|
80
|
+
/** The section ID. */
|
|
81
|
+
sectionId: string;
|
|
82
|
+
};
|
|
83
|
+
export declare const AccordionSectionBlockContext: import("react").Context<AccordionSectionBlockContextValue | undefined>;
|
|
84
|
+
/**
|
|
85
|
+
* Hook to create the AccordionSectionBlockContext value.
|
|
86
|
+
*
|
|
87
|
+
* @param props - AccordionSectionBlockProps
|
|
88
|
+
* @returns AccordionSectionBlockContextValue
|
|
89
|
+
*/
|
|
90
|
+
export declare function useAccordionSectionBlockContext(props: AccordionSectionBlockProps): AccordionSectionBlockContextValue;
|
|
91
|
+
/**
|
|
92
|
+
* Context to track whether we're inside an AccordionSectionItem.
|
|
93
|
+
* Used to prevent nested items from being individually manageable.
|
|
94
|
+
*/
|
|
95
|
+
export declare const AccordionItemDepthContext: import("react").Context<boolean>;
|
|
96
|
+
/**
|
|
97
|
+
* Derived item state, computed from the accordion state during render.
|
|
98
|
+
*/
|
|
99
|
+
export type AccordionItemState = {
|
|
100
|
+
/** The globally unique item ID. */
|
|
101
|
+
itemUniqueId: string;
|
|
102
|
+
/** Whether this item is nested inside another AccordionSectionItem. */
|
|
103
|
+
isNested: boolean;
|
|
104
|
+
/** Whether this item is pinned. */
|
|
105
|
+
isPinned: boolean;
|
|
106
|
+
/** Whether this item is hidden. */
|
|
107
|
+
isHidden: boolean;
|
|
108
|
+
/** Whether this item matches the current search term. */
|
|
109
|
+
isMatch: boolean;
|
|
110
|
+
/** The index of this item in the pinned list (for ordering). */
|
|
111
|
+
pinnedIndex: number;
|
|
112
|
+
/** Whether edit mode is active. */
|
|
113
|
+
inEditMode: boolean;
|
|
114
|
+
/** Callbacks to modify state. */
|
|
115
|
+
actions: {
|
|
116
|
+
togglePinned: () => void;
|
|
117
|
+
toggleHidden: () => void;
|
|
118
|
+
movePinnedUp: () => void;
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Hook to compute item state from accordion context.
|
|
123
|
+
*
|
|
124
|
+
* @param props - AccordionSectionItemProps
|
|
125
|
+
* @returns AccordionItemState, or undefined if no accordion context or nested item.
|
|
126
|
+
*/
|
|
127
|
+
export declare function useAccordionSectionItemState(props: AccordionSectionItemProps): AccordionItemState | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* Hook to determine if a section should be hidden because it has no visible items.
|
|
130
|
+
* This is computed during render based on the current state.
|
|
131
|
+
*
|
|
132
|
+
* @param sectionId - The section ID to check.
|
|
133
|
+
* @param registeredItems - Map of item IDs to their labels in this section.
|
|
134
|
+
* @returns Whether the section is empty (has no visible items).
|
|
135
|
+
*/
|
|
136
|
+
export declare function useIsSectionEmpty(sectionId: string, registeredItems: Map<string, string>): boolean;
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { createContext, useContext, useEffect, useMemo, useReducer, useRef } from "react";
|
|
2
|
+
import { DataStorage } from "@babylonjs/core/Misc/dataStorage.js";
|
|
3
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Storage Helpers
|
|
6
|
+
// ============================================================================
|
|
7
|
+
const STORAGE_KEY_ROOT = "Babylon/Accordion";
|
|
8
|
+
const ReadFromStorage = (path, initial) => {
|
|
9
|
+
try {
|
|
10
|
+
const stored = DataStorage.ReadString(`${STORAGE_KEY_ROOT}/${path}`, "");
|
|
11
|
+
return stored ? JSON.parse(stored) : initial;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return initial;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const WriteToStorage = (path, data) => {
|
|
18
|
+
DataStorage.WriteString(`${STORAGE_KEY_ROOT}/${path}`, JSON.stringify(data));
|
|
19
|
+
};
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// Reducer
|
|
22
|
+
// ============================================================================
|
|
23
|
+
const AccordionReducer = (state, action) => {
|
|
24
|
+
switch (action.type) {
|
|
25
|
+
case "SET_SEARCH_TERM":
|
|
26
|
+
return { ...state, searchTerm: action.term };
|
|
27
|
+
case "SET_EDIT_MODE":
|
|
28
|
+
return { ...state, editMode: action.enabled };
|
|
29
|
+
case "TOGGLE_PINNED": {
|
|
30
|
+
const isPinned = state.pinnedIds.includes(action.itemId);
|
|
31
|
+
return {
|
|
32
|
+
...state,
|
|
33
|
+
pinnedIds: isPinned ? state.pinnedIds.filter((id) => id !== action.itemId) : [...state.pinnedIds, action.itemId],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
case "TOGGLE_HIDDEN": {
|
|
37
|
+
const isHidden = state.hiddenIds.includes(action.itemId);
|
|
38
|
+
return {
|
|
39
|
+
...state,
|
|
40
|
+
hiddenIds: isHidden ? state.hiddenIds.filter((id) => id !== action.itemId) : [...state.hiddenIds, action.itemId],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
case "MOVE_PINNED_UP": {
|
|
44
|
+
const index = state.pinnedIds.indexOf(action.itemId);
|
|
45
|
+
if (index <= 0) {
|
|
46
|
+
return state;
|
|
47
|
+
}
|
|
48
|
+
const newPinnedIds = [...state.pinnedIds];
|
|
49
|
+
[newPinnedIds[index - 1], newPinnedIds[index]] = [newPinnedIds[index], newPinnedIds[index - 1]];
|
|
50
|
+
return { ...state, pinnedIds: newPinnedIds };
|
|
51
|
+
}
|
|
52
|
+
case "SHOW_ALL":
|
|
53
|
+
return { ...state, hiddenIds: [] };
|
|
54
|
+
case "HIDE_ALL_VISIBLE":
|
|
55
|
+
return {
|
|
56
|
+
...state,
|
|
57
|
+
hiddenIds: [...new Set([...state.hiddenIds, ...action.visibleItemIds])],
|
|
58
|
+
};
|
|
59
|
+
default:
|
|
60
|
+
return state;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
export const AccordionContext = createContext(undefined);
|
|
64
|
+
/**
|
|
65
|
+
* Hook to create and manage the AccordionContext value.
|
|
66
|
+
*
|
|
67
|
+
* @param props - AccordionProps
|
|
68
|
+
* @returns AccordionContextValue, or undefined if no features are enabled or no uniqueId is provided.
|
|
69
|
+
*/
|
|
70
|
+
export function useAccordionContext(props) {
|
|
71
|
+
const { uniqueId: accordionId, enablePinnedItems, enableHiddenItems, enableSearchItems } = props;
|
|
72
|
+
const features = useMemo(() => ({
|
|
73
|
+
pinning: enablePinnedItems ?? false,
|
|
74
|
+
hiding: enableHiddenItems ?? false,
|
|
75
|
+
search: enableSearchItems ?? false,
|
|
76
|
+
}), [enablePinnedItems, enableHiddenItems, enableSearchItems]);
|
|
77
|
+
const hasFeatures = features.pinning || features.hiding || features.search;
|
|
78
|
+
// Initialize state from localStorage
|
|
79
|
+
const initialState = useMemo(() => {
|
|
80
|
+
if (!accordionId || !hasFeatures) {
|
|
81
|
+
return { pinnedIds: [], hiddenIds: [], searchTerm: "", editMode: false };
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
pinnedIds: features.pinning ? ReadFromStorage(`Pinned/${accordionId}`, []) : [],
|
|
85
|
+
hiddenIds: features.hiding ? ReadFromStorage(`Hidden/${accordionId}`, []) : [],
|
|
86
|
+
searchTerm: "",
|
|
87
|
+
editMode: false,
|
|
88
|
+
};
|
|
89
|
+
}, [accordionId, hasFeatures, features.pinning, features.hiding]);
|
|
90
|
+
const [state, dispatch] = useReducer(AccordionReducer, initialState);
|
|
91
|
+
const pinnedContainerRef = useRef(null);
|
|
92
|
+
const registeredItemIds = useRef(new Set());
|
|
93
|
+
// Persist pinnedIds to localStorage when they change
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (accordionId && features.pinning) {
|
|
96
|
+
WriteToStorage(`Pinned/${accordionId}`, state.pinnedIds);
|
|
97
|
+
}
|
|
98
|
+
}, [accordionId, features.pinning, state.pinnedIds]);
|
|
99
|
+
// Persist hiddenIds to localStorage when they change
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (accordionId && features.hiding) {
|
|
102
|
+
WriteToStorage(`Hidden/${accordionId}`, state.hiddenIds);
|
|
103
|
+
}
|
|
104
|
+
}, [accordionId, features.hiding, state.hiddenIds]);
|
|
105
|
+
// Return undefined if no accordionId or no features enabled
|
|
106
|
+
if (!accordionId || !hasFeatures) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
accordionId,
|
|
111
|
+
state,
|
|
112
|
+
dispatch,
|
|
113
|
+
features,
|
|
114
|
+
pinnedContainerRef,
|
|
115
|
+
registeredItemIds,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
export const AccordionSectionBlockContext = createContext(undefined);
|
|
119
|
+
/**
|
|
120
|
+
* Hook to create the AccordionSectionBlockContext value.
|
|
121
|
+
*
|
|
122
|
+
* @param props - AccordionSectionBlockProps
|
|
123
|
+
* @returns AccordionSectionBlockContextValue
|
|
124
|
+
*/
|
|
125
|
+
export function useAccordionSectionBlockContext(props) {
|
|
126
|
+
const { sectionId } = props;
|
|
127
|
+
return useMemo(() => ({ sectionId }), [sectionId]);
|
|
128
|
+
}
|
|
129
|
+
// ============================================================================
|
|
130
|
+
// Item Depth Context (to detect nested AccordionSectionItems)
|
|
131
|
+
// ============================================================================
|
|
132
|
+
/**
|
|
133
|
+
* Context to track whether we're inside an AccordionSectionItem.
|
|
134
|
+
* Used to prevent nested items from being individually manageable.
|
|
135
|
+
*/
|
|
136
|
+
export const AccordionItemDepthContext = createContext(false);
|
|
137
|
+
/**
|
|
138
|
+
* Hook to compute item state from accordion context.
|
|
139
|
+
*
|
|
140
|
+
* @param props - AccordionSectionItemProps
|
|
141
|
+
* @returns AccordionItemState, or undefined if no accordion context or nested item.
|
|
142
|
+
*/
|
|
143
|
+
export function useAccordionSectionItemState(props) {
|
|
144
|
+
const { uniqueId: itemId, label: itemLabel, staticItem } = props;
|
|
145
|
+
const accordionCtx = useContext(AccordionContext);
|
|
146
|
+
const sectionCtx = useContext(AccordionSectionBlockContext);
|
|
147
|
+
const isNested = useContext(AccordionItemDepthContext);
|
|
148
|
+
// Build the globally unique item ID
|
|
149
|
+
const itemUniqueId = useMemo(() => {
|
|
150
|
+
if (!accordionCtx || !sectionCtx) {
|
|
151
|
+
return "";
|
|
152
|
+
}
|
|
153
|
+
return `${accordionCtx.accordionId}\0${sectionCtx.sectionId}\0${itemId}`;
|
|
154
|
+
}, [accordionCtx?.accordionId, sectionCtx?.sectionId, itemId]);
|
|
155
|
+
// Debug: warn if itemId changes (should be stable)
|
|
156
|
+
const prevItemIdRef = useRef(itemId);
|
|
157
|
+
useEffect(() => {
|
|
158
|
+
if (prevItemIdRef.current !== itemId) {
|
|
159
|
+
Logger.Warn(`Accordion: The uniqueId "${itemId}" in section "${sectionCtx?.sectionId}" has changed from "${prevItemIdRef.current}". ` +
|
|
160
|
+
`Each item must have a unique, stable ID for pin/hide persistence to work correctly.`);
|
|
161
|
+
}
|
|
162
|
+
prevItemIdRef.current = itemId;
|
|
163
|
+
}, [itemId, sectionCtx?.sectionId]);
|
|
164
|
+
// Debug: warn if itemUniqueId is not unique (duplicate detection)
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
if (!accordionCtx || !itemUniqueId) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const { registeredItemIds } = accordionCtx;
|
|
170
|
+
if (registeredItemIds.current.has(itemUniqueId)) {
|
|
171
|
+
Logger.Warn(`Accordion: Duplicate uniqueId "${itemId}" detected in section "${sectionCtx?.sectionId}". ` +
|
|
172
|
+
`Each item must have a unique ID within its section for pin/hide persistence to work correctly.`);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
registeredItemIds.current.add(itemUniqueId);
|
|
176
|
+
}
|
|
177
|
+
return () => {
|
|
178
|
+
registeredItemIds.current.delete(itemUniqueId);
|
|
179
|
+
};
|
|
180
|
+
}, [accordionCtx, itemUniqueId, itemId, sectionCtx?.sectionId]);
|
|
181
|
+
// If no context, static item, or nested, return undefined
|
|
182
|
+
if (!accordionCtx || staticItem) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
const { state, dispatch, features } = accordionCtx;
|
|
186
|
+
const { pinnedIds, hiddenIds, searchTerm, editMode } = state;
|
|
187
|
+
// Compute derived state
|
|
188
|
+
const isPinned = features.pinning && pinnedIds.includes(itemUniqueId);
|
|
189
|
+
const isHidden = features.hiding && hiddenIds.includes(itemUniqueId);
|
|
190
|
+
const pinnedIndex = isPinned ? pinnedIds.indexOf(itemUniqueId) : -1;
|
|
191
|
+
// Search matching
|
|
192
|
+
const searchText = (itemLabel ?? itemId).toLowerCase();
|
|
193
|
+
const isMatch = !features.search || !searchTerm || searchText.includes(searchTerm.toLowerCase());
|
|
194
|
+
return {
|
|
195
|
+
itemUniqueId,
|
|
196
|
+
isNested,
|
|
197
|
+
isPinned,
|
|
198
|
+
isHidden,
|
|
199
|
+
isMatch,
|
|
200
|
+
pinnedIndex,
|
|
201
|
+
inEditMode: editMode,
|
|
202
|
+
actions: {
|
|
203
|
+
togglePinned: () => dispatch({ type: "TOGGLE_PINNED", itemId: itemUniqueId }),
|
|
204
|
+
toggleHidden: () => dispatch({ type: "TOGGLE_HIDDEN", itemId: itemUniqueId }),
|
|
205
|
+
movePinnedUp: () => dispatch({ type: "MOVE_PINNED_UP", itemId: itemUniqueId }),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// Helper hook to check if a section is empty
|
|
211
|
+
// ============================================================================
|
|
212
|
+
/**
|
|
213
|
+
* Hook to determine if a section should be hidden because it has no visible items.
|
|
214
|
+
* This is computed during render based on the current state.
|
|
215
|
+
*
|
|
216
|
+
* @param sectionId - The section ID to check.
|
|
217
|
+
* @param registeredItems - Map of item IDs to their labels in this section.
|
|
218
|
+
* @returns Whether the section is empty (has no visible items).
|
|
219
|
+
*/
|
|
220
|
+
export function useIsSectionEmpty(sectionId, registeredItems) {
|
|
221
|
+
const accordionCtx = useContext(AccordionContext);
|
|
222
|
+
if (!accordionCtx) {
|
|
223
|
+
return false; // No context means no filtering, section is not empty
|
|
224
|
+
}
|
|
225
|
+
const { state, features, accordionId } = accordionCtx;
|
|
226
|
+
const { pinnedIds, hiddenIds, searchTerm, editMode } = state;
|
|
227
|
+
// In edit mode, always show sections
|
|
228
|
+
if (editMode) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
// Check if any item in this section is visible
|
|
232
|
+
for (const [itemId, itemLabel] of registeredItems) {
|
|
233
|
+
const itemUniqueId = `${accordionId}\0${sectionId}\0${itemId}`;
|
|
234
|
+
const isPinned = features.pinning && pinnedIds.includes(itemUniqueId);
|
|
235
|
+
const isHidden = features.hiding && hiddenIds.includes(itemUniqueId);
|
|
236
|
+
const searchText = (itemLabel ?? itemId).toLowerCase();
|
|
237
|
+
const isMatch = !features.search || !searchTerm || searchText.includes(searchTerm.toLowerCase());
|
|
238
|
+
// For the Pinned section, show items that are pinned and match
|
|
239
|
+
if (sectionId === "Pinned") {
|
|
240
|
+
if (isPinned && isMatch) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// For regular sections, show items that are not pinned, not hidden, and match
|
|
246
|
+
if (!isPinned && !isHidden && isMatch) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=accordion.contexts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accordion.contexts.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/accordion.contexts.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { RefObject } from \"react\";\nimport type { AccordionProps, AccordionSectionBlockProps, AccordionSectionItemProps } from \"./accordion\";\nimport { createContext, useContext, useEffect, useMemo, useReducer, useRef } from \"react\";\nimport { DataStorage } from \"core/Misc/dataStorage\";\nimport { Logger } from \"core/Misc/logger\";\n\n// ============================================================================\n// Storage Helpers\n// ============================================================================\n\nconst STORAGE_KEY_ROOT = \"Babylon/Accordion\";\n\nconst ReadFromStorage = <T,>(path: string, initial: T): T => {\n try {\n const stored = DataStorage.ReadString(`${STORAGE_KEY_ROOT}/${path}`, \"\");\n return stored ? JSON.parse(stored) : initial;\n } catch {\n return initial;\n }\n};\n\nconst WriteToStorage = (path: string, data: unknown): void => {\n DataStorage.WriteString(`${STORAGE_KEY_ROOT}/${path}`, JSON.stringify(data));\n};\n\n// ============================================================================\n// State Types\n// ============================================================================\n\n/**\n * Immutable state for the Accordion.\n */\nexport type AccordionState = {\n /** IDs of pinned items (persisted to localStorage). */\n pinnedIds: string[];\n /** IDs of hidden items (persisted to localStorage). */\n hiddenIds: string[];\n /** Current search/filter term. */\n searchTerm: string;\n /** Whether edit mode is active (shows pin/hide controls). */\n editMode: boolean;\n};\n\n/**\n * Actions that can be dispatched to update accordion state.\n */\nexport type AccordionAction =\n | { type: \"SET_SEARCH_TERM\"; term: string }\n | { type: \"SET_EDIT_MODE\"; enabled: boolean }\n | { type: \"TOGGLE_PINNED\"; itemId: string }\n | { type: \"TOGGLE_HIDDEN\"; itemId: string }\n | { type: \"MOVE_PINNED_UP\"; itemId: string }\n | { type: \"SHOW_ALL\" }\n | { type: \"HIDE_ALL_VISIBLE\"; visibleItemIds: string[] };\n\n/**\n * Feature flags for the Accordion (immutable after initialization).\n */\nexport type AccordionFeatures = {\n /** Whether pinning is enabled. */\n pinning: boolean;\n /** Whether hiding is enabled. */\n hiding: boolean;\n /** Whether search is enabled. */\n search: boolean;\n};\n\n// ============================================================================\n// Reducer\n// ============================================================================\n\nconst AccordionReducer = (state: AccordionState, action: AccordionAction): AccordionState => {\n switch (action.type) {\n case \"SET_SEARCH_TERM\":\n return { ...state, searchTerm: action.term };\n\n case \"SET_EDIT_MODE\":\n return { ...state, editMode: action.enabled };\n\n case \"TOGGLE_PINNED\": {\n const isPinned = state.pinnedIds.includes(action.itemId);\n return {\n ...state,\n pinnedIds: isPinned ? state.pinnedIds.filter((id) => id !== action.itemId) : [...state.pinnedIds, action.itemId],\n };\n }\n\n case \"TOGGLE_HIDDEN\": {\n const isHidden = state.hiddenIds.includes(action.itemId);\n return {\n ...state,\n hiddenIds: isHidden ? state.hiddenIds.filter((id) => id !== action.itemId) : [...state.hiddenIds, action.itemId],\n };\n }\n\n case \"MOVE_PINNED_UP\": {\n const index = state.pinnedIds.indexOf(action.itemId);\n if (index <= 0) {\n return state;\n }\n const newPinnedIds = [...state.pinnedIds];\n [newPinnedIds[index - 1], newPinnedIds[index]] = [newPinnedIds[index], newPinnedIds[index - 1]];\n return { ...state, pinnedIds: newPinnedIds };\n }\n\n case \"SHOW_ALL\":\n return { ...state, hiddenIds: [] };\n\n case \"HIDE_ALL_VISIBLE\":\n return {\n ...state,\n hiddenIds: [...new Set([...state.hiddenIds, ...action.visibleItemIds])],\n };\n\n default:\n return state;\n }\n};\n\n// ============================================================================\n// Accordion Context\n// ============================================================================\n\n/**\n * Context value for the Accordion component.\n */\nexport type AccordionContextValue = {\n /** The unique ID of the Accordion instance. */\n accordionId: string;\n /** State for the Accordion, managed via dispatch function. */\n state: AccordionState;\n /** Dispatch function to update state. */\n dispatch: React.Dispatch<AccordionAction>;\n /** Feature flags. */\n features: AccordionFeatures;\n /** Ref for the pinned items portal container. */\n pinnedContainerRef: RefObject<HTMLDivElement>;\n /** Set of registered item IDs (for duplicate detection). */\n registeredItemIds: React.MutableRefObject<Set<string>>;\n};\n\nexport const AccordionContext = createContext<AccordionContextValue | undefined>(undefined);\n\n/**\n * Hook to create and manage the AccordionContext value.\n *\n * @param props - AccordionProps\n * @returns AccordionContextValue, or undefined if no features are enabled or no uniqueId is provided.\n */\nexport function useAccordionContext(props: AccordionProps): AccordionContextValue | undefined {\n const { uniqueId: accordionId, enablePinnedItems, enableHiddenItems, enableSearchItems } = props;\n\n const features: AccordionFeatures = useMemo(\n () => ({\n pinning: enablePinnedItems ?? false,\n hiding: enableHiddenItems ?? false,\n search: enableSearchItems ?? false,\n }),\n [enablePinnedItems, enableHiddenItems, enableSearchItems]\n );\n\n const hasFeatures = features.pinning || features.hiding || features.search;\n\n // Initialize state from localStorage\n const initialState = useMemo((): AccordionState => {\n if (!accordionId || !hasFeatures) {\n return { pinnedIds: [], hiddenIds: [], searchTerm: \"\", editMode: false };\n }\n return {\n pinnedIds: features.pinning ? ReadFromStorage<string[]>(`Pinned/${accordionId}`, []) : [],\n hiddenIds: features.hiding ? ReadFromStorage<string[]>(`Hidden/${accordionId}`, []) : [],\n searchTerm: \"\",\n editMode: false,\n };\n }, [accordionId, hasFeatures, features.pinning, features.hiding]);\n\n const [state, dispatch] = useReducer(AccordionReducer, initialState);\n\n const pinnedContainerRef = useRef<HTMLDivElement>(null);\n const registeredItemIds = useRef<Set<string>>(new Set());\n\n // Persist pinnedIds to localStorage when they change\n useEffect(() => {\n if (accordionId && features.pinning) {\n WriteToStorage(`Pinned/${accordionId}`, state.pinnedIds);\n }\n }, [accordionId, features.pinning, state.pinnedIds]);\n\n // Persist hiddenIds to localStorage when they change\n useEffect(() => {\n if (accordionId && features.hiding) {\n WriteToStorage(`Hidden/${accordionId}`, state.hiddenIds);\n }\n }, [accordionId, features.hiding, state.hiddenIds]);\n\n // Return undefined if no accordionId or no features enabled\n if (!accordionId || !hasFeatures) {\n return undefined;\n }\n\n return {\n accordionId,\n state,\n dispatch,\n features,\n pinnedContainerRef,\n registeredItemIds,\n };\n}\n\n// ============================================================================\n// Section Context\n// ============================================================================\n\n/**\n * Context value for an AccordionSectionBlock.\n */\nexport type AccordionSectionBlockContextValue = {\n /** The section ID. */\n sectionId: string;\n};\n\nexport const AccordionSectionBlockContext = createContext<AccordionSectionBlockContextValue | undefined>(undefined);\n\n/**\n * Hook to create the AccordionSectionBlockContext value.\n *\n * @param props - AccordionSectionBlockProps\n * @returns AccordionSectionBlockContextValue\n */\nexport function useAccordionSectionBlockContext(props: AccordionSectionBlockProps): AccordionSectionBlockContextValue {\n const { sectionId } = props;\n return useMemo(() => ({ sectionId }), [sectionId]);\n}\n\n// ============================================================================\n// Item Depth Context (to detect nested AccordionSectionItems)\n// ============================================================================\n\n/**\n * Context to track whether we're inside an AccordionSectionItem.\n * Used to prevent nested items from being individually manageable.\n */\nexport const AccordionItemDepthContext = createContext<boolean>(false);\n\n// ============================================================================\n// Item Context Hook\n// ============================================================================\n\n/**\n * Derived item state, computed from the accordion state during render.\n */\nexport type AccordionItemState = {\n /** The globally unique item ID. */\n itemUniqueId: string;\n /** Whether this item is nested inside another AccordionSectionItem. */\n isNested: boolean;\n /** Whether this item is pinned. */\n isPinned: boolean;\n /** Whether this item is hidden. */\n isHidden: boolean;\n /** Whether this item matches the current search term. */\n isMatch: boolean;\n /** The index of this item in the pinned list (for ordering). */\n pinnedIndex: number;\n /** Whether edit mode is active. */\n inEditMode: boolean;\n /** Callbacks to modify state. */\n actions: {\n togglePinned: () => void;\n toggleHidden: () => void;\n movePinnedUp: () => void;\n };\n};\n\n/**\n * Hook to compute item state from accordion context.\n *\n * @param props - AccordionSectionItemProps\n * @returns AccordionItemState, or undefined if no accordion context or nested item.\n */\nexport function useAccordionSectionItemState(props: AccordionSectionItemProps): AccordionItemState | undefined {\n const { uniqueId: itemId, label: itemLabel, staticItem } = props;\n\n const accordionCtx = useContext(AccordionContext);\n const sectionCtx = useContext(AccordionSectionBlockContext);\n const isNested = useContext(AccordionItemDepthContext);\n\n // Build the globally unique item ID\n const itemUniqueId = useMemo(() => {\n if (!accordionCtx || !sectionCtx) {\n return \"\";\n }\n return `${accordionCtx.accordionId}\\0${sectionCtx.sectionId}\\0${itemId}`;\n }, [accordionCtx?.accordionId, sectionCtx?.sectionId, itemId]);\n\n // Debug: warn if itemId changes (should be stable)\n const prevItemIdRef = useRef(itemId);\n useEffect(() => {\n if (prevItemIdRef.current !== itemId) {\n Logger.Warn(\n `Accordion: The uniqueId \"${itemId}\" in section \"${sectionCtx?.sectionId}\" has changed from \"${prevItemIdRef.current}\". ` +\n `Each item must have a unique, stable ID for pin/hide persistence to work correctly.`\n );\n }\n prevItemIdRef.current = itemId;\n }, [itemId, sectionCtx?.sectionId]);\n\n // Debug: warn if itemUniqueId is not unique (duplicate detection)\n useEffect(() => {\n if (!accordionCtx || !itemUniqueId) {\n return;\n }\n const { registeredItemIds } = accordionCtx;\n if (registeredItemIds.current.has(itemUniqueId)) {\n Logger.Warn(\n `Accordion: Duplicate uniqueId \"${itemId}\" detected in section \"${sectionCtx?.sectionId}\". ` +\n `Each item must have a unique ID within its section for pin/hide persistence to work correctly.`\n );\n } else {\n registeredItemIds.current.add(itemUniqueId);\n }\n return () => {\n registeredItemIds.current.delete(itemUniqueId);\n };\n }, [accordionCtx, itemUniqueId, itemId, sectionCtx?.sectionId]);\n\n // If no context, static item, or nested, return undefined\n if (!accordionCtx || staticItem) {\n return undefined;\n }\n\n const { state, dispatch, features } = accordionCtx;\n const { pinnedIds, hiddenIds, searchTerm, editMode } = state;\n\n // Compute derived state\n const isPinned = features.pinning && pinnedIds.includes(itemUniqueId);\n const isHidden = features.hiding && hiddenIds.includes(itemUniqueId);\n const pinnedIndex = isPinned ? pinnedIds.indexOf(itemUniqueId) : -1;\n\n // Search matching\n const searchText = (itemLabel ?? itemId).toLowerCase();\n const isMatch = !features.search || !searchTerm || searchText.includes(searchTerm.toLowerCase());\n\n return {\n itemUniqueId,\n isNested,\n isPinned,\n isHidden,\n isMatch,\n pinnedIndex,\n inEditMode: editMode,\n actions: {\n togglePinned: () => dispatch({ type: \"TOGGLE_PINNED\", itemId: itemUniqueId }),\n toggleHidden: () => dispatch({ type: \"TOGGLE_HIDDEN\", itemId: itemUniqueId }),\n movePinnedUp: () => dispatch({ type: \"MOVE_PINNED_UP\", itemId: itemUniqueId }),\n },\n };\n}\n\n// ============================================================================\n// Helper hook to check if a section is empty\n// ============================================================================\n\n/**\n * Hook to determine if a section should be hidden because it has no visible items.\n * This is computed during render based on the current state.\n *\n * @param sectionId - The section ID to check.\n * @param registeredItems - Map of item IDs to their labels in this section.\n * @returns Whether the section is empty (has no visible items).\n */\nexport function useIsSectionEmpty(sectionId: string, registeredItems: Map<string, string>): boolean {\n const accordionCtx = useContext(AccordionContext);\n\n if (!accordionCtx) {\n return false; // No context means no filtering, section is not empty\n }\n\n const { state, features, accordionId } = accordionCtx;\n const { pinnedIds, hiddenIds, searchTerm, editMode } = state;\n\n // In edit mode, always show sections\n if (editMode) {\n return false;\n }\n\n // Check if any item in this section is visible\n for (const [itemId, itemLabel] of registeredItems) {\n const itemUniqueId = `${accordionId}\\0${sectionId}\\0${itemId}`;\n const isPinned = features.pinning && pinnedIds.includes(itemUniqueId);\n const isHidden = features.hiding && hiddenIds.includes(itemUniqueId);\n const searchText = (itemLabel ?? itemId).toLowerCase();\n const isMatch = !features.search || !searchTerm || searchText.includes(searchTerm.toLowerCase());\n\n // For the Pinned section, show items that are pinned and match\n if (sectionId === \"Pinned\") {\n if (isPinned && isMatch) {\n return false;\n }\n } else {\n // For regular sections, show items that are not pinned, not hidden, and match\n if (!isPinned && !isHidden && isMatch) {\n return false;\n }\n }\n }\n\n return true;\n}\n"]}
|
|
@@ -1,11 +1,62 @@
|
|
|
1
1
|
import type { ForwardRefExoticComponent, FunctionComponent, PropsWithChildren, RefAttributes } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Props: `AccordionSectionBlock`.
|
|
4
|
+
*/
|
|
5
|
+
export type AccordionSectionBlockProps = {
|
|
6
|
+
/** The ID of the `AccordionSectionBlock`, unique within the `Accordion` instance. */
|
|
7
|
+
sectionId: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Props: `AccordionSectionItem`.
|
|
11
|
+
*/
|
|
12
|
+
export type AccordionSectionItemProps = {
|
|
13
|
+
/** The ID of the `AccordionSectionItem`, unique within the `AccordionSectionBlock` instance. */
|
|
14
|
+
uniqueId: string;
|
|
15
|
+
/** The searchable text label for the item. */
|
|
16
|
+
label?: string;
|
|
17
|
+
/** Whether the item is not interactable. */
|
|
18
|
+
staticItem?: boolean;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Wrapper component that must encapsulate individual items.
|
|
22
|
+
* - Renders the pin button and tracks the pinned state of the item.
|
|
23
|
+
* - Renders the hide button and tracks the hidden state of the item.
|
|
24
|
+
* - Filters items based on the current search term.
|
|
25
|
+
*
|
|
26
|
+
* @param props - `AccordionSectionItemProps`
|
|
27
|
+
* @returns `Portal` if pinned; `null` if hidden/filtered; `children` otherwise.
|
|
28
|
+
*/
|
|
29
|
+
export declare const AccordionSectionItem: FunctionComponent<PropsWithChildren<AccordionSectionItemProps>>;
|
|
30
|
+
/**
|
|
31
|
+
* Props: `AccordionSection`.
|
|
32
|
+
*/
|
|
2
33
|
export type AccordionSectionProps = {
|
|
34
|
+
/** The text label shown in the section header. */
|
|
3
35
|
title: string;
|
|
36
|
+
/** Indicates whether the `AccordionSection` is initially collapsed. */
|
|
4
37
|
collapseByDefault?: boolean;
|
|
5
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Wrapper component that must encapsulate the section body.
|
|
41
|
+
*
|
|
42
|
+
* @param props - `AccordionSectionProps`
|
|
43
|
+
* @returns `div`
|
|
44
|
+
*/
|
|
6
45
|
export declare const AccordionSection: FunctionComponent<PropsWithChildren<AccordionSectionProps>>;
|
|
46
|
+
/**
|
|
47
|
+
* Props: `Accordion`.
|
|
48
|
+
*/
|
|
7
49
|
export type AccordionProps = {
|
|
50
|
+
/** The unique ID of the `Accordion` instance. */
|
|
51
|
+
uniqueId?: string;
|
|
52
|
+
/** The list of sections to be highlighted. */
|
|
8
53
|
highlightSections?: readonly string[];
|
|
54
|
+
/** Enables the pinned items feature. */
|
|
55
|
+
enablePinnedItems?: boolean;
|
|
56
|
+
/** Enables the hidden items feature. */
|
|
57
|
+
enableHiddenItems?: boolean;
|
|
58
|
+
/** Enables the search items feature. */
|
|
59
|
+
enableSearchItems?: boolean;
|
|
9
60
|
};
|
|
10
61
|
export declare const Accordion: ForwardRefExoticComponent<AccordionProps & {
|
|
11
62
|
children?: import("react").ReactNode | undefined;
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Children, forwardRef, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { Accordion as FluentAccordion, AccordionItem, AccordionHeader, AccordionPanel, Divider, Subtitle2Stronger, Portal, SearchBox, makeStyles, tokens, MessageBar, MessageBarBody, } from "@fluentui/react-components";
|
|
4
|
+
import { EditRegular, CheckmarkFilled, PinRegular, PinFilled, ArrowCircleUpRegular, EyeFilled, EyeOffRegular, FilterRegular } from "@fluentui/react-icons";
|
|
5
|
+
import { Button } from "./button.js";
|
|
4
6
|
import { CustomTokens } from "./utils.js";
|
|
5
7
|
import { ToolContext } from "../hoc/fluentToolWrapper.js";
|
|
8
|
+
import { AccordionContext, AccordionSectionBlockContext, AccordionItemDepthContext, useAccordionContext, useAccordionSectionBlockContext, useAccordionSectionItemState, } from "./accordion.contexts.js";
|
|
6
9
|
const useStyles = makeStyles({
|
|
7
10
|
accordion: {
|
|
8
|
-
overflowX: "hidden",
|
|
9
|
-
overflowY: "auto",
|
|
10
|
-
paddingBottom: tokens.spacingVerticalM, // bottom padding since there is no divider at the bottom
|
|
11
11
|
display: "flex",
|
|
12
12
|
flexDirection: "column",
|
|
13
13
|
height: "100%",
|
|
14
14
|
},
|
|
15
|
+
accordionBody: {
|
|
16
|
+
overflowX: "hidden",
|
|
17
|
+
overflowY: "auto",
|
|
18
|
+
paddingBottom: tokens.spacingVerticalM, // bottom padding since there is no divider at the bottom
|
|
19
|
+
},
|
|
15
20
|
divider: {
|
|
16
21
|
paddingTop: CustomTokens.dividerGap,
|
|
17
22
|
paddingBottom: CustomTokens.dividerGap,
|
|
@@ -44,7 +49,156 @@ const useStyles = makeStyles({
|
|
|
44
49
|
},
|
|
45
50
|
},
|
|
46
51
|
},
|
|
52
|
+
menuBar: {
|
|
53
|
+
display: "flex",
|
|
54
|
+
},
|
|
55
|
+
menuBarControls: {
|
|
56
|
+
display: "flex",
|
|
57
|
+
flexGrow: 1,
|
|
58
|
+
justifyContent: "end",
|
|
59
|
+
},
|
|
60
|
+
sectionEmpty: {
|
|
61
|
+
display: "none",
|
|
62
|
+
},
|
|
63
|
+
sectionItemContainer: {
|
|
64
|
+
display: "flex",
|
|
65
|
+
flexDirection: "row",
|
|
66
|
+
},
|
|
67
|
+
sectionItemButtons: {
|
|
68
|
+
display: "flex",
|
|
69
|
+
flexDirection: "row",
|
|
70
|
+
alignItems: "start",
|
|
71
|
+
marginRight: tokens.spacingHorizontalXS,
|
|
72
|
+
},
|
|
73
|
+
pinnedContainer: {
|
|
74
|
+
display: "flex",
|
|
75
|
+
flexDirection: "column",
|
|
76
|
+
},
|
|
77
|
+
pinnedContainerEmpty: {
|
|
78
|
+
"&:not(:only-child)": {
|
|
79
|
+
display: "none",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
searchBox: {
|
|
83
|
+
width: "100%",
|
|
84
|
+
},
|
|
47
85
|
});
|
|
86
|
+
/**
|
|
87
|
+
* Renders the menu bar and control buttons.
|
|
88
|
+
*
|
|
89
|
+
* @returns `div`, or `undefined` if all features are disabled.
|
|
90
|
+
*/
|
|
91
|
+
const AccordionMenuBar = () => {
|
|
92
|
+
AccordionMenuBar.displayName = "AccordionMenuBar";
|
|
93
|
+
const classes = useStyles();
|
|
94
|
+
const accordionCtx = useContext(AccordionContext);
|
|
95
|
+
if (!accordionCtx) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
const { state, dispatch, features } = accordionCtx;
|
|
99
|
+
const { editMode } = state;
|
|
100
|
+
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: () => {
|
|
101
|
+
// Hide all visible items - we pass all non-hidden, matching items
|
|
102
|
+
// For simplicity, we dispatch with an empty array; the actual filtering
|
|
103
|
+
// would need to be done with knowledge of all registered items.
|
|
104
|
+
// This is a limitation - in a full implementation, you'd track registered items.
|
|
105
|
+
dispatch({ type: "HIDE_ALL_VISIBLE", visibleItemIds: [] });
|
|
106
|
+
} })] })), (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 }) }))] })] }));
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Wrapper component that must encapsulate the section headers and panels.
|
|
110
|
+
* - Stores the section ID for use in `AccordionSectionItem`.
|
|
111
|
+
*
|
|
112
|
+
* @param props - `AccordionSectionBlockProps`
|
|
113
|
+
* @returns `AccordionSectionBlockContext.Provider`, or `AccordionItem` if all features are disabled.
|
|
114
|
+
*/
|
|
115
|
+
const AccordionSectionBlock = (props) => {
|
|
116
|
+
AccordionSectionBlock.displayName = "AccordionSectionBlock";
|
|
117
|
+
const { children, sectionId } = props;
|
|
118
|
+
const accordionCtx = useContext(AccordionContext);
|
|
119
|
+
const sectionContext = useAccordionSectionBlockContext(props);
|
|
120
|
+
if (accordionCtx) {
|
|
121
|
+
return (_jsx(AccordionSectionBlockContext.Provider, { value: sectionContext, children: _jsx(AccordionItem, { value: sectionId, children: children }) }));
|
|
122
|
+
}
|
|
123
|
+
return _jsx(AccordionItem, { value: sectionId, children: children });
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Wrapper component that must encapsulate individual items.
|
|
127
|
+
* - Renders the pin button and tracks the pinned state of the item.
|
|
128
|
+
* - Renders the hide button and tracks the hidden state of the item.
|
|
129
|
+
* - Filters items based on the current search term.
|
|
130
|
+
*
|
|
131
|
+
* @param props - `AccordionSectionItemProps`
|
|
132
|
+
* @returns `Portal` if pinned; `null` if hidden/filtered; `children` otherwise.
|
|
133
|
+
*/
|
|
134
|
+
export const AccordionSectionItem = (props) => {
|
|
135
|
+
AccordionSectionItem.displayName = "AccordionSectionItem";
|
|
136
|
+
const { children, staticItem } = props;
|
|
137
|
+
const classes = useStyles();
|
|
138
|
+
const accordionCtx = useContext(AccordionContext);
|
|
139
|
+
const itemState = useAccordionSectionItemState(props);
|
|
140
|
+
const [ctrlMode, setCtrlMode] = useState(false);
|
|
141
|
+
// If static item or no context, just render children
|
|
142
|
+
if (staticItem || !accordionCtx || !itemState) {
|
|
143
|
+
return _jsx(_Fragment, { children: children });
|
|
144
|
+
}
|
|
145
|
+
const { pinnedContainerRef, features } = accordionCtx;
|
|
146
|
+
const { isNested, isPinned, isHidden, isMatch, pinnedIndex, inEditMode, actions } = itemState;
|
|
147
|
+
// Nested items just render children (don't show controls)
|
|
148
|
+
if (isNested) {
|
|
149
|
+
return _jsx(_Fragment, { children: children });
|
|
150
|
+
}
|
|
151
|
+
// If hidden (and not in edit mode) or doesn't match search, don't render
|
|
152
|
+
if ((isHidden && !inEditMode) || !isMatch) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const pinnedContainer = isPinned ? pinnedContainerRef.current : null;
|
|
156
|
+
const showControls = inEditMode || ctrlMode;
|
|
157
|
+
const onMouseMove = (e) => {
|
|
158
|
+
if (e.ctrlKey !== ctrlMode) {
|
|
159
|
+
setCtrlMode(e.ctrlKey);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const onMouseLeave = () => {
|
|
163
|
+
if (ctrlMode) {
|
|
164
|
+
setCtrlMode(false);
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const itemElement = (_jsxs("div", { className: classes.sectionItemContainer, style: isPinned ? { order: pinnedIndex } : undefined, onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, 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, { title: "Move up", icon: ArrowCircleUpRegular, appearance: "transparent", disabled: pinnedIndex === 0, onClick: actions.movePinnedUp }))] }))] })), _jsx(AccordionItemDepthContext.Provider, { value: true, children: children })] }));
|
|
168
|
+
return pinnedContainer ? _jsx(Portal, { mountNode: pinnedContainer, children: itemElement }) : itemElement;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Renders the Pinned section container and defines the portal target for the pinned items.
|
|
172
|
+
*
|
|
173
|
+
* @returns `div`
|
|
174
|
+
*/
|
|
175
|
+
const AccordionPinnedContainer = () => {
|
|
176
|
+
AccordionPinnedContainer.displayName = "AccordionPinnedContainer";
|
|
177
|
+
const classes = useStyles();
|
|
178
|
+
const accordionCtx = useContext(AccordionContext);
|
|
179
|
+
return (_jsx("div", { ref: accordionCtx?.pinnedContainerRef, className: classes.pinnedContainer, children: _jsx(MessageBar, { className: classes.pinnedContainerEmpty, children: _jsx(MessageBarBody, { children: "No pinned items" }) }) }));
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Renders the search box for filtering items.
|
|
183
|
+
*
|
|
184
|
+
* @returns `SearchBox`, or `null` if the feature is disabled.
|
|
185
|
+
*/
|
|
186
|
+
const AccordionSearchBox = () => {
|
|
187
|
+
AccordionSearchBox.displayName = "AccordionSearchBox";
|
|
188
|
+
const classes = useStyles();
|
|
189
|
+
const accordionCtx = useContext(AccordionContext);
|
|
190
|
+
if (!accordionCtx?.features.search) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const { state, dispatch } = accordionCtx;
|
|
194
|
+
return (_jsx(SearchBox, { className: classes.searchBox, appearance: "underline", contentBefore: _jsx(FilterRegular, {}), placeholder: "Filter", value: state.searchTerm, onChange: (_, data) => dispatch({ type: "SET_SEARCH_TERM", term: data.value }) }));
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Wrapper component that must encapsulate the section body.
|
|
198
|
+
*
|
|
199
|
+
* @param props - `AccordionSectionProps`
|
|
200
|
+
* @returns `div`
|
|
201
|
+
*/
|
|
48
202
|
export const AccordionSection = (props) => {
|
|
49
203
|
AccordionSection.displayName = "AccordionSection";
|
|
50
204
|
const classes = useStyles();
|
|
@@ -53,11 +207,22 @@ export const AccordionSection = (props) => {
|
|
|
53
207
|
const StringAccordion = FluentAccordion;
|
|
54
208
|
export const Accordion = forwardRef((props, ref) => {
|
|
55
209
|
Accordion.displayName = "Accordion";
|
|
210
|
+
const { children, highlightSections, ...rest } = props;
|
|
56
211
|
const classes = useStyles();
|
|
57
212
|
const { size } = useContext(ToolContext);
|
|
58
|
-
const
|
|
213
|
+
const accordionCtx = useAccordionContext(props);
|
|
214
|
+
const hasPinning = accordionCtx?.features.pinning ?? false;
|
|
215
|
+
const pinnedSectionElement = useMemo(() => {
|
|
216
|
+
return (hasPinning && (_jsx(AccordionSection, { title: "Pinned", collapseByDefault: false, children: _jsx(AccordionPinnedContainer, {}) })));
|
|
217
|
+
}, [hasPinning]);
|
|
218
|
+
// Prevents sections contents from unmounting when closed, allowing their elements to be used in the Pinned section.
|
|
219
|
+
const preventUnmountMotion = useMemo(() => {
|
|
220
|
+
// https://github.com/microsoft/fluentui/issues/34309#issuecomment-2824364945
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
222
|
+
return hasPinning ? { children: (Component, props) => _jsx(Component, { ...props, unmountOnExit: false }) } : undefined;
|
|
223
|
+
}, [hasPinning]);
|
|
59
224
|
const validChildren = useMemo(() => {
|
|
60
|
-
return (Children.map(children, (child) => {
|
|
225
|
+
return (Children.map([pinnedSectionElement, children], (child) => {
|
|
61
226
|
if (isValidElement(child)) {
|
|
62
227
|
const childProps = child.props;
|
|
63
228
|
if (childProps.title) {
|
|
@@ -108,9 +273,9 @@ export const Accordion = forwardRef((props, ref) => {
|
|
|
108
273
|
setOpenItems((prev) => prev.filter((item) => item !== data.value));
|
|
109
274
|
}
|
|
110
275
|
}, []);
|
|
111
|
-
return (_jsx(StringAccordion, { ref: ref, className: classes.accordion, collapsible: true, multiple: true, onToggle: onToggle, openItems: openItems, ...rest, children: validChildren.map((child, index) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
276
|
+
return (_jsx(StringAccordion, { ref: ref, className: classes.accordion, collapsible: true, multiple: true, onToggle: onToggle, openItems: openItems, ...rest, children: _jsxs(AccordionContext.Provider, { value: accordionCtx, children: [_jsx(AccordionMenuBar, {}), _jsx("div", { className: classes.accordionBody, children: validChildren.map((child, index) => {
|
|
277
|
+
const isHighlighted = highlightSections?.includes(child.title);
|
|
278
|
+
return (_jsxs(AccordionSectionBlock, { sectionId: child.title, children: [_jsxs("div", { className: isHighlighted ? classes.highlightDiv : undefined, children: [_jsx(AccordionHeader, { size: size, children: _jsx(Subtitle2Stronger, { children: child.title }) }), _jsx(AccordionPanel, { collapseMotion: preventUnmountMotion, children: _jsx("div", { className: classes.panelDiv, children: child.content }) })] }), index < validChildren.length - 1 && _jsx(Divider, { inset: true, className: size === "small" ? classes.dividerSmall : classes.divider })] }, child.content.key ?? child.title));
|
|
279
|
+
}) })] }) }));
|
|
115
280
|
});
|
|
116
281
|
//# sourceMappingURL=accordion.js.map
|
|
@@ -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 { AccordionToggleData, AccordionToggleEvent, AccordionProps as FluentAccordionProps } from \"@fluentui/react-components\";\r\nimport type { ForwardRefExoticComponent, FunctionComponent, PropsWithChildren, RefAttributes } from \"react\";\r\n\r\nimport { Children, forwardRef, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\r\n\r\nimport { AccordionHeader, AccordionItem, AccordionPanel, Divider, Accordion as FluentAccordion, Subtitle2Stronger, makeStyles, tokens } from \"@fluentui/react-components\";\r\nimport { CustomTokens } from \"./utils\";\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\n\r\nconst useStyles = makeStyles({\r\n accordion: {\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 display: \"flex\",\r\n flexDirection: \"column\",\r\n height: \"100%\",\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});\r\n\r\nexport type AccordionSectionProps = {\r\n title: string;\r\n collapseByDefault?: boolean;\r\n};\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\nexport type AccordionProps = {\r\n highlightSections?: readonly string[];\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 classes = useStyles();\r\n const { size } = useContext(ToolContext);\r\n const { children, highlightSections, ...rest } = props;\r\n const validChildren = useMemo(() => {\r\n return (\r\n Children.map(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 {validChildren.map((child, index) => {\r\n const isHighlighted = highlightSections?.includes(child.title);\r\n return (\r\n <AccordionItem key={child.content.key ?? child.title} value={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>\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 </AccordionItem>\r\n );\r\n })}\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 { AccordionToggleData, AccordionToggleEvent, AccordionProps as FluentAccordionProps, AccordionPanelProps } from \"@fluentui/react-components\";\r\nimport type { ForwardRefExoticComponent, FunctionComponent, PropsWithChildren, RefAttributes } from \"react\";\r\n\r\nimport { Children, forwardRef, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\r\nimport {\r\n Accordion as FluentAccordion,\r\n AccordionItem,\r\n AccordionHeader,\r\n AccordionPanel,\r\n Divider,\r\n Subtitle2Stronger,\r\n Portal,\r\n SearchBox,\r\n makeStyles,\r\n tokens,\r\n MessageBar,\r\n MessageBarBody,\r\n} from \"@fluentui/react-components\";\r\nimport { EditRegular, CheckmarkFilled, PinRegular, PinFilled, ArrowCircleUpRegular, EyeFilled, EyeOffRegular, FilterRegular } from \"@fluentui/react-icons\";\r\nimport { Button } from \"./button\";\r\nimport { CustomTokens } from \"./utils\";\r\nimport { ToolContext } from \"../hoc/fluentToolWrapper\";\r\nimport {\r\n AccordionContext,\r\n AccordionSectionBlockContext,\r\n AccordionItemDepthContext,\r\n useAccordionContext,\r\n useAccordionSectionBlockContext,\r\n useAccordionSectionItemState,\r\n} from \"./accordion.contexts\";\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\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 onMouseMove = (e: React.MouseEvent) => {\r\n if (e.ctrlKey !== ctrlMode) {\r\n setCtrlMode(e.ctrlKey);\r\n }\r\n };\r\n\r\n const onMouseLeave = () => {\r\n if (ctrlMode) {\r\n setCtrlMode(false);\r\n }\r\n };\r\n\r\n const itemElement = (\r\n <div className={classes.sectionItemContainer} style={isPinned ? { order: pinnedIndex } : undefined} onMouseMove={onMouseMove} onMouseLeave={onMouseLeave}>\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"]}
|
|
@@ -22,6 +22,8 @@ const useCollapseStyles = makeStyles({
|
|
|
22
22
|
export const Collapse = (props) => {
|
|
23
23
|
Collapse.displayName = "Collapse";
|
|
24
24
|
const classes = useCollapseStyles();
|
|
25
|
-
|
|
25
|
+
// Since portalling breaks DOM hierarchy, `unmountOnExit` is required to ensure descendants are unmounted when the logical ancestor collapses.
|
|
26
|
+
// If this is a breaking change, the alternative would be creating a context to pass the `visible` state down to the descendants.
|
|
27
|
+
return (_jsx(FluentCollapse, { visible: props.visible, orientation: props.orientation, unmountOnExit: true, children: _jsx("div", { className: `${classes.collapseContent} ${props.orientation === "horizontal" ? classes.horizontal : classes.vertical}`, children: props.children }) }));
|
|
26
28
|
};
|
|
27
29
|
//# sourceMappingURL=collapse.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collapse.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/collapse.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAQvF,MAAM,iBAAiB,GAAG,UAAU,CAAC;IACjC,eAAe,EAAE;QACb,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,MAAM;KAClB;IACD,UAAU,EAAE;QACR,aAAa,EAAE,KAAK;KACvB;IACD,QAAQ,EAAE;QACN,aAAa,EAAE,QAAQ;KAC1B;CACJ,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAwD,CAAC,KAAK,EAAE,EAAE;IACnF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC;IAClC,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"collapse.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/collapse.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,QAAQ,IAAI,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAQvF,MAAM,iBAAiB,GAAG,UAAU,CAAC;IACjC,eAAe,EAAE;QACb,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,MAAM;KAClB;IACD,UAAU,EAAE;QACR,aAAa,EAAE,KAAK;KACvB;IACD,QAAQ,EAAE;QACN,aAAa,EAAE,QAAQ;KAC1B;CACJ,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAwD,CAAC,KAAK,EAAE,EAAE;IACnF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC;IAClC,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IAEpC,8IAA8I;IAC9I,iIAAiI;IAEjI,OAAO,CACH,KAAC,cAAc,IAAC,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,aAAa,kBACjF,cAAK,SAAS,EAAE,GAAG,OAAO,CAAC,eAAe,IAAI,KAAK,CAAC,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAG,KAAK,CAAC,QAAQ,GAAO,GACrI,CACpB,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { makeStyles } from \"@fluentui/react-components\";\r\nimport { Collapse as FluentCollapse } from \"@fluentui/react-motion-components-preview\";\r\nimport type { FunctionComponent, PropsWithChildren } from \"react\";\r\n\r\ntype CollapseProps = {\r\n visible: boolean;\r\n orientation?: \"horizontal\" | \"vertical\";\r\n};\r\n\r\nconst useCollapseStyles = makeStyles({\r\n collapseContent: {\r\n overflow: \"hidden\",\r\n display: \"flex\",\r\n },\r\n horizontal: {\r\n flexDirection: \"row\",\r\n },\r\n vertical: {\r\n flexDirection: \"column\",\r\n },\r\n});\r\n\r\n/**\r\n * Wraps the passed in children with a fluent collapse component, handling smooth animation when visible prop changes\r\n * NOTE: When passing in children, prefer react fragment over empty div to avoid bloating the react tree with an unnecessary div\r\n * @param props\r\n * @returns\r\n */\r\nexport const Collapse: FunctionComponent<PropsWithChildren<CollapseProps>> = (props) => {\r\n Collapse.displayName = \"Collapse\";\r\n const classes = useCollapseStyles();\r\n\r\n // Since portalling breaks DOM hierarchy, `unmountOnExit` is required to ensure descendants are unmounted when the logical ancestor collapses.\r\n // If this is a breaking change, the alternative would be creating a context to pass the `visible` state down to the descendants.\r\n\r\n return (\r\n <FluentCollapse visible={props.visible} orientation={props.orientation} unmountOnExit>\r\n <div className={`${classes.collapseContent} ${props.orientation === \"horizontal\" ? classes.horizontal : classes.vertical}`}>{props.children}</div>\r\n </FluentCollapse>\r\n );\r\n};\r\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infoLabel.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/infoLabel.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,SAAS,IAAI,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAiB5H,MAAM,kBAAkB,GAAG,UAAU,CAAC;IAClC,SAAS,EAAE;QACP,UAAU,EAAE,QAAQ;QACpB,SAAS,EAAE,YAAY;KAC1B;IACD,SAAS,EAAE;QACP,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,CAAC;KACd;IACD,SAAS,EAAE;QACP,UAAU,EAAE,QAAQ;QACpB,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,UAAU;KAC3B;IACD,QAAQ,EAAE;QACN,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"infoLabel.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/infoLabel.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { FunctionComponent, MouseEvent, MouseEventHandler } from \"react\";\r\nimport { useCallback, useState, useEffect } from \"react\";\r\nimport { Body1Strong, InfoLabel as FluentInfoLabel, makeStyles, mergeClasses, useFluent } from \"@fluentui/react-components\";\r\n\r\nexport type InfoLabelProps = {\r\n htmlFor: string; // required ID of the element whose label we are applying\r\n info?: JSX.Element;\r\n label: string;\r\n className?: string;\r\n /**\r\n * When true, applies flex layout styling to the label slot for proper truncation in flex containers\r\n */\r\n flexLabel?: boolean;\r\n /**\r\n * Handler for right-click context menu. Also triggers on Ctrl+click.\r\n */\r\n onContextMenu?: MouseEventHandler;\r\n};\r\nexport type InfoLabelParentProps = Omit<InfoLabelProps, \"htmlFor\">;\r\nconst useInfoLabelStyles = makeStyles({\r\n infoPopup: {\r\n whiteSpace: \"normal\",\r\n wordBreak: \"break-word\",\r\n },\r\n labelSlot: {\r\n display: \"flex\",\r\n minWidth: 0,\r\n },\r\n labelText: {\r\n whiteSpace: \"nowrap\",\r\n overflow: \"hidden\",\r\n textOverflow: \"ellipsis\",\r\n },\r\n copyable: {\r\n cursor: \"pointer\",\r\n },\r\n});\r\n/**\r\n * Renders a label with an optional popup containing more info\r\n * @param props\r\n * @returns\r\n */\r\nexport const InfoLabel: FunctionComponent<InfoLabelProps> = (props) => {\r\n InfoLabel.displayName = \"InfoLabel\";\r\n const classes = useInfoLabelStyles();\r\n const { targetDocument } = useFluent();\r\n\r\n const [ctrlPressed, setCtrlPressed] = useState(false);\r\n\r\n useEffect(() => {\r\n const targetWindow = targetDocument?.defaultView ?? window;\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.ctrlKey) {\r\n setCtrlPressed(true);\r\n }\r\n };\r\n const handleKeyUp = (e: KeyboardEvent) => {\r\n if (!e.ctrlKey) {\r\n setCtrlPressed(false);\r\n }\r\n };\r\n const handleBlur = () => {\r\n setCtrlPressed(false);\r\n };\r\n\r\n targetWindow.addEventListener(\"keydown\", handleKeyDown);\r\n targetWindow.addEventListener(\"keyup\", handleKeyUp);\r\n targetWindow.addEventListener(\"blur\", handleBlur);\r\n\r\n return () => {\r\n targetWindow.removeEventListener(\"keydown\", handleKeyDown);\r\n targetWindow.removeEventListener(\"keyup\", handleKeyUp);\r\n targetWindow.removeEventListener(\"blur\", handleBlur);\r\n };\r\n }, [targetDocument]);\r\n\r\n const infoContent = props.info ? <div className={classes.infoPopup}>{props.info}</div> : undefined;\r\n\r\n const showCopyCursor = ctrlPressed && props.onContextMenu;\r\n\r\n // Handle Ctrl+click as context menu action\r\n const handleClick = useCallback(\r\n (e: MouseEvent) => {\r\n if (e.ctrlKey && props.onContextMenu) {\r\n props.onContextMenu(e);\r\n }\r\n },\r\n [props.onContextMenu]\r\n );\r\n\r\n return infoContent ? (\r\n <FluentInfoLabel\r\n htmlFor={props.htmlFor}\r\n info={infoContent}\r\n className={mergeClasses(props.className, showCopyCursor ? classes.copyable : undefined)}\r\n label={props.flexLabel ? { className: classes.labelSlot } : undefined}\r\n onContextMenu={props.onContextMenu}\r\n onClick={handleClick}\r\n >\r\n <Body1Strong className={classes.labelText}>{props.label}</Body1Strong>\r\n </FluentInfoLabel>\r\n ) : (\r\n <Body1Strong className={mergeClasses(props.className, showCopyCursor ? classes.copyable : undefined)} onContextMenu={props.onContextMenu} onClick={handleClick}>\r\n {props.label}\r\n </Body1Strong>\r\n );\r\n};\r\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { MessageBar as FluentMessageBar, MessageBarTitle, MessageBarBody, makeStyles, tokens } from "@fluentui/react-components";
|
|
3
3
|
import { Link } from "./link.js";
|
|
4
|
+
import { AccordionSectionItem } from "./accordion.js";
|
|
4
5
|
const useClasses = makeStyles({
|
|
5
6
|
container: {
|
|
6
7
|
display: "flex",
|
|
@@ -10,8 +11,8 @@ const useClasses = makeStyles({
|
|
|
10
11
|
});
|
|
11
12
|
export const MessageBar = (props) => {
|
|
12
13
|
MessageBar.displayName = "MessageBar";
|
|
13
|
-
const { message, title, intent, docLink } = props;
|
|
14
|
+
const { message, title, intent, docLink, staticItem } = props;
|
|
14
15
|
const classes = useClasses();
|
|
15
|
-
return (_jsx("div", { className: classes.container, children: _jsx(FluentMessageBar, { intent: intent, layout: "multiline", children: _jsxs(MessageBarBody, { children: [title && _jsx(MessageBarTitle, { children: title }), message, docLink && (_jsxs(_Fragment, { children: [" - ", _jsx(Link, { url: docLink, value: "Learn More" })] }))] }) }) }));
|
|
16
|
+
return (_jsx(AccordionSectionItem, { uniqueId: title ?? message, staticItem: staticItem ?? true, children: _jsx("div", { className: classes.container, children: _jsx(FluentMessageBar, { intent: intent, layout: "multiline", children: _jsxs(MessageBarBody, { children: [title && _jsx(MessageBarTitle, { children: title }), message, docLink && (_jsxs(_Fragment, { children: [" - ", _jsx(Link, { url: docLink, value: "Learn More" })] }))] }) }) }) }));
|
|
16
17
|
};
|
|
17
18
|
//# sourceMappingURL=messageBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageBar.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/messageBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"messageBar.js","sourceRoot":"","sources":["../../../../../dev/sharedUiComponents/src/fluent/primitives/messageBar.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAEjI,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,UAAU,GAAG,UAAU,CAAC;IAC1B,SAAS,EAAE;QACP,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,QAAQ;QACvB,GAAG,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM;KACvC;CACJ,CAAC,CAAC;AAUH,MAAM,CAAC,MAAM,UAAU,GAAuC,CAAC,KAAK,EAAE,EAAE;IACpE,UAAU,CAAC,WAAW,GAAG,YAAY,CAAC;IACtC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAC9D,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,OAAO,CACH,KAAC,oBAAoB,IAAC,QAAQ,EAAE,KAAK,IAAI,OAAO,EAAE,UAAU,EAAE,UAAU,IAAI,IAAI,YAC5E,cAAK,SAAS,EAAE,OAAO,CAAC,SAAS,YAC7B,KAAC,gBAAgB,IAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAC,WAAW,YAChD,MAAC,cAAc,eACV,KAAK,IAAI,KAAC,eAAe,cAAE,KAAK,GAAmB,EACnD,OAAO,EACP,OAAO,IAAI,CACR,8BACK,KAAK,EACN,KAAC,IAAI,IAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAC,YAAY,GAAG,IAC1C,CACN,IACY,GACF,GACjB,GACa,CAC1B,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { MessageBar as FluentMessageBar, MessageBarTitle, MessageBarBody, makeStyles, tokens } from \"@fluentui/react-components\";\r\nimport type { FunctionComponent } from \"react\";\r\nimport { Link } from \"./link\";\r\nimport { AccordionSectionItem } from \"./accordion\";\r\n\r\nconst useClasses = makeStyles({\r\n container: {\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: tokens.spacingVerticalS, // 8px\r\n },\r\n});\r\n\r\ntype MessageBarProps = {\r\n message: string;\r\n title?: string;\r\n docLink?: string;\r\n intent: \"info\" | \"success\" | \"warning\" | \"error\";\r\n staticItem?: boolean;\r\n};\r\n\r\nexport const MessageBar: FunctionComponent<MessageBarProps> = (props) => {\r\n MessageBar.displayName = \"MessageBar\";\r\n const { message, title, intent, docLink, staticItem } = props;\r\n const classes = useClasses();\r\n\r\n return (\r\n <AccordionSectionItem uniqueId={title ?? message} staticItem={staticItem ?? true}>\r\n <div className={classes.container}>\r\n <FluentMessageBar intent={intent} layout=\"multiline\">\r\n <MessageBarBody>\r\n {title && <MessageBarTitle>{title}</MessageBarTitle>}\r\n {message}\r\n {docLink && (\r\n <>\r\n {\" - \"}\r\n <Link url={docLink} value=\"Learn More\" />\r\n </>\r\n )}\r\n </MessageBarBody>\r\n </FluentMessageBar>\r\n </div>\r\n </AccordionSectionItem>\r\n );\r\n};\r\n"]}
|
|
@@ -28,7 +28,7 @@ export declare const CustomTokens: {
|
|
|
28
28
|
rightAlignOffset: string;
|
|
29
29
|
};
|
|
30
30
|
export declare const UniformWidthStyling: GriffelStyle;
|
|
31
|
-
export declare const useInputStyles: () => Record<"input" | "container" | "
|
|
31
|
+
export declare const useInputStyles: () => Record<"input" | "container" | "invalid" | "inputSlot", string>;
|
|
32
32
|
export declare function HandleOnBlur(event: FocusEvent<HTMLInputElement>): void;
|
|
33
33
|
export declare function HandleKeyDown(event: KeyboardEvent<HTMLInputElement>): void;
|
|
34
34
|
/**
|