UNPKG

@reusable-ui/button

Version:

A button component for initiating an action.

221 lines (220 loc) 8.16 kB
// cssfn: import { // writes css in javascript: rule, variants, states, fallback, style, vars, // strongly typed of css variables: cssVars, switchOf, // reads/writes css variables configuration: usesCssProps, usesPrefixedProps, // writes complex stylesheets in simpler way: watchChanges, memoizeStyle, } from '@cssfn/core'; // writes css in javascript // reusable-ui core: import { // a border (stroke) management system: borderRadiuses, // a spacer (gap) management system: spacers, // a typography management system: typos, // border (stroke) stuff of UI: usesBorder, // padding (inner spacing) stuff of UI: usesPadding, usesOrientationable, // size options of UI: usesResizable, // gradient variant of UI: usesGradientable, setGradient, // outlined (background-less) variant of UI: usesOutlineable, // adds an interactive feel to a UI: ifArrive, ifLeave, // shows the UI as clicked when activated: usesActiveAsClick, } from '@reusable-ui/core'; // a set of reusable-ui packages which are responsible for building any component // reusable-ui components: import { // configs: basics, } from '@reusable-ui/basic'; // a base component import { // styles: onActionControlStylesChange, usesActionControlLayout, usesActionControlVariants, usesActionControlStates, } from '@reusable-ui/action-control'; // a base component // internals: import { // defaults: defaultOrientationableOptions, } from '../defaults.js'; import { // configs: buttons, cssButtonConfig, } from './config.js'; const [condBorderVars] = cssVars(); // no need to have SSR support because the variables are not shared externally (outside <ProgressBar>) // utility styles: const usesAppearAsOutlined = () => { // dependencies: // features: const { borderVars } = usesBorder(); // variants: const { outlineableVars } = usesOutlineable(); return style({ // compositions: ...vars({ [borderVars.border]: [[ borderVars.borderStyle, switchOf(condBorderVars.condBorderWidthTg, // border is supported '0px'), borderVars.borderColor, ]], }), // toggling functions: ...vars({ [condBorderVars.condBorderWidthTg]: [[ outlineableVars.outlinedSw, borderVars.borderWidth, ]], }), // toggling functions: ...vars({ [outlineableVars.noBackgTg]: [[ 'transparent', // the no background color definition ]], [outlineableVars.backgTg]: [[ outlineableVars.backgFn, // the outlined background color definition ]], [outlineableVars.foregTg]: [[ outlineableVars.foregFn, // the outlined foreground color definition ]], [outlineableVars.altBackgTg]: [[ outlineableVars.altBackgFn, // the outlined alternate background color definition ]], [outlineableVars.altForegTg]: [[ outlineableVars.altForegFn, // the outlined alternate foreground color definition ]], }), }); }; const usesButtonLinkVariant = () => { // dependencies: // features: const { borderVars } = usesBorder(); const { paddingVars } = usesPadding(); // variants: const { gradientableVars } = usesGradientable(); const { outlineableVars } = usesOutlineable(); return style({ // layouts: ...style({ // accessibilities: userSelect: 'contain', ...fallback({ userSelect: 'text', // a link should be selectable }), // borders: // small rounded corners on top: [borderVars.borderStartStartRadius]: borderRadiuses.sm, [borderVars.borderStartEndRadius]: borderRadiuses.sm, // small rounded corners on bottom: [borderVars.borderEndStartRadius]: borderRadiuses.sm, [borderVars.borderEndEndRadius]: borderRadiuses.sm, // spacings: [paddingVars.paddingInline]: spacers.xs, [paddingVars.paddingBlock]: `max(0px, ${spacers.xs} - (0.5em * (${switchOf(basics.lineHeight, typos.lineHeight)} - 1)))`, marginInline: `calc(0px - ${paddingVars.paddingInline})`, marginBlock: `calc(0px - ${paddingVars.paddingBlock})`, // typos: textDecoration: 'underline', lineHeight: switchOf(basics.lineHeight, typos.lineHeight), // customize: ...usesCssProps(usesPrefixedProps(buttons, 'link')), // apply config's cssProps starting with link*** }), // toggling functions: ...vars({ [gradientableVars.backgGradTg]: [[ outlineableVars.outlinedSw, gradientableVars.gradientSw, gradientableVars.backgGrad, // the gradient definition ]], }), }); }; const usesButtonGhostVariant = () => { return style({ // layouts: ...style({ // borders: boxShadow: ['none', '!important'], // customize: ...usesCssProps(usesPrefixedProps(buttons, 'ghost')), // apply config's cssProps starting with ghost*** }), // states: ...states([ ifArrive({ // appearances: opacity: buttons.ghostOpacityArrive, // increase the opacity to increase visibility }), ifLeave( // backgrounds: setGradient(false)), ]), }); }; // styles: export const onButtonStylesChange = watchChanges(onActionControlStylesChange, cssButtonConfig.onChange); export const usesButtonLayout = memoizeStyle((options) => { // options: const orientationableStuff = usesOrientationable(options, defaultOrientationableOptions); const { ifOrientationInline, ifOrientationBlock } = orientationableStuff; return style({ // layouts: ...usesActionControlLayout(), ...style({ // layouts: display: 'inline-flex', ...ifOrientationInline({ flexDirection: 'row', // items are stacked horizontally }), ...ifOrientationBlock({ flexDirection: 'column', // items are stacked vertically }), justifyContent: 'center', alignItems: 'center', flexWrap: 'wrap', // positions: verticalAlign: 'baseline', // typos: textAlign: 'center', // customize: ...usesCssProps(buttons), // apply config's cssProps }), }); }, onButtonStylesChange); export const usesButtonVariants = memoizeStyle(() => { // dependencies: // variants: const { resizableRule } = usesResizable(buttons); return style({ // variants: /* write specific buttonStyle first, so it can be overriden by `.nude`, `.mild`, `.outlined`, etc */ ...variants([ rule(['.link', '.ghost'], usesAppearAsOutlined()), rule('.link', usesButtonLinkVariant()), rule('.ghost', usesButtonGhostVariant()), ]), ...usesActionControlVariants(), ...resizableRule(), }); }, onButtonStylesChange); export const usesButtonStates = memoizeStyle(() => { // dependencies: // states: const { activeAsClickRule } = usesActiveAsClick(); return style({ // states: ...usesActionControlStates(), ...activeAsClickRule(), }); }, onButtonStylesChange); export default memoizeStyle(() => style({ // layouts: ...usesButtonLayout(), // variants: ...usesButtonVariants(), // states: ...usesButtonStates(), }), onButtonStylesChange);