theme.tsx 9.1 KB

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