@icomponents/tokens 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +28 -0
- package/src/fonts.test.ts +14 -0
- package/src/fonts.ts +17 -0
- package/src/index.ts +9 -0
- package/src/testids.ts +66 -0
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@icomponents/tokens",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Платформо-независимая основа кита: контракт data-testid и набор шрифтов",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./src/index.ts",
|
|
15
|
+
"./testids": "./src/testids.ts",
|
|
16
|
+
"./fonts": "./src/fonts.ts"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"type-check": "bunx tsc --noEmit",
|
|
20
|
+
"test": "bun test"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@icomponents/typescript-config": "workspace:*",
|
|
24
|
+
"@types/bun": "latest",
|
|
25
|
+
"typescript": "latest",
|
|
26
|
+
"@types/node": "latest"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { fonts } from "./fonts";
|
|
4
|
+
|
|
5
|
+
describe("shadcn-admin default fonts", () => {
|
|
6
|
+
it("does not offer any banned font family", () => {
|
|
7
|
+
const banned = ["dm-sans", "barlow-condensed", "roboto", "arial", "space-grotesk"];
|
|
8
|
+
for (const f of fonts) expect(banned).not.toContain(f);
|
|
9
|
+
});
|
|
10
|
+
it("offers the shadcn-admin default families", () => {
|
|
11
|
+
expect(fonts).toContain("inter");
|
|
12
|
+
expect(fonts).toContain("manrope");
|
|
13
|
+
});
|
|
14
|
+
});
|
package/src/fonts.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List of available font names (visit the url `/settings/appearance`).
|
|
3
|
+
* This array is used to generate dynamic font classes (e.g., `font-inter`,
|
|
4
|
+
* `font-manrope`).
|
|
5
|
+
*
|
|
6
|
+
* 📝 How to Add a New Font (Tailwind v4+):
|
|
7
|
+
* 1. Add the font name here (kebab-case, e.g. 'jetbrains-mono').
|
|
8
|
+
* 2. Update the `<link>` tag in 'index.html' to load the family from Google Fonts.
|
|
9
|
+
* 3. Add the family to 'theme.css' via `@theme inline`, e.g.:
|
|
10
|
+
* @theme inline {
|
|
11
|
+
* // ... other font families
|
|
12
|
+
* --font-jetbrains-mono: "JetBrains Mono", monospace;
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* shadcn-admin default type set.
|
|
16
|
+
*/
|
|
17
|
+
export const fonts = ["inter", "manrope", "system"] as const;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Платформо-независимая основа кита.
|
|
3
|
+
*
|
|
4
|
+
* Здесь только то, что одинаково для веба и React Native: контракт `data-testid`, на который
|
|
5
|
+
* опирается приёмка, и список шрифтов. Ни одного импорта React — иначе пакет перестанет быть
|
|
6
|
+
* общим ровно в тот момент, когда появится вторая реализация.
|
|
7
|
+
*/
|
|
8
|
+
export * from "./fonts";
|
|
9
|
+
export * from "./testids";
|
package/src/testids.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* КОНТРАКТ ВЁРСТКИ: устойчивые `data-testid`.
|
|
3
|
+
*
|
|
4
|
+
* Зачем он существует. Дизайн меняют двумя способами, и второй ломает всё, что цепляется за наш DOM:
|
|
5
|
+
*
|
|
6
|
+
* 1. Перекраска (shadcn / Base UI): меняются токены и классы — разметка остаётся нашей.
|
|
7
|
+
* 2. Готовая вёрстка прототипа: разметка ЗАМЕНЯЕТСЯ ЦЕЛИКОМ, и в неё вайрится наша логика.
|
|
8
|
+
*
|
|
9
|
+
* Во втором случае тест, написанный по классу (`.btn-primary`), по тексту («Добавить запись») или по
|
|
10
|
+
* структуре (`table > tbody > tr`), покраснеет весь разом — и не докажет ничего: он покраснел не
|
|
11
|
+
* потому, что сломалась функция, а потому, что дизайнер иначе назвал кнопку. Такой набор тестов после
|
|
12
|
+
* редизайна просто выключают — а сеть нужна ровно тогда.
|
|
13
|
+
*
|
|
14
|
+
* Поэтому контракт один и явный: **новая вёрстка обязана нести эти `data-testid`**. Тогда прогон
|
|
15
|
+
* означает то, что должен: экран смонтировался, список отдал строки, разрушительное действие
|
|
16
|
+
* спрашивает подтверждение. Подписи, цвета и структура — свободны.
|
|
17
|
+
*
|
|
18
|
+
* Правила:
|
|
19
|
+
* — ID стабилен. Переименование = поломка контракта, а не «мелкая правка».
|
|
20
|
+
* — ID описывает РОЛЬ элемента, а не его вид: `table-empty`, а не `grey-box`.
|
|
21
|
+
* — Для строк списка — `row-<id>`, чтобы тест мог адресовать конкретную сущность.
|
|
22
|
+
*
|
|
23
|
+
* ЗДЕСЬ ТОЛЬКО ОБЩЕЕ. Ядро знает про экран, навигацию, список, форму и вход — то есть про то, что
|
|
24
|
+
* есть у любого приложения. Хваталки СВОИХ действий (`plan-subscribe-*`, `role-save-*`) объявляет
|
|
25
|
+
* слайс, который ими владеет, — в своём пакете, рядом с экраном: `@app/<пакет>/testids`. Складывать
|
|
26
|
+
* их сюда значило бы, что ядро знает про биллинг продукта, а `sync-core.sh` затирал бы их при каждом
|
|
27
|
+
* обновлении ядра.
|
|
28
|
+
*/
|
|
29
|
+
export const TESTID = {
|
|
30
|
+
/** Корень экрана. Есть = экран смонтировался (а не отрисовался пустой каркас или экран ошибки). */
|
|
31
|
+
screen: "screen",
|
|
32
|
+
/** Заголовок экрана. */
|
|
33
|
+
screenTitle: "screen-title",
|
|
34
|
+
/** Главное действие экрана: «Добавить запись», «Создать проект» и т. п. */
|
|
35
|
+
screenPrimaryAction: "screen-primary-action",
|
|
36
|
+
|
|
37
|
+
/** Навигация. Пропала — человек заперт на одном экране, и это не «косметика». */
|
|
38
|
+
nav: "nav",
|
|
39
|
+
navItem: (key: string) => `nav-item-${key}`,
|
|
40
|
+
|
|
41
|
+
/** Таблица/список. */
|
|
42
|
+
table: "table",
|
|
43
|
+
tableRow: (id: string) => `row-${id}`,
|
|
44
|
+
/** Пустое состояние. Молчащая пустая таблица читается как «данные грузятся» — и человек ждёт зря. */
|
|
45
|
+
tableEmpty: "table-empty",
|
|
46
|
+
|
|
47
|
+
/** Диалог подтверждения разрушительного действия. */
|
|
48
|
+
confirmDialog: "confirm-dialog",
|
|
49
|
+
confirmAccept: "confirm-accept",
|
|
50
|
+
confirmCancel: "confirm-cancel",
|
|
51
|
+
|
|
52
|
+
/** Форма в панели/диалоге. */
|
|
53
|
+
formSubmit: "form-submit",
|
|
54
|
+
formError: "form-error",
|
|
55
|
+
/** Поле формы по имени: `field-email`. Позволяет тесту заполнить форму, не зная её вёрстки. */
|
|
56
|
+
field: (name: string) => `field-${name}`,
|
|
57
|
+
|
|
58
|
+
/** Вход/выход. */
|
|
59
|
+
signIn: "sign-in",
|
|
60
|
+
signOut: "sign-out",
|
|
61
|
+
/** Переключение «вход ↔ регистрация» на экране входа. */
|
|
62
|
+
signUpToggle: "sign-up-toggle",
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
/** Готовый атрибут: `<div {...testid(TESTID.screen)}>`. */
|
|
66
|
+
export const testid = (id: string): { "data-testid": string } => ({ "data-testid": id });
|