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

Implement some features missing for literal syntax #43

Merged
merged 29 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e6eb320
Add StyleContext and RuleBlock.
futursolo Sep 9, 2021
17bd902
Add Style Context.
futursolo Sep 9, 2021
910173e
Padded Style Generation.
futursolo Sep 9, 2021
377d3c5
Block Content for Block.
futursolo Sep 9, 2021
60f1700
Remove folding and perfer native AST generation.
futursolo Sep 9, 2021
2e5d54f
Adjust output naming to align with stylist::ast.
futursolo Sep 9, 2021
c825c27
Optimise Bundle Size.
futursolo Sep 10, 2021
dc699fe
Optimise Error Handling.
futursolo Sep 10, 2021
221dbd9
Fix implementation.
futursolo Sep 10, 2021
e4e64d9
Derive default
futursolo Sep 10, 2021
52d65f8
Reduce code size.
futursolo Sep 10, 2021
c5afdbb
Add Parser for Rule Block.
futursolo Sep 11, 2021
6164ab2
Fix Clippy.
futursolo Sep 11, 2021
c34e7cb
Keyframes with RuleBlock.
futursolo Sep 11, 2021
c1c05db
Fix Clippy.
futursolo Sep 11, 2021
a5733db
Swap for AtomicBool.
futursolo Sep 11, 2021
2ba1586
Remove extra lifetime.
futursolo Sep 11, 2021
0e9e05b
Optimise for size.
futursolo Sep 11, 2021
b68f0ab
Reduce code size.
futursolo Sep 12, 2021
3f8003d
Reduce more code size.
futursolo Sep 12, 2021
6f86cbd
ContextRecorder -> ReifyContext.
futursolo Sep 12, 2021
d3a3a85
Expose some methods on StyleContext.
futursolo Sep 12, 2021
10be644
Resolve conflict.
futursolo Sep 13, 2021
b9e54a3
Address some review comments.
futursolo Sep 14, 2021
757cea6
Address Parser Comments.
futursolo Sep 14, 2021
215eac8
Address more comments.
futursolo Sep 14, 2021
7bd1793
Address comments.
futursolo Sep 14, 2021
6bdafe2
Apply to `:root`.
futursolo Sep 14, 2021
59c9cec
Merge branch 'master' into rule-block
futursolo Sep 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Trunk.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ ignore = [
"examples/yew-theme-agent/target/",
"examples/yew-theme-yewdux/target/",
]

[tools]
wasm_bindgen = "0.2.77"
2 changes: 1 addition & 1 deletion examples/benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ log = "0.4.14"
console_log = { version = "0.2.0", features = ["color"] }
yew = "0.18.0"
stylist = { path = "../../packages/stylist", features = ["yew_integration"] }
web-sys = { version = "0.3.53", features = [
web-sys = { version = "0.3.54", features = [
"Window",
"Performance",
] }
Expand Down
6 changes: 3 additions & 3 deletions examples/yew-integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ yew = "0.18.0"
stylist = { path = "../../packages/stylist", features = ["yew_integration"] }

[dev-dependencies]
wasm-bindgen-test = "0.3.26"
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.27"
wasm-bindgen = "0.2.77"

[dev-dependencies.web-sys]
version = "0.3.53"
version = "0.3.54"
features = [
"Window",
"Document",
Expand Down
2 changes: 1 addition & 1 deletion examples/yew-shadow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ stylist = { path = "../../packages/stylist", features = ["yew_integration"] }
once_cell = "1.8.0"

[dependencies.web-sys]
version = "0.3.53"
version = "0.3.54"
features = [
"Window",
"Document",
Expand Down
6 changes: 3 additions & 3 deletions examples/yew-theme-yewdux/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ stylist = { path = "../../packages/stylist", features = ["yew_integration"] }
yewdux = "0.6.2"

[dev-dependencies]
wasm-bindgen-test = "0.3.26"
wasm-bindgen = "0.2"
wasm-bindgen-test = "0.3.27"
wasm-bindgen = "0.2.77"

[dev-dependencies.web-sys]
version = "0.3.53"
version = "0.3.54"
features = [
"Window",
"Document",
Expand Down
6 changes: 3 additions & 3 deletions packages/stylist-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ resolver = "2"

[dependencies]
nom = { version = "7.0.0", optional = true }
thiserror = "1.0.26"
wasm-bindgen = "0.2.76"
thiserror = "1.0.29"
wasm-bindgen = "0.2.77"
once_cell = "1.8.0"

[dev-dependencies]
log = "0.4.14"
env_logger = "0.9.0"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.26"
wasm-bindgen-test = "0.3.27"

[features]
parser = ["nom"]
52 changes: 27 additions & 25 deletions packages/stylist-core/src/ast/block.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::borrow::Cow;
use std::fmt;

use super::{Selector, StyleAttribute, ToStyleStr};
use crate::Result;
use super::{RuleBlockContent, Selector, StyleContext, ToStyleStr};

/// A block is a set of css properties that apply to elements that
/// match the condition. The CSS standard calls these "Qualified rules".
Expand All @@ -20,35 +18,39 @@ pub struct Block {
/// If the value is set as [`&[]`], it signals to substitute with the classname generated for the
/// [`Sheet`](super::Sheet) in which this is contained.
pub condition: Cow<'static, [Selector]>,
pub style_attributes: Cow<'static, [StyleAttribute]>,
pub content: Cow<'static, [RuleBlockContent]>,
}

impl ToStyleStr for Block {
fn write_style<W: fmt::Write>(&self, w: &mut W, class_name: Option<&str>) -> Result<()> {
if !self.condition.is_empty() {
for (index, sel) in self.condition.iter().enumerate() {
sel.write_style(w, class_name)?;
if index < self.condition.len() - 1 {
write!(w, ",")?;
}
write!(w, " ")?;
}
} else if let Some(m) = class_name {
write!(w, ".{} ", m)?;
} else {
// Generates global style for dangling block.
write!(w, "html ")?;
impl Block {
fn cond_str(&self, ctx: &mut StyleContext<'_>) -> Option<String> {
if self.condition.is_empty() {
return None;
}

writeln!(w, "{{")?;
let mut cond = "".to_string();

for attr in self.style_attributes.iter() {
attr.write_style(w, class_name)?;
writeln!(w)?;
for (index, sel) in self.condition.iter().enumerate() {
sel.write_style(&mut cond, ctx);
if index < self.condition.len() - 1 {
cond.push_str(", ");
}
}

write!(w, "}}")?;
Some(cond)
}
}

impl ToStyleStr for Block {
fn write_style(&self, w: &mut String, ctx: &mut StyleContext<'_>) {
// TODO: nested block, which is not supported at the moment.
let cond_s = self.cond_str(ctx);

let mut block_ctx = ctx.with_block_condition(cond_s);

for attr in self.content.iter() {
attr.write_style(w, &mut block_ctx);
}

Ok(())
block_ctx.finish(w);
}
}
174 changes: 174 additions & 0 deletions packages/stylist-core/src/ast/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
use std::borrow::Cow;
use std::sync::atomic::{AtomicBool, Ordering};

/// A context to faciliate [`ToStyleStr`](super::ToStyleStr).
#[derive(Debug)]
pub struct StyleContext<'a> {
pub class_name: Option<&'a str>,
parent_ctx: Option<&'a StyleContext<'a>>,

rules: Vec<Cow<'a, str>>,
selectors: Vec<Cow<'a, str>>,

is_open: AtomicBool,
WorldSEnder marked this conversation as resolved.
Show resolved Hide resolved
}

impl<'a> StyleContext<'a> {
pub fn new(class_name: Option<&'a str>) -> Self {
Self {
parent_ctx: None,
class_name,
rules: Vec::new(),
selectors: Vec::new(),

is_open: AtomicBool::new(false),
}
}

fn is_open(&self) -> bool {
self.is_open.load(Ordering::Relaxed)
}

fn set_open(&self, value: bool) {
self.is_open.store(value, Ordering::Relaxed);
}

// We close until we can find a parent that has nothing differs from current path.
fn close_until_common_parent(&self, w: &mut String) {
while let Some(m) = self.open_parent() {
if self.differ_conditions().is_empty() {
break;
}
m.finish(w);
}
}

fn open_parent(&self) -> Option<&StyleContext<'a>> {
self.parent_ctx.and_then(|m| {
if m.is_open() {
Some(m)
} else {
m.open_parent()
}
})
}

fn conditions(&self) -> Vec<&str> {
self.rules
.iter()
.chain(self.selectors.iter())
.map(|m| m.as_ref())
.collect()
}

fn common_conditions(&self) -> Vec<&str> {
match self.open_parent() {
Some(m) => self
.conditions()
.into_iter()
.zip(m.conditions())
.filter_map(|(m1, m2)| if m1 == m2 { Some(m1) } else { None })
.collect(),
futursolo marked this conversation as resolved.
Show resolved Hide resolved
None => Vec::new(),
}
}

/// Calculate the layers that current context differs from the parent context
fn unique_conditions(&self) -> Vec<&str> {
self.conditions()
.into_iter()
.skip(self.common_conditions().len())
.collect()
}

/// Calculate the layers that parent context differs from current context
fn differ_conditions(&self) -> Vec<&str> {
match self.open_parent() {
Some(m) => m
.conditions()
.into_iter()
.skip(self.common_conditions().len())
.collect(),
None => Vec::new(),
}
}

fn write_padding_impl(&self, w: &mut String, no: usize) {
WorldSEnder marked this conversation as resolved.
Show resolved Hide resolved
for _ in 0..no {
w.push_str(" ");
}
}

fn write_min_padding(&self, w: &mut String) {
self.write_padding_impl(w, self.common_conditions().len())
}

pub fn finish(&self, w: &mut String) {
if self.is_open() {
for i in (0..self.unique_conditions().len()).rev() {
self.write_min_padding(w);
self.write_padding_impl(w, i);
w.push_str("}\n");
}
}
self.set_open(false);
}

pub fn start(&self, w: &mut String) {
if !self.is_open() {
self.close_until_common_parent(w);

for (index, cond) in self.unique_conditions().iter().enumerate() {
self.write_min_padding(w);
self.write_padding_impl(w, index);
w.push_str(cond);
w.push_str(" {\n");
}
}
self.set_open(true);
}

pub fn write_padding(&self, w: &mut String) {
self.write_padding_impl(w, self.conditions().len());
}

pub fn with_block_condition<S>(&'a self, cond: Option<S>) -> Self
where
S: Into<Cow<'a, str>>,
{
let mut selectors = self.selectors.clone();

if let Some(m) = cond {
selectors.push(m.into());
} else if self.selectors.is_empty() {
selectors.push(
self.class_name
.map(|m| format!(".{}", m).into())
.unwrap_or_else(|| "html".into()),
futursolo marked this conversation as resolved.
Show resolved Hide resolved
)
}

Self {
parent_ctx: Some(self),
class_name: self.class_name,
rules: self.rules.clone(),
selectors,

is_open: AtomicBool::new(false),
}
}

pub fn with_rule_condition<S: Into<Cow<'a, str>>>(&'a self, cond: S) -> Self {
let mut rules = self.rules.clone();
rules.push(cond.into());

Self {
parent_ctx: Some(self),
class_name: self.class_name,
rules,
selectors: self.selectors.clone(),

is_open: AtomicBool::new(false),
}
}
}
Loading