refactor!: remove lepty-scoping feature and make its behaviour the default; deprecate scope members; bump MSRV; bump deps

This commit is contained in:
yiffyrusdev 2025-09-12 14:15:47 +05:00 • committed by spushk
commit 6690ae1751
Signed by: spushk
GPG key ID: 7797B761E105E8AA

178
README.md
View file

@ -25,17 +25,6 @@ sabry::scssy!(tokens {"@mixin colored{color: red;}"});
<hr/>
Get the *(almost)* proper autocompletion for your scope from rust-analyzer
```rust
sabry::styly!(scope {".cls1{} #id1{}"});
/* autocompleted for you */
scope::cls1;
scope::theid1;
```
<hr/>
Code your SASS in separate files to get proper syntax highlighting, or do sass-in-the-rust to keep things in one place
```rust
@ -71,13 +60,23 @@ Keep things as private and modular as you wish
```rust
sabry::styly!(pub cats "tests/assets/mixin-module.scss");
sabry::styly!(dogs {"#howl {border: none;}"});
sabry::styly!(dogs {".howl {border: none;}"});
```
```rust,ignore
```html
/// something like render function
{
<div class={cats::meow}>
<ul id={dogs::thehowl}></ul>
<div class={concatcp!("meow ", CATS)}>
<ul class={concatcp!("howl ", DOGS)}></ul>
</div>
}
```
```html
/// or even better with leptos
view!{class=CATS
<div class="meow">
{move || view!{class=DOGS,
<ul class="howl"></ul>
}}
</div>
}
```
@ -122,7 +121,7 @@ The only need is the dependency
#Cargo.toml
[dependencies]
sabry = {version = "0.0.5"}
sabry = {version = "0.0.6"}
```
And a proc-macro
```rust
@ -155,7 +154,7 @@ Depend on sabry
# Cargo.toml
[dependencies]
sabry = {version = "0.0.5"}
sabry = {version = "0.0.6"}
```
And create a style scope wherever you want:
```rust
@ -173,18 +172,18 @@ styly!(styles {"
color: white;
}
"});
/* Now you can use all scoped selectors: */
let badges_scoped_class = styles::badges;
let wolf_scoped_id = styles::thewolf;
```
Every selector, if that does make sense, now available for you as a member of `styles` scope. In this example - `styles::badges`, `styles::thewolf` and `styles::_list()`. More about scoping and member names you can read [here](#styly-scopes).
```html
<ul class={concatcp!("badges ", STYLES)}>
<li class={STYLES} id="wolf">
"HOOOOWL!"
</li>
</ul>
```
### Use styles earlier created in another crate
> **Tip** | If you use [leptos](https://github.com/leptos-rs/leptos) - check [this](#leptos-specials) section as well
The combination of previous two, with some additional work to do and some extra sugar to enjoy.
Sabry is needed as both dependency and build-dependency.
@ -193,10 +192,10 @@ To be able to compile all styles sabry also needs the *build* feature flag:
# Cargo.toml
[dependencies]
sabry = {version = "0.0.5"}
sabry = {version = "0.0.6"}
[build-dependencies]
sabry = {version = "0.0.5", features = ["build"]}
sabry = {version = "0.0.6", features = ["build"]}
```
> If you do use some non-default feature flags make sure to keep them in sync between sabry-dependency and sabry-build-dependency.
@ -318,81 +317,6 @@ So I'd say - do the const function back-propogation and let the consumer decide
</details>
### Leptos specials
With [leptos](https://github.com/leptos-rs/leptos) framework you can do the trick to apply some class to most of HtmlElements for the entire component/island:
```rust
use leptos::prelude::*;
#[component]
fn component() -> impl IntoView {
view! {class="cls1", /* <- here */
<h1>"Head"</h1>
<p>"text"</p>
}
}
```
... and have "cls1" on both `h1` and `p` auto-assigned. Isn't that cool?
So, if you're on leptos, and don't mind to take this approach, I'd highly recommend turning the *lepty-scoping* feature on:
```toml
# Cargo.toml
[dependencies]
sabry = {version = "0.0.5", features = ["lepty-scoping"]}
[build-dependencies]
sabry = {version = "0.0.5", features = ["build", "lepty-scoping"]}
```
```rust
use leptos::prelude::*;
use sabry::styly;
styly!(scope {"
// assuming we have tokens!() macro generated by `scssy!`, which is handled by `buildy`
@use 'tokens';
h1 {
@include tokens.sectionhead();
img {
@include tokens.sectionimg();
}
}
.breadcumbs {
@include tokens.badgelist();
&__item {
@include tokens.badge(secondary);
}
}
"});
#[component]
fn component() -> impl IntoView {
view! {class=SCOPE,
<h1>
"Head"
<img src="whatever"/>
</h1>
<ul class="breadcumbs">
<li class="breadcumbs__item">
"Home page"
</li>
</ul>
}
}
```
That will perform *much* better:
- All scope members - like `scope::breadcumbs` - wont contain repeating scope hash, just the original class/id selector
- So instead of scope members (which [aren't](https://github.com/yiffyrusdev/sabry/issues/2) autocompleted for sass-in-the-rust yet) you could just write bare selectors, as you do, for example, with svelte: `<li class="breadcumbs__item">`
- You'll still have the rusty mod generated: its just the `scope::breadcumbs` is the `"breadcumbs"` without the hash
- You will not encounter [the catch](#scoping) with nested tagname selectors
Also, this isn't really exclusive leptos-supporting feature. It just changes scoping behavour.
## Configuration
Sabry configuration lives in `[package.metadata.sabry]` table of the manifest file.
@ -562,8 +486,8 @@ In general the scope does look like this:
```rust,ignore
const FOX: &str = "J9k_s9";
mod fox {
pub const fur: &str = "J9k_s9 fur";
pub fn _dark(c: &str) -> String {format!("{c}-dark")}
#[deprecated(since = "0.0.6", note = "will remove")]
pub const fur: &str = "fur J9k_s9";
}
```
@ -572,9 +496,6 @@ mod fox {
Styly macro itself does not generate the scope. It is done in the `sabry_intrnl::scoper`. However, as a result, you will have the following:
- `const` with the UPPER_CASE name of the scope, which contains its hash
- `mod` with exact scope name which is the scope you're going to use
- for simple selectors, like `.fur` you will have a const members with hashed original selectors to use wherever you need a class/id/etc.
- for parent-selectors like `&-dark` you will have a non-const function, which will create matching the selector from any other.
You can read more about scoping and hashing in the [scoping](#scoping) section.
@ -600,7 +521,6 @@ Which results in following:
```rust,ignore
const SCOPE: &str = /* scope hash */;
const SCOPE_CSS: &str = /* compiled from src/assets/scope.scss */;
mod scope {/* selector collection */}
```
> **There is a catch** | with the `const` modifier macro must compile CSS at compile-time. That results in several game changers:
@ -666,15 +586,15 @@ Exactly this kind of macros is produced by [`scssy!`](#style-definition-with-scs
### Scoping
Sabry handles scoping by restriction or mutation of existing selectors
Sabry handles scoping by restriction of existing selectors
with the hash. Hash is calculated for the entire scope by the [`styly!`](#scoping-with-styly) macro.
Currently the following types of selectors are scoped:
- class
- id
- tagname
- SASS parent selectors (see below, there is a catch)
- tagname (see below, there is a catch)
Sabry does not make difference between top-level and nested selectors,
also selector complexity isn't taken into account: sabry simply walks through all compound selectors
@ -683,40 +603,8 @@ and apply scoping for supported ones.
Different selector types are scoped differently:
- class selectors are restricted with scope hash: `.class` -> `.HASH.class`
- id selector are mutated with scope hash: `#id` -> `#id-HASH`
- tagname selectors are changed into indirect descendance: `div` -> `.HASH div`
> **There is a catch** | currently tagname selectors are scoped with indirect descendancy
> hash restriction. That means - if you do use tagnames in scoped stylesheets, you have to wrap your markdown
> with `SCOPE` class generated by `styly!` macro.
>
> Also if there are nested tagname selectors - sabry won't take this into account and you'll
> have to wrap them with `SCOPE` class as well
>
> **However** If you are able to apply some class to all html elements you have - like `view!{class=CLASS...}` with Leptos - you could use *lepty-scoping* feature flag for sabry and get rid of this catch! See more [here](#leptos-specials).
As for **SASS parent selectors**: they are currently handled in different way. Instead of
walking up the syntax tree sabry just creates function member for the scope and leave the rest to grass:
```rust
sabry::styly!(scope {"
.cls1 {
&-dark {}
}
"});
```
is something like
```rust,ignore
const SCOPE: &str = "Ut8CskJ";
mod scope {
pub const cls1: &str = "Ut8CskJ cls1";
pub fn _dark(c: &str) -> String {format!("{c}-dark")}
}
```
So you still can get the scoped variant of `cls1-dark` class: `scope::_dark(scope::cls1)`.
This isn't very handy, also isn't strict enough, and is a high-priority subject to change. wip.
- id selector are mutated with scope hash: `#id` -> `.HASH#id`
- tagname selectors are changed into indirect descendance: `div` -> `div.HASH`
#### Scope member naming rules
@ -763,9 +651,9 @@ If you'd like to lend a paw - feel free to check the [WIP](#wip) section out, or
## MSRV
Sabry passes its own tests on 1.78 nightly/stable.
Sabry passes its own tests on 1.88 nightly/stable.
Examples are on 1.82.
Examples are on 1.88.
## License