Open tomrav opened 3 years ago
(WIP)
tailwind
We are already encounter inline combinations of types in rules:
/* compound selector with multiple types */
.x.y {
}
/* nested union types */
:is(.x, .y) {
}
/* nested intersection types */
:is(.x.y) {
}
Today when we define parts in Stylable we can use -st-extends
to give it a "single" type.
We want to allow multiple types to be assigned to the same part
support intersection and union (|,&) in -st-extends
directive.
development runtime type checking (inject dev rules)
validate that all types are matching inside intersection and union
implement transform for intersection and union
handle custom selectors the same way we handle :is
compound selectors infer/transform according to anchor location
can we use :is
and :where
to transform intersection and union ?
can :where
be used to narrow type inference ?
extend Stylable definitions ?
-st-extends
to support attributes - e.g input[type="submit"] | button
Native elements:
/* @dev-check .root:not(div, span) */
.root {
-st-extends: div | span;
}
function Comp({ isBlock }) {
return isBlock ? (
<div className={classes.root} />
) : (
<span className={classes.root} />
);
}
Element and class:
.full-width {
/* implicit -st-extends: Element */
}
/* @js-export entry__root */
/* @dev-check .root:not(header, .full-width) */
.root {
-st-extends: header | .full-width;
}
function Comp() {
<header className={st(classes.root)} />
<header className={st(classes.root, classes['full-width'])} />
<div className={st(classes.root, classes['full-width'])} />
}
Two classes with non conflicting states:
/* entry */
.full-width {
-st-states: size(enum(viewport, content));
}
.flex {
-st-states: orientation(enum(horizontal, vertical));
}
/* @js-export entry__root */
/* @dev-check .root:not(.flex, .full-width) */
.root {
-st-extends: .flex | .full-width;
/* :is(.flex, .full-width) */
}
.root:size(viewport) {
}
.root:orientation(horizontal) {
}
.root:size(viewport):orientation(horizontal) {
}
function Comp() {
// consider add dev check for this
<div className={st(classes.root, {orientation: '...'}, classes['full-width'])} />
// skip the example
}
Conflicting states:
/* entry */
.flex-center {
-st-states: orientation(enum(h, v));
display: flex;
align-items: center;
justify-content: center;
}
.flex {
-st-states: orientation(enum(horizontal, vertical));
display: flex;
}
/* @js-export entry__top */
.top {
-st-extends: .flex | .flex-center;
/* :is(.flex, .full-width) */
}
/* @transform-error Argument of type 'orientation(horizontal)' is not assignable to parameter of type orientation(enum(h, v)). */
.top:orientation(horizontal) {
}
/* utils */
.flex-center {
-st-states: orientation("[data-orientation][data-xxx]");
display: flex;
align-items: center;
justify-content: center;
}
/* entry */
.flex {
-st-states: orientation(enum(horizontal, vertical));
display: flex;
}
/* @js-export entry__top */
.top {
-st-extends: .flex | .flex-center;
/* :is(.flex, .full-width) */
}
/* @rule .entry__top:is(.entry--orientation-horizontal, [data-orientation][data-xxx]) */
/* @rule .entry__top.entry--orientation-horizontal, .entry__top[data-orientation][data-xxx] */
/* @rule .entry__top.entry__top:where(.entry--orientation-horizontal, [data-orientation][data-xxx]) */
.top:orientation(horizontal) {
}
/* we need to find solution for this case */
:orientation(horizontal) {
}
/* should only work if there is a default state value */
.top:orientation {
}
Native elements intersection:
/* entry */
.root {
/* @analyze-error cannot intersect two element */
-st-extends: div & span;
}
.full-width {
/* implicit -st-extends: Element */
}
/* @js-export entry__top entry__full-width */
.top {
-st-extends: header & .full-width;
/* header.full-width */
}
Parts intersection:
/* A */
@st-import [same] from './common.st.css';
.root {
}
.same {
}
.conflict {
}
.a-only {
}
/* B */
@st-import [same] from './common.st.css';
.root {
}
.same {
}
.conflict {
}
/* entry */
.root {
-st-extends: A & B;
}
/* @rule .entry__root .common__same */
.root::same {
}
/* @transform-error .conflict in A & B does reference the same part */
.root::conflict {
}
/* ? WHAT TO DO WHEN ONLY ONE SIDE DEFINE THE PART ? */
.root::a-only {
}