Skip to content

Commit

Permalink
fix: typesafe
Browse files Browse the repository at this point in the history
  • Loading branch information
tkow committed Dec 31, 2022
1 parent 02d8cf6 commit 29bdfb1
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 24 deletions.
1 change: 0 additions & 1 deletion src/internals/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-nocheck
export const COLOR_PROPERTIES = {
backgroundColor: 'colors',
border: 'colors',
Expand Down
37 changes: 27 additions & 10 deletions src/internals/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// @ts-nocheck
import { useMemo, useRef } from 'react';
import { PixelRatio, useWindowDimensions } from 'react-native';
import { resolveMediaRangeQueries } from './media';
import { processStyleSheet } from './styles';
import { resolveMediaRangeQueries, Media } from './media';
import { processStyleSheet, ProcessedStyleSheetArgs } from './styles';
import { getCompoundKey } from './utils';

/**
Expand All @@ -15,7 +14,7 @@ import { getCompoundKey } from './utils';
* tablet: DeviceInfo.isTablet(),
* }
*/
export function useMediaQueries(media) {
export function useMediaQueries(media: Media): string[] {
const { width: windowWidth } = useWindowDimensions();

return useMemo(() => {
Expand All @@ -28,20 +27,29 @@ export function useProcessedStyleSheet({
media,
activeMediaQueries,
styleSheet,
}) {
}: ProcessedStyleSheetArgs) {
return useMemo(() => {
return processStyleSheet(styleSheet, media, activeMediaQueries);
}, [styleSheet, activeMediaQueries]); // eslint-disable-line react-hooks/exhaustive-deps
}

type UseVariantStylesArgs = {
props: any;
variants: any;
defaultVariants: Record<string, VariantValue>;
media: ProcessedStyleSheetArgs['media'];
styleSheet: ProcessedStyleSheetArgs['styleSheet'];
activeMediaQueries: ProcessedStyleSheetArgs['activeMediaQueries'];
};

export function useVariantStyles({
props: _props,
variants,
defaultVariants,
media,
styleSheet,
activeMediaQueries,
}) {
}: UseVariantStylesArgs) {
// Only recalculate if the variant props have changed
const props = useStableVariantProps(variants, _props);

Expand Down Expand Up @@ -75,7 +83,7 @@ export function useVariantStyles({
// so that later ones overwrite earlier ones.
if (activeMediaQueries.length > 0) {
activeMediaQueries.forEach((mediaKey) => {
const value = propValue[`@${mediaKey}`];
const value = (propValue as VariantValue)[`@${mediaKey}`];

if (value !== undefined && styleSheet[`${prop}_${value}`]) {
variantStyle = {
Expand Down Expand Up @@ -125,7 +133,13 @@ export function useCompoundVariantStyles({

// Helpers ---------------------------------------------------------------------

function variantPropsEqual(variants, props) {
type VariantValue = { [key: string]: string } | string;
type Optional<Value> = Value | undefined;

function variantPropsEqual(
variants: Record<string, Optional<VariantValue>>,
props: Record<string, Optional<VariantValue>>
): boolean {
const variantKeys = Object.keys(variants);
for (let i = 0; i < variantKeys.length; i++) {
const key = variantKeys[i];
Expand All @@ -134,8 +148,11 @@ function variantPropsEqual(variants, props) {
return true;
}

function useStableVariantProps(variants, props) {
const propsRef = useRef();
function useStableVariantProps(
variants: Record<string, Optional<VariantValue>>,
props: Record<string, Optional<VariantValue>>
) {
const propsRef = useRef<Record<string, Optional<VariantValue>>>();

if (!propsRef.current || !variantPropsEqual(variants, propsRef.current)) {
propsRef.current = props;
Expand Down
9 changes: 5 additions & 4 deletions src/internals/media.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @ts-nocheck
export function resolveMediaRangeQueries(media, width) {
const activeMediaQueries = [];
export type Media = Record<string, boolean | string>;

export function resolveMediaRangeQueries(media: Media, width: number) {
const activeMediaQueries: string[] = [];

for (const [name, query] of Object.entries(media)) {
if (typeof query === 'boolean' && query) {
Expand All @@ -18,7 +19,7 @@ export function resolveMediaRangeQueries(media, width) {

const validSigns = ['<=', '<', '>=', '>'];

function matchMediaRangeQuery(query, windowWidth) {
function matchMediaRangeQuery(query: string, windowWidth: number) {
const singleRangeRegex = /^\(width\s+([><=]+)\s+([0-9]+)px\)$/;
const multiRangeRegex = /^\(([0-9]+)px\s([><=]+)\swidth\s+([><=]+)\s+([0-9]+)px\)$/; // prettier-ignore
const singleRangeMatches = query.match(singleRangeRegex);
Expand Down
46 changes: 40 additions & 6 deletions src/internals/styles.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
// @ts-nocheck
import { StyleSheet } from 'react-native';
import { DEFAULT_THEME_MAP } from './constants';
import { getThemeKey, processThemeMap } from './theme';
import { getCompoundKey } from './utils';
import { Media } from './media';

type StyleValue =
| {
value?: any;
}
| string;

export type ProcessStylesArgs = {
styles: Record<string, StyleValue>;
theme: Record<string, object>;
themeMap: any;
};

/**
* Process styles by replacing all theme tokens with their actual value.
* NOTE: passed styles need to be flattened before calling this!
*/
export function processStyles({ styles, theme, themeMap: customThemeMap }) {
export function processStyles({
styles,
theme,
themeMap: customThemeMap,
}: ProcessStylesArgs) {
const themeMap = processThemeMap(customThemeMap || DEFAULT_THEME_MAP);

return Object.entries(styles).reduce((acc, [key, val]) => {
if (typeof val === 'string' && val.indexOf('$') !== -1) {
// Handle theme tokens, eg. `color: "$primary"` or `color: "$colors$primary"`
const arr = val.split('$');
const token = arr.pop();
const token: string = arr.pop() as string;
const scaleOrSign = arr.pop();
const maybeSign = arr.pop(); // handle negative values
const scale = scaleOrSign !== '-' ? scaleOrSign : undefined;
Expand Down Expand Up @@ -44,13 +60,21 @@ export function processStyles({ styles, theme, themeMap: customThemeMap }) {
}, {});
}

export type CreateStyleSheetArgs = {
theme: any;
themeMap: any;
styles: any;
variants: Record<string, StyleValue>;
compoundVariants: any;
};

export function createStyleSheet({
theme,
themeMap,
styles,
variants,
compoundVariants,
}) {
}: CreateStyleSheetArgs) {
return StyleSheet.create({
base: styles
? processStyles({
Expand Down Expand Up @@ -98,6 +122,12 @@ export function createStyleSheet({
});
}

export type ProcessedStyleSheetArgs = {
media: Media;
activeMediaQueries: string[];
styleSheet: Record<string, object>;
};

/**
* Process the style sheet by inlining media styles.
*
Expand All @@ -118,8 +148,12 @@ export function createStyleSheet({
* @param {string[]} activeMediaQueries
* @returns {Record<string, object>}
*/
export function processStyleSheet(styleSheet, media, activeMediaQueries) {
const prosessedStyleSheet = {};
export function processStyleSheet(
styleSheet: ProcessedStyleSheetArgs['styleSheet'],
media: ProcessedStyleSheetArgs['media'],
activeMediaQueries: ProcessedStyleSheetArgs['activeMediaQueries']
) {
const prosessedStyleSheet: Record<string, object> = {};

Object.entries(styleSheet).forEach(([sKey, sVal]) => {
prosessedStyleSheet[sKey] = {};
Expand Down
1 change: 0 additions & 1 deletion src/internals/theme.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-nocheck
import { THEME_VALUES } from './constants';

export function processThemeMap(themeMap) {
Expand Down
3 changes: 1 addition & 2 deletions src/internals/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-nocheck
import merge from 'lodash.merge';

export function getCompoundKey(compoundEntries) {
Expand Down Expand Up @@ -172,7 +171,7 @@ export function flattenStyles(styles, utils) {
* },
* }
*/
export function flattenVariantStyles(variants, utils) {
export function flattenVariantStyles(variants: Record<string, any>, utils) {
const flatVariants = {};

Object.entries(variants).forEach(([variantProp, variantObj]) => {
Expand Down

0 comments on commit 29bdfb1

Please sign in to comment.