Skip to content

Instantly share code, notes, and snippets.

@chipx86
Last active December 31, 2021 08:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chipx86/11a5f1eb696039fbf1a1a66719281689 to your computer and use it in GitHub Desktop.
Save chipx86/11a5f1eb696039fbf1a1a66719281689 to your computer and use it in GitHub Desktop.
CardStock: Experiments in layered component-based CSS generation and LessCSS
/*
* Layer 1: Button structure factory
*/
#cs-ns-widget-structures() {
/**
* Mixins for creating button structures.
*/
.button() {
/**
* Create a button structure.
*
* This will construct rules to place in a button-like component. Rules
* can be provided for the button or for various button states (on-hover,
* disabled, primary buttons, and dangerous buttons).
*
* If any of those provided, suitable rules will be added to enable those
* states.
*
* DOM Attributes:
* disabled:
* The button is disabled. This will be added if ``@disabled-rules``
* are provided. Alternatively, set the ``-is-disabled`` attribute.
*
* Modifiers:
* -is-danger:
* The button performs a dangerous action. This will be added if
* ``@danger-rules`` are provided.
*
* -is-disbled:
* The button is disabled. This will be added if ``@disabled-rules``
* are provided. Alternatively, set the ``disabled`` attributes.
*
* -is-primary:
* The button performs a primary action. This will be added if
* ``@primary-rules`` are provided.
*
* -js-hover:
* The button is in a hover state. This can be used by JavaScript
* to simulate hovering over the button (if, for example, a sibling
* component is currently being hovered over).
*
* This will be added if ``@hover-rules`` are provided.
*
* Args:
* @main-rules (ruleset, optional):
* Theme rules for the main ``cs-c-button``.
*
* @hover-rules (ruleset, optional):
* Theme rules for when the user hovers over a button.
*
* @danger-rules (ruleset, optional):
* Theme rules for the button when using the ``-is-danger``
* modifier.
*
* @disabled-rules (ruleset, optional):
* Theme rules for the button is disabled.
*
* @primary-rules (ruleset, optional):
* Theme rules for primary buttons.
*/
.create(@main-rules: null;
@hover-rules: null;
@danger-rules: null;
@disabled-rules: null;
@primary-rules: null) {
#cs-ns-widget-factory.base();
.add-rules(@main-rules);
&:hover,
.js-hover {
.add-rules(@hover-rules);
}
&.-is-danger {
.add-rules(@danger-rules);
}
&[disabled],
&.-is-disabled {
.add-rules(@disabled-rules);
}
&.-is-primary {
.add-rules(@primary-rules);
}
}
}
}
/*
* Layer 2: Component component creator/styler
*/
@import (reference) "button-structure.less";
#cs-ns-widgets() {
/**
* Mixins for creating and styling button widgets.
*/
.button() {
/**
* Create a cs-c-button component.
*
* This should be called by the theme to construct the styled rules for
* ``cs-c-button``.
*
* DOM Attributes:
* disabled:
* The button is disabled. This will be added if ``@disabled-rules``
* are provided. Alternatively, set the ``-is-disabled`` attribute.
*
* Modifiers:
* -is-danger:
* The button performs a dangerous action. This will be added if
* ``@danger-rules`` are provided.
*
* -is-disbled:
* The button is disabled. This will be added if ``@disabled-rules``
* are provided. Alternatively, set the ``disabled`` attributes.
*
* -is-primary:
* The button performs a primary action. This will be added if
* ``@primary-rules`` are provided.
*
* -js-hover:
* The button is in a hover state. This can be used by JavaScript
* to simulate hovering over the button (if, for example, a sibling
* component is currently being hovered over).
*
* This will be added if ``@hover-rules`` are provided.
*
* Args:
* @main-rules (ruleset, optional):
* Theme rules for the main ``cs-c-button``.
*
* @hover-rules (ruleset, optional):
* Theme rules for when the user hovers over a button.
*
* @danger-rules (ruleset, optional):
* Theme rules for the button when using the ``-is-danger``
* modifier.
*
* @disabled-rules (ruleset, optional):
* Theme rules for the button is disabled.
*
* @primary-rules (ruleset, optional):
* Theme rules for primary buttons.
*/
.create(@main-rules: null;
@hover-rules: null;
@danger-rules: null;
@disabled-rules: null;
@primary-rules: null) {
.cs-c-button {
#cs-ns-widget-structures.button.create(
@main-rules: {
cursor: pointer;
display: inline-block;
line-height: normal;
text-decoration: none;
.add-rules(@main-rules);
};
@hover-rules: {
text-decoration: none;
.add-rules(@hover-rules);
};
@danger-rules: @danger-rules;
@disabled-rules: @disabled-rules;
@primary-rules: @primary-rules
);
}
button,
input[type="button"],
input[type="submit"] {
&:extend(.cs-c-button all);
}
}
/**
* Style an existing cs-c-button.
*
* This can be used to add new theme rules to top-level or nested
* ``cs-c-button``, with or without a media selector.
*
* Args:
* @media (string, optional):
* An optional media selector for these styles.
*
* @main-rules (ruleset, optional):
* Theme rules for the main ``cs-c-button``.
*
* @hover-rules (ruleset, optional):
* Theme rules for when the user hovers over a button.
*
* @danger-rules (ruleset, optional):
* Theme rules for the button when using the ``-is-danger``
* modifier.
*
* @disabled-rules (ruleset, optional):
* Theme rules for the button is disabled.
*
* @primary-rules (ruleset, optional):
* Theme rules for primary buttons.
*/
.style(@media: null;
@main-rules: null;
@hover-rules: null;
@danger-rules: null;
@disabled-rules: null;
@primary-rules: null) {
#cs-ns-widget-factory.base.for-media(
@media: @media;
@rules: {
.cs-c-button {
#cs-ns-widget-structures.button.create(
@main-rules: @main-rules;
@hover-rules: @hover-rules;
@danger-rules: @danger-rules;
@disabled-rules: @disabled-rules;
@primary-rules: @primary-rules;
);
}
}
);
}
}
}
/*
* Layer 3: Button theme and CSS generation
*/
@import (reference) "button-component.less";
#cs-ns-widgets.button.create(
@main-rules: {
background: grey;
border: 1px outset solid;
};
@hover-rules: {
background: blue;
};
@danger-rules: {
font-size: 500%;
background: red;
color: white;
};
);
/* Let's make a dark mode version. */
#cs-ns-widgets.button.style(
@media: ~"prefers-color-scheme: dark";
@main-rules: {
color: white;
background: black;
};
);
@import (reference) "button-structure.less";
@import (reference) "button-component.less";
/* Let's specialize the hover state of any nested buttons in this class. */
.something-specializing-button {
#cs-ns-widgets.button.style(
@hover-rules: {
background: orange;
color: red;
}
);
}
/*
* Let's make something that is not a cs-c-button, but is structured like one,
* with nothing but primary button rules.
*/
.something-button-like {
#cs-ns-widget-structure.button.create(
@main-rules: {
border: 1px blue solid;
color: blue;
};
@primary-rules: {
background: yellow;
};
);
}
/* @main-rules */
.cs-c-button,
button,
input[type="button"],
input[type="submit"] {
cursor: pointer;
display: inline-block;
line-height: normal;
text-decoration: none;
background: grey;
border: 1px outset solid;
}
/* @hover-rules */
.cs-c-button:hover,
.cs-c-button .js-hover,
button:hover,
button .js-hover,
input[type="button"]:hover,
input[type="button"] .js-hover,
input[type="submit"]:hover,
input[type="submit"] .js-hover {
text-decoration: none;
background: blue;
}
/* @danger-rules */
.cs-c-button.-is-danger,
button.-is-danger,
input[type="button"].-is-danger,
input[type="submit"].-is-danger {
font-size: 500%;
background: red;
color: white;
}
/* Dark mode styling */
@media (prefers-color-scheme: dark) {
.cs-c-button,
button,
input[type="button"],
input[type="submit"] {
color: white;
background: black;
}
}
/* Let's specialize the hover state of any nested buttons in this class. */
.something-specializing-button .cs-c-button:hover,
.something-specializing-button .cs-c-button .js-hover,
.something-specializing-button button:hover,
.something-specializing-button button .js-hover,
.something-specializing-button input[type="button"]:hover,
.something-specializing-button input[type="button"] .js-hover,
.something-specializing-button input[type="submit"]:hover,
.something-specializing-button input[type="submit"] .js-hover {
background: orange;
color: red;
}
/*
* Let's make something that is not a cs-c-button, but is structured like one,
* with nothing but primary button rules.
*/
.something-button-like {
border: 1px blue solid;
color: blue;
}
.something-button-like.-is-primary {
background: yellow;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment