@feugene/granularity-code
Releases of @feugene/granularity-code from its CHANGELOG: the latest 8 in full, the earlier ones as a list of versions.
v1.1.02026-10-16
Changed
- Peer
@feugene/granum—>=2.0.0 <3.0.0. Пакет собран granum 2.0:distне импортирует granum — контракт встроен вdist/granum/contract.js, и SSR-сервер с внешними пакетами, задеплоенный с--omit=dev, больше не падает сERR_MODULE_NOT_FOUND. Приложению —@feugene/granumи@feugene/granum-engine-wind^2.0.0. - Компонент из корня пакета —
ComponentRootImportErrorу приложения на granum 2.0. Компоненты берут из<пакет>/components/<Имя>. - Авто-импорт — один
GranularityResolver()из@feugene/unplugin-granularity1.1: он находит пакет вpackage.jsonприложения сам, порядок резолверов больше не важен. Собственный./resolverостаётся для уже написанных конфигов. - Необязательный peer
@feugene/fint-i18n—>=0.9.0 <1.0.0. Пакет тестируется на 0.9 вместе с ядром; на 0.7 и 0.8 он не проверялся.
v1.0.42026-10-13
Fixed
- Подписи пропуска
GrDiffбез i18n согласуют число. Словари пакета держат формыone/other, а встроенный запасной текст был одной строкой во множественном числе: приложение без адаптера i18n показывало «Show 1 more lines». Теперь запасной английский текст выбирает форму сам — уexpand,expandTop,expandBottomиhidden.
v1.0.32026-10-06
Fixed
- Замечания
validateуGrCodeEditorвидны в тексте. Проп обещал «подчёркивание в месте и метку в жёлобе», а декорации строились только для ролей подсветки: замечание было лишь пунктом списка под полем. Теперь у каждого замечания волнистое подчёркивание на[from, to)в тоне важности (точечное расширяется до символа), метка в отдельной колонке жёлоба на его строке с текстом вtitle, а пункт списка начинается со строки и столбца («Line 3, column 11 — Error: …»). Колонка держит ширину, пока заданvalidate; ответ асинхронногоvalidateдоезжает до подчёркивания тоже. Цвета — хуки--gr-code-editor-issue-error/-warning/-infoповерх ролей текста тонов, без темы CodeMirror. - Сбой сериализации
GrCodeBlockпортит только своё значение. ШтатныйJSON.stringifyзовётtoJSONраньшеreplacer, и один враждебныйtoJSONобрывал весь вызов: объект с ошибкой, релизом,BigInt-идентификатором, циклическим запросом и полемcustomer, чейtoJSONбросает, печатался одной строкой[Unserializable]. Теперь значение обходится своим кодом,toJSONи чтение каждого поля идут в своёмtry, и маркер"[Unserializable]"встаёт только на место упавшего значения — соседи,[Circular]иBigIntсnостаются. Так же для геттеров, которые бросают, и дляGrDiff(serializeStable).
Documentation
- Появились описания у пропов, событий и методов
GrCodeBlock,GrCodeEditorиGrDiff, которые в API и на портале были пустыми.
v1.0.22026-10-06
Changed
- Safelist компонентов пуст. Все записи лежали в коде целыми литералами —
в шаблонах и
.ts-хелперах, включая общую поверхностьinternal/codeSurface.ts. granum извлекает такие классы сам, обходя от входа компонента все его чанки, общие включительно, и вычищал записи из манифеста как уже извлечённые. Списки пережили UnoCSS-пресет, который общий чанк не сканировал. Набор классов не изменился — проверено сверкой манифестов по селекции каждого компонента; расходятся только случайные токены, которые экстрактор выхватывает из минифицированного кода. - Удалён
internal/classTokens.ts: он служил только спискам. - Подключён гейт
defineSafelistGateиз test-kit: запись safelist, которая лежит целым литералом в коде компонента, он называет лишней. Нужен safelist только классу, собранному в рантайме из частей.
v1.0.12026-09-29
Починка доставки CSS. Публичная поверхность не менялась, обновление безопасное.
Fixed
-
CSS компонента больше не доставляется дважды. Сборка пакета звала
libInjectCss(), и тот вписывал в JS-чанк каждого компонентаimport '../styles.css'. До granum это был единственный канал доставки стилей. С granum тот же файл приезжает приложению через манифест (css: ['components/<Name>/styles.css']), и вместе выходила двойная доставка: один и тот же CSS в общем листе и отдельным чанком.Второй экземпляр был хуже, чем лишние байты. Он приезжал вне слоёв
granum.*, а незаслоённый CSS бьёт любой@layerнезависимо от специфичности, — то есть стили компонента становились сильнее всей библиотеки, и переопределить их из приложения было нечем.Ядро сняло плагин при переезде на granum, спутники остались на старом конфиге. Предупреждение
css-double-delivery(INV-CSS-5) этого не поймало: granum смотрит бандл раньше, чемlibInjectCssвписывает импорт, — вchunk.codeна тот момент его ещё нет.
Changed
- Веса гранулярных импортов пересчитаны: CSS больше не считается в entry. Стили от этого никуда не делись — их доставляет granum.
v1.0.02026-09-28
Переезд на @feugene/granum 1.0 и первый мажор пакета.
Публичная поверхность не менялась — ломающий тут сам конвейер: peer-зависимость
уезжает с @feugene/unocss-preset-granular на @feugene/granum
(>=1.0.0 <2.0.0), а приложение переходит с uno.config.ts на
granum.config.ts. Версия выровнена с ядром: @feugene/granularity 1.0.0.
Перед обновлением стоит прочитать руководство по переезду в granum — в частности про каскадные слои и сброс браузерных стилей, который теперь нужно импортировать в слой.
Changed
yarn doctorisgranum doctor --strict, without a wrapper script.scripts/granum-doctor.mjsexisted for two reasons and both are gone. It mutedtoken-undefinedthrough the monorepo’s token registry — granum 0.4.0 derives the same verdict from the code itself (a use with a fallback, a token the component assigns itself anddynamicTokensare not findings), so the registry is unnecessary. And it kept recorded debt from failing the gate — that is now--allow=<codes>. Findings across the eight packages went from 861 to 1, and that one is the deliberate!importanton the drag cursor inGrTransfer, recorded through--allow.- Safelists in the manifests shrank from 3479 entries to 430 (zero in every companion): granum drops entries that static extraction already covers. Nothing in the sources changed and the CSS is byte-for-byte identical — the safelist there is derived from the component’s own class constants, and whether extraction sees a given class is decided by chunking, not by the author.
- The utility engine changed:
@feugene/granum-engine-wind^0.4.0instead of@feugene/granum-engine-mini. It vendorspreset-wind3rather thanpreset-mini, so the vocabulary gainedborder-collapse,list-none,touch-none,table-fixedandscroll-p*— utilities that existed neither inpreset-mininor in the former extra rules, which is why a class in the markup silently produced no CSS. The package dialect is nowunocss/preset-wind3+granum@66, and the peer on the core moved to>=0.3.0 <1.0.0. A consumer swaps the pair in dev dependencies and replacesminiEngine()withwindEngine()ingranum.config.*. - The package is built by
@feugene/granum, not by the@feugene/unocss-preset-granularpreset. Thedistlayout and the component entries are driven by thegranumProvider({ provider, engine: miniEngine(), entries })plugin: it builds them from the provider registry, extracts the classes and the consumed tokens by walking the bundle graph, and writes a machine-generatedgranum.manifest.jsonnext todist. The package’s ownbuild.lib,granularChunkFileNamesand hand-written component entries are gone fromvite.config.ts. - The manifest is exported as
./granum.manifest.json. An application resolves it through exactly that subpath — without the export the package’s provider cannot be wired up. granum never scansnode_modules: the component classes are computed when the package is built. - The peer changed:
@feugene/granum>=0.2.0 <1.0.0instead of the preset. The utility engine comes from the application (@feugene/granum-engine-minisits in the package’s dev dependencies), while the package declares a vocabulary dialect in the manifest —unocss/preset-mini+granum@66, the vocabulary its component classes are written against. An application running an engine of a different vocabulary getsprovider-dialect-mismatchand every lost class listed by name instead of silently half-drawn components. - The descriptor contract was renamed without a change of meaning.
defineGranularComponent→defineGranumComponent,defineGranularProvider→defineGranumProvider, imported from@feugene/granum/contract. Donors are declared as strings (dependencies: ['@feugene/granularity']) rather than instances: an instance would pull the donor into the graph in object form and make the application scan itsdistinstead of reading the manifest.packageBaseUrlis gone — the manifest’s directory is the base — sogranular-provider/nodeis now a plain alias of the browser entry. granular.options.mjswas replaced bygranum.config.mjs, andyarn doctorrunsgranum doctoragainst the package’s manifests.- Helpers shared by several components moved to
src/components/shared/. An import from another component’s directory counts as a declared edge, and declaring it would make a consumer who picked one component pay for the other’s CSS and safelist in full. The public surface is unchanged: the re-exports from the previous paths are still there.
v0.2.02026-09-01
Added
-
--gr-code-editor-placeholder— hook token for the empty-editor hint colour. -
grCode.diff.lineAdded/grCode.diff.lineRemovedin all three locales.
Fixed
-
The editor placeholder failed AA contrast in both themes.
grThemestyled the background, caret, selection, active line and gutters but left.cm-placeholderto CodeMirror’s built-in#888: 3.2:1 on the light surface and 2.9:1 on the dark one, against the 4.5:1 threshold. It now reads--gr-code-editor-placeholder, defaulting to--gr-muted-fg— 5.7:1 and 5.0:1.Nothing caught it because the showcase page was outside the axe sweep: the package was never wired into
apps/showcase/e2e/components.ts, soGrCodeBlock,GrCodeEditorandGrDiffwere scanned by neither axe nor the visual layer. The sweep now covers them. -
GrCodeEditor: a failed validation moved the form to the editor without putting the caret in it.GrFormfinds the control of a field by selector —input, select, textarea, button, [tabindex]:not([tabindex="-1"])— and that is how bothscrollToFieldand the focus-first-error path work. Acontenteditablenode is focusable withouttabindex, but it does not match that selector, so the form found nothing inside the field at all..cm-contentnow carriestabindex="0", on the same node that carries the role. -
GrDiff: added and removed lines are no longer distinguished by colour alone. The row tone carried the whole message: the+/−sign next to it isaria-hidden, deliberately, so that a screen reader would not read “plus” before every line. The side effect was that it read nothing at all — added, removed and unchanged lines came out identical, and a diff that cannot say what changed is not a diff. Changed lines now carry a visually hidden label (added/removed, translated) in both layouts; context lines stay silent so the marker does not appear on every line of the file. Axe never caught this — roles and contrast were fine all along.
v0.1.12026-08-31
Fixed
- The peer floor on the core is
>=0.41.0, not>=0.40.0.GrCodeBlockleft the core in 0.41.0, so with 0.40.0 installed the component would arrive twice — once from the core barrel and once from here, with two granular providers declaring the same name. The floor now states what the package actually needs.
Earlier versions
The bodies of these releases are not shown: the full feed weighs more than a page is allowed to. The file in the repository is always complete.
v0.1.02026-08-31