@kashi-ui/tokens 0.5.0 → 0.6.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/dist/index.d.ts CHANGED
@@ -1,19 +1,20 @@
1
1
  export declare const font: {
2
2
  "family": {
3
3
  "sans": "\"Vazirmatn\", \"Vazir\", Tahoma, system-ui, sans-serif",
4
+ "display": "var(--k-font-sans)",
4
5
  "mono": "ui-monospace, \"SF Mono\", Menlo, Consolas, \"Vazirmatn\", monospace"
5
6
  },
6
7
  "size": {
7
- "xs": "0.75rem",
8
- "sm": "0.875rem",
9
- "md": "0.9375rem",
10
- "lg": "1.0625rem",
11
- "xl": "1.25rem",
12
- "2xl": "1.5rem",
13
- "3xl": "1.875rem",
14
- "4xl": "2.25rem",
15
- "5xl": "3rem",
16
- "6xl": "3.75rem"
8
+ "xs": "calc(0.75rem * var(--k-text-scale))",
9
+ "sm": "calc(0.875rem * var(--k-text-scale))",
10
+ "md": "calc(0.9375rem * var(--k-text-scale))",
11
+ "lg": "calc(1.0625rem * var(--k-text-scale))",
12
+ "xl": "calc(1.25rem * var(--k-text-scale))",
13
+ "2xl": "calc(1.5rem * var(--k-text-scale))",
14
+ "3xl": "calc(1.875rem * var(--k-text-scale))",
15
+ "4xl": "calc(2.25rem * var(--k-text-scale))",
16
+ "5xl": "calc(3rem * var(--k-text-scale))",
17
+ "6xl": "calc(3.75rem * var(--k-text-scale))"
17
18
  },
18
19
  "weight": {
19
20
  "light": "300",
@@ -32,7 +33,8 @@ export declare const font: {
32
33
 
33
34
  export declare const knobs: {
34
35
  "radius-factor": "1",
35
- "density": "1"
36
+ "density": "1",
37
+ "text-scale": "1"
36
38
  };
37
39
 
38
40
  export declare const motion: {
@@ -270,6 +272,33 @@ export declare const zIndex: {
270
272
  };
271
273
 
272
274
  export declare function brandScale(color: string): Record<number, string>;
275
+ export declare const FALLBACK_SANS: string;
276
+ /** «IRANSans» را به فهرست کامل با فونت‌های جایگزین تبدیل می‌کند */
277
+ export declare function fontStack(family: string, fallback?: string): string;
278
+
279
+ export interface FontFaceSource {
280
+ url: string;
281
+ /** "woff2" | "woff" | "truetype" | "opentype" */
282
+ format: string;
283
+ }
284
+
285
+ export interface FontFaceOptions {
286
+ /** نام خانوادهٔ فونت، همان که در fontFamily استفاده می‌کنید */
287
+ family: string;
288
+ /** آدرس فایل؛ قالب از پسوند تشخیص داده می‌شود */
289
+ src: string | Array<string | FontFaceSource>;
290
+ /** وزن ثابت (400) یا بازه برای فونت متغیر ("100 900") @default "400" */
291
+ weight?: string | number;
292
+ /** @default "normal" */
293
+ style?: string;
294
+ /** @default "swap" */
295
+ display?: string;
296
+ unicodeRange?: string;
297
+ }
298
+
299
+ /** قاعدهٔ @font-face برای فونت خودمیزبان (رایگان یا خریداری‌شده) */
300
+ export declare function fontFace(options: FontFaceOptions): string;
301
+
273
302
  export interface ThemeOptions {
274
303
  /** رنگ پایهٔ برند (پلهٔ ۵۰۰) یا طیف کامل ۵۰ تا ۹۵۰ */
275
304
  brand?: string | Record<number, string>;
@@ -277,7 +306,16 @@ export interface ThemeOptions {
277
306
  radius?: number;
278
307
  /** ضریب تراکم — 0.875 فشرده، 1 عادی، 1.125 جادار */
279
308
  density?: number;
309
+ /** فونت متن؛ نام تنها («IRANSans») خودکار با فونت‌های جایگزین کامل می‌شود */
280
310
  fontFamily?: string;
311
+ /** فونت عنوان‌ها (h1 تا h6)؛ پیش‌فرض همان fontFamily */
312
+ displayFontFamily?: string;
313
+ /** فونت کد */
314
+ monoFontFamily?: string;
315
+ /** ضریب اندازهٔ همهٔ متن‌ها؛ مثلاً 0.95 برای فونتی که درشت‌تر دیده می‌شود */
316
+ textScale?: number;
317
+ /** فایل‌های فونت برای ساخت @font-face */
318
+ fonts?: FontFaceOptions[];
281
319
  /** پیش‌فرض ":root" */
282
320
  selector?: string;
283
321
  }
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export * from "./tokens.js";
2
- export { createTheme } from "./theme.js";
2
+ export { createTheme, brandScale, fontFace, fontStack, FALLBACK_SANS } from "./theme.js";
package/dist/theme.js CHANGED
@@ -1,4 +1,4 @@
1
- // ساخت تم سفارشی: یک رنگ برند می‌گیرد و CSS آماده برمی‌گرداند.
1
+ // ساخت تم سفارشی: رنگ برند، گردی، تراکم و فونت‌ها را می‌گیرد و CSS آماده برمی‌گرداند.
2
2
  // import { createTheme } from "@kashi-ui/tokens";
3
3
  // const css = createTheme({ brand: "#7c3aed", radius: 1.5, density: 0.875 });
4
4
 
@@ -6,6 +6,9 @@ const STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
6
6
  // درصد اختلاط با سفید (مثبت) یا سیاه (منفی) برای هر پله نسبت به رنگ پایه (۵۰۰)
7
7
  const MIX = { 50: 92, 100: 82, 200: 64, 300: 44, 400: 22, 500: 0, 600: -18, 700: -34, 800: -48, 900: -60, 950: -76 };
8
8
 
9
+ /** فونت‌های جایگزین وقتی فونت اصلی هنوز بارگذاری نشده یا حرفی را ندارد */
10
+ export const FALLBACK_SANS = '"Vazirmatn", Tahoma, system-ui, sans-serif';
11
+
9
12
  /** یک طیف ۱۱ پله‌ای از یک رنگ می‌سازد (با color-mix در فضای oklch) */
10
13
  export function brandScale(color) {
11
14
  return Object.fromEntries(
@@ -17,15 +20,50 @@ export function brandScale(color) {
17
20
  );
18
21
  }
19
22
 
23
+ const quote = (name) => (/^["']|^[\w-]+$/.test(name) && !/\s/.test(name) ? name : `"${name.replace(/"/g, "")}"`);
24
+
25
+ /** «IRANSans» → '"IRANSans", "Vazirmatn", Tahoma, …'؛ فهرست کامل (با کاما) دست‌نخورده می‌ماند */
26
+ export function fontStack(family, fallback = FALLBACK_SANS) {
27
+ return family.includes(",") ? family : `${quote(family.trim())}, ${fallback}`;
28
+ }
29
+
30
+ /** قاعدهٔ @font-face برای فونتی که فایلش را خودتان میزبانی می‌کنید (رایگان یا خریداری‌شده) */
31
+ export function fontFace({ family, src, weight = "400", style = "normal", display = "swap", unicodeRange }) {
32
+ const sources = (Array.isArray(src) ? src : [src])
33
+ .map((s) => {
34
+ const url = typeof s === "string" ? s : s.url;
35
+ const format = typeof s === "string" ? (url.match(/\.(woff2?|ttf|otf)(\?|#|$)/)?.[1] ?? "woff2") : s.format;
36
+ const fmt = { woff2: "woff2", woff: "woff", ttf: "truetype", otf: "opentype" }[format] ?? format;
37
+ return `url("${url}") format("${fmt}")`;
38
+ })
39
+ .join(",\n ");
40
+ return [
41
+ "@font-face {",
42
+ ` font-family: ${quote(family)};`,
43
+ ` src: ${sources};`,
44
+ ` font-weight: ${weight};`,
45
+ ` font-style: ${style};`,
46
+ ` font-display: ${display};`,
47
+ unicodeRange ? ` unicode-range: ${unicodeRange};` : null,
48
+ "}",
49
+ ].filter(Boolean).join("\n");
50
+ }
51
+
20
52
  /**
21
53
  * @param {object} o
22
54
  * @param {string | Record<string,string>} [o.brand] رنگ پایه یا طیف کامل
23
55
  * @param {number} [o.radius] ضریب گردی گوشه‌ها
24
56
  * @param {number} [o.density] ضریب تراکم
25
- * @param {string} [o.fontFamily] فونت جایگزین
57
+ * @param {string} [o.fontFamily] فونت متن، مثل "IRANSans" یا یک فهرست کامل
58
+ * @param {string} [o.displayFontFamily] فونت عنوان‌ها
59
+ * @param {string} [o.monoFontFamily] فونت کد
60
+ * @param {number} [o.textScale] ضریب اندازهٔ متن‌ها
61
+ * @param {object[]} [o.fonts] فایل‌های فونت برای ساخت @font-face
26
62
  * @param {string} [o.selector] انتخاب‌گر CSS، پیش‌فرض :root
27
63
  */
28
- export function createTheme({ brand, radius, density, fontFamily, selector = ":root" } = {}) {
64
+ export function createTheme({
65
+ brand, radius, density, fontFamily, displayFontFamily, monoFontFamily, textScale, fonts = [], selector = ":root",
66
+ } = {}) {
29
67
  const vars = {};
30
68
  if (brand) {
31
69
  const scale = typeof brand === "string" ? brandScale(brand) : brand;
@@ -33,7 +71,12 @@ export function createTheme({ brand, radius, density, fontFamily, selector = ":r
33
71
  }
34
72
  if (radius != null) vars["--k-radius-factor"] = String(radius);
35
73
  if (density != null) vars["--k-density"] = String(density);
36
- if (fontFamily) vars["--k-font-sans"] = fontFamily;
74
+ if (textScale != null) vars["--k-text-scale"] = String(textScale);
75
+ if (fontFamily) vars["--k-font-sans"] = fontStack(fontFamily);
76
+ if (displayFontFamily) vars["--k-font-display"] = fontStack(displayFontFamily, "var(--k-font-sans)");
77
+ if (monoFontFamily) vars["--k-font-mono"] = fontStack(monoFontFamily, 'ui-monospace, Menlo, Consolas, "Vazirmatn", monospace');
78
+ const faces = fonts.map(fontFace).join("\n\n");
37
79
  const body = Object.entries(vars).map(([k, v]) => ` ${k}: ${v};`).join("\n");
38
- return `${selector} {\n${body}\n}\n`;
80
+ const rule = body ? `${selector} {\n${body}\n}\n` : "";
81
+ return faces ? `${faces}\n\n${rule}` : rule;
39
82
  }
package/dist/tokens.css CHANGED
@@ -2,6 +2,7 @@
2
2
  :root {
3
3
  --k-radius-factor: 1;
4
4
  --k-density: 1;
5
+ --k-text-scale: 1;
5
6
  --k-firoozeh-50: #e6fbf8;
6
7
  --k-firoozeh-100: #c2f4ee;
7
8
  --k-firoozeh-200: #8ce9df;
@@ -109,17 +110,18 @@
109
110
  --k-radius-2xl: calc(1.5rem * var(--k-radius-factor));
110
111
  --k-radius-full: 9999px;
111
112
  --k-font-sans: "Vazirmatn", "Vazir", Tahoma, system-ui, sans-serif;
113
+ --k-font-display: var(--k-font-sans);
112
114
  --k-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Vazirmatn", monospace;
113
- --k-text-xs: 0.75rem;
114
- --k-text-sm: 0.875rem;
115
- --k-text-md: 0.9375rem;
116
- --k-text-lg: 1.0625rem;
117
- --k-text-xl: 1.25rem;
118
- --k-text-2xl: 1.5rem;
119
- --k-text-3xl: 1.875rem;
120
- --k-text-4xl: 2.25rem;
121
- --k-text-5xl: 3rem;
122
- --k-text-6xl: 3.75rem;
115
+ --k-text-xs: calc(0.75rem * var(--k-text-scale));
116
+ --k-text-sm: calc(0.875rem * var(--k-text-scale));
117
+ --k-text-md: calc(0.9375rem * var(--k-text-scale));
118
+ --k-text-lg: calc(1.0625rem * var(--k-text-scale));
119
+ --k-text-xl: calc(1.25rem * var(--k-text-scale));
120
+ --k-text-2xl: calc(1.5rem * var(--k-text-scale));
121
+ --k-text-3xl: calc(1.875rem * var(--k-text-scale));
122
+ --k-text-4xl: calc(2.25rem * var(--k-text-scale));
123
+ --k-text-5xl: calc(3rem * var(--k-text-scale));
124
+ --k-text-6xl: calc(3.75rem * var(--k-text-scale));
123
125
  --k-weight-light: 300;
124
126
  --k-weight-regular: 400;
125
127
  --k-weight-medium: 500;
package/dist/tokens.js CHANGED
@@ -43,6 +43,8 @@ export const knobs = {
43
43
  "radius-factor": "1",
44
44
  // تراکم: 0.875 = فشرده (مثل Polaris)، 1 = عادی، 1.125 = جادار
45
45
  "density": "1",
46
+ // ضریب اندازهٔ همهٔ متن‌ها؛ برای فونت‌هایی که درشت‌تر یا ریزتر از وزیرمتن دیده می‌شوند
47
+ "text-scale": "1",
46
48
  };
47
49
 
48
50
  /** فاصله‌ها — مضرب ۴ پیکسل */
@@ -58,16 +60,20 @@ export const radius = {
58
60
  none: "0", sm: r(0.25), md: r(0.5), lg: r(0.75), xl: r(1), "2xl": r(1.5), full: "9999px",
59
61
  };
60
62
 
63
+ const t = (rem) => `calc(${rem}rem * var(--k-text-scale))`;
64
+
61
65
  export const font = {
62
66
  family: {
63
67
  sans: '"Vazirmatn", "Vazir", Tahoma, system-ui, sans-serif',
68
+ // فونت عنوان‌ها؛ پیش‌فرض همان فونت متن
69
+ display: "var(--k-font-sans)",
64
70
  // وزیرمتن به‌عنوان جایگزین تا متن فارسی داخل کد هم یکدست باشد
65
71
  mono: 'ui-monospace, "SF Mono", Menlo, Consolas, "Vazirmatn", monospace',
66
72
  },
67
73
  // متن فارسی در اندازه‌های یکسان کمی کوچک‌تر از لاتین دیده می‌شود؛ پایه ۱۵px است
68
74
  size: {
69
- xs: "0.75rem", sm: "0.875rem", md: "0.9375rem", lg: "1.0625rem", xl: "1.25rem",
70
- "2xl": "1.5rem", "3xl": "1.875rem", "4xl": "2.25rem", "5xl": "3rem", "6xl": "3.75rem",
75
+ xs: t(0.75), sm: t(0.875), md: t(0.9375), lg: t(1.0625), xl: t(1.25),
76
+ "2xl": t(1.5), "3xl": t(1.875), "4xl": t(2.25), "5xl": t(3), "6xl": t(3.75),
71
77
  },
72
78
  weight: { light: "300", regular: "400", medium: "500", semibold: "600", bold: "700", black: "900" },
73
79
  // حروف فارسی نقطه و دندانه دارند و به ارتفاع خط بیشتری نیاز دارند
package/dist/tokens.json CHANGED
@@ -2,19 +2,20 @@
2
2
  "font": {
3
3
  "family": {
4
4
  "sans": "\"Vazirmatn\", \"Vazir\", Tahoma, system-ui, sans-serif",
5
+ "display": "var(--k-font-sans)",
5
6
  "mono": "ui-monospace, \"SF Mono\", Menlo, Consolas, \"Vazirmatn\", monospace"
6
7
  },
7
8
  "size": {
8
- "xs": "0.75rem",
9
- "sm": "0.875rem",
10
- "md": "0.9375rem",
11
- "lg": "1.0625rem",
12
- "xl": "1.25rem",
13
- "2xl": "1.5rem",
14
- "3xl": "1.875rem",
15
- "4xl": "2.25rem",
16
- "5xl": "3rem",
17
- "6xl": "3.75rem"
9
+ "xs": "calc(0.75rem * var(--k-text-scale))",
10
+ "sm": "calc(0.875rem * var(--k-text-scale))",
11
+ "md": "calc(0.9375rem * var(--k-text-scale))",
12
+ "lg": "calc(1.0625rem * var(--k-text-scale))",
13
+ "xl": "calc(1.25rem * var(--k-text-scale))",
14
+ "2xl": "calc(1.5rem * var(--k-text-scale))",
15
+ "3xl": "calc(1.875rem * var(--k-text-scale))",
16
+ "4xl": "calc(2.25rem * var(--k-text-scale))",
17
+ "5xl": "calc(3rem * var(--k-text-scale))",
18
+ "6xl": "calc(3.75rem * var(--k-text-scale))"
18
19
  },
19
20
  "weight": {
20
21
  "light": "300",
@@ -32,7 +33,8 @@
32
33
  },
33
34
  "knobs": {
34
35
  "radius-factor": "1",
35
- "density": "1"
36
+ "density": "1",
37
+ "text-scale": "1"
36
38
  },
37
39
  "motion": {
38
40
  "duration": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kashi-ui/tokens",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "توکن‌های طراحی کاشی — رنگ، فاصله، فونت",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,8 @@
22
22
  "*.css"
23
23
  ],
24
24
  "scripts": {
25
- "build": "node contrast.mjs && node build.mjs"
25
+ "build": "node contrast.mjs && node build.mjs",
26
+ "test": "node --test test/*.test.mjs"
26
27
  },
27
28
  "license": "MIT",
28
29
  "repository": {