您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

functions.any.ts 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. declare type StyleSheet = {
  2. [key: string]: string | number | { [key: string]: string | number; };
  3. };
  4. export type StyleType = StyleSheet | Array<StyleSheet>;
  5. /**
  6. * RegExp pattern for long HEX color format.
  7. */
  8. const HEX_LONG_COLOR_FORMAT
  9. = /^#([0-9A-F]{2,2})([0-9A-F]{2,2})([0-9A-F]{2,2})$/i;
  10. /**
  11. * RegExp pattern for short HEX color format.
  12. */
  13. const HEX_SHORT_COLOR_FORMAT
  14. = /^#([0-9A-F]{1,1})([0-9A-F]{1,1})([0-9A-F]{1,1})$/i;
  15. /**
  16. * RegExp pattern for RGB color format.
  17. */
  18. const RGB_COLOR_FORMAT = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/i;
  19. /**
  20. * RegExp pattern for RGBA color format.
  21. */
  22. const RGBA_COLOR_FORMAT
  23. = /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*([0-9.]+)\)$/i;
  24. /**
  25. * The list of the well-known style properties which may not be numbers on Web
  26. * but must be numbers on React Native.
  27. *
  28. * @private
  29. */
  30. const _WELL_KNOWN_NUMBER_PROPERTIES = [ 'height', 'width' ];
  31. /**
  32. * Function to convert complex StyleType styles into a single flat object,
  33. * so then they can be deconstructed for further processing.
  34. *
  35. * @param {Styletype} st - The complex style type.
  36. * @returns {Object}
  37. */
  38. export function styleTypeToObject(st: StyleType | StyleType[]) {
  39. if (!st) {
  40. return {};
  41. }
  42. if (Array.isArray(st)) {
  43. const flatStyle = {};
  44. for (const styleElement of st) {
  45. Object.assign(flatStyle, styleTypeToObject(styleElement));
  46. }
  47. return flatStyle;
  48. }
  49. return st;
  50. }
  51. /**
  52. * Combines the given 2 styles into a single one.
  53. *
  54. * @param {StyleType} a - An object or array of styles.
  55. * @param {StyleType} b - An object or array of styles.
  56. * @private
  57. * @returns {StyleType} - The merged styles.
  58. */
  59. export function combineStyles(a: StyleType, b: StyleType): StyleType {
  60. const result: Array<StyleSheet> = [];
  61. if (a) {
  62. if (Array.isArray(a)) {
  63. result.push(...a);
  64. } else {
  65. result.push(a);
  66. }
  67. }
  68. if (b) {
  69. if (Array.isArray(b)) {
  70. result.push(...b);
  71. } else {
  72. result.push(b);
  73. }
  74. }
  75. return result;
  76. }
  77. /**
  78. * Create a style sheet using the provided style definitions.
  79. *
  80. * @param {StyleSheet} styles - A dictionary of named style definitions.
  81. * @param {StyleSheet} [overrides={}] - Optional set of additional (often
  82. * platform-dependent/specific) style definitions that will override the base
  83. * (often platform-independent) styles.
  84. * @returns {StyleSheet}
  85. */
  86. export function createStyleSheet(
  87. styles: StyleSheet, overrides: StyleSheet = {}): StyleSheet {
  88. const combinedStyles: any = {};
  89. for (const k of Object.keys(styles)) {
  90. combinedStyles[k]
  91. = _shimStyles({
  92. // @ts-ignore
  93. ...styles[k],
  94. // @ts-ignore
  95. ...overrides[k]
  96. });
  97. }
  98. return combinedStyles;
  99. }
  100. /**
  101. * Returns an rgba format of the provided color if it's in hex or rgb format.
  102. *
  103. * NOTE: The function will return the same color if it's not in one of those
  104. * two formats (e.g. 'white').
  105. *
  106. * @param {string} color - The string representation of the color in rgb or hex
  107. * format.
  108. * @param {number} alpha - The alpha value to apply.
  109. * @returns {string}
  110. */
  111. export function getRGBAFormat(color: string, alpha: number): string {
  112. let match = color.match(HEX_LONG_COLOR_FORMAT);
  113. if (match) {
  114. return `#${match[1]}${match[2]}${match[3]}${_getAlphaInHex(alpha)}`;
  115. }
  116. match = color.match(HEX_SHORT_COLOR_FORMAT);
  117. if (match) {
  118. return `#${match[1]}${match[1]}${match[2]}${match[2]}${match[3]}${
  119. match[3]}${_getAlphaInHex(alpha)}`;
  120. }
  121. match = color.match(RGB_COLOR_FORMAT);
  122. if (match) {
  123. return `rgba(${match[1]}, ${match[2]}, ${match[3]}, ${alpha})`;
  124. }
  125. return color;
  126. }
  127. /**
  128. * Decides if a color is light or dark based on the ITU-R BT.709 and W3C
  129. * recommendations.
  130. *
  131. * NOTE: Please see https://www.w3.org/TR/WCAG20/#relativeluminancedef.
  132. *
  133. * @param {string} color - The color in rgb, rgba or hex format.
  134. * @returns {boolean}
  135. */
  136. export function isDarkColor(color: string): boolean {
  137. const rgb = _getRGBObjectFormat(color);
  138. return ((_getColorLuminance(rgb.r) * 0.2126)
  139. + (_getColorLuminance(rgb.g) * 0.7152)
  140. + (_getColorLuminance(rgb.b) * 0.0722)) <= 0.179;
  141. }
  142. /**
  143. * Converts an [0..1] alpha value into HEX.
  144. *
  145. * @param {number} alpha - The alpha value to convert.
  146. * @returns {string}
  147. */
  148. function _getAlphaInHex(alpha: number): string {
  149. return Number(Math.round(255 * alpha)).toString(16)
  150. .padStart(2, '0');
  151. }
  152. /**
  153. * Calculated the color luminance component for an individual color channel.
  154. *
  155. * NOTE: Please see https://www.w3.org/TR/WCAG20/#relativeluminancedef.
  156. *
  157. * @param {number} c - The color which we need the individual luminance
  158. * for.
  159. * @returns {number}
  160. */
  161. function _getColorLuminance(c: number): number {
  162. return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
  163. }
  164. /**
  165. * Parses a color string into an object containing the RGB values as numbers.
  166. *
  167. * NOTE: Object properties are not alpha-sorted for sanity.
  168. *
  169. * @param {string} color - The color to convert.
  170. * @returns {{
  171. * r: number,
  172. * g: number,
  173. * b: number
  174. * }}
  175. */
  176. function _getRGBObjectFormat(color: string): { b: number; g: number; r: number; } {
  177. let match = color.match(HEX_LONG_COLOR_FORMAT);
  178. if (match) {
  179. return {
  180. r: parseInt(match[1], 16) / 255.0,
  181. g: parseInt(match[2], 16) / 255.0,
  182. b: parseInt(match[3], 16) / 255.0
  183. };
  184. }
  185. match = color.match(HEX_SHORT_COLOR_FORMAT);
  186. if (match) {
  187. return {
  188. r: parseInt(`${match[1]}${match[1]}`, 16) / 255.0,
  189. g: parseInt(`${match[2]}${match[2]}`, 16) / 255.0,
  190. b: parseInt(`${match[3]}${match[3]}`, 16) / 255.0
  191. };
  192. }
  193. match = color.match(RGB_COLOR_FORMAT) || color.match(RGBA_COLOR_FORMAT);
  194. if (match) {
  195. return {
  196. r: parseInt(match[1], 10) / 255.0,
  197. g: parseInt(match[2], 10) / 255.0,
  198. b: parseInt(match[3], 10) / 255.0
  199. };
  200. }
  201. return {
  202. r: 0,
  203. g: 0,
  204. b: 0
  205. };
  206. }
  207. /**
  208. * Shims style properties to work correctly on native. Allows us to minimize the
  209. * number of style declarations that need to be set or overridden for specific
  210. * platforms.
  211. *
  212. * @param {StyleSheet} styles - An object which represents a stylesheet.
  213. * @private
  214. * @returns {StyleSheet}
  215. */
  216. function _shimStyles<T extends StyleSheet>(styles: T): T {
  217. // Certain style properties may not be numbers on Web but must be numbers on
  218. // React Native. For example, height and width may be expressed in percent
  219. // on Web but React Native will not understand them and we will get errors
  220. // (at least during development). Convert such well-known properties to
  221. // numbers if possible; otherwise, remove them to avoid runtime errors.
  222. for (const k of _WELL_KNOWN_NUMBER_PROPERTIES) {
  223. const v = styles[k];
  224. const typeofV = typeof v;
  225. if (typeofV !== 'undefined' && typeofV !== 'number') {
  226. const numberV = Number(v);
  227. if (Number.isNaN(numberV)) {
  228. delete styles[k];
  229. } else {
  230. // @ts-ignore
  231. styles[k] = numberV;
  232. }
  233. }
  234. }
  235. return styles;
  236. }