Skip to content

Commit

Permalink
feat(styling): Add support for fallthrough modifiers (#2944)
Browse files Browse the repository at this point in the history
A modifier key of `_` can be used to indicate a fallthrough modifier. This is useful if we want to conditionally add a CSS property only when a CSS variable is provided.

#2941

[category:Styling]
  • Loading branch information
NicholasBoll authored Oct 2, 2024
1 parent 8cf0838 commit 39cc095
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
50 changes: 50 additions & 0 deletions modules/styling-transform/spec/utils/handleCreateStencil.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,56 @@ describe('handleCreateStencil', () => {
);
});

it('should handle modifiers with fallthrough keys', () => {
const program = createProgramFromSource(`
import {createStencil, px2rem} from '@workday/canvas-kit-styling';
const buttonStencil = createStencil({
vars: {
padding: ''
},
base: {},
modifiers: {
padding: {
large: {
padding: 40,
},
small: {
padding: 20,
}
_: ({ padding }) => ({
padding
})
}
}
})
`);

const styles = {};
const names = {};
const extractedNames = {};

const result = transform(
program,
'test.ts',
withDefaultContext(program.getTypeChecker(), {styles, names, extractedNames})
);

expect(result).toMatch(/base: { name: "[0-9a-z]+", styles: "box-sizing:border-box;" }/);
expect(result).toMatch(/large: { name: "[0-9a-z]+", styles: "padding:40px;" }/);
expect(result).toMatch(
/_: { name: "[0-9a-z]+", styles: "padding:var\(--padding-button-[a-z0-9]+\);" }/
);

expect(styles['test.css']).toContainEqual(compileCSS('.css-button{box-sizing:border-box;}'));
expect(styles['test.css']).toContainEqual(
compileCSS('.css-button.padding-large{padding: 40px;}')
);
expect(styles['test.css']).toContainEqual(
compileCSS('.css-button.padding{padding: var(--css-button-padding)}')
);
});

it('should add to extracted styles', () => {
const program = createProgramFromSource(`
import {createStencil} from '@workday/canvas-kit-styling';
Expand Down
6 changes: 4 additions & 2 deletions modules/styling/lib/cs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,8 +415,10 @@ export function createModifiers<M extends ModifierConfig>(input: M): ModifierRet
const modifierFn = (modifiers: Partial<ModifierValues<M>>) => {
return combineClassNames(
Object.keys(input)
.filter(key => (input as any)[key][modifiers[key]])
.map(key => (input as any)[key][modifiers[key]])
.map(
key => (input as any)[key][modifiers[key]] || (modifiers[key] && (input as any)[key]._)
)
.filter(input => input) // only return defined class names
);
};

Expand Down
23 changes: 23 additions & 0 deletions modules/styling/spec/cs.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,29 @@ describe('cs', () => {
const myModifiers = myModifiersFactory();
expectTypeOf(myModifiers.size).toMatchTypeOf<{large: CS; small: CS}>();
});

describe('with a "_" modifier key', () => {
const myModifiersFactory = () =>
createModifiers({
size: {
large: createStyles({fontSize: '1.5rem'}),
small: createStyles({fontSize: '0.8rem'}),
_: createStyles({fontSize: 'var(--size)'}),
},
});

it('should not return any classes when "size" is not provided', () => {
const myModifiers = myModifiersFactory();

expect(myModifiers({})).toEqual('');
});

it('should return the CSS class of the "_" key when no other modifier matches and a matching modifier key is provided', () => {
const myModifiers = myModifiersFactory();

expect(myModifiers({size: 'foo' as any})).toEqual(myModifiers.size._);
});
});
});

describe('createCompoundModifiers', () => {
Expand Down

0 comments on commit 39cc095

Please sign in to comment.