Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
toCamelCase,
getRGBAFromString,
getHexFromRGBA,
changeAlpha,
shadeColor,
InteractiveVariation,
getInteractiveVariants,
Expand All @@ -30,6 +31,7 @@ export = {
toCamelCase,
getRGBAFromString,
getHexFromRGBA,
changeAlpha,
shadeColor,
InteractiveVariation,
getInteractiveVariants,
Expand Down
1 change: 1 addition & 0 deletions packages/private/test-utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './expects';
export * from './dom';
export * from './styles';
7 changes: 7 additions & 0 deletions packages/private/test-utils/src/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function getNumberFromCSSProperty(prop: string | undefined | null): number {
expect(typeof prop).toBe('string');
const reg = /^(\d+)\D*$/;
expect(prop).toMatch(reg);
const result = (prop as string).match(reg);
return Number((result as string[])[1]);
}
32 changes: 32 additions & 0 deletions packages/public/common-ui-web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,35 @@ function MyComponent() {
| sight | Sight | The sight to display the SVG overlay of. | ✔️ | |
| getAttributes | <code>(element: Element, groupIds: string[]) => SVGProps<SVGSVGElement> &#124; null</code> | A customization function that lets you specify custom HTML attributes to give to the tags in the SVG file based on the HTML element itself and the IDs of the groups it is part of. | | |
| getInnerText | <code>(element: Element, groupIds: string[]) => string &#124; null</code> | A customization function that lets you specify the innner text of the tags in the SVG file based on the HTML element itself and the IDs of the groups it is part of. | | |

## SwitchButton
### Description
Switch button component that can be used to turn ON or OFF a feature.

### Example
```tsx
import { SwitchButton } from '@monkvision/common-ui-web';

export function MyComponent() {
const [checked, setChecked] = useState(false);
return (
<div>
<SwitchButton checked={checked} onSwitch={(value) => setChecked(value)} />
</div>
);
}
```

### Props
| Prop | Type | Description | Required | Default Value |
|-------------------------|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-----------------|
| size | `'normal' &#124; 'small'` | The size of the button. Normal buttons are bigger and have their icon and labels inside the button. Small buttons are smaller, accept no label and have their icon inside the knob. | | 'normal' |
| checked | boolean | Boolean used to control the SwitchButton. Set to `true` to make the Button switched on and `false` for off. | | false |
| onSwitch | `(value: boolean) => void` | Callback called when the SwitchButton is switched. The value passed as the first parameter is the result `checked` value. | | |
| disabled | boolean | Boolean indicating if the button is disabled or not. | | false |
| checkedPrimaryColor | ColorProp | Primary color (background and knob overlay color) of the button when it is checked. | | 'primary' |
| checkedSecondaryColor | ColorProp | Secondary color (knob, labels and icons color) of the button when it is checked. | | 'text-white' |
| uncheckedPrimaryColor | ColorProp | Primary color (background and knob overlay color) of the button when it is unchecked. | | 'text-tertiary' |
| uncheckedSecondaryColor | ColorProp | Secondary color (knob, labels and icons color) of the button when it is unchecked. | | 'text-white' |
| checkedLabel | ColorProp | Custom label that can be displayed instead of the check icon when the button is checked. This prop is ignored for small buttons. | | |
| uncheckedLabel | ColorProp | Custom label that can be displayed when the button is unchecked. This prop is ignored for small buttons. | | |
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Styles } from '@monkvision/types';

export const slideTransitionFrames = '0.3s ease-out';

export const sizes = {
normal: {
width: 65,
height: 30,
knobPadding: 2,
labelPadding: 10,
knobOverlayExpansion: 3,
iconSize: 18,
},
small: {
width: 36,
height: 22,
knobPadding: 2,
knobOverlayExpansion: 2,
iconSize: 10,
},
};

export const styles: Styles = {
button: {
width: sizes.normal.width,
height: sizes.normal.height,
padding: `0 ${sizes.normal.labelPadding}px`,
overflow: 'visible',
borderRadius: 9999999,
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
border: 'none',
cursor: 'pointer',
transition: `background-color ${slideTransitionFrames}`,
},
buttonDisabled: {
opacity: 0.37,
cursor: 'default',
},
buttonSmall: {
padding: 0,
width: sizes.small.width,
height: sizes.small.height,
},
knobOverlay: {
width: sizes.normal.height + 2 * sizes.normal.knobOverlayExpansion,
height: sizes.normal.height + 2 * sizes.normal.knobOverlayExpansion,
borderRadius: '50%',
position: 'absolute',
top: -sizes.normal.knobOverlayExpansion,
left: -sizes.normal.knobOverlayExpansion,
transition: `left ${slideTransitionFrames}`,
},
knobOverlaySmall: {
width: sizes.small.height + 2 * sizes.small.knobOverlayExpansion,
height: sizes.small.height + 2 * sizes.small.knobOverlayExpansion,
top: -sizes.small.knobOverlayExpansion,
left: -sizes.small.knobOverlayExpansion,
},
knobOverlayChecked: {
left: sizes.normal.width - sizes.normal.height - sizes.normal.knobOverlayExpansion,
},
knobOverlaySmallChecked: {
left: sizes.small.width - sizes.small.height - sizes.small.knobOverlayExpansion,
},
knob: {
width: sizes.normal.height - 2 * sizes.normal.knobPadding,
height: sizes.normal.height - 2 * sizes.normal.knobPadding,
borderRadius: '50%',
position: 'absolute',
top: sizes.normal.knobPadding,
left: sizes.normal.knobPadding,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: `left ${slideTransitionFrames}`,
},
knobSmall: {
width: sizes.small.height - 2 * sizes.small.knobPadding,
height: sizes.small.height - 2 * sizes.small.knobPadding,
top: sizes.small.knobPadding,
left: sizes.small.knobPadding,
},
knobChecked: {
left: sizes.normal.width - sizes.normal.height + sizes.normal.knobPadding,
},
knobSmallChecked: {
left: sizes.small.width - sizes.small.height + sizes.small.knobPadding,
},
label: {
fontSize: 12,
fontWeight: 400,
lineHeight: '18px',
letterSpacing: '0.4px',
transition: `opacity ${slideTransitionFrames}`,
},
icon: {
transition: `opacity ${slideTransitionFrames}`,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useInteractiveStatus } from '@monkvision/common';
import { SwitchButtonProps, useSwitchButtonStyles } from './hooks';
import { Icon } from '../../icons';

/**
* Switch button component that can be used to turn ON or OFF a feature.
*
* @see https://uxplanet.org/checkbox-vs-toggle-switch-7fc6e83f10b8
* @example
* export function MyComponent() {
* const [checked, setChecked] = useState(false);
* return (
* <div>
* <SwitchButton checked={checked} onSwitch={(value) => setChecked(value)} />
* </div>
* );
* }
*/
export function SwitchButton({
size = 'normal',
checked = false,
onSwitch,
disabled = false,
checkedPrimaryColor = 'primary',
checkedSecondaryColor = 'text-white',
uncheckedPrimaryColor = 'text-tertiary',
uncheckedSecondaryColor = 'text-white',
checkedLabel,
uncheckedLabel,
}: SwitchButtonProps) {
const { status, eventHandlers } = useInteractiveStatus({ disabled });
const switchButtonStyles = useSwitchButtonStyles({
size,
checked,
checkedPrimaryColor,
checkedSecondaryColor,
uncheckedPrimaryColor,
uncheckedSecondaryColor,
status,
});

const handleSwitch = () => {
if (onSwitch) {
onSwitch(!checked);
}
};

return (
<button
style={switchButtonStyles.buttonStyle}
onClick={handleSwitch}
disabled={disabled}
{...eventHandlers}
data-testid='switch-btn'
>
{size === 'normal' && !checkedLabel && (
<Icon
icon='check'
primaryColor={switchButtonStyles.icon.color}
size={switchButtonStyles.icon.size}
style={switchButtonStyles.icon.style}
/>
)}
{size === 'normal' && checkedLabel && (
<div style={switchButtonStyles.checkedLabelStyle}>{checkedLabel ?? ''}</div>
)}
{size === 'normal' && (
<div style={switchButtonStyles.uncheckedLabelStyle}>{uncheckedLabel ?? ''}</div>
)}
<div style={switchButtonStyles.knobStyle} data-testid='switch-knob'>
{size === 'small' && checked && (
<Icon
icon='check'
primaryColor={switchButtonStyles.iconSmall.color}
size={switchButtonStyles.iconSmall.size}
style={switchButtonStyles.iconSmall.style}
/>
)}
</div>
<div style={switchButtonStyles.knobOverlayStyle}></div>
</button>
);
}
Loading