layout_attributes.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. - [ ] pub display: Display,
  3. - [x] pub position_type: PositionType, --> kinda, taffy doesnt support everything
  4. - [ ] pub direction: Direction,
  5. - [x] pub flex_direction: FlexDirection,
  6. - [x] pub flex_wrap: FlexWrap,
  7. - [x] pub flex_grow: f32,
  8. - [x] pub flex_shrink: f32,
  9. - [x] pub flex_basis: Dimension,
  10. - [x] pub overflow: Overflow, ---> kinda implemented... taffy doesnt have support for directional overflow
  11. - [x] pub align_items: AlignItems,
  12. - [x] pub align_self: AlignSelf,
  13. - [x] pub align_content: AlignContent,
  14. - [x] pub margin: Rect<Dimension>,
  15. - [x] pub padding: Rect<Dimension>,
  16. - [x] pub justify_content: JustifyContent,
  17. - [ ] pub position: Rect<Dimension>,
  18. - [x] pub border: Rect<Dimension>,
  19. - [ ] pub size: Size<Dimension>, ----> ??? seems to only be relevant for input?
  20. - [ ] pub min_size: Size<Dimension>,
  21. - [ ] pub max_size: Size<Dimension>,
  22. - [ ] pub aspect_ratio: Number,
  23. */
  24. use taffy::{
  25. prelude::*,
  26. style::{FlexDirection, PositionType},
  27. };
  28. /// applies the entire html namespace defined in dioxus-html
  29. pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) {
  30. match name {
  31. "align-content"
  32. | "align-items"
  33. | "align-self" => apply_align(name, value, style),
  34. "animation"
  35. | "animation-delay"
  36. | "animation-direction"
  37. | "animation-duration"
  38. | "animation-fill-mode"
  39. | "animation-iteration-count"
  40. | "animation-name"
  41. | "animation-play-state"
  42. | "animation-timing-function" => apply_animation(name, value, style),
  43. "backface-visibility" => {}
  44. "border"
  45. | "border-bottom"
  46. | "border-bottom-color"
  47. | "border-bottom-left-radius"
  48. | "border-bottom-right-radius"
  49. | "border-bottom-style"
  50. | "border-bottom-width"
  51. | "border-collapse"
  52. | "border-color"
  53. | "border-image"
  54. | "border-image-outset"
  55. | "border-image-repeat"
  56. | "border-image-slice"
  57. | "border-image-source"
  58. | "border-image-width"
  59. | "border-left"
  60. | "border-left-color"
  61. | "border-left-style"
  62. | "border-left-width"
  63. | "border-radius"
  64. | "border-right"
  65. | "border-right-color"
  66. | "border-right-style"
  67. | "border-right-width"
  68. | "border-spacing"
  69. | "border-style"
  70. | "border-top"
  71. | "border-top-color"
  72. | "border-top-left-radius"
  73. | "border-top-right-radius"
  74. | "border-top-style"
  75. | "border-top-width"
  76. | "border-width" => apply_border(name, value, style),
  77. "bottom" => {}
  78. "box-shadow" => {}
  79. "box-sizing" => {}
  80. "caption-side" => {}
  81. "clear" => {}
  82. "clip" => {}
  83. "column-count"
  84. | "column-fill"
  85. | "column-gap"
  86. | "column-rule"
  87. | "column-rule-color"
  88. | "column-rule-style"
  89. | "column-rule-width"
  90. | "column-span"
  91. // add column-width
  92. | "column-width" => apply_column(name, value, style),
  93. "columns" => {}
  94. "content" => {}
  95. "counter-increment" => {}
  96. "counter-reset" => {}
  97. "cursor" => {}
  98. "direction" => {}
  99. "display" => apply_display(name, value, style),
  100. "empty-cells" => {}
  101. "flex"
  102. | "flex-basis"
  103. | "flex-direction"
  104. | "flex-flow"
  105. | "flex-grow"
  106. | "flex-shrink"
  107. | "flex-wrap" => apply_flex(name, value, style),
  108. "float" => {}
  109. "height" => {
  110. if let Some(v) = parse_value(value){
  111. style.size.height = match v {
  112. UnitSystem::Percent(v)=> Dimension::Percent(v/100.0),
  113. UnitSystem::Point(v)=> Dimension::Points(v),
  114. };
  115. }
  116. }
  117. "justify-content" => {
  118. use JustifyContent::*;
  119. style.justify_content = match value {
  120. "flex-start" => FlexStart,
  121. "flex-end" => FlexEnd,
  122. "center" => Center,
  123. "space-between" => SpaceBetween,
  124. "space-around" => SpaceAround,
  125. "space-evenly" => SpaceEvenly,
  126. _ => FlexStart,
  127. };
  128. }
  129. "left" => {}
  130. "letter-spacing" => {}
  131. "line-height" => {}
  132. "list-style"
  133. | "list-style-image"
  134. | "list-style-position"
  135. | "list-style-type" => {}
  136. "margin"
  137. | "margin-bottom"
  138. | "margin-left"
  139. | "margin-right"
  140. | "margin-top" => apply_margin(name, value, style),
  141. "max-height" => {}
  142. "max-width" => {}
  143. "min-height" => {}
  144. "min-width" => {}
  145. "opacity" => {}
  146. "order" => {}
  147. "outline" => {}
  148. "outline-color"
  149. | "outline-offset"
  150. | "outline-style"
  151. | "outline-width" => {}
  152. "overflow"
  153. | "overflow-x"
  154. | "overflow-y" => apply_overflow(name, value, style),
  155. "padding"
  156. | "padding-bottom"
  157. | "padding-left"
  158. | "padding-right"
  159. | "padding-top" => apply_padding(name, value, style),
  160. "page-break-after"
  161. | "page-break-before"
  162. | "page-break-inside" => {}
  163. "perspective"
  164. | "perspective-origin" => {}
  165. "position" => {
  166. match value {
  167. "static" => {}
  168. "relative" => style.position_type = PositionType::Relative,
  169. "fixed" => {}
  170. "absolute" => style.position_type = PositionType::Absolute,
  171. "sticky" => {}
  172. _ => {}
  173. }
  174. }
  175. "pointer-events" => {}
  176. "quotes" => {}
  177. "resize" => {}
  178. "right" => {}
  179. "tab-size" => {}
  180. "table-layout" => {}
  181. "top" => {}
  182. "transform"
  183. | "transform-origin"
  184. | "transform-style" => apply_transform(name, value, style),
  185. "transition"
  186. | "transition-delay"
  187. | "transition-duration"
  188. | "transition-property"
  189. | "transition-timing-function" => apply_transition(name, value, style),
  190. "vertical-align" => {}
  191. "visibility" => {}
  192. "white-space" => {}
  193. "width" => {
  194. if let Some(v) = parse_value(value){
  195. style.size.width = match v {
  196. UnitSystem::Percent(v)=> Dimension::Percent(v/100.0),
  197. UnitSystem::Point(v)=> Dimension::Points(v),
  198. };
  199. }
  200. }
  201. "word-break" => {}
  202. "word-spacing" => {}
  203. "word-wrap" => {}
  204. "z-index" => {}
  205. _ => {}
  206. }
  207. }
  208. /// a relative or absolute size
  209. #[derive(Clone, Copy, PartialEq, Debug)]
  210. pub enum UnitSystem {
  211. Percent(f32),
  212. Point(f32),
  213. }
  214. impl From<UnitSystem> for Dimension {
  215. fn from(other: UnitSystem) -> Dimension {
  216. match other {
  217. UnitSystem::Percent(v) => Dimension::Percent(v),
  218. UnitSystem::Point(v) => Dimension::Points(v),
  219. }
  220. }
  221. }
  222. /// parse relative or absolute value
  223. pub fn parse_value(value: &str) -> Option<UnitSystem> {
  224. if value.ends_with("px") {
  225. if let Ok(px) = value.trim_end_matches("px").parse::<f32>() {
  226. Some(UnitSystem::Point(px))
  227. } else {
  228. None
  229. }
  230. } else if value.ends_with('%') {
  231. if let Ok(pct) = value.trim_end_matches('%').parse::<f32>() {
  232. Some(UnitSystem::Percent(pct))
  233. } else {
  234. None
  235. }
  236. } else {
  237. None
  238. }
  239. }
  240. fn apply_overflow(_name: &str, _value: &str, _style: &mut Style) {
  241. // todo: add overflow support to taffy
  242. }
  243. fn apply_display(_name: &str, value: &str, style: &mut Style) {
  244. style.display = match value {
  245. "flex" => Display::Flex,
  246. "block" => Display::None,
  247. _ => Display::Flex,
  248. }
  249. // TODO: there are way more variants
  250. // taffy needs to be updated to handle them
  251. //
  252. // "block" => Display::Block,
  253. // "inline" => Display::Inline,
  254. // "inline-block" => Display::InlineBlock,
  255. // "inline-table" => Display::InlineTable,
  256. // "list-item" => Display::ListItem,
  257. // "run-in" => Display::RunIn,
  258. // "table" => Display::Table,
  259. // "table-caption" => Display::TableCaption,
  260. // "table-cell" => Display::TableCell,
  261. // "table-column" => Display::TableColumn,
  262. // "table-column-group" => Display::TableColumnGroup,
  263. // "table-footer-group" => Display::TableFooterGroup,
  264. // "table-header-group" => Display::TableHeaderGroup,
  265. // "table-row" => Display::TableRow,
  266. // "table-row-group" => Display::TableRowGroup,
  267. // "none" => Display::None,
  268. // _ => Display::Inline,
  269. }
  270. fn apply_border(name: &str, value: &str, style: &mut Style) {
  271. match name {
  272. "border" => {}
  273. "border-bottom" => {}
  274. "border-bottom-color" => {}
  275. "border-bottom-left-radius" => {}
  276. "border-bottom-right-radius" => {}
  277. "border-bottom-style" => {
  278. if style.border.bottom == Dimension::default() {
  279. let v = Dimension::Points(1.0);
  280. style.border.bottom = v;
  281. }
  282. }
  283. "border-bottom-width" => {
  284. if let Some(v) = parse_value(value) {
  285. style.border.bottom = v.into();
  286. }
  287. }
  288. "border-collapse" => {}
  289. "border-color" => {}
  290. "border-image" => {}
  291. "border-image-outset" => {}
  292. "border-image-repeat" => {}
  293. "border-image-slice" => {}
  294. "border-image-source" => {}
  295. "border-image-width" => {}
  296. "border-left" => {}
  297. "border-left-color" => {}
  298. "border-left-style" => {
  299. if style.border.start == Dimension::default() {
  300. let v = Dimension::Points(1.0);
  301. style.border.start = v;
  302. }
  303. }
  304. "border-left-width" => {
  305. if let Some(v) = parse_value(value) {
  306. style.border.start = v.into();
  307. }
  308. }
  309. "border-radius" => {}
  310. "border-right" => {}
  311. "border-right-color" => {}
  312. "border-right-style" => {
  313. let v = Dimension::Points(1.0);
  314. style.border.end = v;
  315. }
  316. "border-right-width" => {
  317. if let Some(v) = parse_value(value) {
  318. style.border.end = v.into();
  319. }
  320. }
  321. "border-spacing" => {}
  322. "border-style" => {
  323. if style.border.top == Dimension::default() {
  324. let v = Dimension::Points(1.0);
  325. style.border.top = v;
  326. }
  327. if style.border.bottom == Dimension::default() {
  328. let v = Dimension::Points(1.0);
  329. style.border.bottom = v;
  330. }
  331. if style.border.start == Dimension::default() {
  332. let v = Dimension::Points(1.0);
  333. style.border.start = v;
  334. }
  335. if style.border.end == Dimension::default() {
  336. let v = Dimension::Points(1.0);
  337. style.border.end = v;
  338. }
  339. }
  340. "border-top" => {}
  341. "border-top-color" => {}
  342. "border-top-left-radius" => {}
  343. "border-top-right-radius" => {}
  344. "border-top-style" => {
  345. if style.border.top == Dimension::default() {
  346. let v = Dimension::Points(1.0);
  347. style.border.top = v;
  348. }
  349. }
  350. "border-top-width" => {
  351. if let Some(v) = parse_value(value) {
  352. style.border.top = v.into();
  353. }
  354. }
  355. "border-width" => {
  356. let values: Vec<_> = value.split(' ').collect();
  357. if values.len() == 1 {
  358. if let Some(w) = parse_value(values[0]) {
  359. style.border.top = w.into();
  360. style.border.bottom = w.into();
  361. style.border.start = w.into();
  362. style.border.end = w.into();
  363. }
  364. } else {
  365. let border_widths = [
  366. &mut style.border.top,
  367. &mut style.border.bottom,
  368. &mut style.border.start,
  369. &mut style.border.end,
  370. ];
  371. for (v, width) in values.into_iter().zip(border_widths) {
  372. if let Some(w) = parse_value(v) {
  373. *width = w.into();
  374. }
  375. }
  376. }
  377. }
  378. _ => (),
  379. }
  380. }
  381. fn apply_animation(name: &str, _value: &str, _style: &mut Style) {
  382. match name {
  383. "animation" => {}
  384. "animation-delay" => {}
  385. "animation-direction =>{}" => {}
  386. "animation-duration" => {}
  387. "animation-fill-mode" => {}
  388. "animation-itera =>{}tion-count" => {}
  389. "animation-name" => {}
  390. "animation-play-state" => {}
  391. "animation-timing-function" => {}
  392. _ => {}
  393. }
  394. }
  395. fn apply_column(name: &str, _value: &str, _style: &mut Style) {
  396. match name {
  397. "column-count" => {}
  398. "column-fill" => {}
  399. "column-gap" => {}
  400. "column-rule" => {}
  401. "column-rule-color" => {}
  402. "column-rule-style" => {}
  403. "column-rule-width" => {}
  404. "column-span" => {}
  405. "column-width" => {}
  406. _ => {}
  407. }
  408. }
  409. fn apply_flex(name: &str, value: &str, style: &mut Style) {
  410. // - [x] pub flex_direction: FlexDirection,
  411. // - [x] pub flex_wrap: FlexWrap,
  412. // - [x] pub flex_grow: f32,
  413. // - [x] pub flex_shrink: f32,
  414. // - [x] pub flex_basis: Dimension,
  415. match name {
  416. "flex" => {}
  417. "flex-direction" => {
  418. use FlexDirection::*;
  419. style.flex_direction = match value {
  420. "row" => Row,
  421. "row-reverse" => RowReverse,
  422. "column" => Column,
  423. "column-reverse" => ColumnReverse,
  424. _ => Row,
  425. };
  426. }
  427. "flex-basis" => {
  428. if let Some(v) = parse_value(value) {
  429. style.flex_basis = match v {
  430. UnitSystem::Percent(v) => Dimension::Percent(v / 100.0),
  431. UnitSystem::Point(v) => Dimension::Points(v),
  432. };
  433. }
  434. }
  435. "flex-flow" => {}
  436. "flex-grow" => {
  437. if let Ok(val) = value.parse::<f32>() {
  438. style.flex_grow = val;
  439. }
  440. }
  441. "flex-shrink" => {
  442. if let Ok(px) = value.parse::<f32>() {
  443. style.flex_shrink = px;
  444. }
  445. }
  446. "flex-wrap" => {
  447. use FlexWrap::*;
  448. style.flex_wrap = match value {
  449. "nowrap" => NoWrap,
  450. "wrap" => Wrap,
  451. "wrap-reverse" => WrapReverse,
  452. _ => NoWrap,
  453. };
  454. }
  455. _ => {}
  456. }
  457. }
  458. fn apply_padding(name: &str, value: &str, style: &mut Style) {
  459. match parse_value(value) {
  460. Some(UnitSystem::Percent(v)) => match name {
  461. "padding" => {
  462. let v = Dimension::Percent(v / 100.0);
  463. style.padding.top = v;
  464. style.padding.bottom = v;
  465. style.padding.start = v;
  466. style.padding.end = v;
  467. }
  468. "padding-bottom" => style.padding.bottom = Dimension::Percent(v / 100.0),
  469. "padding-left" => style.padding.start = Dimension::Percent(v / 100.0),
  470. "padding-right" => style.padding.end = Dimension::Percent(v / 100.0),
  471. "padding-top" => style.padding.top = Dimension::Percent(v / 100.0),
  472. _ => {}
  473. },
  474. Some(UnitSystem::Point(v)) => match name {
  475. "padding" => {
  476. style.padding.top = Dimension::Points(v);
  477. style.padding.bottom = Dimension::Points(v);
  478. style.padding.start = Dimension::Points(v);
  479. style.padding.end = Dimension::Points(v);
  480. }
  481. "padding-bottom" => style.padding.bottom = Dimension::Points(v),
  482. "padding-left" => style.padding.start = Dimension::Points(v),
  483. "padding-right" => style.padding.end = Dimension::Points(v),
  484. "padding-top" => style.padding.top = Dimension::Points(v),
  485. _ => {}
  486. },
  487. None => {}
  488. }
  489. }
  490. fn apply_transform(_name: &str, _value: &str, _style: &mut Style) {
  491. todo!()
  492. }
  493. fn apply_transition(_name: &str, _value: &str, _style: &mut Style) {
  494. todo!()
  495. }
  496. fn apply_align(name: &str, value: &str, style: &mut Style) {
  497. match name {
  498. "align-items" => {
  499. use AlignItems::*;
  500. style.align_items = match value {
  501. "flex-start" => FlexStart,
  502. "flex-end" => FlexEnd,
  503. "center" => Center,
  504. "baseline" => Baseline,
  505. "stretch" => Stretch,
  506. _ => FlexStart,
  507. };
  508. }
  509. "align-content" => {
  510. use AlignContent::*;
  511. style.align_content = match value {
  512. "flex-start" => FlexStart,
  513. "flex-end" => FlexEnd,
  514. "center" => Center,
  515. "space-between" => SpaceBetween,
  516. "space-around" => SpaceAround,
  517. _ => FlexStart,
  518. };
  519. }
  520. "align-self" => {
  521. use AlignSelf::*;
  522. style.align_self = match value {
  523. "auto" => Auto,
  524. "flex-start" => FlexStart,
  525. "flex-end" => FlexEnd,
  526. "center" => Center,
  527. "baseline" => Baseline,
  528. "stretch" => Stretch,
  529. _ => Auto,
  530. };
  531. }
  532. _ => {}
  533. }
  534. }
  535. fn apply_margin(name: &str, value: &str, style: &mut Style) {
  536. match parse_value(value) {
  537. Some(UnitSystem::Percent(v)) => match name {
  538. "margin" => {
  539. let v = Dimension::Percent(v / 100.0);
  540. style.margin.top = v;
  541. style.margin.bottom = v;
  542. style.margin.start = v;
  543. style.margin.end = v;
  544. }
  545. "margin-top" => style.margin.top = Dimension::Percent(v / 100.0),
  546. "margin-bottom" => style.margin.bottom = Dimension::Percent(v / 100.0),
  547. "margin-left" => style.margin.start = Dimension::Percent(v / 100.0),
  548. "margin-right" => style.margin.end = Dimension::Percent(v / 100.0),
  549. _ => {}
  550. },
  551. Some(UnitSystem::Point(v)) => match name {
  552. "margin" => {
  553. style.margin.top = Dimension::Points(v);
  554. style.margin.bottom = Dimension::Points(v);
  555. style.margin.start = Dimension::Points(v);
  556. style.margin.end = Dimension::Points(v);
  557. }
  558. "margin-top" => style.margin.top = Dimension::Points(v),
  559. "margin-bottom" => style.margin.bottom = Dimension::Points(v),
  560. "margin-left" => style.margin.start = Dimension::Points(v),
  561. "margin-right" => style.margin.end = Dimension::Points(v),
  562. _ => {}
  563. },
  564. None => {}
  565. }
  566. }