Genesis
This commit is contained in:
125
src/ElevatedPill.jsx
Normal file
125
src/ElevatedPill.jsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import { Component } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Switch from '@mui/material/Switch';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { alpha } from '@mui/material/styles';
|
||||
|
||||
/**
|
||||
* Base pill with elevation, shared styling, and an overridable trailing element.
|
||||
* Root class for ToggleElevatedPill and ActionElevatedPill.
|
||||
*
|
||||
* @component ElevatedPill
|
||||
* @import dashgui/ElevatedPill
|
||||
* @defaultExport
|
||||
*
|
||||
* @prop {ReactNode} [label] - Text shown inside the pill.
|
||||
* @prop {boolean} [active=false] - When true, uses a stronger primary gradient background.
|
||||
* @prop {() => void} [onClick] - Called when the pill is clicked.
|
||||
*
|
||||
* @behaviour Rendered as a pill-shaped (borderRadius 999) inline-flex Box with a subtle primary-tinted gradient and shadow 1.
|
||||
* @behaviour `renderTrailing()` may be overridden by subclasses to append an element (switch / icon).
|
||||
* @behaviour Clicking toggles via onClick — the pill itself is not a form control.
|
||||
*/
|
||||
class ElevatedPill extends Component {
|
||||
renderTrailing() {
|
||||
return null;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { label, active = false, onClick } = this.props;
|
||||
return (
|
||||
<Box
|
||||
component="label"
|
||||
onClick={onClick}
|
||||
sx={(theme) => ({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: 0.5,
|
||||
px: 1.5,
|
||||
py: 0.25,
|
||||
borderRadius: 999,
|
||||
background: active
|
||||
? `linear-gradient(180deg, ${alpha(theme.palette.primary.main, 0.28)}, ${alpha(
|
||||
theme.palette.primary.main,
|
||||
0.22,
|
||||
)})`
|
||||
: `linear-gradient(180deg, ${alpha(theme.palette.primary.main, 0.16)}, ${alpha(
|
||||
theme.palette.primary.main,
|
||||
0.10,
|
||||
)})`,
|
||||
color: 'text.primary',
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
boxShadow: theme.shadows[1],
|
||||
transition: 'background 150ms ease, box-shadow 150ms ease',
|
||||
})}
|
||||
>
|
||||
<Typography variant="body2" sx={{ lineHeight: 1 }}>
|
||||
{label}
|
||||
</Typography>
|
||||
{this.renderTrailing()}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ElevatedPill with a trailing MUI Switch bound to `checked` / `onToggle` —
|
||||
* a labelled on/off toggle.
|
||||
*
|
||||
* @component ToggleElevatedPill
|
||||
* @import dashgui/ElevatedPill
|
||||
*
|
||||
* @prop {ReactNode} [label] - Text shown next to the switch.
|
||||
* @prop {boolean} checked - Controlled switch state.
|
||||
* @prop {(next: boolean) => void} onToggle - Called with the new checked value when the switch is toggled.
|
||||
*
|
||||
* @behaviour The switch is styled with a success color when on, grey when off.
|
||||
* @behaviour Controlled: the parent owns `checked` and updates it via `onToggle`.
|
||||
*/
|
||||
export class ToggleElevatedPill extends ElevatedPill {
|
||||
renderTrailing() {
|
||||
const { checked, onToggle } = this.props;
|
||||
return (
|
||||
<Switch
|
||||
size="small"
|
||||
checked={checked}
|
||||
onChange={(event) => onToggle(event.target.checked)}
|
||||
sx={(theme) => ({
|
||||
'& .MuiSwitch-switchBase': {
|
||||
color: checked ? 'success.main' : 'grey.300',
|
||||
},
|
||||
'& .Mui-checked': {
|
||||
color: 'success.main',
|
||||
},
|
||||
'& .Mui-checked + .MuiSwitch-track': {
|
||||
backgroundColor: alpha(theme.palette.success.main, 0.35),
|
||||
},
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ElevatedPill whose trailing slot is a custom icon — used for clickable pill
|
||||
* buttons.
|
||||
*
|
||||
* @component ActionElevatedPill
|
||||
* @import dashgui/ElevatedPill
|
||||
*
|
||||
* @prop {ReactNode} [label] - Text shown next to the icon.
|
||||
* @prop {ReactNode} [icon] - Icon node rendered as the trailing element.
|
||||
* @prop {boolean} [active=false] - When true, uses the stronger primary gradient background.
|
||||
* @prop {() => void} [onClick] - Called when the pill is clicked.
|
||||
*
|
||||
* @behaviour Clicking the whole pill fires `onClick` — the icon is decorative, not a separate control.
|
||||
* @behaviour `active` gives a pressed/selected look via the stronger gradient.
|
||||
*/
|
||||
export class ActionElevatedPill extends ElevatedPill {
|
||||
renderTrailing() {
|
||||
return this.props.icon;
|
||||
}
|
||||
}
|
||||
|
||||
export default ElevatedPill;
|
||||
Reference in New Issue
Block a user