Skip to content

Commit

Permalink
Merge pull request #20 from ORBISAG/feature/icons
Browse files Browse the repository at this point in the history
Feature/icons
  • Loading branch information
brasov2de authored Apr 20, 2022
2 parents fd4898e + fd39af2 commit decfa85
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 35 deletions.
5 changes: 3 additions & 2 deletions Control/ColorfulOptionset/CSS/ColorfulOptionset.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

.ORBIS\.ColorfulOptionset .ComboBox{
/*.ORBIS\.ColorfulOptionset .ComboBox{
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
Expand All @@ -10,7 +10,8 @@
outline-width: 0;
outline-style: none;
box-shadow: none;
}
width:100%;
}*/

.ORBIS\.ColorfulOptionset .ComboBox .option{
text-align: left;
Expand Down
53 changes: 36 additions & 17 deletions Control/ColorfulOptionset/ColorfulOptionsetControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,18 @@ import { Icon} from "@fluentui/react/lib/Icon";
import {ISelectableOption} from "@fluentui/react/lib/SelectableOption";
import {dropdownStyles, myTheme} from "./DropdownStyles";

export interface ISetupSchemaValue{
icon ?: string;
color ?: string;
}
export interface ISetupSchema{
[value: string] : ISetupSchemaValue;
}

export interface IConfig{
jsonConfig: ISetupSchema | undefined;
defaultIconName : string;
}

/*
//IComboBoxOption[]
Expand All @@ -23,36 +34,44 @@ interface IColorfulOptionsetProperties {
onChange: (value: number|null) => void
isDisabled : boolean;
defaultValue : number | undefined;
config: IConfig;
}



const _renderOption =(option: ISelectableOption | undefined, className ?:string) : JSX.Element => {
return (
<div className={className}>
<Icon className="colorIcon" style={{color: option?.data?.color || "#ffffff", marginRight: "8px"}} iconName="CircleShapeSolid" aria-hidden="true" />
<span>{option?.text || ""}</span>
</div>
);
}

const _onRenderOption = (option: ISelectableOption | undefined): JSX.Element => {
return _renderOption(option, "ORBIS_ColorfulOptionset_item")
};

const _onRenderTitle = (options: IDropdownOption[] | undefined): JSX.Element => {
const option = (options || [])[0];
return _renderOption(option, "option");

};


//export default class ColorfulOptionsetControl extends React.Component<IColorfulOptionsetProperties, {}> {
export const ColorfulOptionsetControl = ({options, selectedKey, onChange, isDisabled, defaultValue}:IColorfulOptionsetProperties): JSX.Element =>{
export const ColorfulOptionsetControl = ({options, selectedKey, onChange, isDisabled, defaultValue, config}:IColorfulOptionsetProperties): JSX.Element =>{

const _onSelectedChanged = (event: any, option?: IDropdownOption) => {
const val = (option?.key == null || option?.key===-1) ? null : option?.key as number;
onChange(val);
}

const _renderOption =(option: ISelectableOption | undefined, className ?:string) : JSX.Element => {
const icon = ((config.jsonConfig && option?.key) ? config.jsonConfig[option?.key]?.icon : config.defaultIconName) ?? config.defaultIconName;
const defaultColor = option?.data?.color || "#ffffff";
const color = ((config.jsonConfig && option?.key) ? config.jsonConfig[option?.key]?.color : defaultColor) ?? defaultColor;
return (
<div className={className}>
<Icon className="colorIcon" style={{color: color, marginRight: "8px"}} iconName={icon} aria-hidden="true" />
<span>{option?.text || ""}</span>
</div>
);
}

const _onRenderOption = (option: ISelectableOption | undefined): JSX.Element => {
return _renderOption(option, "ORBIS_ColorfulOptionset_item")
};

const _onRenderTitle = (options: IDropdownOption[] | undefined): JSX.Element => {
const option = (options || [])[0];
return _renderOption(option, "option");

};

return (
<Dropdown
Expand Down
9 changes: 7 additions & 2 deletions Control/ColorfulOptionset/ControlManifest.Input.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<manifest>
<control namespace="ORBIS" constructor="ColorfulOptionset" version="0.0.6" display-name-key="ORBIS.ColorfulOptionset" description-key="ColorfulOptionset description" control-type="virtual">
<property name="optionsInput" display-name-key="Property_Display_Key" description-key="Property_Desc_Key" of-type="OptionSet" usage="bound" required="true" />
<control namespace="ORBIS" constructor="ColorfulOptionset" version="0.0.7" display-name-key="ORBIS.ColorfulOptionset" description-key="ColorfulOptionset description" control-type="virtual">
<property name="optionsInput" display-name-key="OptionSet" description-key="OptionSet" of-type="OptionSet" usage="bound" required="true" />
<property name="icon" display-name-key="Icon" description-key="Icon" of-type="SingleLine.Text" usage="input" required="false" />
<property name="sortBy" display-name-key="Sort by" description-key="Sort by" of-type="Enum" usage="input" required="true" >
<value name="VALUE" display-name-key="Value" description-key="Sort by the value of the options" default="true">VALUE</value>
<value name="TEXT" display-name-key="Text" description-key="Sort by the text of the options, corresponding to the user language">TEXT</value>
</property>
<resources>
<code path="index.ts" order="1"/>
<css path="css/ColorfulOptionset.css" order="1" />
Expand Down
10 changes: 9 additions & 1 deletion Control/ColorfulOptionset/DropdownStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,21 @@ export const dropdownStyles = (props: IDropdownStyleProps):Partial<IDropdownStyl
boxShadow: "none"
}
}
}],
}],
root: {
width: "100%"
},
dropdown: [{

appearance: "none",
outline: "none",
border: "1px solid transparent",
outlineColor: "transparent",
outlineWidth: "0",
outlineStyle : "none",
outlineOffset: "0",
boxShadow: "none",
width: "100%",
selectors:{
":focus:after": {
outline: "none",
Expand Down
40 changes: 27 additions & 13 deletions Control/ColorfulOptionset/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {IInputs, IOutputs} from "./generated/ManifestTypes";
import { IDropdownOption } from "@fluentui/react/lib/Dropdown";
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {ColorfulOptionsetControl} from "./ColorfulOptionsetControl";
import {ColorfulOptionsetControl, IConfig, ISetupSchema} from "./ColorfulOptionsetControl";



Expand Down Expand Up @@ -33,6 +33,8 @@ const DEFAULT_OPTIONS : ComponentFramework.PropertyHelper.OptionMetadata[] = [{
}
];



export class ColorfulOptionset implements ComponentFramework.ReactControl<IInputs, IOutputs> {

private allOptions : ComponentFramework.PropertyHelper.OptionMetadata[];
Expand All @@ -44,12 +46,24 @@ export class ColorfulOptionset implements ComponentFramework.ReactControl<IInput
private currentValue: number | null;
private notifyOutputChanged: () => void;

private config : IConfig | undefined;


constructor()
{

}


private parseIconConfig(defaultIcon : string, iconConfig ?: string): IConfig{
const isJSON = iconConfig && iconConfig.includes("{");
this.config = {
jsonConfig : isJSON === true ? JSON.parse(iconConfig as string) as ISetupSchema : undefined,
defaultIconName : (!isJSON ? iconConfig : defaultIcon) ?? defaultIcon
}
return this.config;
}

/**
* Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
* Data-set values are not initialized here, use updateView.
Expand All @@ -61,14 +75,7 @@ export class ColorfulOptionset implements ComponentFramework.ReactControl<IInput
public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container:HTMLDivElement)
{

console.log("using virtual control in ColorfulOptionset");
let opts = context.parameters.optionsInput.attributes!.Options;
//todo
/*if(opts?.length === 3){
opts = DEFAULT_OPTIONS;
} */
this.allOptions = [{Label: "--Select--", Value: -1, Color: "transparent"}, ...opts];
this.dropdownOptions = this.allOptions.map((option : ComponentFramework.PropertyHelper.OptionMetadata ) => ({key: option.Value, text : option.Label, data: {color: option.Color}}) )
console.log("using virtual control in ColorfulOptionset");
this.defaultValue = context.parameters.optionsInput.attributes?.DefaultValue;

this.container = container;
Expand All @@ -78,9 +85,15 @@ export class ColorfulOptionset implements ComponentFramework.ReactControl<IInput

private renderControl(context: ComponentFramework.Context<IInputs>) : React.ReactElement {


this.allOptions = [{Label: "--Select--", Value: -1, Color: "transparent"}, ...context.parameters.optionsInput.attributes!.Options];
this.dropdownOptions = this.allOptions
.map((option : ComponentFramework.PropertyHelper.OptionMetadata ) => ({key: option.Value, text : option.Label, data: {color: option.Color}}) )
if(context.parameters.sortBy?.raw==="TEXT"){
this.dropdownOptions = this.dropdownOptions.sort((a, b) =>a.text.localeCompare(b.text));
}

this.isDisabled = context.mode.isControlDisabled;
this.currentValue = context.parameters.optionsInput.raw;
this.currentValue = context.parameters.optionsInput.raw;
let params = {
options: this.dropdownOptions,
selectedKey: this.currentValue,
Expand All @@ -89,7 +102,8 @@ export class ColorfulOptionset implements ComponentFramework.ReactControl<IInput
this.notifyOutputChanged();
},
isDisabled : this.isDisabled,
defaultValue : this.defaultValue
defaultValue : this.defaultValue,
config: this.config ?? this.parseIconConfig("CircleShapeSolid", context.parameters.icon?.raw ?? undefined)
};
return React.createElement(ColorfulOptionsetControl, params );

Expand Down Expand Up @@ -122,5 +136,5 @@ export class ColorfulOptionset implements ComponentFramework.ReactControl<IInput
*/
public destroy(): void
{
}
}
}
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,51 @@ This control is designed for Optionset attribute types. In order to define the c
![colors](./readmeContent/CustomizingColors.png)


## Icons

To customize the icons, you can choose the icons from the [FluentUI Icons](https://uifabricicons.azurewebsites.net/)

Just define it for the icon parameter. If not, the default will be the "dot".
![customizing](./readmeContent/CustomizingIcon.png)


![icons](./readmeContent/Icons%20and%20Sort.png)

### Different icons
If you need different icons for different options, you can specify a JSON for the icon parameter. The structure will be {value: {icon, color}}
Here is an example
```javascript
{"434350002": {"icon": "Sad", "color": "#ff0000"},
"434350001": { "color": "orange"},
"434350000":{"icon":"Emoji2"}}
```

- If the "color" is not specified, the color from the Options Metadata will be taken.
- If the "icon" is missing, the "dot" will be shown
- You can specify both "icon" and "color" for each option
- You cal leave options not being defined. In that case the fallbacks will be applied.

It will look something like this:

![configJSON](./readmeContent/CustomizingIconWith%20JSON.png)
Here is the result of the above configuration (yellow has no icon, so it takes the default):
![IconsAndColos](./readmeContent/Icons%20and%20Colors.png)


# Sort by

Usually the OptionSet (Choice) will list the options in the order defined in the customizing. That will be the default also for ColorfulOptionSet component.
But if you would like to have it sorted by "text", so every user is getting the options alphabetically sorted (doesn't matter which language she/he uses), you can define it by choosing: "Sort by" "Text".

![sortBy](./readmeContent/CustomizingSortBy.png)

Here is the standard sorting in a out of the box OptionSet control(by Value):
![standrad sorting](./readmeContent//Stadard%20Sort.png)

Here is the "Text" sorting in ColorfulOptionSet
![text sorting](./readmeContent/Icons%20and%20Sort.png)


## License

[MIT](./LICENSE)
Binary file added readmeContent/CustomizingIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readmeContent/CustomizingIconWith JSON.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readmeContent/CustomizingSortBy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readmeContent/Icons and Colors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readmeContent/Icons and Sort.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readmeContent/Stadard Sort.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit decfa85

Please sign in to comment.