Skip to content

Commit c641250

Browse files
committed
Implement devup hot reload
Fix camel selector issue
1 parent a7c50bf commit c641250

File tree

11 files changed

+150
-50
lines changed

11 files changed

+150
-50
lines changed

apps/next/devup.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"theme": {
33
"colors": {
44
"default": {
5-
"text": "#333"
5+
"text": "green"
66
},
77
"dark": {
88
"text": "#fff"
99
}
1010
}
1111
}
12-
}
12+
}

apps/next/src/app/page.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default function HomePage() {
99

1010
return (
1111
<div>
12-
<a />
12+
<p>Track & field champions:</p>
1313
<Box
1414
_hover={{
1515
bg: ['yellow', 'red'],
@@ -24,7 +24,20 @@ export default function HomePage() {
2424
position="relative"
2525
py="28px"
2626
>
27-
hello
27+
<Box
28+
_lastChild={{
29+
color: 'purple',
30+
}}
31+
>
32+
hello
33+
</Box>
34+
<Box
35+
_lastChild={{
36+
color: 'purple',
37+
}}
38+
>
39+
hello
40+
</Box>
2841
</Box>
2942
<Text
3043
className={css`

bindings/devup-ui-wasm/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl Output {
7474
if !collected {
7575
return None;
7676
}
77-
Some(sheet.create_css(vec![0, 480, 768, 992, 1280]))
77+
Some(sheet.create_css())
7878
}
7979
}
8080

@@ -104,7 +104,7 @@ pub fn code_extract(
104104
Err(error) => Err(JsValue::from_str(error.to_string().as_str())),
105105
}
106106
}
107-
pub fn theme_object_to_hashmap(js_value: JsValue) -> Result<Theme, JsValue> {
107+
fn theme_object_to_hashmap(js_value: JsValue) -> Result<Theme, JsValue> {
108108
let mut theme = Theme::new();
109109

110110
if let Some(obj) = js_value.dyn_into::<Object>().ok() {
@@ -153,9 +153,14 @@ pub fn theme_object_to_hashmap(js_value: JsValue) -> Result<Theme, JsValue> {
153153

154154
#[wasm_bindgen(js_name = "registerTheme")]
155155
pub fn register_theme(theme_object: JsValue) -> Result<(), JsValue> {
156-
log(&theme_object);
157156
let theme_object = theme_object_to_hashmap(theme_object)?;
158157
let mut sheet = GLOBAL_STYLE_SHEET.lock().unwrap();
159158
sheet.set_theme(theme_object);
160159
Ok(())
161160
}
161+
162+
#[wasm_bindgen(js_name = "getCss")]
163+
pub fn get_css() -> Result<String, JsValue> {
164+
let mut sheet = GLOBAL_STYLE_SHEET.lock().unwrap();
165+
Ok(sheet.create_css())
166+
}

libs/css/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ static GLOBAL_STYLE_PROPERTY: Lazy<Mutex<HashMap<&str, PropertyType>>> = Lazy::n
6666
map
6767
})
6868
});
69-
fn to_kebab_case(value: &str) -> String {
69+
pub fn to_kebab_case(value: &str) -> String {
7070
value
7171
.chars()
7272
.enumerate()

libs/extractor/src/lib.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ pub fn extract(
168168
code: &str,
169169
option: ExtractOption,
170170
) -> Result<ExtractOutput, Box<dyn Error>> {
171+
let source_type = SourceType::from_path(filename)?;
171172
if !code.contains(option.package.as_str()) {
172173
// skip if not using package
173174
return Ok(ExtractOutput {
@@ -176,25 +177,15 @@ pub fn extract(
176177
});
177178
}
178179
let allocator = Allocator::default();
179-
let source_type = SourceType::from_path(filename)?;
180180

181181
let ParserReturn {
182182
mut program, // AST
183-
errors, // Syntax errors
184183
panicked, // Parser encountered an error it couldn't recover from
185184
..
186185
} = Parser::new(&allocator, code, source_type).parse();
187186
if panicked {
188187
return Err("Parser panicked".into());
189188
}
190-
if !errors.is_empty() {
191-
return Err(errors
192-
.iter()
193-
.map(|e| e.to_string())
194-
.collect::<Vec<_>>()
195-
.join("\n")
196-
.into());
197-
}
198189
let mut visitor = DevupVisitor::new(
199190
&allocator,
200191
&option.package,
@@ -742,4 +733,33 @@ mod tests {
742733
)
743734
.unwrap());
744735
}
736+
737+
#[test]
738+
fn raise_error() {
739+
assert!(extract(
740+
"test.wrong",
741+
"const a = 1;",
742+
ExtractOption {
743+
package: "@devup-ui/core".to_string(),
744+
css_file: None
745+
},
746+
)
747+
.unwrap_err()
748+
.to_string()
749+
.starts_with("Unknown file extension"));
750+
751+
assert_eq!(
752+
extract(
753+
"test.tsx",
754+
"import {} '@devup-ui/core';\na a = 1;",
755+
ExtractOption {
756+
package: "@devup-ui/core".to_string(),
757+
css_file: None
758+
},
759+
)
760+
.unwrap_err()
761+
.to_string(),
762+
"Parser panicked"
763+
);
764+
}
745765
}

libs/sheet/src/lib.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub mod theme;
22

33
use crate::theme::Theme;
4-
use css::{convert_property, PropertyType};
4+
use css::{convert_property, to_kebab_case, PropertyType};
55
use std::collections::{BTreeMap, HashSet};
66

77
trait ExtractStyle {
@@ -19,7 +19,7 @@ pub struct StyleSheetProperty {
1919
impl ExtractStyle for StyleSheetProperty {
2020
fn extract(&self) -> String {
2121
let selector = if let Some(selector) = &self.selector {
22-
format!(":{}", selector)
22+
format!(":{}", to_kebab_case(selector))
2323
} else {
2424
String::new()
2525
};
@@ -71,6 +71,7 @@ pub struct StyleSheet {
7171
/// level -> properties
7272
pub properties: BTreeMap<u8, HashSet<StyleSheetProperty>>,
7373
pub css: HashSet<StyleSheetCss>,
74+
theme: Theme,
7475
theme_declaration: String,
7576
}
7677

@@ -86,6 +87,7 @@ impl StyleSheet {
8687
properties: BTreeMap::new(),
8788
css: HashSet::new(),
8889
theme_declaration: String::new(),
90+
theme: Theme::new(),
8991
}
9092
}
9193

@@ -114,13 +116,20 @@ impl StyleSheet {
114116
pub fn set_theme(&mut self, theme: Theme) {
115117
let mut theme_declaration = String::new();
116118
theme_declaration.push_str(theme.colors.to_css().as_str());
119+
self.theme = theme;
117120
self.theme_declaration = theme_declaration;
118121
}
119122

120-
pub fn create_css(&self, break_points: Vec<u16>) -> String {
123+
pub fn create_css(&self) -> String {
121124
let mut css = self.theme_declaration.clone();
122125
for (level, props) in self.properties.iter() {
123-
let inner_css = props
126+
// If has a selector property, move it to the back
127+
let (mut select_props, other_props): (Vec<_>, Vec<_>) =
128+
props.iter().partition(|prop| prop.selector.is_some());
129+
let mut sorted_props = other_props;
130+
sorted_props.append(&mut select_props);
131+
132+
let inner_css = sorted_props
124133
.iter()
125134
.map(|prop| prop.extract())
126135
.collect::<Vec<String>>()
@@ -131,12 +140,18 @@ impl StyleSheet {
131140
css.push_str(
132141
format!(
133142
"\n@media (min-width:{}px){{{}}}",
134-
break_points
143+
self.theme
144+
.break_points
135145
.iter()
136146
.enumerate()
137147
.find(|(idx, _)| (*idx as u8) == *level)
138148
.map(|(_, bp)| *bp)
139-
.unwrap_or_else(|| break_points.last().cloned().unwrap_or(0)),
149+
.unwrap_or_else(|| self
150+
.theme
151+
.break_points
152+
.last()
153+
.cloned()
154+
.unwrap_or(0)),
140155
inner_css
141156
)
142157
.as_str(),

libs/sheet/src/theme.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ impl Color {
9595

9696
pub struct Theme {
9797
pub colors: Color,
98+
pub break_points: Vec<u16>,
9899
}
99100

100101
impl Default for Theme {
@@ -107,6 +108,18 @@ impl Theme {
107108
pub fn new() -> Self {
108109
Self {
109110
colors: Color::new(),
111+
break_points: vec![0, 480, 768, 992, 1280],
112+
}
113+
}
114+
115+
pub fn update_break_points(&mut self, break_points: Vec<u16>) {
116+
for (idx, value) in break_points.iter().enumerate() {
117+
let prev = self.break_points.get_mut(idx);
118+
if let Some(prev) = prev {
119+
*prev = *value;
120+
} else {
121+
self.break_points.push(*value);
122+
}
110123
}
111124
}
112125

packages/next-plugin/src/plugin.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import { existsSync, readFileSync } from 'node:fs'
2-
31
import {
42
DevupUIWebpackPlugin,
5-
DevupUiWebpackPluginOptions,
3+
type DevupUIWebpackPluginOptions,
64
} from '@devup-ui/webpack-plugin'
75
import { type NextConfig } from 'next'
86

9-
type DevupUiNextPluginOptions = Partial<DevupUiWebpackPluginOptions>
7+
type DevupUiNextPluginOptions = Partial<DevupUIWebpackPluginOptions>
108

119
/**
1210
* Devup UI Next Plugin
@@ -19,16 +17,6 @@ export function DevupUI(
1917
options: DevupUiNextPluginOptions = {},
2018
): NextConfig {
2119
const { webpack } = config
22-
if (!options.devupTheme && existsSync('devup.json')) {
23-
try {
24-
options.devupTheme = JSON.parse(readFileSync('devup.json', 'utf-8'))?.[
25-
'theme'
26-
]
27-
} catch (error) {
28-
console.error(error)
29-
}
30-
}
31-
3220
config.webpack = (config, _options) => {
3321
config.plugins.push(new DevupUIWebpackPlugin(options))
3422
if (typeof webpack === 'function') return webpack(config, _options)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export {
22
DevupUIWebpackPlugin,
3-
type DevupUiWebpackPluginOptions,
3+
type DevupUIWebpackPluginOptions,
44
} from './plugin'

packages/webpack-plugin/src/loader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface DevupUiLoaderOptions {
88
cssFile: string
99
}
1010

11-
const devupUiLoader: RawLoaderDefinitionFunction<DevupUiLoaderOptions> =
11+
const devupUILoader: RawLoaderDefinitionFunction<DevupUiLoaderOptions> =
1212
function (source) {
1313
const { package: libPackage, cssFile } = this.getOptions()
1414
const callback = this.async()
@@ -41,4 +41,4 @@ const devupUiLoader: RawLoaderDefinitionFunction<DevupUiLoaderOptions> =
4141
}
4242
return
4343
}
44-
export default devupUiLoader
44+
export default devupUILoader

0 commit comments

Comments
 (0)