@smicolon/fasla-ui 0.2.3 → 0.3.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/README.md +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +91 -23
- package/dist/registry/index.js +31 -2
- package/dist/tokens/index.d.ts +75 -6
- package/dist/tokens/index.js +59 -20
- package/package.json +4 -1
- package/registry/blocks/app-shell/AppShell.tsx +1 -1
- package/registry/blocks/data-table/DataTable.test.tsx +61 -0
- package/registry/blocks/data-table/DataTable.tsx +53 -16
- package/registry/blocks/data-table/index.ts +1 -0
- package/registry/blocks/empty-state/EmptyState.test.tsx +12 -0
- package/registry/blocks/empty-state/EmptyState.tsx +22 -31
- package/registry/blocks/form-section/FormSection.tsx +1 -1
- package/registry/blocks/navbar/Navbar.test.tsx +12 -0
- package/registry/blocks/navbar/Navbar.tsx +8 -23
- package/registry/blocks/page-header/PageHeader.tsx +5 -2
- package/registry/blocks/sidebar/Sidebar.tsx +9 -16
- package/registry/blocks/stats-card/StatsCard.tsx +9 -27
- package/registry/effects/animated-gradient/animated-gradient.tsx +23 -8
- package/registry/effects/border-beam/border-beam.tsx +77 -53
- package/registry/effects/effects.test.tsx +266 -0
- package/registry/effects/glow-card/glow-card.tsx +68 -43
- package/registry/effects/shimmer-button/shimmer-button.tsx +62 -23
- package/registry/effects/spotlight/spotlight.tsx +73 -29
- package/registry/effects/text-reveal/index.ts +1 -0
- package/registry/effects/text-reveal/text-reveal.test.tsx +66 -0
- package/registry/effects/text-reveal/text-reveal.tsx +68 -21
- package/registry/effects/typewriter-text/typewriter-text.tsx +41 -22
- package/registry/text-props-undefined.test.tsx +73 -0
- package/registry/ui/avatar/avatar.test.tsx +316 -0
- package/registry/ui/avatar/avatar.tsx +235 -108
- package/registry/ui/avatar/index.ts +1 -1
- package/registry/ui/badge/badge.test.tsx +267 -32
- package/registry/ui/badge/badge.tsx +233 -21
- package/registry/ui/button/button.test.tsx +6 -0
- package/registry/ui/button/button.tsx +6 -23
- package/registry/ui/card/card.tsx +1 -1
- package/registry/ui/checkbox/checkbox.tsx +13 -26
- package/registry/ui/combobox/combobox.test.tsx +43 -0
- package/registry/ui/combobox/combobox.tsx +27 -55
- package/registry/ui/input/input.test.tsx +2 -2
- package/registry/ui/input/input.tsx +4 -4
- package/registry/ui/radio/index.ts +1 -0
- package/registry/ui/radio/radio.test.tsx +248 -0
- package/registry/ui/radio/radio.tsx +208 -0
- package/registry/ui/select/select.tsx +4 -14
- package/registry/ui/skeleton/skeleton.tsx +1 -1
- package/registry/ui/status-indicator/index.ts +6 -0
- package/registry/ui/status-indicator/status-indicator.test.tsx +148 -0
- package/registry/ui/status-indicator/status-indicator.tsx +87 -0
- package/registry/ui/switch/index.ts +1 -1
- package/registry/ui/switch/switch.test.tsx +323 -0
- package/registry/ui/switch/switch.tsx +254 -57
- package/registry/ui/textarea/textarea.tsx +1 -1
- package/registry.json +435 -78
- package/tailwind-preset.ts +143 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import plugin from "tailwindcss/plugin"
|
|
2
|
+
import type { Config } from "tailwindcss"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shared typography preset — the single place the Fasla type system lives.
|
|
6
|
+
*
|
|
7
|
+
* Every value here is read from the `Tailwind En/*` and `Tailwind AR/*` text
|
|
8
|
+
* styles in the Fasla Figma file. Figma is the source of truth: nothing in this
|
|
9
|
+
* file is rounded, averaged or invented. If a value looks wrong, fix the style
|
|
10
|
+
* in Figma and mirror it here — never the other way round.
|
|
11
|
+
*
|
|
12
|
+
* Geist carries LTR, Cairo carries RTL. The two ramps are 1:1 by size and
|
|
13
|
+
* deliberately not 1:1 by line-height — Cairo needs more vertical room for
|
|
14
|
+
* descenders and diacritics.
|
|
15
|
+
*
|
|
16
|
+
* Line-height is delivered as a CSS variable per rung, so `[dir="rtl"]`
|
|
17
|
+
* re-points the whole ramp at once. That is what makes every `text-*` utility
|
|
18
|
+
* direction-aware without a single component knowing about it.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Line-height as Figma states it: a px value against a px size.
|
|
23
|
+
*
|
|
24
|
+
* It is emitted as `calc(lineHeight / fontSize)` — a unitless ratio, so it
|
|
25
|
+
* stays correct when a rung is used at a responsive size, and exact, because
|
|
26
|
+
* CSS does the division at full precision. Eight of these ratios are
|
|
27
|
+
* non-terminating (18→26 is 1.444…), so writing them as decimals would mean
|
|
28
|
+
* rounding a source-of-truth value. calc() avoids that entirely.
|
|
29
|
+
*
|
|
30
|
+
* `null` means Figma has the rung on AUTO — the font's own metrics, which CSS
|
|
31
|
+
* spells `normal`. No rung is currently on AUTO: all 144 styles are bound, in
|
|
32
|
+
* both scripts, at every size. The mechanism stays because AUTO is a legitimate
|
|
33
|
+
* choice Figma can express, and a rung may return to it.
|
|
34
|
+
*/
|
|
35
|
+
const LEADING = {
|
|
36
|
+
// size En AR
|
|
37
|
+
// XXS is the one rung below Tailwind's stock scale. Figma binds En to
|
|
38
|
+
// `typography/line-height/L-neg-0,5` (14) and AR to `L-0` (16).
|
|
39
|
+
xxs: /* 10 */ [/* 14 */ 14, /* 16 */ 16],
|
|
40
|
+
xs: /* 12 */ [/* 16 */ 16, /* 20 */ 20],
|
|
41
|
+
sm: /* 14 */ [/* 20 */ 20, /* 24 */ 24],
|
|
42
|
+
base: /* 16 */ [/* 24 */ 24, /* 28 */ 28],
|
|
43
|
+
lg: /* 18 */ [/* 28 */ 28, /* 32 */ 32],
|
|
44
|
+
xl: /* 20 */ [/* 28 */ 28, /* 36 */ 36],
|
|
45
|
+
"2xl": /* 24 */ [/* 32 */ 32, /* 40 */ 40],
|
|
46
|
+
"3xl": /* 30 */ [/* 40 */ 40, /* 50 */ 50],
|
|
47
|
+
"4xl": /* 36 */ [/* 44 */ 44, /* 60 */ 60],
|
|
48
|
+
"5xl": /* 48 */ [/* 58 */ 58, /* 72 */ 72],
|
|
49
|
+
"6xl": /* 60 */ [/* 72 */ 72, /* 90 */ 90],
|
|
50
|
+
"7xl": /* 72 */ [/* 90 */ 90, /* 108 */ 108],
|
|
51
|
+
"8xl": /* 96 */ [/* 108 */ 108, /* 144 */ 144],
|
|
52
|
+
"9xl": /* 128 */ [/* 144 */ 144, /* 192 */ 192],
|
|
53
|
+
// `Extra/*` — two styles that sit outside the XXS–9XL ramp but are part of it.
|
|
54
|
+
// Weight, underline and case are left to the ordinary utilities: `Extra/Link`
|
|
55
|
+
// is 400 + underline, `Extra/List Header` is 500 + uppercase. Uppercase is
|
|
56
|
+
// English-only; Arabic has no uppercase and must never be given one.
|
|
57
|
+
link: /* 16 */ [/* 24 */ 24, /* 24 */ 24],
|
|
58
|
+
"list-header": /* 14 */ [/* 16 */ 16, /* 16 */ 16],
|
|
59
|
+
} as const satisfies Record<string, readonly [number | null, number | null]>
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Figma's size scale. From XS up it matches Tailwind's own scale 1:1; XXS
|
|
63
|
+
* (10px, `typography/font-size/xxs`) is Fasla's addition below it.
|
|
64
|
+
*/
|
|
65
|
+
const SIZE_PX = {
|
|
66
|
+
xxs: 10,
|
|
67
|
+
xs: 12,
|
|
68
|
+
sm: 14,
|
|
69
|
+
base: 16,
|
|
70
|
+
lg: 18,
|
|
71
|
+
xl: 20,
|
|
72
|
+
"2xl": 24,
|
|
73
|
+
"3xl": 30,
|
|
74
|
+
"4xl": 36,
|
|
75
|
+
"5xl": 48,
|
|
76
|
+
"6xl": 60,
|
|
77
|
+
"7xl": 72,
|
|
78
|
+
"8xl": 96,
|
|
79
|
+
"9xl": 128,
|
|
80
|
+
link: 16,
|
|
81
|
+
"list-header": 14,
|
|
82
|
+
} as const
|
|
83
|
+
|
|
84
|
+
type Rung = keyof typeof LEADING
|
|
85
|
+
|
|
86
|
+
const rungs = Object.keys(LEADING) as Rung[]
|
|
87
|
+
|
|
88
|
+
const rem = (px: number) => `${px / 16}rem`
|
|
89
|
+
const cssVar = (rung: Rung) => `--leading-${rung}`
|
|
90
|
+
|
|
91
|
+
/** Exact, unitless, and never rounded — CSS divides at full precision. */
|
|
92
|
+
const ratio = (leadingPx: number, sizePx: number) => `calc(${leadingPx} / ${sizePx})`
|
|
93
|
+
|
|
94
|
+
/** `text-xl` resolves its leading through the variable, never a literal. */
|
|
95
|
+
const fontSize = Object.fromEntries(
|
|
96
|
+
rungs.map((rung) => [rung, [rem(SIZE_PX[rung]), `var(${cssVar(rung)})`]])
|
|
97
|
+
) as Record<Rung, [string, string]>
|
|
98
|
+
|
|
99
|
+
const leadingFor = (index: 0 | 1) =>
|
|
100
|
+
Object.fromEntries(
|
|
101
|
+
rungs.map((rung) => {
|
|
102
|
+
const px = LEADING[rung][index]
|
|
103
|
+
return [cssVar(rung), px === null ? "normal" : ratio(px, SIZE_PX[rung])]
|
|
104
|
+
})
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Figma sets `letterSpacing` to 0% on all 144 text styles, both scripts, every
|
|
109
|
+
* weight — so the ramp declares no tracking and components should set none.
|
|
110
|
+
* Tailwind's stock `tracking-*` scale is left in place for the one sanctioned
|
|
111
|
+
* exception, the letter-spaced eyebrow that design/DESIGN.md documents as
|
|
112
|
+
* deliberately detached. Reach for it only for that.
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
const preset = {
|
|
116
|
+
content: [],
|
|
117
|
+
theme: {
|
|
118
|
+
extend: {
|
|
119
|
+
fontFamily: {
|
|
120
|
+
// Brand V2.5 §14 — product tier.
|
|
121
|
+
sans: ["var(--font-geist-sans)", "system-ui", "sans-serif"],
|
|
122
|
+
mono: ["var(--font-geist-mono)", "ui-monospace", "monospace"],
|
|
123
|
+
// Brand V2.5 §14 — the Arabic face. Geist has no Arabic coverage.
|
|
124
|
+
arabic: ["var(--font-cairo)", "system-ui", "sans-serif"],
|
|
125
|
+
},
|
|
126
|
+
fontSize,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
plugins: [
|
|
130
|
+
plugin(({ addBase }) => {
|
|
131
|
+
addBase({
|
|
132
|
+
":root": leadingFor(0),
|
|
133
|
+
// Source order matters: same specificity as `:root`, so this must win by
|
|
134
|
+
// coming second. `dir` is on a wrapper element, not <html>, in both apps —
|
|
135
|
+
// the variables cascade down from wherever it sits.
|
|
136
|
+
'[dir="rtl"]': leadingFor(1),
|
|
137
|
+
})
|
|
138
|
+
}),
|
|
139
|
+
],
|
|
140
|
+
} satisfies Config
|
|
141
|
+
|
|
142
|
+
export { LEADING, SIZE_PX }
|
|
143
|
+
export default preset
|