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(input-time-zone): add offsetStyle prop #9426

Merged
merged 40 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
451f3fa
feat(input-time-zone): add offsetStyle prop
jcfranco May 25, 2024
19edc90
add tests
jcfranco Jun 21, 2024
7374723
tidy up
jcfranco Jun 21, 2024
aa065cd
merge dev
jcfranco Jun 21, 2024
52fb107
recreate components.d.ts
jcfranco Jun 21, 2024
44f7876
filter tests for CI debuggging
jcfranco Jun 24, 2024
812df92
handle error logs for better debug messages
jcfranco Jun 24, 2024
439c572
merge dev
jcfranco Jun 24, 2024
62a802e
improve jshandle error message check
jcfranco Jun 24, 2024
66426ff
skip newly added test time zones
jcfranco Jun 24, 2024
24db245
tweak global error tracking
jcfranco Jun 24, 2024
556bdf4
clear test locales for debugging
jcfranco Jun 24, 2024
bb96e99
remove lang for testing
jcfranco Jun 24, 2024
635b1f9
skip custom error handling for debugging
jcfranco Jun 24, 2024
8e51aa0
restore offsetStyle tests
jcfranco Jun 24, 2024
0b2b719
tidy up
jcfranco Jun 24, 2024
daa6b3c
test failing assertion
jcfranco Jun 24, 2024
999ad14
restore global error checking
jcfranco Jun 24, 2024
59210d2
restore assertion
jcfranco Jun 24, 2024
ce96130
remove test filter for debugging
jcfranco Jun 24, 2024
7970206
filter tests for CI debuggging
jcfranco Jun 24, 2024
389f37c
add custom error logging
jcfranco Jun 24, 2024
24ba79e
only offsetStyle
jcfranco Jun 24, 2024
9fc77bd
omit one lang change for testing
jcfranco Jun 25, 2024
03aa5eb
remove all lang again
jcfranco Jun 25, 2024
93528cc
skip assertions
jcfranco Jun 25, 2024
659a556
skip assertions
jcfranco Jun 25, 2024
63514ca
remove custom error logging and restore all but one langs
jcfranco Jun 25, 2024
e1a3caf
skip assertions
jcfranco Jun 25, 2024
6973413
restore assertions, remove langs
jcfranco Jun 25, 2024
2eaa4d9
remove unused vars
jcfranco Jun 25, 2024
3e569e5
restore offsetStyle tests and skip to test others
jcfranco Jun 25, 2024
5da7580
restore single offsetStyle test
jcfranco Jun 25, 2024
396ef09
remove offsetStyle skip
jcfranco Jun 25, 2024
502e597
test invalid assertion
jcfranco Jun 25, 2024
7b1cf5d
add dummy assertion to sniff out error
jcfranco Jun 25, 2024
d74e6c4
restore assertion and add emulated time zone
jcfranco Jun 25, 2024
28a401b
ensure time zone is emulated for all tests and restore offsetStyle tests
jcfranco Jun 25, 2024
b58de84
remove test filter
jcfranco Jun 25, 2024
576e5b5
tidy up
jcfranco Jun 25, 2024
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
14 changes: 12 additions & 2 deletions packages/calcite-components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import { InputTextMessages } from "./components/input-text/assets/input-text/t9n
import { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n";
import { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n";
import { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n";
import { TimeZoneMode } from "./components/input-time-zone/interfaces";
import { OffsetStyle, TimeZoneMode } from "./components/input-time-zone/interfaces";
import { ListDragDetail } from "./components/list/interfaces";
import { ItemData } from "./components/list-item/interfaces";
import { ListMessages } from "./components/list/assets/list/t9n";
Expand Down Expand Up @@ -144,7 +144,7 @@ export { InputTextMessages } from "./components/input-text/assets/input-text/t9n
export { InputTimePickerMessages } from "./components/input-time-picker/assets/input-time-picker/t9n";
export { TimePickerMessages } from "./components/time-picker/assets/time-picker/t9n";
export { InputTimeZoneMessages } from "./components/input-time-zone/assets/input-time-zone/t9n";
export { TimeZoneMode } from "./components/input-time-zone/interfaces";
export { OffsetStyle, TimeZoneMode } from "./components/input-time-zone/interfaces";
export { ListDragDetail } from "./components/list/interfaces";
export { ItemData } from "./components/list-item/interfaces";
export { ListMessages } from "./components/list/assets/list/t9n";
Expand Down Expand Up @@ -2844,6 +2844,11 @@ export namespace Components {
* Specifies the name of the component. Required to pass the component's `value` on form submission.
*/
"name": string;
/**
* Specifies how the offset will be displayed, where `"user"` uses `UTC` or `GMT` depending on the user's locale, `"gmt"` always uses `GMT`, and `"utc"` always uses `UTC`. This only applies to the `offset` mode.
* @default "user"
*/
"offsetStyle": OffsetStyle;
/**
* When `true`, displays and positions the component.
*/
Expand Down Expand Up @@ -10714,6 +10719,11 @@ declare namespace LocalJSX {
* Specifies the name of the component. Required to pass the component's `value` on form submission.
*/
"name"?: string;
/**
* Specifies how the offset will be displayed, where `"user"` uses `UTC` or `GMT` depending on the user's locale, `"gmt"` always uses `GMT`, and `"utc"` always uses `UTC`. This only applies to the `offset` mode.
* @default "user"
*/
"offsetStyle"?: OffsetStyle;
/**
* Fires when the component is requested to be closed and before the closing transition begins.
*/
Expand Down
4 changes: 2 additions & 2 deletions packages/calcite-components/src/components/alert/alert.scss
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ $border-style: 1px solid var(--calcite-color-border-3);
inset-block-start: -2px;
block-size: 2px;
border-radius: var(--calcite-border-radius) var(--calcite-border-radius) 0 0;
&:after {
&::after {
@apply absolute
top-0
block;
Expand Down Expand Up @@ -299,7 +299,7 @@ $alertDurations:
}
}

.container.focused .dismiss-progress:after {
.container.focused .dismiss-progress::after {
jcfranco marked this conversation as resolved.
Show resolved Hide resolved
animation-play-state: paused;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,66 @@ describe("calcite-input-time-zone", () => {
currComboboxItem = await page.find("calcite-input-time-zone >>> calcite-combobox-item");
expect(currComboboxItem).not.toBe(prevComboboxItem);
});

describe("offsetStyle", () => {
const gmtTimeZoneLocale = "en-GB";
const utcTimeZoneLocale = "fr";

let page: E2EPage;

async function assertItemLabelMatches(page: E2EPage, offsetMarker: "GMT" | "UTC"): Promise<void> {
// all items are formatted equally, so we only need to check the first one
const firstTimeZoneItem = await page.find("calcite-input-time-zone >>> calcite-combobox-item");

expect(await firstTimeZoneItem.getProperty("textLabel")).toContain(offsetMarker);
}

beforeEach(async () => {
page = await newE2EPage();
});

describe("displays UTC or GMT based on user's locale (default)", () => {
it("displays GMT for GMT-preferred zone", async () => {
await page.setContent(
addTimeZoneNamePolyfill(
html`<calcite-input-time-zone lang="${gmtTimeZoneLocale}"></calcite-input-time-zone>`,
),
);

await assertItemLabelMatches(page, "GMT");
});

it("displays UTC for UTC-preferred zone", async () => {
await page.setContent(
addTimeZoneNamePolyfill(
html`<calcite-input-time-zone lang="${utcTimeZoneLocale}"></calcite-input-time-zone>`,
),
);

await assertItemLabelMatches(page, "UTC");
});
});

it("supports GMT as a style", async () => {
await page.setContent(
addTimeZoneNamePolyfill(
html`<calcite-input-time-zone lang="${utcTimeZoneLocale}" offset-style="gmt"></calcite-input-time-zone>`,
),
);

await assertItemLabelMatches(page, "GMT");
});

it("supports UTC as a style", async () => {
await page.setContent(
addTimeZoneNamePolyfill(
html`<calcite-input-time-zone lang="${gmtTimeZoneLocale}" offset-style="utc"></calcite-input-time-zone>`,
),
);

await assertItemLabelMatches(page, "UTC");
});
});
});

/**
Expand All @@ -519,6 +579,8 @@ function addTimeZoneNamePolyfill(testHtml: string): string {

if (timeZoneName === "shortOffset") {
const { timeZone } = this.originalOptions;
const resolved = this.resolvedOptions();

let offsetString;

// hardcoding GMT and time zone names for this particular test suite
Expand All @@ -532,15 +594,21 @@ function addTimeZoneNamePolyfill(testHtml: string): string {
offsetString = offsetString.replace("-", "+");
}
} else {
const offsetMarker = resolved.locale === "en-GB" ? "GMT" : resolved.locale === "fr" ? "UTC" : "GMT";

offsetString =
"GMT" +
offsetMarker +
(timeZone === "America/Mexico_City" || timeZone === "Pacific/Galapagos"
? "-6"
: timeZone === "America/Phoenix"
? "-7"
: timeZone === "Pacific/Guam" || timeZone === "Pacific/Chuuk"
? "+10"
: "+0");
: timeZone === "Europe/London"
? "+1"
: timeZone === "Europe/Paris"
? "+2"
: timeZone === "Pacific/Guam" || timeZone === "Pacific/Chuuk"
? "+10"
: "+0");
}

originalParts.push({ type: "timeZoneName", value: offsetString });
Expand Down Expand Up @@ -571,6 +639,8 @@ function addTimeZoneNamePolyfill(testHtml: string): string {
return [
"America/Mexico_City",
"America/Phoenix",
"Europe/London",
"Europe/Paris",
"Pacific/Galapagos",
"Pacific/Guam",

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import {
getUserTimeZoneOffset,
} from "./utils";
import { InputTimeZoneMessages } from "./assets/input-time-zone/t9n";
import { TimeZoneItem, TimeZoneMode } from "./interfaces";
import { OffsetStyle, TimeZoneItem, TimeZoneMode } from "./interfaces";

@Component({
tag: "calcite-input-time-zone",
Expand Down Expand Up @@ -137,6 +137,19 @@ export class InputTimeZone
this.updateTimeZoneItemsAndSelection();
}

/**
* Specifies how the offset will be displayed, where
*
* `"user"` uses `UTC` or `GMT` depending on the user's locale,
* `"gmt"` always uses `GMT`, and
* `"utc"` always uses `UTC`.
*
* This only applies to the `offset` mode.
*
* @default "user"
*/
@Prop({ reflect: true }) offsetStyle: OffsetStyle = "user";

/** Specifies the validation message to display under the component. */
@Prop() validationMessage: string;

Expand Down Expand Up @@ -408,6 +421,7 @@ export class InputTimeZone
this.referenceDate instanceof Date
? this.referenceDate
: new Date(this.referenceDate ?? Date.now()),
this.offsetStyle,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export interface TimeZoneItem<T extends number | string = number | string> {
value: T;
filterValue: string | string[];
}

export type OffsetStyle = "user" | "utc" | "gmt";
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getDateTimeFormat, SupportedLocale } from "../../utils/locale";
import { TimeZoneItem, TimeZoneMode, TimeZoneName } from "./interfaces";
import { OffsetStyle, TimeZoneItem, TimeZoneMode, TimeZoneName } from "./interfaces";
import { InputTimeZoneMessages } from "./assets/input-time-zone/t9n";

const hourToMinutes = 60;
Expand Down Expand Up @@ -66,6 +66,7 @@ export async function createTimeZoneItems(
messages: InputTimeZoneMessages,
mode: TimeZoneMode,
referenceDate: Date,
standardTime: OffsetStyle,
): Promise<TimeZoneItem[]> {
const referenceDateInMs: number = referenceDate.getTime();
const timeZoneNames = Intl.supportedValuesOf("timeZone");
Expand Down Expand Up @@ -106,10 +107,20 @@ export async function createTimeZoneItems(
.filter((index) => index >= 0 && index < group.tzs.length);
});

const effectiveLocale =
standardTime === "user"
? locale
: // we use locales that will always yield a short offset that matches `standardTime`
standardTime === "utc"
? "fr"
: "en-GB";

return timeZoneGroups
.map<TimeZoneItem<number>>(({ labelTzIndices, tzs }) => {
const groupRepTz = tzs[0];
const decimalOffset = timeZoneOffsetToDecimal(getTimeZoneShortOffset(groupRepTz, locale, referenceDateInMs));
const decimalOffset = timeZoneOffsetToDecimal(
getTimeZoneShortOffset(groupRepTz, effectiveLocale, referenceDateInMs),
);
const value = toOffsetValue(groupRepTz, referenceDateInMs);
const tzLabels = labelTzIndices.map((index: number) => {
const timeZone = tzs[index];
Expand Down
18 changes: 9 additions & 9 deletions packages/calcite-components/src/components/link/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ You can programmatically focus a `calcite-link` with the `setFocus()` method:

## Properties

| Property | Attribute | Description | Type | Default |
| ------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ----------- |
| `disabled` | `disabled` | When `true`, interaction is prevented and the component is displayed with lower opacity. | `boolean` | `false` |
| Property | Attribute | Description | Type | Default |
| ------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ----------- |
| `disabled` | `disabled` | When `true`, interaction is prevented and the component is displayed with lower opacity. | `boolean` | `false` |
| `download` | `download` | Prompts the user to save the linked URL instead of navigating to it. Can be used with or without a value: Without a value, the browser will suggest a filename/extension See <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-download>. | `boolean \| string` | `false` |
| `href` | `href` | Specifies the URL of the linked resource, which can be set as an absolute or relative path. | `string` | `undefined` |
| `iconEnd` | `icon-end` | Specifies an icon to display at the end of the component. | `string` | `undefined` |
| `iconFlipRtl` | `icon-flip-rtl` | Displays the `iconStart` and/or `iconEnd` as flipped when the element direction is right-to-left (`"rtl"`). | `"both" \| "end" \| "start"` | `undefined` |
| `iconStart` | `icon-start` | Specifies an icon to display at the start of the component. | `string` | `undefined` |
| `rel` | `rel` | Specifies the relationship to the linked document defined in `href`. | `string` | `undefined` |
| `target` | `target` | Specifies the frame or window to open the linked document. | `string` | `undefined` |
| `href` | `href` | Specifies the URL of the linked resource, which can be set as an absolute or relative path. | `string` | `undefined` |
| `iconEnd` | `icon-end` | Specifies an icon to display at the end of the component. | `string` | `undefined` |
| `iconFlipRtl` | `icon-flip-rtl` | Displays the `iconStart` and/or `iconEnd` as flipped when the element direction is right-to-left (`"rtl"`). | `"both" \| "end" \| "start"` | `undefined` |
| `iconStart` | `icon-start` | Specifies an icon to display at the start of the component. | `string` | `undefined` |
| `rel` | `rel` | Specifies the relationship to the linked document defined in `href`. | `string` | `undefined` |
| `target` | `target` | Specifies the frame or window to open the linked document. | `string` | `undefined` |

## Methods

Expand Down
Loading