This repository was archived by the owner on Mar 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 53
[WIP] feat(create-component): add create component #2200
Closed
+904
−0
Closed
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
1ab8182
-wip
mnajdova cc410c2
-added prototype for testing
mnajdova d275011
merge master, resolve conflicts
levithomason e1d33ce
add clarification comment and perf gain todo
levithomason 458898f
-added mergeComponentStyles cache
mnajdova 132181e
-changed hash fn
mnajdova 67aad10
-fixed bug
mnajdova ec188cf
-more fixes
mnajdova df1a0fe
-make the hash combination of the merged themes
mnajdova ad662f4
-fixed for screener tests
mnajdova cbab865
-removed new package
mnajdova 956c1fa
-allowed inline styles to be nested object
mnajdova 38a3623
-revert mergeComponentStyles cache changes
mnajdova 01a5e63
-reverted factories
mnajdova File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import * as React from 'react' | ||
import { mergeCss } from '@uifabric/merge-styles' | ||
import { | ||
Provider, | ||
FluentTheme, | ||
PlannerFluentTheme, | ||
FluentButton, | ||
FluentMenu, | ||
FluentMenuItem, | ||
} from '@fluentui/react-theming' | ||
|
||
const oddRedBorder = mergeCss({ border: '10px solid red' }) | ||
const example = mergeCss({ margin: 20 }) | ||
|
||
const MenuItemText = (props: any) => { | ||
return <span {...props}>{props.children}</span> | ||
} | ||
|
||
// This is a bad API... :( | ||
const items = [ | ||
{ | ||
slots: { text: MenuItemText, menu: FluentMenu }, | ||
slotProps: { | ||
text: { id: 'blabla', children: 'Bla' }, | ||
menu: { | ||
slotProps: { | ||
items: [ | ||
{ | ||
slots: { text: MenuItemText }, | ||
slotProps: { text: { id: 'blabla', children: 'Boo' } }, | ||
}, | ||
{ | ||
slots: { text: MenuItemText }, | ||
slotProps: { text: { id: 'blabla', children: 'Coo' } }, | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
rounded: true, | ||
}, | ||
{ slots: { text: MenuItemText }, slotProps: { text: { id: 'blabla', children: 'Foo' } } }, | ||
] | ||
|
||
// Much better in my opinion | ||
// const items = [ | ||
// { slots: { text: MenuItemText }, text: { id: 'blabla', children: 'Bla' } }, | ||
// { slots: { text: MenuItemText }, text: { id: 'blabla', children: 'Foo' } } | ||
// ]; | ||
|
||
const Icon: React.FunctionComponent<any> = props => <span {...props}>@</span> | ||
const ButtonThemedExample: React.FunctionComponent<{}> = props => { | ||
const onClick = React.useCallback(() => console.log('clicked button'), []) | ||
const variants = () => { | ||
return ( | ||
<> | ||
<div className={example}> | ||
<FluentButton tiny>tiny</FluentButton> | ||
</div> | ||
<div className={example}> | ||
<FluentButton large>large</FluentButton> | ||
</div> | ||
<div className={example}> | ||
<FluentButton size="s">small</FluentButton> | ||
<FluentButton size="m">medium</FluentButton> | ||
<FluentButton size="l">large</FluentButton> | ||
</div> | ||
|
||
<div className={example}> | ||
<FluentButton shadowed>shadowed</FluentButton> | ||
</div> | ||
<div className={example}> | ||
<FluentButton | ||
bigIcon={true} | ||
slots={{ icon: Icon, primaryText: () => <span>BigIcon</span> }} | ||
/> | ||
</div> | ||
<div className={example}> | ||
<FluentButton id="sdasdas" shadowed tiny> | ||
shadowed & tiny | ||
</FluentButton> | ||
</div> | ||
<div className={example}> | ||
<FluentButton onClick={onClick} shadowed tiny bigIcon> | ||
Shadowed tiny bigIcon | ||
</FluentButton> | ||
</div> | ||
<div className={example}> | ||
<FluentButton onClick={onClick} beautiful> | ||
Beautiful | ||
</FluentButton> | ||
</div> | ||
|
||
<div className={example}> | ||
<FluentButton onClick={onClick} className={oddRedBorder}> | ||
Fluent Button with an odd red border | ||
</FluentButton> | ||
</div> | ||
</> | ||
) | ||
} | ||
return ( | ||
<div> | ||
<h1>Fluent Theme</h1> | ||
<Provider theme={FluentTheme}>{variants()}</Provider> | ||
|
||
<h1>Planner Fluent Theme</h1> | ||
<Provider theme={PlannerFluentTheme}>{variants()}</Provider> | ||
|
||
<h1>Menu</h1> | ||
<Provider theme={PlannerFluentTheme}> | ||
<FluentMenu rounded slotProps={{ items }} /> | ||
<FluentMenuItem | ||
slots={{ menu: FluentMenu }} | ||
slotProps={{ menu: { slotProps: { items } } }} | ||
/> | ||
</Provider> | ||
</div> | ||
) | ||
} | ||
|
||
export default ButtonThemedExample |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
38 changes: 38 additions & 0 deletions
38
packages/react-theming/src/components/Button/BaseButton.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import * as React from 'react'; | ||
|
||
/** | ||
* TODO: | ||
* 1) do we really need slots prop? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean keeping this in context only opposed to also having a slot? <Provider theme={{
components: {
Button: {
slots: { icon: MyIcon },
}
}
}}
/>
vs <Button slots={{ icon: MyIcon }} /> This would allow easy inline overrides of the slots, but is it necessary? |
||
*/ | ||
interface IBaseButtonProps extends React.AllHTMLAttributes<any> { | ||
slots?: any; | ||
slotProps?: any; | ||
} | ||
|
||
export const ButtonText: React.FunctionComponent<any> = props => <span {...props}>my button</span>; | ||
|
||
export const BaseButton: React.FunctionComponent<IBaseButtonProps> = props => { | ||
const { slots, children, slotProps, ...rest } = props; | ||
const { | ||
root: Root = 'button', | ||
icon: Icon, | ||
primaryText: PrimaryText, | ||
secondaryText: SecondaryText, | ||
} = slots || {}; | ||
const { root = {}, icon = {}, primaryText = {}, secondaryText = {} } = slotProps || {}; | ||
|
||
const rootClassName = `${root.className || ''}${` ${rest.className}` || ''}`; | ||
const content = children || ( | ||
<> | ||
{Icon && <Icon {...icon} />} | ||
{PrimaryText && <PrimaryText {...primaryText} />} | ||
{SecondaryText && <SecondaryText {...secondaryText} />} | ||
</> | ||
); | ||
|
||
return ( | ||
<Root {...root} {...rest} className={rootClassName}> | ||
{content} | ||
</Root> | ||
); | ||
}; |
4 changes: 4 additions & 0 deletions
4
packages/react-theming/src/components/Button/FluentButton.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { BaseButton } from './BaseButton'; | ||
import { createComponent } from '../../create-component/createComponent'; | ||
|
||
export const FluentButton = createComponent('FluentButton', BaseButton); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import * as React from 'react'; | ||
import { BaseMenuItem } from './BaseMenuItem'; | ||
|
||
interface IMenuProps { | ||
className?: string; | ||
slots?: any; | ||
slotProps?: any; | ||
} | ||
|
||
export const BaseMenu: React.FunctionComponent<IMenuProps> = props => { | ||
const { slotProps = {}, slots = {}, ...rest } = props; | ||
const { item: MenuItem = BaseMenuItem, root: Root = 'div' } = slots; | ||
const { root: rootProps = {}, items = [] } = slotProps; | ||
const rootClassName = `${rootProps.className || ''}${` ${rest && rest.className}` || ''}`; | ||
return ( | ||
<Root {...rootProps} {...rest} className={rootClassName}> | ||
{items.map((item: any) => ( | ||
<MenuItem key={item.id} {...item} /> | ||
))} | ||
</Root> | ||
); | ||
}; |
32 changes: 32 additions & 0 deletions
32
packages/react-theming/src/components/Menu/BaseMenuItem.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import * as React from 'react'; | ||
|
||
interface IMenuItemProps { | ||
className?: string; | ||
slots?: any; | ||
slotProps?: any; | ||
} | ||
|
||
export const BaseMenuItem: React.FunctionComponent<IMenuItemProps> = props => { | ||
const { children, slots = {}, slotProps = {}, ...rest } = props; | ||
const { root: Root = 'div', text: Text, icon: Icon, menu: Menu } = slots; | ||
const { | ||
root: rootProps = {}, | ||
text: textProps = {}, | ||
icon: iconProps = {}, | ||
menu: menuProps = {}, | ||
} = slotProps; | ||
const rootClassName = `${rootProps.className || ''}${` ${rest && rest.className}` || ''}`; | ||
const content = children || ( | ||
<> | ||
{Icon && <Icon {...iconProps} />} | ||
{Text && <Text {...textProps} />} | ||
{Menu && <Menu {...menuProps} />} | ||
</> | ||
); | ||
|
||
return ( | ||
<Root {...rootProps} {...rest} className={rootClassName}> | ||
{content} | ||
</Root> | ||
); | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { BaseMenu } from './BaseMenu'; | ||
import { FluentMenuItem } from './FluentMenuItem'; | ||
import { createComponent } from '../../create-component/createComponent'; | ||
|
||
export const FluentMenu = createComponent('FluentMenu', BaseMenu, { | ||
slots: { | ||
item: FluentMenuItem, | ||
}, | ||
}); |
13 changes: 13 additions & 0 deletions
13
packages/react-theming/src/components/Menu/FluentMenuItem.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { BaseMenuItem } from './BaseMenuItem'; | ||
import { createComponent } from '../../create-component/createComponent'; | ||
// import { FluentMenu } from './' | ||
|
||
export const FluentMenuItem = createComponent( | ||
'FluentMenuItem', | ||
BaseMenuItem, | ||
// { | ||
// slots: { | ||
// menu: FluentMenu, | ||
// } | ||
// } | ||
); |
14 changes: 14 additions & 0 deletions
14
packages/react-theming/src/components/ThemeProvider/Provider.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import * as React from 'react'; | ||
// import { IBaseThemeShape } from './ThemeShape'; | ||
|
||
/* | ||
interface IProviderProps<T extends IBaseThemeShape> { | ||
theme: T; | ||
} | ||
*/ | ||
|
||
export const ProviderContext = React.createContext(null); | ||
|
||
export const Provider: React.FunctionComponent<any> = props => { | ||
return <ProviderContext.Provider value={props.theme}>{props.children}</ProviderContext.Provider>; | ||
}; |
49 changes: 49 additions & 0 deletions
49
packages/react-theming/src/create-component/ClassCache.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { ClassCache, VariantBasedCacheKeyStrategy } from './ClassCache'; | ||
|
||
describe('ClassCache', () => { | ||
it('allows access via theme and string', () => { | ||
const c = new ClassCache(); | ||
const val = {}; | ||
const theme = {}; | ||
c.set(theme, 'foo-bar-baz', val); | ||
expect(c.get(theme, 'foo-bar-baz')).toBe(val); | ||
}); | ||
|
||
it('allows access via theme and multiple strings', () => { | ||
const c = new ClassCache(); | ||
const val = {}; | ||
const theme = {}; | ||
c.set(theme, 'foo-bar-baz', val); | ||
c.set(theme, 'foo-bar', {}); | ||
expect(c.get(theme, 'foo-bar-baz')).toBe(val); | ||
}); | ||
|
||
it('returns null if entry not found', () => { | ||
const c = new ClassCache(); | ||
expect(c.get({}, '')).toBeNull(); | ||
}); | ||
|
||
describe('getOrSet', () => { | ||
it('allows for passing in of a default value', () => { | ||
const c = new ClassCache(); | ||
const cacheEntry = {}; | ||
const theme = {}; | ||
const key = ''; | ||
const fetchedEntry: any = c.getOrSet(theme, key, cacheEntry); | ||
expect(fetchedEntry).toBe(cacheEntry); | ||
expect(c.get(theme, key)).toBe(cacheEntry); | ||
}); | ||
}); | ||
|
||
describe('with automative cache key computation', () => { | ||
it('handles cache key computation', () => { | ||
const c = new ClassCache(); | ||
const val = {}; | ||
const theme = {}; | ||
c.set(theme, new VariantBasedCacheKeyStrategy(['a', 'b', 'c'], {}).toString(), val); | ||
expect(c.get(theme, new VariantBasedCacheKeyStrategy(['a', 'b', 'c'], {}).toString())).toBe( | ||
val, | ||
); | ||
}); | ||
}); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
export class ClassCache { | ||
private cache = new WeakMap(); | ||
|
||
public get(theme: {}, arg1: string): any { | ||
const obj = this.cache.get(theme); | ||
if (!obj) { | ||
return null; | ||
} | ||
return obj[arg1] || null; | ||
} | ||
|
||
public set(theme: {}, arg1: string, val: {}) { | ||
let themeEntry; | ||
if (this.cache.get(theme)) { | ||
themeEntry = this.cache.get(theme); | ||
} else { | ||
themeEntry = {}; | ||
this.cache.set(theme, themeEntry); | ||
} | ||
themeEntry[arg1] = val; | ||
} | ||
|
||
public getOrSet(theme: {}, key: string, cacheEntry: any): any { | ||
const existing = this.get(theme, key); | ||
if (existing !== undefined && existing !== null) { | ||
return existing; | ||
} | ||
this.set(theme, key, cacheEntry); | ||
return cacheEntry; | ||
} | ||
} | ||
|
||
export class VariantBasedCacheKeyStrategy { | ||
private computed: string; | ||
|
||
constructor(private variants: string[] = [], private props: any = {}) {} | ||
|
||
public toString() { | ||
if (this.computed) { | ||
return this.computed; | ||
} | ||
const computedRaw: any = {}; | ||
this.variants.slice().forEach(v => (computedRaw[v] = this.props[v])); | ||
this.computed = JSON.stringify(computedRaw); | ||
return this.computed; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, you should update this PR based on your proposal here.