Aller au contenu
Krizaka TypeScript
Krizaka TypeScript

@krizaka/config

Le kit qualité de chaque dépôt TypeScript : configs ESLint, preset dependency-cruiser, bases tsconfig, Prettier et le cliquet de dette.

Installer

bashTerminal
npm install @krizaka/config

Aussi publié en sous-chemins : @krizaka/config/eslint, @krizaka/config/eslint/next, @krizaka/config/eslint/krizaka-ui, @krizaka/config/eslint/no-locale-ternary, @krizaka/config/eslint/stack, @krizaka/config/eslint/ui-warnings, @krizaka/config/eslint/env-names, @krizaka/config/eslint/plugin, @krizaka/config/dependency-cruiser, @krizaka/config/covered-domains, @krizaka/config/covered-domains.json, @krizaka/config/known-violations, @krizaka/config/patterns, @krizaka/config/ratchet, @krizaka/config/prettier, @krizaka/config/tsconfig/base.json, @krizaka/config/tsconfig/react-library.json, @krizaka/config/tsconfig/next.json, @krizaka/config/tsconfig/react-native.json, @krizaka/config/editorconfig.

Le README ci-dessous est celui du paquet sur npm, en anglais.

The shared configuration of every Krizaka JavaScript repository. ESLint flat configs (base, Next.js, the four UI rules, the three stack rules, no locale ternary), the dependency-cruiser boundary, tsconfig bases, Prettier, EditorConfig — and krizaka-ratchet, the counter that keeps the UI and stack debts from coming back.

npm License

Adopt it in three lines

npm install -D @krizaka/config eslint typescript     # + eslint-config-next for a Next.js app, prettier if you format
// eslint.config.mjs — a Next.js app (a library: `krizakaBase` from "@krizaka/config/eslint")
import { krizakaNext } from "@krizaka/config/eslint/next";
import { krizakaUi } from "@krizaka/config/eslint/krizaka-ui";
import { noLocaleTernary } from "@krizaka/config/eslint/no-locale-ternary";
import { krizakaStack } from "@krizaka/config/eslint/stack";

export default [...krizakaNext, ...krizakaUi(), ...krizakaStack(), ...noLocaleTernary()];
// .dependency-cruiser.cjs — « Krizaka first », cycles, unresolvable imports, dev dependencies, plus the app's own rules
module.exports = { extends: "@krizaka/config/dependency-cruiser", forbidden: [] };
// tsconfig.json — base · react-library · next · react-native
{ "extends": "@krizaka/config/tsconfig/next.json", "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"] }

Prettier: export { default } from "@krizaka/config/prettier"; in prettier.config.js (120 columns, double quotes, trailing commas). EditorConfig: cp node_modules/@krizaka/config/.editorconfig ..

eslint ^9 and typescript ^5 are peer dependencies; eslint-config-next (Next.js apps) and prettier are optional peers. The plugins (typescript-eslint, eslint-plugin-react-hooks, eslint-plugin-simple-import-sort) come with the package.

What is inside

ExportWhat it gives
@krizaka/config/eslintkrizakaBase: @eslint/js + typescript-eslint recommended, React hooks, import ordering (a warning, autofixable), ignores of generated output, _-prefixed unused arguments allowed.
@krizaka/config/eslint/nextkrizakaNext: eslint-config-next (core web vitals + TypeScript, which already carry typescript-eslint, React hooks and import) + the same basics.
@krizaka/config/eslint/krizaka-uikrizakaUi(options?): the four UI rules below. Also krizakaUiRules and krizakaUiRestrictedSyntax(options?).
@krizaka/config/eslint/no-locale-ternarynoLocaleTernary(options?): krizaka/no-locale-ternary — no locale === "fr" ? … : … outside routing code.
@krizaka/config/eslint/ui-warningskrizakaUiWarnings(options?): the same two debts as named plugin rules, as warnings — krizaka/no-light-variant (no light:: tokens do the theming) and krizaka/no-raw-palette (no bg-zinc-900, text-violet-400: a role; allow families). krizaka-ratchet counts them (light, palette), so a product adopts them now and brings the counts to 0.
@krizaka/config/eslint/stackkrizakaStack(options?): the three stack rules below (warnings). Also STACK_RULES.
@krizaka/config/eslint/pluginkrizakaPlugin: the krizaka plugin carrying every rule, for a hand-written config.
@krizaka/config/dependency-cruiserThe shared dependency-cruiser config, generated from the covered-domains map: one krizaka-first-<domain> rule per domain (dates, i18n, query, icons, ui), no-circular, not-to-unresolvable, not-to-dev-dep. .withOptions({ exemptFrom }) for a monorepo whose own packages are the facades.
@krizaka/config/covered-domains · /covered-domains.jsonThe covered-domains map (one data file) and its helpers: the message, the patterns, the Markdown table of « Use Krizaka first ».
krizaka-known-violations (bin) · @krizaka/config/known-violationsThe known violations of dependency-cruiser, which only shrink, see below.
@krizaka/config/tsconfig/*.jsonbase (strict, ES2022, bundler resolution), react-library (+ DOM, react-jsx), next (+ the Next plugin, noEmit, incremental), react-native (jsx: react-native, customConditions; with Expo: "extends": ["expo/tsconfig.base", "@krizaka/config/tsconfig/react-native.json"]).
@krizaka/config/prettier · .editorconfigThe formatting.
krizaka-ratchet (bin)The debt counter, see below.

The four UI rules

On every string literal inside a className (in cn(…), a ternary…), with no plugin — no-restricted-syntax selectors:

  1. No raw palette colour — bg-zinc-900, text-violet-400/80: use a role of @krizaka/tailwind (bg-surface-1, text-fg-secondary, border-border-default, text-accent, text-danger).
  2. No light: — a theme is a set of tokens; a dark island takes .theme-dark on its ancestor.
  3. No arbitrary [var(--…)] utility — the variable has a utility in @krizaka/tailwind.
  4. No template literal in className — cn(…) merges the classes and lets the override win.
krizakaUi({
  allow: ["emerald"],             // palette families tolerated for documented, isolated cases
  files: ["**/*.{jsx,tsx}"],      // default
  ignores: ["app/og/**"],         // e.g. generated OG images
  severity: "error",              // "warn" while the ratchet brings the debt down
});

Flat config replaces a rule's options instead of concatenating them: a repository that already sets no-restricted-syntax merges both lists with krizakaUiRestrictedSyntax(). no-locale-ternary is a plugin rule for that reason — it composes with anything.

The stack rules

From ADR-001 — the TanStack engines run headless, behind @krizaka/* facades; a product never imports them. Warnings: krizaka-ratchet counts the same patterns, so an app adopts them before it is clean and brings each count to 0 by the end of its adoption.

  1. krizaka/no-fetch-in-client-effect — a fetch / krizakaFetch inside a useEffect (or useLayoutEffect) of a "use client" file: render the first screen in a Server Component, read the rest with @krizaka/query.
  2. krizaka/no-local-table-or-form — a <table>, or a <form> of more than one field (native fields and the field primitives of @krizaka/ui; a hidden or submit <input> is not a field): use DataTable and createKrizakaForm. A search box or a one-field newsletter stays a plain form.
krizakaStack({
  files: ["**/*.{js,jsx,mjs,cjs,ts,tsx,mts,cts}"], // default
  ignores: ["packages/**"],                        // e.g. the facades of a monorepo
  severity: "warn",                                // default; "error" once the app's counts are at 0
  maxFormFields: 1,                                // default
});

« Krizaka first » — the refused imports (dependency-cruiser)

Part of the stack ADR and of krizaka-ui#609, in one tool: dependency-cruiser carries every refused import (an import is an edge: it catches re-exports and dynamic imports, and the same file holds the layers); ESLint keeps the framework rules above. The ESLint rule krizaka/no-direct-tanstack-import is retired: @tanstack/* is krizaka-first-query.

The covered-domains map is covered-domains.json, the single source. Each domain names its Krizaka home and what is refused in an app; the preset generates krizaka-first-<domain> from it, and the page « Use Krizaka first » of ui.krizaka.com is laid out from it (coveredDomainsMarkdown()).

DomainKrizaka homeRefused in an appRule
Dates, times, local days@krizaka/intl (formatting, localDay), @krizaka/time (arithmetic; a facade created on the first real need, krizaka-ts#76)date-fns*, @date-fns/*, dayjs, luxon, moment, moment-timezonekrizaka-first-dates
Words, languages@krizaka/i18ni18next*, react-i18next, next-intl, next-i18next, react-intl, @formatjs/*, @lingui/*, i18n-js, typesafe-i18nkrizaka-first-i18n
Data fetching, cache, tables, forms, virtual lists@krizaka/query, @krizaka/ui, @krizaka/pacer@tanstack/*krizaka-first-query
Icons@krizaka/iconslucide-react, react-icons, @heroicons/*krizaka-first-icons
Interface primitives@krizaka/ui@radix-ui/*, radix-uikrizaka-first-ui

An entry is a package (dayjs, and its subpaths), a prefix (date-fns*) or a scope (@tanstack/*). It matches the resolved file and the module as written when it cannot be resolved (a package the app does not declare), never a local folder of the same name. A Krizaka package is exempt: it is the facade. In an app that is the packages in node_modules; in a monorepo that holds its own Krizaka packages, say where they live:

// .dependency-cruiser.cjs of a monorepo (krizaka-ui, krizaka-ts)
module.exports = require("@krizaka/config/dependency-cruiser").withOptions({ exemptFrom: ["(^|/)packages/"] });

Every message names the home and ends « Missing function? add it to the package first. » — a missing function is added to the Krizaka package, never worked around with the library. Run it with depcruise --output-type err-long <folders> to read the message (err prints the rule name only). Beside the domains, the preset owes every repository no-circular, not-to-unresolvable (declare the dependency, or fix the path; set options.tsConfig for path aliases) and not-to-dev-dep (tests, stories, scripts and tool configs may import devDependencies). Run depcruise from the workspace that owns the package.json.

Known violations (they only shrink)

An app that adopts the rules late records what it already breaks, and the debt only goes down:

krizaka-known-violations init src app         # once, in the adoption pull request: writes .dependency-cruiser-known-violations.json
depcruise src app --config .dependency-cruiser.cjs --ignore-known .dependency-cruiser-known-violations.json   # lint: new violations fail
krizaka-known-violations check src app        # lint: also fails on a recorded violation that is fixed ("lock the gain")
krizaka-known-violations update src app       # removes the fixed ones; NEVER adds one, and fails while a new one exists

The file is the format of depcruise-baseline, so --ignore-known reads it. init refuses to overwrite it; there is no command that records a new violation. It replaces the directTanstackImport counter of krizaka-ratchet, which stays only for repositories that have not moved yet.

noLocaleTernary({ files, routing }): routing lists the files allowed to compare locales (default: proxy.ts, middleware.ts, i18n.ts, seo.ts, app/[locale]/layout.tsx, I18nProvider.tsx).

Environment variable names (krizaka/env-name)

Environment variables are named by bounded context (krizaka/.github#46): <CONTEXT>_<THING> with CONTEXT one of APP_ DATABASE_ AUTH_ MEDIA_ MAIL_ PUSH_ PAYMENTS_ REALTIME_ ABUSE_ OBSERVABILITY_ AI_ OPERATOR_. The rule — on in krizakaBase and krizakaNext — refuses a name read through process.env.X, process.env["X"] or import.meta.env.X that starts (after NEXT_PUBLIC_, EXPO_PUBLIC_ or VITE_) with:

  • a product: the organisation's name, the repository's own (the first word of its package.json name, acme-monorepo → ACME_), or one you name — a deployment already says which product it is;
  • a vendor (BUNNY_, MAILGUN_, RESEND_, STRIPE_, GOOGLE_, EXPO_, REDIS_…): the vendor is a value (MEDIA_STORAGE_PROVIDER=bunny, MAIL_PROVIDER=mailgun) and its settings sit under the context (MEDIA_STORAGE_API_KEY, MAIL_API_KEY).

The platforms' own names (GITHUB_TOKEN, EAS_BUILD, …) pass. Tune it with envNames({ products, vendors, allow }) from @krizaka/config/eslint/env-names; envNamePrefixProblem(name) gives the same verdict to a script (a .env.example or deployment spec check).

The ratchet

A repository with debt cannot turn the rules on in one pull request. The ratchet lets it adopt them now: it counts the four UI debts and the four stack debts, records the counts in lint-ratchet.json at the root, and fails when a count goes up. Every migration pull request lowers them; when a count reaches zero, the matching rule becomes a strict error.

npx krizaka-ratchet --init      # once: creates lint-ratchet.json with today's counts — commit it
npx krizaka-ratchet             # locally: compares (exit 1 when a count went up)
npx krizaka-ratchet --update    # after a migration: lowers the recorded counts (never raises them), records new counters — commit it
npx krizaka-ratchet --json      # in CI: the same check, machine-readable
CounterPattern (same regex as the ESLint rule)
palette\b(bg|text|border|from|via|to|ring|shadow|fill|stroke)-(zinc|slate|…|indigo)-[0-9]
light\blight:
arbitraryVar\[var\(--
classNameTemplateclassName=\{\s*`
fetchInClientEffectin a file opening with "use client": fetch( / krizakaFetch( between the parentheses of a useEffect( / useLayoutEffect(
directTanstackImportfrom / import / import( / require( of "@tanstack/…"
localTableOrForm<table, and <form … </form> holding more fields than maxFormFields (default 1)
retiredImportan import of a dependency listed in retire (e.g. ["framer-motion"]): the way out of a dependency
routeStateSelectiona Tabs / chip group / choice grid / segmented switch (incl. RadioGroup.Root variant="segmented") / toggle group of a view driven by local state (value, defaultValue, onValueChange) without routeKey, and without // @ephemeral: <reason>: the URL is the state

The UI counters scan app/**/*.tsx, components/**/*.tsx and src/**/*.tsx by default (node_modules, dist, .next never), or the globs given on the command line; the stack counters scan every source file (js, jsx, mjs, ts, tsx, mts) of app, components, src, lib, hooks and features (stackGlobs). --init stores both in the file so that every later run counts the same set. A file written before the stack counters still checks; the next --update records them at their current value. The counts apply the regex to the whole source text — a class held in a constant or a cn() argument counts too — so the ratchet is never looser than the rule. Exit codes: 0 ok, 1 a count went up, 2 usage or file error.

// lint-ratchet.json
{
  "globs": ["app/**/*.tsx", "components/**/*.tsx", "src/**/*.tsx"],
  "stackGlobs": ["app/**/*.{js,jsx,mjs,ts,tsx,mts}", "…"],
  "allow": [],                                   // optional: same families as krizakaUi({ allow })
  "retire": ["framer-motion"],                   // optional: dependencies on their way out
  "maxFormFields": 1,                            // optional: same option as krizakaStack({ maxFormFields })
  "counters": {
    "palette": 2400, "light": 1151, "arbitraryVar": 0, "classNameTemplate": 128,
    "fetchInClientEffect": 41, "directTanstackImport": 3, "localTableOrForm": 38, "retiredImport": 4
  }
}

The CI step, after the install:

- run: npx krizaka-ratchet --json

License

Apache-2.0

Exports

Les 0 noms que le paquet exporte, lus dans ses types.

NomNatureCe que c’est

@krizaka/config/eslint

NomNatureCe que c’est
defaultconstante
KRIZAKA_IGNORESconstanteGenerated or vendored output, never linted.
krizakaBaseconstante
krizakaCommonconstanteShared by krizakaBase and krizakaNext: ignores, globals, import ordering.

@krizaka/config/eslint/next

NomNatureCe que c’est
defaultconstante
krizakaNextconstante

@krizaka/config/eslint/krizaka-ui

NomNatureCe que c’est
defaultfonctionFlat config: the four UI rules on the given files.
krizakaUifonctionFlat config: the four UI rules on the given files.
krizakaUiRestrictedSyntaxfonctionThe no-restricted-syntax entries, for a repository that already uses that rule and must merge both lists (flat config replaces a rule's options, it never c…
krizakaUiRulesconstanteThe rule set, for a spread into a config object's rules.

@krizaka/config/eslint/no-locale-ternary

NomNatureCe que c’est
defaultfonctionFlat config: krizaka/no-locale-ternary on the given files, except routing code.
DEFAULT_ROUTING_FILESconstanteRouting files that legitimately compare locales (the krizaka.com layout, a common convention).
krizakaPluginconstante
LOCALE_TERNARY_SELECTORSconstanteThe selectors of no-locale-ternary, also usable in no-restricted-syntax.
noLocaleTernaryfonctionFlat config: krizaka/no-locale-ternary on the given files, except routing code.

@krizaka/config/eslint/stack

NomNatureCe que c’est
defaultfonctionFlat config: the stack rules on an app's sources.
krizakaStackfonctionFlat config: the stack rules on an app's sources.
STACK_RULESconstanteThe rule names, as configured.

@krizaka/config/eslint/ui-warnings

NomNatureCe que c’est
defaultfonctionFlat config: the two named UI rules on a product's components.
krizakaUiWarningsfonctionFlat config: the two named UI rules on a product's components.
UI_WARNING_RULESconstanteThe rule names, as configured.

@krizaka/config/eslint/env-names

NomNatureCe que c’est
defaultfonctionFlat config: krizaka/env-name on the given files.
ENV_PLATFORM_NAMESconstanteNames the platforms set themselves (GitHub Actions, EAS): read, never chosen.
ENV_PRODUCT_PREFIXESconstanteThe organisation's name is never a prefix; a repository's own product is found from its package.json (below) and a config may name more (products): a deplo…
ENV_VENDOR_PREFIXESconstanteVendors: a vendor is a value (MEDIA_STORAGE_PROVIDER=bunny, MAIL_PROVIDER=mailgun), never a name.
envNamePrefixProblemfonctionThe prefix that makes an environment variable name refused, or null.
envNamesfonctionFlat config: krizaka/env-name on the given files.
krizakaPluginconstante
ownProductPrefixfonctionThe product a repository is: the first word of the nearest package.json's name, scope removed (acme-monorepo → ACME, @org/acme-admin → ACME); null for a…

@krizaka/config/eslint/plugin

NomNatureCe que c’est
defaultconstante
krizakaPluginconstante

@krizaka/config/dependency-cruiser

NomNatureCe que c’est
withOptionstype

@krizaka/config/covered-domains

NomNatureCe que c’est
CoveredDomaintype
coveredDomainsconstanteThe domains, in the order of the map.
coveredDomainsMarkdownfonctionThe table of the page « Use Krizaka first » (Markdown), generated from the map.
domainMessagefonctionThe message of a domain: what is refused, the Krizaka home, and what to do when the function is missing.
domainPatternfonctionOne pattern for a whole domain.
MISSING_FUNCTIONconstanteThe last thing every message says.
refusedPatternfonctionThe dependency-cruiser to.path regular expression of a refused entry.
ruleNamefonctionThe name of the dependency-cruiser rule of a domain.

@krizaka/config/covered-domains.json

NomNatureCe que c’est

@krizaka/config/known-violations

NomNatureCe que c’est
comparefonctionCompare the recorded violations with the current ones.
CONFIG_FILEconstante
currentViolationsfonctionRun dependency-cruiser without the known file and read every violation (the baseline report).
keyOffonctionThe identity of a violation, as depcruise matches it: the rule, the two ends, and the cycle's modules.
KNOWN_FILEconstante
runKnownViolationsfonctioncheck | update | init.
shrinkfonctionWhat update writes: the recorded violations that still happen.
Violationtype

@krizaka/config/patterns

NomNatureCe que c’est
ARBITRARY_VAR_SOURCEconstantebg-[var(--surface-1)] — the variable has a utility in
balancedArgumentsfonctionThe text between the parenthesis that opens at open and the one that closes it, skipping strings and comments.
CLASSNAME_TEMPLATE_SOURCEconstanteclassName=\{…${x}\} — the ratchet's text approximation of the TemplateLiteral rule.
COLOR_UTILITIESconstanteUtilities that take a colour.
countFormFieldsfonctionThe value-holding fields inside a form's source text.
EFFECT_CALL_SOURCEconstanteThe opening of an effect call: useEffect(, React.useLayoutEffect(.
EFFECT_NAMES_SOURCEconstanteThe names the ESLint rule matches (callee identifier or member property).
EPHEMERAL_SOURCEconstanteThe justification that keeps a local selection: `//
FETCH_CALL_SOURCEconstanteA fetch call: fetch(, window.fetch(, krizakaFetch( — never refetch(.
FETCH_NAMES_SOURCEconstante
FORM_FIELD_TAGSconstanteThe elements that hold a value in a form: native fields and the field primitives of @krizaka/ui.
importSourcefonctionAn import of one of the given packages (or scopes ending in /): from "x", import "x", import("x"), require("x"), export … from "x".
isLocalSelectionfonctionIs this opening tag a selection driven by local state?
LIGHT_VARIANT_SOURCEconstantelight:bg-white — a theme is a set of tokens, never a variant.
LOCAL_SELECTION_PROPSconstanteThe props that make a selection local: its own value, its starting value, its change handler.
PALETTE_FAMILIESconstanteTailwind palette families a product never writes: a component reads a role (bg-surface-1, text-accent…).
paletteSourcefonctionbg-zinc-900, text-violet-400/80… — a raw palette step.
ROUTE_KEY_PROPconstanteThe prop that binds it to the URL.
SELECTION_COMPONENTSconstanteThe selection components whose choice belongs in the URL: tabs, a segmented switch, toggle groups, chip groups, choice tiles.
selectionTagsfonctionThe opening tags (&lt;Tabs.Root … >) of the selection components in a source text, each with the line above it.
TABLE_OR_FORM_SOURCEconstanteA &lt;table or &lt;form element written in an app (JSX or HTML).
TANSTACK_SCOPEconstanteThe headless engines that only enter through a @krizaka/* package.
USE_CLIENT_SOURCEconstanteA "use client" directive heading the file (after comments).

@krizaka/config/ratchet

NomNatureCe que c’est
CounterNametype
counterPatternsfonction
Counterstype
COUNTERSconstanteEvery counter, in report order.
countRepositoryfonctionCounts the debts under root: the UI counters in the files of globs, the stack counters in those of stackGlobs.
countSourcefonctionCounts the four UI debts in one source text.
countStackSourcefonctionCounts the stack debts in one source text: fetch calls inside the effects of a "use client" file, imports of @tanstack/*, hand-written tables and forms o…
DEFAULT_GLOBSconstante
DEFAULT_STACK_GLOBSconstanteThe stack counters read every source file: data hooks and fetchers live in .ts too.
RATCHET_FILEconstante
RatchetErrorclasseA usage or file error (exit code 2), as opposed to a counter going up (exit code 1).
RatchetFiletype
RatchetResulttype
runRatchetfonctionRuns the ratchet.
STACK_COUNTERSconstanteThe stack counters (the three rules of krizakaStack, and the dependencies to retire), in report order.
StackCounterNametype
UI_COUNTERSconstanteThe UI counters (the four rules of krizakaUi), in report order.
UiCounterNametype

@krizaka/config/prettier

NomNatureCe que c’est
defaultconstante

@krizaka/config/tsconfig/base.json

NomNatureCe que c’est

@krizaka/config/tsconfig/react-library.json

NomNatureCe que c’est

@krizaka/config/tsconfig/next.json

NomNatureCe que c’est

@krizaka/config/tsconfig/react-native.json

NomNatureCe que c’est

@krizaka/config/editorconfig

NomNatureCe que c’est

Paquet

Version sur npm0.8.0 (npm)
LicenceApache-2.0
Node.js>=22
Dépendances@eslint/js ^9.39.0
Dépendances à fournireslint ^9
Code sourceconfig

Journal des versions

0.8.0

Minor changes

  • @krizaka/config now lives in krizaka-ts (the quality kit is not UI), with its history. Same name, same exports, same behaviour; the repository, bug tracker and homepage links change. Releases are published from krizaka-ts.

  • « Krizaka first » (krizaka-ui#609, #612): the covered-domains map (covered-domains.json, dates, i18n, query, icons, ui: each names its Krizaka home and the refused imports) and the dependency-cruiser preset generated from it, one krizaka-first-<domain> rule per domain, with no-circular, not-to-unresolvable and not-to-dev-dep. The message names the Krizaka home and says « Missing function? add it to the package first. ». .withOptions({ exemptFrom }) for a monorepo's own packages. New krizaka-known-violations (init, check, update): a known-violations baseline that only shrinks. New exports @krizaka/config/covered-domains and /known-violations; dependency-cruiser is now a dependency.

    Breaking: the ESLint rule krizaka/no-direct-tanstack-import is retired (and leaves STACK_RULES): the TanStack import is krizaka-first-query in dependency-cruiser, one tool only. krizaka-no-direct-tanstack is replaced by it.

0.7.0

Minor changes

  • #496 64ede61 Thanks @krizaka-agents! - Peer range eslint: ^9 || ^10 (and @eslint/js likewise). The ESLint suite and the lint of the package pass under both ESLint 9.39 and 10.13 (krizaka-ui#141).

0.6.0

Minor changes

  • #488 c4a6ce1 Thanks @krizaka-agents! - The URL is the state, made impossible to forget (Oussama, 2026-10-22: « changer les tabs doit changer les routes »).

    • New @krizaka/ui/router: useRouteState(key, { values, default, history }) keeps a value in a search parameter, typed from an as const list (an unknown value reads as the default, the default is never written, other parameters are kept); RouteStateProvider takes your router's adapter once (the History API is the default); pure readRouteValue / writeRouteValue.
    • routeKey (+ routeValues) on Tabs.Root, Chip.Group (single) and ChoiceGrid: they bind to the URL, no useState. Local state stays for ephemeral UI only.
    • @krizaka/config: the rule krizaka/route-state-selection (in krizakaStack(), severity of the stack, only pages and route components) refuses a Tabs / Chip.Group / ChoiceGrid / SegmentedControl / ToggleGroup driven by local state without routeKey, unless the line carries // @ephemeral: <reason>; the ratchet counts it as routeStateSelection (only goes down).

0.5.0

Minor changes

  • #486 0b1d80d Thanks @krizaka-agents! - No more family switcher: krizaka.com is the only way back between the Krizaka sites (Oussama, 2026-10-22).

    • NavBar.Family is deprecated (removed in the next minor once no site uses it).
    • SiteFooter lists the family on the hub only: family now defaults to current === "krizaka", so every other site's footer holds its own columns, the legal links and one quiet « A Krizaka project » line linking to www.krizaka.com. New products prop filters the hub's Products column (krizaka.com's focus products), replacing CSS that hid links by URL.
    • @krizaka/config: the krizaka/no-family-switcher rule (an error in krizakaStack()) refuses NavBar.Family so it does not come back.

0.4.2

Patch changes

  • #467 af54020 Thanks @krizaka-agents! - Vercel is retired: its platform variable names are no longer allowed by the env-name rule (a VERCEL_ variable is refused like any vendor name).

0.4.1

Patch changes

  • #179 e3bcc51 Thanks @oussamaABID! - The documentation moved to https://ui.krizaka.com, built from this repository (apps/site) at every change: the packages' homepage (what npm shows) and READMEs point there — @krizaka/tokens to /foundations/tokens, @krizaka/icons to /foundations/icons, @krizaka/fonts to /foundations/typography, the packages without UI to /packages/<name>.

0.4.0

Minor changes

  • #169 c08ae66 Thanks @oussamaABID! - Two named ESLint rules for the adoption: krizaka/no-light-variant (refuse Tailwind light: in products — tokens do the theming) and krizaka/no-raw-palette (refuse bg-zinc-900, text-violet-400… — use a role; allow families for isolated cases), registered on the krizaka plugin and shipped as warnings by krizakaUiWarnings() (@krizaka/config/eslint/ui-warnings). krizaka-ratchet already counts the same patterns (light, palette): a product adopts the warnings now and brings both counts to 0. krizakaUi() stays the strict set.

0.3.1

Patch changes

  • #143 d0e43fd Thanks @oussamaABID! - Package homepage points to the documentation on krizaka.com (the page the npm listing links to is the one that explains the package).

0.3.0

Minor changes

  • #129 86484f5 Thanks @oussamaABID! - krizaka/env-name: environment variables are named by bounded context (krizaka/.github#46) — <CONTEXT>_<THING>, never after a product (the organisation's, the repository's own read from its package.json, or one a config names) nor a vendor (BUNNY_, MAILGUN_, GOOGLE_, EXPO_…: a vendor is a value, MAIL_PROVIDER=mailgun). It reads process.env.X, process.env["X"] and import.meta.env.X, sees through NEXT_PUBLIC_ / EXPO_PUBLIC_ / VITE_, lets the platforms' own names through (GITHUB_TOKEN, VERCEL_URL, EAS_BUILD…), and is on in krizakaBase and krizakaNext; envNames({ products, vendors, allow }) (@krizaka/config/eslint/env-names) tunes it. @krizaka/realtime's error and docs name REALTIME_REDIS_URL, @krizaka/push's docs PUSH_ACCESS_TOKEN.

0.2.0

Minor changes

  • #109 406e62c Thanks @oussamaABID! - The stack rules of ADR-001 (TanStack under @krizaka/* facades): krizakaStack() (@krizaka/config/eslint/stack) brings three warnings — krizaka/no-fetch-in-client-effect (a fetch / krizakaFetch in a useEffect of a "use client" file), krizaka/no-direct-tanstack-import (any @tanstack/* import outside a @krizaka/* package) and krizaka/no-local-table-or-form (a <table>, or a <form> of more than one field). krizaka-ratchet counts the same patterns (fetchInClientEffect, directTanstackImport, localTableOrForm) and the imports of the dependencies listed under retire (retiredImport); a lint-ratchet.json without them still checks, and --update records them. New @krizaka/config/dependency-cruiser: the shared boundary (krizaka-no-direct-tanstack) an app extends. Every krizaka/* rule now lives in one plugin object (@krizaka/config/eslint/plugin), so the configs compose.

0.1.0

Minor changes

  • #7 8446ac9 Thanks @oussamaABID! - Initial release: the shared configuration of every Krizaka JavaScript repository — ESLint flat configs (krizakaBase, krizakaNext, the four UI rules krizakaUi(options?) with a palette allowlist, noLocaleTernary), tsconfig bases (base, react-library, next, react-native), Prettier, EditorConfig, and krizaka-ratchet, the counter that fails when the UI debt goes up (--init, --update, --json).

Sur cette page