theme.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import {
  2. useContext
  3. } from "react";
  4. import {
  5. type ThemeContextStateType,
  6. type GapPropagationType,
  7. type ThemeContextType,
  8. type SharpnessType,
  9. type ThemesType
  10. } from "../types";
  11. import NCoreContext, {
  12. type ConfigType
  13. } from "ncore-context";
  14. import {
  15. mergeTypographyTokens,
  16. mergePalettes,
  17. mergeShapes
  18. } from "../helpers";
  19. import _defaultPaletteData from "../variants/themes/default.json";
  20. import {
  21. androidTypographyFixer
  22. } from "../utils";
  23. const defaultPaletteData = androidTypographyFixer(_defaultPaletteData);
  24. class NCoreUIKitTheme<T extends ThemesType> extends NCoreContext<ThemeContextType, ConfigType<ThemeContextType>> {
  25. projectThemes?: NCoreUIKit.Palette = defaultPaletteData;
  26. useContext = ({
  27. gapPropagation,
  28. paletteKey,
  29. sharpness,
  30. themeKey
  31. }: {
  32. gapPropagation?: GapPropagationType;
  33. paletteKey?: NCoreUIKit.PaletteKey;
  34. themeKey?: NCoreUIKit.ThemeKey;
  35. sharpness?: SharpnessType;
  36. } = {}): ThemeContextType => {
  37. const currentState = useContext(this.stateContext);
  38. if(
  39. gapPropagation ||
  40. paletteKey ||
  41. sharpness ||
  42. themeKey
  43. ) {
  44. const activeState = this.prepare({
  45. activeGapPropagation: gapPropagation ? gapPropagation : currentState.activeGapPropagation,
  46. activeSharpness: sharpness ? sharpness : currentState.activeSharpness,
  47. activePalette: paletteKey ? paletteKey : currentState.activePalette,
  48. activeTheme: themeKey ? themeKey : currentState.activeTheme
  49. });
  50. return {
  51. ...currentState,
  52. ...activeState
  53. };
  54. }
  55. return currentState;
  56. };
  57. constructor(initialState: T) {
  58. const {
  59. projectThemes,
  60. initialSelectedActiveSharpness,
  61. initialSelectedGapPropagation,
  62. initialSelectedPalette,
  63. initialSelectedTheme
  64. } = initialState;
  65. const initialPalette = defaultPaletteData.palettes.find(p => p.name === "nibgat");
  66. if(!initialPalette) {
  67. throw new Error("Initial Theme error!.");
  68. }
  69. const initialTheme = initialPalette.themes[initialSelectedTheme as keyof typeof initialPalette.themes];
  70. super({
  71. activeGapPropagation: initialSelectedGapPropagation ?? "compact",
  72. activeSharpness: initialSelectedActiveSharpness ?? "soft",
  73. inlineSpaces: defaultPaletteData.shapes.inlineSpaces,
  74. typography: defaultPaletteData.typography.spacious,
  75. radiuses: defaultPaletteData.shapes.radiuses.soft,
  76. spaces: defaultPaletteData.shapes.spaces.spacious,
  77. activePalette: initialSelectedPalette ?? "nibgat",
  78. activeTheme: initialSelectedTheme ?? "dark",
  79. borders: defaultPaletteData.shapes.borders,
  80. colors: initialTheme
  81. }, {
  82. key: "NCoreUIKitTheme"
  83. });
  84. this.projectThemes = projectThemes;
  85. const activeState = this.prepare({
  86. activeGapPropagation: initialSelectedGapPropagation ?? "compact",
  87. activeSharpness: initialSelectedActiveSharpness ?? "soft",
  88. activePalette: initialSelectedPalette ?? "nibgat",
  89. activeTheme: initialSelectedTheme ?? "dark"
  90. });
  91. this.setState(activeState);
  92. }
  93. prepare = (props?: {
  94. activeGapPropagation?: GapPropagationType;
  95. activePalette?: NCoreUIKit.PaletteKey;
  96. activeTheme?: NCoreUIKit.ThemeKey;
  97. activeSharpness?: SharpnessType;
  98. }): ThemeContextStateType => {
  99. const gapPropagation = props && props.activeGapPropagation ? props.activeGapPropagation : this.state.activeGapPropagation;
  100. const sharpness = props && props.activeSharpness ? props.activeSharpness : this.state.activeSharpness;
  101. const palette = props && props.activePalette ? props.activePalette : this.state.activePalette;
  102. const theme = props && props.activeTheme ? props.activeTheme : this.state.activeTheme;
  103. const defaultPalette = defaultPaletteData.palettes.find(p => p.name === palette) ?? defaultPaletteData.palettes[0]!;
  104. const defaultTheme = defaultPalette.themes[theme as keyof typeof defaultPalette.themes] ?? defaultPalette.themes.dark;
  105. const defaultState: ThemeContextStateType = {
  106. typography: defaultPaletteData.typography[gapPropagation],
  107. spaces: defaultPaletteData.shapes.spaces[gapPropagation],
  108. radiuses: defaultPaletteData.shapes.radiuses[sharpness],
  109. inlineSpaces: defaultPaletteData.shapes.inlineSpaces,
  110. borders: defaultPaletteData.shapes.borders,
  111. activeGapPropagation: gapPropagation,
  112. activeSharpness: sharpness,
  113. activePalette: palette,
  114. colors: defaultTheme,
  115. activeTheme: theme
  116. };
  117. if(!this.projectThemes || (this.projectThemes && !this.projectThemes.palettes.length)) {
  118. return defaultState;
  119. }
  120. const currentProjectPalette = this.projectThemes.palettes.find(p => p.name === palette);
  121. if(!currentProjectPalette) {
  122. return defaultState;
  123. }
  124. const currentProjectTheme = currentProjectPalette.themes[theme];
  125. if(!currentProjectTheme) {
  126. return defaultState;
  127. }
  128. const shapes = mergeShapes({
  129. projectShapes: this.projectThemes.shapes,
  130. defaultShapes: defaultPaletteData.shapes
  131. });
  132. const typography = mergeTypographyTokens({
  133. defaultTypographyTokens: defaultPaletteData.typography,
  134. projectTypographyTokens: this.projectThemes.typography
  135. });
  136. const colors = mergePalettes(
  137. defaultPaletteData.palettes,
  138. this.projectThemes.palettes,
  139. palette,
  140. theme
  141. );
  142. const newState: ThemeContextStateType = {
  143. typography: typography[gapPropagation],
  144. spaces: shapes.spaces[gapPropagation],
  145. activeGapPropagation: gapPropagation,
  146. radiuses: shapes.radiuses[sharpness],
  147. inlineSpaces: shapes.inlineSpaces,
  148. activeSharpness: sharpness,
  149. borders: shapes.borders,
  150. activePalette: palette,
  151. activeTheme: theme,
  152. colors: colors
  153. };
  154. return newState;
  155. };
  156. switch = ({
  157. gapPropagation,
  158. paletteKey,
  159. sharpness,
  160. themeKey
  161. }: {
  162. gapPropagation?: GapPropagationType;
  163. paletteKey?: NCoreUIKit.PaletteKey;
  164. themeKey?: NCoreUIKit.ThemeKey;
  165. sharpness?: SharpnessType;
  166. }) => {
  167. const activeState = this.prepare({
  168. activeGapPropagation: gapPropagation ?? this.state.activeGapPropagation,
  169. activeSharpness: sharpness ?? this.state.activeSharpness,
  170. activePalette: paletteKey ?? this.state.activePalette,
  171. activeTheme: themeKey ?? this.state.activeTheme
  172. });
  173. this.setState(activeState);
  174. };
  175. updateProjectTheme = (newProjectThemes: NCoreUIKit.Palette, newState?: {
  176. activeGapPropagation?: GapPropagationType;
  177. activePalette?: NCoreUIKit.PaletteKey;
  178. activeTheme?: NCoreUIKit.ThemeKey;
  179. activeSharpness?: SharpnessType;
  180. }) => {
  181. this.projectThemes = newProjectThemes;
  182. const activeState = this.prepare(newState);
  183. this.setState(activeState);
  184. };
  185. }
  186. export default NCoreUIKitTheme;