廓形仪rn版本-技术调研
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.1 KiB

  1. import { Dimensions, useWindowDimensions } from 'react-native';
  2. import { useEffect, useState } from 'react';
  3. import resolveConfig from 'tailwindcss/resolveConfig';
  4. import * as tailwindConfig from '@/tailwind.config';
  5. const TailwindTheme = resolveConfig(tailwindConfig as any);
  6. const screenSize = TailwindTheme.theme.screens;
  7. type breakpoints = keyof typeof screenSize | 'default';
  8. type MediaQueriesBreakpoints = {
  9. key: breakpoints;
  10. breakpoint: number;
  11. isValid: boolean;
  12. value?: unknown;
  13. };
  14. type BreakPointValue = Partial<Record<breakpoints, unknown>>;
  15. const resolveScreenWidth: Record<breakpoints, number> = {
  16. default: 0,
  17. };
  18. Object.entries(screenSize).forEach(([key, value]) => {
  19. if (typeof value === 'string') {
  20. resolveScreenWidth[key] = parseInt(value.replace('px', ''), 10);
  21. }
  22. });
  23. export const getBreakPointValue = (
  24. values: BreakPointValue,
  25. width: number
  26. ): unknown => {
  27. if (typeof values !== 'object') return values;
  28. let finalBreakPointResolvedValue: unknown;
  29. const mediaQueriesBreakpoints: Array<MediaQueriesBreakpoints> = [
  30. {
  31. key: 'default',
  32. breakpoint: 0,
  33. isValid: true,
  34. },
  35. ];
  36. Object.keys(resolveScreenWidth).forEach((key) => {
  37. const isValid = isValidBreakpoint(resolveScreenWidth[key], width);
  38. mediaQueriesBreakpoints.push({
  39. key: key,
  40. breakpoint: resolveScreenWidth[key],
  41. isValid: isValid,
  42. });
  43. });
  44. mediaQueriesBreakpoints.sort(
  45. (a: MediaQueriesBreakpoints, b: MediaQueriesBreakpoints) =>
  46. a.breakpoint - b.breakpoint
  47. );
  48. mediaQueriesBreakpoints.forEach(
  49. (breakpoint: MediaQueriesBreakpoints, index: number) => {
  50. breakpoint.value = values.hasOwnProperty(breakpoint.key)
  51. ? values[breakpoint.key]
  52. : mediaQueriesBreakpoints[index - 1]?.value ||
  53. mediaQueriesBreakpoints[0]?.value;
  54. }
  55. );
  56. const lastValidObject = getLastValidObject(mediaQueriesBreakpoints);
  57. if (!lastValidObject) {
  58. finalBreakPointResolvedValue = values;
  59. } else {
  60. finalBreakPointResolvedValue = lastValidObject.value;
  61. }
  62. return finalBreakPointResolvedValue;
  63. };
  64. export function useBreakpointValue(values: BreakPointValue): unknown {
  65. const { width } = useWindowDimensions();
  66. const [currentBreakPointValue, setCurrentBreakPointValue] = useState<unknown>(
  67. getBreakPointValue(values, width)
  68. );
  69. useEffect(() => {
  70. if (typeof values === 'object') {
  71. const finalBreakPointResolvedValue = getBreakPointValue(values, width);
  72. setCurrentBreakPointValue(finalBreakPointResolvedValue);
  73. }
  74. }, [values, width]);
  75. if (typeof values !== 'object') return values;
  76. return currentBreakPointValue;
  77. }
  78. export function isValidBreakpoint(
  79. breakPointWidth: number,
  80. width: number = Dimensions.get('window')?.width || 0
  81. ) {
  82. const windowWidth = width;
  83. return windowWidth >= breakPointWidth;
  84. }
  85. function getLastValidObject(
  86. mediaQueries: Array<{
  87. key: breakpoints;
  88. breakpoint: number;
  89. isValid: boolean;
  90. value?: unknown;
  91. }>
  92. ) {
  93. for (let i = mediaQueries.length - 1; i >= 0; i--) {
  94. if (mediaQueries[i].isValid) {
  95. return mediaQueries[i];
  96. }
  97. }
  98. return null; // No valid object found
  99. }