From ede43e39019e08c10f713ab0cce4b09e569c45c7 Mon Sep 17 00:00:00 2001 From: Adam Dierkens Date: Wed, 29 Jul 2026 17:11:08 -0400 Subject: [PATCH 1/5] refactor: reimplement RelativeTime in React Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: bfa22b31-cbe2-4b07-8add-f302af4c1a2b --- .changeset/react-first-relative-time.md | 5 + package-lock.json | 7 - packages/react/package.json | 1 - .../src/RelativeTime/RelativeTime.docs.json | 37 +- .../RelativeTime.features.stories.tsx | 4 +- .../src/RelativeTime/RelativeTime.stories.tsx | 4 +- .../src/RelativeTime/RelativeTime.test.tsx | 119 ++++-- .../react/src/RelativeTime/RelativeTime.tsx | 368 +++++++++++++++++- 8 files changed, 462 insertions(+), 83 deletions(-) create mode 100644 .changeset/react-first-relative-time.md diff --git a/.changeset/react-first-relative-time.md b/.changeset/react-first-relative-time.md new file mode 100644 index 00000000000..9b7188426e2 --- /dev/null +++ b/.changeset/react-first-relative-time.md @@ -0,0 +1,5 @@ +--- +'@primer/react': major +--- + +RelativeTime: Render a native time element without the custom-element dependency. The custom-element lifecycle, `update`, and `as` props are no longer supported. diff --git a/package-lock.json b/package-lock.json index 4ccd4102b8a..13097d8eb1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3907,12 +3907,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@github/relative-time-element": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-5.0.0.tgz", - "integrity": "sha512-L/2r0DNR/rMbmHWcsdmhtOiy2gESoGOhItNFD4zJ3nZfHl79Dx3N18Vfx/pYr2lruMOdk1cJZb4wEumm+Dxm1w==", - "license": "MIT" - }, "node_modules/@hono/node-server": { "version": "1.19.14", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", @@ -28776,7 +28770,6 @@ "license": "MIT", "dependencies": { "@github/mini-throttle": "^2.1.1", - "@github/relative-time-element": "^5.0.0", "@lit-labs/react": "1.2.1", "@oddbird/popover-polyfill": "^0.5.2", "@primer/behaviors": "^1.10.3", diff --git a/packages/react/package.json b/packages/react/package.json index 506a3edd147..06aab72a449 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -76,7 +76,6 @@ }, "dependencies": { "@github/mini-throttle": "^2.1.1", - "@github/relative-time-element": "^5.0.0", "@lit-labs/react": "1.2.1", "@oddbird/popover-polyfill": "^0.5.2", "@primer/behaviors": "^1.10.3", diff --git a/packages/react/src/RelativeTime/RelativeTime.docs.json b/packages/react/src/RelativeTime/RelativeTime.docs.json index 3e373c44e11..ece20b9dbab 100644 --- a/packages/react/src/RelativeTime/RelativeTime.docs.json +++ b/packages/react/src/RelativeTime/RelativeTime.docs.json @@ -23,18 +23,18 @@ "name": "datetime", "type": "string", "defaultValue": "", - "required": true, + "required": false, "description": "An ISO8601 time representing the time" }, { "name": "date", - "type": "string", + "type": "Date", "defaultValue": "", "description": "Instead of passing the `datetime`, it is possible to pass a full `Date` object into the `date` prop" }, { "name": "format", - "type": "'auto' | 'micro' | 'elapsed'", + "type": "'auto' | 'datetime' | 'duration' | 'elapsed' | 'micro' | 'relative'", "defaultValue": "'auto'", "description": "The format with which to display the time" }, @@ -110,44 +110,17 @@ "defaultValue": "", "description": "The format with which to render the time zone" }, - { - "name": "ref", - "type": "React.RefObject" - }, { "name": "noTitle", "type": "boolean", "defaultValue": "", "description": "Removes the `title` attribute provided on the element by default" }, - { - "name": "attributeChangedCallback", - "type": "(attrName: string, oldValue: unknown, newValue: unknown) => void", - "description": "", - "defaultValue": "" - }, - { - "name": "connectedCallback", - "type": "() => void", - "description": "", - "defaultValue": "" - }, { "name": "onRelativeTimeUpdated", - "type": "null | (event: RelativeTimeUpdatedEvent) => void", - "description": "", + "type": "(event: RelativeTimeUpdatedEvent) => void", + "description": "Called after the rendered time text or title changes", "defaultValue": "" - }, - { - "name": "update", - "type": "() => void", - "description": "", - "defaultValue": "" - }, - { - "name": "as", - "type": "React.ElementType", - "defaultValue": "\"relative-time\"" } ], "subcomponents": [] diff --git a/packages/react/src/RelativeTime/RelativeTime.features.stories.tsx b/packages/react/src/RelativeTime/RelativeTime.features.stories.tsx index c9ecb5a24e4..71a36255f41 100644 --- a/packages/react/src/RelativeTime/RelativeTime.features.stories.tsx +++ b/packages/react/src/RelativeTime/RelativeTime.features.stories.tsx @@ -7,9 +7,7 @@ const meta: Meta = { parameters: { layout: 'fullscreen', controls: { - // StoryBook infers from type info of the component which includes CE Lifecycle, - // SX props, and methods we want to otherwise ignore - exclude: /^(getFormatted.*|datetime|as|theme|forwardedAs|.*Callback|update)$/g, + exclude: /^(datetime|theme|forwardedAs|onRelativeTimeUpdated)$/g, }, }, args: { diff --git a/packages/react/src/RelativeTime/RelativeTime.stories.tsx b/packages/react/src/RelativeTime/RelativeTime.stories.tsx index b5241465cd2..8d1712f95f1 100644 --- a/packages/react/src/RelativeTime/RelativeTime.stories.tsx +++ b/packages/react/src/RelativeTime/RelativeTime.stories.tsx @@ -7,9 +7,7 @@ const meta: Meta = { parameters: { layout: 'fullscreen', controls: { - // StoryBook infers from type info of the component which includes CE Lifecycle, - // SX props, and methods we want to otherwise ignore - exclude: /^(getFormatted.*|datetime|as|theme|forwardedAs|.*Callback|update)$/g, + exclude: /^(datetime|theme|forwardedAs|onRelativeTimeUpdated)$/g, }, }, } diff --git a/packages/react/src/RelativeTime/RelativeTime.test.tsx b/packages/react/src/RelativeTime/RelativeTime.test.tsx index ba9f48430f5..0b32982a094 100644 --- a/packages/react/src/RelativeTime/RelativeTime.test.tsx +++ b/packages/react/src/RelativeTime/RelativeTime.test.tsx @@ -1,49 +1,118 @@ -import {describe, expect, it} from 'vitest' +import {act, render} from '@testing-library/react' +import {renderToString} from 'react-dom/server' +import {afterEach, describe, expect, it, vi} from 'vitest' import RelativeTime from '.' -import {render} from '@testing-library/react' import {implementsClassName} from '../utils/testing' describe('RelativeTime', () => { + afterEach(() => { + vi.useRealTimers() + }) + implementsClassName(RelativeTime) - it('renders a ', () => { + + it('renders a