Skip to content

Commit

Permalink
feat: Add content switcher component (#142)
Browse files Browse the repository at this point in the history
* Add content-switcher

* Add UI-content-switcher file

* Add exports for content-switcher

* Lint alittle

* Lint alittle

* Add svg for content-switcher

* Fix indentation

* Lint alittle

* Update src/fragment-components/a-content-switcher.tsx

Co-authored-by: Akshat Patel <[email protected]>

* Update src/fragment-components/a-content-switcher.tsx

Co-authored-by: Akshat Patel <[email protected]>

* Add notice for size input on angular code export

* Add size prop to angular export

Signed-off-by: Moiz Masud <[email protected]>

* Update carbon-components-angular package version

Signed-off-by: Moiz Masud <[email protected]>

* Update content-switcher.svg

* Update content-switcher.svg

* Update src/fragment-components/a-content-switcher.tsx

Co-authored-by: Akshat Patel <[email protected]>

* Update src/fragment-components/a-content-switcher.tsx

Co-authored-by: Akshat Patel <[email protected]>

* Change updateItem function name

Signed-off-by: Moiz Masud <[email protected]>

Signed-off-by: Moiz Masud <[email protected]>
Co-authored-by: Moiz Masud <[email protected]>
Co-authored-by: Akshat Patel <[email protected]>
  • Loading branch information
3 people authored Dec 1, 2022
1 parent 1d8cce0 commit 40b1998
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/assets/component-icons/content-switcher.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
227 changes: 227 additions & 0 deletions src/fragment-components/a-content-switcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
import React from 'react';
import {
Checkbox,
TextInput,
Dropdown,
ContentSwitcher,
Switch
} from 'carbon-components-react';
import { AComponent, ComponentInfo } from './a-component';
import { DraggableTileList } from '../components';
import image from './../assets/component-icons/content-switcher.svg';
import {
angularClassNamesFromComponentObj,
nameStringToVariableString,
reactClassNamesFromComponentObj
} from '../utils/fragment-tools';
import { css, cx } from 'emotion';

const preventCheckEvent = css`
pointer-events: none;
`;

export const AContentSwitcherSettingsUI = ({ selectedComponent, setComponent }: any) => {
const sizeItems = [
{ id: 'sm', text: 'Small' },
{ id: 'md', text: 'Medium' },
{ id: 'lg', text: 'Large' }
];

const selectedItems = selectedComponent.items.map((step: any, index: number) => ({ id: index, text: step.text }));

const updateItem = (key: string, value: any, index: number) => {
const step = {
...selectedComponent.items[index],
[key]: value
};

setComponent({
...selectedComponent,
items: [
...selectedComponent.items.slice(0, index),
step,
...selectedComponent.items.slice(index + 1)
]
});
};

const updateStepList = (newList: any[]) => {
setComponent({
...selectedComponent,
items: newList
});
};

const template = (item: any, index: number) => {
return <>
<TextInput
light
value={item.text}
labelText='Text'
onChange={(event: any) => {
updateItem('text', event.currentTarget.value, index);
}} />
<Checkbox
labelText='Disabled'
id={`disabled-${index}`}
checked={selectedComponent.disabled}
onChange={(checked: boolean) => {
updateItem('disabled', checked, index);
}} />
</>;
};

return <>
<Dropdown
id='content-switcher-size'
label='Size'
titleText='Size'
items={sizeItems}
selectedItem={sizeItems.find(item => item.id === selectedComponent.size)}
itemToString={(item: any) => (item ? item.text : '')}
onChange={(event: any) => setComponent({
...selectedComponent,
size: event.selectedItem.id
})} />
<Dropdown
id='selected-item'
label='Selected content'
titleText='Selected content'
items={selectedItems}
selectedItem={selectedItems.find((item: any) => item.id === selectedComponent.selectedIndex)}
itemToString={(item: any) => (item ? item.text : '')}
onChange={(event: any) => setComponent({
...selectedComponent,
selectedIndex: event.selectedItem.id
})} />
<DraggableTileList
dataList={[...selectedComponent.items]}
setDataList={updateStepList}
updateItem={updateItem}
defaultObject={{
type: 'switch-item',
disabled: false,
name: 'new-option',
text: 'New option'
}}
template={template} />
</>;
};

export const AContentSwitcherCodeUI = ({ selectedComponent, setComponent }: any) => <TextInput
value={selectedComponent.codeContext?.name}
labelText='Input name'
onChange={(event: any) => {
setComponent({
...selectedComponent,
codeContext: {
...selectedComponent.codeContext,
name: event.currentTarget.value
}
});
}}
/>;

export const AContentSwitcher = ({
componentObj,
...rest
}: any) => {
return (
<AComponent
componentObj={componentObj}
{...rest}>
<ContentSwitcher
size={componentObj.size}
selectedIndex={componentObj.selectedIndex}
className={cx(preventCheckEvent, componentObj.cssClasses?.map((cc: any) => cc.id).join(' '))}>
{
componentObj.items.map((step: any, index: number) => <Switch
className={step.className}
name={step.name}
text={step.text}
disabled={step.disabled}
key={index} />
)
}
</ContentSwitcher>
</AComponent>
);
};

export const componentInfo: ComponentInfo = {
component: AContentSwitcher,
settingsUI: AContentSwitcherSettingsUI,
codeUI: AContentSwitcherCodeUI,
keywords: ['content', 'switcher'],
name: 'Content switcher',
type: 'content-switcher',
defaultComponentObj: {
type: 'content-switcher',
size: 'sm',
selectedIndex: 0,
items: [
{
name: 'first',
text: 'First section',
disabled: false,
type: 'switch-item'
},
{
name: 'second',
text: 'Second section',
disabled: false,
type: 'switch-item'
},
{
name: 'third',
text: 'Third section',
disabled: false,
type: 'switch-item'
}
]
},
image,
codeExport: {
angular: {
inputs: ({ json }) => `@Input() ${nameStringToVariableString(json.codeContext?.name)}Size = "${json.size}";`,
outputs: ({ json }) => `@Output() ${nameStringToVariableString(json.codeContext?.name)}Selected = new EventEmitter();`,
imports: ['ContentSwitcherModule'],
code: ({ json }) => {
return `<ibm-content-switcher
[size]="${nameStringToVariableString(json.codeContext?.name)}Size"
${angularClassNamesFromComponentObj(json)}
(selected)="${nameStringToVariableString(json.codeContext?.name)}Selected.emit()">
${json.items.map((step: any, index: number) => `<button
${json.selectedIndex === index ? `active="${json.selectedIndex === index}"` : ''}
ibmContentOption
name="${step.name}"
[disabled]="${step.disabled}">
${step.text}
</button>`
).join('\n')}
</ibm-content-switcher>`;
}
},
react: {
imports: ['ContentSwitcher', 'Switch'],
code: ({ json }) => {
return `<ContentSwitcher
size="${json.size}"
selectedIndex={state["${nameStringToVariableString(json.codeContext?.name)}"] || ${json.selectedIndex}}
${reactClassNamesFromComponentObj(json)}
onChange={(selectedItem) => handleInputChange({
target: {
name: "${nameStringToVariableString(json.codeContext?.name)}",
value: selectedItem.index
}
})}>
${json.items.map((step: any) => `<Switch
name="${step.name}"
text="${step.text}"
disabled={${step.disabled}}/>`
).join('\n')}
</ContentSwitcher>`;
}
}
}
};
3 changes: 3 additions & 0 deletions src/fragment-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as checkbox from './a-checkbox';
import * as codeSnippet from './a-code-snippet';
import * as column from './a-column';
import * as combobox from './a-combobox';
import * as contentSwitcher from './a-content-switcher';
import * as dropdown from './a-dropdown';
import * as fragment from './a-fragment';
import * as grid from './a-grid';
Expand Down Expand Up @@ -42,6 +43,7 @@ export { ACodeSnippet, ACodeSnippetSettingsUI, ACodeSnippetCodeUI } from './a-co
export { ACheckbox, ACheckboxSettingsUI, ACheckboxCodeUI } from './a-checkbox';
export { AColumn, AColumnSettingsUI } from './a-column';
export { AComboBox, AComboBoxSettingsUI, AComboBoxCodeUI } from './a-combobox';
export { AContentSwitcher, AContentSwitcherSettingsUI, AContentSwitcherCodeUI } from './a-content-switcher';
export { ADropdown, ADropdownSettingsUI, ADropdownCodeUI } from './a-dropdown';
export * from './a-component';
export { AFragment, AFragmentSettingsUI, AFragmentCodeUI } from './a-fragment';
Expand Down Expand Up @@ -79,6 +81,7 @@ export const allComponents = {
checkbox,
codeSnippet,
combobox,
contentSwitcher,
column,
dropdown,
fragment,
Expand Down
37 changes: 37 additions & 0 deletions src/ui-fragment/src/components/ui-content-switcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { ContentSwitcher, Switch } from 'carbon-components-react';
import { CssClasses } from '../types';

export interface ContentSwitcherState {
type: string;
items: [];
size: [];
selectedIndex: number;
cssClasses?: CssClasses[];
}

export const UIContentSwitcher = ({ state }: {
state: ContentSwitcherState;
setState: (state: any) => void;
setGlobalState: (state: any) => void;
}) => {
if (state.type !== 'content-switcher') {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <></>;
}

return <ContentSwitcher
size={state.size}
selectedIndex={state.selectedIndex}
className={state.cssClasses?.map((cc: any) => cc.id).join(' ')}>
{
state.items.map((step: any, index: number) => <Switch
className={step.className}
name={step.name}
text={step.text}
disabled={step.disabled}
key={index}
/>)
}
</ContentSwitcher>;
};
4 changes: 4 additions & 0 deletions src/ui-fragment/src/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { UIClickableTile } from './components/ui-clickable-tile';
import { UICodeSnippet } from './components/ui-code-snippet';
import { UIColumn } from './components/ui-column';
import { UIComboBox } from './components/ui-combobox';
import { UIContentSwitcher } from './components/ui-content-switcher';
import { UIDropdown } from './components/ui-dropdown';
import { UIExpandableTile } from './components/ui-expandable-tile';
import { UIGrid } from './components/ui-grid';
Expand Down Expand Up @@ -138,6 +139,9 @@ export const renderComponents = (state: any, setState: (state: any) => void, set
case 'combobox':
return <UIComboBox key={state.id} state={state} setState={setState} setGlobalState={setGlobalState} />;

case 'content-switcher':
return <UIContentSwitcher key={state.id} state={state} setState={setState} setGlobalState={setGlobalState} />;

case 'dropdown':
return <UIDropdown key={state.id} state={state} setState={setState} setGlobalState={setGlobalState} />;

Expand Down

0 comments on commit 40b1998

Please sign in to comment.