Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature request] useTheme hook #676

Closed
1 of 2 tasks
x0s3 opened this issue Oct 15, 2019 · 11 comments
Closed
1 of 2 tasks

[feature request] useTheme hook #676

x0s3 opened this issue Oct 15, 2019 · 11 comments
Assignees
Labels
💡 Proposal 📱 Components components module-specific

Comments

@x0s3
Copy link

x0s3 commented Oct 15, 2019

Issue type

I'm submitting a ...

  • bug report
  • feature request

Issue description

Current behavior:
Not implemented yet.

Expected behavior:
Exposing a custom hook useTheme to access to theme context value.

Using this hook we can be able to access the current value theme in this manner:

e.x:

import React from 'react';
import { View } from 'react-native';
import { useTheme } from 'themes';

function MyComponent() {
  const themeValue = useTheme();
  const backgroundColor = React.useMemo(
    () =>
      themeValue === 'light'
        ? { backgroundColor: 'blue' }
        : { backgroundColor: 'darkblue' },
    [themeValue]
  );

  return <View style={[backgroundColor]}></View>;
}

Related code:

Adding a useContext consuming ThemeContext.

export function useTheme(): ThemeType {
  const themeContext = useContext(ThemeContext);

  if (isEmpty(themeContext)) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }

  return themeContext;
}

Other information:

I have a fork with useTheme implemented with tests, but im not able to start expo app -.-
It's not finished yet but if maintainers are agree and see useful this feature im glad to keep working on this pr. link to repo with useTheme: https://github.com/x0s3/react-native-ui-kitten

Im open to talk else feel free to close this feature request :)

@artyorsh
Copy link
Collaborator

artyorsh commented Oct 15, 2019

Hi! Thanks for advice 👍 We'll definitely think about this. Did you know we have withStyles HOC? This will also add theme property in wrapped component.

import { withStyles } from 'react-native-ui-kitten';

const MyComponent = (props) => (
  <View style={{ backgroundColor: props.theme['color-primary-default'] }} />
);

export const MyThemedComponent = withStyles(MyComponent);

Btw to launch playground app in dev mode consider following in this guide

P.S: Just seen we forgot to mention the feature described above in docs :)

@artyorsh artyorsh self-assigned this Oct 15, 2019
@viktor-nikolaev
Copy link

viktor-nikolaev commented Oct 15, 2019

Hi,
I think useStyles is also worth to be implemented.

I used some of yours internal exports, hopefully that's ok.

import { useContext, useMemo } from 'react';
import { StyleType, ThemedStyleType, ThemeType } from 'react-native-ui-kitten';
import { createThemedStyle } from 'react-native-ui-kitten/theme/style/style.service';
import { ThemeContext } from 'react-native-ui-kitten/theme/theme/themeContext';

const createThemedStyles = (style: ThemedStyleType, theme: ThemeType): ThemedStyleType => {
  return Object.keys(style).reduce((acc: StyleType, current: string): ThemedStyleType => {
    return { ...acc, [current]: createThemedStyle(style[current], theme) };
  }, {});
};

export type CreateStylesFunction<T> = (theme: ThemeType) => T;

export function useStyles<T>(createStyles?: CreateStylesFunction<T>): T {
  const theme = useContext(ThemeContext);

  if (!theme) {
    throw new Error('useStyles must be used within a ThemeProvider');
  }

  return useMemo(() => {
    const style: ThemedStyleType = createStyles ? createStyles(theme) : {};
    return createThemedStyles(style, theme);
  }, [createStyles, theme]);
}

usage:

export const Dashboard = ({ style, ...props }) => {
  const styles = useStyles(themedStyle);

  return (
    <Layout {...props} style={[styles.dashboard, style]}/>
  );
};

const themedStyle = theme => ({
  dashboard: {
    backgroundColor: theme['color-danger-disabled'],
  },
});

I would appreciate if you point me on possible errors.

@artyorsh
Copy link
Collaborator

@Veikedo your code does the same, but it memoizes style object rather than passing it to props like it does withStyles. For now, consider using withStyles like it is described in example above. In future, I guess, we can think about renaming this feature :)

@viktor-nikolaev
Copy link

@artyorsh yeah, it's the idea to do the same but with hooks rather than HOC.

@viktor-nikolaev
Copy link

viktor-nikolaev commented Oct 16, 2019

Btw, why not use a plain object instead of CreateStylesFunction ?
eg:

export const ThemedButton = withStyles(Button, {
  backgroundColor: 'color-primary-default',
});

vs current:

export const ThemedButton = withStyles(Button, (theme) => ({
  backgroundColor: theme['color-primary-default'],
}));

is it to make it lazy?

@artyorsh
Copy link
Collaborator

@Veikedo nice notice. It's in our backlog. We currently think about simplifying this APIs, and appreciate any ideas.

Your solution has one lack: in case theme contains more parameters: not only colors but global border-radius etc (sometimes it will) - there is no way to get it from theme

@artyorsh
Copy link
Collaborator

@Veikedo We also have already some scripts to generate typescript interfaces for theme, component parameters and other Eva-based things, so it can make work autocomplete in your IDE, but it is also a beta feature

I also want to answer one question that you probably might have:
We use dash-case for naming variables because we also have a web framework that is also based on Eva Design System :)

@artyorsh artyorsh mentioned this issue Dec 3, 2019
@artyorsh artyorsh closed this as completed Dec 3, 2019
@henoktsegaye
Copy link

'color-primary-default'

This, unfortunately, doesn't work for my case.
its outputting $color-primary-500

@artyorsh
Copy link
Collaborator

artyorsh commented Dec 18, 2019

@henoktsegaye you should use withStyles when accepting theme values

import { withStyles } from '@ui-kitten/components';

const ThemedComponent = withStyles(MyComponent, theme => ({
  container: {
    backgroundColor: theme['color-primary-default'],
  },
}));

@henoktsegaye
Copy link

@artyorsh I don't want to put it in a style, I want to have it as a value

@artyorsh
Copy link
Collaborator

artyorsh commented Dec 18, 2019

@henoktsegaye when using withStyles in component you can do

const backgroundColor = props.themedStyle.container.backgroundColor;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💡 Proposal 📱 Components components module-specific
Projects
None yet
Development

No branches or pull requests

4 participants