From b6c8fc214c6f022ffb41a6ff139fccfd4b221dd4 Mon Sep 17 00:00:00 2001 From: sangeet-fw Date: Thu, 22 Jun 2023 14:45:05 +0530 Subject: [PATCH 1/2] feat(select-fallback): added fallback placement prop for select --- packages/crayons-core/src/components.d.ts | 8 ++ .../src/components/select/readme.md | 79 ++++++++++--------- .../src/components/select/select.tsx | 5 ++ 3 files changed, 53 insertions(+), 39 deletions(-) diff --git a/packages/crayons-core/src/components.d.ts b/packages/crayons-core/src/components.d.ts index 86d5e5d33..64138d49d 100644 --- a/packages/crayons-core/src/components.d.ts +++ b/packages/crayons-core/src/components.d.ts @@ -1696,6 +1696,10 @@ export namespace Components { * Error text displayed below the text box. */ "errorText": string; + /** + * Alternative placement for popover if the default placement is not possible. + */ + "fallbackPlacements": [PopoverPlacementType]; /** * If true, the user must select a value. The default value is not displayed. */ @@ -4636,6 +4640,10 @@ declare namespace LocalJSX { * Error text displayed below the text box. */ "errorText"?: string; + /** + * Alternative placement for popover if the default placement is not possible. + */ + "fallbackPlacements"?: [PopoverPlacementType]; /** * If true, the user must select a value. The default value is not displayed. */ diff --git a/packages/crayons-core/src/components/select/readme.md b/packages/crayons-core/src/components/select/readme.md index 74507f1ee..a1ee59b13 100644 --- a/packages/crayons-core/src/components/select/readme.md +++ b/packages/crayons-core/src/components/select/readme.md @@ -1605,45 +1605,46 @@ Refer the [css variables](#css-custom-properties) for modifying the appearance o ## Properties -| Property | Attribute | Description | Type | Default | -| ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -| `allowDeselect` | `allow-deselect` | Whether clicking on the already selected option disables it. | `boolean` | `true` | -| `boundary` | -- | Describes the select's boundary HTMLElement | `HTMLElement` | `undefined` | -| `caret` | `caret` | Whether the arrow/caret should be shown in the select. | `boolean` | `true` | -| `checkbox` | `checkbox` | Place a checkbox. | `boolean` | `false` | -| `creatableProps` | -- | Props to be passed for creatable select isCreatable: boolean - If true, select accepts user input that are not present as options and add them as options validateNewOption: (value) => boolean - If passed, this function will determine the error state for every new option entered. If return value is true, error state of the newly created option will be false and if return value is false, then the error state of the newly created option will be true. formatCreateLabel: (label) => string - Gets the label for the "create new ..." option in the menu. Current input value is provided as argument. | `{ isCreatable: boolean; validateNewOption: (_value: any) => boolean; formatCreateLabel: (label: any) => string; }` | `{ isCreatable: false, validateNewOption: (_value): boolean => true, formatCreateLabel: (label): string => label, }` | -| `debounceTimer` | `debounce-timer` | Debounce timer for the search promise function. | `number` | `300` | -| `disabled` | `disabled` | Disables the component on the interface. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | -| `errorText` | `error-text` | Error text displayed below the text box. | `string` | `''` | -| `forceSelect` | `force-select` | If true, the user must select a value. The default value is not displayed. | `boolean` | `true` | -| `hintText` | `hint-text` | Hint text displayed below the text box. | `string` | `''` | -| `hoist` | `hoist` | Option to prevent the select options from being clipped when the component is placed inside a container with `overflow: auto\|hidden\|scroll`. | `boolean` | `false` | -| `label` | `label` | Label displayed on the interface, for the component. | `string` | `''` | -| `labelledBy` | `labelled-by` | If the default label prop is not used, then use this prop to pass the id of the label. | `string` | `''` | -| `max` | `max` | Works with `multiple` enabled. Configures the maximum number of options that can be selected with a multi-select component. | `number` | `Number.MAX_VALUE` | -| `maxHeight` | `max-height` | Sets the max height of select with multiple options selected and displays a scroll when maxHeight value is exceeded | `string` | `'none'` | -| `multiple` | `multiple` | Enables selection of multiple options. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | -| `name` | `name` | Name of the component, saved as part of form data. | `string` | `''` | -| `noDataText` | `no-data-text` | Text to be displayed when there is no data available in the select. | `string` | `''` | -| `notFoundText` | `not-found-text` | Default option to be shown if the option doesn't match the filterText. | `string` | `''` | -| `optionLabelPath` | `option-label-path` | Key for determining the label for a given option | `string` | `'text'` | -| `optionValuePath` | `option-value-path` | Key for determining the value for a given option | `string` | `'value'` | -| `options` | `options` | The data for the select component, the options will be of type array of fw-select-options. | `any` | `undefined` | -| `optionsPlacement` | `options-placement` | Placement of the options list with respect to select. | `"bottom" \| "bottom-end" \| "bottom-start" \| "left" \| "left-end" \| "left-start" \| "right" \| "right-end" \| "right-start" \| "top" \| "top-end" \| "top-start"` | `'bottom'` | -| `optionsVariant` | `options-variant` | Standard is the default option without any graphics other options are icon and avatar which places either the icon or avatar at the beginning of the row. The props for the icon or avatar are passed as an object via the graphicsProps. | `"avatar" \| "icon" \| "standard"` | `'standard'` | -| `placeholder` | `placeholder` | Text displayed in the list box before an option is selected. | `string` | `undefined` | -| `readonly` | `readonly` | If true, the user cannot modify the default value selected. If the attribute's value is undefined, the value is set to true. | `boolean` | `false` | -| `required` | `required` | Specifies the select field as a mandatory field and displays an asterisk next to the label. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | -| `sameWidth` | `same-width` | Whether the select width to be same as that of the options. | `boolean` | `true` | -| `search` | `search` | Filter function which takes in filterText and dataSource and return a Promise. Where filter text is the text to filter the value in dataSource array. The returned promise should contain the array of options to be displayed. | `any` | `undefined` | -| `searchable` | `searchable` | Allow to search for value. Default is true. | `boolean` | `true` | -| `selectedOptions` | -- | Array of the options that is displayed as the default selection, in the list box. Must be a valid option corresponding to the fw-select-option components used in Select. | `any[]` | `[]` | -| `state` | `state` | Theme based on which the list box is styled. | `"error" \| "normal" \| "warning"` | `'normal'` | -| `tagVariant` | `tag-variant` | The variant of tag to be used. | `"avatar" \| "standard"` | `'standard'` | -| `type` | `type` | Type of option accepted as the input value. If a user tries to enter an option other than the specified type, the list is not populated. | `"number" \| "text"` | `'text'` | -| `value` | `value` | Value of the option that is displayed as the default selection, in the list box. Must be a valid value corresponding to the fw-select-option components used in Select. | `any` | `undefined` | -| `variant` | `variant` | The UI variant of the select to be used. | `"button" \| "mail" \| "standard"` | `'standard'` | -| `warningText` | `warning-text` | Warning text displayed below the text box. | `string` | `''` | +| Property | Attribute | Description | Type | Default | +| -------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `allowDeselect` | `allow-deselect` | Whether clicking on the already selected option disables it. | `boolean` | `true` | +| `boundary` | -- | Describes the select's boundary HTMLElement | `HTMLElement` | `undefined` | +| `caret` | `caret` | Whether the arrow/caret should be shown in the select. | `boolean` | `true` | +| `checkbox` | `checkbox` | Place a checkbox. | `boolean` | `false` | +| `creatableProps` | -- | Props to be passed for creatable select isCreatable: boolean - If true, select accepts user input that are not present as options and add them as options validateNewOption: (value) => boolean - If passed, this function will determine the error state for every new option entered. If return value is true, error state of the newly created option will be false and if return value is false, then the error state of the newly created option will be true. formatCreateLabel: (label) => string - Gets the label for the "create new ..." option in the menu. Current input value is provided as argument. | `{ isCreatable: boolean; validateNewOption: (_value: any) => boolean; formatCreateLabel: (label: any) => string; }` | `{ isCreatable: false, validateNewOption: (_value): boolean => true, formatCreateLabel: (label): string => label, }` | +| `debounceTimer` | `debounce-timer` | Debounce timer for the search promise function. | `number` | `300` | +| `disabled` | `disabled` | Disables the component on the interface. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | +| `errorText` | `error-text` | Error text displayed below the text box. | `string` | `''` | +| `fallbackPlacements` | -- | Alternative placement for popover if the default placement is not possible. | `[PopoverPlacementType]` | `['bottom']` | +| `forceSelect` | `force-select` | If true, the user must select a value. The default value is not displayed. | `boolean` | `true` | +| `hintText` | `hint-text` | Hint text displayed below the text box. | `string` | `''` | +| `hoist` | `hoist` | Option to prevent the select options from being clipped when the component is placed inside a container with `overflow: auto\|hidden\|scroll`. | `boolean` | `false` | +| `label` | `label` | Label displayed on the interface, for the component. | `string` | `''` | +| `labelledBy` | `labelled-by` | If the default label prop is not used, then use this prop to pass the id of the label. | `string` | `''` | +| `max` | `max` | Works with `multiple` enabled. Configures the maximum number of options that can be selected with a multi-select component. | `number` | `Number.MAX_VALUE` | +| `maxHeight` | `max-height` | Sets the max height of select with multiple options selected and displays a scroll when maxHeight value is exceeded | `string` | `'none'` | +| `multiple` | `multiple` | Enables selection of multiple options. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | +| `name` | `name` | Name of the component, saved as part of form data. | `string` | `''` | +| `noDataText` | `no-data-text` | Text to be displayed when there is no data available in the select. | `string` | `''` | +| `notFoundText` | `not-found-text` | Default option to be shown if the option doesn't match the filterText. | `string` | `''` | +| `optionLabelPath` | `option-label-path` | Key for determining the label for a given option | `string` | `'text'` | +| `optionValuePath` | `option-value-path` | Key for determining the value for a given option | `string` | `'value'` | +| `options` | `options` | The data for the select component, the options will be of type array of fw-select-options. | `any` | `undefined` | +| `optionsPlacement` | `options-placement` | Placement of the options list with respect to select. | `"bottom" \| "bottom-end" \| "bottom-start" \| "left" \| "left-end" \| "left-start" \| "right" \| "right-end" \| "right-start" \| "top" \| "top-end" \| "top-start"` | `'bottom'` | +| `optionsVariant` | `options-variant` | Standard is the default option without any graphics other options are icon and avatar which places either the icon or avatar at the beginning of the row. The props for the icon or avatar are passed as an object via the graphicsProps. | `"avatar" \| "icon" \| "standard"` | `'standard'` | +| `placeholder` | `placeholder` | Text displayed in the list box before an option is selected. | `string` | `undefined` | +| `readonly` | `readonly` | If true, the user cannot modify the default value selected. If the attribute's value is undefined, the value is set to true. | `boolean` | `false` | +| `required` | `required` | Specifies the select field as a mandatory field and displays an asterisk next to the label. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | +| `sameWidth` | `same-width` | Whether the select width to be same as that of the options. | `boolean` | `true` | +| `search` | `search` | Filter function which takes in filterText and dataSource and return a Promise. Where filter text is the text to filter the value in dataSource array. The returned promise should contain the array of options to be displayed. | `any` | `undefined` | +| `searchable` | `searchable` | Allow to search for value. Default is true. | `boolean` | `true` | +| `selectedOptions` | -- | Array of the options that is displayed as the default selection, in the list box. Must be a valid option corresponding to the fw-select-option components used in Select. | `any[]` | `[]` | +| `state` | `state` | Theme based on which the list box is styled. | `"error" \| "normal" \| "warning"` | `'normal'` | +| `tagVariant` | `tag-variant` | The variant of tag to be used. | `"avatar" \| "standard"` | `'standard'` | +| `type` | `type` | Type of option accepted as the input value. If a user tries to enter an option other than the specified type, the list is not populated. | `"number" \| "text"` | `'text'` | +| `value` | `value` | Value of the option that is displayed as the default selection, in the list box. Must be a valid value corresponding to the fw-select-option components used in Select. | `any` | `undefined` | +| `variant` | `variant` | The UI variant of the select to be used. | `"button" \| "mail" \| "standard"` | `'standard'` | +| `warningText` | `warning-text` | Warning text displayed below the text box. | `string` | `''` | ## Events diff --git a/packages/crayons-core/src/components/select/select.tsx b/packages/crayons-core/src/components/select/select.tsx index 2b5c0fefb..850c332dc 100644 --- a/packages/crayons-core/src/components/select/select.tsx +++ b/packages/crayons-core/src/components/select/select.tsx @@ -205,6 +205,10 @@ export class Select { * Placement of the options list with respect to select. */ @Prop() optionsPlacement: PopoverPlacementType = 'bottom'; + /** + * Alternative placement for popover if the default placement is not possible. + */ + @Prop() fallbackPlacements: [PopoverPlacementType] = ['bottom']; /** * The variant of tag to be used. */ @@ -992,6 +996,7 @@ export class Select { ref={(popoverRef) => (this.popoverRef = popoverRef)} same-width={this.sameWidth} placement={this.optionsPlacement} + fallbackPlacements={this.fallbackPlacements} boundary={this.boundary} hoist={this.hoist} > From b6330ba426b763619eae127c9d8e1361d3a77a2f Mon Sep 17 00:00:00 2001 From: sangeet-fw Date: Mon, 26 Jun 2023 09:57:28 +0530 Subject: [PATCH 2/2] chore(select-fallback): added fallback placement property for select --- .../src/components/popover/popover.tsx | 65 ++++++++++++------- .../src/components/select/readme.md | 2 +- .../src/components/select/select.tsx | 4 +- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/packages/crayons-core/src/components/popover/popover.tsx b/packages/crayons-core/src/components/popover/popover.tsx index 29c4e2418..6cfc5ca8e 100644 --- a/packages/crayons-core/src/components/popover/popover.tsx +++ b/packages/crayons-core/src/components/popover/popover.tsx @@ -8,6 +8,7 @@ import { Method, Prop, h, + Watch, } from '@stencil/core'; import { createPopper, Instance } from '@popperjs/core'; import { PopoverPlacementType, PopoverTriggerType } from '../../utils/types'; @@ -184,6 +185,44 @@ export class Popover { } } + @Watch('boundary') + @Watch('placement') + @Watch('fallbackPlacements') + handlePlacementChange(): void { + this.popperInstance?.destroy(); + this.popperInstance = null; + this.setPopperOptions(); + this.updatePopper(); + } + + setPopperOptions() { + this.popperOptions = { + placement: this.placement, + strategy: this.hoist ? 'fixed' : 'absolute', + modifiers: [ + { + name: 'flip', + options: { + fallbackPlacements: this.fallbackPlacements, + }, + }, + { + name: 'preventOverflow', + options: { + boundary: this.boundary || 'clippingParents', + }, + }, + { + name: 'offset', + options: { + offset: [Number(this.skidding), Number(this.distance)], + }, + }, + popperModifierRTL, + ], + }; + } + componentWillLoad() { this.contentRef = this.host.querySelector('[slot="popover-content"]'); this.triggerRef = this.host.querySelector('[slot="popover-trigger"]'); @@ -225,31 +264,7 @@ export class Popover { } }); } - this.popperOptions = { - placement: this.placement, - strategy: this.hoist ? 'fixed' : 'absolute', - modifiers: [ - { - name: 'flip', - options: { - fallbackPlacements: this.fallbackPlacements, - }, - }, - { - name: 'preventOverflow', - options: { - boundary: this.boundary || 'clippingParents', - }, - }, - { - name: 'offset', - options: { - offset: [Number(this.skidding), Number(this.distance)], - }, - }, - popperModifierRTL, - ], - }; + this.setPopperOptions(); } private async delay(ms: number) { diff --git a/packages/crayons-core/src/components/select/readme.md b/packages/crayons-core/src/components/select/readme.md index a1ee59b13..289aa654b 100644 --- a/packages/crayons-core/src/components/select/readme.md +++ b/packages/crayons-core/src/components/select/readme.md @@ -1615,7 +1615,7 @@ Refer the [css variables](#css-custom-properties) for modifying the appearance o | `debounceTimer` | `debounce-timer` | Debounce timer for the search promise function. | `number` | `300` | | `disabled` | `disabled` | Disables the component on the interface. If the attribute’s value is undefined, the value is set to false. | `boolean` | `false` | | `errorText` | `error-text` | Error text displayed below the text box. | `string` | `''` | -| `fallbackPlacements` | -- | Alternative placement for popover if the default placement is not possible. | `[PopoverPlacementType]` | `['bottom']` | +| `fallbackPlacements` | -- | Alternative placement for popover if the default placement is not possible. | `[PopoverPlacementType]` | `['top']` | | `forceSelect` | `force-select` | If true, the user must select a value. The default value is not displayed. | `boolean` | `true` | | `hintText` | `hint-text` | Hint text displayed below the text box. | `string` | `''` | | `hoist` | `hoist` | Option to prevent the select options from being clipped when the component is placed inside a container with `overflow: auto\|hidden\|scroll`. | `boolean` | `false` | diff --git a/packages/crayons-core/src/components/select/select.tsx b/packages/crayons-core/src/components/select/select.tsx index 850c332dc..71821a416 100644 --- a/packages/crayons-core/src/components/select/select.tsx +++ b/packages/crayons-core/src/components/select/select.tsx @@ -208,7 +208,7 @@ export class Select { /** * Alternative placement for popover if the default placement is not possible. */ - @Prop() fallbackPlacements: [PopoverPlacementType] = ['bottom']; + @Prop() fallbackPlacements: [PopoverPlacementType] = ['top']; /** * The variant of tag to be used. */ @@ -994,7 +994,7 @@ export class Select { distance='8' trigger='manual' ref={(popoverRef) => (this.popoverRef = popoverRef)} - same-width={this.sameWidth} + sameWidth={this.sameWidth} placement={this.optionsPlacement} fallbackPlacements={this.fallbackPlacements} boundary={this.boundary}