diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 43b193f5..12d72d89 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,15 +1,19 @@ ## Context (Environment) + ## Expected Behavior + ## Current Behavior + ## Steps to Reproduce or Reproduction Link + @@ -21,6 +25,7 @@ ## Video, Screenshot or other visual aids ## Possible Solution + ## Acceptance criteria @@ -33,4 +38,4 @@ **Then** the outcome of the action in “When” -**And** used to continue any of three previous statements \ No newline at end of file +**And** used to continue any of three previous statements diff --git a/.github/ISSUE_TEMPLATE/user_story.md b/.github/ISSUE_TEMPLATE/user_story.md index 05db3e57..ded86d6e 100644 --- a/.github/ISSUE_TEMPLATE/user_story.md +++ b/.github/ISSUE_TEMPLATE/user_story.md @@ -26,4 +26,4 @@ Some recommendations regarding project and implementation details 2. - [ ] Team understands acceptance criteria 3. - [ ] Team has defined solution / steps to satisfy acceptance criteria 4. - [ ] Acceptance criteria is verifiable / testable -5. - [ ] External / 3rd Party dependencies identified \ No newline at end of file +5. - [ ] External / 3rd Party dependencies identified diff --git a/.github/actions/node-setup-and-install/action.yml b/.github/actions/node-setup-and-install/action.yml index a1962c8c..73526ef2 100644 --- a/.github/actions/node-setup-and-install/action.yml +++ b/.github/actions/node-setup-and-install/action.yml @@ -16,7 +16,7 @@ runs: uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version-file: ".nvmrc" - cache: 'pnpm' # Caches pnpm store globally — shared across all jobs + cache: "pnpm" # Caches pnpm store globally — shared across all jobs # Cache node_modules keyed on OS + lockfile — the only cache needed. # No restore-keys: a partially wrong node_modules is worse than a miss. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0632bbfd..219b7cd3 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -31,4 +31,4 @@ Based on: [example implementation](gistUrl) - [ ] New feature (a non-breaking change that adds functionality) - [ ] Performance (a non-breaking change that reduces time or space complexity of a flow) - [ ] Refactor (a non-breaking change that restructures existing code) -- [ ] Test (added or updated existing tests without implementation changes) \ No newline at end of file +- [ ] Test (added or updated existing tests without implementation changes) diff --git a/.github/workflows/commit-lint.yaml b/.github/workflows/commit-lint.yaml index 4e7c948b..3793e196 100644 --- a/.github/workflows/commit-lint.yaml +++ b/.github/workflows/commit-lint.yaml @@ -2,7 +2,7 @@ name: Conventional Commit (PR title) on: pull_request: - types: [opened, synchronize, reopened, edited] + types: [ opened, synchronize, reopened, edited ] concurrency: group: commit-lint-${{ github.event.pull_request.number }} diff --git a/AGENTS.md b/AGENTS.md index 65f2db3a..6545ee89 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,15 +6,15 @@ Personal open-source monorepo for publishable npm packages under the `@tutods` s ## Stack -| Piece | Version / tool | Notes | -|-------|---------------|-------| -| Workspace | Nx 23 + pnpm 11 (`pnpm-workspace.yaml`: `packages/*`, `configs/*`) | Nx runs/caches builds; pnpm is the only package manager | -| Bundler | Rslib (`@rslib/core`) per package | ESM only, `dts: true` — no CJS output | -| Language | TypeScript 7.x (native TS compiler — bleeding edge) | | -| UI | React 19 as **peerDependency** (`>=19.2.7`) | Never move React to `dependencies` | -| Lint/format | Biome (config from `@tutods/biome-config`, workspace package) | Tabs, double quotes — Biome enforces, don't hand-format | -| Hooks | lefthook (`.lefthook.yml`): pre-commit Biome on staged, commit-msg commitlint | | -| Releases | `nx release` — independent versioning, conventional commits drive bumps | | +| Piece | Version / tool | Notes | +| ----------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------- | +| Workspace | Nx 23 + pnpm 11 (`pnpm-workspace.yaml`: `packages/*`, `configs/*`) | Nx runs/caches builds; pnpm is the only package manager | +| Bundler | Rslib (`@rslib/core`) per package | ESM only, `dts: true` — no CJS output | +| Language | TypeScript 7.x (native TS compiler — bleeding edge) | | +| UI | React 19 as **peerDependency** (`>=19.2.7`) | Never move React to `dependencies` | +| Lint/format | Biome (config from `@tutods/biome-config`, workspace package) | 2 spaces, single quotes — Biome enforces, don't hand-format | +| Hooks | lefthook (`.lefthook.yml`): pre-commit Biome on staged, commit-msg commitlint | | +| Releases | `nx release` — independent versioning, conventional commits drive bumps | | Layout: @@ -27,14 +27,14 @@ configs/ @tutods/{biome,typescript,renovate}-config — published Run from repo root with pnpm (never npm/yarn — `packageManager` pins pnpm): -| Command | What | -|---------|------| -| `pnpm build` | `nx run-many -t build` — builds all packages | -| `pnpm lint` | `biome check .` | -| `pnpm lint:fix` | Biome with `--write` | -| `pnpm lint:ci` | CI variant | -| `pnpm --filter @tutods/components dev` | Rslib watch mode for the components package | -| `pnpm release` | `nx release` — only when explicitly asked; it creates a version commit (no tag/push) | +| Command | What | +| -------------------------------------- | ------------------------------------------------------------------------------------ | +| `pnpm build` | `nx run-many -t build` — builds all packages | +| `pnpm lint` | `biome check .` | +| `pnpm lint:fix` | Biome with `--write` | +| `pnpm lint:ci` | CI variant | +| `pnpm --filter @tutods/components dev` | Rslib watch mode for the components package | +| `pnpm release` | `nx release` — only when explicitly asked; it creates a version commit (no tag/push) | There is no `test` or `typecheck` script. Type errors surface via `pnpm build` (Rslib emits d.ts). If you need a standalone type check, run `pnpm exec tsc --noEmit -p packages/components/tsconfig.json`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dba62f6d..48d2d442 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,19 +206,24 @@ Include: ```markdown ## What + Brief description of what this PR does. ## Why + Reason for these changes. ## How + Technical approach (if needed). ## Related + - Closes #123 - Related to #456 ## Checklist + - [ ] Code follows project standards - [ ] Tests pass - [ ] Documentation updated diff --git a/README.md b/README.md index 2da90418..220f8ae0 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,10 @@ > A collection of reusable packages, configurations, and components for web development projects. --- + ## Table of Contents + - [📄 Goal](#-goal) - [What you will find](#what-you-will-find) - [📦 Packages](#-packages) diff --git a/biome.json b/biome.json index 15d4aee9..bdbfcba6 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,6 @@ { "$schema": "https://biomejs.dev/schemas/2.6.3/schema.json", "root": true, - "extends": ["@tutods/biome-config"] + "extends": ["@tutods/biome-config"], + "files": { "includes": ["!.agents"] } } diff --git a/configs/renovate-config/README.md b/configs/renovate-config/README.md index e41e3ad2..caa1c5c5 100644 --- a/configs/renovate-config/README.md +++ b/configs/renovate-config/README.md @@ -6,6 +6,7 @@ --- ## Table of Contents + - [📄 Goal](#-goal) - [💡 What you get](#-what-you-get) - [✨ Features](#-features) @@ -25,17 +26,17 @@ This is a **shared Renovate preset**: a single source of truth for dependency up ### 💡 What you get -| Area | Behavior | -|------|----------| -| **Minor & patch** | Auto-merged via PR | -| **Major** | Requires dashboard approval | -| **Security advisories** | Instantly processed, auto-merged (minor/patch), grouped with `fix(deps):` prefix | -| **GitHub Actions** | Digest-pinned, minor/patch auto-merged | -| **Docker images** | Digest-pinned, minor/patch auto-merged | -| **devDependencies** | Grouped by minor/patch and major | -| **TypeScript, Biome, Testing, Build tools** | Dedicated groups with appropriate commit prefixes | -| **pnpm** | Runs `pnpm dedupe` post-update | -| **Lockfile** | Monthly maintenance PR | +| Area | Behavior | +| ------------------------------------------- | -------------------------------------------------------------------------------- | +| **Minor & patch** | Auto-merged via PR | +| **Major** | Requires dashboard approval | +| **Security advisories** | Instantly processed, auto-merged (minor/patch), grouped with `fix(deps):` prefix | +| **GitHub Actions** | Digest-pinned, minor/patch auto-merged | +| **Docker images** | Digest-pinned, minor/patch auto-merged | +| **devDependencies** | Grouped by minor/patch and major | +| **TypeScript, Biome, Testing, Build tools** | Dedicated groups with appropriate commit prefixes | +| **pnpm** | Runs `pnpm dedupe` post-update | +| **Lockfile** | Monthly maintenance PR | ## ✨ Features @@ -137,51 +138,51 @@ Any key you set in your local `renovate.json` overrides the inherited value. For ### Core settings -| Setting | Value | Why | -|---------|-------|-----| -| `schedule` | `before 3am every weekday` | Runs outside working hours | -| `timezone` | `Europe/Lisbon` | Consistent timezone reference | -| `prHourlyLimit` | `2` | Prevents PR floods | -| `prConcurrentLimit` | `10` | Keeps the PR list manageable | -| `branchConcurrentLimit` | `5` | Limits parallel branch noise | -| `minimumReleaseAge` | `3 days` | Avoids broken releases | -| `rebaseWhen` | `conflicted` | Only force-push when needed | -| `rangeStrategy` | `bump` | Bumps ranges to the new version | -| `separateMinorPatch` | `true` | Separate PRs for minor and patch | -| `separateMultipleMajor` | `true` | Separate PRs per major dependency | -| `dependencyDashboardApproval` | `true` | Major updates require explicit approval | -| `dependencyDashboardAutoclose` | `true` | Auto-closes dashboard when clean | -| `stopUpdatingLabel` | `renovate:stop` | Emergency brake for vulnerable deps | -| `osvVulnerabilityAlerts` | `true` | OSV/GHSA vulnerability scanning | -| `fetchChangeLogs` | `"pr"` | Embeds changelogs in PR body | -| `rollbackPrs` | `true` | Creates rollback PRs for pulled releases | -| `configMigration` | `true` | Auto-migrates config on breaking Renovate changes | -| `postUpdateOptions` | `["pnpmDedupe"]` | Dedupes pnpm lockfile after updates | -| `lockFileMaintenance` | Monthly, auto-merged | Keeps the lockfile healthy | +| Setting | Value | Why | +| ------------------------------ | -------------------------- | ------------------------------------------------- | +| `schedule` | `before 3am every weekday` | Runs outside working hours | +| `timezone` | `Europe/Lisbon` | Consistent timezone reference | +| `prHourlyLimit` | `2` | Prevents PR floods | +| `prConcurrentLimit` | `10` | Keeps the PR list manageable | +| `branchConcurrentLimit` | `5` | Limits parallel branch noise | +| `minimumReleaseAge` | `3 days` | Avoids broken releases | +| `rebaseWhen` | `conflicted` | Only force-push when needed | +| `rangeStrategy` | `bump` | Bumps ranges to the new version | +| `separateMinorPatch` | `true` | Separate PRs for minor and patch | +| `separateMultipleMajor` | `true` | Separate PRs per major dependency | +| `dependencyDashboardApproval` | `true` | Major updates require explicit approval | +| `dependencyDashboardAutoclose` | `true` | Auto-closes dashboard when clean | +| `stopUpdatingLabel` | `renovate:stop` | Emergency brake for vulnerable deps | +| `osvVulnerabilityAlerts` | `true` | OSV/GHSA vulnerability scanning | +| `fetchChangeLogs` | `"pr"` | Embeds changelogs in PR body | +| `rollbackPrs` | `true` | Creates rollback PRs for pulled releases | +| `configMigration` | `true` | Auto-migrates config on breaking Renovate changes | +| `postUpdateOptions` | `["pnpmDedupe"]` | Dedupes pnpm lockfile after updates | +| `lockFileMaintenance` | Monthly, auto-merged | Keeps the lockfile healthy | ### Package rules -| Rule | Scope | Automerge | -|------|-------|-----------| -| Major updates | All ecosystems | No (dashboard approval required) | -| Minor & patch updates | All ecosystems | Yes | -| Security advisories (minor/patch) | All ecosystems | Yes | -| Security advisories (major) | All ecosystems | No | -| devDep security (minor/patch) | devDependencies | Yes | -| devDep security (major) | devDependencies | No | -| devDep minor & patch | devDependencies | Yes (grouped) | -| devDep major | devDependencies | No (grouped) | -| GitHub Actions (minor/patch) | `github-tags` | Yes, digest-pinned | -| GitHub Actions (major) | `github-tags` | No, digest-pinned | -| Pin digest updates | All | Yes | -| Digest updates | All | Yes | -| Docker (minor/patch) | `docker` | Yes, digest-pinned | -| Docker (major) | `docker` | No, digest-pinned | -| TypeScript packages | TS ecosystem | Grouped | -| Biome packages | Biome ecosystem | Grouped | -| Testing packages | Jest, Vitest, Testing Library | Grouped | -| Build tools | Webpack, Vite, Rollup, esbuild | Grouped | -| Node engine | Node.js | Disabled (ignored) | +| Rule | Scope | Automerge | +| --------------------------------- | ------------------------------ | -------------------------------- | +| Major updates | All ecosystems | No (dashboard approval required) | +| Minor & patch updates | All ecosystems | Yes | +| Security advisories (minor/patch) | All ecosystems | Yes | +| Security advisories (major) | All ecosystems | No | +| devDep security (minor/patch) | devDependencies | Yes | +| devDep security (major) | devDependencies | No | +| devDep minor & patch | devDependencies | Yes (grouped) | +| devDep major | devDependencies | No (grouped) | +| GitHub Actions (minor/patch) | `github-tags` | Yes, digest-pinned | +| GitHub Actions (major) | `github-tags` | No, digest-pinned | +| Pin digest updates | All | Yes | +| Digest updates | All | Yes | +| Docker (minor/patch) | `docker` | Yes, digest-pinned | +| Docker (major) | `docker` | No, digest-pinned | +| TypeScript packages | TS ecosystem | Grouped | +| Biome packages | Biome ecosystem | Grouped | +| Testing packages | Jest, Vitest, Testing Library | Grouped | +| Build tools | Webpack, Vite, Rollup, esbuild | Grouped | +| Node engine | Node.js | Disabled (ignored) | ## 📋 Compatibility @@ -192,4 +193,4 @@ Any key you set in your local `renovate.json` overrides the inherited value. For --- -*Last updated: Renovate v43+ — repository-hosted preset usage, digest pinning, config migration, rollback PRs* +_Last updated: Renovate v43+ — repository-hosted preset usage, digest pinning, config migration, rollback PRs_ diff --git a/configs/typescript-config/README.md b/configs/typescript-config/README.md index 7b397658..60b22479 100644 --- a/configs/typescript-config/README.md +++ b/configs/typescript-config/README.md @@ -6,6 +6,7 @@ --- ## Table of Contents + - [📄 Goal](#-goal) - [What you will find](#what-you-will-find) - [✨ Features](#-features) @@ -109,9 +110,9 @@ Create a `tsconfig.json` file in your project root and extend the configuration ## 📋 Available configurations -| Config | Use for | -|--------|---------| -| `@tutods/typescript-config/base.json` | Shared strict defaults for any TypeScript project | -| `@tutods/typescript-config/react.json` | React applications and libraries | -| `@tutods/typescript-config/node.json` | Node.js applications and packages | -| `@tutods/typescript-config/nestjs.json` | NestJS backend applications | +| Config | Use for | +| --------------------------------------- | ------------------------------------------------- | +| `@tutods/typescript-config/base.json` | Shared strict defaults for any TypeScript project | +| `@tutods/typescript-config/react.json` | React applications and libraries | +| `@tutods/typescript-config/node.json` | Node.js applications and packages | +| `@tutods/typescript-config/nestjs.json` | NestJS backend applications | diff --git a/docs/ADDING_PACKAGES.md b/docs/ADDING_PACKAGES.md index 5660e1d5..1fff07ce 100644 --- a/docs/ADDING_PACKAGES.md +++ b/docs/ADDING_PACKAGES.md @@ -15,9 +15,9 @@ This guide covers the steps to add a new publishable package to this monorepo ## Directory Conventions -| Path | Purpose | -|------|---------| -| `configs//` | Shareable configurations (Biome, TypeScript, Renovate, etc.) | +| Path | Purpose | +| ------------------ | ------------------------------------------------------------ | +| `configs//` | Shareable configurations (Biome, TypeScript, Renovate, etc.) | | `packages//` | Runtime libraries (React components, hooks, utilities, etc.) | Both are automatically discovered by pnpm and NX — no manual workspace registration needed. `pnpm-workspace.yaml` already includes `configs/*` and `packages/*`. @@ -65,13 +65,13 @@ Use an existing sibling package as a template. Here are the critical fields: } ``` -| Field | Why it matters | -|-------|---------------| -| `private: false` | Without this, npm refuses to publish | -| `publishConfig.access: "public"` | Required for scoped packages (`@tutods/*`) | -| `repository.directory` | Must match the subdirectory path exactly — npm provenance depends on it | -| `files` | Controls what lands in the tarball — keep it minimal | -| `version` | Start at `0.0.1` — NX will bump it from the first conventional commit | +| Field | Why it matters | +| -------------------------------- | ----------------------------------------------------------------------- | +| `private: false` | Without this, npm refuses to publish | +| `publishConfig.access: "public"` | Required for scoped packages (`@tutods/*`) | +| `repository.directory` | Must match the subdirectory path exactly — npm provenance depends on it | +| `files` | Controls what lands in the tarball — keep it minimal | +| `version` | Start at `0.0.1` — NX will bump it from the first conventional commit | ## Step 3 — Add Package Content @@ -143,10 +143,10 @@ release.yaml ──► npm publish (OIDC) + git tags + GitHub Releases ## Common Pitfalls -| Problem | Cause | Fix | -|---------|-------|-----| -| NX skips the package during `nx release` | No git tag exists for the package | Create the baseline tag (Step 4) | -| `npm publish` fails with 404 | npm Trusted Publishing not configured for the new package scope | Add the GitHub repo to [npm's Trusted Publishers](https://www.npmjs.com/settings/tutods/publishers) | -| `pnpm install` fails in CI with `ERR_PNPM_IGNORED_BUILDS` | New transitive dependencies need build script approval | Run `pnpm approve-builds` locally or set `allowBuilds` in `pnpm-workspace.yaml` | -| `private: false` but package still won't publish | Missing `publishConfig.access: "public"` for scoped packages | Add the field (Step 2) | -| Version goes `0.0.1` → `0.0.1` (no bump) | Commit type is `chore`, `docs`, `style`, or `test` — these don't bump version | Use `feat` for a minor bump or `fix` for a patch | +| Problem | Cause | Fix | +| --------------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| NX skips the package during `nx release` | No git tag exists for the package | Create the baseline tag (Step 4) | +| `npm publish` fails with 404 | npm Trusted Publishing not configured for the new package scope | Add the GitHub repo to [npm's Trusted Publishers](https://www.npmjs.com/settings/tutods/publishers) | +| `pnpm install` fails in CI with `ERR_PNPM_IGNORED_BUILDS` | New transitive dependencies need build script approval | Run `pnpm approve-builds` locally or set `allowBuilds` in `pnpm-workspace.yaml` | +| `private: false` but package still won't publish | Missing `publishConfig.access: "public"` for scoped packages | Add the field (Step 2) | +| Version goes `0.0.1` → `0.0.1` (no bump) | Commit type is `chore`, `docs`, `style`, or `test` — these don't bump version | Use `feat` for a minor bump or `fix` for a patch | diff --git a/docs/LABELS.md b/docs/LABELS.md index e7247d8a..33bc0b99 100644 --- a/docs/LABELS.md +++ b/docs/LABELS.md @@ -40,27 +40,27 @@ This document lists all the labels that should be configured in this repository. ## 🎨 Label Colors (Recommended) -| Label | Color | Description | -|-------|-------|-------------| -| `dependencies` | `#0366d6` | Blue | -| `renovate` | `#0e8a16` | Green | -| `dev-dependencies` | `##5319e7` | Purple | -| `major-update` | `##d73a4a` | Red | -| `minor-patch-update` | `##a2eeef` | Light blue | -| `security` | `##b60205` | Dark red | -| `pin-digest` | `##fbca04` | Yellow | -| `digest-update` | `###7057ff` | Purple | -| `priority-high` | `##b60205` | Dark red | -| `priority-medium` | `##fbca04` | Yellow | -| `priority-low` | `##e4e669` | Light green | -| `github-actions` | `##2088ff` | Blue | -| `docker` | `##384d54` | Dark gray | -| `typescript` | `##3178c6` | TypeScript blue | -| `biome` | `##60a5fa` | Biome blue | -| `testing` | `###f1e05a` | JavaScript yellow | -| `build-tools` | `###0052cc` | Dark blue | -| `release` | `##2cbe4e` | Green | -| `automated` | `###0066cc` | Blue | +| Label | Color | Description | +| -------------------- | ----------- | ----------------- | +| `dependencies` | `#0366d6` | Blue | +| `renovate` | `#0e8a16` | Green | +| `dev-dependencies` | `##5319e7` | Purple | +| `major-update` | `##d73a4a` | Red | +| `minor-patch-update` | `##a2eeef` | Light blue | +| `security` | `##b60205` | Dark red | +| `pin-digest` | `##fbca04` | Yellow | +| `digest-update` | `###7057ff` | Purple | +| `priority-high` | `##b60205` | Dark red | +| `priority-medium` | `##fbca04` | Yellow | +| `priority-low` | `##e4e669` | Light green | +| `github-actions` | `##2088ff` | Blue | +| `docker` | `##384d54` | Dark gray | +| `typescript` | `##3178c6` | TypeScript blue | +| `biome` | `##60a5fa` | Biome blue | +| `testing` | `###f1e05a` | JavaScript yellow | +| `build-tools` | `###0052cc` | Dark blue | +| `release` | `##2cbe4e` | Green | +| `automated` | `###0066cc` | Blue | ## 📝 Creating Labels in GitHub @@ -127,4 +127,4 @@ Renovate automatically applies labels based on the rules in `.github/renovate.js --- -*Last updated: 2025-04-04* +_Last updated: 2025-04-04_ diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 70dfb14d..e2244ae2 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -212,17 +212,17 @@ After merging the release PR: NX Release uses **Conventional Commits** to determine version increments: -| Commit Type | Bump | Example | -|-------------|------|---------| -| `feat` | **Minor** | 0.8.0 → 0.9.0 | -| `fix` | **Patch** | 0.8.0 → 0.8.1 | -| `docs` | **Patch** | 0.8.0 → 0.8.1 | -| `refactor` | **Patch** | 0.8.0 → 0.8.1 | -| `chore` | **Patch** | 0.8.0 → 0.8.1 | -| `ci` | **Patch** | 0.8.0 → 0.8.1 | -| `style` | **Patch** | 0.8.0 → 0.8.1 | -| `perf` | **Minor** | 0.8.0 → 0.9.0 | -| `test` | **None** | Ignored | +| Commit Type | Bump | Example | +| ----------- | --------- | ------------- | +| `feat` | **Minor** | 0.8.0 → 0.9.0 | +| `fix` | **Patch** | 0.8.0 → 0.8.1 | +| `docs` | **Patch** | 0.8.0 → 0.8.1 | +| `refactor` | **Patch** | 0.8.0 → 0.8.1 | +| `chore` | **Patch** | 0.8.0 → 0.8.1 | +| `ci` | **Patch** | 0.8.0 → 0.8.1 | +| `style` | **Patch** | 0.8.0 → 0.8.1 | +| `perf` | **Minor** | 0.8.0 → 0.9.0 | +| `test` | **None** | Ignored | ### Examples @@ -411,4 +411,4 @@ If you have questions or issues with the release process: --- -*Happy releasing! 🚀* +_Happy releasing! 🚀_ diff --git a/packages/components/README.md b/packages/components/README.md index 9ebf0b3c..56e32f2d 100644 --- a/packages/components/README.md +++ b/packages/components/README.md @@ -58,11 +58,7 @@ type User = { function ProfileGreeting({ user }: { user?: User }) { return ( - Welcome, guest.

} - render={currentUser =>

Welcome, {currentUser.name}.

} - /> + Welcome, guest.

} render={currentUser =>

Welcome, {currentUser.name}.

} /> ); } ``` @@ -101,9 +97,9 @@ function SmartAction({ href, children }: SmartActionProps) { ## Available Components -| Component | Purpose | -|-----------|---------| -| `Show` | Conditional rendering with optional fallback and render-prop support | +| Component | Purpose | +| ---------------------- | ------------------------------------------------------------------------- | +| `Show` | Conditional rendering with optional fallback and render-prop support | | `ConditionalContainer` | Switches the rendered wrapper element/component while preserving children | ## 🏗️ Development diff --git a/packages/components/biome.json b/packages/components/biome.json index 38de98fd..08fc7fc1 100644 --- a/packages/components/biome.json +++ b/packages/components/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.6.3/schema.json", - "root": false, - "extends": ["../../biome.json", "@tutods/biome-config/react"] + "$schema": "https://biomejs.dev/schemas/2.6.3/schema.json", + "root": false, + "extends": ["../../biome.json", "@tutods/biome-config/react"] } diff --git a/packages/components/package.json b/packages/components/package.json index 93a6ed07..9af37709 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,54 +1,54 @@ { - "name": "@tutods/components", - "version": "0.9.7", - "description": "React generic components that can be used in any scenario", - "license": "MIT", - "publishConfig": { - "access": "public" - }, - "author": { - "name": "Daniel Sousa @TutoDS", - "url": "https://github.com/tutods" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/tutods/lib.git", - "directory": "packages/components" - }, - "homepage": "https://github.com/tutods/lib/blob/main/packages/components/README.md", - "type": "module", - "keywords": [ - "react", - "components", - "typescript", - "jsx", - "tsx" - ], - "files": [ - "dist" - ], - "exports": { - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } - } - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "module": "./dist/index.js", - "scripts": { - "dev": "rslib build --watch", - "build": "rslib build" - }, - "devDependencies": { - "@rsbuild/plugin-react": "^2.1.1", - "@rslib/core": "^1.0.4", - "@tutods/typescript-config": "0.7.1" - }, - "peerDependencies": { - "react": ">=19.3.1", - "react-dom": ">=19.3.1" - } + "name": "@tutods/components", + "version": "0.9.7", + "description": "React generic components that can be used in any scenario", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "author": { + "name": "Daniel Sousa @TutoDS", + "url": "https://github.com/tutods" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/tutods/lib.git", + "directory": "packages/components" + }, + "homepage": "https://github.com/tutods/lib/blob/main/packages/components/README.md", + "type": "module", + "keywords": [ + "react", + "components", + "typescript", + "jsx", + "tsx" + ], + "files": [ + "dist" + ], + "exports": { + ".": { + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + } + }, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "module": "./dist/index.js", + "scripts": { + "dev": "rslib build --watch", + "build": "rslib build" + }, + "devDependencies": { + "@rsbuild/plugin-react": "^2.1.1", + "@rslib/core": "^1.0.4", + "@tutods/typescript-config": "0.7.1" + }, + "peerDependencies": { + "react": ">=19.3.1", + "react-dom": ">=19.3.1" + } } diff --git a/packages/components/rslib.config.ts b/packages/components/rslib.config.ts index ef382df0..4517b1c2 100644 --- a/packages/components/rslib.config.ts +++ b/packages/components/rslib.config.ts @@ -1,46 +1,46 @@ -import { pluginReact } from "@rsbuild/plugin-react"; -import { defineConfig } from "@rslib/core"; +import { pluginReact } from '@rsbuild/plugin-react'; +import { defineConfig } from '@rslib/core'; export default defineConfig(({ env }) => { - const isDev = env === "development"; + const isDev = env === 'development'; - return { - source: { - entry: { - index: "./src/index.ts", - }, - }, - lib: [ - { - format: "esm", - dts: true, - autoExtension: false, - }, - ], - output: { - target: "web", - cleanDistPath: true, - injectStyles: true, - emitCss: true, - minify: !isDev, - sourceMap: isDev, - cssModules: { - auto: true, - }, - }, - plugins: [ - pluginReact(), - /** - * If in the future needs to have SVGs in this package, use `@rsbuild/plugin-svgr` with the following configuration: - * ```ts - * pluginSvgr({ - * mixedImport: true, - * svgrOptions: { - * exportType: 'named', - * }, - * }), - * ``` - */ - ], - }; + return { + source: { + entry: { + index: './src/index.ts', + }, + }, + lib: [ + { + format: 'esm', + dts: true, + autoExtension: false, + }, + ], + output: { + target: 'web', + cleanDistPath: true, + injectStyles: true, + emitCss: true, + minify: !isDev, + sourceMap: isDev, + cssModules: { + auto: true, + }, + }, + plugins: [ + pluginReact(), + /** + * If in the future needs to have SVGs in this package, use `@rsbuild/plugin-svgr` with the following configuration: + * ```ts + * pluginSvgr({ + * mixedImport: true, + * svgrOptions: { + * exportType: 'named', + * }, + * }), + * ``` + */ + ], + }; }); diff --git a/packages/components/src/components/conditional-contianer/index.tsx b/packages/components/src/components/conditional-contianer/index.tsx index 28058cad..18f7f2c2 100644 --- a/packages/components/src/components/conditional-contianer/index.tsx +++ b/packages/components/src/components/conditional-contianer/index.tsx @@ -1,6 +1,6 @@ -import { createElement } from "react"; +import { createElement } from 'react'; -import type { ConditionalContainerProps, RenderElement } from "./types"; +import type { ConditionalContainerProps, RenderElement } from './types'; /** * Component to render a specific element or component according a condition @@ -23,33 +23,28 @@ import type { ConditionalContainerProps, RenderElement } from "./types"; * * ``` */ -const ConditionalContainer = < - TRender extends RenderElement, - TFallback extends RenderElement, ->({ - children, - fallback, - render, - when, +const ConditionalContainer = ({ + children, + fallback, + render, + when, }: ConditionalContainerProps) => { - if (when) { - const { element, props: renderProps } = render; + if (when) { + const { element, props: renderProps } = render; - return children - ? createElement(element, renderProps, children) - : createElement(element, renderProps); - } + return children ? createElement(element, renderProps, children) : createElement(element, renderProps); + } - if (!when && fallback) { - const { element: fallbackElement, props: fallbackProps = {} } = fallback; + if (!when && fallback) { + const { element: fallbackElement, props: fallbackProps = {} } = fallback; - return children - ? createElement(fallbackElement, fallbackProps, children) - : createElement(fallbackElement, fallbackProps); - } + return children + ? createElement(fallbackElement, fallbackProps, children) + : createElement(fallbackElement, fallbackProps); + } - // When no `fallback` element is specified - return <>{children}; + // When no `fallback` element is specified + return <>{children}; }; export type { ConditionalContainerProps }; diff --git a/packages/components/src/components/conditional-contianer/types.ts b/packages/components/src/components/conditional-contianer/types.ts index a2d908e0..8b9537a4 100644 --- a/packages/components/src/components/conditional-contianer/types.ts +++ b/packages/components/src/components/conditional-contianer/types.ts @@ -1,58 +1,49 @@ -import type { - ComponentProps, - ForwardRefExoticComponent, - JSX, - ReactElement, - ReactNode, -} from "react"; +import type { ComponentProps, ForwardRefExoticComponent, JSX, ReactElement, ReactNode } from 'react'; /** * Available types to be used on `render` or `otherwise` */ type RenderElement = - | keyof JSX.IntrinsicElements - // biome-ignore lint/suspicious/noExplicitAny: This is a generic type that can accept any component, so `any` is necessary here. - | ((props: any) => ReactElement) - // biome-ignore lint/suspicious/noExplicitAny: This is a generic type that can accept any component, so `any` is necessary here. - | ForwardRefExoticComponent; + | keyof JSX.IntrinsicElements + // biome-ignore lint/suspicious/noExplicitAny: This is a generic type that can accept any component, so `any` is necessary here. + | ((props: any) => ReactElement) + // biome-ignore lint/suspicious/noExplicitAny: This is a generic type that can accept any component, so `any` is necessary here. + | ForwardRefExoticComponent; type ComponentArgs = { - /** - * Element to be rendered - * @example `Button` - */ - element: T; - - /** - * Properties to apply to element - * @example `{type: 'button'}` - */ - props?: Omit, "children">; + /** + * Element to be rendered + * @example `Button` + */ + element: T; + + /** + * Properties to apply to element + * @example `{type: 'button'}` + */ + props?: Omit, 'children'>; }; -type ConditionalContainerProps< - TRender extends RenderElement, - TFallback extends RenderElement, -> = { - /** - * Condition to display the `render` element - */ - when: boolean; - - /** - * Children of the container - */ - children?: ReactNode; - - /** - * Component to be rendered when the condition is satisfied - */ - render: ComponentArgs; - - /** - * Component to be rendered when the condition isn't satisfied - */ - fallback?: ComponentArgs; +type ConditionalContainerProps = { + /** + * Condition to display the `render` element + */ + when: boolean; + + /** + * Children of the container + */ + children?: ReactNode; + + /** + * Component to be rendered when the condition is satisfied + */ + render: ComponentArgs; + + /** + * Component to be rendered when the condition isn't satisfied + */ + fallback?: ComponentArgs; }; export type { ConditionalContainerProps, RenderElement }; diff --git a/packages/components/src/components/index.ts b/packages/components/src/components/index.ts index 48156aba..d6b0604f 100644 --- a/packages/components/src/components/index.ts +++ b/packages/components/src/components/index.ts @@ -1,2 +1,2 @@ -export * from "./conditional-contianer"; -export * from "./show"; +export * from './conditional-contianer'; +export * from './show'; diff --git a/packages/components/src/components/show.tsx b/packages/components/src/components/show.tsx index e92a41ce..66391770 100644 --- a/packages/components/src/components/show.tsx +++ b/packages/components/src/components/show.tsx @@ -1,28 +1,28 @@ -import type { ReactNode } from "react"; +import type { ReactNode } from 'react'; type Props = { - /** - * Condition to match. - */ - when: T | undefined | null; + /** + * Condition to match. + */ + when: T | undefined | null; - /** - * Function that returns the component or element to render if condition is met. - * Using a function prevents the children from being evaluated when condition is false. - */ - children?: (() => ReactNode) | ReactNode; + /** + * Function that returns the component or element to render if condition is met. + * Using a function prevents the children from being evaluated when condition is false. + */ + children?: (() => ReactNode) | ReactNode; - /** - * Render prop — receives the non-nullable `when` value for type-safe access. - * Takes precedence over `children` when both are provided. - */ - render?: (value: NonNullable) => ReactNode; + /** + * Render prop — receives the non-nullable `when` value for type-safe access. + * Takes precedence over `children` when both are provided. + */ + render?: (value: NonNullable) => ReactNode; - /** - * Fallback component/element to render if condition is not met. - * @default null - */ - fallback?: ReactNode; + /** + * Fallback component/element to render if condition is not met. + * @default null + */ + fallback?: ReactNode; }; /** @@ -49,19 +49,19 @@ type Props = { * ``` */ function Show({ when, render, children, fallback = null }: Props) { - if (when) { - if (render) { - return render(when as NonNullable); - } + if (when) { + if (render) { + return render(when as NonNullable); + } - if (typeof children === "function") { - return children(); - } + if (typeof children === 'function') { + return children(); + } - return children ?? null; - } + return children ?? null; + } - return fallback; + return fallback; } export { Show }; diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 40b494c5..07635cbb 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -1 +1 @@ -export * from "./components"; +export * from './components'; diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 947e9773..d869a3fb 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -1,8 +1,8 @@ { - "$schema": "https://json.schemastore.org/tsconfig", - "extends": ["@tutods/typescript-config/react.json"], - "compilerOptions": { - "rootDir": "src" - }, - "include": ["src"] + "$schema": "https://json.schemastore.org/tsconfig", + "extends": ["@tutods/typescript-config/react.json"], + "compilerOptions": { + "rootDir": "src" + }, + "include": ["src"] }