@dhis2-ui/select 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.
- package/build/cjs/select/select.js +5 -2
- package/build/cjs/simple-single-select/use-handle-key-press/use-handle-key-press-on-filter-input.js +2 -2
- package/build/es/select/select.js +5 -2
- package/build/es/simple-single-select/use-handle-key-press/use-handle-key-press-on-filter-input.js +2 -2
- package/package.json +17 -16
- package/src/index.js +9 -0
- package/src/locales/ar/translations.json +7 -0
- package/src/locales/ar_IQ/translations.json +7 -0
- package/src/locales/ckb/translations.json +7 -0
- package/src/locales/cs/translations.json +7 -0
- package/src/locales/da/translations.json +7 -0
- package/src/locales/en/translations.json +11 -0
- package/src/locales/en_US/translations.json +9 -0
- package/src/locales/es/translations.json +7 -0
- package/src/locales/es_419/translations.json +7 -0
- package/src/locales/fr/translations.json +7 -0
- package/src/locales/hi_IN/translations.json +7 -0
- package/src/locales/id/translations.json +7 -0
- package/src/locales/index.js +80 -0
- package/src/locales/km/translations.json +7 -0
- package/src/locales/lo/translations.json +7 -0
- package/src/locales/my/translations.json +7 -0
- package/src/locales/nb/translations.json +7 -0
- package/src/locales/nl/translations.json +7 -0
- package/src/locales/prs/translations.json +7 -0
- package/src/locales/ps/translations.json +7 -0
- package/src/locales/pt/translations.json +7 -0
- package/src/locales/pt_BR/translations.json +7 -0
- package/src/locales/ru/translations.json +7 -0
- package/src/locales/sv/translations.json +7 -0
- package/src/locales/tet/translations.json +7 -0
- package/src/locales/tg/translations.json +7 -0
- package/src/locales/uk/translations.json +7 -0
- package/src/locales/ur/translations.json +7 -0
- package/src/locales/uz_Latn/translations.json +7 -0
- package/src/locales/uz_UZ_Cyrl/translations.json +7 -0
- package/src/locales/uz_UZ_Latn/translations.json +7 -0
- package/src/locales/vi/translations.json +7 -0
- package/src/locales/zh/translations.json +9 -0
- package/src/locales/zh_CN/translations.json +7 -0
- package/src/multi-select/__tests__/multi-select.test.js +23 -0
- package/src/multi-select/__tests__/selection-list.test.js +102 -0
- package/src/multi-select/features/accepts_blur_cb/index.js +14 -0
- package/src/multi-select/features/accepts_blur_cb.feature +8 -0
- package/src/multi-select/features/accepts_focus_cb/index.js +14 -0
- package/src/multi-select/features/accepts_focus_cb.feature +6 -0
- package/src/multi-select/features/accepts_initial_focus/index.js +5 -0
- package/src/multi-select/features/accepts_initial_focus.feature +5 -0
- package/src/multi-select/features/accepts_loading/index.js +22 -0
- package/src/multi-select/features/accepts_loading.feature +14 -0
- package/src/multi-select/features/accepts_max_height/index.js +31 -0
- package/src/multi-select/features/accepts_max_height.feature +11 -0
- package/src/multi-select/features/accepts_placeholder/index.js +25 -0
- package/src/multi-select/features/accepts_placeholder.feature +10 -0
- package/src/multi-select/features/accepts_prefix/index.js +19 -0
- package/src/multi-select/features/accepts_prefix.feature +10 -0
- package/src/multi-select/features/allows_invalid_options/index.js +27 -0
- package/src/multi-select/features/allows_invalid_options.feature +12 -0
- package/src/multi-select/features/allows_selecting/index.js +81 -0
- package/src/multi-select/features/allows_selecting.feature +44 -0
- package/src/multi-select/features/can_be_cleared/index.js +22 -0
- package/src/multi-select/features/can_be_cleared.feature +6 -0
- package/src/multi-select/features/can_be_disabled/index.js +36 -0
- package/src/multi-select/features/can_be_disabled.feature +32 -0
- package/src/multi-select/features/can_be_empty/index.js +28 -0
- package/src/multi-select/features/can_be_empty.feature +16 -0
- package/src/multi-select/features/can_be_filtered/index.js +23 -0
- package/src/multi-select/features/can_be_filtered.feature +14 -0
- package/src/multi-select/features/can_be_opened_and_closed/index.js +32 -0
- package/src/multi-select/features/can_be_opened_and_closed.feature +41 -0
- package/src/multi-select/features/common/index.js +49 -0
- package/src/multi-select/features/duplicate_option_values/index.js +21 -0
- package/src/multi-select/features/duplicate_option_values.feature +7 -0
- package/src/multi-select/features/menu_width_matches_input/index.js +53 -0
- package/src/multi-select/features/menu_width_matches_input.feature +11 -0
- package/src/multi-select/features/position/index.js +160 -0
- package/src/multi-select/features/position.feature +46 -0
- package/src/multi-select/features/shows_selections/index.js +18 -0
- package/src/multi-select/features/shows_selections.feature +9 -0
- package/src/multi-select/filterable-menu.js +43 -0
- package/src/multi-select/index.js +1 -0
- package/src/multi-select/input.js +129 -0
- package/src/multi-select/menu.js +91 -0
- package/src/multi-select/multi-select.e2e.stories.js +407 -0
- package/src/multi-select/multi-select.js +148 -0
- package/src/multi-select/multi-select.prod.stories.js +408 -0
- package/src/multi-select/selection-list.js +79 -0
- package/src/multi-select-field/__tests__/multi-select-field.test.js +29 -0
- package/src/multi-select-field/features/accepts_help_text/index.js +9 -0
- package/src/multi-select-field/features/accepts_help_text.feature +5 -0
- package/src/multi-select-field/features/accepts_label/index.js +9 -0
- package/src/multi-select-field/features/accepts_label.feature +5 -0
- package/src/multi-select-field/features/accepts_validation_text/index.js +9 -0
- package/src/multi-select-field/features/accepts_validation_text.feature +5 -0
- package/src/multi-select-field/features/can_be_required/index.js +11 -0
- package/src/multi-select-field/features/can_be_required.feature +5 -0
- package/src/multi-select-field/features/has_default_clear_text/index.js +16 -0
- package/src/multi-select-field/features/has_default_clear_text.feature +6 -0
- package/src/multi-select-field/features/has_default_empty_text/index.js +13 -0
- package/src/multi-select-field/features/has_default_empty_text.feature +6 -0
- package/src/multi-select-field/features/has_default_filter_nomatch_text/index.js +17 -0
- package/src/multi-select-field/features/has_default_filter_nomatch_text.feature +7 -0
- package/src/multi-select-field/features/has_default_filter_placeholder/index.js +15 -0
- package/src/multi-select-field/features/has_default_filter_placeholder.feature +6 -0
- package/src/multi-select-field/features/has_default_loading_text/index.js +13 -0
- package/src/multi-select-field/features/has_default_loading_text.feature +6 -0
- package/src/multi-select-field/index.js +1 -0
- package/src/multi-select-field/multi-select-field.e2e.stories.js +45 -0
- package/src/multi-select-field/multi-select-field.js +178 -0
- package/src/multi-select-field/multi-select-field.prod.stories.js +137 -0
- package/src/multi-select-option/index.js +1 -0
- package/src/multi-select-option/multi-select-option.js +70 -0
- package/src/select/__tests__/select.test.js +31 -0
- package/src/select/debounce/debounce.js +30 -0
- package/src/select/debounce/debounce.spec.js +35 -0
- package/src/select/empty.js +28 -0
- package/src/select/filter-input.js +42 -0
- package/src/select/filterable-menu.js +106 -0
- package/src/select/index.js +14 -0
- package/src/select/input-clear-button.js +66 -0
- package/src/select/input-placeholder.js +30 -0
- package/src/select/input-prefix.js +32 -0
- package/src/select/input-wrapper.js +114 -0
- package/src/select/loading.js +33 -0
- package/src/select/menu-wrapper.js +52 -0
- package/src/select/no-match.js +28 -0
- package/src/select/option-helpers.js +34 -0
- package/src/select/select.js +256 -0
- package/src/simple-single-select/__stories__/DefaultPosition.js +37 -0
- package/src/simple-single-select/__stories__/Dense.js +17 -0
- package/src/simple-single-select/__stories__/Empty.js +15 -0
- package/src/simple-single-select/__stories__/EmptyWithEmptyNode.js +27 -0
- package/src/simple-single-select/__stories__/EmptyWithEmptyText.js +16 -0
- package/src/simple-single-select/__stories__/FlippedPosition.js +36 -0
- package/src/simple-single-select/__stories__/InfiniteLoading.js +65 -0
- package/src/simple-single-select/__stories__/Loading.js +15 -0
- package/src/simple-single-select/__stories__/ShiftedIntoView.js +35 -0
- package/src/simple-single-select/__stories__/WithClearButton.js +26 -0
- package/src/simple-single-select/__stories__/WithCustomLowMaxHeight.js +17 -0
- package/src/simple-single-select/__stories__/WithCustomOptions.js +78 -0
- package/src/simple-single-select/__stories__/WithDisabledOption.js +25 -0
- package/src/simple-single-select/__stories__/WithFilterField.js +30 -0
- package/src/simple-single-select/__stories__/WithInitialFocus.js +29 -0
- package/src/simple-single-select/__stories__/WithManyOptions.js +19 -0
- package/src/simple-single-select/__stories__/WithMultipleSelectsAndScrollableParent.js +65 -0
- package/src/simple-single-select/__stories__/WithNoMatchText.js +25 -0
- package/src/simple-single-select/__stories__/WithOnBlur.js +22 -0
- package/src/simple-single-select/__stories__/WithOnFocus.js +22 -0
- package/src/simple-single-select/__stories__/WithOptionsAndDisabled.js +17 -0
- package/src/simple-single-select/__stories__/WithOptionsAndLoading.js +23 -0
- package/src/simple-single-select/__stories__/WithOptionsAndLoadingText.js +24 -0
- package/src/simple-single-select/__stories__/WithPlaceholder.js +18 -0
- package/src/simple-single-select/__stories__/WithPlaceholderAndSelection.js +20 -0
- package/src/simple-single-select/__stories__/WithPrefix.js +17 -0
- package/src/simple-single-select/__stories__/WithPrefixAndSelection.js +20 -0
- package/src/simple-single-select/__stories__/WithRTL.js +29 -0
- package/src/simple-single-select/__stories__/WithScrollingParent.js +51 -0
- package/src/simple-single-select/__stories__/WithSelection.js +19 -0
- package/src/simple-single-select/__stories__/WithSelectionAndDisabled.js +20 -0
- package/src/simple-single-select/__stories__/WithServerSideFilteringDemo.js +245 -0
- package/src/simple-single-select/__stories__/WithSimpleFilteringDemo.js +50 -0
- package/src/simple-single-select/__stories__/WithoutOptionsAndLoading.js +16 -0
- package/src/simple-single-select/__stories__/WithoutSelection.js +17 -0
- package/src/simple-single-select/__stories__/options.js +96 -0
- package/src/simple-single-select/__stories__/simple-single-select-server-side-filtering/CustomDataProvider.js +70 -0
- package/src/simple-single-select/__stories__/simple-single-select-server-side-filtering/dataElements.js +4271 -0
- package/src/simple-single-select/__stories__/simple-single-select-server-side-filtering/index.js +1 -0
- package/src/simple-single-select/features/keyboard-interactions.test.e2e.js +581 -0
- package/src/simple-single-select/features/menu-positioning.test.e2e.js +187 -0
- package/src/simple-single-select/index.js +2 -0
- package/src/simple-single-select/is-option-hidden.js +21 -0
- package/src/simple-single-select/menu/empty.js +27 -0
- package/src/simple-single-select/menu/filter.js +61 -0
- package/src/simple-single-select/menu/index.js +1 -0
- package/src/simple-single-select/menu/loading.js +38 -0
- package/src/simple-single-select/menu/menu.js +171 -0
- package/src/simple-single-select/menu/no-match.js +28 -0
- package/src/simple-single-select/menu/option.js +161 -0
- package/src/simple-single-select/menu/options-list.js +107 -0
- package/src/simple-single-select/selected-value/clear-button.js +71 -0
- package/src/simple-single-select/selected-value/container.js +146 -0
- package/src/simple-single-select/selected-value/index.js +1 -0
- package/src/simple-single-select/selected-value/placeholder.js +24 -0
- package/src/simple-single-select/selected-value/prefix.js +26 -0
- package/src/simple-single-select/selected-value/selected-value.js +174 -0
- package/src/simple-single-select/shared-prop-types.js +8 -0
- package/src/simple-single-select/simple-single-select.e2e.stories.js +216 -0
- package/src/simple-single-select/simple-single-select.js +389 -0
- package/src/simple-single-select/simple-single-select.prod.stories.js +41 -0
- package/src/simple-single-select/simple-single-select.test.js +1136 -0
- package/src/simple-single-select/use-handle-key-press/index.js +2 -0
- package/src/simple-single-select/use-handle-key-press/use-focus-option.js +24 -0
- package/src/simple-single-select/use-handle-key-press/use-handle-key-press-on-combobox.js +259 -0
- package/src/simple-single-select/use-handle-key-press/use-handle-key-press-on-filter-input.js +147 -0
- package/src/simple-single-select/use-handle-key-press/use-handle-typing.js +79 -0
- package/src/simple-single-select/use-handle-key-press/use-highlight-first-option-on-previous-page.js +62 -0
- package/src/simple-single-select/use-handle-key-press/use-highlight-first-visible-option.js +38 -0
- package/src/simple-single-select/use-handle-key-press/use-highlight-last-option-on-next-page.js +60 -0
- package/src/simple-single-select/use-handle-key-press/use-highlight-last-visible-option.js +52 -0
- package/src/simple-single-select/use-handle-key-press/use-page-down.js +50 -0
- package/src/simple-single-select/use-handle-key-press/use-page-up.js +50 -0
- package/src/simple-single-select/use-handle-key-press/utils.js +23 -0
- package/src/simple-single-select-field/index.js +1 -0
- package/src/simple-single-select-field/simple-single-select-field.js +198 -0
- package/src/simple-single-select-field/simple-single-select-field.prod.stories.js +188 -0
- package/src/simple-single-select-field/simple-single-select-field.test.js +144 -0
- package/src/single-select/__tests__/selection.test.js +102 -0
- package/src/single-select/__tests__/single-select.test.js +23 -0
- package/src/single-select/features/accepts_blur_cb/index.js +14 -0
- package/src/single-select/features/accepts_blur_cb.feature +8 -0
- package/src/single-select/features/accepts_focus_cb/index.js +14 -0
- package/src/single-select/features/accepts_focus_cb.feature +6 -0
- package/src/single-select/features/accepts_initial_focus/index.js +5 -0
- package/src/single-select/features/accepts_initial_focus.feature +5 -0
- package/src/single-select/features/accepts_loading/index.js +22 -0
- package/src/single-select/features/accepts_loading.feature +14 -0
- package/src/single-select/features/accepts_max_height/index.js +31 -0
- package/src/single-select/features/accepts_max_height.feature +11 -0
- package/src/single-select/features/accepts_placeholder/index.js +25 -0
- package/src/single-select/features/accepts_placeholder.feature +10 -0
- package/src/single-select/features/accepts_prefix/index.js +19 -0
- package/src/single-select/features/accepts_prefix.feature +10 -0
- package/src/single-select/features/allows_invalid_options/index.js +28 -0
- package/src/single-select/features/allows_invalid_options.feature +12 -0
- package/src/single-select/features/allows_selecting/index.js +38 -0
- package/src/single-select/features/allows_selecting.feature +21 -0
- package/src/single-select/features/can_be_cleared/index.js +22 -0
- package/src/single-select/features/can_be_cleared.feature +6 -0
- package/src/single-select/features/can_be_disabled/index.js +39 -0
- package/src/single-select/features/can_be_disabled.feature +32 -0
- package/src/single-select/features/can_be_empty/index.js +28 -0
- package/src/single-select/features/can_be_empty.feature +16 -0
- package/src/single-select/features/can_be_filtered/index.js +23 -0
- package/src/single-select/features/can_be_filtered.feature +14 -0
- package/src/single-select/features/can_be_opened_and_closed/index.js +32 -0
- package/src/single-select/features/can_be_opened_and_closed.feature +41 -0
- package/src/single-select/features/common/index.js +44 -0
- package/src/single-select/features/duplicate_option_values/index.js +26 -0
- package/src/single-select/features/duplicate_option_values.feature +7 -0
- package/src/single-select/features/menu_width_matches_input/index.js +53 -0
- package/src/single-select/features/menu_width_matches_input.feature +11 -0
- package/src/single-select/features/position/index.js +111 -0
- package/src/single-select/features/position.feature +26 -0
- package/src/single-select/features/shows_selections/index.js +9 -0
- package/src/single-select/features/shows_selections.feature +5 -0
- package/src/single-select/filterable-menu.js +41 -0
- package/src/single-select/index.js +1 -0
- package/src/single-select/input.js +101 -0
- package/src/single-select/menu.js +75 -0
- package/src/single-select/selection.js +60 -0
- package/src/single-select/single-select.e2e.stories.js +376 -0
- package/src/single-select/single-select.js +146 -0
- package/src/single-select/single-select.prod.stories.js +358 -0
- package/src/single-select-field/__tests__/single-select-field.test.js +29 -0
- package/src/single-select-field/features/accepts_help_text/index.js +9 -0
- package/src/single-select-field/features/accepts_help_text.feature +5 -0
- package/src/single-select-field/features/accepts_label/index.js +9 -0
- package/src/single-select-field/features/accepts_label.feature +5 -0
- package/src/single-select-field/features/accepts_validation_text/index.js +9 -0
- package/src/single-select-field/features/accepts_validation_text.feature +5 -0
- package/src/single-select-field/features/can_be_required/index.js +11 -0
- package/src/single-select-field/features/can_be_required.feature +5 -0
- package/src/single-select-field/features/has_default_clear_text/index.js +16 -0
- package/src/single-select-field/features/has_default_clear_text.feature +6 -0
- package/src/single-select-field/features/has_default_empty_text/index.js +13 -0
- package/src/single-select-field/features/has_default_empty_text.feature +6 -0
- package/src/single-select-field/features/has_default_filter_nomatch_text/index.js +17 -0
- package/src/single-select-field/features/has_default_filter_nomatch_text.feature +7 -0
- package/src/single-select-field/features/has_default_filter_placeholder/index.js +15 -0
- package/src/single-select-field/features/has_default_filter_placeholder.feature +6 -0
- package/src/single-select-field/features/has_default_loading_text/index.js +13 -0
- package/src/single-select-field/features/has_default_loading_text.feature +6 -0
- package/src/single-select-field/index.js +1 -0
- package/src/single-select-field/single-select-field.e2e.stories.js +45 -0
- package/src/single-select-field/single-select-field.js +178 -0
- package/src/single-select-field/single-select-field.prod.stories.js +146 -0
- package/src/single-select-option/index.js +1 -0
- package/src/single-select-option/single-select-option.js +84 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a filterable MultiSelectField is rendered', () => {
|
|
4
|
+
cy.visitStory('MultiSelectField', 'With filterable')
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
When('the Select is opened', () => {
|
|
8
|
+
cy.get('[data-test="dhis2-uicore-select-input"]').click()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
Then('the filter placeholder exists', () => {
|
|
12
|
+
cy.get(
|
|
13
|
+
'[data-test="dhis2-uicore-multiselect-filterinput"] [placeholder="Type to filter options"]'
|
|
14
|
+
).should('exist')
|
|
15
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Given, Then, When } from '@badeball/cypress-cucumber-preprocessor'
|
|
2
|
+
|
|
3
|
+
Given('a loading MultiSelectField is rendered', () => {
|
|
4
|
+
cy.visitStory('MultiSelectField', 'With loading')
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
When('the Select is opened', () => {
|
|
8
|
+
cy.get('[data-test="dhis2-uicore-select-input"]').click()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
Then('the loading text is visible', () => {
|
|
12
|
+
cy.contains('Loading options').should('be.visible')
|
|
13
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MultiSelectField } from './multi-select-field.js'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { MultiSelectOption } from '../index.js'
|
|
3
|
+
import { MultiSelectField } from './index.js'
|
|
4
|
+
|
|
5
|
+
export default { title: 'MultiSelectField' }
|
|
6
|
+
export const WithLabel = () => (
|
|
7
|
+
<MultiSelectField label="The label">
|
|
8
|
+
<MultiSelectOption value="1" label="one" />
|
|
9
|
+
<MultiSelectOption value="2" label="two" />
|
|
10
|
+
<MultiSelectOption value="3" label="three" />
|
|
11
|
+
</MultiSelectField>
|
|
12
|
+
)
|
|
13
|
+
export const WithHelpText = () => (
|
|
14
|
+
<MultiSelectField helpText="The help text">
|
|
15
|
+
<MultiSelectOption value="1" label="one" />
|
|
16
|
+
<MultiSelectOption value="2" label="two" />
|
|
17
|
+
<MultiSelectOption value="3" label="three" />
|
|
18
|
+
</MultiSelectField>
|
|
19
|
+
)
|
|
20
|
+
export const WithValidationText = () => (
|
|
21
|
+
<MultiSelectField validationText="The validation text">
|
|
22
|
+
<MultiSelectOption value="1" label="one" />
|
|
23
|
+
<MultiSelectOption value="2" label="two" />
|
|
24
|
+
<MultiSelectOption value="3" label="three" />
|
|
25
|
+
</MultiSelectField>
|
|
26
|
+
)
|
|
27
|
+
export const WithLabelAndRequiredStatus = () => (
|
|
28
|
+
<MultiSelectField label="The label" required>
|
|
29
|
+
<MultiSelectOption value="1" label="one" />
|
|
30
|
+
<MultiSelectOption value="2" label="two" />
|
|
31
|
+
<MultiSelectOption value="3" label="three" />
|
|
32
|
+
</MultiSelectField>
|
|
33
|
+
)
|
|
34
|
+
export const WithClearableAndSelectedOption = () => (
|
|
35
|
+
<MultiSelectField selected={['1']} clearable>
|
|
36
|
+
<MultiSelectOption key="1" value="1" label="One" />
|
|
37
|
+
</MultiSelectField>
|
|
38
|
+
)
|
|
39
|
+
export const WithFilterable = () => (
|
|
40
|
+
<MultiSelectField filterable>
|
|
41
|
+
<MultiSelectOption key="1" value="1" label="One" />
|
|
42
|
+
</MultiSelectField>
|
|
43
|
+
)
|
|
44
|
+
export const WithLoading = () => <MultiSelectField loading />
|
|
45
|
+
export const WithoutOptions = () => <MultiSelectField />
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { sharedPropTypes } from '@dhis2/ui-constants'
|
|
2
|
+
import { Box } from '@dhis2-ui/box'
|
|
3
|
+
import { Field } from '@dhis2-ui/field'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import i18n from '../locales/index.js'
|
|
7
|
+
import { MultiSelect } from '../multi-select/index.js'
|
|
8
|
+
|
|
9
|
+
// TODO: translate
|
|
10
|
+
const translate = (prop, interpolationObject) => {
|
|
11
|
+
if (typeof prop === 'function') {
|
|
12
|
+
return prop(interpolationObject)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return prop
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class MultiSelectField extends React.Component {
|
|
19
|
+
static defaultProps = {
|
|
20
|
+
selected: [],
|
|
21
|
+
dataTest: 'dhis2-uiwidgets-multiselectfield',
|
|
22
|
+
|
|
23
|
+
clearText: () => i18n.t('Clear'),
|
|
24
|
+
empty: () => i18n.t('No data found'),
|
|
25
|
+
filterPlaceholder: () => i18n.t('Type to filter options'),
|
|
26
|
+
loadingText: () => i18n.t('Loading options'),
|
|
27
|
+
noMatchText: () => i18n.t('No options found'),
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
render() {
|
|
31
|
+
const {
|
|
32
|
+
className,
|
|
33
|
+
onChange,
|
|
34
|
+
onFocus,
|
|
35
|
+
onKeyDown,
|
|
36
|
+
onBlur,
|
|
37
|
+
required,
|
|
38
|
+
label,
|
|
39
|
+
valid,
|
|
40
|
+
error,
|
|
41
|
+
disabled,
|
|
42
|
+
warning,
|
|
43
|
+
loading,
|
|
44
|
+
selected = MultiSelectField.defaultProps.selected,
|
|
45
|
+
tabIndex,
|
|
46
|
+
helpText,
|
|
47
|
+
validationText,
|
|
48
|
+
maxHeight,
|
|
49
|
+
inputMaxHeight,
|
|
50
|
+
inputWidth,
|
|
51
|
+
children,
|
|
52
|
+
clearable,
|
|
53
|
+
clearText = MultiSelectField.defaultProps.clearText,
|
|
54
|
+
filterable,
|
|
55
|
+
filterPlaceholder = MultiSelectField.defaultProps.filterPlaceholder,
|
|
56
|
+
placeholder,
|
|
57
|
+
prefix,
|
|
58
|
+
empty = MultiSelectField.defaultProps.empty,
|
|
59
|
+
loadingText = MultiSelectField.defaultProps.loadingText,
|
|
60
|
+
noMatchText = MultiSelectField.defaultProps.noMatchText,
|
|
61
|
+
initialFocus,
|
|
62
|
+
dense,
|
|
63
|
+
dataTest = MultiSelectField.defaultProps.dataTest,
|
|
64
|
+
} = this.props
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Field
|
|
68
|
+
className={className}
|
|
69
|
+
dataTest={dataTest}
|
|
70
|
+
disabled={disabled}
|
|
71
|
+
required={required}
|
|
72
|
+
label={label}
|
|
73
|
+
helpText={helpText}
|
|
74
|
+
validationText={validationText}
|
|
75
|
+
error={error}
|
|
76
|
+
warning={warning}
|
|
77
|
+
valid={valid}
|
|
78
|
+
>
|
|
79
|
+
<Box width={inputWidth} minWidth="100px">
|
|
80
|
+
<MultiSelect
|
|
81
|
+
selected={selected}
|
|
82
|
+
tabIndex={tabIndex}
|
|
83
|
+
maxHeight={maxHeight}
|
|
84
|
+
inputMaxHeight={inputMaxHeight}
|
|
85
|
+
onChange={onChange}
|
|
86
|
+
onFocus={onFocus}
|
|
87
|
+
onKeyDown={onKeyDown}
|
|
88
|
+
onBlur={onBlur}
|
|
89
|
+
loading={loading}
|
|
90
|
+
error={error}
|
|
91
|
+
warning={warning}
|
|
92
|
+
valid={valid}
|
|
93
|
+
disabled={disabled}
|
|
94
|
+
clearable={clearable}
|
|
95
|
+
clearText={translate(clearText)}
|
|
96
|
+
filterable={filterable}
|
|
97
|
+
filterPlaceholder={translate(filterPlaceholder)}
|
|
98
|
+
placeholder={placeholder}
|
|
99
|
+
prefix={prefix}
|
|
100
|
+
empty={translate(empty)}
|
|
101
|
+
loadingText={translate(loadingText)}
|
|
102
|
+
noMatchText={translate(noMatchText)}
|
|
103
|
+
initialFocus={initialFocus}
|
|
104
|
+
dense={dense}
|
|
105
|
+
>
|
|
106
|
+
{children}
|
|
107
|
+
</MultiSelect>
|
|
108
|
+
</Box>
|
|
109
|
+
</Field>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
MultiSelectField.propTypes = {
|
|
115
|
+
/** Should be `MultiSelectOption` components */
|
|
116
|
+
children: PropTypes.node,
|
|
117
|
+
className: PropTypes.string,
|
|
118
|
+
/** Label for the button that clears selections */
|
|
119
|
+
clearText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
120
|
+
/** Adds a button to the MultiSelect that clears selections when pressed */
|
|
121
|
+
clearable: PropTypes.bool,
|
|
122
|
+
dataTest: PropTypes.string,
|
|
123
|
+
/** Makes the MultiSelect smaller */
|
|
124
|
+
dense: PropTypes.bool,
|
|
125
|
+
/** Disables the MultiSelect */
|
|
126
|
+
disabled: PropTypes.bool,
|
|
127
|
+
/** Text to display when there are no options */
|
|
128
|
+
empty: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
129
|
+
/** Adds 'error' appearance for validation feedback. Mutually exclusive with 'valid' and 'warning' props */
|
|
130
|
+
error: sharedPropTypes.statusPropType,
|
|
131
|
+
/** Placeholder text to show in the filter field when it is empty */
|
|
132
|
+
filterPlaceholder: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
|
|
133
|
+
/** Adds a field to filter options */
|
|
134
|
+
filterable: PropTypes.bool,
|
|
135
|
+
/** Useful guiding text to display below the MultiSelect */
|
|
136
|
+
helpText: PropTypes.string,
|
|
137
|
+
/** Grabs initial focus on the page */
|
|
138
|
+
initialFocus: PropTypes.bool,
|
|
139
|
+
/** Constrains the height of the input */
|
|
140
|
+
inputMaxHeight: PropTypes.string,
|
|
141
|
+
/** Sets the width of the input. Can be any valid CSS measurement */
|
|
142
|
+
inputWidth: PropTypes.string,
|
|
143
|
+
/** Text for the label above the MultiSelect */
|
|
144
|
+
label: PropTypes.string,
|
|
145
|
+
/** Applies a loading appearance to the dropdown options */
|
|
146
|
+
loading: PropTypes.bool,
|
|
147
|
+
/** Text to display when `loading` is true */
|
|
148
|
+
loadingText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
149
|
+
/** Constrains height of the MultiSelect */
|
|
150
|
+
maxHeight: PropTypes.string,
|
|
151
|
+
/** Text to display when there are no filter results */
|
|
152
|
+
noMatchText: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
|
153
|
+
/** Placeholder text when the MultiSelect is empty */
|
|
154
|
+
placeholder: PropTypes.string,
|
|
155
|
+
/** Leading text to prefix selections */
|
|
156
|
+
prefix: PropTypes.string,
|
|
157
|
+
/** Indicates that a selection is required */
|
|
158
|
+
required: PropTypes.bool,
|
|
159
|
+
/** Selected items in the MultiSelect (each string should refer to the item's `value` attribute) */
|
|
160
|
+
selected: PropTypes.arrayOf(PropTypes.string),
|
|
161
|
+
tabIndex: PropTypes.string,
|
|
162
|
+
/** Adds 'valid' appearance for validation feedback. Mutually exclusive with 'error' and 'warning' props */
|
|
163
|
+
valid: sharedPropTypes.statusPropType,
|
|
164
|
+
/** Text to provide form validation feedback. Receives styles according to validation status */
|
|
165
|
+
validationText: PropTypes.string,
|
|
166
|
+
/** Adds 'warning' appearance for validation feedback. Mutually exclusive with 'valid' and 'error' props */
|
|
167
|
+
warning: sharedPropTypes.statusPropType,
|
|
168
|
+
/** Called with signature `({ selected: [String] }, event)` */
|
|
169
|
+
onBlur: PropTypes.func,
|
|
170
|
+
/** Called with signature `({ selected: [String] }, event)` */
|
|
171
|
+
onChange: PropTypes.func,
|
|
172
|
+
/** Called with signature `({ selected: [String] }, event)` */
|
|
173
|
+
onFocus: PropTypes.func,
|
|
174
|
+
/** Called with signature `({ selected: [String] }, event)` */
|
|
175
|
+
onKeyDown: PropTypes.func,
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { MultiSelectField }
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { sharedPropTypes } from '@dhis2/ui-constants'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { MultiSelectOption } from '../index.js'
|
|
4
|
+
import { MultiSelectField } from './index.js'
|
|
5
|
+
|
|
6
|
+
const description = `
|
|
7
|
+
\`MultiSelectField\` is a wrapper around a \`MultiSelect\` component that adds a label, help text, validation text, and other features.
|
|
8
|
+
|
|
9
|
+
See the MultiSelect for more information, and read more at [Design System: Select](https://github.com/dhis2/design-system/blob/master/molecules/select.md#multiple-selection).
|
|
10
|
+
|
|
11
|
+
\`\`\`js
|
|
12
|
+
import { MultiSelectField, MultiSelectOption } from '@dhis2/ui'
|
|
13
|
+
\`\`\`
|
|
14
|
+
|
|
15
|
+
_**Note**: The dropdowns in some of the following stories won't appear correctly on this page. View these demos in the 'Canvas' tab._
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
const onChange = (selected) =>
|
|
19
|
+
alert(`Selected changed to: ${JSON.stringify(selected, null, 2)}`)
|
|
20
|
+
|
|
21
|
+
const options = [
|
|
22
|
+
<MultiSelectOption key="1" value="1" label="one" />,
|
|
23
|
+
<MultiSelectOption key="2" value="2" label="two" />,
|
|
24
|
+
<MultiSelectOption key="3" value="3" label="three" />,
|
|
25
|
+
<MultiSelectOption key="4" value="4" label="four" />,
|
|
26
|
+
<MultiSelectOption key="5" value="5" label="five" />,
|
|
27
|
+
<MultiSelectOption key="6" value="6" label="six" />,
|
|
28
|
+
<MultiSelectOption key="7" value="7" label="seven" />,
|
|
29
|
+
<MultiSelectOption key="8" value="8" label="eight" />,
|
|
30
|
+
<MultiSelectOption key="9" value="9" label="nine" />,
|
|
31
|
+
<MultiSelectOption key="10" value="10" label="ten" />,
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
title: 'Multi Select Field',
|
|
36
|
+
component: MultiSelectField,
|
|
37
|
+
subcomponents: { MultiSelectOption },
|
|
38
|
+
parameters: { docs: { description: { component: description } } },
|
|
39
|
+
// default args for stories
|
|
40
|
+
args: {
|
|
41
|
+
// Fix default prop issues - causes 'i18n is not defined' error
|
|
42
|
+
dataTest: 'dhis2-uiwidgets-multiselectfield',
|
|
43
|
+
clearText: 'Clear',
|
|
44
|
+
empty: 'No data found',
|
|
45
|
+
filterPlaceholder: 'Type to filter options',
|
|
46
|
+
loadingText: 'Loading options',
|
|
47
|
+
noMatchText: 'No options found',
|
|
48
|
+
|
|
49
|
+
label: 'Default label',
|
|
50
|
+
selected: ['1'],
|
|
51
|
+
children: options,
|
|
52
|
+
onChange: onChange,
|
|
53
|
+
},
|
|
54
|
+
argTypes: {
|
|
55
|
+
valid: { ...sharedPropTypes.statusArgType },
|
|
56
|
+
warning: { ...sharedPropTypes.statusArgType },
|
|
57
|
+
error: { ...sharedPropTypes.statusArgType },
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const Template = (args) => <MultiSelectField {...args} />
|
|
62
|
+
|
|
63
|
+
export const Default = Template.bind({})
|
|
64
|
+
|
|
65
|
+
export const WithHelpText = Template.bind({})
|
|
66
|
+
WithHelpText.args = { helpText: 'Helpful text.' }
|
|
67
|
+
WithHelpText.parameters = {
|
|
68
|
+
docs: {
|
|
69
|
+
description: {
|
|
70
|
+
story: `_**Note**: The dropdowns in the following stories won't appear correctly on this page. View these demos in the 'Canvas' tab._`,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const StatusValid = Template.bind({})
|
|
76
|
+
StatusValid.args = {
|
|
77
|
+
valid: true,
|
|
78
|
+
validationText: 'Totally valid!',
|
|
79
|
+
...WithHelpText.args,
|
|
80
|
+
}
|
|
81
|
+
StatusValid.storyName = 'Status: Valid'
|
|
82
|
+
|
|
83
|
+
export const StatusWarning = Template.bind({})
|
|
84
|
+
StatusWarning.args = {
|
|
85
|
+
warning: true,
|
|
86
|
+
validationText: 'Hm, not quite, I warn thee!',
|
|
87
|
+
...WithHelpText.args,
|
|
88
|
+
}
|
|
89
|
+
StatusWarning.storyName = 'Status: Warning'
|
|
90
|
+
|
|
91
|
+
export const StatusError = Template.bind({})
|
|
92
|
+
StatusError.args = {
|
|
93
|
+
error: true,
|
|
94
|
+
validationText: 'That value is wrong. Sorry!',
|
|
95
|
+
...WithHelpText.args,
|
|
96
|
+
}
|
|
97
|
+
StatusError.storyName = 'Status: Error'
|
|
98
|
+
|
|
99
|
+
export const Required = Template.bind({})
|
|
100
|
+
Required.args = { required: true }
|
|
101
|
+
|
|
102
|
+
export const InputWidth = Template.bind({})
|
|
103
|
+
InputWidth.args = {
|
|
104
|
+
inputWidth: '200px',
|
|
105
|
+
label: 'A very long label indeed, well at least longer than the input field to show how it looks and works and stuff',
|
|
106
|
+
required: true,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const DefaultClearText = Template.bind({})
|
|
110
|
+
DefaultClearText.args = {
|
|
111
|
+
clearable: true,
|
|
112
|
+
children: (
|
|
113
|
+
<MultiSelectOption
|
|
114
|
+
key="1"
|
|
115
|
+
value="1"
|
|
116
|
+
label="Not translated, just for showing clear button"
|
|
117
|
+
/>
|
|
118
|
+
),
|
|
119
|
+
label: null,
|
|
120
|
+
}
|
|
121
|
+
DefaultClearText.storyName = 'Default: clearText'
|
|
122
|
+
|
|
123
|
+
export const DefaultEmpty = Template.bind({})
|
|
124
|
+
DefaultEmpty.args = { children: null, selected: [], label: null }
|
|
125
|
+
DefaultEmpty.storyName = 'Default: empty'
|
|
126
|
+
|
|
127
|
+
export const DefaultFilterPlaceholderAndNoMatchText = Template.bind({})
|
|
128
|
+
DefaultFilterPlaceholderAndNoMatchText.args = {
|
|
129
|
+
filterable: true,
|
|
130
|
+
...DefaultEmpty.args,
|
|
131
|
+
}
|
|
132
|
+
DefaultFilterPlaceholderAndNoMatchText.storyName =
|
|
133
|
+
'Default: filterPlaceholder and noMatchText'
|
|
134
|
+
|
|
135
|
+
export const DefaultLoadingText = Template.bind({})
|
|
136
|
+
DefaultLoadingText.args = { loading: true, ...DefaultEmpty.args }
|
|
137
|
+
DefaultLoadingText.storyName = 'Default: loadingText'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MultiSelectOption } from './multi-select-option.js'
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { colors, spacers } from '@dhis2/ui-constants'
|
|
2
|
+
import { Checkbox } from '@dhis2-ui/checkbox'
|
|
3
|
+
import cx from 'classnames'
|
|
4
|
+
import PropTypes from 'prop-types'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import { resolve } from 'styled-jsx/css'
|
|
7
|
+
|
|
8
|
+
// Padding has to be set on the label, so that the entire area is clickable
|
|
9
|
+
const { styles, className: checkboxClassname } = resolve`
|
|
10
|
+
padding: ${spacers.dp8} ${spacers.dp12};
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
const MultiSelectOption = ({
|
|
14
|
+
label,
|
|
15
|
+
active,
|
|
16
|
+
disabled,
|
|
17
|
+
onClick,
|
|
18
|
+
className,
|
|
19
|
+
dataTest = 'dhis2-uicore-multiselectoption',
|
|
20
|
+
value,
|
|
21
|
+
}) => (
|
|
22
|
+
<div
|
|
23
|
+
className={cx(className, { active, disabled })}
|
|
24
|
+
data-test={dataTest}
|
|
25
|
+
data-value={value}
|
|
26
|
+
data-label={label}
|
|
27
|
+
>
|
|
28
|
+
<Checkbox
|
|
29
|
+
name={label}
|
|
30
|
+
className={checkboxClassname}
|
|
31
|
+
checked={active}
|
|
32
|
+
label={label}
|
|
33
|
+
onChange={onClick}
|
|
34
|
+
disabled={disabled}
|
|
35
|
+
dense
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
{styles}
|
|
39
|
+
|
|
40
|
+
<style jsx>{`
|
|
41
|
+
div:hover {
|
|
42
|
+
background-color: ${colors.grey200};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
div.active {
|
|
46
|
+
background-color: ${colors.teal050};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
div.active:hover {
|
|
50
|
+
background-color: #e6f4f4;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
div.disabled:hover {
|
|
54
|
+
background-color: initial;
|
|
55
|
+
}
|
|
56
|
+
`}</style>
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
MultiSelectOption.propTypes = {
|
|
61
|
+
label: PropTypes.string.isRequired,
|
|
62
|
+
value: PropTypes.string.isRequired,
|
|
63
|
+
active: PropTypes.bool,
|
|
64
|
+
className: PropTypes.string,
|
|
65
|
+
dataTest: PropTypes.string,
|
|
66
|
+
disabled: PropTypes.bool,
|
|
67
|
+
onClick: PropTypes.func,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { MultiSelectOption }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { render, fireEvent, screen } from '@testing-library/react'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { Select } from '../select.js'
|
|
4
|
+
|
|
5
|
+
describe('<Select />', () => {
|
|
6
|
+
it('should call the onKeyDown callback when provided', () => {
|
|
7
|
+
const onKeyDown = jest.fn()
|
|
8
|
+
|
|
9
|
+
render(
|
|
10
|
+
<Select
|
|
11
|
+
input={<input type="text" />}
|
|
12
|
+
menu={<div />}
|
|
13
|
+
selected=""
|
|
14
|
+
onKeyDown={onKeyDown}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
fireEvent.keyDown(screen.getByRole('textbox'), {
|
|
19
|
+
key: 'Enter',
|
|
20
|
+
code: 'Enter',
|
|
21
|
+
charCode: 13,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
expect(onKeyDown).toHaveBeenCalledWith(
|
|
25
|
+
{ selected: '' },
|
|
26
|
+
expect.objectContaining({})
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
expect(onKeyDown).toHaveBeenCalledTimes(1)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a function, that, as long as it continues to be invoked, will not be triggered. The
|
|
3
|
+
* function will be called after it stops being called for N milliseconds. If `immediate` is
|
|
4
|
+
* passed, trigger the function on the leading edge, instead of the trailing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const debounce = (func, wait, immediate) => {
|
|
8
|
+
let timeout
|
|
9
|
+
|
|
10
|
+
return (...args) => {
|
|
11
|
+
const context = this
|
|
12
|
+
|
|
13
|
+
const later = () => {
|
|
14
|
+
timeout = null
|
|
15
|
+
|
|
16
|
+
if (!immediate) {
|
|
17
|
+
func.apply(context, args)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const callNow = immediate && !timeout
|
|
22
|
+
|
|
23
|
+
clearTimeout(timeout)
|
|
24
|
+
timeout = setTimeout(later, wait)
|
|
25
|
+
|
|
26
|
+
if (callNow) {
|
|
27
|
+
func.apply(context, args)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { debounce } from './debounce.js'
|
|
2
|
+
|
|
3
|
+
beforeEach(() => {
|
|
4
|
+
jest.useFakeTimers()
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
describe('debounce', () => {
|
|
8
|
+
it('should call the debounced function once after the timeout without immediate', () => {
|
|
9
|
+
const spy = jest.fn()
|
|
10
|
+
const debounced = debounce(spy, 100)
|
|
11
|
+
|
|
12
|
+
debounced()
|
|
13
|
+
debounced()
|
|
14
|
+
|
|
15
|
+
expect(spy).not.toHaveBeenCalled()
|
|
16
|
+
|
|
17
|
+
jest.runAllTimers()
|
|
18
|
+
|
|
19
|
+
expect(spy).toHaveBeenCalledTimes(1)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should call the debounced function once immediately if immediate is set', () => {
|
|
23
|
+
const spy = jest.fn()
|
|
24
|
+
const debounced = debounce(spy, 100, true)
|
|
25
|
+
|
|
26
|
+
debounced()
|
|
27
|
+
debounced()
|
|
28
|
+
|
|
29
|
+
expect(spy).toHaveBeenCalledTimes(1)
|
|
30
|
+
|
|
31
|
+
jest.runAllTimers()
|
|
32
|
+
|
|
33
|
+
expect(spy).toHaveBeenCalledTimes(1)
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { colors, spacers, theme } from '@dhis2/ui-constants'
|
|
2
|
+
import PropTypes from 'prop-types'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
const Empty = ({ message, className, dataTest }) => (
|
|
6
|
+
<div className={className} data-test={dataTest}>
|
|
7
|
+
{message}
|
|
8
|
+
<style jsx>{`
|
|
9
|
+
div {
|
|
10
|
+
color: ${colors.grey700};
|
|
11
|
+
font-family: ${theme.fonts};
|
|
12
|
+
font-size: 13px;
|
|
13
|
+
line-height: 16px;
|
|
14
|
+
padding-block: ${spacers.dp8};
|
|
15
|
+
padding-inline: ${spacers.dp24};
|
|
16
|
+
text-align: center;
|
|
17
|
+
}
|
|
18
|
+
`}</style>
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
Empty.propTypes = {
|
|
23
|
+
dataTest: PropTypes.string.isRequired,
|
|
24
|
+
message: PropTypes.string.isRequired,
|
|
25
|
+
className: PropTypes.string,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { Empty }
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { spacers, colors } from '@dhis2/ui-constants'
|
|
2
|
+
import { Input } from '@dhis2-ui/input'
|
|
3
|
+
import PropTypes from 'prop-types'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
|
|
6
|
+
const FilterInput = ({ value, onChange, placeholder, className, dataTest }) => (
|
|
7
|
+
<div className={className}>
|
|
8
|
+
<Input
|
|
9
|
+
dense
|
|
10
|
+
dataTest={dataTest}
|
|
11
|
+
value={value}
|
|
12
|
+
onChange={onChange}
|
|
13
|
+
type="text"
|
|
14
|
+
name="filter"
|
|
15
|
+
placeholder={placeholder}
|
|
16
|
+
initialFocus
|
|
17
|
+
/>
|
|
18
|
+
|
|
19
|
+
<style jsx>{`
|
|
20
|
+
div {
|
|
21
|
+
position: sticky;
|
|
22
|
+
inset-block-start: 0;
|
|
23
|
+
background: ${colors.white};
|
|
24
|
+
padding-block-start: ${spacers.dp8};
|
|
25
|
+
padding-inline-end: ${spacers.dp8};
|
|
26
|
+
padding-block-end: ${spacers.dp4};
|
|
27
|
+
padding-inline-start: ${spacers.dp8};
|
|
28
|
+
z-index: 1;
|
|
29
|
+
}
|
|
30
|
+
`}</style>
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
FilterInput.propTypes = {
|
|
35
|
+
dataTest: PropTypes.string.isRequired,
|
|
36
|
+
value: PropTypes.string.isRequired,
|
|
37
|
+
className: PropTypes.string,
|
|
38
|
+
placeholder: PropTypes.string,
|
|
39
|
+
onChange: PropTypes.func,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { FilterInput }
|