-
-
Notifications
You must be signed in to change notification settings - Fork 32.8k
[utils] Add all @material-ui/core/utils to @material-ui/utils #23264
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
Changes from all commits
5901bda
c9489d7
e866f5e
080dd7e
c625415
bd907da
324b3a8
11bbc63
a9a4247
3957119
328ca77
2747327
9066f7a
e0f137c
2d1ac56
c9e7ba0
7a3b4c2
fca1e8d
ebfdc06
623a89e
76810d7
831d74b
e0bc921
b5fe610
39dac58
b65508e
6fd966f
837e33f
9eefcca
5706036
21c706d
18be046
8438658
e2104a5
1312f19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export default class MuiError { | ||
| constructor(message: string); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "1": "Material-UI: Expected valid input target.\nDid you use `inputComponent`?" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import MuiError from '../../../macros/MuiError.macro'; | ||
|
|
||
| throw new MuiError('Material-UI: Expected valid input target.\n' + 'Did you use `inputComponent`?'); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import _formatMuiErrorMessage from '../../formatMuiErrorMessage'; | ||
| throw new Error( | ||
| process.env.NODE_ENV !== 'production' | ||
| ? `Material-UI: Expected valid input target. | ||
| Did you use \`inputComponent\`?` | ||
| : _formatMuiErrorMessage(1), | ||
| ); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export default function capitalize(string: string): string; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import MuiError from '../macros/MuiError.macro'; | ||
| // It should to be noted that this function isn't equivalent to `text-transform: capitalize`. | ||
| // | ||
| // A strict capitalization should uppercase the first letter of each word in the sentence. | ||
| // We only handle the first word. | ||
| export default function capitalize(string) { | ||
| if (typeof string !== 'string') { | ||
| throw new MuiError('Material-UI: `capitalize(string)` expects a string argument.'); | ||
| } | ||
|
|
||
| return string.charAt(0).toUpperCase() + string.slice(1); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export type ChainedFunction = ((...args: any[]) => void) | undefined | null; | ||
|
|
||
| export default function createChainedFunction( | ||
| ...funcs: ChainedFunction[] | ||
| ): (...args: any[]) => never; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /** | ||
| * Safe chained function. | ||
| * | ||
| * Will only create a new function if needed, | ||
| * otherwise will pass back existing functions or null. | ||
| * @param {function} functions to chain | ||
| * @returns {function|null} | ||
| */ | ||
| export default function createChainedFunction(...funcs) { | ||
| return funcs.reduce( | ||
| (acc, func) => { | ||
| if (func == null) { | ||
| return acc; | ||
| } | ||
|
|
||
| if (process.env.NODE_ENV !== 'production') { | ||
| if (typeof func !== 'function') { | ||
| console.error( | ||
| 'Material-UI: Invalid argument type - must only provide functions, undefined, or null.', | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| return function chainedFunction(...args) { | ||
| acc.apply(this, args); | ||
| func.apply(this, args); | ||
| }; | ||
| }, | ||
| () => {}, | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| export interface Cancelable { | ||
| clear(): void; | ||
| } | ||
|
|
||
| export default function debounce<T extends (...args: any[]) => any>( | ||
| func: T, | ||
| wait?: number | ||
| ): T & Cancelable; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // Corresponds to 10 frames at 60 Hz. | ||
| // A few bytes payload overhead when lodash/debounce is ~3 kB and debounce ~300 B. | ||
| export default function debounce(func, wait = 166) { | ||
| let timeout; | ||
| function debounced(...args) { | ||
| const later = () => { | ||
| func.apply(this, args); | ||
| }; | ||
| clearTimeout(timeout); | ||
| timeout = setTimeout(later, wait); | ||
| } | ||
|
|
||
| debounced.clear = () => { | ||
| clearTimeout(timeout); | ||
| }; | ||
|
|
||
| return debounced; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export default function deprecatedPropType<T>(validator: T, reason: string): T; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| export default function deprecatedPropType(validator, reason) { | ||
| if (process.env.NODE_ENV === 'production') { | ||
| return () => null; | ||
| } | ||
|
|
||
| return (props, propName, componentName, location, propFullName) => { | ||
| const componentNameSafe = componentName || '<<anonymous>>'; | ||
| const propFullNameSafe = propFullName || propName; | ||
|
|
||
| if (typeof props[propName] !== 'undefined') { | ||
| return new Error( | ||
| `The ${location} \`${propFullNameSafe}\` of ` + | ||
| `\`${componentNameSafe}\` is deprecated. ${reason}`, | ||
| ); | ||
| } | ||
|
|
||
| return null; | ||
| }; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // A change of the browser zoom change the scrollbar size. | ||
| // Credit https://github.com/twbs/bootstrap/blob/3ffe3a5d82f6f561b82ff78d82b32a7d14aed558/js/src/modal.js#L512-L519 | ||
| export default function getScrollbarSize(doc: Document): number { | ||
| const scrollDiv = doc.createElement('div'); | ||
| scrollDiv.style.width = '99px'; | ||
| scrollDiv.style.height = '99px'; | ||
| scrollDiv.style.position = 'absolute'; | ||
| scrollDiv.style.top = '-9999px'; | ||
| scrollDiv.style.overflow = 'scroll'; | ||
|
|
||
| doc.body.appendChild(scrollDiv); | ||
| const scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth; | ||
| doc.body.removeChild(scrollDiv); | ||
|
|
||
| return scrollbarSize; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,3 +8,24 @@ export { default as getDisplayName } from './getDisplayName'; | |
| export { default as HTMLElementType } from './HTMLElementType'; | ||
| export { default as ponyfillGlobal } from './ponyfillGlobal'; | ||
| export { default as refType } from './refType'; | ||
| export { default as unstable_capitalize } from './capitalize'; | ||
| export { default as unstable_createChainedFunction } from './createChainedFunction'; | ||
| export { default as unstable_debounce } from './debounce'; | ||
| export { default as unstable_deprecatedPropType } from './deprecatedPropType'; | ||
| export { default as unstable_isMuiElement } from './isMuiElement'; | ||
| export { default as unstable_ownerDocument } from './ownerDocument'; | ||
| export { default as unstable_ownerWindow } from './ownerWindow'; | ||
| export { default as unstable_requirePropFactory } from './requirePropFactory'; | ||
| export { default as unstable_setRef } from './setRef'; | ||
| export { default as unstable_useEnhancedEffect } from './useEnhancedEffect'; | ||
| export { default as unstable_useId } from './useId'; | ||
|
Member
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 we need the unstable prefix if we treat all the modules here private?
Member
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. If they're here, they're public.
Member
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. I forgot where I said but I would be way more comfortable by renaming Or we release it as an alpha. Either way, I agree that the current state of /utils being on the same release line as /core (5.x) does not signal that the package is private. It's simply not enough that we treat it as private since we have some responsibility to not clutter npm with more underdocumented packages.
Member
Author
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. Should we then proceed with #23270 move all utils in
Member
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.
I don't understand what that solves. If we change the API of
Member
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.
Considering that some of the utils are required by the system, it would mean the system needs to depend on unstyled. I assume that it's not something we want because the two are solving independent problems.
I think that this option can work 👍.
Member
Author
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. Alright, let me update the exports then
Member
Author
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. Done, everything in
Member
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. We're importing What did we try to accomplish by adding (and not moving) /core/utils to /utils?
Member
Author
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. I don't want to make changes to the existing |
||
| export { default as unstable_unsupportedProp } from './unsupportedProp'; | ||
| export { default as unstable_useControlled } from './useControlled'; | ||
| export { default as unstable_useEventCallback } from './useEventCallback'; | ||
| export { default as unstable_useForkRef } from './useForkRef'; | ||
| export { default as unstable_useIsFocusVisible } from './useIsFocusVisible'; | ||
| export { default as unstable_getScrollbarSize } from './getScrollbarSize'; | ||
| export { | ||
| detectScrollType as unstable_detectScrollType, | ||
| getNormalizedScrollLeft as unstable_getNormalizedScrollLeft, | ||
| } from './scrollLeft'; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import * as React from 'react'; | ||
|
|
||
| export type ClassNameMap<ClassKey extends string = string> = Record<ClassKey, string>; | ||
|
|
||
| export interface StyledComponentProps<ClassKey extends string = string> { | ||
| /** | ||
| * Override or extend the styles applied to the component. | ||
| */ | ||
| classes?: Partial<ClassNameMap<ClassKey>>; | ||
| innerRef?: React.Ref<any>; | ||
| } | ||
|
|
||
| /** | ||
| * Helper type for conform (describeConformance) components that are decorated with `withStyles | ||
| * However, we don't declare classes on this type. | ||
| * It is recommended to declare them manually with an interface so that each class can have a separate JSDOC. | ||
| */ | ||
| export type StandardProps<C, Removals extends keyof C = never> = Omit<C, 'classes' | Removals> & | ||
| // each component declares it's classes in a separate interface for proper JSDOC | ||
| StyledComponentProps<never> & { | ||
| ref?: C extends { ref?: infer RefType } ? RefType : React.Ref<unknown>; | ||
| // TODO: Remove implicit props. Up to each component. | ||
| className?: string; | ||
| style?: React.CSSProperties; | ||
| }; | ||
|
|
||
| export type NamedMuiComponent = React.ComponentType & { muiName: string }; | ||
|
|
||
| export interface NamedMuiElement { | ||
| type: NamedMuiComponent; | ||
| props: StandardProps<{}>; | ||
| key: string | number | null; | ||
| } | ||
|
|
||
| export default function isMuiElement(element: any, muiNames: string[]): element is NamedMuiElement; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import * as React from 'react'; | ||
|
|
||
| export default function isMuiElement(element, muiNames) { | ||
| return React.isValidElement(element) && muiNames.indexOf(element.type.muiName) !== -1; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| export default function ownerDocument(node: Node | undefined): Document { | ||
| return (node && node.ownerDocument) || document; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import ownerDocument from './ownerDocument'; | ||
|
|
||
| export default function ownerWindow(node: Node | undefined): Window { | ||
| const doc = ownerDocument(node); | ||
| return doc.defaultView || window; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export default function requirePropFactory(componentNameInError: string): any; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| export default function requirePropFactory(componentNameInError) { | ||
| if (process.env.NODE_ENV === 'production') { | ||
| return () => null; | ||
| } | ||
|
|
||
| const requireProp = (requiredProp) => ( | ||
| props, | ||
| propName, | ||
| componentName, | ||
| location, | ||
| propFullName, | ||
| ) => { | ||
| const propFullNameSafe = propFullName || propName; | ||
|
|
||
| if (typeof props[propName] !== 'undefined' && !props[requiredProp]) { | ||
| return new Error( | ||
| `The prop \`${propFullNameSafe}\` of ` + | ||
| `\`${componentNameInError}\` must be used on \`${requiredProp}\`.`, | ||
| ); | ||
| } | ||
|
|
||
| return null; | ||
| }; | ||
| return requireProp; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export function detectScrollType(): string; | ||
| export function getNormalizedScrollLeft(element: HTMLElement, direction: string): number; |
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.
Any reason why we do not
timeout = undefinedhere? AFAICT, thesetTimeoutreturn value is anumberin browsers, and these could be recycled.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.
Happy to submit a PR if this makes sense.