From c8d1d77ff64c75ac97acbc184656d296dd27e5aa Mon Sep 17 00:00:00 2001 From: PK-Microsoft <146996651+PK-Microsoft@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:13:13 -0700 Subject: [PATCH] Subway Nav Component: Added ability to set individual nodes to any Fluent UI icon and color based on user input (#353) * feat: Add Custom state to SubwayNavNodeState enum and ItemColumns enum * Update ControlManifest.Input.xml Reverted name back to original * Update index.ts Reverted name back to original * Update mock-datasets.ts * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts * Update subwaynav-lifecycle.test.ts * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts * Update subwaynav-lifecycle.test.ts * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts * Update subwaynav-lifecycle.test.ts * Update CanvasSubwayNav.tsx * Update CanvasSubwayNav.tsx * Update subway-node.types.ts * Update subway-node.types.ts * Update CanvasSubwayNav.tsx * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts * Update subwaynav-lifecycle.test.ts * Update datasetmapping.test.ts * Update subwaynav-lifecycle.test.ts * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update datasetmapping.test.ts * Update datasetmapping.test.ts * Update datasetmapping.test.ts * Update datasetmapping.test.ts.snap * Update subwaynav-lifecycle.test.ts.snap * Update subwaynav-lifecycle.test.ts * Update datasetmapping.test.ts * Update subwaynav-lifecycle.test.ts * Update subwaynav-lifecycle.test.ts --------- Co-authored-by: Ramakrishnan Raman --- SubwayNav/README.md | 19 ++++- SubwayNav/SubwayNav/ControlManifest.Input.xml | 6 +- SubwayNav/SubwayNav/ManifestConstants.ts | 2 + .../SubwayNav/__mocks__/mock-datasets.ts | 4 +- .../__snapshots__/datasetmapping.test.ts.snap | 82 ++++++++++++++++--- .../subwaynav-lifecycle.test.ts.snap | 66 +++++++++++++++ .../SubwayNav/_test_/datasetmapping.test.ts | 26 ++++-- .../_test_/subwaynav-lifecycle.test.ts | 16 +++- .../SubwayNav/components/CanvasSubwayNav.tsx | 5 ++ .../SubwayNav/components/DatasetMapping.ts | 10 +++ SubwayNav/SubwayNav/components/StepSchema.ts | 2 + .../SubwayNav/components/components.types.ts | 4 + .../utilities/subway-nav/subway-node.types.ts | 22 +++++ .../utilities/subway-nav/wizard.types.ts | 1 + .../subway-node/subway-node.base.tsx | 7 +- .../subway-node/subway-node.styles.ts | 16 +++- .../subway-node/subway-node.types.ts | 21 +++++ 17 files changed, 278 insertions(+), 31 deletions(-) diff --git a/SubwayNav/README.md b/SubwayNav/README.md index c6e38acb..71047af0 100644 --- a/SubwayNav/README.md +++ b/SubwayNav/README.md @@ -17,8 +17,9 @@ The control accepts the following properties: - **Items** - The action items to render - **ItemKey** - The key to use to indicate which item/step is selected. The keys must be unique. - **ItemLabel** - Label for the step - - **ItemState** - Specifying the state of the step. Here is the list of State available. Current|NotStarted|Completed|Unsaved|ViewedNotCompleted|Error|CurrentWithSubSteps|Skipped|WizardComplete - + - **ItemState** - Specifying the state of the step. Here is the list of State available. Current|NotStarted|Completed|Unsaved|ViewedNotCompleted|Error|CurrentWithSubSteps|Skipped|WizardComplete|Custom + - **ItemIcon** - Will not do anything if ItemState isn't set to Custom. If ItemState is set to Custom, you can input the string value of any FluentUI Icon and it will show up. If the ItemIcon name is invalid, blank or doesn't match any FluentUI Icon's, then it will be set to same Icon as when ItemState is equal to Current. + - **ItemColor** - Will not do anything if ItemState isn't set to Custom. If ItemState is set to Custom, you can input most hexadecimal color codes and that will change the color of the Icon. If the input to this column is invalid, it will default to black. If the input to this column is blank, it will be set to the same color as when ItemState is equal to Current. - **SubwayNav state** - To mark the overall state of SubwayNav to Complete or Error. ### Style Properties @@ -142,3 +143,17 @@ Set(varThemeBlueJSON,"{""palette"":{ ``` The Theme JSON string is passed to the component property, whilst the varTheme can be used to style other standard components such as buttons using the individual colors. + + + +### Example using Custom Item State + +Example of input collection value for Items property + +```PowerFx +Table({ItemKey:"1",ItemLabel:"Step 1",ItemState:"Current"}, +{ItemKey:"2",ItemLabel:"Step 2",ItemState:"Custom", ItemIcon:"Admin",ItemColor: "teal"}, +{ItemKey:"3",ItemLabel:"Step 3",ItemState:"Custom",ItemIcon:"AddTo",ItemColor: "#EE82EE"}) +``` + +You can use either the names of colors or the colors hexadecimal value. However, color hexadecimal value is recommended. If the color name isn't basic, it most likely won't work. \ No newline at end of file diff --git a/SubwayNav/SubwayNav/ControlManifest.Input.xml b/SubwayNav/SubwayNav/ControlManifest.Input.xml index 7dc9ca2c..1428f8a4 100644 --- a/SubwayNav/SubwayNav/ControlManifest.Input.xml +++ b/SubwayNav/SubwayNav/ControlManifest.Input.xml @@ -1,6 +1,6 @@ - + @@ -24,6 +24,8 @@ + + - \ No newline at end of file + diff --git a/SubwayNav/SubwayNav/ManifestConstants.ts b/SubwayNav/SubwayNav/ManifestConstants.ts index beb6d4dd..f4676f97 100644 --- a/SubwayNav/SubwayNav/ManifestConstants.ts +++ b/SubwayNav/SubwayNav/ManifestConstants.ts @@ -8,6 +8,8 @@ export const enum ItemColumns { State = 'ItemState', Disabled = 'ItemDisabled', VisuallyDisabled = 'ItemVisuallyDisabled', + ItemIcon = 'ItemIcon', + ItemColor = 'ItemColor', ParentKey = 'ParentItemKey', } diff --git a/SubwayNav/SubwayNav/__mocks__/mock-datasets.ts b/SubwayNav/SubwayNav/__mocks__/mock-datasets.ts index 1c9d1b0c..1c0c1641 100644 --- a/SubwayNav/SubwayNav/__mocks__/mock-datasets.ts +++ b/SubwayNav/SubwayNav/__mocks__/mock-datasets.ts @@ -29,9 +29,7 @@ export class MockDataSet implements ComponentFramework.PropertyTypes.DataSet { linking: ComponentFramework.PropertyHelper.DataSetApi.Linking; loading: boolean; paging: ComponentFramework.PropertyHelper.DataSetApi.Paging; - records: { - [id: string]: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord; - }; + records: { [id: string]: ComponentFramework.PropertyHelper.DataSetApi.EntityRecord }; sortedRecordIds: string[]; sorting: ComponentFramework.PropertyHelper.DataSetApi.SortStatus[]; clearSelectedRecordIds = jest.fn(); diff --git a/SubwayNav/SubwayNav/_test_/__snapshots__/datasetmapping.test.ts.snap b/SubwayNav/SubwayNav/_test_/__snapshots__/datasetmapping.test.ts.snap index cb2d61e4..e20862a9 100644 --- a/SubwayNav/SubwayNav/_test_/__snapshots__/datasetmapping.test.ts.snap +++ b/SubwayNav/SubwayNav/_test_/__snapshots__/datasetmapping.test.ts.snap @@ -14,6 +14,8 @@ Array [ }, "disabled": undefined, "id": "1", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 1", "label": "item1", "parentId": undefined, @@ -32,6 +34,8 @@ Array [ }, "disabled": undefined, "id": "2", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 2", "label": "item2", "parentId": undefined, @@ -50,6 +54,8 @@ Array [ }, "disabled": undefined, "id": "3", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 3", "label": "item3", "parentId": undefined, @@ -68,6 +74,8 @@ Array [ }, "disabled": undefined, "id": "4", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 4", "label": "item4", "parentId": undefined, @@ -79,15 +87,17 @@ Array [ "getNamedReference": [MockFunction], "id": "5", "values": Object { - "ItemKey": "Item 4", - "ItemLabel": "item4", + "ItemKey": "Item 5", + "ItemLabel": "item5", "ItemState": "Error", }, }, "disabled": undefined, "id": "5", - "key": "Item 4", - "label": "item4", + "itemColor": undefined, + "itemIcon": undefined, + "key": "Item 5", + "label": "item5", "parentId": undefined, "state": "Error", "visuallyDisabled": undefined, @@ -97,15 +107,17 @@ Array [ "getNamedReference": [MockFunction], "id": "6", "values": Object { - "ItemKey": "Item 4", - "ItemLabel": "item4", + "ItemKey": "Item 6", + "ItemLabel": "item6", "ItemState": "Skipped", }, }, "disabled": undefined, "id": "6", - "key": "Item 4", - "label": "item4", + "itemColor": undefined, + "itemIcon": undefined, + "key": "Item 6", + "label": "item6", "parentId": undefined, "state": "Skipped", "visuallyDisabled": undefined, @@ -115,18 +127,64 @@ Array [ "getNamedReference": [MockFunction], "id": "7", "values": Object { - "ItemKey": "Item 4", - "ItemLabel": "item4", + "ItemKey": "Item 7", + "ItemLabel": "item7", "ItemState": "Unsaved", }, }, "disabled": undefined, "id": "7", - "key": "Item 4", - "label": "item4", + "itemColor": undefined, + "itemIcon": undefined, + "key": "Item 7", + "label": "item7", "parentId": undefined, "state": "Unsaved", "visuallyDisabled": undefined, }, + Object { + "data": MockEntityRecord { + "getNamedReference": [MockFunction], + "id": "8", + "values": Object { + "ItemColor": "#C8A2C8", + "ItemIcon": "AddFriend", + "ItemKey": "Item 8", + "ItemLabel": "item8", + "ItemState": "Custom", + }, + }, + "disabled": undefined, + "id": "8", + "itemColor": "#C8A2C8", + "itemIcon": "AddFriend", + "key": "Item 8", + "label": "item8", + "parentId": undefined, + "state": "Custom", + "visuallyDisabled": undefined, + }, + Object { + "data": MockEntityRecord { + "getNamedReference": [MockFunction], + "id": "9", + "values": Object { + "ItemColor": "#EE82EE", + "ItemIcon": "AddTo", + "ItemKey": "Item 9", + "ItemLabel": "item8", + "ItemState": "Custom", + }, + }, + "disabled": undefined, + "id": "9", + "itemColor": "#EE82EE", + "itemIcon": "AddTo", + "key": "Item 9", + "label": "item8", + "parentId": undefined, + "state": "Custom", + "visuallyDisabled": undefined, + }, ] `; diff --git a/SubwayNav/SubwayNav/_test_/__snapshots__/subwaynav-lifecycle.test.ts.snap b/SubwayNav/SubwayNav/_test_/__snapshots__/subwaynav-lifecycle.test.ts.snap index 2d5d906a..49472841 100644 --- a/SubwayNav/SubwayNav/_test_/__snapshots__/subwaynav-lifecycle.test.ts.snap +++ b/SubwayNav/SubwayNav/_test_/__snapshots__/subwaynav-lifecycle.test.ts.snap @@ -20,6 +20,8 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "1", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 1", "label": "item1", "parentId": undefined, @@ -38,6 +40,8 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "2", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 2", "label": "item2", "parentId": undefined, @@ -56,6 +60,8 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "3", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 3", "label": "item3", "parentId": undefined, @@ -74,6 +80,8 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "4", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 4", "label": "item4", "parentId": undefined, @@ -92,6 +100,8 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "5", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 4", "label": "item4", "parentId": undefined, @@ -110,6 +120,8 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "6", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 4", "label": "item4", "parentId": undefined, @@ -128,12 +140,58 @@ exports[`SubwayNav renders 1`] = ` }, "disabled": undefined, "id": "7", + "itemColor": undefined, + "itemIcon": undefined, "key": "Item 4", "label": "item4", "parentId": undefined, "state": "Unsaved", "visuallyDisabled": undefined, }, + Object { + "data": MockEntityRecord { + "getNamedReference": [MockFunction], + "id": "8", + "values": Object { + "ItemColor": "#C8A2C8", + "ItemIcon": "AddFriend", + "ItemKey": "Item 8", + "ItemLabel": "item8", + "ItemState": "Custom", + }, + }, + "disabled": undefined, + "id": "8", + "itemColor": "#C8A2C8", + "itemIcon": "AddFriend", + "key": "Item 8", + "label": "item8", + "parentId": undefined, + "state": "Custom", + "visuallyDisabled": undefined, + }, + Object { + "data": MockEntityRecord { + "getNamedReference": [MockFunction], + "id": "9", + "values": Object { + "ItemColor": "#EE82EE", + "ItemIcon": "AddTo", + "ItemKey": "Item 9", + "ItemLabel": "item8", + "ItemState": "Custom", + }, + }, + "disabled": undefined, + "id": "9", + "itemColor": "#EE82EE", + "itemIcon": "AddTo", + "key": "Item 9", + "label": "item8", + "parentId": undefined, + "state": "Custom", + "visuallyDisabled": undefined, + }, ] } onSelected={[Function]} @@ -155,6 +213,8 @@ exports[`SubwayNav renders dummy items when no items configured 1`] = ` Array [ Object { "id": "1", + "itemColor": "", + "itemIcon": "", "key": "1", "label": "Node 1", "parentId": undefined, @@ -162,6 +222,8 @@ exports[`SubwayNav renders dummy items when no items configured 1`] = ` }, Object { "id": "2", + "itemColor": "", + "itemIcon": "", "key": "2", "label": "Node 2", "parentId": undefined, @@ -169,6 +231,8 @@ exports[`SubwayNav renders dummy items when no items configured 1`] = ` }, Object { "id": "3", + "itemColor": "", + "itemIcon": "", "key": "3", "label": "Node 3", "parentId": undefined, @@ -176,6 +240,8 @@ exports[`SubwayNav renders dummy items when no items configured 1`] = ` }, Object { "id": "4", + "itemColor": "", + "itemIcon": "", "key": "4", "label": "Node 4", "parentId": undefined, diff --git a/SubwayNav/SubwayNav/_test_/datasetmapping.test.ts b/SubwayNav/SubwayNav/_test_/datasetmapping.test.ts index adfd33ed..3cbf2044 100644 --- a/SubwayNav/SubwayNav/_test_/datasetmapping.test.ts +++ b/SubwayNav/SubwayNav/_test_/datasetmapping.test.ts @@ -28,20 +28,34 @@ describe('DatasetMapping', () => { [ItemColumns.State]: 'ViewedNotCompleted', }), new MockEntityRecord('5', { - [ItemColumns.Key]: 'Item 4', - [ItemColumns.Label]: 'item4', + [ItemColumns.Key]: 'Item 5', + [ItemColumns.Label]: 'item5', [ItemColumns.State]: 'Error', }), new MockEntityRecord('6', { - [ItemColumns.Key]: 'Item 4', - [ItemColumns.Label]: 'item4', + [ItemColumns.Key]: 'Item 6', + [ItemColumns.Label]: 'item6', [ItemColumns.State]: 'Skipped', }), new MockEntityRecord('7', { - [ItemColumns.Key]: 'Item 4', - [ItemColumns.Label]: 'item4', + [ItemColumns.Key]: 'Item 7', + [ItemColumns.Label]: 'item7', [ItemColumns.State]: 'Unsaved', }), + new MockEntityRecord('8', { + [ItemColumns.Key]: 'Item 8', + [ItemColumns.Label]: 'item8', + [ItemColumns.State]: 'Custom', + [ItemColumns.ItemIcon]: 'AddFriend', + [ItemColumns.ItemColor]: '#C8A2C8', + }), + new MockEntityRecord('9', { + [ItemColumns.Key]: 'Item 9', + [ItemColumns.Label]: 'item8', + [ItemColumns.State]: 'Custom', + [ItemColumns.ItemIcon]: 'AddTo', + [ItemColumns.ItemColor]: '#EE82EE', + }), ]; const actions = getItemsFromDataset(new MockDataSet(items)); diff --git a/SubwayNav/SubwayNav/_test_/subwaynav-lifecycle.test.ts b/SubwayNav/SubwayNav/_test_/subwaynav-lifecycle.test.ts index b347f3ad..f933b7bc 100644 --- a/SubwayNav/SubwayNav/_test_/subwaynav-lifecycle.test.ts +++ b/SubwayNav/SubwayNav/_test_/subwaynav-lifecycle.test.ts @@ -48,7 +48,7 @@ describe('SubwayNav', () => { const subwayNavElement = component.updateView(context); const subwayNav = shallow(subwayNavElement); const subwayNavSteps = subwayNav.find(CustomSubwayNav).props().steps; - expect(subwayNavSteps.length).toEqual(7); + expect(subwayNavSteps.length).toEqual(9); }); it('Analyse theme', () => { @@ -138,6 +138,20 @@ function createComponent() { [ItemColumns.Label]: 'item4', [ItemColumns.State]: 'Unsaved', }), + new MockEntityRecord('8', { + [ItemColumns.Key]: 'Item 8', + [ItemColumns.Label]: 'item8', + [ItemColumns.State]: 'Custom', + [ItemColumns.ItemIcon]: 'AddFriend', + [ItemColumns.ItemColor]: '#C8A2C8', + }), + new MockEntityRecord('9', { + [ItemColumns.Key]: 'Item 9', + [ItemColumns.Label]: 'item8', + [ItemColumns.State]: 'Custom', + [ItemColumns.ItemIcon]: 'AddTo', + [ItemColumns.ItemColor]: '#EE82EE', + }), ]); context.parameters.Theme.raw = JSON.stringify({ palette: { diff --git a/SubwayNav/SubwayNav/components/CanvasSubwayNav.tsx b/SubwayNav/SubwayNav/components/CanvasSubwayNav.tsx index 1000a313..6f2f07e7 100644 --- a/SubwayNav/SubwayNav/components/CanvasSubwayNav.tsx +++ b/SubwayNav/SubwayNav/components/CanvasSubwayNav.tsx @@ -27,6 +27,7 @@ const ariaLabelStrings = { Skipped: 'Skipped', Error: 'Error', WizardComplete: 'Wizard Complete', + Custom: 'Custom', }; export const CanvasSubwayNav = React.memo((props: ISubNavProps): React.ReactElement => { @@ -114,6 +115,8 @@ export const CanvasSubwayNav = React.memo((props: ISubNavProps): React.ReactElem onClickStep, index: 10, isVisuallyDisabled: item.visuallyDisabled ?? false, + itemIcon: item.itemIcon, + itemColor: item.itemColor, }; }); return { @@ -130,6 +133,8 @@ export const CanvasSubwayNav = React.memo((props: ISubNavProps): React.ReactElem onClickStep, index: 10, isVisuallyDisabled: group.visuallyDisabled ?? false, + itemIcon: group.itemIcon, + itemColor: group.itemColor, }; }) as unknown as ISubwayNavNodeProps[]; return allSteps; diff --git a/SubwayNav/SubwayNav/components/DatasetMapping.ts b/SubwayNav/SubwayNav/components/DatasetMapping.ts index 4bc98c2c..dd8454cb 100644 --- a/SubwayNav/SubwayNav/components/DatasetMapping.ts +++ b/SubwayNav/SubwayNav/components/DatasetMapping.ts @@ -24,6 +24,8 @@ export function getItemsFromDataset(dataset: ComponentFramework.PropertyTypes.Da disabled: record.getValue(ItemColumns.Disabled), parentId: record.getValue(ItemColumns.ParentKey), visuallyDisabled: record.getValue(ItemColumns.VisuallyDisabled), + itemIcon: record.getValue(ItemColumns.ItemIcon), + itemColor: record.getValue(ItemColumns.ItemColor), data: record, } as ISubNavItem; }); @@ -42,6 +44,8 @@ export function getDatasetfromItems(steps: ISubwayNavNodeProps[]): ICustomSubway ItemDisabled: subStep.disabled, ParentItemKey: subStep.parentId, ItemVisuallyDisabled: subStep.isVisuallyDisabled, + ItemIcon: subStep.itemIcon, + ItemColor: subStep.itemColor, } as ICustomSubwayNavProps; }), ); @@ -53,6 +57,8 @@ export function getDatasetfromItems(steps: ISubwayNavNodeProps[]): ICustomSubway ItemDisabled: step.disabled, ParentItemKey: step.parentId, ItemVisuallyDisabled: step.isVisuallyDisabled, + ItemIcon: step.itemIcon, + ItemColor: step.itemColor, } as ICustomSubwayNavProps; }); return [...parentstepDateSet, ...stepDataSet]; @@ -65,6 +71,8 @@ function getDummyAction(id: string): ISubNavItem { key: id, parentId: id === '5' ? '2' : undefined, state: id === '1' ? 'Current' : 'Not Started', + itemIcon: '', + itemColor: '', } as ISubNavItem; } @@ -88,6 +96,8 @@ export function getSubwayNavNodeState(state: string): SubwayNavNodeState { return SubwayNavNodeState.CurrentWithSubSteps; case 'WizardComplete': return SubwayNavNodeState.WizardComplete; + case 'Custom': + return SubwayNavNodeState.Custom; default: return SubwayNavNodeState.NotStarted; } diff --git a/SubwayNav/SubwayNav/components/StepSchema.ts b/SubwayNav/SubwayNav/components/StepSchema.ts index 11f3a2fe..53274872 100644 --- a/SubwayNav/SubwayNav/components/StepSchema.ts +++ b/SubwayNav/SubwayNav/components/StepSchema.ts @@ -17,6 +17,8 @@ const stepDetails = { ItemDisabled: { type: 'boolean' }, ItemVisuallyDisabled: { type: 'boolean' }, ParentItemKey: { type: 'string' }, + ItemIcon: { type: 'string' }, + ItemColor: { type: 'string' }, }, }; diff --git a/SubwayNav/SubwayNav/components/components.types.ts b/SubwayNav/SubwayNav/components/components.types.ts index a9758f6d..2ee351bb 100644 --- a/SubwayNav/SubwayNav/components/components.types.ts +++ b/SubwayNav/SubwayNav/components/components.types.ts @@ -11,6 +11,8 @@ export interface ISubNavItem { disabled?: boolean; data: any; visuallyDisabled?: boolean; + itemIcon: string; + itemColor: string; } export interface ICustomSubwayNavProps { @@ -20,6 +22,8 @@ export interface ICustomSubwayNavProps { ItemDisabled?: boolean; ParentItemKey?: string; ItemVisuallyDisabled?: boolean; + ItemIcon: string; + ItemColor: string; } export interface ISubNavProps { diff --git a/SubwayNav/SubwayNav/utilities/subway-nav/subway-node.types.ts b/SubwayNav/SubwayNav/utilities/subway-nav/subway-node.types.ts index f372131e..962e59ee 100644 --- a/SubwayNav/SubwayNav/utilities/subway-nav/subway-node.types.ts +++ b/SubwayNav/SubwayNav/utilities/subway-nav/subway-node.types.ts @@ -35,6 +35,16 @@ export interface ISubwayNavNodeProps extends React.AllHTMLAttributes { disabled = false, isVisuallyDisabled = false, state, + itemIcon, + itemColor, subSteps, index, rootAs, @@ -36,7 +38,8 @@ export class SubwayNodeBase extends React.Component { onRenderStepIcon = this._onRenderStepIcon, } = this.props; - const iconRecord: IIconRecord | undefined = getIcon(getIconMap(isSubStep ?? false)[state]); + const iconMap = getIcon(getIconMap(isSubStep ?? false, itemIcon)[state]); + const iconRecord: IIconRecord | undefined = iconMap || getIcon(getIconMap(isSubStep ?? false, "")[state]); const buttonProps = getNativeProps>(this.props, buttonProperties); @@ -45,6 +48,8 @@ export class SubwayNodeBase extends React.Component { disabled: disabled, isVisuallyDisabled: disabled && isVisuallyDisabled, state, + itemIcon, + itemColor, iconRecord: iconRecord!, hasSubSteps: subSteps ? subSteps.length > 0 : false, index: index!, diff --git a/SubwayNav/SubwayNav/utilities/subway-node/subway-node.styles.ts b/SubwayNav/SubwayNav/utilities/subway-node/subway-node.styles.ts index 04d5272c..e412c518 100644 --- a/SubwayNav/SubwayNav/utilities/subway-node/subway-node.styles.ts +++ b/SubwayNav/SubwayNav/utilities/subway-node/subway-node.styles.ts @@ -16,7 +16,7 @@ export const itemSpacing = 27; export const largeSubwayNavIconSize = 16; export const smallSubwayNavIconSize = 8; -export const getIconMap = (isSubStep: boolean): SubwayNavStateMap => { +export const getIconMap = (isSubStep: boolean, Icon: string): SubwayNavStateMap => { return isSubStep ? { Completed: IconNames.StatusCircleCheckMark, @@ -28,6 +28,7 @@ export const getIconMap = (isSubStep: boolean): SubwayNavStateMap => { Unsaved: IconNames.FullCircleMask, ViewedNotCompleted: IconNames.FullCircleMask, WizardComplete: IconNames.StatusCircleCheckMark, + Custom: !Icon ? IconNames.FullCircleMask : Icon, } : { Completed: IconNames.CompletedSolid, @@ -39,10 +40,11 @@ export const getIconMap = (isSubStep: boolean): SubwayNavStateMap => { Unsaved: IconNames.FullCircleMask, ViewedNotCompleted: IconNames.FullCircleMask, WizardComplete: IconNames.CompletedSolid, + Custom: !Icon ? IconNames.FullCircleMask : Icon, }; }; -export const getIconColorMap = (isSubStep: boolean, theme: IM365Theme): IconColorMap => { +export const getIconColorMap = (isSubStep: boolean, theme: IM365Theme, prefferedColor: string): IconColorMap => { return isSubStep ? { Completed: throwOnUndefinedColor(theme.semanticColors.stepCompleted, 'stepCompleted', 'SubwayNode'), @@ -58,6 +60,8 @@ export const getIconColorMap = (isSubStep: boolean, theme: IM365Theme): IconColo 'allStepsComplete', 'SubwayNode', ), + Custom: !prefferedColor ? throwOnUndefinedColor(theme.semanticColors.stepCurrent, 'stepCurrent', 'SubwayNode') : + throwOnUndefinedColor(prefferedColor, 'ItemColor', 'UserInput'), } : { Completed: throwOnUndefinedColor(theme.semanticColors.stepCompleted, 'stepCompleted', 'SubwayNode'), @@ -77,6 +81,8 @@ export const getIconColorMap = (isSubStep: boolean, theme: IM365Theme): IconColo 'allStepsComplete', 'SubwayNode', ), + Custom: !prefferedColor ? throwOnUndefinedColor(theme.semanticColors.stepCurrent, 'stepCurrent', 'SubwayNode') : + throwOnUndefinedColor(prefferedColor, 'ItemColor', 'UserInput'), }; }; @@ -91,11 +97,12 @@ export const getIconRingColorMap = (theme: IM365Theme): IconRingColorMap => { Unsaved: theme.palette.accent, ViewedNotCompleted: 'transparent', WizardComplete: 'transparent', + Custom: 'transparent', }; }; export const getSubwayNodeStyles = (props: ISubwayNavNodeStyleProps): ISubwayNavNodeStyles => { - const { disabled, isVisuallyDisabled, isSubStep, iconRecord, state, theme } = props; + const { disabled, isVisuallyDisabled, isSubStep, iconRecord, state, itemColor, theme } = props; const options: IGetFocusStylesOptions = { inset: undefined, position: undefined, @@ -105,6 +112,7 @@ export const getSubwayNodeStyles = (props: ISubwayNavNodeStyleProps): ISubwayNav borderColor: 'transparent', outlineColor: undefined, }; + const iconColorMap = getIconColorMap(isSubStep, theme, itemColor)[state]; const useSelectedStyle: boolean = state === SubwayNavNodeState.Current || state === SubwayNavNodeState.CurrentWithSubSteps; @@ -156,7 +164,7 @@ export const getSubwayNodeStyles = (props: ISubwayNavNodeStyleProps): ISubwayNav icon: [ iconRecord?.subset.className, { - fill: visualDisabledBehavior(getIconColorMap(isSubStep, theme)[state]), + fill: visualDisabledBehavior(iconColorMap || getIconColorMap(isSubStep, theme, "")[state]), fontSize: iconSize, }, ], diff --git a/SubwayNav/SubwayNav/utilities/subway-node/subway-node.types.ts b/SubwayNav/SubwayNav/utilities/subway-node/subway-node.types.ts index f372131e..5ff5c1cd 100644 --- a/SubwayNav/SubwayNav/utilities/subway-node/subway-node.types.ts +++ b/SubwayNav/SubwayNav/utilities/subway-node/subway-node.types.ts @@ -35,6 +35,16 @@ export interface ISubwayNavNodeProps extends React.AllHTMLAttributes