廓形仪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.

95 lines
2.8 KiB

  1. 'use client';
  2. import React, { useEffect, useLayoutEffect } from 'react';
  3. import { config } from './config';
  4. import { OverlayProvider } from '@gluestack-ui/overlay';
  5. import { ToastProvider } from '@gluestack-ui/toast';
  6. import { setFlushStyles } from '@gluestack-ui/nativewind-utils/flush';
  7. import { script } from './script';
  8. import { ModeType } from './types';
  9. const variableStyleTagId = 'nativewind-style';
  10. const createStyle = (styleTagId: string) => {
  11. const style = document.createElement('style');
  12. style.id = styleTagId;
  13. style.appendChild(document.createTextNode(''));
  14. return style;
  15. };
  16. export const useSafeLayoutEffect =
  17. typeof window !== 'undefined' ? useLayoutEffect : useEffect;
  18. export function GluestackUIProvider({
  19. mode = 'light',
  20. ...props
  21. }: {
  22. mode?: ModeType;
  23. children?: React.ReactNode;
  24. }) {
  25. let cssVariablesWithMode = ``;
  26. Object.keys(config).forEach((configKey) => {
  27. cssVariablesWithMode +=
  28. configKey === 'dark' ? `\n .dark {\n ` : `\n:root {\n`;
  29. const cssVariables = Object.keys(
  30. config[configKey as keyof typeof config]
  31. ).reduce((acc: string, curr: string) => {
  32. acc += `${curr}:${config[configKey as keyof typeof config][curr]}; `;
  33. return acc;
  34. }, '');
  35. cssVariablesWithMode += `${cssVariables} \n}`;
  36. });
  37. setFlushStyles(cssVariablesWithMode);
  38. const handleMediaQuery = React.useCallback((e: MediaQueryListEvent) => {
  39. script(e.matches ? 'dark' : 'light');
  40. }, []);
  41. useSafeLayoutEffect(() => {
  42. if (mode !== 'system') {
  43. const documentElement = document.documentElement;
  44. if (documentElement) {
  45. documentElement.classList.add(mode);
  46. documentElement.classList.remove(mode === 'light' ? 'dark' : 'light');
  47. documentElement.style.colorScheme = mode;
  48. }
  49. }
  50. }, [mode]);
  51. useSafeLayoutEffect(() => {
  52. if (mode !== 'system') return;
  53. const media = window.matchMedia('(prefers-color-scheme: dark)');
  54. media.addListener(handleMediaQuery);
  55. return () => media.removeListener(handleMediaQuery);
  56. }, [handleMediaQuery]);
  57. useSafeLayoutEffect(() => {
  58. if (typeof window !== 'undefined') {
  59. const documentElement = document.documentElement;
  60. if (documentElement) {
  61. const head = documentElement.querySelector('head');
  62. let style = head?.querySelector(`[id='${variableStyleTagId}']`);
  63. if (!style) {
  64. style = createStyle(variableStyleTagId);
  65. style.innerHTML = cssVariablesWithMode;
  66. if (head) head.appendChild(style);
  67. }
  68. }
  69. }
  70. }, []);
  71. return (
  72. <>
  73. <script
  74. suppressHydrationWarning
  75. dangerouslySetInnerHTML={{
  76. __html: `(${script.toString()})('${mode}')`,
  77. }}
  78. />
  79. <OverlayProvider>
  80. <ToastProvider>{props.children}</ToastProvider>
  81. </OverlayProvider>
  82. </>
  83. );
  84. }