시작하기
빈 크레이트에서 배치된 페이지까지
이 페이지에서는 크레이트를 추가하고, HTML 과 CSS 로 페이지를 쓰고, 배치하고, 클릭해 봅니다. HTML 경로가 아직 화면에 그리지 않으므로 지금 결과는 창이 아니라 상자 목록입니다 (#43).
크레이트 추가
crates.io 에서 크레이트를 추가합니다. 0.0.1 에는 두 경로가 다 있고 compose-rust 0.0.1 에 의존합니다. 0.0.x 는 초기 릴리스이고 API 는 바뀝니다.
cargo add dioxus-compose@0.0.1
cargo add dioxus-hooks@0.7 dioxus-signals@0.7
dioxus-hooks 와 dioxus-signals 는 예제들이 쓰는 대로 use_signal
과 시그널 트레이트를 줍니다. 첫 빌드는
compose-rust 의 빌드 스크립트를 거쳐
렌더러도 내려받습니다. 위젯 경로는 그것으로 그리고, HTML 화면은 아직 쓰지 않습니다.
페이지 쓰기
페이지는 컴포넌트 하나와 스타일시트 하나입니다. 예제들은 둘을 한 파일에 두고
app 과 STYLE 로 내보냅니다. 그래서 창은 그 페이지를 보여 줄 수 있고,
테스트는 창 없이 배치할 수 있습니다.
use dioxus_compose::html::prelude::*;
use dioxus_hooks::use_signal;
pub const STYLE: &str = r#"
body { margin: 0; font-family: system-ui, sans-serif; font-size: 16px; line-height: 1.5; }
.page { padding: 40px 48px; }
h1 { margin: 0 0 16px; font-size: 32px; line-height: 40px; }
p { margin: 12px 0; }
"#;
pub fn app() -> Element {
let mut hellos = use_signal(|| 0u32);
let status = match hellos() {
0 => "Nobody has said hello yet".to_string(),
1 => "You said hello once".to_string(),
n => format!("You said hello {n} times"),
};
rsx! {
main { class: "page",
h1 { id: "title", "Hello, Dioxus" }
p { id: "action",
a {
id: "greet",
href: "#",
onclick: move |event| {
event.prevent_default();
hellos += 1;
},
"Say hello"
}
}
p { id: "status", "{status}" }
}
}
}
요소는 Dioxus 자체의 HTML 요소이고, 웹이나 데스크톱 Dioxus 앱이 쓰는 것과 같습니다. 속성은
class, 이벤트는 onclick 과 oninput 이며,
event.prevent_default() 도 웹에서처럼 동작합니다.
배치하기
HtmlDom 이 앱을 실행하고, CSS 픽셀 단위의 뷰포트 크기와 CSS 픽셀당 장치 픽셀
배율로 배치합니다. 돌려받는 그리기 목록에는 상자마다 항목이 하나씩 그리는 순서대로 있습니다.
fn main() {
let mut dom = HtmlDom::with_config(app, HtmlConfig {
stylesheets: vec![STYLE.to_string()],
..HtmlConfig::default()
});
let list = dom.layout(800.0, 600.0, 1.0);
for entry in &list.entries {
println!("{:<6} {:?}", entry.tag, entry.rect);
}
}
cargo run 은 상자를 출력하고 끝납니다. 창은 열리지 않습니다. 상자를 그리는 일이
아직 없는 다리의 몫이기 때문입니다. HtmlConfig 는 텍스트 측정기, 색 구성표, 기준
URL, 이미지 리졸버도 받으며, 뒤 페이지에서 다룹니다.
클릭하기
한 점을 누르면 렌더러가 보낼 포인터 이벤트처럼 그 아래 요소의 핸들러로 갑니다. 아래는 hello 예제의 테스트를 줄인 것입니다. 수치는 스타일시트와, 모든 글자를 글꼴 크기의 절반 폭으로 재는 테스트용 측정기에서 나옵니다.
let mut dom = HtmlDom::with_config(hello::app, config(hello::STYLE, Measurer::new()));
dom.layout(800.0, 600.0, 1.0);
let run = &entry(&dom, "action").texts[0];
assert_eq!(run.text, "Say hello");
assert_rect(run.rect, 48.0, 132.0, 72.0, 24.0, "the link's text");
let (x, y) = centre(run.rect);
assert_eq!(dom.click(x, y), Some(node(&dom, "greet")));
dom.render();
dom.layout(800.0, 600.0, 1.0);
assert_eq!(text_of(entry(&dom, "status")), "You said hello once");
핸들러는 click 안에서 실행됩니다. render 가 핸들러가 바꾼 것을 문서에
적용하고, 다음 layout 에 그것이 나타납니다.
예제 돌리기
samples/ 의 예제 열한 개가 이렇게 쓰여 있고, 하나가 크레이트 하나입니다. 이 가이드의 나머지 페이지는 이 예제들을 인용합니다. 각 예제의 테스트는 모든 배치를 손으로 계산한 수치와 비교하고, 렌더러가 부를 것과 같은 호출로 클릭하고 입력하고 제출합니다. 저장소 체크아웃에서 다음과 같이 돌립니다.
cargo test -p sample-html-hello
cargo test -p sample-html-hello -p sample-html-chat -p sample-html-todo
| 예제 | 보여 주는 것 | 페이지 |
|---|---|---|
hello | 제목, 인라인 굵게와 기울임, 클릭 수를 세는 링크 | 텍스트 |
article | 제목, 줄바꿈되는 문단, 목록, 인용, 코드 블록 | 텍스트 |
dashboard | 상단 바, 사이드바, 줄바꿈되는 지표 카드. 모두 flexbox | 레이아웃 |
gallery | 그라디언트 헤더 아래 CSS grid 사진 목록 | 이미지 |
settings | 폼: 텍스트 입력란, 텍스트 영역, select, 체크박스, 라디오 그룹 | 폼 |
table | 옆으로 스크롤되는 HTML 표, 금액 머리글로 정렬 | 레이아웃 |
chat | 아래에 고정된 입력 줄 위로 스크롤되는 대화 | 스크롤 |
todo | 키가 있는 행의 추가, 체크, 삭제, 순서 바꾸기 | 폼 |
overlay | 드롭다운 메뉴, 고정 배경 위 대화 상자, 잘린 미리보기 | 오버레이 |
theme | CSS 사용자 정의 속성으로 쓴 색, 어두운 세트, 덮어쓰기 버튼 | 테마 |
workbench | 작은 코드 편집기: 액티비티 바, 파일 트리, 탭, 상태 표시줄 | 레이아웃 |
지금 그려지는 위젯 경로
Compose 위젯 이름으로 쓴 앱은 같은 의존성으로 지금 창에서 돕니다.
dioxus_compose::launch(app) 가 창을 열고, cargo run 이 빌드하고 실행합니다.
렌더러는 compose-rust 에서 오며, 그 빌드 스크립트가 대상 플랫폼의 렌더러를 내려받습니다. 이런 앱을
쓰는 방법은 rsx! 의 위젯에 있고, 예제는
compose-rust/samples/ 에 있습니다.
이 저장소에서 작업하기
이 저장소는 모두 Rust 이므로 테스트는 명령 하나입니다.
cargo test --workspace
./scripts/check.sh 가 전체 검사입니다. 포맷, 경고를 오류로 다루는 Clippy, 테스트,
벤치마크입니다. 렌더러와 그 빌드, 디자인 시스템은
compose-rust 에 있고, 그쪽 작업 방법은 그
README 에 있습니다.