frutjam 2.0.1 → 2.0.2
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/base.css +2 -2
- package/dist/components/accordion.css +2 -2
- package/dist/components/alert.css +2 -2
- package/dist/components/avatar.css +2 -2
- package/dist/components/badge.css +2 -2
- package/dist/components/breadcrumb.css +2 -2
- package/dist/components/button.css +2 -2
- package/dist/components/card.css +2 -2
- package/dist/components/carousel.css +2 -2
- package/dist/components/chat.css +2 -2
- package/dist/components/checkbox.css +2 -2
- package/dist/components/collapsible.css +2 -2
- package/dist/components/combobox.css +2 -2
- package/dist/components/countdown.css +2 -2
- package/dist/components/diff.css +2 -2
- package/dist/components/divider.css +2 -2
- package/dist/components/drawer.css +2 -2
- package/dist/components/footer.css +2 -2
- package/dist/components/header.css +2 -2
- package/dist/components/hero.css +2 -2
- package/dist/components/indicator.css +2 -2
- package/dist/components/input.css +2 -2
- package/dist/components/join.css +2 -2
- package/dist/components/kbd.css +2 -2
- package/dist/components/link.css +2 -2
- package/dist/components/loading.css +2 -2
- package/dist/components/mask.css +2 -2
- package/dist/components/menu.css +2 -2
- package/dist/components/modal.css +2 -2
- package/dist/components/navbar.css +2 -2
- package/dist/components/popover.css +2 -2
- package/dist/components/progress.css +2 -2
- package/dist/components/radial-progress.css +2 -2
- package/dist/components/radio.css +2 -2
- package/dist/components/range.css +2 -2
- package/dist/components/rating.css +2 -2
- package/dist/components/select.css +2 -2
- package/dist/components/sidebar.css +2 -2
- package/dist/components/skeleton.css +2 -2
- package/dist/components/stat.css +2 -2
- package/dist/components/status.css +2 -2
- package/dist/components/steps.css +2 -2
- package/dist/components/surface.css +2 -2
- package/dist/components/swap.css +2 -2
- package/dist/components/table.css +2 -2
- package/dist/components/tabs.css +2 -2
- package/dist/components/tag.css +2 -2
- package/dist/components/textarea.css +2 -2
- package/dist/components/timeline.css +2 -2
- package/dist/components/toast.css +2 -2
- package/dist/components/toggle.css +2 -2
- package/dist/components/tooltip.css +2 -2
- package/dist/frutjam.min.css +3 -3
- package/dist/plugin.js +52 -5
- package/dist/themes/darkberry.css +1 -1
- package/dist/themes/snowberry.css +1 -1
- package/dist/utilities/headings.css +2 -2
- package/dist/utilities/para.css +2 -2
- package/dist/utilities/typography.css +1 -1
- package/dist/utilities/wrapper.css +2 -2
- package/index.js +43 -0
- package/package.json +4 -4
package/dist/plugin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | MIT License | https://frutjam.com */
|
|
2
2
|
|
|
3
3
|
// Tailwind v4 plugin.withOptions implementation
|
|
4
4
|
const plugin = {
|
|
@@ -67,12 +67,59 @@ function sortUtils(obj) {
|
|
|
67
67
|
)
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
//
|
|
70
|
+
// Split a comma-separated selector list by top-level commas (ignores commas inside parentheses)
|
|
71
|
+
function splitTopLevelCommas(str) {
|
|
72
|
+
const parts = []
|
|
73
|
+
let depth = 0, start = 0
|
|
74
|
+
for (let i = 0; i < str.length; i++) {
|
|
75
|
+
if (str[i] === '(') depth++
|
|
76
|
+
else if (str[i] === ')') depth--
|
|
77
|
+
else if (str[i] === ',' && depth === 0) {
|
|
78
|
+
parts.push(str.slice(start, i))
|
|
79
|
+
start = i + 1
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
parts.push(str.slice(start))
|
|
83
|
+
return parts
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Scope one part of a comma-separated selector list to rootSelector.
|
|
87
|
+
// Returns an array of replacement selectors.
|
|
88
|
+
// [data-theme] selectors become compound with rootSelector so theme variables
|
|
89
|
+
// only apply when data-theme is set directly on the root element — no ancestor
|
|
90
|
+
// inheritance, which would break the isolation guarantee of the root option.
|
|
91
|
+
function scopeThemePart(part, rootSelector) {
|
|
92
|
+
const t = part.trimStart()
|
|
93
|
+
const lead = part.slice(0, part.length - t.length)
|
|
94
|
+
if (t.startsWith(rootSelector)) return [part]
|
|
95
|
+
if (t.startsWith(':is([data-theme')) {
|
|
96
|
+
const values = []
|
|
97
|
+
const re = /\[data-theme=["']([^"']+)["']\]/g
|
|
98
|
+
let m
|
|
99
|
+
while ((m = re.exec(t)) !== null) values.push(m[1])
|
|
100
|
+
return values.map(function(v) { return lead + rootSelector + '[data-theme="' + v + '"]' })
|
|
101
|
+
}
|
|
102
|
+
if (/^\[data-theme=/.test(t)) {
|
|
103
|
+
const m = t.match(/^\[data-theme=["']([^"']+)["']\]/)
|
|
104
|
+
if (m) return [lead + rootSelector + '[data-theme="' + m[1] + '"]']
|
|
105
|
+
}
|
|
106
|
+
if (t.startsWith('[data-theme]')) {
|
|
107
|
+
return [lead + rootSelector + '[data-theme]']
|
|
108
|
+
}
|
|
109
|
+
return [part]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Recursively remap :root and scope [data-theme] selectors to a custom root selector
|
|
71
113
|
function remapRoot(obj, rootSelector) {
|
|
72
114
|
if (!rootSelector || rootSelector === ":root") return obj
|
|
73
115
|
return Object.fromEntries(
|
|
74
116
|
Object.entries(obj).map(([k, v]) => {
|
|
75
|
-
|
|
117
|
+
let newKey = k.replace(/:root\b/g, rootSelector)
|
|
118
|
+
if (!newKey.startsWith('@')) {
|
|
119
|
+
newKey = splitTopLevelCommas(newKey).flatMap(function(part) {
|
|
120
|
+
return scopeThemePart(part, rootSelector)
|
|
121
|
+
}).join(',')
|
|
122
|
+
}
|
|
76
123
|
const newVal = (v && typeof v === "object") ? remapRoot(v, rootSelector) : v
|
|
77
124
|
return [newKey, newVal]
|
|
78
125
|
})
|
|
@@ -103,7 +150,7 @@ export default plugin.withOptions(
|
|
|
103
150
|
if (logs) {
|
|
104
151
|
const d = "\x1b[2m", r = "\x1b[0m"
|
|
105
152
|
const badge = "\x1b[46m\x1b[30m frutjam \x1b[0m"
|
|
106
|
-
console.log("\n" + badge + " " + d + "v2.0.
|
|
153
|
+
console.log("\n" + badge + " " + d + "v2.0.2" + r + "\n")
|
|
107
154
|
}
|
|
108
155
|
|
|
109
156
|
// Base
|
|
@@ -112,7 +159,7 @@ export default plugin.withOptions(
|
|
|
112
159
|
// Themes
|
|
113
160
|
const activeThemes = Array.isArray(themes) ? themes : [themes]
|
|
114
161
|
for (const [name, styles] of Object.entries(THEMES)) {
|
|
115
|
-
if (activeThemes.includes(name)) addBase(styles)
|
|
162
|
+
if (activeThemes.includes(name)) addBase(remapRoot(styles, root))
|
|
116
163
|
}
|
|
117
164
|
|
|
118
165
|
// Components — class selectors via addUtilities (enables lg:/hover:/etc. variants),
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
2
|
@layer theme{:is([data-theme=darkberry],[data-theme=dark]){--scheme-color:dark;--border-radius:0.25rem;--color-base:oklch(10.889% 0.00301 17.398);--color-on-base:oklch(98% 0.01 270);--color-neutral:oklch(85% 0 0);--color-on-neutral:oklch(20% 0 0);--color-primary:oklch(66.385% 0.18368 285.592);--color-on-primary:oklch(10% 0.01 270);--color-secondary:oklch(65% 0.18 220);--color-on-secondary:oklch(10% 0.01 220);--color-accent:oklch(75% 0.18 50);--color-on-accent:oklch(10% 0.01 50);--color-info:oklch(91.67% .077 205.04);--color-on-info:oklch(10% 0.01 250);--color-success:oklch(65% 0.18 140);--color-on-success:oklch(10% 0.01 140);--color-warning:oklch(75% 0.20 85);--color-on-warning:oklch(10% 0.01 85);--color-error:oklch(60% 0.22 30);--color-on-error:oklch(10% 0.01 30)}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
2
|
@layer theme{:is([data-theme=snowberry],[data-theme=light]),:root:not([data-theme]){--scheme-color:light;--border-radius:0.25rem;--color-base:oklch(1 0 0);--color-on-base:oklch(0.22 0 0);--color-neutral:oklch(0.15 0 0);--color-on-neutral:oklch(1 0 0);--color-primary:oklch(51.1% 0.262 276.966);--color-on-primary:oklch(96.2% 0.018 272.314);--color-secondary:oklch(0.591 0.293 322.896);--color-on-secondary:oklch(1 0 0);--color-accent:oklch(0.541 0.281 293.009);--color-on-accent:oklch(1 0 0);--color-info:oklch(0.685 0.169 237.323);--color-on-info:oklch(0.15 0 0);--color-success:oklch(0.792 0.209 151.711);--color-on-success:oklch(0.15 0 0);--color-warning:oklch(0.852 0.199 91.936);--color-on-warning:oklch(0.15 0 0);--color-error:oklch(0.577 0.245 27.325);--color-on-error:oklch(1 0 0)}}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
2
|
-
/*! tailwindcss v4.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */.heading-2xl{--heading-size:1rem;--heading-size:1.5rem}.heading-2xl,.heading-3xl{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading-3xl{--heading-size:1rem;--heading-size:1.875rem}.heading-4xl{--heading-size:1rem;--heading-size:2.25rem}.heading-4xl,.heading-5xl{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading-5xl{--heading-size:1rem;--heading-size:3rem}.heading-6xl{--heading-size:1rem;--heading-size:3.75rem}.heading-6xl,.heading-7xl{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading-7xl{--heading-size:1rem;--heading-size:4.5rem}.heading-8xl{--heading-size:1rem;--heading-size:6rem}.heading-8xl,.heading-9xl{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading-9xl{--heading-size:1rem;--heading-size:8rem}.heading-lg{--heading-size:1rem;--heading-size:1.125rem}.heading-lg,.heading-md{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading-md{--heading-size:1rem}.heading-sm{--heading-size:1rem;--heading-size:0.875rem}.heading-sm,.heading-xl{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading-xl{--heading-size:1rem;--heading-size:1.25rem}.heading-xs{--heading-size:1rem;--heading-size:0.75rem}.heading,.heading-xs{color:var(--color-on-base);font-weight:700;text-wrap-style:balance;font-size:var(--heading-size);line-height:1.15}.heading{--heading-size:1rem}
|
package/dist/utilities/para.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
2
|
-
/*! tailwindcss v4.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */.para-2xl{font-size:var(--text-base);font-size:var(--text-2xl)}.para-2xl,.para-3xl{text-wrap-style:pretty;line-height:1.6}.para-3xl{font-size:var(--text-base);font-size:var(--text-3xl)}.para-4xl{font-size:var(--text-base);font-size:var(--text-4xl)}.para-4xl,.para-5xl{text-wrap-style:pretty;line-height:1.6}.para-5xl{font-size:var(--text-base);font-size:var(--text-5xl)}.para-6xl{font-size:var(--text-base);font-size:var(--text-6xl)}.para-6xl,.para-7xl{text-wrap-style:pretty;line-height:1.6}.para-7xl{font-size:var(--text-base);font-size:var(--text-7xl)}.para-8xl{font-size:var(--text-base);font-size:var(--text-8xl)}.para-8xl,.para-9xl{text-wrap-style:pretty;line-height:1.6}.para-9xl{font-size:var(--text-base);font-size:var(--text-9xl)}.para-lg{font-size:var(--text-base);font-size:var(--text-lg)}.para-lg,.para-md{text-wrap-style:pretty;line-height:1.6}.para-md{font-size:var(--text-base)}.para-sm{font-size:var(--text-base);font-size:var(--text-sm)}.para-sm,.para-xl{text-wrap-style:pretty;line-height:1.6}.para-xl{font-size:var(--text-base);font-size:var(--text-xl)}.para-xs{font-size:var(--text-base);font-size:var(--text-xs)}.para,.para-xs{text-wrap-style:pretty;line-height:1.6}.para{font-size:var(--text-base)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
2
|
.prose-frutjam{--tw-prose-body:var(--color-body);--tw-prose-headings:var(--color-on-base);--tw-prose-lead:var(--color-on-neutral);--tw-prose-bold:var(--color-on-base);--tw-prose-links:var(--color-primary);--tw-prose-counters:var(--color-neutral);--tw-prose-bullets:var(--color-neutral);--tw-prose-hr:var(--color-base-soft);--tw-prose-quotes:var(--color-on-base);--tw-prose-quote-borders:var(--color-primary);--tw-prose-code:var(--color-on-base);--tw-prose-pre-code:var(--color-on-base);--tw-prose-pre-bg:var(--color-base-soft);--tw-prose-th-borders:var(--color-base-soft);--tw-prose-td-borders:var(--color-base-soft);--tw-prose-captions:var(--color-on-neutral);--tw-prose-kbd:var(--color-body);--tw-prose-invert-body:var(--color-on-neutral);--tw-prose-invert-headings:var(--color-on-base);--tw-prose-invert-links:var(--color-primary)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/*! frutjam v2.0.
|
|
2
|
-
/*! tailwindcss v4.
|
|
1
|
+
/*! frutjam v2.0.2 (c) 2026 Nezanuha | Released under the MIT License | https://frutjam.com */
|
|
2
|
+
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */.wrapper-full{width:100%;max-width:100%;box-sizing:border-box;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-2xl{box-sizing:border-box;max-width:1536px;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-lg{box-sizing:border-box;max-width:1024px;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-md{box-sizing:border-box;max-width:768px;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-sm{box-sizing:border-box;max-width:640px;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-xl{box-sizing:border-box;max-width:1280px;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper-xs{box-sizing:border-box;max-width:320px;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}.wrapper{box-sizing:border-box;margin-inline:auto;padding-inline:1rem;@media (width >= 40rem){padding-inline:2rem}@media (width >= 64rem){padding-inline:4rem}}
|
package/index.js
CHANGED
|
@@ -133,6 +133,41 @@ const BASE_CORE = [
|
|
|
133
133
|
|
|
134
134
|
// ── Build ────────────────────────────────────────────────────────────────────
|
|
135
135
|
|
|
136
|
+
// Scope one selector part (already split from a comma list) to rootSelector.
|
|
137
|
+
// Returns an array of replacement selectors.
|
|
138
|
+
// [data-theme] selectors become compound with rootSelector so theme variables
|
|
139
|
+
// only apply when data-theme is set directly on the root element — no ancestor
|
|
140
|
+
// inheritance, which would break the isolation guarantee of the root option.
|
|
141
|
+
function scopeThemeSelector(sel, rootSelector) {
|
|
142
|
+
const t = sel.trimStart()
|
|
143
|
+
const lead = sel.slice(0, sel.length - t.length)
|
|
144
|
+
|
|
145
|
+
// Already remapped from :root (e.g. rootSelector:not([data-theme])) — keep as-is
|
|
146
|
+
if (t.startsWith(rootSelector)) return [sel]
|
|
147
|
+
|
|
148
|
+
// :is([data-theme="x"], [data-theme="y"]) — flatten into individual compound selectors
|
|
149
|
+
if (t.startsWith(":is([data-theme")) {
|
|
150
|
+
const values = []
|
|
151
|
+
const re = /\[data-theme=["']([^"']+)["']\]/g
|
|
152
|
+
let m
|
|
153
|
+
while ((m = re.exec(t)) !== null) values.push(m[1])
|
|
154
|
+
return values.map(v => `${lead}${rootSelector}[data-theme="${v}"]`)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// [data-theme="x"] — compound with rootSelector
|
|
158
|
+
if (/^\[data-theme=/.test(t)) {
|
|
159
|
+
const m = t.match(/^\[data-theme=["']([^"']+)["']\]/)
|
|
160
|
+
if (m) return [`${lead}${rootSelector}[data-theme="${m[1]}"]`]
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// [data-theme] without value (base tokens) — compound with rootSelector
|
|
164
|
+
if (t.startsWith("[data-theme]")) {
|
|
165
|
+
return [`${lead}${rootSelector}[data-theme]`]
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return [sel]
|
|
169
|
+
}
|
|
170
|
+
|
|
136
171
|
function buildCSS(prefix, themes, reset, rootSelector, include, exclude) {
|
|
137
172
|
// Resolve which components+utilities to include
|
|
138
173
|
let keys = Object.keys(REGISTRY)
|
|
@@ -169,6 +204,14 @@ function buildCSS(prefix, themes, reset, rootSelector, include, exclude) {
|
|
|
169
204
|
const customThemes = buildCustomThemes(themes)
|
|
170
205
|
if (customThemes) css += "\n\n" + customThemes
|
|
171
206
|
|
|
207
|
+
if (rootSelector !== ":root") {
|
|
208
|
+
const ast = postcss.parse(css)
|
|
209
|
+
ast.walkRules(rule => {
|
|
210
|
+
rule.selectors = rule.selectors.flatMap(sel => scopeThemeSelector(sel, rootSelector))
|
|
211
|
+
})
|
|
212
|
+
css = ast.toString()
|
|
213
|
+
}
|
|
214
|
+
|
|
172
215
|
return { css, utilMap }
|
|
173
216
|
}
|
|
174
217
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "frutjam",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "A utility-first CSS UI Library for Tailwind CSS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -90,12 +90,12 @@
|
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
-
"@tailwindcss/postcss": "^4.
|
|
93
|
+
"@tailwindcss/postcss": "^4.3.0",
|
|
94
94
|
"autoprefixer": "^10.5.0",
|
|
95
|
-
"cssnano": "^8.0.
|
|
95
|
+
"cssnano": "^8.0.1",
|
|
96
96
|
"postcss": "^8.5.14",
|
|
97
97
|
"postcss-js": "^5.1.0",
|
|
98
98
|
"rimraf": "^6.1.3",
|
|
99
|
-
"tailwindcss": "^4.
|
|
99
|
+
"tailwindcss": "^4.3.0"
|
|
100
100
|
}
|
|
101
101
|
}
|