ElementBox.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow strict-local
  9. */
  10. 'use strict';
  11. const BorderBox = require('./BorderBox');
  12. const Dimensions = require('../Utilities/Dimensions');
  13. const React = require('react');
  14. const StyleSheet = require('../StyleSheet/StyleSheet');
  15. const View = require('../Components/View/View');
  16. const flattenStyle = require('../StyleSheet/flattenStyle');
  17. const resolveBoxStyle = require('./resolveBoxStyle');
  18. class ElementBox extends React.Component<$FlowFixMeProps> {
  19. render(): React.Node {
  20. const style = flattenStyle(this.props.style) || {};
  21. let margin = resolveBoxStyle('margin', style);
  22. let padding = resolveBoxStyle('padding', style);
  23. const frameStyle = {...this.props.frame};
  24. const contentStyle = {
  25. width: this.props.frame.width,
  26. height: this.props.frame.height,
  27. };
  28. if (margin != null) {
  29. margin = resolveRelativeSizes(margin);
  30. frameStyle.top -= margin.top;
  31. frameStyle.left -= margin.left;
  32. frameStyle.height += margin.top + margin.bottom;
  33. frameStyle.width += margin.left + margin.right;
  34. if (margin.top < 0) {
  35. contentStyle.height += margin.top;
  36. }
  37. if (margin.bottom < 0) {
  38. contentStyle.height += margin.bottom;
  39. }
  40. if (margin.left < 0) {
  41. contentStyle.width += margin.left;
  42. }
  43. if (margin.right < 0) {
  44. contentStyle.width += margin.right;
  45. }
  46. }
  47. if (padding != null) {
  48. padding = resolveRelativeSizes(padding);
  49. contentStyle.width -= padding.left + padding.right;
  50. contentStyle.height -= padding.top + padding.bottom;
  51. }
  52. return (
  53. <View style={[styles.frame, frameStyle]} pointerEvents="none">
  54. <BorderBox box={margin} style={styles.margin}>
  55. <BorderBox box={padding} style={styles.padding}>
  56. <View style={[styles.content, contentStyle]} />
  57. </BorderBox>
  58. </BorderBox>
  59. </View>
  60. );
  61. }
  62. }
  63. const styles = StyleSheet.create({
  64. frame: {
  65. position: 'absolute',
  66. },
  67. content: {
  68. backgroundColor: 'rgba(200, 230, 255, 0.8)', // blue
  69. },
  70. padding: {
  71. borderColor: 'rgba(77, 255, 0, 0.3)', // green
  72. },
  73. margin: {
  74. borderColor: 'rgba(255, 132, 0, 0.3)', // orange
  75. },
  76. });
  77. type Style = {
  78. top: number,
  79. right: number,
  80. bottom: number,
  81. left: number,
  82. ...
  83. };
  84. /**
  85. * Resolves relative sizes (percentages and auto) in a style object.
  86. *
  87. * @param style the style to resolve
  88. * @return a modified copy
  89. */
  90. function resolveRelativeSizes(style: $ReadOnly<Style>): Style {
  91. let resolvedStyle = Object.assign({}, style);
  92. resolveSizeInPlace(resolvedStyle, 'top', 'height');
  93. resolveSizeInPlace(resolvedStyle, 'right', 'width');
  94. resolveSizeInPlace(resolvedStyle, 'bottom', 'height');
  95. resolveSizeInPlace(resolvedStyle, 'left', 'width');
  96. return resolvedStyle;
  97. }
  98. /**
  99. * Resolves the given size of a style object in place.
  100. *
  101. * @param style the style object to modify
  102. * @param direction the direction to resolve (e.g. 'top')
  103. * @param dimension the window dimension that this direction belongs to (e.g. 'height')
  104. */
  105. function resolveSizeInPlace(
  106. style: Style,
  107. direction: string,
  108. dimension: string,
  109. ) {
  110. if (style[direction] !== null && typeof style[direction] === 'string') {
  111. if (style[direction].indexOf('%') !== -1) {
  112. style[direction] =
  113. (parseFloat(style[direction]) / 100.0) *
  114. Dimensions.get('window')[dimension];
  115. }
  116. if (style[direction] === 'auto') {
  117. // Ignore auto sizing in frame drawing due to complexity of correctly rendering this
  118. style[direction] = 0;
  119. }
  120. }
  121. }
  122. module.exports = ElementBox;