@dhis2-ui/file-input 10.16.1 → 10.16.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/package.json +10 -9
  2. package/src/file-input/__tests__/file-input.test.js +28 -0
  3. package/src/file-input/features/accepts_multiple_files/index.js +32 -0
  4. package/src/file-input/features/accepts_multiple_files.feature +8 -0
  5. package/src/file-input/features/can_be_blurred/index.js +23 -0
  6. package/src/file-input/features/can_be_blurred.feature +6 -0
  7. package/src/file-input/features/can_be_changed/index.js +26 -0
  8. package/src/file-input/features/can_be_changed.feature +8 -0
  9. package/src/file-input/features/can_be_focused/index.js +22 -0
  10. package/src/file-input/features/can_be_focused.feature +6 -0
  11. package/src/file-input/features/common/index.js +21 -0
  12. package/src/file-input/file-input.e2e.stories.js +46 -0
  13. package/src/file-input/file-input.js +159 -0
  14. package/src/file-input/file-input.prod.stories.js +82 -0
  15. package/src/file-input/index.js +1 -0
  16. package/src/file-input-field/__tests__/file-input-field.test.js +29 -0
  17. package/src/file-input-field/features/can_be_required/index.js +9 -0
  18. package/src/file-input-field/features/can_be_required.feature +5 -0
  19. package/src/file-input-field/features/has_default_button_label/index.js +9 -0
  20. package/src/file-input-field/features/has_default_button_label.feature +5 -0
  21. package/src/file-input-field/features/has_default_placeholder/index.js +9 -0
  22. package/src/file-input-field/features/has_default_placeholder.feature +5 -0
  23. package/src/file-input-field/file-input-field.e2e.stories.js +15 -0
  24. package/src/file-input-field/file-input-field.js +139 -0
  25. package/src/file-input-field/file-input-field.prod.stories.js +167 -0
  26. package/src/file-input-field/index.js +1 -0
  27. package/src/file-input-field-with-list/__tests__/file-input-field-with-list.test.js +30 -0
  28. package/src/file-input-field-with-list/features/common/index.js +18 -0
  29. package/src/file-input-field-with-list/features/deduplicates_the_file_list/index.js +43 -0
  30. package/src/file-input-field-with-list/features/deduplicates_the_file_list.feature +8 -0
  31. package/src/file-input-field-with-list/features/disables_button_when_full/index.js +13 -0
  32. package/src/file-input-field-with-list/features/disables_button_when_full.feature +6 -0
  33. package/src/file-input-field-with-list/features/displays_files_in_a_list/index.js +7 -0
  34. package/src/file-input-field-with-list/features/displays_files_in_a_list.feature +5 -0
  35. package/src/file-input-field-with-list/features/files_can_be_removed/index.js +24 -0
  36. package/src/file-input-field-with-list/features/files_can_be_removed.feature +7 -0
  37. package/src/file-input-field-with-list/features/has_default_button_label/index.js +9 -0
  38. package/src/file-input-field-with-list/features/has_default_button_label.feature +5 -0
  39. package/src/file-input-field-with-list/features/has_default_placeholder/index.js +9 -0
  40. package/src/file-input-field-with-list/features/has_default_placeholder.feature +5 -0
  41. package/src/file-input-field-with-list/features/has_default_remove_text/index.js +9 -0
  42. package/src/file-input-field-with-list/features/has_default_remove_text.feature +5 -0
  43. package/src/file-input-field-with-list/file-input-field-with-list.e2e.stories.js +73 -0
  44. package/src/file-input-field-with-list/file-input-field-with-list.js +188 -0
  45. package/src/file-input-field-with-list/file-input-field-with-list.prod.stories.js +67 -0
  46. package/src/file-input-field-with-list/file-list-item-with-remove.js +34 -0
  47. package/src/file-input-field-with-list/index.js +1 -0
  48. package/src/file-list/features/accepts_cancel_text/index.js +14 -0
  49. package/src/file-list/features/accepts_cancel_text.feature +5 -0
  50. package/src/file-list/features/accepts_label/index.js +11 -0
  51. package/src/file-list/features/accepts_label.feature +5 -0
  52. package/src/file-list/features/accepts_remove_text/index.js +11 -0
  53. package/src/file-list/features/accepts_remove_text.feature +5 -0
  54. package/src/file-list/features/can_be_removed/index.js +15 -0
  55. package/src/file-list/features/can_be_removed.feature +6 -0
  56. package/src/file-list/features/file-list-item-accepts_children/index.js +10 -0
  57. package/src/file-list/features/file-list-item-accepts_children.feature +5 -0
  58. package/src/file-list/features/file-list-placeholder-accepts_children/index.js +12 -0
  59. package/src/file-list/features/file-list-placeholder-accepts_children.feature +5 -0
  60. package/src/file-list/features/loading_can_be_cancelled/index.js +15 -0
  61. package/src/file-list/features/loading_can_be_cancelled.feature +6 -0
  62. package/src/file-list/file-list-item.e2e.stories.js +39 -0
  63. package/src/file-list/file-list-item.js +131 -0
  64. package/src/file-list/file-list-placeholder.e2e.stories.js +7 -0
  65. package/src/file-list/file-list-placeholder.js +27 -0
  66. package/src/file-list/file-list.e2e.stories.js +5 -0
  67. package/src/file-list/file-list.js +28 -0
  68. package/src/file-list/index.js +3 -0
  69. package/src/index.js +9 -0
  70. package/src/locales/ar/translations.json +5 -0
  71. package/src/locales/ar_IQ/translations.json +5 -0
  72. package/src/locales/ckb/translations.json +5 -0
  73. package/src/locales/cs/translations.json +5 -0
  74. package/src/locales/da/translations.json +5 -0
  75. package/src/locales/en/translations.json +5 -0
  76. package/src/locales/es/translations.json +5 -0
  77. package/src/locales/es_419/translations.json +5 -0
  78. package/src/locales/fr/translations.json +5 -0
  79. package/src/locales/hi_IN/translations.json +5 -0
  80. package/src/locales/id/translations.json +5 -0
  81. package/src/locales/index.js +82 -0
  82. package/src/locales/km/translations.json +5 -0
  83. package/src/locales/ko_KR/translations.json +5 -0
  84. package/src/locales/lo/translations.json +5 -0
  85. package/src/locales/my/translations.json +5 -0
  86. package/src/locales/nb/translations.json +5 -0
  87. package/src/locales/nl/translations.json +5 -0
  88. package/src/locales/prs/translations.json +5 -0
  89. package/src/locales/ps/translations.json +5 -0
  90. package/src/locales/pt/translations.json +5 -0
  91. package/src/locales/pt_BR/translations.json +5 -0
  92. package/src/locales/ru/translations.json +5 -0
  93. package/src/locales/si/translations.json +5 -0
  94. package/src/locales/sv/translations.json +5 -0
  95. package/src/locales/tet/translations.json +5 -0
  96. package/src/locales/tg/translations.json +5 -0
  97. package/src/locales/uk/translations.json +5 -0
  98. package/src/locales/ur/translations.json +5 -0
  99. package/src/locales/uz_Latn/translations.json +5 -0
  100. package/src/locales/uz_UZ_Cyrl/translations.json +5 -0
  101. package/src/locales/uz_UZ_Latn/translations.json +5 -0
  102. package/src/locales/vi/translations.json +5 -0
  103. package/src/locales/zh/translations.json +5 -0
  104. package/src/locales/zh_CN/translations.json +5 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhis2-ui/file-input",
3
- "version": "10.16.1",
3
+ "version": "10.16.3-alpha.1",
4
4
  "description": "UI FileInput",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,19 +34,20 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@dhis2/prop-types": "^3.1.2",
37
- "@dhis2-ui/button": "10.16.1",
38
- "@dhis2-ui/field": "10.16.1",
39
- "@dhis2-ui/label": "10.16.1",
40
- "@dhis2-ui/loader": "10.16.1",
41
- "@dhis2-ui/status-icon": "10.16.1",
42
- "@dhis2/ui-constants": "10.16.1",
43
- "@dhis2/ui-icons": "10.16.1",
37
+ "@dhis2-ui/button": "10.16.3-alpha.1",
38
+ "@dhis2-ui/field": "10.16.3-alpha.1",
39
+ "@dhis2-ui/label": "10.16.3-alpha.1",
40
+ "@dhis2-ui/loader": "10.16.3-alpha.1",
41
+ "@dhis2-ui/status-icon": "10.16.3-alpha.1",
42
+ "@dhis2/ui-constants": "10.16.3-alpha.1",
43
+ "@dhis2/ui-icons": "10.16.3-alpha.1",
44
44
  "classnames": "^2.3.1",
45
45
  "prop-types": "^15.7.2"
46
46
  },
47
47
  "files": [
48
48
  "build",
49
- "types"
49
+ "types",
50
+ "src"
50
51
  ],
51
52
  "devDependencies": {
52
53
  "@dhis2/d2-i18n": "^1.1.0",
@@ -0,0 +1,28 @@
1
+ import { render, fireEvent, screen } from '@testing-library/react'
2
+ import React from 'react'
3
+ import { FileInput } from '../file-input.js'
4
+
5
+ describe('<FileInput />', () => {
6
+ it('should call the onKeyDown callback when provided', () => {
7
+ const onKeyDown = jest.fn()
8
+
9
+ render(
10
+ <FileInput
11
+ name="foo"
12
+ value="bar"
13
+ checked={false}
14
+ onKeyDown={onKeyDown}
15
+ />
16
+ )
17
+
18
+ fireEvent.keyDown(screen.getByRole('button'), {})
19
+
20
+ expect(onKeyDown).toHaveBeenCalledTimes(1)
21
+
22
+ const input = screen.getByTestId('dhis2-uicore-fileinput-input')
23
+ expect(onKeyDown).toHaveBeenCalledWith(
24
+ { name: 'foo', files: input.files },
25
+ expect.objectContaining({})
26
+ )
27
+ })
28
+ })
@@ -0,0 +1,32 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a FileInput with multiple and onChange handler is rendered', () => {
4
+ cy.visitStory('FileInput', 'With on change and multiple')
5
+ })
6
+
7
+ When('the user selected multiple files', () => {
8
+ cy.get('[data-test="dhis2-uicore-fileinput"] input').uploadMultipleFiles(
9
+ [
10
+ { fileType: 'md', fixture: 'FileInput/file.md' },
11
+ { fileType: 'txt', fixture: 'FileInput/file.txt' },
12
+ ],
13
+ true
14
+ )
15
+ })
16
+
17
+ Then("the onChange handler's payload contains multiple files", () => {
18
+ cy.window().should((win) => {
19
+ const calls = win.onChange.getCalls()
20
+ const callArgs = calls[0].args
21
+ const payload = callArgs[0]
22
+ const files = payload.files
23
+
24
+ expect(files).to.have.lengthOf(2)
25
+
26
+ const file1 = files[0]
27
+ expect(file1.name).to.equal('file.md')
28
+
29
+ const file2 = files[1]
30
+ expect(file2.name).to.equal('file.txt')
31
+ })
32
+ })
@@ -0,0 +1,8 @@
1
+ Feature: The FileInput can handle multiple files
2
+
3
+ Scenario: The user selects multiple files
4
+ Given a FileInput with multiple and onChange handler is rendered
5
+ And the FileInput does not have any files
6
+ When the user selected multiple files
7
+ Then the onChange handler is called
8
+ Then the onChange handler's payload contains multiple files
@@ -0,0 +1,23 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('an FileInput with initialFocus and onBlur handler is rendered', () => {
4
+ cy.visitStory('FileInput', 'With initial focus and on blur')
5
+ })
6
+
7
+ When('the FileInput is blurred', () => {
8
+ cy.focused()
9
+ cy.get('[data-test="dhis2-uicore-fileinput"] button').blur()
10
+ })
11
+
12
+ Then('the onBlur handler is called', () => {
13
+ cy.window().then((win) => {
14
+ cy.get('[data-test="dhis2-uicore-fileinput"] input').should(
15
+ (fileInput) => {
16
+ expect(win.onBlur).to.be.calledWith({
17
+ name: 'upload',
18
+ files: fileInput[0].files,
19
+ })
20
+ }
21
+ )
22
+ })
23
+ })
@@ -0,0 +1,6 @@
1
+ Feature: The FileInput has an onBlur api
2
+
3
+ Scenario: The user blurs the FileInput
4
+ Given an FileInput with initialFocus and onBlur handler is rendered
5
+ When the FileInput is blurred
6
+ Then the onBlur handler is called
@@ -0,0 +1,26 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a FileInput with onChange handler is rendered', () => {
4
+ cy.visitStory('FileInput', 'With on change')
5
+ })
6
+
7
+ When('a file is selected', () => {
8
+ cy.get('[data-test="dhis2-uicore-fileinput"] input').uploadSingleFile(
9
+ '.md',
10
+ 'FileInput/file.md'
11
+ )
12
+ })
13
+
14
+ Then("the onChange handler's payload contains the file", () => {
15
+ cy.window().should((win) => {
16
+ const calls = win.onChange.getCalls()
17
+ const callArgs = calls[0].args
18
+ const payload = callArgs[0]
19
+ const files = payload.files
20
+
21
+ expect(files).to.have.lengthOf(1)
22
+
23
+ const file1 = files[0]
24
+ expect(file1.name).to.equal('file.md')
25
+ })
26
+ })
@@ -0,0 +1,8 @@
1
+ Feature: The FIleInput has an onChange api
2
+
3
+ Scenario: The user selects a file
4
+ Given a FileInput with onChange handler is rendered
5
+ And the FileInput does not have any files
6
+ When a file is selected
7
+ Then the onChange handler is called
8
+ Then the onChange handler's payload contains the file
@@ -0,0 +1,22 @@
1
+ import { Given, When, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a FileInput with onFocus handler is rendered', () => {
4
+ cy.visitStory('FileInput', 'With on focus')
5
+ })
6
+
7
+ When('the FileInput is focused', () => {
8
+ cy.get('[data-test="dhis2-uicore-fileinput"] button').focus()
9
+ })
10
+
11
+ Then('the onFocus handler is called', () => {
12
+ cy.window().then((win) => {
13
+ cy.get('[data-test="dhis2-uicore-fileinput"] input').should(
14
+ (fileInput) => {
15
+ expect(win.onFocus).to.be.calledWith({
16
+ name: 'upload',
17
+ files: fileInput[0].files,
18
+ })
19
+ }
20
+ )
21
+ })
22
+ })
@@ -0,0 +1,6 @@
1
+ Feature: The FileInput has an onFocus api
2
+
3
+ Scenario: The user focuses the FileInput
4
+ Given a FileInput with onFocus handler is rendered
5
+ When the FileInput is focused
6
+ Then the onFocus handler is called
@@ -0,0 +1,21 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('the FileInput does not have any files', () => {
4
+ cy.get('[data-test="dhis2-uicore-fileinput"] input').then(($input) => {
5
+ const files = $input[0].files
6
+ expect(files).to.have.lengthOf(0)
7
+ })
8
+ })
9
+
10
+ Then('the onChange handler is called', () => {
11
+ cy.window().should((win) => {
12
+ const calls = win.onChange.getCalls()
13
+ expect(calls).to.have.lengthOf(1)
14
+
15
+ const callArgs = calls[0].args
16
+ expect(callArgs).to.have.lengthOf(2)
17
+
18
+ const payload = callArgs[0]
19
+ expect(Object.keys(payload)).to.include.members(['files', 'name'])
20
+ })
21
+ })
@@ -0,0 +1,46 @@
1
+ import React from 'react'
2
+ import { FileInput } from './index.js'
3
+
4
+ window.onBlur = window.Cypress && window.Cypress.cy.stub()
5
+ window.onFocus = window.Cypress && window.Cypress.cy.stub()
6
+ window.onChange = window.Cypress && window.Cypress.cy.stub()
7
+
8
+ const onChange = (payload, event) => {
9
+ // NOTE: if files is not transformed into an array,
10
+ // cypress will get an empty file list!
11
+ window.onChange(
12
+ {
13
+ ...payload,
14
+ files: [...payload.files],
15
+ },
16
+ event
17
+ )
18
+ }
19
+
20
+ export default { title: 'FileInput' }
21
+ export const WithOnChange = () => (
22
+ <FileInput onChange={onChange} buttonLabel="Upload file" name="upload" />
23
+ )
24
+ export const WithOnChangeAndMultiple = () => (
25
+ <FileInput
26
+ name="upload"
27
+ onChange={onChange}
28
+ buttonLabel="Upload files"
29
+ multiple
30
+ />
31
+ )
32
+ export const WithInitialFocusAndOnBlur = () => (
33
+ <FileInput
34
+ buttonLabel="Upload file"
35
+ name="upload"
36
+ initialFocus
37
+ onBlur={window.onBlur}
38
+ />
39
+ )
40
+ export const WithOnFocus = () => (
41
+ <FileInput
42
+ buttonLabel="Upload file"
43
+ name="upload"
44
+ onFocus={window.onFocus}
45
+ />
46
+ )
@@ -0,0 +1,159 @@
1
+ import { colors, spacers, sharedPropTypes } from '@dhis2/ui-constants'
2
+ import { IconUpload24 } from '@dhis2/ui-icons'
3
+ import { Button } from '@dhis2-ui/button'
4
+ import { StatusIcon } from '@dhis2-ui/status-icon'
5
+ import cx from 'classnames'
6
+ import PropTypes from 'prop-types'
7
+ import React, { createRef, Component } from 'react'
8
+
9
+ class FileInput extends Component {
10
+ static defaultProps = {
11
+ accept: '*',
12
+ dataTest: 'dhis2-uicore-fileinput',
13
+ }
14
+
15
+ ref = createRef()
16
+
17
+ handleClick = () => {
18
+ this.ref.current.click()
19
+ }
20
+
21
+ handleChange = (e) => {
22
+ if (this.props.onChange) {
23
+ this.props.onChange(this.createHandlerPayload(), e)
24
+ }
25
+
26
+ // reset the file input so it won't prevent on-change
27
+ // if the same file was added in a second attempt
28
+ this.ref.current.value = ''
29
+ }
30
+
31
+ handleBlur = (e) => {
32
+ if (this.props.onBlur) {
33
+ this.props.onBlur(this.createHandlerPayload(), e)
34
+ }
35
+ }
36
+
37
+ handleFocus = (e) => {
38
+ if (this.props.onFocus) {
39
+ this.props.onFocus(this.createHandlerPayload(), e)
40
+ }
41
+ }
42
+
43
+ handleKeyDown = (e) => {
44
+ if (this.props.onKeyDown) {
45
+ this.props.onKeyDown(this.createHandlerPayload(), e)
46
+ }
47
+ }
48
+
49
+ createHandlerPayload() {
50
+ return {
51
+ files: this.ref.current.files,
52
+ name: this.props.name,
53
+ }
54
+ }
55
+
56
+ render() {
57
+ const {
58
+ accept = '*',
59
+ buttonLabel,
60
+ className,
61
+ dataTest = 'dhis2-uicore-fileinput',
62
+ disabled,
63
+ error,
64
+ initialFocus,
65
+ large,
66
+ multiple,
67
+ name,
68
+ small,
69
+ tabIndex,
70
+ valid,
71
+ warning,
72
+ } = this.props
73
+
74
+ return (
75
+ <div className={cx('file-input', className)} data-test={dataTest}>
76
+ <div>
77
+ <input
78
+ id={name}
79
+ name={name}
80
+ type="file"
81
+ ref={this.ref}
82
+ onChange={this.handleChange}
83
+ accept={accept}
84
+ multiple={multiple}
85
+ disabled={disabled}
86
+ data-test={`${dataTest}-input`}
87
+ />
88
+ <Button
89
+ disabled={disabled}
90
+ icon={<IconUpload24 color={colors.grey700} />}
91
+ initialFocus={initialFocus}
92
+ large={large}
93
+ onBlur={this.handleBlur}
94
+ onClick={this.handleClick}
95
+ onFocus={this.handleFocus}
96
+ onKeyDown={this.handleKeyDown}
97
+ small={small}
98
+ tabIndex={tabIndex}
99
+ type="button"
100
+ >
101
+ {buttonLabel}
102
+ </Button>
103
+ </div>
104
+ <StatusIcon error={error} valid={valid} warning={warning} />
105
+
106
+ <style jsx>{`
107
+ input {
108
+ display: none;
109
+ }
110
+
111
+ .file-input {
112
+ display: flex;
113
+ align-items: center;
114
+ gap: ${spacers.dp8};
115
+ padding-bottom: ${spacers.dp4};
116
+ }
117
+ `}</style>
118
+ </div>
119
+ )
120
+ }
121
+ }
122
+
123
+ FileInput.propTypes = {
124
+ /**
125
+ * The `accept` attribute of the [native file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept)
126
+ */
127
+ accept: PropTypes.string,
128
+ buttonLabel: PropTypes.string,
129
+ className: PropTypes.string,
130
+ dataTest: PropTypes.string,
131
+ disabled: PropTypes.bool,
132
+ /** Input status. Mutually exclusive with `warning` and `valid` */
133
+ error: sharedPropTypes.statusPropType,
134
+ initialFocus: PropTypes.bool,
135
+ /** Button size. Mutually exclusive with `small` */
136
+ large: sharedPropTypes.sizePropType,
137
+ /**
138
+ * The `multiple` attribute of the [native file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#multiple)
139
+ */
140
+ multiple: PropTypes.bool,
141
+ name: PropTypes.string,
142
+ /** Button size. Mutually exclusive with `large` */
143
+ small: sharedPropTypes.sizePropType,
144
+ tabIndex: PropTypes.string,
145
+ /** Input status. Mutually exclusive with `warning` and `error` */
146
+ valid: sharedPropTypes.statusPropType,
147
+ /** Input status. Mutually exclusive with `valid` and `error` */
148
+ warning: sharedPropTypes.statusPropType,
149
+ /** Called with signature `(object, event)` */
150
+ onBlur: PropTypes.func,
151
+ /** Called with signature `(object, event)` */
152
+ onChange: PropTypes.func,
153
+ /** Called with signature `(object, event)` */
154
+ onFocus: PropTypes.func,
155
+ /** Called with signature `(object, event)` */
156
+ onKeyDown: PropTypes.func,
157
+ }
158
+
159
+ export { FileInput }
@@ -0,0 +1,82 @@
1
+ import { sharedPropTypes } from '@dhis2/ui-constants'
2
+ import React from 'react'
3
+ import { FileInput } from './index.js'
4
+
5
+ const subtitle = `The file input component allows users to select and upload files from their local machine.`
6
+
7
+ const description = `
8
+ Use a file input component in forms and interfaces wherever a user needs to be able to select and upload a file from their local machine.
9
+
10
+ \`\`\`js
11
+ import { FileInput } from '@dhis2/ui'
12
+ \`\`\`
13
+ `
14
+
15
+ const onChange = (payload, event) => {
16
+ console.log('onChange payload', payload)
17
+ console.log('onChange event', event)
18
+
19
+ // NOTE: if files is not transformed into an array,
20
+ // cypress will get an empty file list!
21
+ window.onChange &&
22
+ window.onChange(
23
+ {
24
+ ...payload,
25
+ files: [...payload.files],
26
+ },
27
+ event
28
+ )
29
+ }
30
+
31
+ const { sizeArgType, statusArgType } = sharedPropTypes
32
+
33
+ export default {
34
+ title: 'File Input',
35
+ component: FileInput,
36
+ // Default args for each story unless overridden
37
+ args: { buttonLabel: 'Upload file', name: 'upload', onChange },
38
+ argTypes: {
39
+ valid: { ...statusArgType },
40
+ warning: { ...statusArgType },
41
+ error: { ...statusArgType },
42
+ small: { ...sizeArgType },
43
+ large: { ...sizeArgType },
44
+ },
45
+ parameters: {
46
+ componentSubtitle: subtitle,
47
+ docs: { description: { component: description } },
48
+ },
49
+ }
50
+
51
+ const Template = (args) => <FileInput {...args} />
52
+
53
+ export const Default = Template.bind({})
54
+
55
+ export const Multiple = Template.bind({})
56
+ Multiple.args = { multiple: true, buttonLabel: 'Upload files' }
57
+
58
+ export const Disabled = Template.bind({})
59
+ Disabled.args = { disabled: true }
60
+
61
+ export const Sizes = (args) => (
62
+ <>
63
+ <FileInput {...args} buttonLabel="Default size" name="default" />
64
+ <FileInput {...args} small buttonLabel="Small" name="small" />
65
+ <FileInput {...args} large buttonLabel="Large" name="large" />
66
+ </>
67
+ )
68
+
69
+ export const Statuses = (args) => (
70
+ <>
71
+ <FileInput {...args} buttonLabel="Default" name="default" />
72
+ <FileInput {...args} buttonLabel="Valid" name="valid" valid />
73
+ <FileInput {...args} buttonLabel="Warning" name="warning" warning />
74
+ <FileInput {...args} buttonLabel="Error" name="error" error />
75
+ </>
76
+ )
77
+
78
+ export const RTL = (args) => (
79
+ <div dir="rtl">
80
+ <FileInput {...args} buttonLabel="Default" name="default" />
81
+ </div>
82
+ )
@@ -0,0 +1 @@
1
+ export { FileInput } from './file-input.js'
@@ -0,0 +1,29 @@
1
+ import { render, fireEvent, screen } from '@testing-library/react'
2
+ import React from 'react'
3
+ import { FileInputField } from '../file-input-field.js'
4
+
5
+ describe('<FileInputField />', () => {
6
+ it('should call the onKeyDown callback when provided', () => {
7
+ const onKeyDown = jest.fn()
8
+
9
+ render(
10
+ <FileInputField
11
+ label="Label"
12
+ name="foo"
13
+ value="bar"
14
+ checked={false}
15
+ onKeyDown={onKeyDown}
16
+ />
17
+ )
18
+
19
+ fireEvent.keyDown(screen.getByRole('button'), {})
20
+
21
+ expect(onKeyDown).toHaveBeenCalledTimes(1)
22
+
23
+ const input = screen.getByTestId('dhis2-uicore-fileinput-input')
24
+ expect(onKeyDown).toHaveBeenCalledWith(
25
+ { name: 'foo', files: input.files },
26
+ expect.objectContaining({})
27
+ )
28
+ })
29
+ })
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a FileInputField with label and a required flag is rendered', () => {
4
+ cy.visitStory('FileInputField', 'With label and required')
5
+ })
6
+
7
+ Then('the required indicator is visible', () => {
8
+ cy.get('[data-test="dhis2-uicore-label-required"]').should('be.visible')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Required status for the FileInputField
2
+
3
+ Scenario: Rendering a FileInputField that is required
4
+ Given a FileInputField with label and a required flag is rendered
5
+ Then the required indicator is visible
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a default FileInputField is rendered', () => {
4
+ cy.visitStory('FileInputField', 'Default')
5
+ })
6
+
7
+ Then('the default button label is visible', () => {
8
+ cy.contains('Upload a file').should('be.visible')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Button label for the FileInputField
2
+
3
+ Scenario: Rendering a FileInputField
4
+ Given a default FileInputField is rendered
5
+ Then the default button label is visible
@@ -0,0 +1,9 @@
1
+ import { Given, Then } from '@badeball/cypress-cucumber-preprocessor'
2
+
3
+ Given('a default FileInputField is rendered', () => {
4
+ cy.visitStory('FileInputField', 'Default')
5
+ })
6
+
7
+ Then('the default placeholder is visible', () => {
8
+ cy.contains('No file uploaded yet').should('be.visible')
9
+ })
@@ -0,0 +1,5 @@
1
+ Feature: Placeholder for the FileInputField
2
+
3
+ Scenario: Rendering a FileInputField
4
+ Given a default FileInputField is rendered
5
+ Then the default placeholder is visible
@@ -0,0 +1,15 @@
1
+ import React from 'react'
2
+ import { FileInputField } from './file-input-field.js'
3
+
4
+ export default { title: 'FileInputField' }
5
+ export const WithLabelAndRequired = () => (
6
+ <FileInputField
7
+ name="upload"
8
+ label="upload something"
9
+ buttonLabel="Upload file"
10
+ required
11
+ />
12
+ )
13
+ export const Default = () => (
14
+ <FileInputField name="upload" label="upload something" />
15
+ )