Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
f91c7a81
Unverified
Commit
f91c7a81
authored
Apr 06, 2020
by
Tobias Skarhed
Committed by
GitHub
Apr 06, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Forms migration: Move Input folders (#23313)
* Remove exports * Move folders * Fix errors
parent
56687a08
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
254 additions
and
431 deletions
+254
-431
packages/grafana-ui/src/components/Cascader/Cascader.tsx
+1
-1
packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.story.tsx
+1
-1
packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx
+1
-1
packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx
+1
-1
packages/grafana-ui/src/components/Forms/Field.story.tsx
+1
-1
packages/grafana-ui/src/components/Forms/Form.story.tsx
+1
-1
packages/grafana-ui/src/components/Forms/Input/Input.story.tsx
+0
-110
packages/grafana-ui/src/components/Forms/Input/Input.tsx
+0
-260
packages/grafana-ui/src/components/Forms/Legacy/Input/Input.story.tsx
+40
-0
packages/grafana-ui/src/components/Forms/Legacy/Input/Input.test.tsx
+2
-2
packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx
+86
-0
packages/grafana-ui/src/components/Forms/Legacy/Input/__snapshots__/Input.test.tsx.snap
+0
-0
packages/grafana-ui/src/components/Forms/getFormStyles.ts
+1
-1
packages/grafana-ui/src/components/Forms/index.ts
+0
-4
packages/grafana-ui/src/components/Icon/Icon.story.tsx
+5
-4
packages/grafana-ui/src/components/Input/Input.mdx
+0
-0
packages/grafana-ui/src/components/Input/Input.story.tsx
+102
-32
packages/grafana-ui/src/components/Input/Input.tsx
+0
-0
packages/grafana-ui/src/components/OptionsUI/number.tsx
+1
-1
packages/grafana-ui/src/components/OptionsUI/string.tsx
+1
-1
packages/grafana-ui/src/components/Select/IndicatorsContainer.tsx
+1
-1
packages/grafana-ui/src/components/Select/InputControl.tsx
+1
-1
packages/grafana-ui/src/components/TagsInput/TagsInput.tsx
+1
-1
packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.tsx
+1
-1
packages/grafana-ui/src/components/ThresholdsEditorNew/ThresholdsEditor.tsx
+1
-1
packages/grafana-ui/src/components/TimePicker/TimePickerContent/TimeRangeForm.tsx
+1
-1
packages/grafana-ui/src/components/ValueMappingsEditor/LegacyMappingRow.tsx
+1
-1
packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx
+1
-1
packages/grafana-ui/src/components/index.ts
+2
-2
No files found.
packages/grafana-ui/src/components/Cascader/Cascader.tsx
View file @
f91c7a81
...
...
@@ -4,7 +4,7 @@ import RCCascader from 'rc-cascader';
import
{
Select
}
from
'../Select/Select'
;
import
{
FormInputSize
}
from
'../Forms/types'
;
import
{
Input
}
from
'../
Forms/
Input/Input'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
SelectableValue
}
from
'@grafana/data'
;
import
{
css
}
from
'emotion'
;
import
{
onChangeCascader
}
from
'./optionMappings'
;
...
...
packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.story.tsx
View file @
f91c7a81
...
...
@@ -3,7 +3,7 @@ import React, { useState } from 'react';
import
{
storiesOf
}
from
'@storybook/react'
;
import
{
withCenteredStory
}
from
'../../utils/storybook/withCenteredStory'
;
import
{
ClipboardButton
}
from
'./ClipboardButton'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Input
}
from
'../
Forms/Legacy/
Input/Input'
;
import
{
text
}
from
'@storybook/addon-knobs'
;
const
getKnobs
=
()
=>
{
...
...
packages/grafana-ui/src/components/ColorPicker/ColorInput.tsx
View file @
f91c7a81
...
...
@@ -3,7 +3,7 @@ import tinycolor from 'tinycolor2';
import
debounce
from
'lodash/debounce'
;
import
{
ColorPickerProps
}
from
'./ColorPickerPopover'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Input
}
from
'../
Forms/Legacy/
Input/Input'
;
interface
ColorInputState
{
previousColor
:
string
;
...
...
packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx
View file @
f91c7a81
...
...
@@ -9,7 +9,7 @@ import { DataSourceSettings } from '@grafana/data';
import
{
HttpSettingsProps
}
from
'./types'
;
import
{
CustomHeadersSettings
}
from
'./CustomHeadersSettings'
;
import
{
Select
}
from
'../Forms/Legacy/Select/Select'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Input
}
from
'../
Forms/Legacy/
Input/Input'
;
import
{
FormField
}
from
'../FormField/FormField'
;
import
{
FormLabel
}
from
'../FormLabel/FormLabel'
;
import
{
Switch
}
from
'../Switch/Switch'
;
...
...
packages/grafana-ui/src/components/Forms/Field.story.tsx
View file @
f91c7a81
import
React
,
{
useState
,
useCallback
}
from
'react'
;
import
{
boolean
,
number
,
text
}
from
'@storybook/addon-knobs'
;
import
{
Field
}
from
'./Field'
;
import
{
Input
}
from
'./Input/Input'
;
import
{
Input
}
from
'.
.
/Input/Input'
;
import
{
Switch
}
from
'./Switch'
;
import
mdx
from
'./Field.mdx'
;
...
...
packages/grafana-ui/src/components/Forms/Form.story.tsx
View file @
f91c7a81
...
...
@@ -4,7 +4,7 @@ import { Legend } from './Legend';
import
{
withCenteredStory
}
from
'../../utils/storybook/withCenteredStory'
;
import
{
withStoryContainer
}
from
'../../utils/storybook/withStoryContainer'
;
import
{
Field
}
from
'./Field'
;
import
{
Input
}
from
'./Input/Input'
;
import
{
Input
}
from
'.
.
/Input/Input'
;
import
{
Button
}
from
'../Button'
;
import
{
Form
}
from
'./Form'
;
import
{
Switch
}
from
'./Switch'
;
...
...
packages/grafana-ui/src/components/Forms/Input/Input.story.tsx
deleted
100644 → 0
View file @
56687a08
import
React
,
{
useState
}
from
'react'
;
import
{
boolean
,
text
,
select
,
number
}
from
'@storybook/addon-knobs'
;
import
{
withCenteredStory
}
from
'../../../utils/storybook/withCenteredStory'
;
import
{
Input
}
from
'./Input'
;
import
{
Button
}
from
'../../Button'
;
import
mdx
from
'./Input.mdx'
;
import
{
getAvailableIcons
,
IconType
}
from
'../../Icon/types'
;
import
{
KeyValue
}
from
'@grafana/data'
;
import
{
Icon
}
from
'../../Icon/Icon'
;
import
{
Field
}
from
'../Field'
;
export
default
{
title
:
'Forms/Input'
,
component
:
Input
,
decorators
:
[
withCenteredStory
],
parameters
:
{
docs
:
{
page
:
mdx
,
},
},
};
export
const
simple
=
()
=>
{
const
prefixSuffixOpts
=
{
None
:
null
,
Text
:
'$'
,
...
getAvailableIcons
().
reduce
<
KeyValue
<
string
>>
((
prev
,
c
)
=>
{
return
{
...
prev
,
[
`Icon:
${
c
}
`
]:
`icon-
${
c
}
`
,
};
},
{}),
};
const
BEHAVIOUR_GROUP
=
'Behaviour props'
;
// ---
const
type
=
select
(
'Type'
,
{
text
:
'text'
,
password
:
'password'
,
number
:
'number'
,
},
'text'
,
BEHAVIOUR_GROUP
);
const
disabled
=
boolean
(
'Disabled'
,
false
,
BEHAVIOUR_GROUP
);
const
invalid
=
boolean
(
'Invalid'
,
false
,
BEHAVIOUR_GROUP
);
const
loading
=
boolean
(
'Loading'
,
false
,
BEHAVIOUR_GROUP
);
const
VISUAL_GROUP
=
'Visual options'
;
// ---
const
placeholder
=
text
(
'Placeholder'
,
'Enter your name here...'
,
VISUAL_GROUP
);
const
before
=
boolean
(
'Addon before'
,
false
,
VISUAL_GROUP
);
const
after
=
boolean
(
'Addon after'
,
false
,
VISUAL_GROUP
);
const
addonAfter
=
<
Button
variant=
"secondary"
>
Load
</
Button
>;
const
addonBefore
=
<
div
style=
{
{
display
:
'flex'
,
alignItems
:
'center'
,
padding
:
'5px'
}
}
>
Input
</
div
>;
const
prefix
=
select
(
'Prefix'
,
prefixSuffixOpts
,
null
,
VISUAL_GROUP
);
const
suffix
=
select
(
'Suffix'
,
prefixSuffixOpts
,
null
,
VISUAL_GROUP
);
let
prefixEl
:
any
=
prefix
;
if
(
prefix
&&
prefix
.
match
(
/icon-/g
))
{
prefixEl
=
<
Icon
name=
{
prefix
.
replace
(
/icon-/g
,
''
)
as
IconType
}
/>;
}
let
suffixEl
:
any
=
suffix
;
if
(
suffix
&&
suffix
.
match
(
/icon-/g
))
{
suffixEl
=
<
Icon
name=
{
suffix
.
replace
(
/icon-/g
,
''
)
as
IconType
}
/>;
}
const
CONTAINER_GROUP
=
'Container options'
;
// ---
const
containerWidth
=
number
(
'Container width'
,
300
,
{
range
:
true
,
min
:
100
,
max
:
500
,
step
:
10
,
},
CONTAINER_GROUP
);
return
(
<
div
style=
{
{
width
:
containerWidth
}
}
>
<
Input
disabled=
{
disabled
}
invalid=
{
invalid
}
prefix=
{
prefixEl
}
suffix=
{
suffixEl
}
loading=
{
loading
}
addonBefore=
{
before
&&
addonBefore
}
addonAfter=
{
after
&&
addonAfter
}
type=
{
type
}
placeholder=
{
placeholder
}
/>
</
div
>
);
};
export
const
withFieldValidation
=
()
=>
{
const
[
value
,
setValue
]
=
useState
(
''
);
return
(
<
div
>
<
Field
invalid=
{
value
===
''
}
error=
{
value
===
''
?
'This input is required'
:
''
}
>
<
Input
value=
{
value
}
onChange=
{
e
=>
setValue
(
e
.
currentTarget
.
value
)
}
/>
</
Field
>
</
div
>
);
};
packages/grafana-ui/src/components/Forms/Input/Input.tsx
deleted
100644 → 0
View file @
56687a08
import
React
,
{
HTMLProps
,
ReactNode
}
from
'react'
;
import
{
GrafanaTheme
}
from
'@grafana/data'
;
import
{
css
,
cx
}
from
'emotion'
;
import
{
getFocusStyle
,
inputSizes
,
sharedInputStyle
}
from
'../commonStyles'
;
import
{
stylesFactory
,
useTheme
}
from
'../../../themes'
;
import
{
Icon
}
from
'../../Icon/Icon'
;
import
{
useClientRect
}
from
'../../../utils/useClientRect'
;
import
{
FormInputSize
}
from
'../types'
;
export
interface
Props
extends
Omit
<
HTMLProps
<
HTMLInputElement
>
,
'prefix'
|
'size'
>
{
/** Show an invalid state around the input */
invalid
?:
boolean
;
/** Show an icon as a prefix in the input */
prefix
?:
JSX
.
Element
|
string
|
null
;
/** Show an icon as a suffix in the input */
suffix
?:
JSX
.
Element
|
string
|
null
;
/** Show a loading indicator as a suffix in the input */
loading
?:
boolean
;
/** Add a component as an addon before the input */
addonBefore
?:
ReactNode
;
/** Add a component as an addon after the input */
addonAfter
?:
ReactNode
;
size
?:
FormInputSize
;
}
interface
StyleDeps
{
theme
:
GrafanaTheme
;
invalid
:
boolean
;
}
export
const
getInputStyles
=
stylesFactory
(({
theme
,
invalid
=
false
}:
StyleDeps
)
=>
{
const
colors
=
theme
.
colors
;
const
borderRadius
=
theme
.
border
.
radius
.
sm
;
const
height
=
theme
.
spacing
.
formInputHeight
;
const
prefixSuffixStaticWidth
=
'28px'
;
const
prefixSuffix
=
css
`
position: absolute;
top: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
flex-grow: 0;
flex-shrink: 0;
font-size:
${
theme
.
typography
.
size
.
md
}
;
height: 100%;
/* Min width specified for prefix/suffix classes used outside React component*/
min-width:
${
prefixSuffixStaticWidth
}
;
`
;
return
{
// Wraps inputWrapper and addons
wrapper
:
cx
(
css
`
label: input-wrapper;
display: flex;
width: 100%;
height:
${
height
}
;
border-radius:
${
borderRadius
}
;
&:hover {
> .prefix,
.suffix,
.input {
border-color:
${
invalid
?
colors
.
redBase
:
colors
.
formInputBorder
}
;
}
// only show number buttons on hover
input[type='number'] {
-moz-appearance: number-input;
-webkit-appearance: number-input;
appearance: textfield;
}
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
-webkit-appearance: inner-spin-button !important;
opacity: 1;
}
}
`
),
// Wraps input and prefix/suffix
inputWrapper
:
css
`
label: input-inputWrapper;
position: relative;
flex-grow: 1;
/* we want input to be above addons, especially for focused state */
z-index: 1;
/* when input rendered with addon before only*/
&:not(:first-child):last-child {
> input {
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
/* when input rendered with addon after only*/
&:first-child:not(:last-child) {
> input {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
/* when rendered with addon before and after */
&:not(:first-child):not(:last-child) {
> input {
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
input {
/* paddings specified for classes used outside React component */
&:not(:first-child) {
padding-left:
${
prefixSuffixStaticWidth
}
;
}
&:not(:last-child) {
padding-right:
${
prefixSuffixStaticWidth
}
;
}
&[readonly] {
cursor: default;
}
}
`
,
input
:
cx
(
getFocusStyle
(
theme
),
sharedInputStyle
(
theme
,
invalid
),
css
`
label: input-input;
position: relative;
z-index: 0;
flex-grow: 1;
border-radius:
${
borderRadius
}
;
height: 100%;
width: 100%;
`
),
inputDisabled
:
css
`
background-color:
${
colors
.
formInputBgDisabled
}
;
color:
${
colors
.
formInputDisabledText
}
;
`
,
addon
:
css
`
label: input-addon;
display: flex;
justify-content: center;
align-items: center;
flex-grow: 0;
flex-shrink: 0;
position: relative;
&:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
> :last-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
&:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
> :first-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
> *:focus {
/* we want anything that has focus and is an addon to be above input */
z-index: 2;
}
`
,
prefix
:
cx
(
prefixSuffix
,
css
`
label: input-prefix;
padding-left:
${
theme
.
spacing
.
sm
}
;
padding-right:
${
theme
.
spacing
.
xs
}
;
border-right: none;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
`
),
suffix
:
cx
(
prefixSuffix
,
css
`
label: input-suffix;
padding-right:
${
theme
.
spacing
.
sm
}
;
padding-left:
${
theme
.
spacing
.
xs
}
;
border-left: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
right: 0;
`
),
loadingIndicator
:
css
`
& + * {
margin-left:
${
theme
.
spacing
.
xs
}
;
}
`
,
};
});
export
const
Input
=
React
.
forwardRef
<
HTMLInputElement
,
Props
>
((
props
,
ref
)
=>
{
const
{
className
,
addonAfter
,
addonBefore
,
prefix
,
suffix
,
invalid
,
loading
,
size
=
'auto'
,
...
restProps
}
=
props
;
/**
* Prefix & suffix are positioned absolutely within inputWrapper. We use client rects below to apply correct padding to the input
* when prefix/suffix is larger than default (28px = 16px(icon) + 12px(left/right paddings)).
* Thanks to that prefix/suffix do not overflow the input element itself.
*/
const
[
prefixRect
,
prefixRef
]
=
useClientRect
<
HTMLDivElement
>
();
const
[
suffixRect
,
suffixRef
]
=
useClientRect
<
HTMLDivElement
>
();
const
theme
=
useTheme
();
const
styles
=
getInputStyles
({
theme
,
invalid
:
!!
invalid
});
return
(
<
div
className=
{
cx
(
styles
.
wrapper
,
inputSizes
()[
size
],
className
)
}
>
{
!!
addonBefore
&&
<
div
className=
{
styles
.
addon
}
>
{
addonBefore
}
</
div
>
}
<
div
className=
{
styles
.
inputWrapper
}
>
{
prefix
&&
(
<
div
className=
{
styles
.
prefix
}
ref=
{
prefixRef
}
>
{
prefix
}
</
div
>
)
}
<
input
ref=
{
ref
}
className=
{
styles
.
input
}
{
...
restProps
}
style=
{
{
paddingLeft
:
prefixRect
?
prefixRect
.
width
:
undefined
,
paddingRight
:
suffixRect
?
suffixRect
.
width
:
undefined
,
}
}
/>
{
(
suffix
||
loading
)
&&
(
<
div
className=
{
styles
.
suffix
}
ref=
{
suffixRef
}
>
{
loading
&&
<
Icon
name=
"spinner"
className=
{
cx
(
'fa-spin'
,
styles
.
loadingIndicator
)
}
/>
}
{
suffix
}
</
div
>
)
}
</
div
>
{
!!
addonAfter
&&
<
div
className=
{
styles
.
addon
}
>
{
addonAfter
}
</
div
>
}
</
div
>
);
});
Input
.
displayName
=
'Input'
;
packages/grafana-ui/src/components/Forms/Legacy/Input/Input.story.tsx
0 → 100644
View file @
f91c7a81
import
React
,
{
useState
}
from
'react'
;
import
{
zip
,
fromPairs
}
from
'lodash'
;
import
{
storiesOf
}
from
'@storybook/react'
;
import
{
withCenteredStory
}
from
'../../../../utils/storybook/withCenteredStory'
;
import
{
Input
}
from
'./Input'
;
import
{
text
,
select
}
from
'@storybook/addon-knobs'
;
import
{
EventsWithValidation
}
from
'../../../../utils'
;
const
getKnobs
=
()
=>
{
return
{
validation
:
text
(
'Validation regex (will do a partial match if you do not anchor it)'
,
''
),
validationErrorMessage
:
text
(
'Validation error message'
,
'Input not valid'
),
validationEvent
:
select
(
'Validation event'
,
fromPairs
(
zip
(
Object
.
keys
(
EventsWithValidation
),
Object
.
values
(
EventsWithValidation
))),
EventsWithValidation
.
onBlur
),
};
};
const
Wrapper
=
()
=>
{
const
{
validation
,
validationErrorMessage
,
validationEvent
}
=
getKnobs
();
const
[
value
,
setValue
]
=
useState
(
''
);
const
validations
=
{
[
validationEvent
]:
[
{
rule
:
(
value
:
string
)
=>
{
return
!!
value
.
match
(
validation
);
},
errorMessage
:
validationErrorMessage
,
},
],
};
return
<
Input
value=
{
value
}
onChange=
{
e
=>
setValue
(
e
.
currentTarget
.
value
)
}
validationEvents=
{
validations
}
/>;
};
const
story
=
storiesOf
(
'General/Input'
,
module
);
story
.
addDecorator
(
withCenteredStory
);
story
.
add
(
'input'
,
()
=>
<
Wrapper
/>);
packages/grafana-ui/src/components/Input/Input.test.tsx
→
packages/grafana-ui/src/components/
Forms/Legacy/
Input/Input.test.tsx
View file @
f91c7a81
...
...
@@ -2,8 +2,8 @@ import React from 'react';
import
renderer
from
'react-test-renderer'
;
import
{
shallow
}
from
'enzyme'
;
import
{
Input
}
from
'./Input'
;
import
{
EventsWithValidation
}
from
'../../utils'
;
import
{
ValidationEvents
}
from
'../../types'
;
import
{
EventsWithValidation
}
from
'../../
../../
utils'
;
import
{
ValidationEvents
}
from
'../../
../../
types'
;
const
TEST_ERROR_MESSAGE
=
'Value must be empty or less than 3 chars'
;
const
testBlurValidation
:
ValidationEvents
=
{
...
...
packages/grafana-ui/src/components/Forms/Legacy/Input/Input.tsx
0 → 100644
View file @
f91c7a81
import
React
,
{
PureComponent
,
ChangeEvent
}
from
'react'
;
import
classNames
from
'classnames'
;
import
{
validate
,
EventsWithValidation
,
hasValidationEvent
}
from
'../../../../utils'
;
import
{
ValidationEvents
,
ValidationRule
}
from
'../../../../types'
;
export
enum
LegacyInputStatus
{
Invalid
=
'invalid'
,
Valid
=
'valid'
,
}
interface
Props
extends
React
.
HTMLProps
<
HTMLInputElement
>
{
validationEvents
?:
ValidationEvents
;
hideErrorMessage
?:
boolean
;
inputRef
?:
React
.
LegacyRef
<
HTMLInputElement
>
;
// Override event props and append status as argument
onBlur
?:
(
event
:
React
.
FocusEvent
<
HTMLInputElement
>
,
status
?:
LegacyInputStatus
)
=>
void
;
onFocus
?:
(
event
:
React
.
FocusEvent
<
HTMLInputElement
>
,
status
?:
LegacyInputStatus
)
=>
void
;
onChange
?:
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
,
status
?:
LegacyInputStatus
)
=>
void
;
}
interface
State
{
error
:
string
|
null
;
}
export
class
Input
extends
PureComponent
<
Props
,
State
>
{
static
defaultProps
=
{
className
:
''
,
};
state
:
State
=
{
error
:
null
,
};
get
status
()
{
return
this
.
state
.
error
?
LegacyInputStatus
.
Invalid
:
LegacyInputStatus
.
Valid
;
}
get
isInvalid
()
{
return
this
.
status
===
LegacyInputStatus
.
Invalid
;
}
validatorAsync
=
(
validationRules
:
ValidationRule
[])
=>
{
return
(
evt
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
errors
=
validate
(
evt
.
target
.
value
,
validationRules
);
this
.
setState
(
prevState
=>
{
return
{
...
prevState
,
error
:
errors
?
errors
[
0
]
:
null
};
});
};
};
populateEventPropsWithStatus
=
(
restProps
:
any
,
validationEvents
:
ValidationEvents
|
undefined
)
=>
{
const
inputElementProps
=
{
...
restProps
};
if
(
!
validationEvents
)
{
return
inputElementProps
;
}
Object
.
keys
(
EventsWithValidation
).
forEach
(
eventName
=>
{
if
(
hasValidationEvent
(
eventName
as
EventsWithValidation
,
validationEvents
)
||
restProps
[
eventName
])
{
inputElementProps
[
eventName
]
=
async
(
evt
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
evt
.
persist
();
// Needed for async. https://reactjs.org/docs/events.html#event-pooling
if
(
hasValidationEvent
(
eventName
as
EventsWithValidation
,
validationEvents
))
{
await
this
.
validatorAsync
(
validationEvents
[
eventName
]).
apply
(
this
,
[
evt
]);
}
if
(
restProps
[
eventName
])
{
restProps
[
eventName
].
apply
(
null
,
[
evt
,
this
.
status
]);
}
};
}
});
return
inputElementProps
;
};
render
()
{
const
{
validationEvents
,
className
,
hideErrorMessage
,
inputRef
,
...
restProps
}
=
this
.
props
;
const
{
error
}
=
this
.
state
;
const
inputClassName
=
classNames
(
'gf-form-input'
,
{
invalid
:
this
.
isInvalid
},
className
);
const
inputElementProps
=
this
.
populateEventPropsWithStatus
(
restProps
,
validationEvents
);
return
(
<
div
style=
{
{
flexGrow
:
1
}
}
>
<
input
{
...
inputElementProps
}
ref=
{
inputRef
}
className=
{
inputClassName
}
/>
{
error
&&
!
hideErrorMessage
&&
<
span
>
{
error
}
</
span
>
}
</
div
>
);
}
}
packages/grafana-ui/src/components/Input/__snapshots__/Input.test.tsx.snap
→
packages/grafana-ui/src/components/
Forms/Legacy/
Input/__snapshots__/Input.test.tsx.snap
View file @
f91c7a81
File moved
packages/grafana-ui/src/components/Forms/getFormStyles.ts
View file @
f91c7a81
...
...
@@ -5,7 +5,7 @@ import { getLegendStyles } from './Legend';
import
{
getFieldValidationMessageStyles
}
from
'./FieldValidationMessage'
;
import
{
getButtonStyles
,
ButtonVariant
}
from
'../Button'
;
import
{
ComponentSize
}
from
'../../types/size'
;
import
{
getInputStyles
}
from
'./Input/Input'
;
import
{
getInputStyles
}
from
'.
.
/Input/Input'
;
import
{
getSwitchStyles
}
from
'./Switch'
;
import
{
getCheckboxStyles
}
from
'./Checkbox'
;
...
...
packages/grafana-ui/src/components/Forms/index.ts
View file @
f91c7a81
import
{
Controller
as
InputControl
}
from
'react-hook-form'
;
import
{
getFormStyles
}
from
'./getFormStyles'
;
import
{
Label
}
from
'./Label'
;
// To be removed
import
{
Input
}
from
'./Input/Input'
;
import
{
RadioButtonGroup
}
from
'./RadioButtonGroup/RadioButtonGroup'
;
import
{
Form
}
from
'./Form'
;
import
{
Field
}
from
'./Field'
;
...
...
@@ -16,8 +14,6 @@ const Forms = {
Switch
,
getFormStyles
,
Label
,
// To be removed
Input
,
Form
,
Field
,
InputControl
,
...
...
packages/grafana-ui/src/components/Icon/Icon.story.tsx
View file @
f91c7a81
import
React
,
{
ChangeEvent
,
useState
}
from
'react'
;
import
{
css
}
from
'emotion'
;
import
{
Forms
}
from
'../index'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Field
}
from
'../Forms/Field'
;
import
{
Icon
}
from
'./Icon'
;
import
{
getAvailableIcons
,
IconType
}
from
'./types'
;
import
{
withCenteredStory
}
from
'../../utils/storybook/withCenteredStory'
;
...
...
@@ -79,13 +80,13 @@ export const simple = () => {
width: 100%;
`
}
>
<
F
orms
.
F
ield
<
Field
className=
{
css
`
width: 300px;
`
}
>
<
Forms
.
Input
onChange=
{
searchIcon
}
placeholder=
"Search icons by name"
/>
</
F
orms
.
F
ield
>
<
Input
onChange=
{
searchIcon
}
placeholder=
"Search icons by name"
/>
</
Field
>
<
div
className=
{
css
`
display: flex;
...
...
packages/grafana-ui/src/components/
Forms/
Input/Input.mdx
→
packages/grafana-ui/src/components/Input/Input.mdx
View file @
f91c7a81
File moved
packages/grafana-ui/src/components/Input/Input.story.tsx
View file @
f91c7a81
import
React
,
{
useState
}
from
'react'
;
import
{
zip
,
fromPairs
}
from
'lodash'
;
import
{
storiesOf
}
from
'@storybook/react'
;
import
{
boolean
,
text
,
select
,
number
}
from
'@storybook/addon-knobs'
;
import
{
withCenteredStory
}
from
'../../utils/storybook/withCenteredStory'
;
import
{
Input
}
from
'./Input'
;
import
{
text
,
select
}
from
'@storybook/addon-knobs'
;
import
{
EventsWithValidation
}
from
'../../utils'
;
const
getKnobs
=
()
=>
{
return
{
validation
:
text
(
'Validation regex (will do a partial match if you do not anchor it)'
,
''
),
validationErrorMessage
:
text
(
'Validation error message'
,
'Input not valid'
),
validationEvent
:
select
(
'Validation event'
,
fromPairs
(
zip
(
Object
.
keys
(
EventsWithValidation
),
Object
.
values
(
EventsWithValidation
))),
EventsWithValidation
.
onBlur
),
};
import
{
Button
}
from
'../Button'
;
import
mdx
from
'./Input.mdx'
;
import
{
getAvailableIcons
,
IconType
}
from
'../Icon/types'
;
import
{
KeyValue
}
from
'@grafana/data'
;
import
{
Icon
}
from
'../Icon/Icon'
;
import
{
Field
}
from
'../Forms/Field'
;
export
default
{
title
:
'Forms/Input'
,
component
:
Input
,
decorators
:
[
withCenteredStory
],
parameters
:
{
docs
:
{
page
:
mdx
,
},
},
};
const
Wrapper
=
()
=>
{
const
{
validation
,
validationErrorMessage
,
validationEvent
}
=
getKnobs
();
const
[
value
,
setValue
]
=
useState
(
''
);
const
validations
=
{
[
validationEvent
]:
[
{
rule
:
(
value
:
string
)
=>
{
return
!!
value
.
match
(
validation
);
},
errorMessage
:
validationErrorMessage
,
},
],
export
const
simple
=
()
=>
{
const
prefixSuffixOpts
=
{
None
:
null
,
Text
:
'$'
,
...
getAvailableIcons
().
reduce
<
KeyValue
<
string
>>
((
prev
,
c
)
=>
{
return
{
...
prev
,
[
`Icon:
${
c
}
`
]:
`icon-
${
c
}
`
,
};
},
{}),
};
return
<
Input
value=
{
value
}
onChange=
{
e
=>
setValue
(
e
.
currentTarget
.
value
)
}
validationEvents=
{
validations
}
/>;
const
BEHAVIOUR_GROUP
=
'Behaviour props'
;
// ---
const
type
=
select
(
'Type'
,
{
text
:
'text'
,
password
:
'password'
,
number
:
'number'
,
},
'text'
,
BEHAVIOUR_GROUP
);
const
disabled
=
boolean
(
'Disabled'
,
false
,
BEHAVIOUR_GROUP
);
const
invalid
=
boolean
(
'Invalid'
,
false
,
BEHAVIOUR_GROUP
);
const
loading
=
boolean
(
'Loading'
,
false
,
BEHAVIOUR_GROUP
);
const
VISUAL_GROUP
=
'Visual options'
;
// ---
const
placeholder
=
text
(
'Placeholder'
,
'Enter your name here...'
,
VISUAL_GROUP
);
const
before
=
boolean
(
'Addon before'
,
false
,
VISUAL_GROUP
);
const
after
=
boolean
(
'Addon after'
,
false
,
VISUAL_GROUP
);
const
addonAfter
=
<
Button
variant=
"secondary"
>
Load
</
Button
>;
const
addonBefore
=
<
div
style=
{
{
display
:
'flex'
,
alignItems
:
'center'
,
padding
:
'5px'
}
}
>
Input
</
div
>;
const
prefix
=
select
(
'Prefix'
,
prefixSuffixOpts
,
null
,
VISUAL_GROUP
);
const
suffix
=
select
(
'Suffix'
,
prefixSuffixOpts
,
null
,
VISUAL_GROUP
);
let
prefixEl
:
any
=
prefix
;
if
(
prefix
&&
prefix
.
match
(
/icon-/g
))
{
prefixEl
=
<
Icon
name=
{
prefix
.
replace
(
/icon-/g
,
''
)
as
IconType
}
/>;
}
let
suffixEl
:
any
=
suffix
;
if
(
suffix
&&
suffix
.
match
(
/icon-/g
))
{
suffixEl
=
<
Icon
name=
{
suffix
.
replace
(
/icon-/g
,
''
)
as
IconType
}
/>;
}
const
CONTAINER_GROUP
=
'Container options'
;
// ---
const
containerWidth
=
number
(
'Container width'
,
300
,
{
range
:
true
,
min
:
100
,
max
:
500
,
step
:
10
,
},
CONTAINER_GROUP
);
return
(
<
div
style=
{
{
width
:
containerWidth
}
}
>
<
Input
disabled=
{
disabled
}
invalid=
{
invalid
}
prefix=
{
prefixEl
}
suffix=
{
suffixEl
}
loading=
{
loading
}
addonBefore=
{
before
&&
addonBefore
}
addonAfter=
{
after
&&
addonAfter
}
type=
{
type
}
placeholder=
{
placeholder
}
/>
</
div
>
);
};
const
story
=
storiesOf
(
'General/Input'
,
module
);
story
.
addDecorator
(
withCenteredStory
);
story
.
add
(
'input'
,
()
=>
<
Wrapper
/>);
export
const
withFieldValidation
=
()
=>
{
const
[
value
,
setValue
]
=
useState
(
''
);
return
(
<
div
>
<
Field
invalid=
{
value
===
''
}
error=
{
value
===
''
?
'This input is required'
:
''
}
>
<
Input
value=
{
value
}
onChange=
{
e
=>
setValue
(
e
.
currentTarget
.
value
)
}
/>
</
Field
>
</
div
>
);
};
packages/grafana-ui/src/components/Input/Input.tsx
View file @
f91c7a81
This diff is collapsed.
Click to expand it.
packages/grafana-ui/src/components/OptionsUI/number.tsx
View file @
f91c7a81
...
...
@@ -5,7 +5,7 @@ import {
toFloatOrUndefined
,
NumberFieldConfigSettings
,
}
from
'@grafana/data'
;
import
{
Input
}
from
'../
Forms/
Input/Input'
;
import
{
Input
}
from
'../Input/Input'
;
export
const
NumberValueEditor
:
React
.
FC
<
FieldConfigEditorProps
<
number
,
NumberFieldConfigSettings
>>
=
({
value
,
...
...
packages/grafana-ui/src/components/OptionsUI/string.tsx
View file @
f91c7a81
import
React
from
'react'
;
import
{
FieldConfigEditorProps
,
StringFieldConfigSettings
}
from
'@grafana/data'
;
import
{
Input
}
from
'../
Forms/
Input/Input'
;
import
{
Input
}
from
'../Input/Input'
;
export
const
StringValueEditor
:
React
.
FC
<
FieldConfigEditorProps
<
string
,
StringFieldConfigSettings
>>
=
({
value
,
...
...
packages/grafana-ui/src/components/Select/IndicatorsContainer.tsx
View file @
f91c7a81
import
React
from
'react'
;
import
{
useTheme
}
from
'../../themes/ThemeContext'
;
import
{
getInputStyles
}
from
'../
Forms/
Input/Input'
;
import
{
getInputStyles
}
from
'../Input/Input'
;
import
{
cx
,
css
}
from
'emotion'
;
export
const
IndicatorsContainer
=
React
.
forwardRef
<
HTMLDivElement
,
React
.
PropsWithChildren
<
any
>>
((
props
,
ref
)
=>
{
...
...
packages/grafana-ui/src/components/Select/InputControl.tsx
View file @
f91c7a81
import
React
from
'react'
;
import
{
useTheme
}
from
'../../themes/ThemeContext'
;
import
{
getFocusCss
,
sharedInputStyle
}
from
'../Forms/commonStyles'
;
import
{
getInputStyles
}
from
'../
Forms/
Input/Input'
;
import
{
getInputStyles
}
from
'../Input/Input'
;
import
{
cx
,
css
}
from
'emotion'
;
import
{
stylesFactory
}
from
'../../themes'
;
import
{
GrafanaTheme
}
from
'@grafana/data'
;
...
...
packages/grafana-ui/src/components/TagsInput/TagsInput.tsx
View file @
f91c7a81
...
...
@@ -2,7 +2,7 @@ import React, { ChangeEvent, KeyboardEvent, PureComponent } from 'react';
import
{
css
,
cx
}
from
'emotion'
;
import
{
stylesFactory
}
from
'../../themes/stylesFactory'
;
import
{
Button
}
from
'../Button'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Input
}
from
'../
Forms/Legacy/
Input/Input'
;
import
{
TagItem
}
from
'./TagItem'
;
interface
Props
{
...
...
packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.tsx
View file @
f91c7a81
...
...
@@ -3,7 +3,7 @@ import { Threshold, sortThresholds, ThresholdsConfig, ThresholdsMode, Selectable
import
{
colors
}
from
'../../utils'
;
import
{
getColorFromHexRgbOrName
}
from
'@grafana/data'
;
import
{
ThemeContext
}
from
'../../themes/ThemeContext'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Input
}
from
'../
Forms/Legacy/
Input/Input'
;
import
{
ColorPicker
}
from
'../ColorPicker/ColorPicker'
;
import
{
css
}
from
'emotion'
;
import
{
PanelOptionsGroup
}
from
'../PanelOptionsGroup/PanelOptionsGroup'
;
...
...
packages/grafana-ui/src/components/ThresholdsEditorNew/ThresholdsEditor.tsx
View file @
f91c7a81
...
...
@@ -10,7 +10,7 @@ import {
}
from
'@grafana/data'
;
import
{
colors
}
from
'../../utils'
;
import
{
ThemeContext
}
from
'../../themes/ThemeContext'
;
import
{
Input
}
from
'../
Forms/
Input/Input'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
ColorPicker
}
from
'../ColorPicker/ColorPicker'
;
import
{
stylesFactory
}
from
'../../themes'
;
import
{
Icon
}
from
'../Icon/Icon'
;
...
...
packages/grafana-ui/src/components/TimePicker/TimePickerContent/TimeRangeForm.tsx
View file @
f91c7a81
...
...
@@ -4,7 +4,7 @@ import { stringToDateTimeType, isValidTimeString } from '../time';
import
{
mapStringsToTimeRange
}
from
'./mapper'
;
import
{
TimePickerCalendar
}
from
'./TimePickerCalendar'
;
import
Forms
from
'../../Forms'
;
import
{
Input
}
from
'../../
Forms/
Input/Input'
;
import
{
Input
}
from
'../../Input/Input'
;
import
{
Button
}
from
'../../Button'
;
interface
Props
{
...
...
packages/grafana-ui/src/components/ValueMappingsEditor/LegacyMappingRow.tsx
View file @
f91c7a81
...
...
@@ -2,7 +2,7 @@ import React, { ChangeEvent, PureComponent } from 'react';
import
{
FormField
}
from
'../FormField/FormField'
;
import
{
FormLabel
}
from
'../FormLabel/FormLabel'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
Input
}
from
'../
Forms/Legacy/
Input/Input'
;
import
{
Select
}
from
'../Forms/Legacy/Select/Select'
;
import
{
MappingType
,
ValueMapping
}
from
'@grafana/data'
;
...
...
packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx
View file @
f91c7a81
...
...
@@ -2,7 +2,7 @@ import React, { ChangeEvent } from 'react';
import
{
HorizontalGroup
}
from
'../Layout/Layout'
;
import
{
Select
}
from
'../index'
;
import
Forms
from
'../Forms'
;
import
{
Input
}
from
'../
Forms/
Input/Input'
;
import
{
Input
}
from
'../Input/Input'
;
import
{
MappingType
,
RangeMap
,
ValueMap
,
ValueMapping
}
from
'@grafana/data'
;
import
*
as
styleMixins
from
'../../themes/mixins'
;
import
{
useTheme
}
from
'../../themes'
;
...
...
packages/grafana-ui/src/components/index.ts
View file @
f91c7a81
...
...
@@ -139,7 +139,7 @@ export { ButtonSelect } from './Select/ButtonSelect';
export
{
HorizontalGroup
,
VerticalGroup
,
Container
}
from
'./Layout/Layout'
;
export
{
RadioButtonGroup
}
from
'./Forms/RadioButtonGroup/RadioButtonGroup'
;
export
{
Input
}
from
'./
Forms/
Input/Input'
;
export
{
Input
}
from
'./Input/Input'
;
// Legacy forms
...
...
@@ -150,7 +150,7 @@ import { NoOptionsMessage } from './Forms/Legacy/Select/NoOptionsMessage';
import
{
ButtonSelect
}
from
'./Forms/Legacy/Select/ButtonSelect'
;
//Input
import
{
Input
,
LegacyInputStatus
}
from
'./Input/Input'
;
import
{
Input
,
LegacyInputStatus
}
from
'./
Forms/Legacy/
Input/Input'
;
// Export these until Enterprise migrations have been merged
// export { Input, InputStatus}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment