Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(form-field-time-zone-picker) - addition of form-field-time-zone-picker component #2

Merged
merged 1 commit into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
- [gux-form-field-dropdown](../../stable/gux-form-field/components/gux-form-field-dropdown)
- [gux-form-field-phone](../../stable/gux-form-field/components/gux-form-field-phone)
- [gux-form-field-time-picker](../../stable/gux-form-field/components/gux-form-field-time-picker)
- [gux-form-field-time-zone-picker](../../stable/gux-form-field/components/gux-form-field-time-zone-picker)

### Graph
```mermaid
graph TD;
gux-form-field-dropdown --> gux-screen-reader-beta
gux-form-field-phone --> gux-screen-reader-beta
gux-form-field-time-picker --> gux-screen-reader-beta
gux-form-field-time-zone-picker --> gux-screen-reader-beta
style gux-screen-reader-beta fill:#f9f,stroke:#333,stroke-width:4px
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export class GuxTimeZonePickerBeta {
@Prop()
public localDefault: string;

@Prop()
hasError: boolean = false;

@Prop()
disabled: boolean = false;

@Prop()
required: boolean = false;

@State()
private searchString: string = '';

Expand Down Expand Up @@ -232,6 +241,8 @@ export class GuxTimeZonePickerBeta {
filter-type="custom"
placeholder={this.i18n('selectZone')}
value={this.value}
hasError={this.hasError}
disabled={this.disabled}
>
<gux-listbox aria-label={this.i18n('timeZones')}>
{this.renderDefaultsList()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

## Properties

| Property | Attribute | Description | Type | Default |
| ------------------ | ------------------- | ----------- | -------- | ----------- |
| `localDefault` | `local-default` | | `string` | `undefined` |
| `value` | `value` | | `string` | `undefined` |
| `workspaceDefault` | `workspace-default` | | `string` | `undefined` |
| Property | Attribute | Description | Type | Default |
| ------------------ | ------------------- | ----------- | --------- | ----------- |
| `disabled` | `disabled` | | `boolean` | `false` |
| `hasError` | `has-error` | | `boolean` | `false` |
| `localDefault` | `local-default` | | `string` | `undefined` |
| `required` | `required` | | `boolean` | `false` |
| `value` | `value` | | `string` | `undefined` |
| `workspaceDefault` | `workspace-default` | | `string` | `undefined` |


## Dependencies
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<h1>gux-form-field-time-zone-picker</h1>

<p>
slot a gux-time-zone-picker-beta element into a
gux-form-field-time-zone-picker element
</p>

<h2>Examples</h2>
<form onchange="notify(event)" oninput="notify(event)">
<fieldset>
<legend>Label Above</legend>
<gux-form-field-time-zone-picker label-position="above">
<gux-time-zone-picker-beta
Copy link
Collaborator

@jason-evans-genesys jason-evans-genesys Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gavin-everett-genesys could we have just 1 component instead of 2 for the time zone picker logic, since gux-time-zone-picker-beta is always going to be the child of gux-form-field-time-zone-picker? What's the reasoning behind having 2 separate components?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could bring this up in standup, but I think the form-field acts as a wrapper which includes the different states like error, required etc.

value="Etc/GMT+1"
workspace-default="Etc/GMT"
local-default="America/Detroit"
>
</gux-time-zone-picker-beta>
<label slot="label">Select Time Zone</label>
</gux-form-field-time-zone-picker>
</fieldset>

<fieldset>
<legend>Disabled</legend>
<gux-form-field-time-zone-picker label-position="above">
<gux-time-zone-picker-beta
disabled
value="Etc/GMT+1"
workspace-default="Etc/GMT"
local-default="America/Detroit"
>
</gux-time-zone-picker-beta>
<label slot="label">Select Time Zone</label>
</gux-form-field-time-zone-picker>
</fieldset>

<fieldset>
<legend>Error</legend>
<gux-form-field-time-zone-picker label-position="above">
<gux-time-zone-picker-beta
value="Etc/GMT+1"
workspace-default="Etc/GMT"
local-default="America/Detroit"
>
</gux-time-zone-picker-beta>
<label slot="label">Select Time Zone</label>
<span slot="error">This is an error message</span>
</gux-form-field-time-zone-picker>
</fieldset>
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@use '../../../../../style/typography.scss';
@use '../../functional-components/gux-form-field-fieldset-container/gux-form-field-fieldset-container.scss';
@use '../../functional-components/gux-form-field-error/gux-form-field-error.scss';
@use '../../functional-components/gux-form-field-legend-label/gux-form-field-legend-label.scss';
@use '../../functional-components/gux-form-field-help/gux-form-field-help.scss';

@include gux-form-field-fieldset-container.Style;
@include gux-form-field-error.Style;
@include gux-form-field-legend-label.Style;
@include gux-form-field-help.Style;

::slotted(label) {
@include typography.gse-ui-formControl-label;
}

.gux-input-and-error-container {
flex-grow: 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { Component, Element, h, JSX, Prop, State, Watch } from '@stencil/core';

import { buildI18nForComponent, GetI18nValue } from '../../../../../i18n';
import { ILocalizedComponentResources } from '../../../../../i18n/fetchResources';
import { OnMutation } from '@utils/decorator/on-mutation';
import {
onDisabledChange,
onRequiredChange
} from '@utils/dom/on-attribute-change';
import { hasSlot } from '@utils/dom/has-slot';
import { getSlotTextContent } from '@utils/dom/get-slot-text-content';

import {
GuxFormFieldHelp,
GuxFormFieldError,
GuxFormFieldFieldsetContainer,
GuxFormFieldLegendLabel
} from '../../functional-components/functional-components';

import { GuxFormFieldLabelPosition } from '../../gux-form-field.types';
import {
getComputedLabelPosition,
validateFormIds
} from '../../gux-form-field.service';
import { trackComponent } from '@utils/tracking/usage';
import componentResources from './i18n/en.json';

/**
* @slot Required slot for gux-time-zone-picker-beta tag
* @slot label - Required slot for label tag
* @slot error - Optional slot for error message
* @slot help - Optional slot for help message
*/
@Component({
styleUrl: 'gux-form-field-time-zone-picker.scss',
tag: 'gux-form-field-time-zone-picker',
shadow: true
})
export class GuxFormFieldTimeZonePicker {
private getI18nValue: GetI18nValue;
private timeZonePickerElement: HTMLGuxTimeZonePickerBetaElement;
private label: HTMLLabelElement;
private disabledObserver: MutationObserver;
private requiredObserver: MutationObserver;

@Element()
private root: HTMLElement;

@Prop()
labelPosition: GuxFormFieldLabelPosition;

@State()
private computedLabelPosition: GuxFormFieldLabelPosition = 'above';

@State()
private disabled: boolean;

@State()
private required: boolean;

@State()
private hasError: boolean = false;

@State()
private hasHelp: boolean = false;

@Watch('hasError')
watchValue(hasError: boolean): void {
const timeZonePickerSlot = this.root.querySelector(
'gux-time-zone-picker-beta'
);
if (timeZonePickerSlot) {
timeZonePickerSlot.hasError = hasError;
}
}

@OnMutation({ childList: true, subtree: true })
onMutation(): void {
this.hasError = hasSlot(this.root, 'error');
this.hasHelp = hasSlot(this.root, 'help');
}

async componentWillLoad(): Promise<void> {
this.getI18nValue = await buildI18nForComponent(
this.root,
componentResources as ILocalizedComponentResources
);

this.setInput();
this.setLabel();

this.hasError = hasSlot(this.root, 'error');
this.hasHelp = hasSlot(this.root, 'help');

trackComponent(this.root, { variant: this.variant });
}

disconnectedCallback(): void {
if (this.disabledObserver) {
this.disabledObserver.disconnect();
}
if (this.requiredObserver) {
this.requiredObserver.disconnect();
}
}

render(): JSX.Element {
return (
<GuxFormFieldFieldsetContainer labelPosition={this.computedLabelPosition}>
<GuxFormFieldLegendLabel
position={this.computedLabelPosition}
required={this.required}
>
<slot name="label" onSlotchange={() => this.setLabel()} />
{this.renderScreenReaderText(
this.getI18nValue('required'),
this.required
)}
{this.renderScreenReaderText(
getSlotTextContent(this.root, 'error'),
this.hasError
)}
</GuxFormFieldLegendLabel>
<div class="gux-input-and-error-container">
<div
class={{
'gux-input': true,
'gux-input-error': this.hasError,
'gux-time-zone-picker-container': true,
'gux-disabled': this.disabled
}}
>
<slot />
</div>
<GuxFormFieldError show={this.hasError}>
<slot name="error" />
</GuxFormFieldError>
<GuxFormFieldHelp show={!this.hasError && this.hasHelp}>
<slot name="help" />
</GuxFormFieldHelp>
</div>
</GuxFormFieldFieldsetContainer>
) as JSX.Element;
}

private renderScreenReaderText(
text: string,
condition: boolean = true
): JSX.Element {
if (condition) {
return (
<gux-screen-reader-beta>{text}</gux-screen-reader-beta>
) as JSX.Element;
}
}

private get variant(): string {
const labelPositionVariant = this.labelPosition
? this.labelPosition.toLowerCase()
: 'none';

const type = 'timeZonePicker';

return `${type}-${labelPositionVariant}`;
}

private setInput(): void {
this.timeZonePickerElement = this.root.querySelector(
'gux-time-zone-picker-beta'
);

this.disabled = this.timeZonePickerElement.disabled;
this.required = this.timeZonePickerElement.required;

this.disabledObserver = onDisabledChange(
this.timeZonePickerElement,
(disabled: boolean) => {
this.disabled = disabled;
}
);
this.requiredObserver = onRequiredChange(
this.timeZonePickerElement,
(required: boolean) => {
this.required = required;
}
);

validateFormIds(this.root, this.timeZonePickerElement);
}

private setLabel(): void {
this.label = this.root.querySelector('label[slot="label"]');

this.computedLabelPosition = getComputedLabelPosition(
this.label,
this.labelPosition
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"required": "Required"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# gux-form-field-time-zone-picker



<!-- Auto Generated Below -->


## Properties

| Property | Attribute | Description | Type | Default |
| --------------- | ---------------- | ----------- | --------------------------------------- | ----------- |
| `labelPosition` | `label-position` | | `"above" \| "beside" \| "screenreader"` | `undefined` |


## Slots

| Slot | Description |
| --------------------------------------------------- | ------------------------------- |
| `"Required slot for gux-time-zone-picker-beta tag"` | |
| `"error"` | Optional slot for error message |
| `"help"` | Optional slot for help message |
| `"label"` | Required slot for label tag |


## Dependencies

### Depends on

- [gux-screen-reader-beta](../../../../beta/gux-screen-reader)
- [gux-icon](../../../gux-icon)

### Graph
```mermaid
graph TD;
gux-form-field-time-zone-picker --> gux-screen-reader-beta
gux-form-field-time-zone-picker --> gux-icon
style gux-form-field-time-zone-picker fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
Loading
Loading