Skip to content

Commit 990e153

Browse files
committed
fix: fix build and add release notes
1 parent a547874 commit 990e153

6 files changed

Lines changed: 284 additions & 21 deletions

File tree

.czrc

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"path": "cz-conventional-changelog",
3-
"types": [
4-
{ "value": "feat", "name": "feat: A new feature" },
5-
{ "value": "fix", "name": "fix: A bug fix" },
6-
{ "value": "docs", "name": "docs: Documentation only changes" },
7-
{ "value": "style", "name": "style: Formatting, missing semi-colons, etc; no logic change" },
8-
{ "value": "refactor", "name": "refactor: A code change that is neither a bug fix nor a new feature" },
9-
{ "value": "perf", "name": "perf: A code change that improves performance" },
10-
{ "value": "test", "name": "test: Adding missing or correcting existing tests" },
11-
{ "value": "chore", "name": "chore: Changes to the build process or auxiliary tools" },
12-
{ "value": "revert", "name": "revert: Revert to a commit" },
13-
{ "value": "ci", "name": "ci: Changes to CI configuration files and scripts" },
14-
{ "value": "vercel", "name": "vercel: Vercel deployment configuration" }
15-
]
3+
"types": {
4+
"feat": { "description": "A new feature", "title": "Features" },
5+
"fix": { "description": "A bug fix", "title": "Bug Fixes" },
6+
"docs": { "description": "Documentation only changes", "title": "Documentation" },
7+
"style": { "description": "Formatting, missing semi-colons, etc; no logic change", "title": "Styles" },
8+
"refactor": { "description": "A code change that is neither a bug fix nor a new feature", "title": "Code Refactoring" },
9+
"perf": { "description": "A code change that improves performance", "title": "Performance Improvements" },
10+
"test": { "description": "Adding missing or correcting existing tests", "title": "Tests" },
11+
"chore": { "description": "Changes to the build process or auxiliary tools", "title": "Chores" },
12+
"revert": { "description": "Revert to a commit", "title": "Reverts" },
13+
"ci": { "description": "Changes to CI configuration files and scripts", "title": "Continuous Integration" },
14+
"vercel": { "description": "Vercel deployment configuration", "title": "Vercel" }
15+
}
1616
}

CEDAR-17-RELEASE-NOTES.md

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
# Cedar 17
2+
3+
TypeScript types for all components, tree-shakeable per-component entrypoints, Vue 3 script-setup migration, Storybook, and a modernized toolchain.
4+
5+
## Update steps
6+
7+
| package name | version |
8+
|---|---|
9+
| `@rei/cedar` | ^17.x.x |
10+
11+
> **Node.js requirement raised:** Cedar 17 requires **Node.js >= 22**. Node 20 is no longer supported.
12+
13+
---
14+
15+
## New features
16+
17+
### TypeScript types for every component
18+
19+
Every Cedar component now ships a `types.ts` that exports a fully-typed `Props` interface. Types are re-exported from each component's individual entrypoint and from the main package entry:
20+
21+
```ts
22+
import type { CdrButtonProps, CdrInputProps, CdrModalProps } from '@rei/cedar';
23+
```
24+
25+
This enables autocomplete, inline prop documentation, and compile-time safety in TypeScript projects with no additional setup. Examples of the new interfaces:
26+
27+
```ts
28+
import type { CdrAccordionProps } from '@rei/cedar/accordion';
29+
import type { CdrInputProps } from '@rei/cedar/input';
30+
import type { CdrModalProps } from '@rei/cedar/modal';
31+
32+
// Use them to type your own wrapper components or composables
33+
const modalProps: CdrModalProps = {
34+
opened: true,
35+
label: 'Confirm action',
36+
role: 'alertdialog',
37+
};
38+
```
39+
40+
### Per-component tree-shakeable entrypoints
41+
42+
76 dedicated entrypoints have been added under `@rei/cedar/<component-name>`, one per component and one per text preset. Bundlers (Vite, Rollup, Webpack 5) can now eliminate every Cedar component your project does not use.
43+
44+
**Recommended usage — import only what you need:**
45+
46+
```ts
47+
import { CdrButton } from '@rei/cedar/button';
48+
import { CdrInput } from '@rei/cedar/input';
49+
import { CdrModal } from '@rei/cedar/modal';
50+
import { CdrAccordion } from '@rei/cedar/accordion';
51+
import { CdrFilmstrip } from '@rei/cedar/filmstrip';
52+
```
53+
54+
**Types are co-located with the entrypoint:**
55+
56+
```ts
57+
import { CdrButton } from '@rei/cedar/button';
58+
import type { CdrButtonProps } from '@rei/cedar/button';
59+
```
60+
61+
**Text preset entrypoints:**
62+
63+
```ts
64+
import { CdrText } from '@rei/cedar/heading-display';
65+
import { CdrText } from '@rei/cedar/heading-serif';
66+
import { CdrText } from '@rei/cedar/body';
67+
import { CdrText } from '@rei/cedar/utility-sans';
68+
import { CdrText } from '@rei/cedar/eyebrow';
69+
```
70+
71+
**Avoid the barrel import in performance-sensitive contexts:**
72+
73+
```ts
74+
// Before — pulls the entire Cedar bundle
75+
import { CdrButton, CdrInput, CdrModal } from '@rei/cedar';
76+
77+
// After — bundler tree-shakes to only the three components above
78+
import { CdrButton } from '@rei/cedar/button';
79+
import { CdrInput } from '@rei/cedar/input';
80+
import { CdrModal } from '@rei/cedar/modal';
81+
```
82+
83+
The main `@rei/cedar` barrel import remains available and unchanged for projects that prefer it or that rely on a bundler with full tree-shaking already configured.
84+
85+
### New exports added to the main entrypoint
86+
87+
The following components existed in the codebase but were not exported from `@rei/cedar`. They are now fully public and available from both the barrel and their dedicated entrypoints:
88+
89+
| Component | Entrypoint |
90+
|---|---|
91+
| `CdrFormError` | `@rei/cedar/form-error` |
92+
| `CdrLabelStandalone` | `@rei/cedar/label-standalone` |
93+
| `CdrLabelWrapper` | `@rei/cedar/label-wrapper` |
94+
| `CdrPopup` | `@rei/cedar/popup` |
95+
| `CdrFilmstripEngine` | `@rei/cedar/filmstrip-engine` |
96+
97+
### Storybook
98+
99+
`storybook` ^8.6 with the `@storybook/vue3-vite` builder, accessibility addon, and essentials addon has been added to the project. This provides an interactive development and documentation environment for components, making it easier to explore Cedar components in isolation, test edge cases, and review accessibility directly in the browser.
100+
101+
---
102+
103+
## Vue 3 component migration
104+
105+
35 components have been migrated from the legacy Options API / runtime `defineProps` object syntax to the modern Vue 3 `<script setup>` + TypeScript generic API. This is an internal refactor — the public prop API of each component is unchanged.
106+
107+
**What changed internally:**
108+
109+
```ts
110+
// Before — runtime object syntax with inline JSDoc
111+
const props = defineProps({
112+
modifier: {
113+
type: String,
114+
required: false,
115+
default: 'primary',
116+
validator: (value: string) => propValidator(value, ['primary', 'secondary']),
117+
},
118+
});
119+
120+
// After — TypeScript generic syntax backed by the new types.ts
121+
const props = withDefaults(defineProps<CdrButtonProps>(), {
122+
modifier: 'primary',
123+
});
124+
```
125+
126+
12 components also added `defineSlots<{}>()` typed slot declarations, giving TypeScript consumers slot-level type checking:
127+
128+
```ts
129+
// Example: CdrToast now declares its slots with types
130+
defineSlots<{
131+
/** Icon matching toast messaging type */
132+
'icon-left'(props: Record<string, never>): any;
133+
/** Toast message body */
134+
'default'(props: Record<string, never>): any;
135+
}>();
136+
```
137+
138+
**Migrated components:** `CdrAbstract`, `CdrAccordion`, `CdrAccordionGroup`, `CdrCheckbox`, `CdrFilmstripEngine`, `CdrFulfillmentTile`, `CdrImg`, `CdrInput`, `CdrKicker`, `CdrLink`, `CdrMediaObject`, `CdrModal`, `CdrObjectOverlay`, `CdrPagination`, `CdrPicture`, `CdrPopover`, `CdrRating`, `CdrSelect`, `CdrSplitSurface`, `CdrSurfaceSelection`, `CdrTabs`, `CdrText`, `CdrTitle`, `CdrToast`, `CdrToggleGroup`, `CdrTooltip`, and all 8 text preset components (`CdrBody`, `CdrEyebrow`, `CdrHeadingDisplay`, `CdrHeadingSans`, `CdrHeadingSerif`, `CdrSubheadingSans`, `CdrUtilitySans`, `CdrUtilitySerif`).
139+
140+
---
141+
142+
## Breaking changes
143+
144+
### Node.js minimum version raised to 22
145+
146+
The `engines` field in `package.json` now requires `node >= 22.0.0`. The `npm` engine constraint has been removed in favour of the existing `pnpm` lockfile.
147+
148+
### `tabbable` upgraded from v4 to v6
149+
150+
`tabbable` is a runtime dependency used by the focus-trap logic in `CdrPopover` and `CdrModal`. v6 switched from a default export to named exports:
151+
152+
**Before (tabbable v4)**
153+
```ts
154+
import tabbable from 'tabbable';
155+
tabbable(container);
156+
```
157+
158+
**After (tabbable v6)**
159+
```ts
160+
import { tabbable } from 'tabbable';
161+
tabbable(container);
162+
```
163+
164+
If your project imports `tabbable` directly alongside Cedar, update to the named export.
165+
166+
---
167+
168+
## Bug fixes
169+
170+
### `CdrTabPanel`: removed erroneous `aria-hidden` on active panel
171+
172+
`CdrTabPanel` was setting `:aria-hidden="!isActive"` on the panel element. This caused the active tab panel — which is visible and focusable via `tabindex="0"` — to be simultaneously hidden from the accessibility tree in some states, breaking screen reader navigation. The attribute has been removed; visibility is now controlled exclusively by `v-show`.
173+
174+
### `CdrFilmstripEngine`: resize observer lifecycle fixed
175+
176+
The `useResizeObserver` call was previously initialised inside `onMounted` with its cleanup registered inside `onUnmounted` — also nested inside `onMounted`. This caused the cleanup to never run in certain unmount sequences, leaking the observer. The observer is now initialised at setup time and its stop handle is called directly in `onUnmounted`.
177+
178+
### `CdrPopover`: `aria-controls` now set imperatively on mount
179+
180+
`aria-controls` could be missing from the trigger element in certain slot rendering orders. It is now explicitly applied in `onMounted` to guarantee the attribute is always present regardless of slot timing.
181+
182+
### `CdrLabelStandalone`: removed stray whitespace adjacent to required/optional spans
183+
184+
A template formatting inconsistency caused a stray space character to appear next to the required asterisk and optional label text in some rendering contexts. The template whitespace has been normalised.
185+
186+
### `CdrTabs`: resize and scroll listeners now cleaned up on unmount
187+
188+
`CdrTabs` adds `resize` and `scroll` event listeners on mount. These were not removed on unmount, causing memory leaks when tabs were conditionally rendered. `onUnmounted` now calls `removeEventListener` for both handlers.
189+
190+
---
191+
192+
## Toolchain updates
193+
194+
### ESLint + Prettier replaced by oxlint + oxfmt
195+
196+
| Before | After |
197+
|---|---|
198+
| `eslint` ^8 + `eslint-plugin-vue` + `@typescript-eslint/*` | `oxlint` ^1.50 |
199+
| `prettier` + `eslint-plugin-prettier` | `oxfmt` ^0.35 |
200+
201+
`.eslintrc` and `.prettierrc.json` are removed. Config now lives in `.oxlintrc.json` and `.oxfmtrc.json`. `lint-staged` runs both tools automatically on staged files via the Husky pre-commit hook.
202+
203+
Contributor commands:
204+
205+
```sh
206+
pnpm lint:js # check
207+
pnpm lint:js:fix # auto-fix
208+
pnpm format:check # check formatting
209+
pnpm format # auto-format
210+
```
211+
212+
### Commitizen + commitlint enforced on every commit
213+
214+
Conventional Commits are now enforced at commit time:
215+
216+
- `commitizen` (`cz-conventional-changelog`) is wired to `prepare-commit-msg` via Husky. Running `git commit` launches an interactive prompt.
217+
- `commitlint` validates the final message against `@commitlint/config-conventional`.
218+
219+
```sh
220+
pnpm commit # guided commit wizard
221+
```
222+
223+
Allowed types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`, `revert`, `vercel`.
224+
225+
### Major dependency version bumps
226+
227+
| Package | Before | After |
228+
|---|---|---|
229+
| `vite` | ^5.0 | ^7.3 |
230+
| `vitest` | ^1.1 | ^4.0 |
231+
| `typescript` | 5.6.3 | 5.9.3 |
232+
| `vue-tsc` | 2.1.10 | 3.2.2 |
233+
| `vite-plugin-dts` | ^3.3 | ^4.5 |
234+
| `@vitejs/plugin-vue` | ^4 | ^6 |
235+
| `husky` | ^4 | ^9 |
236+
| `@playwright/test` | ^1.49 | ^1.57 |
237+
| `@vue/test-utils` | ^2.2 | ^2.4 |
238+
| `sass` | ^1.9 | ^1.97 |
239+
| `stylelint` | ^16.10 | ^16.26 |
240+
| `postcss` | ^8.4 | ^8.5 |
241+
| `jsdom` | ^16 | ^27 |
242+
| `sinon` | ^11 | ^21 |
243+
| `fs-extra` | ^10 | ^11 |
244+
| `glob` | ^7 | ^13 |
245+
| `chalk` | ^4 | ^5 |
246+
| `c8` | ^7 | ^10 |
247+
248+
### `@types/tabbable` removed
249+
250+
Type declarations are now bundled inside `tabbable` v6 itself, so the separate `@types/tabbable` dev dependency has been removed.
251+
252+
---
253+
254+
## Test suite
255+
256+
All **64 test files / 550 tests** pass. As part of the Vue 3 migration and oxfmt formatting rollout, all spec files across every component and utility were updated to match the new code style (trailing commas, consistent semicolons, import grouping). All affected snapshots have been regenerated to reflect the reformatted component templates.

docgen.mjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import { parse } from 'vue-docgen-api';
22
import fs from 'fs-extra';
3-
import glob from 'glob';
3+
import { sync as globSync } from 'glob';
44
import _ from 'lodash-es';
55
import path from 'path';
66
import parseSCSS from './docgen-scss.mjs';
77

8-
const componentFiles = glob.sync('./src/components/**/*.vue', {
8+
const componentFiles = globSync('./src/components/**/*.vue', {
99
ignore: [
1010
'./src/components/**/examples/**/*',
1111
'./src/components/**/components/*',
1212
'./src/components/icon/comps/*.vue',
1313
],
1414
});
15-
const iconFiles = glob.sync('./src/components/icon/comps/*.vue');
15+
const iconFiles = globSync('./src/components/icon/comps/*.vue');
1616
const componentObj = {};
1717
const iconComponentsObj = {};
1818

@@ -73,7 +73,7 @@ for (const component in componentObj) {
7373
const scssFilePathPattern = path.join(componentDir, 'styles', '**', `${component}.*.scss`);
7474

7575
// Use glob to find matching files
76-
const matchingFiles = glob.sync(scssFilePathPattern);
76+
const matchingFiles = globSync(scssFilePathPattern);
7777

7878
// Iterate over the matching files
7979
for (const matchingFile of matchingFiles) {

src/components/filmstrip/examples/Lifestyle/BasePicture.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ const cssVars = computed(() => ({
211211
212212
const loading = computed(() => (props.lazyLoad ? 'lazy' : undefined));
213213
const computedFetchPriority = computed(() =>
214-
props.fetchPriority?.length ? props.fetchPriority : null,
214+
props.fetchPriority?.length ? (props.fetchPriority as 'auto' | 'high' | 'low') : undefined,
215215
);
216216
217217
/**

src/components/icon/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,4 @@ export { default as IconXSm } from './comps/x-sm.vue';
185185
export { default as IconXStroke } from './comps/x-stroke.vue';
186186
export { default as IconYoutube } from './comps/youtube.vue';
187187
export { default as IconZoomIn } from './comps/zoom-in.vue';
188-
export { default as IconZoomOut } from './comps/zoom-out.vue';
188+
export { default as IconZoomOut } from './comps/zoom-out.vue';

src/components/rating/CdrRating.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import CdrStar25 from './components/CdrStar25.vue';
99
import CdrStar00 from './components/CdrStar00.vue';
1010
import CdrStarNull from './components/CdrStarNull.vue';
1111
12+
// Lookup map for dynamic star components resolved by remainder value
13+
const starComponentMap: Record<string, object> = {
14+
'75': CdrStar75,
15+
'50': CdrStar50,
16+
'25': CdrStar25,
17+
};
18+
1219
/** Provides insight into user opinions for products, experiences, and more */
1320
defineOptions({
1421
name: 'CdrRating',
@@ -86,14 +93,14 @@ const srText = computed(() => {
8693
/>
8794
<component
8895
v-if="remainder !== '00'"
89-
:is="`CdrStar${remainder}`"
96+
:is="starComponentMap[remainder]"
9097
:size="size"
9198
aria-hidden="true"
9299
/>
93100

94101
<component
95102
v-for="empty in Array(empties).keys()"
96-
:is="hasReviews ? 'CdrStar00' : 'CdrStarNull'"
103+
:is="hasReviews ? CdrStar00 : CdrStarNull"
97104
:size="size"
98105
:key="`rating-empty-${empty}`"
99106
aria-hidden="true"

0 commit comments

Comments
 (0)