Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Type only class definition #2676

Open
idoros opened this issue Aug 23, 2022 · 0 comments
Open

proposal: Type only class definition #2676

idoros opened this issue Aug 23, 2022 · 0 comments
Assignees
Labels
core Processing and transforming logic discussion Ongoing conversation feature New syntax feature or behavior

Comments

@idoros
Copy link
Collaborator

idoros commented Aug 23, 2022

There are cases where components don't allow passing a CSS class to the root of the component, but expose styling of inner parts.

For example Radix has components with an invisible unstylable wrapper, like Alert and Tooltip that don't accept styling for the grouping component, but accept a class for inner parts like trigger, overlay, and content.

Current state

When writing a selector in Stylable, CSS class might be transformed to namespace or map to a different selector, but the intent to target something is preserved.

If we define an alert.st.css stylesheet today, with inner parts and try to use the alert root class as a selector then we get the alert__root class that won't be in the DOM, so it won't target and apply anything:

/* theme.st.css */
@st-import Alert from './alert.st.css';

Alert::trigger {} /* .alert__root .alert__trigger */
Alert::overlay {} /* .alert__root .alert__overlay */

This means that we can try and model the style API to treat each inner part as a separate component by either:

1. Having a different stylesheet for each part

/* alert-trigger.st.css */
.root {}
/* alert-overlay.st.css */
.root {}
/* theme.st.css */
@st-import AlertTrigger from './alert-trigger.st.css';
@st-import AlertOverlay from './alert-overlay.st.css';

AlertTrigger {} /* .alertTrigger__root */
AlertOverlay {} /* .alertOverlay__root */

2. Import inner parts

/* alert.st.css */
.root {}
.trigger {}
.overlay {}
/* theme.st.css */
@st-import [trigger, overlay] from './alert.st.css';

.trigger {} /* .alert__trigger */
.overlay {} /* .alert__overlay */

The second is probably better as it is less verbose on files and code, but it is still less good then having a component root to group inner parts as syntactic sugar, especially with some component stylesheets containing many parts.

Goals

  • Group a set of parts together
  • Mark a class to only exist for build time - transpiled away

Proposal

  • New interface only class - A new stylable declaration -st-type-only or maybe add an option to -st-extends to accept a "none" value to indicate its not a runtime class and is not intended to target anything.
  • Can only be applied to root class (not sure there is a case for inner parts)
  • Sticky interface - extending is basically stating that a new class is going to be set on the same DOM node as the extended class. Since we are defining a class that cannot exist in the DOM, Then extending such a class would mean the extending class is also an interface only class.
  • transform away interface only class during the build process
  • Report error when a selector subject is unstylable
  • No runtime style API mapping for such classes
  • Filter out interface classes from programmatic reflection APIs (transformIntoSelector, getAllClasses, etc.) - need to see how to differentiate between symbols and runtime classes

definition

/* alert.st.css */
.root {
    -st-extends: (); /* interface only root */
}
.trigger {}
.overlay {}

transform away interface only root

/* theme.st.css */
@st-import Alert from './alert.st.css';

Alert::trigger {} /* .alert__trigger */
Alert::overlay {} /* .alert__overlay */

/* report: unstylable selector subject */
Alert {}

no runtime

/* alert.js */
import { classes } from `./alert.st.css`;

classes.root {}    // undefined
classes.trigger {} // alert__trigger
classes.overlay {} // alert__overlay

extend interface only class

/* super-alert.st.css */
@st-import Alert from './alert.st.css';

.root {
    -st-extends: Alert; /* also set as interface only */
}
.part {};

.root::trigger {} /* .alert__trigger */
.root::overlay {} /* .alert__overlay */
.root::part {}    /* .super-alert__part */

/* report: unstylable selector subject */
root {}
@idoros idoros added feature New syntax feature or behavior discussion Ongoing conversation core Processing and transforming logic labels Aug 23, 2022
@idoros idoros self-assigned this Aug 23, 2022
@idoros idoros changed the title Type only class definition proposal: Type only class definition Aug 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Processing and transforming logic discussion Ongoing conversation feature New syntax feature or behavior
Projects
Status: No status
Development

No branches or pull requests

1 participant