Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

feat(Accordion): add props interface #33

Merged
merged 17 commits into from Aug 24, 2018
Merged

Conversation

bmdalex
Copy link
Collaborator

@bmdalex bmdalex commented Jul 31, 2018

Component Interfaces

This PR introduces a fix for UIComponent props to make them work with React attributes

@codecov
Copy link

codecov bot commented Jul 31, 2018

Codecov Report

Merging #33 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master      #33   +/-   ##
=======================================
  Coverage   88.37%   88.37%           
=======================================
  Files          47       47           
  Lines         774      774           
  Branches      101      110    +9     
=======================================
  Hits          684      684           
  Misses         87       87           
  Partials        3        3
Impacted Files Coverage Δ
src/components/Accordion/Accordion.tsx 66% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1da274c...aa26eb0. Read the comment docs.

@bmdalex
Copy link
Collaborator Author

bmdalex commented Jul 31, 2018

@mnajdova will take over, it's probably good to go as is

@bmdalex bmdalex changed the title fix: Component interfaces extend React attributes [READY FOR REVIEW] fix: Component interfaces extend React attributes Jul 31, 2018
Copy link
Contributor

@kuzhelov kuzhelov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you 👍

@@ -1,5 +1,5 @@
import { pxToRem } from '../../lib'
import { PositionProperty } from '../../../node_modules/csstype'
import { PositionProperty } from 'csstype'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, thanks for fixing this

}

static handledProps = ['as', 'children', 'circular', 'className', 'content']
static handledProps = ['as', 'children', 'circular', 'className', 'content', 'variables']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@kuzhelov kuzhelov changed the title [READY FOR REVIEW] fix: Component interfaces extend React attributes [CONFIRM MERGE] fix: Component interfaces extend React attributes Aug 1, 2018
@kuzhelov kuzhelov changed the title [CONFIRM MERGE] fix: Component interfaces extend React attributes [ON REVIEW] fix: Component interfaces extend React attributes Aug 1, 2018
class UIComponent<P, S> extends React.Component<P, S> {
export interface UIComponentProps extends HTMLAttributes<HTMLElement> {
as?: string | Function
variables?: (siteVariables: object) => object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, we should make it clear whether plain object could be accepted as value for variables prop - there are quite a few places where this approach is used now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my vote would be to support both options, due to otherwise we could introduce unnecessary additional complexity for the client of this code in certain cases (where it is about just providing some predefined variables independent of theming aspects)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will address this, agreed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will go away with #16, which adds typings for all theming concerns:

https://github.com/stardust-ui/react/blob/418e94761913b8bfc1035982d115693a406d0c12/types/theme.d.ts

import renderComponent, { IRenderResultConfig } from './renderComponent'

class UIComponent<P, S> extends React.Component<P, S> {
export interface UIComponentProps extends HTMLAttributes<HTMLElement> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will flood the user's intellisense with a lot of HTML prop noise. That will make it difficult to know which props are for the component specifically.

There have been some community proposals and discussions in SUIR for how to handle typings like this. The current resolution is to include only typings for the props our components specifically handle. See Semantic-Org/Semantic-UI-React#1072.

Beyond this, there is also some desire to have strict typings that do not allow [key: string]: any. The ideas have not yet been merged, but you can see the need and proposal here: Semantic-Org/Semantic-UI-React#2836

@levithomason
Copy link
Member

levithomason commented Aug 2, 2018

Can we get more information on the issue at hand and how this solves it? I'm not sure this should be merged.

@mnajdova
Copy link
Contributor

mnajdova commented Aug 2, 2018

There were some interfaces added for some of the Components's props, that started complaining when using some props that were not included in the interface (like the variables prop). This is the reason why we added this logic. If we decide not to merge this, then I will create a PR that will delete the usage of the props interfaces for now, and once we have a clear idea how to proceed this, I will return to this. Is this ok? @kuzhelov @levithomason

@kuzhelov
Copy link
Contributor

kuzhelov commented Aug 2, 2018

I agree with making a step back with the types support, and afterwards make an incremental changes that will steadily introduce this back (starting from the general properties that are library-wide, and moving to component-specific interfaces). While doing that, we should keep an eye on preventing IntelliSense flood, as @levithomason has noticed - as well as ensuring that this won't decrease developer's productivity with false compiler warnings and complains.

In general, support @mnajdova proposal on this.

@kuzhelov kuzhelov changed the title [ON REVIEW] fix: Component interfaces extend React attributes [POSTPONED] fix: Component interfaces extend React attributes Aug 2, 2018
@levithomason
Copy link
Member

As a min bar, I think we should include typings for the current props. I don't see a downside to this as it offers intellisense. To avoid the issue of not allowing other props in the typings, we can just add [key: string]: any for now. This will at least keep track of which props our components use.

@mnajdova
Copy link
Contributor

mnajdova commented Aug 8, 2018

@levithomason that's actually a good point, but I would rather wait for the typescript build issues to be resolved first. What do you think?

@levithomason
Copy link
Member

I have captured the thoughts here in #117. Let's add typings one component per PR. I'm sure there will be plenty of fixes / discussions on each as we go.

@levithomason levithomason mentioned this pull request Aug 20, 2018
19 tasks
@levithomason
Copy link
Member

@Bugaa92 I have scoped this PR to "Accordion" since it is first on the #117 list and I'd like to set precedent for linking PRs to each component there.

Would you like to update it to fix Accordion's props per our conclusions?

@levithomason levithomason changed the title [POSTPONED] fix: Component interfaces extend React attributes feat(Accordion): add props interface Aug 20, 2018
@kuzhelov kuzhelov added the needs author changes Author needs to implement changes before merge label Aug 22, 2018
manajdov added 2 commits August 23, 2018 13:40
# Conflicts:
#	src/components/Avatar/avatarRules.ts
#	src/components/Button/Button.tsx
#	src/components/Icon/Icon.tsx
#	src/components/Label/Label.tsx
#	src/components/Text/Text.tsx
#	src/lib/UIComponent.tsx
@mnajdova
Copy link
Contributor

mnajdova commented Aug 23, 2018

Guys, I added initial proposal for the props interface for the Accordion in this PR. Please share your thoughts, and let's use this PR for discussing all aspects of the props interface definitions, so that after this is merged, we can apply the same on the other components as well. cc @Bugaa92 @kuzhelov @smykhailov @miroslavstastny @levithomason

export interface IAccordionProps extends IAccordionPropsStrict {
[key: string]: any
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can try to define following generic type:

type NotStrictProps<T> = T & {
  [key: string]: any
}

then you should be able to use:

interface IAccordionPropsStrict  {
  /** An element type to render as (string or function). */
  as?: any
}

type IAccordionProps = NotStrictProps<IAccordionPropsStrict>

const a: IAccordionProps = {}

a.as = 'div'
a.whatever = 'works as well'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, as this is going to be used in all components, it would be good to be extracted as separate type. Thanks!

@@ -8,12 +8,59 @@ import AccordionContent from './AccordionContent'
import { DefaultBehavior } from '../../lib/accessibility'
import { Accessibility } from '../../lib/accessibility/interfaces'

export interface IAccordionPropsStrict {
/** An element type to render as (string or function). */
as?: any
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make a separate interface for as. Then it could be used in getElementType()

}[]

/** Accessibility behavior if overridden by the user. */
accessibility?: object | Function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accessibility, styles, variables, className are common for all components, shouldn't we extract them to separate interface. If so, then to how many?
Does the same apply to children?

Copy link
Contributor

@mnajdova mnajdova Aug 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about the same thing. For the children, they should be provided even from React itself so I am not sure if we should specify them here at all. Not sure if the same applies for the className as well. For the rest, I would propose having the styles and variables in one interface, because for all themed components both would apply, and having the accessibility in other interface, because I am not sure if it is applicable to all components. We should think about the 'as' property as well. Having this said, I am kind a worry that we would end up with lot's of interfaces, which can become confusing, but at the same time I agree that it could be good for refactoring, if we need to add some common property or rename existing common property in the future for some reason. Any thoughts on this? @kuzhelov @levithomason

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree with the points mentioned above. However, my vote would rather be to do it after strict rtpes will be introduced for all components, so that at this point we will have clear picture around what are the general parts and what are the exceptions/edge cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it! Will wait then for final approve for this PR in order for it to be merged.

* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {object} data - All item props.
*/
onTitleClick?: Function
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be more specific with Function types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

variables?: object | Function
}

export interface IAccordionProps extends IAccordionPropsStrict {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually it can be done in more generic way

type Indexer<T> = { [key: string]: T }

interface IAccordionPropsStrict {
  as?: string
  ...
}

interface IAccordionProps extends Indexer<any>, IAccordionPropsStrict {
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these approach as being more generic, but I think the NotStrictProps types defined as is is sufficient enough and is more explicit with it's name when defining the not strict props interfaces. I will change the definition if you think that we should go with the Indexer type.

@mnajdova mnajdova added 🚀 ready for review and removed needs author changes Author needs to implement changes before merge labels Aug 23, 2018
accessibility?: object | Function

/** Custom styles to be applied for component. */
styles?: object | Function
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use ICSSInJSStyle to get better typings (instead of object)

/** Custom styles to be applied for component. */
styles?: ICSSInJSStyle | Function

what do u think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this would be the following form {root: () => ICSSInJSStyle, otherPart: () => ICSSInJSStyle...} so we cannot generalize to just ICSSInJSStyle

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking about styles, we may be able to define the variables and styles in the following way:
variables?: ComponentVariablesInput
styles?: IComponentPartStylesInput
as these are the types used in the renderComponent. @levithomason am I right about this?

variables?: object | Function
}

export interface IAccordionProps extends IAccordionPropsStrict {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add this as a prop to extend from in UIComponent.tsx together with the other common props? (as, styles and variables)?

something like :

export interface UIComponentProps {
  [key: string]: any

  /** An element type to render as (string or function). */
  as?: any

  /** Custom styles to be applied for component. */
  styles?: ICSSInJSStyle | Function

  /** Custom variables to be applied for component. */
  variables?: object | Function
}
  
class UIComponent<P, S> extends React.Component<P & UIComponentProps, S> {
   // ...
}

and then we remove these from the particular component interfaces

@mnajdova @kuzhelov @levithomason

@kuzhelov
Copy link
Contributor

agreed to decide on where exactlyNotStrictProps<T> should be placed later - currently leave it in the suggested by this PR place

@mnajdova mnajdova merged commit 4ebb956 into master Aug 24, 2018
@bmdalex bmdalex deleted the fix/component-interfaces branch September 7, 2018 14:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants